리디렉션 시 문자열 추가

리디렉션 시 문자열 추가

모든 출력을 stderr로 리디렉션하는 경우:

stat file >&2

...명령에서 오류가 발생하는 경우(예: 파일이 존재하지 않는 경우) 다음과 같이 임의의 텍스트를 앞에 추가하려면 어떻게 해야 하나요?

<<MY ARBITRARY TEXT>>: stat: cannot stat 'file': No such file or directory

필요한 논리는 다음과 같습니다.

let res = stat file
if error then output "<<MY ARBITRARY TEXT>>"+error to stderr
else output res to stderr

추가 컨텍스트: stdout 및 stderr 스트림은 항상 올바른 순서로 반환되므로 모든 명령 출력은 stderr로 리디렉션됩니다. 즉, 여러 명령이 전송되고 그 중 하나가 오류를 발생시키는 경우 다음 명령의 stdout이 원본의 stderr에 있을 수 있습니다. 명령을 반환하기 전에 명령을 수행하십시오. 이를 방지하기 위해 모든 명령을 stderr에 통합했지만 이상적으로는 오류를 쉽게 식별할 수 있기를 원합니다.

답변1

긴 이야기 짧게: stderr을 동적으로 구문 분석하는 것은 복잡할 수 있으므로 stderr을 변수에 저장하고 나중에 변수 내용을 조작하여 단순화합니다.

고려해야 할 사항은 stderr변수를 캡처한 다음 null이 아닌지 확인하는 것입니다. 다음 예를 고려하십시오.

$ foo=$(stat /etc/passwd 2>&1  > /dev/tty )
  File: /etc/passwd
  Size: 1710        Blocks: 8          IO Block: 4096   regular file
Device: fd00h/64768d    Inode: 537594      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2019-03-08 15:28:10.481688274 -0700
Modify: 2019-03-08 15:28:10.333669255 -0700
Change: 2019-03-08 15:28:10.341670283 -0700
 Birth: -
$ test "x$foo" = "x" && echo "empty"
empty

명령 대체는 $(...)서브쉘을 실행하고 stdout캡처만 수행하므로 이제 명령 대체를 통해 stderr을 캡처할 수 있도록 파일 설명자 1을 2로 복사하고 싶지만 2>&1여전히 화면에서 일반 출력을 보고 싶기 때문에 그 후에는 stdout제어를 가리킵니다. 터미널 /dev/tty.

이제 실제로 stderr을 변수로 캡처하면 어떻게 될까요?

$ foo=$(stat nonexistent.txt 2>&1  > /dev/tty )
$ test "x$foo" = "x" && echo "empty" || echo "not empty"
not empty
$ printf "<Arbitrary Text>%s\n" "$foo"
<Arbitrary Text>stat: cannot stat 'nonexistent.txt': No such file or directory

보시다시피, stderr캡처되었기 때문에 원하는 경우 임의의 텍스트를 둘러쌀 수 있습니다. 변수를 사용하는 주된 이유는 표준 셸 방법(예: 파이프 및 명령 대체)이 stdout파일 설명자 1에서 작동하므로 동적 구문 분석을 많이 수행할 수 없기 때문입니다 stderr. 물론 명명된 파이프를 사용하여 리디렉션할 수 있지만 stat foobar.txt 2> /tmp/named_pipe.fifo이 문제는 차단입니다. 파이프로 전송된 정보는 다른 프로세스에서 소비될 때까지 버퍼링되므로 쉘 스크립트가 중단됩니다. 물론 이는 백그라운드 프로세스를 시작하여 처리할 수 있지만 IMHO는 필요한 것보다 더 복잡하며 실제로 다중 처리 호출에 직접 액세스할 수 있는 Python과 같은 프로그래밍 언어를 사용하여 다중 프로세스를 수행하는 것이 훨씬 좋습니다.

stdout과 stderr을 모두 별도의 변수로 처리하려면,좋은 예가 있습니다스택 오버플로에서는 명명된 파이프와 일부 셸별 메서드/트릭을 통해 이를 수행할 수 있습니다.

참고 사항: testand [는 동일한 명령이므로 [ "x$foo" = "x" ]더 자세한 if-else 문에서 작성하고 사용할 수도 있습니다.

답변2

당신이 하고 싶은 일을 아주 간단하게 성취할 수 있습니다.

1) 파일의 출력을 복원해야 하는 경우 foobar:

 $ (echo "Arbitrary text" && stat /etc/passwd ) 2>&1 | tee foobar

2) 더 간단히 말하면, 관심 있는 모든 내용이 다음으로 출력되는 경우 stdout:

 $ (echo "Arbitrary text" && stat /etc/passwd ) 2>&1

관련 정보