Bash 파이프, 스트림 복사 및 각 줄에서 다른 명령 실행

Bash 파이프, 스트림 복사 및 각 줄에서 다른 명령 실행

출력의 두 번째 줄에서 다른 명령을 어떻게 실행할 수 있나요?

예를 들어, echo foo | sed p어떤 출력이 있습니까?

foo
foo

sed 's/foo/bar/'나는 그 중 하나를 실행하여 얻고 싶습니다 .

bar
foo

답변1

존재하다

$ echo foo | sed p
foo
foo

첫 번째 것은 foo명령에 의해 인쇄되고 p, 두 번째 것은 패턴 공간이 루프의 끝(다음 줄을 읽기 직전)에 인쇄되기 -n때문에 인쇄되지 않습니다.sed

foo그래서 그것을 얻으려면 bar다음과 같습니다.

$ echo foo | sed 'p;s/foo/bar/'
foo
bar

또는:

$ echo foo | sed -n 'p;s/foo/bar/p'
foo
bar

bar대체가 있는 경우에만 인쇄합니다( s대체에 성공하면 플래그가 있는 명령으로).p

bar, 를 얻으려면 이전 원래 줄을 foo가져와 h교체 결과를 인쇄한 후 복원합니다.

$ echo foo | sed 'h;s/foo/bar/p;g'
bar
foo

답변2

데이터의 첫 번째 줄에 영향을 주지 않는 명령을 실행하려면 서브셸에서 해당 명령을 실행하고 다음과 같이 첫 번째 줄을 읽고 출력하는 명령을 앞에 붙입니다.

read -r line; echo "$line"   # pass first line unmodified
sed 's/foo/bar/'             # operate on rest of lines

전체 예는 다음과 같습니다.

$ echo foo | sed p | ( read -r line; echo "$line"; sed 's/foo/bar/')
foo
bar

답변3

입력 줄 번호에 따라 다른 작업을 수행할 수 있는 명령으로 이를 파이프하는 것이 더 좋습니다.

예를 들어 다음과 같습니다 sed.

$ printf 'foo\nfoo\n' | sed '2,$s/foo/bar/'
foo
bar

이는 sed의 주소 지정 구문을 사용하여 작업을 2 줄 s/foo/bar/부터 파일 끝까지( )까지의 줄로 제한합니다.2,$

( man sedGNU 버전, 더 읽기 쉽게 형식을 약간 변경함):

Sed 명령은 주소 없이 실행될 수 있습니다. 이 경우 명령은 주소가 있는 모든 입력 라인에서 실행됩니다. 이 경우 명령은 해당 주소와 일치하는 입력 라인에서만 실행됩니다. 이 경우 명령은 첫 번째 주소에서 시작하여 두 번째 주소까지 이어지는 라인의 포함 범위와 일치하는 모든 입력 라인에 대해 실행됩니다.

주소 범위에 관해 주의할 세 가지 사항은 다음과 같습니다.

  • 구문은 addr1, addr2입니다(즉, 쉼표로 주소를 구분함).

  • addr2가 이전 행을 선택하더라도 addr1과 일치하는 행은 항상 허용됩니다.

  • addr2가 정규식인 경우 addr1과 일치하는 행은 테스트되지 않습니다.

또는 awk:

$ printf 'foo\nfoo\n' | awk 'NR > 1 {gsub(/foo/,"bar")};1'
foo
bar

또는 펄:

$ printf 'foo\nfoo\n' | perl -p -e 's/foo/bar/ if $. > 1'
foo
bar

awk 및 perl 버전은 행 번호( NRawk의 경우, $.perl의 경우)가 1보다 큰지 여부를 테스트합니다.

관련 정보