Utilizzo dei connettori dopo il comando find


10

Voglio che il mio bash stampi 'trovato' solo se viene trovato qualcosa, usando il comando find. Ma usare && non aiuta: anche se non trovo nulla, vengo stampato 'trovato'. Esempio:

$ pwd
/data/data/com.termux/files/home/test/test1/test4
$ ls
xaa  xab
$ find . -name xac && echo 'found'
found
$ find . -name xaa && echo 'found'
./xaa
found

Risposte:


18

Puoi farlo findstampare found:

find . -name xac -printf "found\n" -quit

La -quitfarà find uscire dopo la prima partita , quindi foundviene stampato solo al massimo una volta.

Su un thread simile su Unix e Linux ( fai in modo che la ricerca non riesca quando non viene trovato nulla ), grep -qzrestituivo uno stato di uscita diverso da zero se findnon viene trovato nulla:

find /some/path -print0 -quit | grep -qz .

Che puoi usare per costruire comandi composti usando &&o if:

find /some/path -print0 -quit | grep -qz . && echo found

Ho dovuto fissarlo un po '. /some/pathdice a dove iniziare a cercare, ma nulla gli dice cosa cercare. Lo stesso nella tua risposta collegata. Ciò che funziona per me è find /some/path -name xac -print0 -quit | grep -qz . && echo found. Ho dimenticato qualcosa?
Joe,

@Joe quello che conta qui è il -print0 -quit. Ciò che metti prima dipende da ciò che vuoi trovare. Ho scelto di ometterlo qui.
muru,

13

La risposta di Muru è appropriata e adatta per i casi in cui vogliamo stampare qualcosa se viene trovato il file. Per un caso generale quando vogliamo eseguire un comando esterno, come ad esempio echo, potremmo usare -execflag.

$ find . -name 'xac' -exec echo "I found " {} \; -quit             
I found  ./xac

La {}parte passa il nome file al comando tra -exece \;come argomenti. Nota \prima ;: impedisce alla shell di interpretare erroneamente ; nel punto e virgola di chiusura della shell indica la fine del comando, ma quando viene evasa con una barra, la shell lo tratterà come un testo letterale da passare al findcomando e per trovare il comando serve come -execargomento di chiusura della bandiera.


Per costruire condizionali del if found do this; else do thatgenere, potremmo usare il comando substition $()e testcommand (aka [):

$ [ "x$(find . -name 'noexist' -print -quit)" != "x" ] && echo "found" || echo "not found"                                                                                              
not found

$ [ "x$(find . -name 'xac' -print -quit)" != "x" ] && echo "found" || echo "not found"                                                                                                  
found

Affrontare il commento di Dan

Dan nei commenti ha chiesto:

L'eco "Ho trovato {}" non sarebbe migliore dell'eco "Ho trovato" {}? Forse per l'eco va bene, ma se qualcuno copia il comando e sostituisce l'eco con un altro comando, potrebbe avere un problema

Capiamo prima il problema. Di solito, nelle shell esiste il concetto di suddivisione delle parole, il che significa che variabili non quotate e parametri posizionali verranno espansi e trattati come elementi separati. Per esempio, se si dispone di variabili vare contiene hello worldil testo, quando si esegue touch $varla shell scomposizione in due elementi separati helloe worlde touchcapirà che come se si stesse cercando di creare 2 file separati; se lo fai touch "$var", allora shell tratterà hello worldcome una sola unità e touchcreerà un solo file. Questo è importante per capire che ciò accade solo a causa del funzionamento delle shell.

Al contrario, findnon soffre di tale comportamento, poiché i comandi vengono elaborati da findsoli ed eseguiti da una execvp()chiamata di sistema, quindi non è coinvolta alcuna shell. Mentre le parentesi graffe hanno un significato speciale nelle shell, perché appaiono nel mezzo del findcomando e non all'inizio, in questo caso non hanno alcun significato speciale per le shell. Ecco un esempio Creiamo alcuni nomi di file difficili e proviamo a passarli come argomento da statcomandare.

$ touch with$'\t'tab.txt with$' 'space.txt with$'\n'newline.txt

$ find -type f -exec stat -c "%F" {} \; -print                                                                                                                         
regular empty file
./with?newline.txt
regular empty file
./with space.txt
regular empty file
./with?tab.txt

Come puoi vedere, statriceve perfettamente nomi di file difficili find, il che è uno dei motivi principali per cui è raccomandato per l'uso in script portatili e particolarmente utile quando stai attraversando l'albero di directory e vuoi fare qualcosa con nomi di file che potrebbero potenzialmente avere personaggi speciali in loro. Pertanto, non è necessario citare parentesi graffe per i comandi eseguiti in find.

È una storia diversa quando viene coinvolta la shell. A volte è necessario utilizzare una shell per elaborare il nome file. In tal caso, la quotazione sarà davvero importante, ma è importante rendersi conto che non è un problema di ricerca: è la shell che fa la divisione delle parole.

$ find -type f -exec bash -c "stat {}" sh \;   
stat: cannot stat './with': No such file or directory
sh: line 1: newline.txt: command not found
stat: cannot stat './with': No such file or directory
stat: cannot stat 'space.txt': No such file or directory
stat: cannot stat './with': No such file or directory
stat: cannot stat 'tab.txt': No such file or directory

Quindi quando citiamo all'interno della shell , funzionerà. Ma ancora una volta, questo è importante per la shell, no find.

$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;                                                                                                                 
regular empty file
regular empty file
regular empty file

Non echo "I found {}"sarebbe meglio di echo "I found " {}? Forse per l'eco va bene, ma se qualcuno copia il comando e sostituisce l'eco con un altro comando, potrebbe avere un problema.
Dan

@ L'argomento è stato troppo lungo per essere discusso nei commenti, quindi ho apportato una modifica alla mia risposta. Per favore, vedi
Sergiy Kolodyazhnyy,

1
Grazie per avermi finalmente fatto capire perché quel punto e virgola doveva essere lì. Inoltre, un'ottima spiegazione del preventivo.
Joe,

1
Non mi aspettavo così tanti dettagli come una risposta al mio commento. Apprezzo molto questa spiegazione, grazie!
Dan
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.