기존 파일을 직접 수정하고 "baz"가 포함된 줄에 대해서만 "foo"를 "bar"로 바꿉니다.

기존 파일을 직접 수정하고 "baz"가 포함된 줄에 대해서만 "foo"를 "bar"로 바꿉니다.

아래와 같은 food.txt 파일이 있습니다.

mangoes|foo|faa  
oranges|foo|faa  
chocolates|foo|baz  

교체하려고 해요부자그리고술집조건이 충족되면 baz. (여기서는 regex b*z를 사용할 생각)
현재는 아래 sed 명령어를 사용하고 있지만 기존 파일을 직접 수정하지는 않습니다. 또한 정규식(b*z)도 사용할 수 없습니다.

sed '/baz/s/foo/bar/g' food.txt

기존 파일을 직접 수정하려면 "sed" 외에 다른 방법을 제안해 주세요.

추신: 시도해 보았지만 sed -ised가 아닌 다른 명령을 사용하고 싶습니다.
mobaxterm(OS - Windows)을 사용하고 있습니다.

답변1

sed이 상황에서 사용하는데 아무런 문제가 없다고 생각합니다. 이것은 작업에 적합한 도구입니다.

귀하의 명령은 (주어진 데이터에 대해) 잘 작동합니다.

$ sed '/baz/s/foo/bar/g' food.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

정규식을 사용하여 |b줄의 끝(줄의 어느 곳도 아님)으로 시작하고 끝나는 모든 문자열을 일치시킵니다.zbaz

$ sed '/|b.*z$/s/foo/bar/g' food.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

파일을 변경하려면(GNU 사용 sed):

$ sed -i '/|b.*z$/s/foo/bar/g' food.txt

또는 (모든 sed구현):

$ sed '/|b.*z$/s/foo/bar/g' food.txt >tmpfile && mv tmpfile food.txt

다음을 사용할 수도 있습니다 awk.

$ awk 'BEGIN { OFS=FS="|" } $3 == "baz" { $2 = "bar" }; 1' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

^b.*z$또는 세 번째 필드에서 일치합니다.

$ awk 'BEGIN { OFS=FS="|" } $3 ~ /^b.*z$/ { $2 = "bar" }; 1' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

... 또는밀러( mlr), 여기서 입력은 필드 구분자로 사용되는 헤더 없는 CSV 파일로 읽혀집니다 |.

$ mlr --csv -N --fs pipe put '$3 == "baz" { $2 = "bar" }' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

또는,

$ mlr --csv -N --fs pipe put '$3 =~ "^b.*z$" { $2 = "bar" }' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

awk또는 Miller를 사용하면 격리된 필드에 대해 패턴을 더 쉽고 안전하게 일치시킬 수 있다는 이점이 있습니다. Miller의 또 다른 이점은 CSV 인용 규칙을 이해한다는 것입니다.

답변2

awk다음과 함께 사용 gsub():

awk '/baz$/ {gsub("foo", "bar")};1' food.txt
  • /baz$/원하는 경우 정규식 패턴을 대신 사용하여 일치시킬 수 있습니다.

  • 패턴이 일치하면 gsub()원하는 문자열을 바꾸십시오.


내부 편집을 위해 최신 버전의 GNU awk(>=4.1.0)에는 내부 수정 옵션이 있습니다.

awk -i inplace '/baz$/ {gsub("foo", "bar")};1' food.txt

sponge그렇지 않으면 GNU를 사용 moreutils하거나 임시 파일을 사용할 수 있습니다 .

awk '/baz$/ {gsub("foo", "bar")};1' food.txt >temp_food.txt && \
      mv temp_food.txt food.txt

예:

$ cat file.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|foo|baz

$ awk '/baz$/ {gsub("foo", "bar")};1' file.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

답변3

sed -i필요한 것을 정확히 수행하는 것을 사용하고 싶지 않은 이유를 모르겠지만 대안은 다음과 같습니다 perl.

$ perl -pe 's/foo/bar/g if /b*z/' food.txt 
mangoes|foo|faa  
oranges|foo|faa  
chocolates|bar|baz

이는 -pe"스크립트를 적용한 후 입력 파일의 각 줄을 인쇄합니다.

-i다음을 사용하여 해당 위치에서 파일을 편집 할 수 있습니다 .

perl -i -pe 's/foo/bar/g if /b*z/' food.txt 

또한 정규식은 b*z"0 이상과 일치하고 b뒤에 a가 오는 것을 의미합니다 z. and를 생략하여 일치하고 일치만 하기 때문에 여기서 작동합니다 b*z. 즉, any는 0의 예 다음에 a가 되기 때문에 어떤 것과도 일치합니다. I 사용하고 싶은 것은 b.*z(ab 다음에 0개 이상의 문자가 오고 az가 옵니다)라고 생각하세요.barbazzzbz

perl -i -pe 's/foo/bar/g if /b.*z/' food.txt 

답변4

자동 텍스트 편집을 위한 실제로 가장 좋은 도구는 다음과 같습니다.ex.

직접 전화하는 것도 가능하겠지만 ex, 찾아보니MobaXterm에서전화해야 해요 vim -e.

자동 편집을 수행하는 가장 좋은 방법은MobaXterm에서(다른 *nix 시스템에서도 작동함)은 다음과 같습니다.

printf '%s\n' 'g/b.*z/s/foo/bar/g' x | vim -es food.txt

POSIX와 완전히 호환되도록 하려면 다음과 같이 변경하세요.

printf '%s\n' 'g/b.*z/s/foo/bar/g' x | ex -s food.txt

그러나 이 ex명령을 호출하면 MobaXterm에서 제대로 작동하지 않을 수 있습니다(제가 설치한 경우에는 작동하지 않았습니다). 해당 버전이 실패하면 vim -es이 버전의 명령을 사용해 보십시오.ex

관련 정보