如何使“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

相關內容