সেড শিক্ষানবিস: একটি ফোল্ডারে সমস্ত উপস্থিতি পরিবর্তন করা


98

একটি ফোল্ডারে (এবং এর সাবফোল্ডার) সমস্ত ফাইলের জন্য আমি একটি রেইজেক্স সন্ধান এবং প্রতিস্থাপন করতে হবে। এটি করার জন্য লিনাক্স শেল কমান্ডটি কী হবে?

উদাহরণস্বরূপ, আমি এটি সমস্ত ফাইলের মধ্যে চালাতে এবং পুরানো ফাইলটিকে নতুন, প্রতিস্থাপিত পাঠ্যের সাথে ওভাররাইট করতে চাই।

sed 's/old text/new text/g' 

উত্তর:


150

এটি কেবলমাত্র সেড ব্যবহার করে করার কোনও উপায় নেই। আপনাকে কমপক্ষে অনুসন্ধানের ইউটিলিটি একসাথে ব্যবহার করতে হবে:

find . -type f -exec sed -i.bak "s/foo/bar/g" {} \;

এই কমান্ডটি .bakপ্রতিটি পরিবর্তিত ফাইলের জন্য একটি ফাইল তৈরি করবে ।

মন্তব্য:

  • -iজন্য যুক্তি sedকমান্ড, একটি গনুহ এক্সটেনশন, তাই আপনি এই কমান্ড চালান তাহলে বাসদ সাথে sedআপনি একটি নতুন ফাইল আউটপুট পুনর্নির্দেশ করতে হবে তারপর, এটা নামান্তর।
  • findউপযোগ বাস্তবায়ন না -execবয়সী ইউনিক্স বাক্সে যুক্তি, তাই, আপনি একটি ব্যবহার করতে হবে | xargsপরিবর্তে।

4
কিসের \;জন্য?
অ্যান্ড্রি মাকুখা

4
আর্গুমেন্ট-এক্সেকের কমান্ডটি একটি ";" দিয়ে শেষ হয় তা আমাদের খুঁজে বের করতে হবে। তবে শেলটি শেল কমান্ড বিভাজক হিসাবে একই চিহ্ন (;) ব্যবহার করে, সুতরাং আমাদের "পালাতে হবে"; শেল থেকে এটি সন্ধানের-এক্সেক আর্গুমেন্টে পাস করুন।
ওসন্তানা

4
এটি লক্ষণীয় যে এটি -iনিজেই একটি ব্যাকআপ ফাইল তৈরি করে না এবং এটি কারণেই ফাইলটিতে অপারেশন সম্পাদনের কারণ ঘটায়।
কাইল

4
কিসের {}জন্য?
নাম

4
{}প্রতিটি ফাইলের নাম পাওয়া দ্বারা প্রতিস্থাপন করা হবে findএবং \;এটি যে কমান্ড তিনি এই সময়ে ফিনিস চালানো প্রয়োজন বলে।
ওসন্তানা

53

আমি find | xargs cmdবেশি ব্যবহার করতে পছন্দ করি find -execকারণ এটি মনে রাখা সহজ।

এই উদাহরণটি বিশ্বব্যাপী আপনার বর্তমান ডিরেক্টরিতে বা নীচে .txt ফাইলগুলিতে "বার" সাথে "ফু" প্রতিস্থাপন করে:

find . -type f -name "*.txt" -print0 | xargs -0 sed -i "s/foo/bar/g"

-print0এবং -0অপশন বাদ করা যাবে যদি আপনার ফাইলের নামের এই ধরনের স্পেস হিসাবে ভীতু অক্ষর থাকে না।


4
যদি আপনি ওএসএক্সে থাকেন তবে চেষ্টা করুন find . -type f -name "*.txt" -print0 | xargs -0 sed -i '' "s/foo/bar/g"( -iআর্গুমেন্টে একটি খালি স্ট্রিং সরবরাহ করুন নোট )।
জাকুব কুকুল

MacOS এ, sed -i.bakপরিবর্তে চালান sed -i। আমি মনে করি @ যাকুবকুকুলের উল্লিখিত sed -i ''হিসাবেও কাজ করে।
ফরজাগ্রীন

7

