
Ao executar um script no CI (Gitlab, contêiner Docker executando Alpine Linux), estou recebendo falhas esporádicas com o sinal 141 que parece indicar um "SIGPIPE". Mas não entendo qual etapa está falhando ou o que fazer para depurá-la.
#!/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 ))
O erro esporádico parece acontecer dentro do pipe na penúltima linha, o log que recebo é:
++ git tag
++ cut -d- -f3
++ sort -nr
++ grep -E 'prod-release-(\d+)'
++ head -1
+ RELEASE=323
ERROR: Job failed: exit code 141
Como eu faria para depurar isso para descobrir qual linha realmente falhou? Parece que a variável RELEASE foi preenchida com sucesso, mas de alguma forma ainda explodiu?
Responder1
Depois de head -1
fazer seu trabalho, ele sai independentemente de sort -nr
ter conseguido gravar todos os dados no pipe. Se sort
tiver algo mais para escrever e head
não existir mais então sort
conseguirá SIGPIPE
.
Nada explode. É assim que funcionam os canos. Ao usar head
em um pipe, você não deve se surpreender se o comando anterior for encerrado por causa de SIGPIPE
.
Teste simples com yes
em vez de sort
:
$ set -o pipefail
$ yes | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
141 <- overall exit status
141 <- from `yes'
0 <- from `head'
O status de saída é 141
e vem de yes
.
Isso mostra como depurar: examinando arquivos ${PIPESTATUS[@]}
.
O comportamento é esperado. Use um subshell em vez de yes
(ou no seu caso, em vez de sort
) para manipular o status de saída desta parte do tubo. Exemplo:
$ set -o pipefail
$ (yes; true) | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
0
0
0
Lógica mais complexa para suprimir apenas 141
:
(yes; e="$?"; [ "$e" -eq 141 ] && exit 0; exit "$e") | head -n 1