올바른 줄을 찾아서 내용을 변경 한 다음 원래 파일로 다시 넣으려면 sed?


9

파일의 특정 줄에서 한 단어를 변경하려고하는데 모두 함께 연결하는 데 문제가 있습니다.

기본적으로 내 파일의 한 줄에는 키워드 'firmware_revision'이 있으며이 줄 (이 줄에만)에는 'test'라는 단어를 'production'이라는 단어로 바꾸고 싶습니다.

그래서 나는 이것을 할 수 있습니다 :

grep 'firmware_revision' myfile.py | sed 's/test/production'

원하는 줄을 선택하고 대체를 수행하지만 이전 줄을 대체하기 위해이 새 줄을 원본 파일로 가져 오는 방법을 알 수 없습니다. 분명히 파일로 다시 리디렉션 할 수 없으므로 어떻게해야합니까?

임시를 사용하더라도 grep줄을 가져 오기 위해 파일을 사용하면 파일의 다른 모든 데이터가 손실되므로 더 이상 모든 파일을 임시 파일로 리디렉션 할 수 없으며 원본을 임시로 바꿀 수 없습니다.

편집-누군가 더 많은 정보를 요청했습니다

이 줄로 가득 찬 파일이 있다고 가정 해 봅시다.

[
  ('key_name1', str, 'value1', 'Description'),
  ('key_name2', str, 'value2', 'Description'),
  ('key_name3', str, 'value3', 'Description'),
  ('firmware_revision', str, 'my-firmware-name-test', 'Firmware revision name')
]

이제 'firmware_revision'이 포함 된 줄을 찾고 해당 줄에서 'test'라는 단어의 모든 인스턴스를 'production'으로 변경하는 스크립트 (이상적으로는 한 줄짜리)를 작성하고 싶습니다. 'test'라는 단어가 해당 파일의 다른 위치에있을 수 있으며 변경하지 않기를 바랍니다. 분명히하기 위해 위의 줄을

('firmware_revision', str, 'my-firmware-name-production', 'Firmware revision name')

어떻게해야합니까?


5
sed매우 강력하고 기능 grep과 대체 기능을 모두 수행 할 수 있지만 라인이 어떻게 도움이되는지에 대한 자세한 정보가 필요합니다.
grochmal

원래 게시물에 더 많은 정보를 추가하겠습니다
John Allard

7
시도 :sed -i.bak '/firmware_revision/ s/test/production/' myfile.py
John1024

1
아 완벽하게 작동했습니다! 구문을 설명 할 수 있습니까?
John Allard

@JohnAllard 아주 좋아. 설명과 함께 답변을 추가했습니다.
John1024

답변:


22

시험:

sed -i.bak '/firmware_revision/ s/test/production/' myfile.py

여기에서 /firmware_revision/조건으로 작동합니다. 정규식 firmware_revision과 일치하는 줄은 true 이고 다른 줄은 false입니다. 조건이 참이면 다음 명령이 실행됩니다. 이 경우 해당 명령은 첫 번째 항목을 test로 대체하는 대체 명령입니다 production.

즉, 명령 s/test/production/은 정규식과 일치하는 행에서만 실행됩니다 firmware_revision. 다른 모든 선은 변경되지 않습니다.

기본적으로 sed는 출력을 표준 출력으로 보냅니다. 그러나 파일을 적절히 변경하려고했습니다. 그래서 우리는 -i옵션 을 추가했습니다 . 특히, 확장명으로 -i.bak저장된 백업 사본으로 파일이 제자리에서 변경되도록 .bak합니다.

명령이 당신에게 적합하다고 결정하고 위험한 삶을 살고 백업을 만들지 않으려면 GNU sed (Linux)와 함께 다음을 사용하십시오.

sed -i '/firmware_revision/ s/test/production/' myfile.py

반대로 BSD (OSX)에서는 -i옵션에 인수가 있어야합니다. 백업을 유지하지 않으려면 빈 인수를 제공하십시오. 따라서 다음을 사용하십시오.

