При работе с конвейерами (пайпами, «трубами», 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 $?
отображает корректный код завершения.
С учетом вышеизложенного, а так же с учетом знания о кодах завершения wget
(копия) и о том, что wget
портит файлы в случае ошибки загрузки (копия) можно красиво модифицировать скрипт, чтоб он сообщал пользователю о результате после загрузки.
#!/bin/bash FADDR="http://tolik-punkoff.com/static/test.mp3" FPATH="./test.mp3" messagebox() #1 - title $2 - message { dialog --title "$1" --msgbox "$2" 10 41 } set -o pipefail wget --progress=dot --tries=10 --timeout=30 -O "$FPATH" "$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 RETVAL=$? case "$RETVAL" in 0) messagebox "Complete!" "File downloaded!" ;; 1) messagebox "Error" "Generic error ($RETVAL)" ;; 2) messagebox "Error" "Command line or config error ($RETVAL)" ;; 3) messagebox "Error" "I/O error ($RETVAL)" ;; 4) messagebox "Error" "Network failure ($RETVAL)" ;; 5) messagebox "Error" "SSL verification failure ($RETVAL)" ;; 6) messagebox "Error" "Username/password authentication failure ($RETVAL)" ;; 7) messagebox "Error" "Protocol error ($RETVAL)" ;; 8) messagebox "Error" "Server error ($RETVAL)" ;; *) messagebox "Error" "Unknow error ($RETVAL)" ;; esac #remove wrong file if exist if [ "$RETVAL" -ne 0 ];then if [ -e "$FPATH" ];then rm "$FPATH" fi fi
Все ОК:
Обрыв связи:
Неверный адрес: