我有時會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