여러 파일 변경


194

다음 명령은 2 개의 파일 내용을 올바르게 변경합니다.

sed -i 's/abc/xyz/g' xaa1 xab1 

그러나 내가해야 할 일은 여러 파일을 동적으로 변경하는 것이며 파일 이름을 모릅니다. I로 시작하는 현재 디렉토리의 모든 파일을 읽어들이는 명령을 쓰고 싶어 xa*하고 sed파일 내용을 변경해야합니다.


63
당신은 의미 sed -i 's/abc/xyz/g' xa*합니까?
Paul R

3
여기에 대한 답변으로는 충분하지 않습니다. 참조 unix.stackexchange.com/questions/112023/...
이삭

답변:


136

더 나은 아직 :

for i in xa*; do
    sed -i 's/asd/dfg/g' $i
done

파일이 몇 개인 지 아무도 모르기 때문에 명령 줄 제한을 위반하기 쉽습니다.

파일이 너무 많으면 어떻게됩니까?

# grep -c aaa *
-bash: /bin/grep: Argument list too long
# for i in *; do grep -c aaa $i; done
0
... (output skipped)
#

18
파일이 많으면 명령에서 명령 줄 제한을 해제합니다 for. 자신을 보호하려면 다음을 사용해야합니다.find ... | xargs ...
glenn jackman

1
구현을 모르지만 "xa *"패턴은 어느 시점에서 확장되어야합니다. 쉘은 다르게 확장을 할 수 있는가 for가에 대한보다 echogrep?
glenn jackman

4
업데이트 된 답변을 참조하십시오. 더 많은 정보가 필요하면 사람들이 당신을 도울 수 있도록 공식적인 질문을하십시오.
lenik

5
sed 명령에서 공백이있는 파일 이름에서 단어가 분리되는 것을 피하기 위해 "$i"대신에 사용해야 $i합니다. 그렇지 않으면 이것은 매우 좋습니다.
와일드 카드

4
목록과 관련하여 차이점은 for언어 구문의 일부이며 내장 기능조차도 아닙니다. 의 경우 sed -i 's/old/new' *확장은 *모두 sed의 arglist로 전달되어야하며 sed프로세스가 시작 되기 전에 이것이 반드시 발생해야합니다 . for루프를 사용하면 전체 arglist (의 확장 *)는 명령으로 전달되지 않으며 셸 메모리에만 저장되고 반복됩니다. 나는 이것에 대한 어떤 언급도 전혀 없지만, 그것이 차이점 일 가능성이 높습니다. (저는 더 많은 지식을 가진 사람의 의견을 듣고 싶습니다 ...)
와일드 카드

167

-exec 인수를 언급 한 사람이 아무도 없습니다.이 유형의 유스 케이스에 적합하지만 각 일치하는 파일 이름에 대해 프로세스를 시작합니다.

find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} \;

또는 xargs를 사용하여 더 적은 수의 프로세스를 호출 할 수 있습니다.

find . -type f -name 'xa*' | xargs sed -i 's/asd/dsg/g'

또는 find가 서브 프로세스 호출 당 둘 이상의 파일을 제공 할 수 있도록 find 대신 + exec 변형을 사용하십시오 ;.

find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} +

8
이 답변에서 명령을 다음과 같이 수정해야했습니다 .OSX의 find ./ -type f -name 'xa*' -exec sed -i '' 's/asd/dsg/g' {} \;경우 find 명령의 위치 ./와 작은 따옴표 쌍입니다 -i.
shelbydz 2016 년

find 명령은이 ealfonso에 의해 공급되는 작품, ./동일 .이후 -i에만 backupsuffix의 매개 변수가 있습니다.
uhausbrand 8

-exec와 함께 발견의 옵션은 {} +명시된 바와 같이 문제를 해결하기에 충분하며, 대부분의 요구 사항을 잘해야한다. 그러나 옵션을 xargs사용한 병렬 처리도 가능하기 때문에 일반적으로 더 나은 선택입니다 -p. glob 확장이 명령 행 길이를 초과 할만큼 충분히 크면 순차적 실행보다 속도가 향상 될 수 있습니다.
Amit Naidu

78

grep과 sed를 함께 사용할 수 있습니다. 하위 디렉토리를 재귀 적으로 검색 할 수 있습니다.

Linux: grep -r -l <old> * | xargs sed -i 's/<old>/<new>/g'
OS X: grep -r -l <old> * | xargs sed -i '' 's/<old>/<new>/g'

For grep:
    -r recursively searches subdirectories 
    -l prints file names that contain matches
For sed:
    -i extension (Note: An argument needs to be provided on OS X)

3
이 방법의 보너스는 grep -v자식 폴더를 피하기 위해 미끄러 져 들어갈 수 있다는 것입니다grep -rl <old> . | grep -v \.git | xargs sed -i 's/<old>/<new>/g'
Martin Lyne

Mac을위한 최고의 솔루션!
후작 Blount

30

이러한 명령은 sedMac OS X과 함께 제공 되는 기본값에서는 작동하지 않습니다.

보낸 사람 man 1 sed:

-i extension
             Edit files in-place, saving backups with the specified
             extension.  If a zero-length extension is given, no backup 
             will be saved.  It is not recommended to give a zero-length
             extension when in-place editing files, as you risk corruption
             or partial content in situations where disk space is exhausted, etc.

시도

sed -i '.bak' 's/old/new/g' logfile*

for i in logfile*; do sed -i '.bak' 's/old/new/g' $i; done

둘 다 잘 작동합니다.


2
@sumek 다음은 OS X에서 모든 발생을 대체하는 sed를 보여주는 터미널 세션의 예입니다. GitHub Gist
funroll

