長時間のxargs
ジョブを夜間に実行することがあり、今晩のように、たとえば 1 つの特殊なケースでセグメンテーション エラーが発生したためにジョブが途中で停止したことを朝になって発見するのはxargs
本当にイライラします。
たとえ 1 つの子xargs
プロセスが強制終了されたとしても、それ以上の入力は処理されません。
コンソール 1:
[09:35:48] % seq 40 | xargs -i --max-procs=4 bash -c 'sleep 10; date +"%H:%M:%S {}";'
xargs: bash: terminated by signal 15
09:35:58 3
09:35:58 4
09:35:58 2
<Exit with code 125>
コンソール2:
[09:35:54] kill 5601
xargs
子プロセスが終了したら、それ以上の入力の処理を停止せずに、処理を続行することはできますか?
答え1
いいえ、できません。xargs
savannah.gnu.org のソース:
if (WEXITSTATUS (status) == CHILD_EXIT_PLEASE_STOP_IMMEDIATELY)
error (XARGS_EXIT_CLIENT_EXIT_255, 0,
_("%s: exited with status 255; aborting"), bc_state.cmd_argv[0]);
if (WIFSTOPPED (status))
error (XARGS_EXIT_CLIENT_FATAL_SIG, 0,
_("%s: stopped by signal %d"), bc_state.cmd_argv[0], WSTOPSIG (status));
if (WIFSIGNALED (status))
error (XARGS_EXIT_CLIENT_FATAL_SIG, 0,
_("%s: terminated by signal %d"), bc_state.cmd_argv[0], WTERMSIG (status));
if (WEXITSTATUS (status) != 0)
child_error = XARGS_EXIT_CLIENT_EXIT_NONZERO;
そのチェック、またはそれを呼び出す関数の周囲にはフラグがありません。これは最大プロセス数に関連しているようですが、それは理にかなっていると思います。最大プロセス数を十分に高く設定すると、制限に達するまでチェックが行われなくなり、制限に達することがなくなる可能性があります。
あなたがしようとしていることに対するより良い解決策は、GNU メイク:
TARGETS=$(patsubst %,target-%,$(shell seq 1 40))
all: $(TARGETS)
target-%:
sleep 10; date +"%H:%M:%S $*"
それから:
$ make -k -j4
同じ効果が得られ、より優れた制御が可能になります。
答え2
最も明白な口語表現の 1 つは、他の提案によってのみ暗示されているようです。
つまり、次のものを使用できます。
bash -c '$PROG_WHICH_MAY_FAIL ; (true)'
「成功を強制する」ために。
これは、ロルニックス(ただ、言葉では言い表せないだけです)。
いずれにせよ、これは実際のプロセス終了ステータスを事実上無視しているので、事後分析のためにサブプロセス ステータスを何らかの方法で保存することを検討してください。例:
bash -c '$PROG_WHICH_MAY_FAIL || touch failed; (true)'
ここtrue
では多少冗長なので、次のように記述した方がよいでしょう。
bash -c '$PROG_WHICH_MAY_FAIL || touch failed'
おそらく、'失敗した'ファイルがいつ変更できなかったのか知りたいと思うでしょう。言い換えれば、私たちはもはや無視する失敗は記録に残し、継続しています。
そして、この問題の再帰的な性質を考慮すると、おそらく私たちはまさになぜxargs では失敗を無視するのは簡単ではありません。それは決して良い考えではないからです。代わりに、開発中のプロセス内でエラー処理を強化する必要があります。しかし、この概念は「Unix 哲学」自体に内在していると思います。
最後に、これは James Youngman が を推奨することでほのめかしていることでもあり、おそらく同様の方法で使用できると思いますtrap
。つまり、問題を無視しないでください... それを捕捉して処理しないと、ある日目覚めたときにサブプログラムのどれもまったく成功しなかったことに気付くかもしれません ;-)
答え3
使用trap
:
$ seq 40 | xargs -i --max-procs=4 bash -c \
'trap "echo erk; exit 1" INT TERM; sleep 10; date +"%H:%M:%S {}";' fnord
16:07:39 2
16:07:39 4
erk
16:07:39 1
^C
erk
erk
erk
erk
あるいは、シェルから別の言語に切り替えて、シグナル ハンドラーを設定することもできます。
また、 によって生成された最初の単語が消費されないように、 が取るbash -c foo..
値$0
(ここでは) を指定する必要があることにも注意してください。fnord
seq
答え4
どちらも私には機能しtime
ませんでしたenv
(子プログラムの戻り値を渡す) ので、次のように書きましたbliss
:
#!/bin/sh
"$@"
exit 0
それからchmod u+x ~/bliss
そして、find_or_similar | xargs ~/bliss fatally_dying_program.sh