Возврат к ошибке в shellscript вместо выхода при ошибке

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

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

Вот пример-скрипт myScript.sh чтобы показать проблему:

 #!/bin/sh set -e copySomeStuff() { source="$1" dest="$2" cp -rt "$source" "$dest" return 0 } installStuff() { dest="$1" copySomeStuff dir1 "$dest" copySomeStuff dir2 "$dest" copySomeStuff nonExistingDirectory "$dest" } 

Сценарий используется следующим образом:

 $ source myScript.sh $ installStuff 

Это просто закроет консоль. Ошибка, отображаемая cp будет потеряна.

Я бы порекомендовал иметь один скрипт, который вы запускаете как под-оболочку, возможно, используя файл для чтения в определениях функций. Пусть этот скрипт устанавливает для себя параметр оболочки errexit .

Когда вы используете source из командной строки, «скрипт» – это ваша интерактивная оболочка. Выход означает завершение сеанса оболочки. Возможно, это возможно, но лучший вариант, если вы хотите установить errexit для сеанса, – это просто:

 #!/bin/bash set -o errexit source file_with_functions do_things_using_functions 

Дополнительная выгода: не будет загрязнять интерактивную сессию функциями.

Если вы источник, что он будет игнорировать #! и применит set -e к вызывающей оболочке, поэтому применим ко всем последующим командам.

вы можете заставить суб-оболочку:

 copySomeStuff() { ( set -e source="$1" dest="$2" cp -r "$source" "$dest" return 0 ) } 

Также для безопасности:

  • Не используйте все имена переменных caps, так как они могут столкнуться с именами среды. (на прошлой неделе у нас был вопрос о том, почему сценарий не работал, он имел переменную PATH)

  • Используйте кавычки.

  • Всегда используйте параметр -t или -T для cp , mv , ln . например

    • cp -t destination_directory source_files …
    • cp -T source_file destination_file

    обратите внимание, что -t и -T являются расширениями Gnu и недоступны для некоторых других Unix, поэтому для переносимости вы можете вместо опции -t :

    • cp source_files … destination_directory/

    Я не знаю альтернативной безопасной формы для -T