Jak sprawić, by `xargs` ignorował wyjście dziecka i kontynuował przetwarzanie


24

Czasami wykonuję długie xargsprace z dnia na dzień i naprawdę denerwuje mnie odkrycie, że xargsumarł gdzieś pośrodku, na przykład z powodu błędu segmentacji w jednym szczególnym przypadku, jak to miało miejsce tej nocy.

Jeśli nawet jedno xargsdziecko zostanie zabite, nie przetwarza już żadnych danych wejściowych:

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

Konsola 2:

[09:35:54] kill 5601

Czy mogę w jakiś sposób zapobiec xargszatrzymywaniu przetwarzania danych po śmierci procesu potomnego i kontynuować przetwarzanie?


Korzystam z xargswersji 4.4.2 debian wheezyi wygląda na to, że wszystko działa dobrze, nawet jeśli zabiję określony sleepproces. Z której wersji xargskorzystasz? być może rozwiązali problem w najnowszej wersji.
Kannan Mohan

Trochę późno na imprezę, ale co powiesz na to, xargs ... bash -c '...;exit 0'a nawetxargs ... bash -c '... || echo erk'
Samveen

Pamiętaj, że parallel -j 1jest to możliwe rozwiązanie hakerskie.
barrycarter

Odpowiedzi:


25

Nie możesz Ze xargsźródeł na 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;

Wokół tego czeku ani wokół funkcji, która go wywołuje, nie ma flagi. Wydaje się, że ma to związek z maksymalnymi procesami, co, jak sądzę, ma sens: jeśli ustawisz wystarczająco wysokie maks. Procy, nie będzie to przeszkadzało w sprawdzaniu, dopóki nie osiągnie limitu, którym może być nigdy.

Lepszym rozwiązaniem tego, co próbujesz zrobić, może być użycie GNU Make :

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

all: $(TARGETS)

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

Następnie:

$ make -k -j4 

będzie miał ten sam efekt i da ci znacznie lepszą kontrolę.


9

Wydawałoby się, że na jeden z najbardziej oczywistych kolokwializmów nawiązują jedynie inne propozycje.

Oznacza to, że możesz użyć następujących opcji:

bash -c '$PROG_WHICH_MAY_FAIL ; (true)'

w celu „wymuszenia sukcesu”.

Zauważ, że jest to zgodne z propozycją lornix (po prostu nie w wielu słowach).

W każdym razie, ponieważ skutecznie ignoruje to faktyczny status wyjścia z procesu, powinienem rozważyć zapisanie statusu podprocesu do analizy pośmiertnej. Na przykład:

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

trueTutaj jest nieco zbędny i tak może to być lepiej zapisać jako:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed'

Ponieważ prawdopodobnie chcielibyśmy wiedzieć, kiedy nie można było dotknąć „nieudanego” pliku. Innymi słowy, nie ignorujemy już niepowodzenia, odnotowujemy i kontynuujemy.

Po przeanalizowaniu rekurencyjnego charakteru tego problemu, być może widzimy dokładnie, dlaczego xargs nie ułatwia ignorowania błędów. Ponieważ nigdy nie jest to dobry pomysł - zamiast tego powinieneś usprawnić obsługę błędów w rozwijanym procesie. Uważam jednak, że to pojęcie jest bardziej nieodłączne od samej „filozofii uniksowej”.

Wreszcie, przypuszczam, że właśnie o tym wspomina James Youngman, zalecając trap, które prawdopodobnie można by wykorzystać w podobny sposób. To znaczy, nie ignoruj ​​problemu ... złap go w pułapkę i załatw, bo obudzisz się pewnego dnia i okaże się, że żaden z podprogramów w ogóle się nie powiódł ;-)


3

Użyj 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

Ewentualnie przełącz się z powłoki na inny język, w którym można również ustawić procedury obsługi sygnałów.

Zauważ też, że po tym, jak bash -c foo..powinieneś podać wartość, którą $0powinieneś przyjąć (tutaj fnord), aby pierwsze słowo wytworzone przez seqnie zostało zjedzone.


2

Wprowadź tam inne polecenie, aby „zjeść” sygnał z programu umierania.

Próbowałem twojego przykładu, początkowo jak pokazano, aby udowodnić problem ... „killall sleep” zabija proces snu, przerywa bash i xargs kończy pracę.

Jako test umieściłem polecenie typu „Uruchom inną komendę” pomiędzy xargs i bash ... w tym przypadku „/ usr / bin / time”. tym razem (bez gry słów) killall sleep zabija proces snu, ale xargs trwa dalej.

Skończysz przesyłać dane wyjściowe do / dev / null, a to zrobi dokładnie to, czego szukasz bez większego przepisywania istniejącego procesu.

Wyobrażam sobie, że jeśli zastanowię się przez chwilę, mógłbym wymyślić inny program, aby zrobić to samo bez gadania stderr z „/ usr / bin / time”. Lub nawet sam napisać, to tylko pochodna „fork” (lub exec ()).

Pamiętaj, aby używać „/ usr / bin / time”, ponieważ nie jestem pewien, czy wbudowany „time” z bash zrobi to samo „zjadanie” sygnału.


1
Dobrą alternatywą timedla tego celu byłoby env, ponieważ wszystko, co robi, to dodać zero lub więcej opcjonalnych zmiennych do środowiska uruchomionego programu. Nie emituje żadnych danych wyjściowych, a kod powrotu wywoływanego programu zostanie przekazany z powrotem do dowolnego wywołanego programu env.
James Sneeringer,

{Śmiech} Myślałem o tym chwilę po tym, jak to napisałem. Czas był pierwszą rzeczą, która przyszła mi do głowy jako polecenie „uruchom coś”. Ale ładnie działa. Gratulacje i dziękuję.
lornix,

2

Ani dla mnie timenie envdziałały (przekazują wartość zwracaną przez ich program potomny), więc napisałem bliss:

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

następnie chmod u+x ~/bliss

i coś w tym rodzaju find_or_similar | xargs ~/bliss fatally_dying_program.sh

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.