Що означає параметр -e для командного рядка оболонки bash?


78

У мене є скрипт оболонки bash із заголовком #!/bin/bash -e.

Коли я запускаю сценарій, він буде перерваний після grepзапуску команди, але коли я видалю параметр -e, то скрипт може запускатися нормально. Що означає параметр -e?


1
@MitchWheat Однак немає -eможливості bash, так що ж насправді відбувається в цьому випадку? :(

2
Це дійсно не очевидно, але це-e варіант для Баша: serverfault.com/questions/391255 / ... .
Ерік Лебіго

Лише на один пункт більше. Наприклад, коли ви знайдете це: [-e filepath] Повертає true, якщо файл існує.
Альберто Перес

Відповіді:


107

В -eопції означає : «Якщо трубопровід коли - або закінчується зі статусом ненульовим (" помилка "), завершити скрипт негайно». Оскільки grepповертає статус виходу, 1коли він не знаходить жодного збігу, це може призвести -eдо завершення роботи сценарію, навіть якщо не було справжньої "помилки".

Якщо ви хочете зберегти -eваріант, але є grepкоманда , яка не може законним чином знайти не матчі, ви можете додати || :до grepкоманді. Це означає "або, якщо grepкоманда повертає ненульовий статус виходу, запустити :(що нічого не робить)"; тому чистий ефект полягає у відключенні -eдля grepкоманди. Так:

grep PATTERN FILE... || :

Відредаговано для додавання: Вищевказаний підхід відкидає кожну помилку: якщо grepповертається, 1оскільки не знайдено збігів, це ігнорується, а також якщо grepповертається, 2оскільки сталася помилка, яка ігнорується, а якщо grepнемає в шляху (тому Bash повертається 127), це ігнорується - і так далі. Тож замість того :, можливо, краще використовувати команду, яка перевіряє код результату та повторно видає помилку, якщо це щось інше, ніж 1. Наприклад:

grep PATTERN FILE || (( $? == 1 ))

Але це руйнує статус виходу; зазвичай, коли невдала команда закінчує сценарій Bash -e, скрипт повертає статус виходу команди, але у наведеному вище прикладі сценарій просто повертається 1. Якщо (і лише якщо) нас це турбує, ми можемо це виправити, написавши щось подібне:

grep PATTERN FILE || exit_code=$?
if (( exit_code > 1 )) ; then
    exit $exit_code
fi

(перший рядок c / o коментар dsummersl ).

На даний момент, мабуть, найкраще створити функцію оболонки, яка б обробляла це для нас:

function grep_no_match_ok () {
    local exit_code
    grep "$@" || exit_code=$?
    return $(( exit_code == 1 ? 0 : exit_code ))
}

(зверніть увагу на використання returnзамість exit; ми дозволимо -eобробляти вихід, коли це доречно); таким чином, ми можемо просто написати:

grep_no_match_ok PATTERN FILE     # won't kill script if no matches are found

Насправді, оскільки ми, швидше за все, хочемо використовувати цю функцію для всіх випадків grepв цьому сценарії, ми можемо насправді просто назвати функцію grep:

function grep () {
    local exit_code
    command grep "$@" || exit_code=$?
    return $(( exit_code == 1 ? 0 : exit_code ))
}

grep PATTERN FILE     # won't kill script if no matches are found

(зверніть увагу на використання функції commandобходу оболонки у своєму власному тілі: ми хочемо, щоб функція викликала звичайну програму grep, а не повторювала нескінченно).


Дуже мило. Я взяв за допомогою порад , щоб захопити код виходу для подальшого використання: grep XXX FILE || exitcode=$?. Супер зручно!
dsummersl

@dsummersl: Класно, я рада, що тобі сподобалось! Ваш коментар надихнув мене розширити свою відповідь деякими потенційними покращеннями, які можуть вам сподобатися.
ruahh

Серйозно, дякую за це. Шаблон, який ви окреслили, є просвітницьким; це хороший шаблон для захисту від несподіваних кодів виходу, одночасно ігноруючи очікувані ... Я точно можу бачити, як використовувати цей шаблон для спрощення основного потоку моїх сценаріїв.
dsummersl

@ruakh Відмінна відповідь, функція grep дійсно корисна. Дякую.
Джо

Лише на один пункт більше. Наприклад, коли ви знайдете це: [-e filepath] Повертає true, якщо файл існує.
Альберто Перес

19

З чудового посібника :

На додаток до параметрів командного рядка оболонки з одним символом (див. Набір вбудованих), є кілька багатосимвольних параметрів, якими ви можете скористатися.

І тоді, якщо ми подивимося, що setсказати:

-e
Негайно закрийте конвеєр (див. Конвеєри), який може складатися з однієї простої команди (див. Прості команди), команди під оболонки, укладеної в дужки (див. Групування команд), або однієї з команд, що виконуються як частина списку команд, дужки (див. Групування команд) повертає ненульовий статус.

Отже, коли ви говорите bash -e, якщо будь-яка команда у сценарії зазнає невдачі (тобто повертає ненульовий статус існування), то весь сценарій негайно виходить з ладу. Отже, ви grepповертаєте ненульове значення, оскільки воно не збігається, і це вимикає весь сценарій, якщо ви вказали -eпід час запуску bash.


1
Ах так, я підозрював, що це з, setале хотів побачити це в посібнику. Мені було цікаво, чому я цього не побачив man bash, це тому, що я перейшов прямо до перерахованих параметрів і пропустив абзац, який сказав: "Усі параметри оболонки з одним символом, задокументовані в описі набору вбудованих команд, включаючи -o може використовуватися як опція при виклику оболонки ". Все там!
Нагєв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.