বহনযোগ্যতার জন্য, আমি লিনাক্স বা বিএসডি-র সাথে নির্দিষ্ট সেডের বৈশিষ্ট্যগুলিতে নির্ভর করি না। পরিবর্তে আমি overwriteস্ক্রিপ্টটি কার্নিগান এবং পাইকের বই ইউনিক্স প্রোগ্রামিং পরিবেশের উপর ব্যবহার করি।

কমান্ডটি তখন

find /the/folder -type f -exec overwrite '{}' sed 's/old/new/g' {} ';'

এবং overwriteস্ক্রিপ্ট (যা আমি পুরো জায়গা জুড়ে ব্যবহার করি)

#!/bin/sh
# overwrite:  copy standard input to output after EOF
# (final version)

# set -x

case $# in
0|1)        echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2
esac

file=$1; shift
new=/tmp/$$.new; old=/tmp/$$.old
trap 'rm -f $new; exit 1' 1 2 15    # clean up files

if "$@" >$new               # collect input
then
    cp $file $old   # save original file
    trap 'trap "" 1 2 15; cp $old $file     # ignore signals
          rm -f $new $old; exit 1' 1 2 15   # during restore
    cp $new $file
else
    echo "overwrite: $1 failed, $file unchanged" 1>&2
    exit 1
fi
rm -f $new $old

ধারণাটি হ'ল এটি কোনও ফাইলকে ওভাররাইট করে কেবল যদি কোনও কমান্ড সফল হয়। দরকারে findএবং যেখানে আপনি ব্যবহার না করার চাইবেন

sed 's/old/new/g' file > file  # THIS CODE DOES NOT WORK

কারণ শেল ফাইলটি sedপড়ার আগে এটি কেটে দেয় ।



0

