find: -exec vs xargs (aka Perché "find | xargs basename" si interrompe?)


10

Stavo cercando di trovare tutti i file di un certo tipo sparsi nelle sottodirectory e per i miei scopi avevo solo bisogno del nome del file. Ho provato a rimuovere il componente path tramite basename, ma non ha funzionato con xargs:

$ find . -name '*.deb' -print | xargs basename 
basename: extra operand `./pool/main/a/aalib/libaa1_1.4p5-37+b1_i386.deb'
Try `basename --help' for more information.

Ottengo la stessa cosa (esattamente lo stesso errore) con una di queste varianti:

$ find . -name '*.deb' -print0 | xargs -0 basename 
$ find . -name '*.deb' -print | xargs basename {}

Questo, d'altra parte, funziona come previsto:

$ find . -name '*.deb' -exec basename {} \;
foo
bar
baz

Questo accade su Cygwin e Debian 5.0.3 aggiornati. La mia diagnosi è che xargs sta per qualche ragione passando due linee di input a basename, ma perché? Cosa sta succedendo qui?

Risposte:


23

Perché basenamevuole solo un parametro ... non MOLTE. E xargscrea molti parametri.

Per risolvere il tuo vero problema (elenca solo i nomi dei file):

 find . -name '*.deb' -printf "%f\n"

Che stampa solo il 'basename' (man find):

 %f     File's name with any leading directories
        removed (only the last element).

1
oooh .... / schiaffeggia di nuovo la fronte / penso di aver bisogno di un libro "trova per i manichini" ...
Quack Quixote

ho pensato che il punto xargsè che crea un elenco di argomenti e alimenta ciascuno il comando che viene dopo? altrimenti qual è la differenza tra questo e find . -name '*.deb' | basename?
WindowsMaker

Il nome di base GNU ora ha -aun'opzione: "supporta più argomenti e tratta ciascuno come un nome".
vescovo

1
@WindowsMaker si xargsconverte stdinin argomenti di comando. In un certo senso, è l'opposto di echo, a cui converte i suoi argomenti stdout. La differenza tra find ... | xargs -n1 basenameo find ... | xargs basename -aed find ... | basenameè che i primi due lavoreranno con le implementazioni di basenamequello ignorato stdin.
8

19

Prova questo:

find . -name '*.deb' | xargs -n1 basename

questa non è la spiegazione, questa è una soluzione alternativa. e la soluzione alternativa è buona come chiamare 'basename' tramite -exec per qualsiasi file trovato.
Akira,

4
+1 ... pur non essendo una spiegazione, questo mi porterebbe a indagare sul cambio di xargs che mostri, che alla fine mi porterebbe al movimento di schiaffo sulla fronte che ho appena usato per leggere le risposte di Akira e John T ...
Quack Quixote

1
Questo è come lo faccio. Non ho voglia di imparare tutti i dettagli del findcomando, quindi lo uso solo per trovare ed elencare i file e uso xargs per tutto il resto.
Ryan C. Thompson,

4

basename accetta solo un singolo argomento. L'utilizzo -execfunziona correttamente perché ognuno {}è sostituito dal nome file corrente in fase di elaborazione e il comando viene eseguito una volta per file corrispondente , anziché cercare di inviare tutti gli argomenti al nome file in una volta sola.


3

xargs può essere costretto a passare anche solo un argomento ...

find . -name '*.deb' -print | xargs -n1 basename

Funziona, tuttavia la risposta accettata viene utilizzata findin un modo più appropriato. Ho trovato questa domanda alla ricerca di xargs basenameproblemi mentre sto usando un altro comando per ottenere un elenco di posizioni dei file. La -n1bandiera per è xargsstata la risposta definitiva per me.

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.