Impedire a grep di uscire in caso di nomatch


29

Questo script non fa eco "dopo":

#!/bin/bash -e

echo "before"

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

echo "after"
exit

Lo farebbe anche se avessi rimosso l' -eopzione sulla riga shebang, ma desidero mantenerlo in modo che il mio script si interrompa in caso di errore. Non considero grep che non trova corrispondenza come errore. Come posso impedirgli di uscire così bruscamente?


Questa è un'osservazione pensata solo per considerazione. Forse la logica di questa sceneggiatura dovrebbe essere ripensata. Se non è importante trovare la stringa, perché cercarla? La definizione di grep è tale che si prendono decisioni basate sulla presenza o l'assenza di una stringa. Se non ti interessa in entrambi i casi, non è importante. Inoltre, sembrerebbe -epresupporre che ti interessi: così tanto che qualsiasi problema è catastrofico.
Andrew Falanga,

2
@AndrewFalanga Mi interessa in entrambi i casi poiché sto effettivamente analizzando il contenuto var=$(complex command | grep complex_pattern)che potrebbe essere nullo (nel qual caso il mio programma non dovrebbe terminare). Questo è solo uno script ridotto che causa il problema. Nessun buco nero metafisico nella logica qui, giusto? ;)
iago-lito,

Sapere ora che intendevi catturare l'output chiarisce alcune cose. Come presentato, mi ha confuso.
Andrew Falanga,

Risposte:


33
echo "anything" | grep e || true

Spiegazione:

$ 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

Il "||" significa "o". Se la prima parte del comando "non riesce" (che significa "grep e" restituisce un codice di uscita diverso da zero), la parte dopo "||" viene eseguito, ha esito positivo e restituisce zero come codice di uscita ( truerestituisce sempre zero).


3
Una versione leggermente più corta della stessa che non gira /bin/trueè: command || :(quindi nel tuo caso set -e; grep 'needle' haystack || :).
DopeGhoti,

1
@DopeGhoti, trueè integrato in alcune shell (almeno bash 4.3su RHEL)
iruvar,

3
Non valido perché se il primo comando fallisce nasconderà l'errore. Una soluzione corretta dovrebbe restituire un valore diverso da zero se il primo comando nella pipe non riesce.
sorin

11

Un modo affidabile per inviare messaggi in modo sicuro e facoltativo 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

Secondo il manuale posix , il codice di uscita 1 indica che non sono state selezionate righe e> 1 indica un errore.


1
Questa dovrebbe essere la risposta accettata, poiché sopprime il codice di uscita di avviso (1) solo se grep non trova nulla, ma trasmette errori veri (codici di uscita> 1). Le altre soluzioni qui eliminano sempre i veri errori, che di solito sono cattivi.
HaroldFinch

7

Un'altra opzione è quella di aggiungere un altro comando alla pipeline - uno che non fallisce:

echo "anything" | grep e | cat

Poiché catora è l'ultimo comando nella pipeline, sarà lo stato di uscita di cat, non di grep, che verrà utilizzato per determinare se la pipeline è fallita o meno.



3

Soluzione

#!/bin/bash -e

echo "before"

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

echo "after"
exit

Spiegazione

set -e o set -o errexit

Esci immediatamente se una pipeline (che può consistere in un singolo comando semplice ), un elenco o un comando composto (vedi SHELL GRAMMARsopra), esce con uno stato diverso da zero. La shell non si chiude se il comando che fallisce fa parte dell'elenco dei comandi immediatamente dopo una whileo untilparola chiave, parte del test che segue le parole riservate ifo elif, parte di qualsiasi comando eseguito in una &&o ||lista tranne il comando che segue il finale &&o ||, qualsiasi comando in una pipeline ma l'ultimo, o se il valore di ritorno del comando viene invertito con!. Se un comando composto diverso da una subshell restituisce uno stato diverso da zero perché un comando non -eè stato eseguito mentre veniva ignorato, la shell non si chiude. Una trap su ERR, se impostata, viene eseguita prima che la shell esca. Questa opzione si applica all'ambiente shell e a ciascun ambiente sub-shell separatamente (vedere COMMAND EXECUTION ENVIRONMENTsopra) e può causare la chiusura delle subshell prima di eseguire tutti i comandi nella subshell.

Inoltre, :è il comando senza effetti in Bash.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.