如何使“xargs”忽略子进程的退出并继续进一步处理

如何使“xargs”忽略子进程的退出并继续进一步处理

我有时会xargs在一夜之间运行很长时间的工作,早上发现工作xargs在中间的某个地方死掉了,这真的很烦人,例如,由于一个特殊情况下的分段错误,就像今晚发生的那样。

即使有一个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

似乎最明显的口语之一只是其他提案中提到的。

也就是说,您可以使用以下内容:

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

或者从 shell 切换到另一种语言,您也可以在其中设置信号处理程序。

另请注意,在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

相关内容