bash - posso fare: trovare ... -exec questo && quello?


23

C'è un modo per combinare logicamente due comandi di shell che vengono invocati con find - exec ?

Ad esempio, per stampare tutti i file .csv che contengono la stringa foo insieme alla sua occorrenza, vorrei fare:

find . -iname \*.csv -exec grep foo {} && echo {} \;

ma bash si lamenta con "l'argomento mancante di '-exec'"


2
È possibile utilizzare 2 -execin sequenza o utilizzare un singolo -exec sh -c 'grep foo "$0" && printf %s\\n "$0"' {} \;.
jw013,

Questo mi ha inciampato ripetutamente: mi aspetto sempre che il primo argomento passato sh(in questo caso {}) sarà $1e $0sarà qualcosa del genere sh. Ma in realtà, hai ragione, il primo argomento si presenta come $0. Avere il primo argomento come nome del comando invocante è solo una convenzione, che non viene automaticamente applicata in questi casi.
dubiousjim,

Forse dovrebbe essere unito a questa domanda: unix.stackexchange.com/q/18077/4801
dubiousjim

Risposte:


24

-execè un predicato che esegue un comando (non una shell) e viene valutato come vero o falso in base all'esito del comando (stato di uscita zero o diverso da zero).

Così:

find . -iname '*.csv' -exec grep foo {} \; -print

sarebbe stampare il percorso del file se grepreperti foo nel file. Invece di -printte puoi usare un altro -execpredicato o qualsiasi altro predicato

find . -iname '*.csv' -exec grep foo {} \; -exec echo {} \;

Vedi anche gli operatori !e -otrova per negazione e o .

In alternativa, puoi avviare una shell come:

find . -iname '*.csv' -exec sh -c '
   grep foo "$1" && echo "$1"' sh {} \;

O per evitare di dover avviare una shell per ogni file:

find . -iname '*.csv' -exec sh -c '
  for i do
    grep foo "$i" && echo "$i"
  done' sh {} +

10

Il problema che stai affrontando è che la shell prima analizza la riga di comando e vede due semplici comandi separati dall'operatore &&:, find . -iname \*.csv -exec grep foo {}e echo {} \;. Citando &&( find . -iname \*.csv -exec grep foo {} '&&' echo {} \;) ignora che, ma ora il comando eseguito da findè qualcosa di simile grepcon gli argomenti foo, wibble.csv, &&, echoe wibble.csv. È necessario istruire findl'esecuzione di una shell che interpreterà l' &&operatore:

find . -iname \*.csv -exec sh -c 'grep foo "$0" && echo "$0"' {} \;

Si noti che il primo argomento dopo sh -c SOMECOMMANDè $0no $1.

È possibile salvare il tempo di avvio di un processo di shell per ogni file raggruppando le invocazioni dei comandi -exec … +. Per facilitare l'elaborazione, passare un valore fittizio in $0modo che "$@"enumera i nomi dei file.

find . -iname \*.csv -exec sh -c 'for x in "$@"; do grep foo "$x" && echo "$x"; done' \ {} +

Se il comando shell è solo due programmi separati da &&, findpuò fare il lavoro da solo: scrivere due -execazioni consecutive , e il secondo verrà eseguito solo se il primo esce con lo stato 0.

find . -iname \*.csv -exec grep foo {} \; -exec echo {} \;

(Suppongo che grepe echosono solo a scopo illustrativo, in quanto -exec echopuò essere sostituito da -printe l'output risultante non è particolarmente utile comunque.)


2
Tendo a evitare di usare "$ 0" per questo, poiché viene utilizzato anche dalla shell per visualizzare i messaggi di errore. Ad esempio, potresti vedere un ./some-file: grep: command not foundmessaggio di errore confuso . -exec find sh -c '... "$1"' sh {} \;non avrebbe avuto il problema. C'è un refuso (correlato) nel secondo comando find.
Stéphane Chazelas,

3

In questo caso specifico farei:

find . -iname \*.csv -exec grep -l foo \{\} \;

O se hai ack :

ack -al -G '.*\.csv' foo

Per rispondere alla tua vera domanda, qualcosa del genere potrebbe funzionare:

find . -iname \*.csv -exec sh -c "grep foo {} && echo {}" \;


3
Quest'ultimo comando find non è solo non portatile ma anche molto pericoloso poiché i percorsi dei file finiscono per essere valutati come codice shell.
Stéphane Chazelas,

Un motivo in più per cercare di evitarlo usando ack / grep correttamente :)
Dennis Kaarsemaker,

1
L'alternativa di jw013 (fornita in un commento alla domanda) è più sicura in questo senso. (Ho appena notato che le risposte di Gilles e Stephane usano la stessa tecnica.)
dubiousjim
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.