Предотвратить выход grep в случае несоответствия

29

Этот скрипт не повторяет "после":

#!/bin/bash -e

echo "before"

echo "anything" | grep e # it would if I searched for 'y' instead

echo "after"
exit

Также было бы, если бы я удалил -eопцию в строке shebang, но я хотел бы оставить ее, чтобы мой скрипт останавливался, если произошла ошибка. Я не считаю, что grep не находит совпадений как ошибку. Как я могу предотвратить такой резкий выход?

Яго-лито
источник
Это наблюдение предназначено только для рассмотрения. Возможно, логику этого сценария следует еще раз продумать. Если не важно найти строку, зачем искать ее? Определение grep таково, что решения принимаются на основе наличия или отсутствия строки. Если вам все равно, то это не важно. Кроме того, может показаться, -eчто вы заботитесь: настолько, что любая проблема будет катастрофической.
Андрей Фаланга
2
@AndrewFalanga Меня это волнует в любом случае, так как я на самом деле анализирую содержимое, var=$(complex command | grep complex_pattern)которое может быть нулевым (в этом случае моя программа не должна завершаться). Это всего лишь сценарий, позволяющий решить проблему. Здесь нет никакой метафизической черной дыры в логике, верно? ;)
Яго-лито
Знание теперь, что вы намеревались захватить вывод, проясняет некоторые вещи. Как представлено, это смущало меня.
Андрей Фаланга

Ответы:

33
echo "anything" | grep e || true

Объяснение:

$ echo "anything" | grep e
### error
$ echo $?
1
$ echo "anything" | grep e || true
### no error
$ echo $?
0
### DopeGhoti's "no-op" version
### (Potentially avoids spawning a process, if `true` is not a builtin):
$ echo "anything" | grep e || :
### no error
$ echo $?
0

"||" означает «или». Если первая часть команды «терпит неудачу» (что означает «grep e» возвращает ненулевой код выхода), то часть после «||» выполняется, успешно и возвращает ноль в качестве кода выхода ( trueвсегда возвращает ноль).

Джон Н
источник
3
Немного более короткая версия того же, который не раскручивается /bin/true: command || :(так в вашем случае, set -e; grep 'needle' haystack || :).
DopeGhoti
1
@ DopeGhoti, trueвстроен в некоторые оболочки (по крайней мере, bash 4.3на RHEL)
iruvar
3
Недопустимо, потому что, если первая команда не удалась, она скрывает ошибку. Правильное решение должно возвращать ненулевое значение, если первая команда в канале не выполняется.
сорин
11

Надежный способ безопасно и необязательно grep сообщения:

echo something | grep e || [[ $? == 1 ]] ## print 'something', $? is 0
echo something | grep x || [[ $? == 1 ]] ## no output, $? is 0
echo something | grep --wrong-arg e || [[ $? == 1 ]] ## stderr output, $? is 1

Согласно инструкции posix , код выхода 1 означает, что строки не выбраны, а> 1 означает ошибку.

Джеймс З.М. Гао
источник
1
Это должен быть принятый ответ, так как он подавляет код выхода предупреждения (1) только в том случае, если grep ничего не находит, но при этом он передает ошибки (коды выхода> 1). Другие решения здесь всегда подавляют истинные ошибки, что обычно плохо.
HaroldFinch
7

Другой вариант - добавить в конвейер еще одну команду, которая не вызывает ошибок:

echo "anything" | grep e | cat

Поскольку catтеперь это последняя команда в конвейере, это статус выхода cat, а не из grep, который будет использоваться для определения того, вышел ли конвейер из строя или нет.

roelvanmeer
источник
4

Другой вариант:

...
set +e
echo "anything" | grep e
set -e
...
Джефф Шаллер
источник
3

Решение

#!/bin/bash -e

echo "before"

echo "anything" | grep e || : # it would if I searched for 'y' instead

echo "after"
exit

объяснение

set -e или set -o errexit

Выход немедленно, если конвейер (который может состоять из одной простой команды ), списка или составной команды (см. SHELL GRAMMARВыше) выходит с ненулевым статусом. Оболочка не завершает работу, если сбойная команда является частью списка команд, следующих сразу за ключевым словом whileили until, частью теста после зарезервированных слов ifили elif, частью любой команды, выполняемой в списке &&или, ||за исключением команды, следующей за последним &&или ||любым команда в конвейере, но последняя, ​​или если возвращаемое значение команды инвертируется с!, Если составная команда, отличная от подоболочки, возвращает ненулевое состояние из-за сбоя команды во время -eее игнорирования, оболочка не завершается. Ловушка ERR, если установлена, выполняется до выхода из оболочки. Эта опция применяется к среде оболочки и каждой среде суб-оболочки отдельно (см. COMMAND EXECUTION ENVIRONMENTВыше) и может привести к выходу из субоболочек перед выполнением всех команд в подоболочке.

Плюс, :это команда без эффекта в Bash.

Cyker
источник