Получить код выхода из подоболочки через каналы
Как я могу получить код выхода wget
из процесса подоболочки?
Итак, главная проблема в том, что $?
равен 0. Где можно $?=8
быть основанным?
$> OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt" ); echo "$?"
0
Работает без tee
, на самом деле.
$> OUT=$( wget -q "http://budueba.com/net" ); echo "$?"
8
Но ${PIPESTATUS}
массив (я не уверен, что это связано с этим случаем) также не содержит этого значения.
$> OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt" ); echo "${PIPESTATUS[1]}"
$> OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt" ); echo "${PIPESTATUS[0]}"
0
$> OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt" ); echo "${PIPESTATUS[-1]}"
0
Итак, мой вопрос - как я могу получить wget
код выхода через tee
а подоболочка?
Если это может быть полезно, моя версия Bash 4.2.20
,
4 ответа
Используя $()
вы (эффективно) создаете подоболочку. Таким образом PIPESTATUS
экземпляр, на который вам нужно обратить внимание, доступен только внутри вашей оболочки (т.е. внутри $()
), поскольку переменные среды не распространяются от дочерних процессов к родительским.
Вы могли бы сделать что-то вроде этого:
OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt"; exit ${PIPESTATUS[0]} );
echo $? # prints exit code of wget.
Вы можете добиться аналогичного поведения, используя следующее:
OUT=$(wget -q "http://budueba.com/net")
rc=$? # safe exit code for later
echo "$OUT" | tee -a "file.txt"
Остерегайтесь этого при использовании local
переменные:
local OUT=$(command; exit 1)
echo $? # 0
OUT=$(command; exit 1)
echo $? # 1
Для всех, кто используетbash
. Я думаю, что это самое чистое решение как для получения выходного значения , так и для каждого статуса выхода в канале.
Одноразовая заготовка. Давать возможность
lastpipe
вариант оболочки. Это позволяет получить значение из последней команды в канале без использования подоболочки. Если вы находитесь в интерактивной оболочке, также отключите управление заданиями:set +m
(Последнее не нужно для скриптов — там управление заданиями по умолчанию отключено.)shopt -s lastpipe set +m
значение в вашу переменную и естественным образом используйте PIPESTATUS. Например
grep -E "\S" "file.txt" | sort | uniq | read -d '' RES # 'read' exit status 1 means all input was read till EOF, we're OK with that if (( PIPESTATUS[0] > 1 || PIPESTATUS[1] > 0 || PIPESTATUS[2] > 0 || PIPESTATUS[3] > 1 )); then echo "ERROR" else echo "$RES" fi
Вышеприведенное читает все непустые строки из «file.txt», сортирует их и удаляет дубликаты. В этом примере у нас есть пользовательская обработка кодов выхода:grep
статус выхода 1 означает, что строки не были выбраны, с этим все в порядке; статус выхода 1 ожидается для сохранения многострочного вывода (по крайней мере, я не знаю другого чистого способа сделать это). Чистый означает, что код не загромождается только для того, чтобы избежать состояния выхода 1 из .
Обратите вниманиеread -d ''
опция используется для чтения всего ввода в нашу переменную (путем отключения разделителяread
останавливается на, что по умолчанию является символом новой строки). Так мы сохраняем многострочный вывод. Если ваша трубка имеет только одну линию, вы можете использовать простойread RES
(и, вероятно, может изменить ожидаемый статус выхода с чтения на 0, а не на 1, как указано выше).
Сначала скопируйте массив PIPESTATUS. Любые чтения разрушают текущее состояние.
declare -a PSA
cmd1 | cmd2 | cmd3
PSA=( "${PIPESTATUS[@]}" )
Я использовал fifos для решения проблемы sub-shell/PIPESTATUS. Видите bash pipestatus в команде с обратным каналом?
Я также нашел это полезным: bash script: как сохранить возвращаемое значение первой команды в конвейере?
и https://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another/70675