find -exec + vs find | xargs: quale scegliere?


32

Capisco che -execpuò prendere +un'opzione per imitare il comportamento di xargs. C'è qualche situazione in cui preferisci una forma rispetto all'altra?

Personalmente tendo a preferire la prima forma, se non altro per evitare di usare una pipa. Immagino che sicuramente gli sviluppatori di findaver fatto le ottimizzazioni appropriate. Ho ragione?

Risposte:


21

Potresti voler concatenare le chiamate per trovare (una volta, quando hai appreso, che è possibile, che potrebbe essere oggi). Questo è, ovviamente, possibile solo finché rimani in cerca. Una volta che si esegue il pipe su xargs, è fuori portata.

Piccolo esempio, due file a.lst e b.lst:

cat a.lst
fuddel.sh
fiddel.sh

cat b.lst
fuddel.sh

Nessun trucco qui - semplicemente il fatto che entrambi contengono "fuddel" ma solo uno contiene "fiddel".

Supponiamo che non lo sapessimo. Cerchiamo un file che corrisponde a 2 condizioni:

find -exec grep -q fuddel {} ";" -exec grep -q fiddel {} ";" -ls
192097    4 -rw-r--r--   1 stefan   stefan         20 Jun 27 17:05 ./a.lst

Bene, forse conosci la sintassi di grep o di un altro programma per passare entrambe le stringhe come condizione, ma non è questo il punto. Ogni programma che può restituire vero o falso, dato un file come argomento, può essere usato qui - grep era solo un esempio popolare.

E nota, puoi seguire find -exec con altri comandi find, come -ls o -delete o qualcosa di simile. Nota che eliminare non solo rm (rimuove i file), ma rmdir (rimuove anche le directory).

Tale catena viene letta come una combinazione AND di comandi, purché non diversamente specificato (ovvero con un -orinterruttore (e parentesi (che necessitano di mascheramento))).

Quindi non stai lasciando la catena di ricerca, il che è utile. Non vedo alcun vantaggio nell'uso di -xargs, dal momento che devi fare attenzione nel passare i file, il che è qualcosa che non è necessario trovare: gestisce automaticamente il passaggio di ciascun file come argomento singolo per te.

Se ritieni di aver bisogno di mascherare le parentesi graffe {} , sentiti libero di visitare la mia domanda che richiede prove. La mia affermazione è: non lo fai.


3
Questo post mi ha aperto gli occhi su un nuovo modo di usare find. Molte grazie!
Rahmu,

1
"Non vedo alcun vantaggio nell'uso di -xargs". Qual è il -execmodo di fare in xargs -P4modo che tre o quattro core non restino inattivi?
Damian Yerrick,

1
@DamianYerrick: termina il comando -exec non in ";" ma con un segno + (/ più).
utente sconosciuto

25

Il piping sicuro dei nomi dei file xargsrichiede che tu findsupporti l' -print0opzione e tu xargsabbia l'opzione corrispondente per leggerla ( --nullo -0). Altrimenti, i nomi di file con caratteri non stampabili o barre rovesciate o virgolette o spazi bianchi nel nome possono causare comportamenti imprevisti. D'altra parte, find -exec {} +è nelle specifiche POSIXfind , quindi è portatile ed è più sicuro find -print0 | xargs -0e sicuramente più sicuro di find | xargs. Consiglierei di non farne mai afind | xargs meno -print0.