나는 이것을 사용하여 모든 웹 사이트 구성 파일의 두 줄을 아래의 한 줄로 바꿨습니다. sed -i.bak "s / supercache_proxy_config / proxy_includes \ / supercache_config / g; s / basic_proxy_config / proxy_include \ / basic_proxy_config / g"sites-available / * 파일 작업이 완료되면 * .bak 파일을 삭제하는 것을 잊지 마십시오 시스템 위생을 위해.
Josiah 2016 년

19

@PaulR 은 이것을 의견으로 게시했지만 사람들은 그것을 답변으로보아야합니다 (그리고이 답변은 내 요구에 가장 적합합니다).

sed -i 's/abc/xyz/g' xa*

이것은 아마도 수십 개 정도의 파일은 적당하지만 수백만 개 정도는 아닐 것입니다 .


대체품에 슬래시가 있다고 가정하십시오. 파일 경로가있는 또 다른 예 sed -i 's|auth-user-pass nordvpn.txt|auth-user-pass /etc/openvpn/nordvpn.txt|g' *.ovpn.
Léo Léopold Hertz 준영

10

또 다른 다목적 방법은 다음을 사용하는 것입니다 find.

sed -i 's/asd/dsg/g' $(find . -type f -name 'xa*')

1
find 명령의 출력이 확장되므로 문제가 해결되지 않습니다. 대신 -exec
ealfonso

@erjoalgo 이것은 sed 명령이 여러 입력 파일을 처리 할 수 ​​있기 때문에 작동합니다. find 명령이 제대로 작동하려면 확장이 필요했습니다.
dkinzer 2016 년

파일 수가 명령 줄 한계에 도달하지 않는 한 작동합니다.
ealfonso 2016 년

이 제한은 컴퓨터에서 사용할 수있는 메모리 리소스에만 의존하며 exec의 제한과 정확히 동일합니다.
dkinzer

4
그것은 사실이 아닙니다. 위의 명령에서 $ (find. ...)는 단일 명령으로 확장되며 일치하는 파일이 많은 경우 매우 길 수 있습니다. 길이가 너무 길면 (예를 들어, 내 시스템에서 제한이 약 2097152 자임) "인수 목록이 너무 깁니다"라는 오류가 표시되고 명령이 실패합니다. 이에 대한 배경 지식을 얻으려면이 오류를 Google에 알려주십시오.
ealfonso 2016 년

2

find비슷한 작업에 사용 하고 있습니다. 매우 간단합니다. 다음 sed과 같은 인수로 전달해야 합니다.

sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`

이렇게하면 복잡한 루프를 작성할 필요가 없으며 변경할 파일이 무엇인지 쉽게 알 find수 있습니다 sed. 실행 하기 전에 실행하십시오 .


1
이것은 @ dkinzer 's answer 와 정확히 동일 합니다.
Mr. Tao

0

너는 만들 수있어

' xxxx '텍스트 u 검색 및 ' yyyy '로 대체

grep -Rn '**xxxx**' /path | awk -F: '{print $1}' | xargs sed -i 's/**xxxx**/**yyyy**/'

0

스크립트를 실행할 수 있다면 비슷한 상황에서 내가 한 일이 있습니다.

sed명령에 dictionary / hashMap (연관 배열) 및 변수 를 사용하여 배열을 반복하여 여러 문자열을 바꿀 수 있습니다. 에 와일드 카드를 포함하면 name_pattern파일의 전체 위치를 name_pattern='File*.txt'특정 디렉토리 ( source_dir) 의 패턴 (와 유사 할 수 있음 )으로 바꿀 수 있습니다 . 모든 변경 사항이 작성됩니다 logfiledestin_dir

#!/bin/bash
source_dir=source_path
destin_dir=destin_path
logfile='sedOutput.txt'
name_pattern='File.txt'

echo "--Begin $(date)--" | tee -a $destin_dir/$logfile
echo "Source_DIR=$source_dir destin_DIR=$destin_dir "

declare -A pairs=( 
    ['WHAT1']='FOR1'
    ['OTHER_string_to replace']='string replaced'
)

for i in "${!pairs[@]}"; do
    j=${pairs[$i]}
    echo "[$i]=$j"
    replace_what=$i
    replace_for=$j
    echo " "
    echo "Replace: $replace_what for: $replace_for"
    find $source_dir -name $name_pattern | xargs sed -i "s/$replace_what/$replace_for/g" 
    find $source_dir -name $name_pattern | xargs -I{} grep -n "$replace_for" {} /dev/null | tee -a $destin_dir/$logfile
done

echo " "
echo "----End $(date)---" | tee -a $destin_dir/$logfile

우선, 쌍 배열이 선언되고, 각각의 쌍은, 대체 문자열로 WHAT1대체 될 것임을 FOR1OTHER_string_to replace대체 될 것임을 string replaced파일 내의 File.txt. 루프에서 배열이 읽 히면 쌍의 첫 번째 멤버는로 검색되고 두 번째 멤버는로 검색 replace_what=$i됩니다 replace_for=$j. find디렉토리에서 명령을 검색 파일 이름 (즉, 와일드 카드를 포함 할 수있다)과 sed -i이전에 정의 된 것 같은 파일 (들)의 명령으로 대체합니다. 마지막으로 grep파일의 변경 사항을 기록하기 위해 로그 파일로 리디렉션을 추가했습니다 .

이것은 bash에서 Loop over tuples에GNU Bash 4.3 sed 4.2.2 대한 VasyaNovikov의 대답을 바탕으로 저 에게 효과적이었습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.