Получить коды выхода канала, когда выход назначен переменной (Подстановка команд)
Получение кода завершения команды pipe работает нормально.
echo "ABC" | false | true
echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]}
#Output is 0 1 0
Но когда я назначаю вывод переменной а, не могу получить коды выхода.
TEST=$(echo "ABC" | false | true)
echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]}
#Output is 0
Как я могу получить коды выхода переданных по конвейеру процессов?
1 ответ
Подстановка команд Bash происходит в под-оболочке, поэтому эти значения существуют, но только внутри этой под-оболочки. Ты видишь ${PIPESTATUS[0]}
отражать$?
от назначения (это будет1
если вы закончили замену с | false
).
Я изменил ваш пример, чтобы включить вывод. Это будет работать и с оригинальным кодом.
# without command substitution
echo "ABC" | false | echo "DEF"
echo "${PIPESTATUS[*]}"
echo "---"
# within command substitution
TEST="$( echo "ABC" | false | echo "DEF"; printf :%s "${PIPESTATUS[*]}" )"
declare -a PIPESTATUS2=( ${TEST##*:} ) # make array w/ content after final colon
if [[ -n "${TEST%:*}" ]]; then # if there was original output
TEST="${TEST%:*}" # remove trailing results from $TEST
TEST="${TEST%$'\n'}" # remove trailing \n like plain $(…)
else
TEST="" # no original output -> empty string
fi
echo "$TEST"
echo "${PIPESTATUS2[*]}"
Выход:
DEF
141 1 0
---
DEF
141 1 0
Код выхода 141 происходит из-за того, чтоfalse
преждевременно завершил конвейер ( SIGPIPE).
Это в основном просто добавляет суб-оболочки$PIPESTATUS
массив к сохраненному значению, используя двоеточие в качестве разделителя (подойдет любой нецифровый код; я выбрал тот, который мне не нужно было экранировать), а затем извлекает его из ответа, заполняя$PIPESTATUS2
массив с этими значениями. Удаление последнего разрыва строки - это еще один удар. Мы могли бы использовать это как разделитель, но тогда это сломалось бы, если исходный вывод не был завершен переводом строки.
Более простоерешение, если вам нужен только один из кодов выхода:
TEST=$( echo "ABC" | false | true; exit ${PIPESTATUS[0]} )
echo $? # 141 from `echo "ABC"
Гораздо более сложное POSIX-совместимое решение (нет необходимости $PIPESTATUS
когда вы можете использовать какую-то темную магию): ищите "Рассмотрим конвейер" в §1d знаменитой программы Csh Programming Exredful Rant, а затем адаптируйте ее к вашим POSIX-совместимым потребностям. Это будет нетривиально, но очень познавательно, если вы тот тип программиста, которому нужно избегать bash и реальных языков.