6
Una notevole eccezione alla portabilità di find … -exec … {} +OpenBSD, che ha acquisito questa funzione solo con la versione 5.1 rilasciata nel 2012. Tutti i BSD hanno avuto -print0per diversi anni, anche OpenBSD (anche se ha resistito per un po 'anche a quella funzionalità). Solaris, d'altra parte, si attiene alle funzionalità POSIX, in modo da ottenere -exec +e no -print0.
Gilles 'SO- smetti di essere malvagio' il

-print0è una seccatura e sebbene si possa sostenere che xargs --delimiter "\n"non sia equivalente, non ho mai usato il primo dopo aver scoperto il secondo.
Sridhar Sarnobat,

3
Non vedo quanto -0sia più doloroso di --delimiter "\n".
jw013,

2
Inoltre -0, GNU xargsdeve -revitare di eseguire il comando se non c'è input.
Stéphane Chazelas,

2
Un altro problema | xargs -r0 cmdè che lo cmdstdin è interessato (a seconda xargsdell'implementazione, è /dev/nullo la pipa.
Stéphane Chazelas,

10

Se si utilizza il -exec ... ;modulo (ricordandosi di sfuggire al punto e virgola), si esegue il comando una volta per nome file. Se lo usi -print0 | xargs -0, esegui più comandi per nome file. Dovresti assolutamente usare il -exec +modulo, che mette più file in una singola riga di comando ed è molto più veloce quando è coinvolto un gran numero di file.

Un grande vantaggio dell'utilizzo xargsè la possibilità di eseguire più comandi in parallelo utilizzando xargs -P. Su sistemi multi-core, ciò può fornire enormi risparmi di tempo.


6
Volevi dire -Pinvece di -p. Tieni presente che xargs -Pnon è nello standard POSIX, mentre lo find -exec {} +è, il che è importante se stai andando per la portabilità.
jw013,

@Alexios Non devi sfuggire al segno più, perché non ha un significato speciale per la shell: find /tmp/ -exec ls "{}" +funziona bene.
Daniel Kullmann,

1
Corrente, ovviamente. Sono scappato -execda così tanto tempo dopo (sono un masochista, non uso nemmeno le virgolette per scappare {}, scrivo sempre \{\}; non chiedere), tutto sembra che debba essere evitato adesso.
Alexios,

1
@Alexios: Se trovi un esempio (tranne che di essere un masochista) in cui il mascheramento delle parentesi graffe è utile, forniscilo come risposta alla mia domanda qui : questo suggerimento è obsoleto e solo un relitto nella manpage. Non ho mai visto un esempio in cui find /tmp/ -exec ls {} +non funzionerebbe.
utente sconosciuto

1
Per me, questa è la memoria muscolare che si è formata ai tempi di SunOS 4. Da quando lo faccio da anni, non ho notato completamente quando ho bashiniziato ad accettare le parentesi graffe alla lettera. Sono abbastanza sicuro che almeno una delle vecchie conchiglie che ho usato abbia lanciato sibilanti se le parentesi graffe non fossero sfuggite.
Alexios,

8

Per quanto riguarda le prestazioni, ho pensato che -exec … +sarebbe semplicemente meglio perché è un singolo strumento che fa tutto il lavoro, ma una parte della documentazione di GNU findutil afferma che -exec … +potrebbe essere meno efficiente in alcuni casi:

[trova con -exec … +] può essere meno efficiente di alcuni usi di xargs; ad esempio, xargsconsente la creazione di nuove righe di comando mentre il comando precedente è ancora in esecuzione e consente di specificare un numero di comandi da eseguire in parallelo. Tuttavia, il find ... -exec ... +costrutto presenta il vantaggio di un'ampia portabilità. I rilevamenti GNU non supportano ' -exec ... +' fino alla versione 4.2.12 [gennaio 2005] ; uno dei motivi di ciò è che ha già avuto " -print0" l'azione in ogni caso.

Non ero esattamente sicuro di cosa significasse, quindi ho chiesto nella chat in cui Derobert lo spiegava come:

findprobabilmente potrebbe continuare a cercare il prossimo batch di file mentre -exec … +è in esecuzione, ma non è così.
find … | xargs …sì, perché la ricerca è un processo diverso e continua a funzionare fino a quando il buffer del tubo si riempie

(Formattazione da parte mia.)

Quindi c'è quello. Ma se le prestazioni contano davvero, dovresti fare un benchmarking realistico o piuttosto chiederti anche se vorresti usare la shell in questi casi.

Qui su questo sito penso che sia meglio consigliare alle persone di usare il -exec … +modulo ogni volta che è possibile perché solo perché è più semplice e per i motivi menzionati nelle altre risposte qui (es. Gestire strani nomi di file senza dover pensare molto).

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.