ソート:書き込み失敗|

ソート:書き込み失敗|

おやすみなさい、

以下は私のスクリプトで使用するコードです。 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使用することもできます。shufcoreutils

ip=$(shuf -n 1 ips.tsv)

SIGPIPEの問題を回避するだけでなく、GNUのようにファイル全体を混在させる必要がないため、より効率的ですsort --random-sortshuf貯水池サンプリング演算そのためには多くの投資が必要です。)

答え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'

これは、パイプの左側でサブプロセスが開始されても動作し、すべて停止します。

関連情報