Può grep restituire vero / falso o ci sono metodi alternativi


130

Come parte di questo script, devo essere in grado di verificare se il primo argomento fornito corrisponde alla prima parola del file. In tal caso, uscire con un messaggio di errore; in caso contrario, aggiungere gli argomenti al file. Capisco come scrivere la ifdichiarazione, ma non come utilizzare grepall'interno di uno script. Capisco che grepsarà simile a questo

grep ^$1 schemas.txt

Sento che questo dovrebbe essere molto più semplice di quello che sto facendo.

Ricevo un errore "troppi argomenti" ifsull'istruzione. Mi sono liberato dello spazio tra grep -qe poi mi aspettavo un errore binario dell'operatore.

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi

1
Perdi il [... ]e funzionerà. Anche se probabilmente vuoi citare il tuo schema:if grep -q "^$1" schemas.txt; then …
derobert,

soluzione a una riga che utilizza la funzione "Comando di gruppo" di Bash: stackoverflow.com/questions/6550484/…
Trevor Boyd Smith,

Risposte:


186

greprestituisce un codice di uscita diverso se ha trovato qualcosa (zero) rispetto a se non ha trovato nulla (diverso da zero). In ifun'istruzione, un codice di uscita zero è mappato su "true" e un codice di uscita diverso da zero è mappato su false. Inoltre, grep ha un -qargomento per non produrre il testo corrispondente (ma restituire solo il codice dello stato di uscita)

Quindi, puoi usare grep in questo modo:

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

Come nota veloce, quando fai qualcosa del genere if [ -z "$var" ]…, si scopre che in [realtà è un comando che stai eseguendo, proprio come grep. Sul mio sistema, lo è /usr/bin/[. (Beh, tecnicamente, probabilmente la tua shell è integrata, ma è un'ottimizzazione. Si comporta come se fosse un comando). Funziona allo stesso modo, [restituisce un codice di uscita zero per true, un codice di uscita diverso da zero per false. ( testè la stessa cosa [, ad eccezione della chiusura ])


Perché l'istruzione if non ha bisogno delle parentesi? Ho funzionato senza, ma non capisco perché. Posso ancora nidificarlo senza le parentesi?
Lauren,

@Lauren ti sei perso la nota veloce? [non fa parte della sintassi if, è (concettualmente) un comando che stai eseguendo, proprio come grep
derobert,

2
@Lauren Non usi grep all'interno di [, usi l'uno o l'altro, a seconda delle condizioni che desideri controllare. (Puoi usare qualsiasi comando all'interno di un if, tra l'altro, se controlla solo il codice di uscita.) ... beh, immagino che potresti trovare un motivo per usare grep dentro [, ma sarebbe uno script abbastanza complicato, e il suo non è una cosa normale da fare.
derobert,

3
Cordiali saluti, corri ls -l /usr/bin/\[e man [per vedere che [è un programma come un altro, sembra solo un elemento sintattico - questo dovrebbe renderlo ovvio e più facile da capire. (per comodità, [è anche integrato in bash, dash e altri, ma è comunque un comando). prova anche type -all [a bash.
Cas

1
@AlexanderCska se vuoi che grep stampi le linee abbinate (ad es. Per condurle da qualche parte), quindi ometti l' -qopzione, quell'opzione dice a grep di essere silenzioso (non stampare le linee abbinate).
derobert il

48

Un altro modo semplice è usare grep -c.

Che genera (non restituisce come codice di uscita), il numero di righe che corrispondono al modello, quindi 0 se non c'è corrispondenza o 1 o più se c'è una corrispondenza.

Quindi, se si desidera verificare che il modello sia abbinato 3 o più volte, è necessario:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...

17
Più precisamente, essa uscita 1 se trovato solo una volta. Per produrre 1 indipendentemente dalla quantità di corrispondenze trovate, utilizzare grep -cim1invece.
arte

Questo metodo può anche essere usato per distinguere tra grep error e grep 'pattern found 0 times'. (anche se non con l'esatta istruzione if usata, penso che sia necessaria una variabile)
Evan Benn

3

So di essere in ritardo per questo, ma adoro questa versione corta:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt

0

Se vogliamo catturare la prima parola di un file, dobbiamo aggiungere -zwa grep

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

Senza -zotteniamo la prima parola di una riga. Senza -wotteniamo parole parziali.


-2

Se si desidera utilizzarlo con parentesi quadre, è possibile eseguire quanto segue

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

Questa logica funziona per tutti i comandi, basta posizionare i comandi all'interno del backtick (il pulsante sopra la scheda o nella parte inferiore del pulsante Esc o alla sinistra del pulsante 1)


1
Dovresti citare `grep -q PATTERN file.txt`, altrimenti viene applicato l'operatore split + glob e ciò causerebbe problemi per qualsiasi output che contiene caratteri $IFSo caratteri jolly. Più in generale, [ "`cmd`" ]restituire true se cmdrestituisce almeno una riga non vuota su stdout (con potenziali problemi se restituisce byte NUL). Ciò significa che la shell dovrà archiviare l'intero output in memoria e attendere che finisca. L'utilizzo if cmd | grep -q .invece può essere preferibile a tale riguardo.
Stéphane Chazelas,

Questo comando non avrebbe alcun senso. Lo scopo -qdell'interruttore è di sopprimere grep l'output. Stai dicendo: Controlla PATTERN in file.txt, elimina qualsiasi output, quindi imposta lo stato di ritorno a seconda che sia stato trovato PATTERN. Quindi, ignora lo stato di ritorno, prendi l'output del comando (che abbiamo costretto a essere vuoto), applica la suddivisione delle parole e l'espansione glob file (senza risultati in alcun argomento), quindi esegui il comando [(aka test) con esattamente un argomento - vale a dire , ]- e quindi, poiché ciò comporterà un errore, echo "non trovato". @ StéphaneChazelas, mi sono perso qualcosa?
Carattere jolly

1
@Wildcard, hai ragione, apparentemente ho trascurato il -q. Quel commento avrebbe avuto senso [ `grep PATTERN file.txt ` ], ma come accennato nel commento, [ "`grep -n PATTERN file.txt`" ]sarebbe meglio se PATTERN potesse corrispondere solo a righe vuote. Anche se qui, ovviamente, è quello if grep -q PATTERN file.txtche vuoi.
Stéphane Chazelas,
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.