2014-10-14 15 views
5

in uno script bash, ho un elenco di righe in un file desidero grep e quindi visualizzare sullo standard out, che è più facile fatto con un po 'di lettura:grep, messaggio Print altro per nessun risultato

grep "regex" "filepath" | while read line; do 
    printf "$line\n" 
done 

Tuttavia, vorrei informare l'utente se nessuna riga è stata abbinata dal grep. So che si può fare questo da updating a variable inside the loop ma sembra un approccio molto più elegante (se possibile) sarebbe quello di provare a leggere una riga in un ciclo fino a quando, e se non ci fosse uscita, potrebbe essere visualizzato un messaggio di errore.

Questo è stato il mio primo tentativo:

grep "regex" "filepath" | until [[ -z ${read line} ]]; do 
    if [[ -z $input ]]; then 
     printf "No matches found\n" 
     break 
    fi 
    printf "$line\n" 
done 

Ma in questo caso il comando di lettura non è corretto, e non ero sicuro di un altro modo in cui la frase la query. Questo approccio è possibile e, in caso contrario, esiste una soluzione più adeguata al problema?

+2

Nel primo esempio, è necessario solo il grep e si ottiene lo stesso comportamento. È solo un esempio o è ciò che vuoi veramente fare? – jordanm

+0

Lo fa? Potresti dimostrare come? Sono ancora abbastanza nuovo da bash e non capisco come usare grep per ottenere quel comportamento. Il codice che ho scritto dimostra il risultato finale che sto cercando di raggiungere, per rispondere alla tua domanda. Ah il gatto è ridondante. Rimosso, grazie. – seraththundhuil

+0

grep stampa le righe corrispondenti sul suo output standard di default, ecco perché il ciclo while/read funziona leggendo input standard. Basta eseguire "grep" regex "" filepath "' e dovresti vedere le linee corrispondenti. –

risposta

13

non hai bisogno di un ciclo a tutti se si desidera semplicemente visualizzare un messaggio quando non c'è alcuna corrispondenza. Invece puoi usare il codice di ritorno di grep. Una semplice dichiarazione if sarà sufficiente:

if ! grep "regex" "filepath"; then 
    echo "no match" >&2 
fi 

Questo visualizzerà i risultati delle partite grep (dato che è il comportamento predefinito di grep), e verrà visualizzato il messaggio di errore se non lo fa.

Un'alternativa popolare a if ! consiste nell'utilizzare l'operatore ||. foo || bar può essere letto come "do foo oppure bar" o "se non foo quindi bar". La risposta di

grep "regex" "filepath" || echo "no match" >&2 
1

Come menzionato da @jordanm, non è necessario un ciclo nel caso d'uso che hai menzionato.

output=$(grep "regex" "file") 
if [[ -n $output ]]; then 
    echo "$output" 
else 
    echo "Sorry, no results..." 
fi 

Se è necessario per scorrere i risultati per l'elaborazione (e non solo la visualizzazione sullo standard output) allora si può fare qualcosa di simile:

output=$(grep "regex" "file") 
if [[ -n $output ]]; then 
    while IFS= read -r line; do 
     # do something with $line 
    done <<< "$output" 
else 
    echo "Sorry, no results..." 
fi 

Questo metodo evita di usare una tubazione o subshell in modo che tutte le assegnazioni di variabili effettuate all'interno del ciclo saranno disponibili per il resto dello script.

Inoltre, non sono sicuro se questo si riferisce a ciò che si sta tentando di fare, ma grep ha la possibilità di caricare i modelli da un file (uno per riga). Si è invocato come segue:

grep search_target -f pattern_file.txt 
1

John Kugelman è quella corretta e succinta e si dovrebbe accettarlo. Sto affrontando la tua domanda sulla sintassi qui solo per completezza.

Non è possibile utilizzare per eseguire ${read line}read - la sintassi brace significa in realtà (vagamente) che si desidera che il valore di una variabile il cui nome contiene uno spazio. Forse si stava girando per $(read line) ma in realtà, il modo corretto di scrivere il ciclo until sarebbe più lungo le linee di

grep "regex" "filepath" | until read line; [[ -z "$line" ]]; do 

... ma, naturalmente, quando non v'è alcuna uscita, il gasdotto riceverete linee , quindi while e until sono entrambi sbagliati qui.

Vale la pena di sottolineare che il motivo per cui è necessario un separato do è che è possibile avere più comandi in là. Anche qualcosa come

while output=$(grep "regex filepath"); echo "grep done, please wait ..."; 
    count=$(echo "$output" | wc -l); [[ $count -gt 0 ]] 
do ... 

anche se, di nuovo, questo è molto più arcano di quanto non avresti mai veramente bisogno. (E in questo caso particolare, probabilmente vorrai effettivamente , non while.)

Come altri già notato, non c'è motivo di usare un loop come quello qui, ma volevo risolvere la domanda su come scrivere un ciclo come questo per ogni volta che ne vuoi uno.

Problemi correlati