「xargs」が子の出口を無視し、さらに処理を続ける方法


24

xargs夜間に長時間仕事をすることもありますが、午前xargs中にどこかで途中で死亡したことを発見するのは本当に迷惑です。たとえば、今夜のように1つの特別なケースでセグメンテーションエラーが発生したためです。

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子プロセスが終了すると、入力の処理を停止することをどうにかして防ぐことができますか?


私はxargsバージョン4.4.2 を使用しdebian wheezyていますが、特定のsleepプロセスを強制終了してもすべてが正常に実行されるようです。どのバージョンxargsを使用していますか?最新バージョンの問題を修正した可能性があります。
カンナンモハン14

パーティーに少し遅れましたが、どうxargs ... bash -c '...;exit 0'xargs ... bash -c '... || echo erk'
ですか

これparallel -j 1はハッキングの可能性があることに注意してください。
バリーカーター

回答:


25

いいえ、できません。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;

そのチェックの周り、またはそれを呼び出す関数の周りにフラグはありません。これはmax procに関連しているように思えますが、これは理にかなっていると思います:max procを十分に高く設定すると、制限に達するまでチェックしなくなります。

あなたがやろうとしていることに対するより良い解決策は、GNU Makeを使用することです:

TARGETS=$(patsubst %,target-%,$(shell seq 1 40))

all: $(TARGETS)

target-%:
    sleep 10; date +"%H:%M:%S $*"

次に:

$ make -k -j4 

同じ効果があり、はるかに優れた制御が可能になります。


9

最も明白な口語表現の1つは、他の提案によってのみ暗示されているように思われます。

つまり、次を使用できます。

bash -c '$PROG_WHICH_MAY_FAIL ; (true)'

「成功を強制する」ため。

これは、lornixによる提案の線に沿っていることに注意してください(あまり多くの言葉ではありません)。

とにかく、これは実際のプロセス終了ステータスを事実上無視しているため、事後分析のためにサブプロセスステータスを何らかの方法で保存することを検討してください。例えば:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed; (true)'

trueここでは、やや冗長で、これは、より良いように記述することができるようです。

bash -c '$PROG_WHICH_MAY_FAIL || touch failed'

おそらく、「失敗した」ファイルにいつ触れられなかったかを知りたいと思うからです。言い換えれば、私たちはもはや失敗を無視しているのではなく、注意を払い続けています。

そして、この問題の再帰的な性質を検討した後、おそらく xargsが失敗を無視することを容易にしない理由を正確に理解するでしょう。決して良いアイデアではないため、開発中のプロセス内でエラー処理を強化する必要があります。ただし、この概念は「Unix哲学」自体に固有のものであると思います。

最後に、これはジェームズ・ヤングマンが推奨することによって暗示するものでもあると思います。これは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


2

そこに別のコマンドを入力して、死にかけているプログラムからの信号を「食べる」。

問題を証明するために最初に示されたように、私はあなたの例を試しました... 'killall sleep'はスリーププロセスを中断し、bashを中断し、xargsが終了します。

テストとして、xargsとbashの間に「別のコマンドを実行」タイプのコマンドを挿入しました...この場合は「/ usr / bin / time」です。今回(駄目ではない)、killall sleepはスリーププロセスを強制終了しますが、xargsは続行します。

時間の出力を/ dev / nullにパイプします。これにより、既存のプロセスを大幅に書き換えることなく、まさに探していることを実行できます。

「/ usr / bin / time」からのstderrチャタリングなしで同じことをする別のプログラムを思い付くことができるかどうか、しばらく考えてみてください。あるいは、自分で書いても、それは単なる「フォーク」(またはexec()派生物)です。

'/ usr / bin / time'を使用することを忘れないでください。bashの組み込みの 'time'が信号の同じ 'eating'を行うかどうかはわかりません。


1
timeこの目的のための適切な代替手段envは、実行するプログラムの環境にゼロ以上のオプション変数を追加するだけなので、になります。独自の出力は生成されず、呼び出されたプログラムの戻りコードは、呼び出されたものに戻されenvます。
ジェームズ・スニーリンガー

{Chuckle}この記事を書いてしばらくして、私はそのことを考えました。「何かを実行する」コマンドとして頭に浮かんだのは時間でした。しかしうまく動作します。おめでとうございます。
lornix

2

どちらtimeenv私のために働いていない(彼らは子プログラムの戻り値を渡す)ので、私は書いたbliss

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

それから chmod u+x ~/bliss

のようなもの find_or_similar | xargs ~/bliss fatally_dying_program.sh

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.