
Während ich ein Skript auf CI (Gitlab, Docker-Container mit Alpine Linux) ausführe, treten sporadisch Fehler mit dem Signal 141 auf, das auf ein „SIGPIPE“ hinzuweisen scheint. Aber ich verstehe nicht, welcher Schritt fehlschlägt oder was ich zum Debuggen tun soll.
#!/usr/bin/env bash
set -euxo pipefail
set -a
# ...
git fetch --tags
RELEASE=$(git tag | grep -E "${BUILD_ENV}-release-(\d+)" | cut -d"-" -f3 | sort -nr | head -1)
RELEASE=$(( RELEASE + 1 ))
Der sporadische Fehler scheint innerhalb der Pipe in der vorletzten Zeile aufzutreten. Das Protokoll, das ich erhalte, lautet:
++ git tag
++ cut -d- -f3
++ sort -nr
++ grep -E 'prod-release-(\d+)'
++ head -1
+ RELEASE=323
ERROR: Job failed: exit code 141
Wie gehe ich beim Debuggen vor, um herauszufinden, welche Zeile tatsächlich fehlgeschlagen ist? Es sieht so aus, als ob die Variable RELEASE erfolgreich gefüllt wurde, aber dann trotzdem irgendwie abgestürzt ist?
Antwort1
Nachdem head -1
es seine Aufgabe erledigt hat, wird es beendet, unabhängig davon, ob sort -nr
es gelungen ist, alle Daten in die Pipe zu schreiben. Wenn sort
noch etwas zu schreiben ist und head
nichts mehr vorhanden ist, sort
wird es abgerufen SIGPIPE
.
Nichts explodiert. So funktionieren Pipes. Wenn Sie head
in einer Pipe verwenden, sollten Sie nicht überrascht sein, wenn der vorhergehende Befehl aufgrund von beendet wird SIGPIPE
.
Einfacher Test mit yes
statt sort
:
$ set -o pipefail
$ yes | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
141 <- overall exit status
141 <- from `yes'
0 <- from `head'
Der Exit-Status ist 141
und kommt von yes
.
Dies zeigt, wie man debuggt: durch Untersuchen ${PIPESTATUS[@]}
.
Das Verhalten entspricht dem erwarteten Verhalten. Verwenden Sie eine Subshell anstelle von yes
(oder in Ihrem Fall anstelle von sort
), um den Beendigungsstatus dieses Teils der Pipe zu manipulieren. Beispiel:
$ set -o pipefail
$ (yes; true) | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
0
0
0
Komplexere Logik, um nur Folgendes zu unterdrücken 141
:
(yes; e="$?"; [ "$e" -eq 141 ] && exit 0; exit "$e") | head -n 1