Evite que grep salga en caso de nomatch

29

Este script no hace eco "después":

#!/bin/bash -e

echo "before"

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

echo "after"
exit

También lo haría si eliminara la -eopción en la línea shebang, pero deseo mantenerla para que mi script se detenga si hay un error. No considero que grep no encuentre coincidencias como un error. ¿Cómo puedo evitar que salga tan abruptamente?

iago-lito
fuente
Esta es una observación destinada únicamente a consideración. Quizás la lógica de este guión debería pensarse nuevamente. Si no es importante encontrar la cadena, ¿por qué buscarla? La definición de grep es tal que uno toma decisiones basadas en la presencia o ausencia de una cadena. Si no te importa de ninguna manera, entonces no es importante. Además, parece -epresuponer que te importa: tanto, que cualquier problema es catastrófico.
Andrew Falanga
2
@AndrewFalanga Me importa de cualquier manera, ya que en realidad estoy analizando el contenido del var=$(complex command | grep complex_pattern)cual puede ser nulo (en cuyo caso mi programa no debería finalizar). Esto es solo un script resumido que hace que ocurra el problema. No hay un agujero negro metafísico en la lógica aquí, ¿verdad? ;)
iago-lito
Saber ahora que tenía la intención de capturar la salida aclara algunas cosas. Como se presentó, fue confuso para mí.
Andrew Falanga

Respuestas:

33
echo "anything" | grep e || true

Explicación:

$ 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

El "||" significa "o". Si la primera parte del comando "falla" (que significa "grep e" devuelve un código de salida distinto de cero), entonces la parte después de "||" se ejecuta, tiene éxito y devuelve cero como el código de salida ( truesiempre devuelve cero).

John N
fuente
3
Una versión ligeramente más corta de la misma que no gira /bin/truees: command || :(en su caso, set -e; grep 'needle' haystack || :).
DopeGhoti
1
@DopeGhoti, trueestá integrado en algunos shells (al menos bash 4.3en RHEL)
iruvar
3
No es válido porque si el primer comando falla, ocultará el error. Una solución correcta debería devolver un valor distinto de cero si falla el primer comando en la tubería.
Sorin
11

Una forma sólida de enviar mensajes de forma segura y opcional 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

Según el manual posix , el código de salida 1 significa que no hay líneas seleccionadas y> 1 significa un error.

James ZM Gao
fuente
1
Esta debería ser la respuesta aceptada, ya que solo suprime el código de salida de advertencia (1) si grep no encuentra nada, pero transmite errores verdaderos (códigos de salida> 1). Las otras soluciones aquí siempre suprimen los errores verdaderos, que generalmente son malos.
HaroldFinch
7

Otra opción es agregar otro comando a la tubería, uno que no falle:

echo "anything" | grep e | cat

Debido a catque ahora es el último comando en la tubería, es el estado de salida de cat, no de grep, el que se usará para determinar si la tubería falló o no.

Roelvanmeer
fuente
4

Otra opción:

...
set +e
echo "anything" | grep e
set -e
...
Jeff Schaller
fuente
3

Solución

#!/bin/bash -e

echo "before"

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

echo "after"
exit

Explicación

set -e o set -o errexit

Salga inmediatamente si una tubería (que puede consistir en un solo comando simple ), una lista o un comando compuesto (ver SHELL GRAMMARarriba), sale con un estado distinto de cero. La cáscara no sale si el comando que no es parte de la lista de comandos inmediatamente después de una whileo untilpalabra clave, parte de la prueba siguiendo las ifo elifpalabras reservadas, parte de cualquier comando ejecutado en una &&o ||lista, excepto el comando siguientes a la final &&o ||, cualquier comando en una tubería pero el último, o si el valor de retorno del comando se invierte con!. Si un comando compuesto que no sea un subshell devuelve un estado distinto de cero porque un comando falló mientras -ese ignoraba, el shell no se cierra. Una trampa activada ERR, si está establecida, se ejecuta antes de que salga el shell. Esta opción se aplica al entorno de shell y a cada entorno de sub-shell por separado (ver COMMAND EXECUTION ENVIRONMENTarriba), y puede hacer que las subcapas salgan antes de ejecutar todos los comandos en la sub-capa .

Además, :es el comando sin efecto en Bash.

Cyker
fuente