2010-09-29 2 views
138

Я noob в shell-scripting. Я хочу напечатать сообщение и выйти из моего сценария, если команда завершилась неудачей. Я пробовал:Как выйти из командной строки?

my_command && (echo 'my_command failed; exit) 

но не работает. Он продолжает выполнять инструкции, следующие за этой строкой в ​​скрипте. Я использую Ubuntu и bash.

+3

Вы предполагали, что незакрытая цитата является синтаксической ошибкой, которая приведет к сбою/выходу? если нет, вы должны закрыть цитату в своем примере. – hobs

ответ

268

Try:

my_command || { echo 'my_command failed' ; exit 1; } 

Четыре изменения:

  • Изменить && для ||
  • Использование { } вместо ()
  • Введение ; после exit и
  • пространства после { и до }

Так как вы хотите, чтобы напечатать сообщение и выход только тогда, когда команда выходит из строя (выходы с ненулевым значением) вам нужно || не &&.

cmd1 && cmd2 

будет работать, когда cmd2cmd1 успешно (значение выхода 0). Где, как

cmd1 || cmd2 

будет работать cmd2, когда cmd1 терпит неудачу (выход ненулевое значение).

Использование () делает команду в них работать в подоболочку и вызов exit оттуда приводит к выходу из подоболочки, а не оригинал оболочки, следовательно, выполнение продолжается в исходной оболочке.

Чтобы преодолеть это использование { }

Последние два изменения требуются Баш.

+3

Кажется, что оно «отменено». Если функция «преуспевает», она возвращает 0, и если она «терпит неудачу», она возвращает ненулевое значение, поэтому можно ожидать, что && может оценить, когда первая половина вернулась отличной от нуля. Это не значит, что приведенный выше ответ неверен - это не так.&& и || в работе скриптов, основанных на успехе, не на возвращаемом значении. – CashCow

+6

Кажется обратным, но прочитайте его, и это имеет смысл: «сделайте эту команду (успешно)« ИЛИ », напечатайте эту ошибку и выйдите из« – simpleuser

+2

Логикой этого является то, что язык использует оценку короткого замыкания (SCE). С SCE f выражение имеет вид «p OR q», а p оценивается как true, тогда нет причин даже смотреть на q. Если выражение имеет вид «p AND q», а p оценивается как ложное, нет никаких оснований смотреть на q. Причиной этого является двукратное: 1) его более быстрое, по очевидным причинам, и 2) оно позволяет избежать определенных ошибок (например: «если x! = 0 И 10/x> 5» сбой, если SCE отсутствует). Возможность использовать его в командной строке, как это, является счастливым побочным эффектом. – user2635263

10

Предоставлено my_command канонически разработан, т.е. возвращает 0 при успешном завершении, то && точно противоположность того, что вы хотите. Вы хотите ||.

Также обратите внимание, что ( не кажется правильным в bash, но я не могу попробовать, откуда я. Расскажи мне.

my_command || { 
    echo 'my_command failed' ; 
    exit 1; 
} 
+0

IIRC, вам нужны точки с запятой после каждой строки внутри {} –

+7

@Alex: нет, если они находятся на отдельной строке. –

53

Обратите внимание, что состояние выхода каждой команды сохраняется в переменной оболочки $ ?, которую вы можете проверить сразу после запуска команды. Ненулевое состояние указывает отказ:

my_command 
if [ $? -eq 0 ] 
then 
    echo "it worked" 
else 
    echo "it failed" 
fi 
+8

Это можно просто заменить, если my_command, здесь нет необходимости использовать тестовую команду. –

+5

+1, потому что я думаю, что вы не должны быть наказаны за то, что указали эту альтернативу - она ​​должна быть на столе - хотя это довольно уродливо и по моему опыту слишком легко запустить другую команду, не заметив природу теста (может быть, я «Просто глупо». –

+1

@BartSas Если команда длинная, лучше поместить ее в свою линию. Это делает скрипт более удобочитаемым. – Michael

94

Другие ответы покрыли прямой вопрос хорошо, но вы также можете быть заинтересованы в использовании set -e. При этом любая команда, которая выходит из строя (за пределами конкретных контекстов, таких как тесты if), вызовет прерывание сценария. Для некоторых скриптов это очень полезно.

12

Я изрубил следующую идиому:

echo "Generating from IDL..." 
idlj -fclient -td java/src echo.idl 
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi 

echo "Compiling classes..." 
javac *java 
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi 

echo "Done." 

перед каждой командой с информативным эхом, и следовать каждой команде с той же
if [ $? -ne 0 ];... линией. (Конечно, вы можете изменить это сообщение об ошибке, если вы хотите.)

+0

Это можно определить как функцию, чтобы повторно использовать ее. –

47

Если вы хотите, чтобы поведение для всех команд в вашем скрипте, просто добавьте

set -e 
    set -o pipefail 

в начале сценария. Эта пара опций сообщает интерпретатору bash выйти, когда команда возвращается с ненулевым кодом выхода.

Это не позволяет печатать сообщение о выходе.

+6

Вы можете запускать команды на выходе с помощью встроенной команды 'trap' bash. –

+0

Это ответ на вопрос X-Y. – jwg

+3

Может быть интересно объяснить, какие команды выполняют самостоятельно, а не пара. Тем более, что 'set -o pipefail' может не быть желательным поведением. Еще спасибо за указание! –

0

Вы также можете использовать, если вы хотите сохранить статус ошибки выхода и иметь читаемый файл с помощью одной команды в каждой строке:

my_command1 || exit $? 
my_command2 || exit $? 

Это, однако, не печатает никаких дополнительных сообщений об ошибке. Но в некоторых случаях ошибка будет напечатана неудачной командой.

0

Встроенная оболочка trap позволяет захватывать сигналы и другие полезные условия, включая выполнение неудачной команды (то есть, ненулевой статус возврата). Поэтому, если вы не хотите явно проверять статус возврата каждой отдельной команды, вы можете сказать trap "your shell code" ERR, и код оболочки будет выполнен в любое время, когда команда вернет ненулевой статус. Например:

trap "echo script failed; exit 1" ERR

Обратите внимание, что как и в других случаях ловли неудачных команд, трубопроводы требуют специальной обработки; выше не поймают false | true.

Смежные вопросы