스크립트 내의 tee /dev/stderr은 stderr이 리디렉션되는 경우 출력 파일을 자릅니다.

스크립트 내의 tee /dev/stderr은 stderr이 리디렉션되는 경우 출력 파일을 자릅니다.

다음과 같은 스크립트가 주어지면 stderr을 파일로 리디렉션하려고 하면 파일이 tee사용될 때 잘립니다.

$ cat test.sh 
#!/bin/bash

set -eux
echo before
echo '{ "foo": "bar" }' | tee /dev/stderr | jq .foo
echo after
$ ./test.sh 2> log
before
"bar"
after
$ cat log 
{ "foo": "bar" }
+ echo after

log파일에는 모든 stderr 출력이 포함되어야 합니다. 리디렉션하지 않고 동일한 스크립트를 실행하면 다음과 같이 표시됩니다.

$ ./test.sh
+ echo before
before
+ echo '{ "foo": "bar" }'
+ tee /dev/stderr
+ jq .foo
{ "foo": "bar" }
"bar"
+ echo after
after

그러면 왜 나는 나타나는 줄만 볼 수 있습니까?뒤쪽에 tee? 사용해도 2>>별 도움이 되지 않는 것 같습니다.

왜 이런 일이 발생하는지 이해하지 못합니다. 전체 스크립트의 표준 오류를 파일로 리디렉션하는 기능을 유지하면서 출력을 얻으려면 어떻게 해야 합니까?

답변1

이는 Linux에서 작동하는 방식 때문 /dev/stderr입니다 /proc/$pid/fd/$num. 저기, /dev/stderr진짜로 열려아니요파일 설명자 2를 반복하고 대신 fd로 직접 연결된 리소스에 액세스합니다.

따라서 tee일반적으로 쓰는 파일을 자르므로 tee /dev/stderr. 귀하의 경우 이는 tee log.

바라보다var=$(</dev/stdin) stdin을 변수로 읽는 데 어떤 문제가 있나요?더 알아보기.


이는 Linux에서만 발생하는 문제입니다. 예를 들어 macOS에서는 상상하는 대로 작동합니다. 다소 압축된 예:

linux$ bash -xc 'false; echo "truncated?" | tee /dev/stderr >/dev/null; true' 2>log
linux$ cat log
truncated?
+ true

~에 맞서

mac$ bash -xc 'false; echo "truncated?" | tee /dev/stderr >/dev/null; true' 2>log
mac$ cat log
+ false
+ tee /dev/stderr
+ echo 'truncated?'
truncated?
+ true

이제 이것이 작동하려면 그것을 사용하는 것을 피하고 /dev/stderr대신 >&2쉘에 파일 설명자 2를 복사하라고 지시하는 것과 같은 것을 사용해야 합니다.

나는 당신이 이것을 할 수 있다고 생각합니다 tee >( cat >&2 ). 이것은 약간 복잡하지만 tee기존 fd를 사용하라고 말할 수는 없습니다.파일 이름, 위의 문제로 인해 스크립트의 stderr을 직접 참조할 수 없습니다.

cat그러나 아래와 같이 백그라운드에서 실행되므로 출력이 지연될 수 있다는 문제가 있습니다 .

linux$ bash -xc 'false; echo "truncated?" | tee >(cat >&2) >/dev/null; true' 2>log
$ cat log
+ false
+ echo 'truncated?'
+ tee /dev/fd/63
++ cat
+ true
truncated?

이는 모든 쓰기가 파일 끝으로 이동한다는 것을 tee -a /dev/stderr의미하지만 원시 stderr를 통해 작성된 모든 것은 도움이 되지 않는다는 점에 유의하십시오.tee아니요, 그러나 해당 파일에 설명된 쓰기 위치를 따릅니다. 그래서 당신은 다음과 같은 것을 얻게 될 것입니다 :

$ bash -xc 'false; echo "truncated?" | tee -a /dev/stderr >/dev/null; true' 2>log
$ cat log
+ false
+ echo 'truncated?'
+ tee -a /dev/stderr
+ true
ed?

마지막 항목 + true<nl>(스크립트의 stderr)은 truncated?(from tee)에 기록됩니다. 또한 원래 리디렉션을 추가된 리디렉션(예: )으로 만들어야 합니다 bash ... 2>>log.

아니면 원본을 파일 대신 파이프로 리디렉션하면 됩니다. 파이프를 사용하면 /dev/stderr파이프에 쓰기 위치가 없고 잘릴 수 없기 때문에 상상하는 것과 더 비슷하게 작동합니다. 다만 그 방법이 조금 복잡해서 그런 것이 필요할 뿐입니다 2> >(cat > log).

답변2

이 글을 쓰면서 나는 이 tee -a옵션이 나에게도 가능하다는 것을 깨달았습니다.

tee /dev/stderr이것이 리디렉션된 파일을 자르는 이유를 아직도 잘 이해하지 못합니다.

관련 정보