sed 초보자 : 폴더의 모든 항목 변경


98

폴더 (및 하위 폴더)의 모든 파일에서 정규식 찾기 및 바꾸기를 수행해야합니다. 이를 수행하는 Linux 쉘 명령은 무엇입니까?

예를 들어, 모든 파일에 대해이 작업을 실행하고 이전 파일을 새 텍스트로 덮어 쓰고 싶습니다.

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

답변:


150

sed 만 사용하여 수행 할 수있는 방법은 없습니다. 최소한 find 유틸리티를 함께 사용해야합니다.

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

이 명령은 .bak 변경된 각 파일에 대한 파일을 합니다.

메모:

  • 명령에 대한 -i인수 sed는 GNU 확장이므로 BSD에서이 명령을 실행하는 경우sed 출력을 새 파일로 리디렉션 한 다음 이름을 바꿔야합니다.
  • find유틸리티는 -exec이전 UNIX 상자에서 인수를 구현하지 않으므로 | xargs대신 a를 사용해야합니다 .

4
무엇입니까 \;?
Andriy Makukha

4
-exec 인수의 명령이”;”로 끝나는 위치를 찾아야합니다. 그러나 쉘은 쉘 명령 구분 기호로 동일한 기호 (;)를 사용하므로”;”을 이스케이프해야합니다. 쉘에서 find의 -exec 인수로 전달합니다.
osantana 19

2
-i자체로는 백업 파일을 생성하지 않으며 sed가 파일에 대한 작업을 제자리에서 수행하게하는 원인이됩니다.
Kyle

1
무엇입니까 {}?
somenickname

1
{}발견 각각의 파일 이름으로 대체됩니다 find하고 \;그 명령 그는이 시점에서 마감을 실행하는 데 필요한 찾을 알려줍니다.
osantana

52

기억하기 쉽기 때문에 find | xargs cmdover 사용하는 것을 선호합니다 find -exec.

이 예제는 현재 디렉토리 또는 그 아래의 .txt 파일에서 "foo"를 "bar"로 전역 적으로 대체합니다.

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

-print0-0당신의 파일 이름이 공백 펑키 문자를 포함하지 않는 경우 옵션은 생략 할 수 있습니다.


3
OSX를 사용하는 경우 시도해보십시오 find . -type f -name "*.txt" -print0 | xargs -0 sed -i '' "s/foo/bar/g"( -i인수에 빈 문자열을 제공하십시오 ).
Jakub Kukul

맥 OS에서 실행하는 sed -i.bak대신 sed -i. @JakubKukul에서 언급했듯이 sed -i ''작동 한다고 생각 합니다.
forzagreen

7

이식성을 위해 linux 또는 BSD에 특정한 sed 기능에 의존하지 않습니다. 대신 overwriteKernighan과 Unix Programming Environment에 대한 Pike의 책에서 스크립트를 사용합니다 .

명령은 다음과 같습니다.

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을 읽기 전에 잘라 내기 때문 입니다.


3

내가 제안 할 수도 있습니다 (파일 백업 후) :

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

0

예 : / app / config / 폴더 및 하위 폴더 아래의 모든 ini 파일에 대해 {AutoStart}를 1로 복제합니다.

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

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

5
당신의 대답을 설명하십시오.
중퇴

이 코드로 OP 문제를 해결할 수 있지만 코드에서 OP 문제를 해결하는 방법에 대한 설명을 포함하는 것이 좋습니다. 이렇게하면 향후 방문자가 게시물에서 학습하고 자신의 코드에 적용 할 수 있습니다. SO는 코딩 서비스가 아니라 지식을위한 리소스입니다. 고품질의 완전한 답변은이 아이디어를 강화하며 찬성 될 가능성이 더 높습니다. 이러한 기능과 모든 게시물이 자체 포함되어야한다는 요구 사항은 포럼과 우리를 차별화하는 플랫폼으로서 SO의 강점입니다. 추가 정보를 추가하거나 소스 문서로 설명을 보완하기 위해 편집 할 수 있습니다.
SherylHohman

2
이 글을 읽을 수 없다면 내 대답을 잊어 버리십시오. 그것은 단지 bash 기본입니다.
DimiDak

0

이것은 나를 위해 일했습니다 (Mac 터미널에서는 Linux에서는 필요하지 않습니다 '' -e).

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

이 명령 grep 'old text' -rl *은 "이전 텍스트"가있는 작업 디렉토리 (및 하위 디렉토리)의 모든 파일을 나열합니다. 그런 다음 sed로 전달됩니다.


-1

내 대량 검색 / 대체 Perl 스크립트 를 시도하고 싶을 수 있습니다 . 연결된 유틸리티 솔루션에 비해 몇 가지 장점이 있습니다 (예 : 여러 수준의 쉘 메타 문자 해석을 처리 할 필요가 없음).

#!/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

폴더의 파일 이름에 정규 이름 (예 : file1, file2 ...)이있는 경우주기에 사용했습니다.

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

이것은 질문과 관련이 없습니다. 이 질문은 동일한 파일 / 폴더 이름 패턴에 대해서는 언급하지 않습니다. 이러한 답변을 피하십시오
Kunal Parekh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.