Cómo hacer que 'xargs' ignore la salida del niño y siga procesando más

24

A veces ejecuto xargstrabajos largos durante la noche y es realmente molesto descubrir en 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 es asesinado, 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

¿De alguna manera puedo evitar que se xargsdetenga para procesar más entradas una vez que un proceso secundario falle y en su lugar continúe procesando?

Christoph Wurm
fuente
Estoy usando la xargsversión 4.4.2 debian wheezyy parece que todo funciona bien incluso si elimino un sleepproceso específico . ¿Qué versión de xargsestás usando? Es posible que hayan solucionado el problema en la última versión.
Kannan Mohan
Un poco tarde para la fiesta, pero ¿qué tal xargs ... bash -c '...;exit 0'o incluso?xargs ... bash -c '... || echo erk'
Samveen
Tenga en cuenta que parallel -j 1es una posible solución de pirateo.
barrycarter

Respuestas:

25

No puedes. De las xargsfuentes 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 bandera alrededor de ese cheque, o alrededor de la función que lo llama. Parece estar relacionado con los procesos máximos, lo que supongo que tiene sentido: si configura los procesos máximos lo suficientemente altos, no se molestará en verificar hasta que llegue al límite, lo que podría llegar a ser nunca.

Una mejor solución para lo que está tratando de hacer podría ser usar GNU Make :

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

all: $(TARGETS)

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

Luego:

$ make -k -j4 

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

ckhan
fuente
9

Parecería que uno de los coloquialismos más obvios solo es mencionado por otras propuestas.

Es decir, puede usar lo siguiente:

bash -c '$PROG_WHICH_MAY_FAIL ; (true)'

para "forzar el éxito".

Tenga en cuenta que esto está en la línea de la propuesta de lornix (solo que no en muchas palabras).

De todos modos, dado que esto ignora efectivamente el estado real de salida del proceso, me aseguraría de que considere guardar de alguna manera 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 puede escribirse mejor como:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed'

Como probablemente nos gustaría saber cuándo no se pudo tocar el archivo 'fallido'. En otras palabras, ya no estamos ignorando la falla, estamos tomando nota y continuando.

Y, después de considerar la naturaleza recursiva de este problema, quizás veamos exactamente por qué xargs no hace que ignorar la falla sea fácil. Como nunca es una buena idea, en su lugar, debería mejorar el manejo de errores dentro del proceso que está desarrollando. Sin embargo, creo que esta noción es más inherente a la "filosofía Unix" en sí misma.

Finalmente, supongo que esto es también a lo que James Youngman alude al recomendar trap, que presumiblemente podría usarse de manera similar. Es decir, no ignore el problema ... atrape y maneje o se despierte un día y descubra que ninguno de los subprogramas tuvo éxito ;-)

kingofephyra
fuente
3

Uso 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 de shell a otro idioma en el que también puede configurar controladores de señal.

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.

James Youngman
fuente
2

Ponga otro comando allí para 'comer' la señal del programa moribundo.

Probé su ejemplo, inicialmente como se muestra para demostrar el problema ... 'killall sleep' mata el proceso de sueño, interrumpe bash y xargs se cierra.

Como prueba, pegué un comando de tipo 'ejecutar otro comando' entre xargs y bash ... en este caso '/ usr / bin / time'. esta vez (sin juego de palabras), el sueño de Killall mata el proceso de sueño, pero los xargs continúan.

Dirigiría la salida del tiempo a / dev / null, y esto haría exactamente lo que está buscando sin una gran reescritura de su proceso existente.

Me imagino que si reflexiono por un momento podría idear otro programa para hacer lo mismo sin la charla stderr de '/ usr / bin / time'. O incluso escribir uno yo mismo, es solo un 'fork' (o derivado exec ()).

Recuerde usar '/ usr / bin / time', ya que no estoy seguro de que el 'tiempo' incorporado de bash haga lo mismo 'comer' la señal.

lornix
fuente
1
Una buena alternativa timepara este propósito sería env, ya que todo lo que hace es agregar cero o más variables opcionales al entorno del programa que ejecuta. No emite ninguna salida propia, y el código de retorno del programa invocado se devolverá a lo que se llame env.
James Sneeringer el
{Chuckle} Pensé en eso un rato después de escribir esto. El tiempo fue lo primero que me vino a la mente como un comando "ejecutar algo". Sin embargo, funciona bien. Felicidades y gracias.
lornix
2

Ni timetampoco envfuncionó para mí (que pasan a lo largo del valor de retorno de su programa infantil) así que escribí bliss:

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

luego chmod u+x ~/bliss

y algo como find_or_similar | xargs ~/bliss fatally_dying_program.sh

pix
fuente