Como fazer com que `xargs` ignore a saída da criança e continue processando

Como fazer com que `xargs` ignore a saída da criança e continue processando

Às vezes faço xargstrabalhos longos durante a noite e é muito chato descobrir pela manhã que xargsmorreu algures no meio, por exemplo devido a uma falha de segmentação num único caso especial, como aconteceu esta noite.

Se pelo menos um xargsfilho for morto, ele não processará mais nenhuma entrada:

Consola 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>

Consola 2:

[09:35:54] kill 5601

Posso, de alguma forma, impedir xargsa interrupção do processamento de mais entradas quando um processo filho morrer e, em vez disso, continuar o processamento?

Responder1

Não, você não pode. Dexargsfontes em 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;

Não há sinalizador em torno dessa verificação ou na função que a chama. Parece estar relacionado ao max procs, o que suponho que faz sentido: se você definir max procs alto o suficiente, não será necessário verificar até atingir o limite, o que talvez nunca aconteça.

Uma solução melhor para o que você está tentando fazer pode ser usarGNU Make:

TARGETS=$(patsubst %,target-%,$(shell seq 1 40))

all: $(TARGETS)

target-%:
    sleep 10; date +"%H:%M:%S $*"

Então:

$ make -k -j4 

terá o mesmo efeito e lhe dará um controle muito melhor.

Responder2

Parece que um dos coloquialismos mais óbvios só é aludido por outras propostas.

Ou seja, você pode usar o seguinte:

bash -c '$PROG_WHICH_MAY_FAIL ; (true)'

para "forçar o sucesso".

Observe que isso está de acordo com a proposta deLórnix(só não com tantas palavras).

De qualquer forma, como isso está efetivamente ignorando o status real de saída do processo, eu garantiria que você considerasse de alguma forma salvar o status do subprocesso para análise post-mortem. Por exemplo:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed; (true)'

O trueaqui é um tanto redundante e, portanto, pode ser melhor escrito como:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed'

Já que provavelmente gostaríamos de saber quando o arquivo 'com falha' não pôde ser tocado. Em outras palavras, não estamos maisignorandoa falha, estamos tomando nota e continuando.

E, depois de considerar a natureza recursiva desta questão, talvez vejamos exatamentepor quexargs não facilita ignorar falhas. Porque nunca é uma boa ideia - você deveria aprimorar o tratamento de erros no processo que está desenvolvendo. Acredito que esta noção, entretanto, seja mais inerente à própria "filosofia Unix".

Finalmente, suponho que é também a isso que James Youngman alude ao recomendar trap, que presumivelmente poderia ser usado de maneira semelhante. Ou seja, não ignore o problema... prenda-o e resolva-o ou você acordará um dia e descobrirá que nenhum dos subprogramas teve sucesso ;-)

Responder3

Usar 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

Como alternativa, mude do shell para outro idioma no qual você também possa definir manipuladores de sinal.

Observe também que depois bash -c foo..você deve especificar o valor que $0deve receber (aqui, fnord) para que a primeira palavra produzida por seqnão seja comida.

Responder4

Nem timenem envfuncionou para mim (eles repassam o valor de retorno de seu programa filho), então escrevi bliss:

#!/bin/sh
"$@"
exit 0

entãochmod u+x ~/bliss

e algo comofind_or_similar | xargs ~/bliss fatally_dying_program.sh

informação relacionada