좋은 저녁이에요,
다음은 내 스크립트에서 사용하는 코드입니다. SSH 세션에서 시작하면 제대로 작동하지만 cron을 통해 실행하면 화면에 파이프 파손 오류가 표시됩니다.
SSH를 통해 재현할 수 없습니다.
암호:
IP=$(sort --random-sort /root/ips.csv | head -n 1); nc -zv -w 2 $IP 443 2>&1 | grep succeeded >> outfile
화면 오류:
sort: write failed: standard output; Broken pipe
sort: write error
어떤 팁이나 조언이 있나요?
감사합니다!
답변1
첫 번째 줄 처리가 끝나면 head
파이프의 다른 쪽 끝을 닫고 종료됩니다. sort
계속해서 더 쓰려는 시도가 있을 수 있으며 닫힌 파이프나 소켓에 쓰면 EPIPE 오류가 반환됩니다. 그러나 SIGPIPE 신호도 발생시켜 신호를 무시하거나 처리하지 않는 한 프로세스를 종료합니다. 신호를 무시하면 sort
오류가 표시되고 불평하고 종료됩니다. 이 신호를 무시하지 않으면 sort
당신은 죽게 됩니다.
우리는 사용할 수 있습니다trap
내장쉘의 신호가 무시되고 오류가 발생합니다.
$ trap "" PIPE
$ sort bigfile | head -1 > /dev/null
sort: write failed: standard output: Broken pipe
sort: write error
하지만 안타깝게도 우리는할 수 없다trap
신호를 무시하지 않고 다음과 같은 원하는 동작을 얻는 데 사용됩니다 .POSIX 요구 사항이 작업은 비대화형 셸(스크립트)에서는 허용되지 않습니다. 대화형 쉘을 허용하지만 Bash는 trap
이 경우에도 그렇게 하지 않습니다.
테스트하려면:
sh$ trap '' PIPE # ignore the signal
sh$ PS1='another$ ' bash # run another shell
another$ trap - PIPE # try to reset the signal
# it doesn't work
another$ sort bigfile |head -1 > /dev/null
sort: write failed: 'standard output': Broken pipe
sort: write error
대신 Perl one-liner와 같은 외부 도구를 사용하여 스크립트나 명령을 실행할 수 있으며 신호는 무시되지 않습니다( sort
여기에서는 자동으로 종료됩니다).
another$ perl -e '$SIG{PIPE}="DEFAULT"; exec "@ARGV"' \
'sort bigfile |head -1' > /dev/null
another$
귀하의 크론 상황은 그 이유가 체계화되어 있을 수 있습니다.분명히 SIGPIPE는 기본적으로 무시됩니다., 언급됨:
[SIGPIPE]는 일반 데몬에는 그다지 유용하지 않으며, 데몬에 유용하고 좋은 실행 환경을 제공하려고 할 때는 이 기능을 해제합니다. 물론 쉘이나 다른 것이 다시 열어야 합니다.
물론 이것도 언급됐지만문서(systemd.exec)에서:
IgnoreSIGPIPE=
부울 매개변수를 사용합니다. true인 경우 실행 프로세스에서 SIGPIPE가 무시됩니다. SIGPIPE는 일반적으로 쉘 파이프에서만 유용하므로 기본값은 true입니다.
내 데비안 시스템에서는/lib/systemd/system/cron.service
명시적 설정IgnoreSIGPIPE=false
, cron에 대한 시스템 기본값을 실행 취소합니다. 이것이 귀하의 경우에 도움이되는지 확인하고 싶을 수도 있습니다.
답변2
어쨌든 GNU 확장 이므로 동일한 GNU 유틸리티 컬렉션(GNU ) 의 GNU를 --random-sort
사용할 수도 있습니다 .shuf
coreutils
ip=$(shuf -n 1 ips.tsv)
SIGPIPE 문제를 피하는 것 외에도 GNU 처럼 전체 파일을 섞을 필요가 없기 때문에 더 효율적입니다 sort --random-sort
.shuf
저수지 샘플링연산그러기 위해서는 많은 투자가 필요합니다.)
답변3
일반적인 솔루션으로 이 Bash 기능을 사용하면 파이프 파손 오류가 발생하지 않고 다른 가능한 오류 메시지를 숨기지 않고 파이프라인을 실행할 수 있습니다.
entire_pipe() {
( set -m; (
trap 'exit 0' INT
echo $BASHPID
$1
) & wait $! ) |
(
trap 'trap - EXIT; kill -s INT -- -$pid 2>/dev/null || :' EXIT
read -r pid
$2
)
}
$BASHPID
휴대성을 높이 려면 $(exec sh -c 'echo "$PPID"')
.
이 문제가 발생했을 때 해당 기능을 사용하려면 교체가 필요합니다.
sort --random-sort /root/ips.csv | head -n 1
통과
entire_pipe 'sort --random-sort /root/ips.csv' 'head -n 1'
이는 파이프의 왼쪽에서 하위 프로세스가 시작되는 경우에도 작동하며 모두 중단됩니다.