Wie kann man `xargs` dazu bringen, den Ausgang des untergeordneten Elements zu ignorieren und die Verarbeitung fortzusetzen?

Wie kann man `xargs` dazu bringen, den Ausgang des untergeordneten Elements zu ignorieren und die Verarbeitung fortzusetzen?

Ich lasse manchmal lange xargsJobs über Nacht laufen und es ist wirklich ärgerlich, wenn man am nächsten Morgen feststellt, dass sie xargsirgendwo mittendrin abgestürzt sind, zum Beispiel aufgrund eines Segmentierungsfehlers in einem einzigen Sonderfall, wie es diese Nacht passiert ist.

Wenn auch nur ein xargsKind getötet wird, verarbeitet es keine weiteren Eingaben:

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

Konsole 2:

[09:35:54] kill 5601

Kann ich irgendwie verhindern, xargsdass die Verarbeitung weiterer Eingaben angehalten wird, wenn ein untergeordneter Prozess beendet wird, und stattdessen mit der Verarbeitung fortfahren?

Antwort1

Nein, das kannst du nicht. Von derxargsQuellen unter 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;

Es gibt kein Flag für diese Prüfung oder für die Funktion, die sie aufruft. Es scheint mit der maximalen Anzahl von Prozeduren zusammenzuhängen, was meiner Meinung nach Sinn macht: Wenn Sie die maximale Anzahl von Prozeduren hoch genug einstellen, wird keine Prüfung durchgeführt, bis das Limit erreicht ist, was möglicherweise nie der Fall sein wird.

Eine bessere Lösung für das, was Sie versuchen, könnte sein,GNU Make:

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

all: $(TARGETS)

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

Dann:

$ make -k -j4 

hat den gleichen Effekt und gibt Ihnen eine viel bessere Kontrolle.

Antwort2

Es scheint, dass einer der offensichtlichsten Umgangsspracheausdrücke in anderen Vorschlägen nur angedeutet wird.

Das heißt, Sie können Folgendes verwenden:

bash -c '$PROG_WHICH_MAY_FAIL ; (true)'

um den „Erfolg zu erzwingen“.

Beachten Sie, dass dies im Einklang mit dem Vorschlag vonAbonnieren(nur nicht mit so vielen Worten).

Da hierdurch der tatsächliche Beendigungsstatus des Prozesses effektiv ignoriert wird, sollten Sie auf jeden Fall in Erwägung ziehen, den Status des Unterprozesses für eine Post-Mortem-Analyse zu speichern. Beispiel:

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

Das true„Hier“ ist etwas redundant und lässt sich daher besser wie folgt schreiben:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed'

Da wir wahrscheinlich wissen möchten, wann die 'fehlgeschlagene' Datei nicht mehr berührt werden konnte. Mit anderen Worten, wir sind nicht mehrignorierendden Misserfolg nehmen wir zur Kenntnis und machen weiter.

Und wenn wir die rekursive Natur dieses Problems betrachten, sehen wir vielleicht genauWarumxargs macht es nicht einfach, Fehler zu ignorieren. Denn das ist nie eine gute Idee – Sie sollten stattdessen die Fehlerbehandlung innerhalb des Prozesses verbessern, den Sie entwickeln. Ich glaube jedoch, dass dieser Gedanke eher der „Unix-Philosophie“ selbst innewohnt.

Und schließlich ist es wohl auch das, worauf James Youngman anspielt, wenn er empfiehlt trap, was vermutlich auf ähnliche Weise verwendet werden könnte. Das heißt, ignorieren Sie das Problem nicht ... fangen Sie es ab und behandeln Sie es, sonst wachen Sie eines Tages auf und stellen fest, dass keines der Unterprogramme überhaupt erfolgreich war ;-)

Antwort3

Verwenden 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

Alternativ können Sie von der Shell zu einer anderen Sprache wechseln, in der Sie auch Signalhandler festlegen können.

Beachten Sie auch, dass Sie danach bash -c foo..den Wert angeben sollten, der $0(hier fnord) angenommen werden soll, damit das erste von erzeugte Wort seqnicht weggefressen wird.

Antwort4

Weder timenoch envhat bei mir funktioniert (sie geben den Rückgabewert ihres untergeordneten Programms weiter), also habe ich geschrieben bliss:

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

Dannchmod u+x ~/bliss

und so etwas wiefind_or_similar | xargs ~/bliss fatally_dying_program.sh

verwandte Informationen