`set -e` и` grep` идиома для предотвращения преждевременного выхода из сценария оболочки, когда шаблон не найден

15

Требуется помощь - в контексте сценариев оболочки на bash GNU / LINUX:

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

Я попытался решить эту проблему следующим образом:

(Попробуйте I)
Если set +o pipefailи вызову grep с чем-то вроде grep 'p' | wc -lэтого, я получу желаемое поведение, пока не включит будущий сопровождающий pipefail. Кроме того, мне нравится включать, pipefailтак что это не работает для меня.

(Попробуйте II)
Используйте a sedили awkи только печатать строки, соответствующие шаблону, затем wcсовпадают линии, чтобы проверить на соответствие шаблону. Мне не нравится эта опция, потому что использование sedto grepкажется обходным решением для моей настоящей проблемы.

(Попробуйте III)
Это мой наименее любимый - что-то вроде:set +e; grep 'p'; set-e

Любое понимание / идиомы будут наиболее цениться - спасибо.

Yeow_Meng
источник

Ответы:

19

Вы можете поместить grep в ifсостояние, или, если вас не волнует состояние выхода, добавьте || true.

Пример: grepубивает снаряд

$ bash
$ set -e
$ echo $$
33913
$ grep foo /etc/motd
$ echo $$
9233

Решение 1: выбросить ненулевой статус выхода

$ bash
$ set -e
$ echo $$
34074
$ grep foo /etc/motd || true
$ echo $$
34074

Решение 2: явно проверить состояние выхода

$ if ! grep foo /etc/motd; then echo not found; fi
not found
$ echo $$
34074

Со страницы руководства bash обсуждаем set -e:

Оболочка не завершает работу, если сбойная команда является частью списка команд, следующих сразу за ключевым словом некоторое время или до , часть теста после зарезервированных слов if или elif , часть любой команды, выполняемой в списке && или ││, кроме команда после последней && или ││ , любая команда в конвейере, кроме последней, или если возвращаемое значение команды инвертируется с помощью ! ,

Гленн Джекман
источник
Учитывая, что bash долгое время неправильно реализовывал -e, возможно, документация еще не верна. Поскольку текст, похоже, идентичен справочной странице bash-3.x, обратите внимание: все версии bash до bash4.0 действительно неправильно реализовали -e.
Шили
Также обратите внимание, что, поскольку стандарт POSIX также был неверным, мы изменили текст POSIX для обработки ошибок с -e в 2009 году
schily
1
@schily Пожалуйста, укажите, где можно узнать, что такое «правильное» поведение -e, что bash <4 делал по-другому и что изменилось в POSIX.
Звол
Ошибки в bash-3 в основном делают его непригодным для использования, так makeкак он не всегда завершается при ошибках. Для связанных обсуждений POSIX, вы можете проверить austingroupbugs.net
schily
@schily Не могли бы вы быть более конкретным?
Звол