У меня есть оболочка script, которая выполняет несколько команд. Как заставить оболочку script выйти, если какая-либо из команд завершится с ненулевым кодом выхода?
Exit Shell Script Исходя из кода выхода процесса
Ответ 1
После каждой команды код выхода можно найти в переменной $?
, чтобы у вас было что-то вроде:
ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
Вам нужно быть осторожным с командами с каналами, поскольку $?
дает только код возврата последнего элемента в трубе, поэтому в коде:
ls -al file.ext | sed 's/^/xx: /"
не вернет код ошибки, если файл не существует (поскольку часть sed
на самом деле работает, возвращается 0).
Оболочка bash
фактически предоставляет массив, который может помочь в этом случае, будучи PIPESTATUS
. Этот массив имеет один элемент для каждого из компонентов конвейера, доступ к которому можно получить индивидуально, например ${PIPESTATUS[0]}
:
pax> false | true ; echo ${PIPESTATUS[0]}
1
Обратите внимание, что это дает вам результат команды false
, а не весь конвейер. Вы также можете получить весь список для обработки по своему усмотрению:
pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1
Если вы хотите получить самый большой код ошибки из конвейера, вы можете использовать что-то вроде:
true | true | false | true | false
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done
echo $rc
Это проходит через каждый из элементов PIPESTATUS
по очереди, сохраняя его в rc
, если он был больше, чем предыдущее значение rc
.
Ответ 2
Если вы хотите работать с $?, вам нужно будет проверить его после каждой команды, так как $? обновляется после выхода каждой команды. Это означает, что если вы выполните конвейер, вы получите только код завершения последнего процесса в конвейере.
Другой подход заключается в следующем:
set -e
set -o pipefail
Если вы поместите это в начало оболочки script, похоже, что bash позаботится об этом для вас. Как отмечалось в предыдущем посте, "set -e" приведет к выходу bash с ошибкой любой простой команды. "set -o pipefail" приведет к тому, что bash завершится с ошибкой по любой команде в конвейере.
См. здесь или здесь для более подробной дискуссии по этой проблеме. Здесь - это раздел руководства bash для встроенного набора.
Ответ 3
"set -e
", вероятно, самый простой способ сделать это. Просто поставьте это перед любыми командами в своей программе.
Ответ 4
Если вы просто вызываете exit в bash без параметров, он вернет код выхода последней команды. В сочетании с OR bash должен вызываться только exit, если предыдущая команда завершилась с ошибкой. Но я не проверял это.
command1 || exit; command2 || exit;
bash также сохранит код выхода последней команды в переменной $?.
Ответ 5
http://cfaj.freeshell.org/shell/cus-faq-2.html#11
-
Как получить код выхода
cmd1
вcmd1|cmd2
Во-первых, обратите внимание, что код выхода
cmd1
может быть отличным от нуля и до сих пор не означает ошибку. Это происходит, например, вcmd | head -1
вы можете увидеть статус выхода 141 (или 269 с ksh93)
cmd1
, но это потому, чтоcmd
был прерван сигналом SIGPIPE, когдаhead -1
завершен после чтения одной строки.Знать статус выхода элементов конвейера
cmd1 | cmd2 | cmd3
а. с zsh:
Коды выхода указаны в специальном массиве pipestatus.
cmd1
код выхода находится в$pipestatus[1]
,cmd3
код выхода в$pipestatus[3]
, так что$?
всегда совпадает с$pipestatus[-1]
.б. с bash:
Коды выхода представлены в специальном массиве
PIPESTATUS
.cmd1
код выхода находится в${PIPESTATUS[0]}
,cmd3
код выхода в${PIPESTATUS[2]}
, так что$?
всегда совпадает с${PIPESTATUS: -1}
....
Подробнее см. ссылку .
Ответ 6
[ $? -eq 0 ] || exit $?; # exit for none-zero return code
Ответ 7
для bash:
# this will trap any errors or commands with non-zero exit status
# by calling function catch_errors()
trap catch_errors ERR;
#
# ... the rest of the script goes here
#
function catch_errors() {
# do whatever on errors
#
#
echo "script aborted, because of errors";
exit 0;
}
Ответ 8
В bash это легко, просто свяжите их вместе с & &:
command1 && command2 && command3
Вы также можете использовать вложенную конструкцию if:
if command1
then
if command2
then
do_something
else
exit
fi
else
exit
fi
Ответ 9
#
#------------------------------------------------------------------------------
# run a command on failure exit with message
# doPrintHelp: doRunCmdOrExit "$cmd"
# call by:
# set -e ; doRunCmdOrExit "$cmd" ; set +e
#------------------------------------------------------------------------------
doRunCmdOrExit(){
cmd="[email protected]" ;
doLog "DEBUG running cmd or exit: \"$cmd\""
msg=$($cmd 2>&1)
export exit_code=$?
# if occured during the execution exit with error
error_msg="Failed to run the command:
\"$cmd\" with the output:
\"$msg\" !!!"
if [ $exit_code -ne 0 ] ; then
doLog "ERROR $msg"
doLog "FATAL $msg"
doExit "$exit_code" "$error_msg"
else
#if no errors occured just log the message
doLog "DEBUG : cmdoutput : \"$msg\""
doLog "INFO $msg"
fi
}
#eof func doRunCmdOrExit