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-pid
und führen Sie Folgendes aus:
$ ./wait-pid
exit code: 124
was ich erwarte, timeout
beendet den sleep
Prozess und beendet ihn mit 124, was wait
pflichtbewusst 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 wait
immer 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, timeout
wenn 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