7

While running a script on CI (Gitlab, Docker container running Alpine Linux), I am getting sporadic failures with signal 141 which seems to indicate a "SIGPIPE". But I do not understand which step is failing or what to do about debugging it.

  #!/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 ))

The sporadic error seems to happen inside the pipe in the second to last line, the log I get is:

++ git tag
++ cut -d- -f3
++ sort -nr
++ grep -E 'prod-release-(\d+)'
++ head -1
+ RELEASE=323
ERROR: Job failed: exit code 141

How would I go about debugging this to figure out which line actually failed? It looks like it got the RELEASE variable populated successfully but then somehow still blew up?

kos
  • 185

1 Answers1

7

After head -1 does its job, it exits regardless if sort -nr managed to write all the data to the pipe. If sort has something more to write and head is no more then sort will get SIGPIPE.

Nothing blows up. This is how pipes work. When you use head in a pipe you should not be surprised if the preceding command exits because of SIGPIPE.


Simple test with yes instead of sort:

$ set -o pipefail
$ yes | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
141             <- overall exit status
141             <- from `yes'
0               <- from `head'

The exit status is 141 and it comes from yes.

This shows how to debug: by examining ${PIPESTATUS[@]}.


The behavior is expected. Use a subshell instead of yes (or in your case instead of sort) to manipulate the exit status of this part of the pipe. Example:

$ set -o pipefail
$ (yes; true) | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
0
0
0

More complex logic to suppress only 141:

(yes; e="$?"; [ "$e" -eq 141 ] && exit 0; exit "$e") | head -n 1