Иногда я запускаю длинные 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'
Поскольку мы, вероятно, хотели бы знать, когда файл «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
не было съедено.
решение4
Ни то, time
ни другое env
у меня не сработало (они передают возвращаемое значение своей дочерней программы), поэтому я написал bliss
:
#!/bin/sh
"$@"
exit 0
затемchmod u+x ~/bliss
и что-то вродеfind_or_similar | xargs ~/bliss fatally_dying_program.sh