trova -exec cmd {} + vs | xargs


Risposte:


107

La differenza di velocità sarà insignificante.

Ma devi assicurarti che:

  1. Il tuo script non presumerà che nessun file abbia spazio, tabulazione, ecc. Nel nome del file; la prima versione è sicura, la seconda no.

  2. Lo script non tratterà un file che inizia con " -" come un'opzione.

Quindi il tuo codice dovrebbe assomigliare a questo:

find . -exec cmd -option1 -option2 -- {} +

o

find . -print0 | xargs -0 cmd -option1 -option2 --

La prima versione è più breve e più facile da scrivere poiché puoi ignorare 1, ma la seconda versione è più portabile e sicura, poiché " -exec cmd {} +" è un'opzione relativamente nuova in GNU findutils (dal 2005, molti sistemi in esecuzione non ce l'hanno ancora) e recentemente era pieno di bug . Anche molte persone non lo sanno " -exec cmd {} +", come puoi vedere da altre risposte.


4
-print0 è anche un'opzione GNU find (e GNU xargs) che manca in molti sistemi non Linux, quindi l'argomento della portabilità non è così valido. Usare solo -print e lasciare -0 off di xargs, tuttavia, è molto portabile.
dannysauer

7
Il punto è che senza -print0 non funziona se c'è un file con uno spazio o una tabulazione ecc. Questa può essere una vulnerabilità di sicurezza come se ci fosse un nome di file come "foo -o index.html" allora -o sarà trattato come opzione. Prova nella directory vuota: "touch - foo \ -o \ index.html; find. | Xargs cat". Otterrai: "gatto: opzione non valida - 'o'"
Tometzky

2
Il suo esempio è un nome di file che contiene un -. Senza -print0, find sputerà ./foo -o index.html. Quindi forse iniziare con un - non è un grosso problema, ma il risultato è leggermente cambiato e, su un sistema multiutente, potrebbe fornire un vettore di attacco se il tuo script è leggibile a livello mondiale.
bobpaul

2
Una nota su qualcosa che mi ha fatto inciampare qui: l'uso execprodurrà risultati non appena vengono trovati, xargsdove, a quanto pare, aspetterà fino a quando l'intera directory viene cercata prima di scrivere su stdout. Se lo stai provando su una directory di grandi dimensioni e sembra che xargsnon funzioni , è consigliabile pazienza.
FarmerGedden

1
@Motivated Without -print0find restituisce nomi di file separati da newline, ma anche newline può essere parte di un nome di file, rendendolo ambiguo. Il byte 0 non può, quindi è un separatore sicuro. Sì, l'aggiunta --a un comando che lo supporta è una buona pratica quando non è possibile controllare i suoi argomenti, anche se non sempre strettamente necessari o non sicuri.
Tometzky

7
find . | xargs cmd

è più efficiente (viene eseguito il cmdminor numero di volte possibile, a differenza di exec, che viene eseguito cmduna volta per ogni partita). Tuttavia, ti imbatterai in problemi se i nomi dei file contengono spazi o caratteri stravaganti.

Si suggerisce di utilizzare quanto segue:

find . -print0 | xargs -0 cmd

questo funzionerà anche se i nomi di file contengono caratteri funky ( -print0marche finddi stampa corrisponda NUL-terminati, -0marche xargsaspettano questo formato.)


28
Questo non è "find. -Exec cmd {} \;" ma "trova. -exec cmd {} +". Quest'ultimo non eseguirà un file alla volta.
Tometzky

2
Notare che l' xargsapproccio è in realtà significativamente più lento se non ci sono (o solo pochi) file corrispondenti e cmdnon ha molto da fare per ogni file. Ad esempio, se eseguita in una directory vuota, la xargsversione impiegherà almeno il doppio del tempo, poiché devono essere avviati due processi invece di uno solo. (Sì, la differenza di solito è impercettibile su * nix, ma in un ciclo potrebbe essere importante; o, provalo su Windows qualche volta ...)
SamB

2

Le xargsversioni di Modern spesso supportano l'esecuzione di pipeline parallele.

Ovviamente potrebbe essere un punto cardine quando si tratta di scegliere tra find … -exec e … | xargs

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.