`xargs` が子プロセスの終了を無視して処理を継続するようにする方法

`xargs` が子プロセスの終了を無視して処理を継続するようにする方法

長時間の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

いいえ、できません。xargssavannah.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(ここでは) を指定する必要があることにも注意してください。fnordseq

答え4

どちらも私には機能しtimeませんでしたenv(子プログラムの戻り値を渡す) ので、次のように書きましたbliss:

#!/bin/sh
"$@"
exit 0

それからchmod u+x ~/bliss

そして、find_or_similar | xargs ~/bliss fatally_dying_program.sh

関連情報