উদাহরণ: / অ্যাপ্লিকেশন / কনফিগারেশন / ফোল্ডার এবং এর চাইল্ড ফোল্ডারের অধীনে থাকা সমস্ত আইএনআই ফাইলের জন্য 1 দিয়ে {অটোস্টার্ট rep প্রতিস্থাপন করুন:

sed 's/{AutoStart}/1/g' /app/config/**/*.ini

0
for i in $(ls);do sed -i 's/old_text/new_text/g' $i;done 

4
আপনার উত্তর ব্যাখ্যা করুন।
ড্রপআউট

এই কোডটি ওপির সমস্যার সমাধান করতে পারে, আপনার কোডটি কীভাবে ওপি'র সমস্যাটিকে সম্বোধন করে তার একটি ব্যাখ্যা অন্তর্ভুক্ত করা ভাল। এইভাবে, ভবিষ্যতের দর্শকরা আপনার পোস্ট থেকে শিখতে এবং তাদের নিজস্ব কোডে প্রয়োগ করতে পারে। এসও কোনও কোডিং পরিষেবা নয়, তবে জ্ঞানের উত্স। উচ্চমানের, সম্পূর্ণ উত্তরগুলি এই ধারণাটিকে শক্তিশালী করে এবং এটিকে উত্সাহিত করার সম্ভাবনা বেশি। এই বৈশিষ্ট্যগুলি, এবং আরও প্রয়োজনীয় যে সমস্ত পোস্ট স্ব-অন্তর্ভুক্ত থাকে, তা এসও এর কিছু শক্তি যা প্ল্যাটফর্ম হিসাবে আমাদের আলাদা করে তোলে ti আপনি অতিরিক্ত তথ্য যোগ করতে এবং / অথবা উত্স ডকুমেন্টেশন সহ আপনার ব্যাখ্যা পরিপূরক করতে সম্পাদনা করতে পারেন।
শেরিলহোমান

4
আপনি যদি এটি পড়তে না পারেন তবে আমার উত্তরটি ভুলে যান। এটি কেবল বাশ বুনিয়াদি।
দিমিডাক

0

এটি আমার পক্ষে কাজ করেছে (ম্যাক টার্মিনালে, লিনাক্সে আপনার প্রয়োজন নেই '' -e):

sed -i '' -e 's/old text/new text/g' `grep 'old text' -rl *`

কমান্ডটি grep 'old text' -rl *ওয়ার্কিং ডিরেক্টরি (এবং উপ-ডিরেক্টরি) যেখানে "পুরানো পাঠ্য" বিদ্যমান রয়েছে সেখানে সমস্ত ফাইল তালিকাভুক্ত করে। এটি তারপর সেড মধ্যে পাস করা হয়।


-1

আমার ভর অনুসন্ধান / পার্ল স্ক্রিপ্টটি প্রতিস্থাপন করতে পারে । শৃঙ্খলযুক্ত-ইউটিলিটি সমাধানগুলির কিছু সুবিধা রয়েছে (যেমন শেল মেটাচার্যাক্টারের ব্যাখ্যার একাধিক স্তরের সাথে ডিল না করা)।

#!/usr/bin/perl

use strict;

use Fcntl qw( :DEFAULT :flock :seek );
use File::Spec;
use IO::Handle;

die "Usage: $0 startdir search replace\n"
    unless scalar @ARGV == 3;
my $startdir = shift @ARGV || '.';
my $search = shift @ARGV or
    die "Search parameter cannot be empty.\n";
my $replace = shift @ARGV;
$search = qr/\Q$search\E/o;

my @stack;

sub process_file($) {
    my $file = shift;
    my $fh = new IO::Handle;
    sysopen $fh, $file, O_RDONLY or
        die "Cannot read $file: $!\n";
    my $found;
    while(my $line = <$fh>) {
        if($line =~ /$search/) {
            $found = 1;
            last;
        }
    }
    if($found) {
        print "  Processing in $file\n";
        seek $fh, 0, SEEK_SET;
        my @file = <$fh>;
        foreach my $line (@file) {
            $line =~ s/$search/$replace/g;
        }
        close $fh;
        sysopen $fh, $file, O_WRONLY | O_TRUNC or
            die "Cannot write $file: $!\n";
        print $fh @file;
    }
    close $fh;
}

sub process_dir($) {
    my $dir = shift;
    my $dh = new IO::Handle;
    print "Entering $dir\n";
    opendir $dh, $dir or
        die "Cannot open $dir: $!\n";
    while(defined(my $cont = readdir($dh))) {
        next
            if $cont eq '.' || $cont eq '..';
        # Skip .swap files
        next
            if $cont =~ /^\.swap\./o;
        my $fullpath = File::Spec->catfile($dir, $cont);
        if($cont =~ /$search/) {
            my $newcont = $cont;
            $newcont =~ s/$search/$replace/g;
            print "  Renaming $cont to $newcont\n";
            rename $fullpath, File::Spec->catfile($dir, $newcont);
            $cont = $newcont;
            $fullpath = File::Spec->catfile($dir, $cont);
        }
        if(-l $fullpath) {
            my $link = readlink($fullpath);
            if($link =~ /$search/) {
                my $newlink = $link;
                $newlink =~ s/$search/$replace/g;
                print "  Relinking $cont from $link to $newlink\n";
                unlink $fullpath;
                my $res = symlink($newlink, $fullpath);
                warn "Symlink of $newlink to $fullpath failed\n"
                    unless $res;
            }
        }
        next
            unless -r $fullpath && -w $fullpath;
        if(-d $fullpath) {
            push @stack, $fullpath;
        } elsif(-f $fullpath) {
            process_file($fullpath);
        }
    }
    closedir($dh);
}

if(-f $startdir) {
    process_file($startdir);
} elsif(-d $startdir) {
    @stack = ($startdir);
    while(scalar(@stack)) {
        process_dir(shift(@stack));
    }
} else {
    die "$startdir is not a file or directory\n";
}

-3

যদি ফোল্ডারে ফাইলগুলির নামের কিছু নিয়মিত নাম থাকে (যেমন ফাইল 1, ফাইল 2 ...) আমি চক্রের জন্য ব্যবহার করেছি।

for i in {1..10000..100}; do sed 'old\new\g' 'file'$i.xml > 'cfile'$i.xml; done

এটি জিজ্ঞাসিত প্রশ্নের সাথে সম্পর্কিত নয়। প্রশ্নটিতে একই ফাইল / ফোল্ডার নামের প্যাটার্ন সম্পর্কে কিছু উল্লেখ করা হয়নি। দয়া করে এরূপ উত্তরগুলি
কুণাল পরেক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.