Как заставить `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'

Поскольку мы, вероятно, хотели бы знать, когда файл «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

Связанный контент