SED를 사용하여 첫 번째 일치 후 전체 줄을 검색하고 바꾸시겠습니까?

SED를 사용하여 첫 번째 일치 후 전체 줄을 검색하고 바꾸시겠습니까?

다음 형식을 사용하는 파일이 있습니다.

M104 S200
M107
M104 S250
M110
M104 S275

M104나는 두 번째 항목을 일치시키고 다른 항목도 포함하도록 전체 줄을 다시 작성하는 방법을 찾으려고 노력하고 있습니다 M104.

나는 노력했다

sed 's/^M104/s/.*/M104 S300/' file - but it replaces all instances of M104
sed '0,/M104/s//M104 S200/' file - leaves the trailing text on the line
  • 다른 변경 사항으로 인해 예상치 못한 결과가 발생했습니다. 도움이 필요하세요? ;)

답변1

Perl이 있다면 다음과 같이 할 것입니다:

$ perl -pe 'if (/M104/) { $i++; if($i == 2) { $_ = "M104 S999\n" } } ' test.txt
M104 S200
M107
M104 S999
M110
M104 S275

/M104/, 일치하면 증가시킨 $i다음 2와 같은지 확인하고 $i, 그렇다면 현재 줄을 바꿉니다(후행 줄 바꿈 포함 \n) .

s/^M104.*/.../거기에서 sed와 같은 대체품을 사용하려면 마지막 부분에서 그렇게 할 수 있습니다.

-i[extension]Perl에는 백업 파일 유무에 관계없이 내부 변경을 수행할 수 있는 sed와 유사한 옵션이 있습니다 .

또는 환경 변수를 통해 키 값을 전달합니다(스크립팅이 더 쉬워집니다).

n=2 repl="S999" perl -pe 'if (/M104/) { $i++; if($i == $ENV{n}) { $_ = "M104 " . $ENV{repl} . "\n" } } ' test.txt

(또는 예를 들어 중첩보다 연결을 선호하는 경우 perl -pe '/M104/ and $i++ and $i == 2 and $_ = "M104 S999\n" ' test.txt.)


또는 awk에서:

$ awk '/M104/ { i++; if (i == 2) $0 = "M104 S999"; } 1' test.txt

그러나 awk에는 표준 내부 옵션이 없습니다.

답변2

귀하의 (실패한) 시도는 귀하의 sed버전이 0범위 시작을 허용한다는 것을 의미합니다 (모든 sed것이 이것을 수행하는 것은 아닙니다). 그렇다면 시도해 보세요.

sed -rn '0,/^M104/{p;b;}; 0,/(^M104).*/ s//\1 S300/; p' file
M104 S200
M107
M104 S300
M110
M104 S275

아이디어는 주소 범위를 두 번 적용하는 것입니다. 첫 번째 범위는 첫 번째 일치까지 변경되지 않은 행을 찾아서 인쇄합니다. 두 번째 범위는 다음 게임을 대체합니다. 마찬가지로, sed두 번째 범위의 시작 주소가 첫 번째 범위에서 사용된 경우 모든 버전에서 두 번째 범위의 시작 주소를 허용하는 것은 아닙니다.

답변3

당신이 사용하는 경우암소 비슷한 일종의 영양 sed, 이 -z옵션을 사용하면 하나의 버퍼에서 전체 파일을 처리하고 s이를 숫자 플래그 명령의 숫자 플래그로 바꿀 수 있습니다.N첫 번째 발생:

sed -zE 's/(^|\n)M104[^\n]*/\1M104 S300/2'

두 번째 항목을 바꾸도록 지시합니다 2.sed

-E개행 또는 파일의 시작 부분을 일치시킬 수 있도록 확장 정규식(옵션)을 사용하고 있으며 \1개행을 유지하기 위해 일치( )를 다시 삽입합니다.

이것가지고 다닐 수 있는버전 -z옵션은 사용할 수 없으며 [^\n]"개행 문자를 제외한 모든 것"에는 허용되지 않으므로 홀딩 버퍼를 사용하여 줄을 수집하고 줄에 인쇄 가능한 문자만 포함될 것으로 예상합니다.

sed -E 'H;1h;$!d;x;s/(^|\n)M104[[:print:]]*/\1M104 S300/2'

또한 매우 큰 파일의 경우 버퍼가 너무 클 수 있습니다.

관련 정보