Cómo hacer que `xargs` ignore la salida del niño y siga procesando

Cómo hacer que `xargs` ignore la salida del niño y siga procesando

A veces realizo xargstrabajos largos durante la noche y es realmente molesto descubrir por la mañana que xargsmurió en algún punto intermedio, por ejemplo debido a una falla de segmentación en un solo caso especial, como sucedió esta noche.

Si incluso un xargsniño muere, no procesa más entradas:

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

¿Puedo de alguna manera evitar xargsdetenerme para procesar más entradas una vez que un proceso secundario muere y, en su lugar, continuar procesando?

Respuesta1

No, no puedes. Desde elxargsfuentes en 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;

No hay ninguna bandera alrededor de esa verificación o de la función que la llama. Parece estar relacionado con los procesos máximos, lo cual supongo que tiene sentido: si estableces los procesos máximos lo suficientemente altos, no se molestará en verificar hasta que alcance el límite, que es posible que nunca llegue a ser.

Una mejor solución para lo que estás intentando hacer podría ser utilizarMarca GNU:

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

all: $(TARGETS)

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

Entonces:

$ make -k -j4 

tendrá el mismo efecto y le dará un control mucho mejor.

Respuesta2

Pareciera que uno de los coloquialismos más obvios sólo aluden otras propuestas.

Es decir, puedes utilizar lo siguiente:

bash -c '$PROG_WHICH_MAY_FAIL ; (true)'

para "forzar el éxito".

Tenga en cuenta que esto va en la línea de la propuesta delornix(pero no con tantas palabras).

De todos modos, dado que esto ignora efectivamente el estado de salida del proceso real, me aseguraría de que considere de alguna manera guardar el estado del subproceso para el análisis post-mortem. P.ej:

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

El trueaquí es algo redundante, por lo que podría escribirse mejor como:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed'

Ya que probablemente nos gustaría saber cuándo no se pudo tocar el archivo "fallido". En otras palabras, ya no estamospostergacióndel fracaso, vamos tomando nota y continuando.

Y, después de considerar la naturaleza recursiva de esta cuestión, tal vez veamos exactamentepor quéxargs no hace que sea fácil ignorar el fracaso. Porque nunca es una buena idea; en su lugar, debería mejorar el manejo de errores dentro del proceso que está desarrollando. Creo que esta noción, sin embargo, es más inherente a la propia "filosofía Unix".

Finalmente, supongo que esto es también a lo que alude James Youngman al recomendar trap, que presumiblemente podría usarse de manera similar. Es decir, no ignores el problema... atrápalo y manéjalo o te despertarás un día y descubrirás que ninguno de los subprogramas tuvo éxito en absoluto ;-)

Respuesta3

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

Alternativamente, cambie del shell a otro idioma en el que también pueda configurar controladores de señales.

Tenga en cuenta también que después bash -c foo..debe especificar el valor que $0debe tomar (aquí, fnord) para que la primera palabra producida por seqno se coma.

Respuesta4

Ninguno timede los dos envfuncionó para mí (pasan el valor de retorno de su programa hijo), así que escribí bliss:

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

entonceschmod u+x ~/bliss

y algo comofind_or_similar | xargs ~/bliss fatally_dying_program.sh

información relacionada