При работе с конвейерами (пайпами, «трубами», pipe), часто возникает вопрос, как отловить ошибку, произошедшую внутри конвейера.
Для примера возьмем код, где ход загрузки файла отображается dialog’овым прогрессбаром (копия):
#!/bin/bash
FADDR="http://tolik-punkoff.com/static/test.mp3"
wget --progress=dot -O "./test.mp3" "$FADDR" 2>&1 |\
stdbuf -o0 awk '/[.] +[0-9][0-9]?[0-9]?%/ { print substr($0,63,3) }' | \
dialog --gauge "Download file from $FADDR" 10 100
Как видите, конвейер (т.е. передача вывода от одной команды другой через |
), тут налицо.
Если после данной команды просто дописать echo $?
, то будет видно, что результат будет 0
.
И когда все в порядке:

И когда все не в порядке (в данном случае, сделан обрыв связи):

На самом деле, это происходит потому, что в переменной $?
оказывается код завершения последней команды в pipe.
В современных версиях bash перед использованием контейнера, необходимо добавить команду:
set -o pipefail
В старых bash и некоторых других оболочках придется извращаться, может как-нибудь вернусь к вопросу (если для какого утюга что писать буду).
После добавления вышеуказанной команды в скрипт делаем тест с обрывом связи:

Или указываем в переменной $FADDR
некорректный адрес:

Теперь echo $?
отображает корректный код завершения.