2013-11-20 4 views
2

Есть ли общий способ в сценарии bash «попробовать» что-то, но продолжить, если он не сработает? Аналог на других языках будет обертывать его в try/catch и игнорировать исключение.Выполнить строку в Bash без прерывания, если она не удалась?

В частности я пытаюсь источник дополнительного файла спутникового сценария:

. $OPTIONAL_PATH 

Но при выполнении этого, если $OPTIONAL_PATH не существует, весь сценарий визжит к остановке.

Я понимаю, что могу проверить, существует ли файл до его поиска, но мне любопытно, есть ли общий механизм многократного использования, который я могу использовать, который будет игнорировать ошибку без остановки.

Обновление: Видимо, это ненормальное поведение. Я не знаю, почему это происходит. Я не указываю в явном виде set -e в любом месте ($- is hB), но он останавливается на ошибке. Вот выход я вижу:

./script.sh: line 36: projects/mobile.sh: No such file or directory 

Я добавил echo "test" сразу после исходной строки, но он никогда не печатает, так что это не что-то после этой строки, которая, выходящая. Я запускаю Mac OS 10.9.

Обновление 2: Ничего не было, это действительно было изменено как #!/bin/sh вместо #!/bin/bash. Спасибо за информативный ответ, Kaz.

+0

Если вы позволите $ OPTIONAL_PATH не существует, просто проверьте, существует ли он и укажите его только тогда, когда он доступен. – ArturFH

ответ

5

Неудачные команды не прерывают сценарий, если вы явно не настроили этот режим с помощью set -e.

Что касается команды точки Баша, все сложно. Если мы вызываем bash как /bin/sh, то он освобождает сценарий, если команда . не находит файл. Если мы вызываем bash как /bin/bash, то это не подведет!

$ cat source.sh 
#!/bin/sh 

. nonexistent 
echo here 
$ ./source.sh 
./source.sh: 3: .: nonexistent: not found 
$ ed source.sh 
35 
1s/sh/bash/ 
wq 
37 
$ ./source.sh 
./source.sh: line 3: nonexistent: No such file or directory 
here 

Он отвечает на set -e; если у нас есть #!/bin/bash, и используйте set -e, то echo не будет достигнут. Таким образом, одним из способов является обращение к bash таким образом.

Если вы хотите, чтобы сценарий был максимально переносимым, похоже, что вам нужно пройти тест.

Поведение команды dot, прерывающей сценарий, требуется POSIX. Найдите ключевое слово «точка» here.

Если считываемый файл не найден, неинтерактивная оболочка прерывается; интерактивная оболочка должна записать диагностическое сообщение в стандартную ошибку, но это условие не должно рассматриваться как синтаксическая ошибка.

Возможно, это правильная вещь, потому что точка используется для включения фрагментов сценария. Как скрипт может продолжаться, когда не будет найден целый фрагмент?

В противном случае, возможно, это Braindamaged поведение несовместимо с обработкой других команд, и поэтому Bash делает его согласованным в своем не-POSIX-совместимом режиме. Если программистам требуется команда сбой, они могут использовать set -e.

Я, как правило, согласен с Bash. Поведение POSIX на самом деле больше, чем сломанный первоначально встречает глаз, потому что это также не работает так, как вы хотите:

if . nonexistent ; then 
    echo loaded 
fi 

Даже если команда протестирована, она по-прежнему прерывает сценарий, когда он выручает.

Поблагодарите GNU-deness, у нас есть альтернативные утилиты с исходным кодом.

+0

Я не намеренно называл 'set -e' нигде. Есть ли способ проверить, было ли это вызвано в другом месте? – devios1

+1

Проверьте значение '$ -' для буквы' e'. – chepner

+0

Ага, он был распущен как '#!/Bin/sh'! Есть ответ. – devios1

1

Это не по умолчанию. Вы использовали set -e или использовали #!/bin/bash -e в любом месте вашего скрипта, чтобы он автоматически выходил из строя?

Если да, то вы можете использовать

. $OPTIONAL_PATH || true 

продолжать в любом случае.

+0

Даже добавление '|| true' продолжает отменять. – devios1

+0

Другой неправильный ответ. – Kaz

2

У вас есть несколько вариантов:

  1. Убедитесь set -e не использовали, или выключить его с set +e. Сценарий bash не должен выходить по умолчанию просто потому, что команда . не удалась.

  2. Проверьте, существует ли файл перед поиском.

    [ -f "$OPTIONAL_PATH" ] && . "$OPTIONAL_PATH" 
    

    Этот вариант осложняется тем, что, если $OPTIONAL_PATH не содержит каких-либо слэш, . будет по-прежнему пытается найти файл на своем пути.

  3. Если вы хотите сохранить set -e на «шкуре» провал, как это:

    . "$OPTIONAL_PATH" || true 
    

    Даже если этот источник, статус выхода из списка команд в целом будет равен 0, из-за || true.

(Большая часть этого покрыта [лучше] на ответ КАЗ, особенно ссылки на стандарт POSIX, но я не был уверен, что, когда и если он будет восстановить свой ответ.)

+0

Я временно удалил ответ, потому что в нем содержалось неправильное утверждение о команде dot. (Это стандартная точка, а «источник» - нестандартная, я их перепутал). – Kaz

+0

Вот что я заметил :) Хороший ответ; Я не знал, что для POSIX требуется отключение интерактивной оболочки. 'bash' даже не делает этого при использовании опции' --posix'. – chepner

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