sed -i '' '/firmware_revision/ s/test/production/' myfile.py

편집하다

질문을 편집 할 때 OP는 줄에서 발생 하는 모든 항목 test을로 바꿉니다 production. 이 경우 전역 (해당 회선의) 교체에 대한 g대체 명령에 옵션을 추가합니다 .

sed -i.bak '/firmware_revision/ s/test/production/g' myfile.py

5
완성도를 높이기 위해 해당 -i.bak부분 을 설명 할 수도 있습니다.
Stephen Harris

5
@StephenHarris 좋은 지적입니다. -i추가 설명 .
John1024

나는 당신이 아마 별에 도달 할 수 있다고 생각합니다. 단지 sed할 수있는 모든 것을 설명하는 책에 서서 …
KlaymenDK

하지 BSD 사람들을 위해 John1024 @, 첫 번째의 이유를 추가 할 수 있습니다 ''후를 -i?
Hastur

3
OP는 해당 줄에서 'test'라는 단어의 모든 인스턴스를 'production' 으로 변경 하려고했습니다 . 이 경우 sed 명령에 / g를 추가하는 것이 중요합니다. sed -i '/firmware_revision/ s/test/production/g' myfile.py그렇지 않으면 첫 번째 인스턴스 만 변경됩니다.
knub

4

sed옵션을 지원하지 않는 구식 컴퓨터가있는 구형 컴퓨터 -i:

TF=$( mktemp -t "${0##*/}"_$$_XXXXXXXX ) && \
trap 'rm -f "$TF"' EXIT HUP INT QUIT TERM && \
sed '/firmware_revision/ s/test/production/' myfile.py >"$TF" && \
mv -f "$TF" myfile.py

1
이러한 구형 컴퓨터에서는 간단히 ed한 줄로 사용 하고 수행 할 수 있습니다 .printf %s\\n g/firmware_revision/s/test/production/g w q | ed -s myfile.py
don_crissti

1
@don_crissti 매우 사실이지만 ed(1)의 사용을 보여줄 어떤 구실도 제공하지 않습니다 mktemp(1).
사토 카츠라

임시 파일을 사용하는 경우 원본 파일의 inode 및 파마를 동일하게 유지할 수 있습니다 ed. 대신을 mv -f "$TF" myfile.pl사용하십시오 cat "$TF" > myfile.pl && rm -f "$TF". BTW, 소문자 변수 이름을 사용하는 것이 좋습니다 ( $tf대신 $TF), bash 내장 vars (아마도 다른 Bourne 쉘)와 충돌하지 않도록 보장합니다.
cas

@cas Re : cat "$TF" > myfile.pl: 시도해보십시오 : touch a b; chmod 0444 a; cat b >a(BTW, sed -i이 경우에도 작동하지 않습니다). 사용자가 더 잘 처리하도록하십시오. 다시 : rm -f "$TF": 필요하지 않습니다 참조하십시오 trap ... EXIT. 다시 : $tf대신 $TF: 아마; 그것은 스타일의 문제입니다.
사토 카츠라

그것은 유닉스 파일 권한의 정상적인 동작입니다. 내 요점은 새 파일을 만들고 원본보다 mv-ing하면 파일 이름에 대한 새로운 inode가 발생한다는 것입니다 (하드 링크 끊기). 2. 전류 umask 가 원래의 파마와 다르면 아마도 파마를 바꿉니다 . 대문자 변수의 경우 스타일의 문제가 아닙니다. 대문자 PATH, RANDOM 또는 SHELL을 사용하는 실수를 저지른 사람이나 자신의 변수에 대한 모든 것이 어려운 방법을 찾았습니다. (그리고 예, 나는 종종 대문자 vars를 사용합니다. 그것이 잘못되었다는 것을 알고 있습니다, 나는 습관을 깰려고합니다.)
cas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.