Ответ 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).
В основном это просто добавляет массив sub-shell $PIPESTATUS
к сохраненному значению, используя двоеточие в качестве разделителя (любая незначная цифра будет делать, я выбрал одну, которую мне не нужно было бежать), а затем вытащил ее из ответ, заполняя массив $PIPESTATUS2
этими значениями. Удаление окончательного разрыва строки - еще один башизм. Мы могли бы использовать это как разделитель, но тогда это сломается, если исходный вывод не будет прерван прерыванием строки.
Упрощенное решение, если вы просто хотите один из кодов выхода:
TEST=$( echo "ABC" | false | true; exit ${PIPESTATUS[0]} )
echo $? # 141 from `echo "ABC"
Более сложное POSIX-совместимое решение $PIPESTATUS
, когда вы можете использовать некоторую темную магию): найдите "Рассмотрим трубопровод" в §1d знаменитого Программирование Csh с учетом вредоносного, а затем адаптируйте его к вашим требованиям, совместимым с POSIX. Это будет нетривиально, но высокообразованным, если вы такой кодер, который должен избегать bash и реальных языков.