Warten auf Prozess in Pipeline gibt falschen Exitcode zurück

Warten auf Prozess in Pipeline gibt falschen Exitcode zurück

Da übersehe ich wohl etwas:

#!/bin/bash
timeout 5 sleep 10 &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"

Rufen Sie das Skript auf wait-pidund führen Sie Folgendes aus:

$ ./wait-pid 
exit code: 124

was ich erwarte, timeoutbeendet den sleepProzess und beendet ihn mit 124, was waitpflichtbewusst zurückkehrt.

Aber wenn ich dem ursprünglichen Befehl eine Pipeline hinzufüge:

timeout 5 sleep 10 | cat &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"

jetzt bekomme ich:

$ ./wait-pid 
exit code: 0

Sollte nicht waitimmer noch den Exit-Code des Prozesses zurückgeben, auf den gewartet wird: timeout. Der Exit-Code sollte also immer noch 124 sein.

Dies ist mit der Bash-Version 4.4.20(1) der Fall.

Antwort1

Ich habe eine Antwort von dem überaus kompetenten Greg Wooledge auf der Bash-Mailingliste erhalten. Das Schlüsselelement ist:

Der Wait-Befehl funktioniert nur bei direkten Kindprozessen der Shell, auch bekannt als „asynchrone Befehle“. Falls Ihr asynchroner Befehl eine Pipeline ist, greifen wir auf den ursprünglichen SH-Funktionssatz zurück. Der Beendigungsstatus Ihres asynchronen Befehls ist der des letzten Befehls in der Pipeline, und die Beendigungsstatus der anderen Befehle werden einfach verworfen.

Aus diesem Grund erhalte ich den Exitcode nicht, timeoutwenn es sich in einer Pipeline befindet.

Um das gewünschte Verhalten zu erreichen, verwende ich eine temporäre Datei, um Exit-Codes aus dem asynchronen Code zu erfassen. So etwas wie:

{
  timeout 5 sleep 10 | cat
  echo "${PIPESTATUS[@]}" > "$tempfile"
} &
wait

verwandte Informationen