다음 명령은 2 개의 파일 내용을 올바르게 변경합니다.
sed -i 's/abc/xyz/g' xaa1 xab1
그러나 내가해야 할 일은 여러 파일을 동적으로 변경하는 것이며 파일 이름을 모릅니다. I로 시작하는 현재 디렉토리의 모든 파일을 읽어들이는 명령을 쓰고 싶어 xa*
하고 sed
파일 내용을 변경해야합니다.
다음 명령은 2 개의 파일 내용을 올바르게 변경합니다.
sed -i 's/abc/xyz/g' xaa1 xab1
그러나 내가해야 할 일은 여러 파일을 동적으로 변경하는 것이며 파일 이름을 모릅니다. I로 시작하는 현재 디렉토리의 모든 파일을 읽어들이는 명령을 쓰고 싶어 xa*
하고 sed
파일 내용을 변경해야합니다.
답변:
더 나은 아직 :
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)
#
for
. 자신을 보호하려면 다음을 사용해야합니다.find ... | xargs ...
for
가에 대한보다 echo
나 grep
?
"$i"
대신에 사용해야 $i
합니다. 그렇지 않으면 이것은 매우 좋습니다.
for
언어 구문의 일부이며 내장 기능조차도 아닙니다. 의 경우 sed -i 's/old/new' *
확장은 *
모두 sed의 arglist로 전달되어야하며 sed
프로세스가 시작 되기 전에 이것이 반드시 발생해야합니다 . for
루프를 사용하면 전체 arglist (의 확장 *
)는 명령으로 전달되지 않으며 셸 메모리에만 저장되고 반복됩니다. 나는 이것에 대한 어떤 언급도 전혀 없지만, 그것이 차이점 일 가능성이 높습니다. (저는 더 많은 지식을 가진 사람의 의견을 듣고 싶습니다 ...)
-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' {} +
find ./ -type f -name 'xa*' -exec sed -i '' 's/asd/dsg/g' {} \;
경우 find 명령의 위치 ./
와 작은 따옴표 쌍입니다 -i
.
./
동일 .
이후 -i
에만 backupsuffix의 매개 변수가 있습니다.
-exec
와 함께 발견의 옵션은 {} +
명시된 바와 같이 문제를 해결하기에 충분하며, 대부분의 요구 사항을 잘해야한다. 그러나 옵션을 xargs
사용한 병렬 처리도 가능하기 때문에 일반적으로 더 나은 선택입니다 -p
. glob 확장이 명령 행 길이를 초과 할만큼 충분히 크면 순차적 실행보다 속도가 향상 될 수 있습니다.
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)
grep -v
자식 폴더를 피하기 위해 미끄러 져 들어갈 수 있다는 것입니다grep -rl <old> . | grep -v \.git | xargs sed -i 's/<old>/<new>/g'
이러한 명령은 sed
Mac 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
둘 다 잘 작동합니다.
@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
.
또 다른 다목적 방법은 다음을 사용하는 것입니다 find
.
sed -i 's/asd/dsg/g' $(find . -type f -name 'xa*')
find
비슷한 작업에 사용 하고 있습니다. 매우 간단합니다. 다음 sed
과 같은 인수로 전달해야 합니다.
sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`
이렇게하면 복잡한 루프를 작성할 필요가 없으며 변경할 파일이 무엇인지 쉽게 알 find
수 있습니다 sed
. 실행 하기 전에 실행하십시오 .
스크립트를 실행할 수 있다면 비슷한 상황에서 내가 한 일이 있습니다.
sed
명령에 dictionary / hashMap (연관 배열) 및 변수 를 사용하여 배열을 반복하여 여러 문자열을 바꿀 수 있습니다. 에 와일드 카드를 포함하면 name_pattern
파일의 전체 위치를 name_pattern='File*.txt'
특정 디렉토리 ( source_dir
) 의 패턴 (와 유사 할 수 있음 )으로 바꿀 수 있습니다 . 모든 변경 사항이 작성됩니다 logfile
에destin_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
대체 될 것임을 FOR1
과 OTHER_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의 대답을 바탕으로 저 에게 효과적이었습니다 .
sed -i 's/abc/xyz/g' xa*
합니까?