おやすみなさい、
以下は私のスクリプトで使用するコードです。 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 です。
私のDebianシステムでは/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'
これは、パイプの左側でサブプロセスが開始されても動作し、すべて停止します。