Mi sembra che tutte le risposte esistenti su questa pagina siano sbagliate, compresa quella contrassegnata come corretta. Ciò deriva dal fatto che la domanda è formulata in modo ambiguo.
Riepilogo: se si desidera eseguire il comando "esattamente una volta per ogni riga di input fornita", passando l'intera riga (senza la nuova riga) al comando come singolo argomento, questo è il modo migliore compatibile UNIX per farlo:
... | tr '\n' '\0' | xargs -0 -n1 ...
GNU xargs
può avere o meno estensioni utili che ti consentono di eliminare tr
, ma non sono disponibili su OS X e altri sistemi UNIX.
Ora per la lunga spiegazione ...
Ci sono due problemi da prendere in considerazione quando si usa xargs:
- come divide l'input in "argomenti"; e
- quanti argomenti per passare il comando figlio alla volta.
Per testare il comportamento di xargs, abbiamo bisogno di un'utilità che mostri quante volte viene eseguita e con quanti argomenti. Non so se esiste un'utilità standard per farlo, ma possiamo codificarlo abbastanza facilmente in bash:
#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo
Supponendo di salvarlo come show
nella directory corrente e renderlo eseguibile, ecco come funziona:
$ ./show one two 'three and four'
-> "one" "two" "three and four"
Ora, se la domanda originale riguarda davvero il punto 2. sopra (come penso, dopo averlo letto più volte) e deve essere letta in questo modo (cambia in grassetto):
Come posso fare in modo che xargs esegua il comando esattamente una volta per ogni argomento di input fornito? Il suo comportamento predefinito è di inserire l' input in argomenti ed eseguire il comando il minor numero di volte possibile , passando più argomenti a ciascuna istanza.
allora la risposta è -n 1
.
Confrontiamo il comportamento predefinito di xargs, che divide l'input attorno agli spazi bianchi e chiama il comando il minor numero di volte possibile:
$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"
e il suo comportamento con -n 1
:
$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"
Se, d'altra parte, la domanda originale riguardava il punto 1. suddivisione degli input e doveva essere letta in questo modo (molte persone che vengono qui sembrano pensare che sia il caso o confondono le due questioni):
Come posso fare in modo che xargs esegua il comando con esattamente un argomento per ogni riga di input fornita? Il suo comportamento predefinito è di tagliare le linee attorno agli spazi bianchi .
allora la risposta è più sottile.
Si potrebbe pensare che -L 1
possa essere di aiuto, ma si scopre che non cambia l'analisi degli argomenti. Esegue il comando solo una volta per ogni riga di input, con tutti gli argomenti presenti su quella riga di input:
$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
Non solo, ma se una riga termina con spazi bianchi, viene aggiunta alla seguente:
$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Chiaramente, -L
non si tratta di cambiare il modo in cui xargs divide l'input in argomenti.
L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0
, che divide l'input attorno ai byte NUL.
Quindi, si tratta solo di tradurre le nuove righe in NUL con l'aiuto di tr
:
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.
Infine, se combini questa tecnica con -n 1
, ottieni esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per guardare alla domanda originale (forse la più intuitiva, dato il titolo):
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"
find /path -type f -delete
sarebbe ancora più efficiente :)