tee
표준 출력이 no-op( ) 명령으로 파이프되면 아무것도:
인쇄되지 않으며 파일 크기는 0입니다.tee
표준 출력을 로 파이프하면cat
모든 것이 올바르게 인쇄되고 파일 크기가 0보다 큽니다.
다음은 이를 보여주는 코드 예제입니다(스크립트의 첫 번째 입력 매개변수에 따라 조건부).
#!/usr/bin/env bash
log_filepath="./log.txt"
[ -f "$log_filepath" ] && { rm "$log_filepath" || exit 1 ; }
fail_tee="$1"
while IFS= read -r -d $'\n' line ; do
printf "%s%s\n" "prefix: " "$line" | \
tee -a "$log_filepath" | \
{
if [ -n "$fail_tee" ]; then
# Nothing is printed to stdout/terminal
# $log_filepath size is ZERO.
: # do nothing.
else
# Each line in the input is prefixed w/ "prefix: " and sent to stdout
# $log_filepath size is 46 bytes
cat
fi
}
done <<'EOF'
1
23
456
7890
EOF
그 뒤에 설명이 있기를 바랍니다.
no-op 명령에 대한 나의 기대 는 출력이 파일로 전송되는 것을 :
방해해서는 안 된다는 것입니다 .tee
답변1
:
in은 여전히 셸에서 설정한 파이프의 읽기 끝을 유지하는 프로세스 tee ... | :
이고 다른 끝은 tee
쓰기입니다. 즉시 종료 되므로 :
파이프에서 데이터를 읽을 수 없습니다. (파이프라인이 작업을 동시에 수행하려면 쉘은 단지 no-op를 처리하기 위한 것일지라도 파이프라인의 각 부분에 대해 새 프로세스를 생성해야 합니다 :
. 귀하의 예에서 프로세스는 if
마지막 명령문을 실행합니다. :
내장 함수를 "실행"한 후 결국 종료됩니다 ).
일반적인 동작은 파이프 판독기가 종료될 때(읽기측 파일 설명자가 닫힘) 기록기가 다음 쓰기 시 SIGPIPE 신호를 수신하여 종료되도록 하는 것입니다.
이는 파이프라인의 오른쪽이 종료되면 왼쪽도 종료되고 잠재적으로 긴 작업이 쓸데없이 계속되지 않는다는 것을 의미하기 때문에 일반적으로 원하는 것입니다. 또는 (더 나쁜 경우) 데이터가 갈 곳이 없기 때문에 쓰기를 허용하지 않는 차단된 파이프에 무력하게 쓰기를 시도합니다.
tee
예외는 없을 것 같으 니까POSIX 사양;가장 가까운 부분에는 파일 피연산자에 대한 쓰기 오류가 언급되어 있습니다.
성공적으로 열린 파일 피연산자에 대한 쓰기가 실패하면 성공적으로 열린 다른 파일 피연산자 및 표준 출력에 대한 쓰기는 계속되어야 하지만 종료 상태는 0이 아니어야 합니다.
SIGPIPE가 무시되면 테스트한 구현이 계속 실행된 EPIPE
다음 호출에서 오류를 반환합니다 write()
.
GNU coreutils 버전에는 쓰기 실패 시 수행할 작업을 제어하는 옵션이 있습니다 tee
.-p
--output-error
지정되지 않은 경우 기본 작업은
--output-error
파이프에 쓰는 동안 오류가 발생하면 즉시 종료하고 비파이프라인 출력에 쓰는 동안 오류를 진단하는 것입니다.
종료 방법은 SIGPIPE를 통한 것이므로 tee
신호를 무시한 것부터 시작하면 종료되지 않습니다.
기본 모드 는 종료하도록 하는 다른 옵션과 달리 "파이프라인이 아닌 출력을 쓰는 동안 오류 진단" -p
입니다 . warn-nopipe
뒤에서는 SIGPIPE 신호도 무시한 다음 파이프에 쓰기 시도를 중지합니다.
따라서 적어도 GNU 버전에서는 tee -p ... | ...
이를 사용하여 파이프 판독기가 종료될 때 종료되는 것을 방지할 수 있습니다. 또는 예를 들어 블랙홀을 모방하도록 오른쪽에 프로그램을 배열할 수 있습니다 cat > /dev/null
(여전히 표시됨).그리고얻는 모든 것을 기록하지만 커널은 결국 기록된 데이터를 무시합니다 /dev/null
.)
답변2
이것은 :
nop 프로세스가 아닙니다. 이것은 cat
논란의 여지가 없습니다. stdin을 읽지 않고 stdout으로 전달합니다(이것은 nop가 아니기 때문에 nop 파이프라인 단계로 처리될 수 있다는 것을 보았지만 이는 또 다른 아이디어입니다). 이것은 과정이 아닙니다.
당신은 무엇이든 파이프하려고합니다. 케이싱의 용도는 모르겠지만 파이프가 아무 것에도 연결되어 있지 않아도 놀라지 않을 것입니다. (또는 쉘에 연결되어 무시될 수도 있습니다). 어쨌든 좋은 일이 일어나지 않았으면 좋겠어.
@Kusalananda가 말했듯이. 파이프는 출력에서 프로세스가 읽을 때까지 기다리지만(또는 적어도 파이프를 닫을 때) 어떤 프로세스도 파이프를 읽거나 닫을 수 없습니다. cat >/dev/null
[(다형성) 으로 파이프할 수 있습니다 . 또는 > /dev/null
(정적으로) 리디렉션할 수 있는 경우].
다음 중 하나(가능하면 고양이가 없는 것이 좋음)
| cat >/dev/null
>/dev/null
또 다른 다형성 솔루션(중복된 고양이 부스러기 방지):
if ...
then
out=/dev/stdout
else
out=/dev/null
fi
command >"$out"
답변3
는 :
stdin에서 읽지 않으므로 PIPE 신호를 생성합니다. PIPE 신호를 받은 후 tee(기본값)가 종료됩니다. 사용하면 :
모든 것이 중지됩니다.
--output-error=warn
GNU tee(bash를 사용한 이후 이미 사용했다고 가정)(te POSIX 옵션 아님)를 사용하는 경우 tee에 추가하여 이를 볼 수 있습니다.
다음을 사용하여 이를 테스트할 수 있습니다.
$ echo "hello" | tee --output-error=warn | :
tee: 'standard output': Broken pipe
:
로 변경하면 PIPE가 종료 cat >/dev/null
되는 것을 방지할 수 있습니다 .tee
하지만:쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?
텍스트 파일(여기 문서)을 한 줄씩 읽은 다음 파이프로 보내는 것은 최선의 선택이 아닙니다.
고려하다:
sed 's/^/preffix: /' <<'EOF' | tee -a "$log_filepath"
1
23
456
7890
EOF
변수 값을 기반으로 배열 내에서 티 옵션을 설정할 수도 있습니다.
또한 문서의 여기 대신 변수에 출력을 설정합니다.
#!/bin/bash --
log_filepath="./log.txt"
[ -f "$log_filepath" ] && { rm "$log_filepath" || exit 1 ; }
enable_stdout="${1:+"yes"}"
enable_log="yes" # comment this line to avoid logging.
out=$'1\n23\n456\n7890\n'
unset teeoptions; teeoptions=()
[ -n "$enable_stdout" ] && teeoptions+=(-a "/dev/tty")
[ -n "$enable_log" ] && teeoptions+=(-a "$log_filepath")
printf '%s' "$out" |
sed 's/^/preffix: /' |
tee "${teeoptions[@]}" >/dev/null