Domanda

Come posso fare in modo che xargs esegua il comando esattamente una volta per ogni riga di input fornita? Il suo comportamento predefinito è di tagliare le linee ed eseguire il comando una volta, passando più linee a ciascuna istanza.

  

Da http://en.wikipedia.org/wiki/Xargs :

     

find / path -type f -print0 | xargs -0 rm

     

In questo esempio, find alimenta l'input di xargs con un lungo elenco di nomi di file. xargs quindi suddivide questo elenco in elenchi secondari e chiama rm una volta per ciascun elenco secondario. Questo è più efficiente di questa versione funzionalmente equivalente:

     

find / path -type f -exec rm '{}' \;

So che find ha il " exec " bandiera. Sto solo citando un esempio illustrativo da un'altra risorsa.

È stato utile?

Soluzione

Quanto segue funzionerà solo se non hai spazi nel tuo input:

xargs -L 1
xargs --max-lines=1 # synonym for the -L option

dalla pagina man:

-L max-lines
          Use at most max-lines nonblank input lines per command line.
          Trailing blanks cause an input line to be logically continued  on
          the next input line.  Implies -x.

Altri suggerimenti

Mi sembra che tutte le risposte esistenti su questa pagina siano sbagliate, inclusa quella contrassegnata come corretta. Ciò deriva dal fatto che la domanda è formulata in modo ambiguo.

Riepilogo: & nbsp; Se vuoi eseguire il comando " esattamente una volta per ogni riga di input fornita, " passando l'intera riga (senza la nuova riga) al comando come argomento singolo, allora questo è il miglior modo compatibile UNIX per farlo:

... | tr '\n' '\0' | xargs -0 -n1 ...

GNU xargs può o meno avere estensioni utili che ti consentono di eliminare tr , ma non sono disponibili su OS X e altri sistemi UNIX.

Ora per la lunga spiegazione & # 8230;


Ci sono due problemi da tenere in considerazione quando si usa xargs:

  1. come divide l'input in " argomenti " ;; e
  2. 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 dell'input fornito? Il suo comportamento predefinito è di inserire input negli argomenti ed eseguire il comando il minor numero di volte possibile , passando più argomenti a ciascuna istanza.

quindi 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. input split e doveva essere letta in questo modo (molte persone che vengono qui sembrano pensare che sia così, o stanno confondendo i due problemi):

  

Come posso fare in modo che xargs esegua il comando con esattamente un argomento per ogni riga di input fornita? Il suo comportamento predefinito è tagliare le linee attorno agli spazi bianchi .

allora la risposta è più sottile.

Si potrebbe pensare che -L 1 potrebbe 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 

Non solo, ma se una riga termina con spazi bianchi, viene aggiunta alla successiva:

$ echo 

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

$ echo 

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

$ 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 successiva:

<*>

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>one \ntwo\nthree and four' | xargs -L 1 ./show -> "one" "two" -> "three" "and" "four"

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>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 successiva:

<*>

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>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 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>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 successiva:

<*>

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>one \ntwo\nthree and four' | xargs -L 1 ./show -> "one" "two" -> "three" "and" "four"

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>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 successiva:

<*>

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show -> "one " -> "two" -> "three and four" 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 successiva:

<*>

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>one \ntwo\nthree and four' | xargs -L 1 ./show -> "one" "two" -> "three" "and" "four"

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>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 successiva:

<*>

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>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 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>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 successiva:

<*>

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>one \ntwo\nthree and four' | xargs -L 1 ./show -> "one" "two" -> "three" "and" "four"

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>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 successiva:

<*>

Chiaramente, -L non riguarda il modo in cui xargs suddivide l'input in argomenti.

L'unico argomento che lo fa in modo multipiattaforma (escluse le estensioni GNU) è -0 , che divide l'input in byte NUL.

Quindi, si tratta solo di tradurre nuove righe in NUL con l'aiuto di tr :

<*>

Ora l'analisi dell'argomento sembra a posto, incluso lo spazio bianco finale.

Infine, se combini questa tecnica con -n 1 , otterrai esattamente un'esecuzione di comando per riga di input, qualunque input tu abbia, che potrebbe essere un altro modo per esaminare la domanda originale ( forse il più intuitivo, dato il titolo):

<*>

Se vuoi eseguire il comando per ogni riga (es. risultato) proveniente da find , allora di cosa hai bisogno xargs per ?

Prova:

find path -type f -exec your-command {} \;

dove il {} letterale viene sostituito dal nome del file e il \; letterale è necessario per find per sapere che il comando personalizzato termina lì.

EDIT:

(dopo la modifica della tua domanda chiarendo che conosci -exec )

Da man xargs :

  

-L linee massime
   Utilizzare al massimo linee massime linee di input non vuote per riga di comando. trailing    gli spazi vuoti fanno sì che una riga di input continui logicamente sulla riga di input successiva.    Implica -x.

Nota che i nomi di file che terminano con spazi vuoti potrebbero causare problemi se usi xargs :

$ mkdir /tmp/bax; cd /tmp/bax
$ touch a\  b c\  c
$ find . -type f -print | xargs -L1 wc -l
0 ./c
0 ./c
0 total
0 ./b
wc: ./a: No such file or directory

Quindi, se non ti interessa l'opzione -exec , è meglio usare -print0 e -0 :

$ find . -type f -print0 | xargs -0L1 wc -l
0 ./c
0 ./c
0 ./b
0 ./a
  

Come posso fare in modo che xargs esegua il comando esattamente una volta per ogni riga di input fornita?

Non utilizzo la risposta -L 1 perché non gestisce i file con spazi all'interno che è una funzione chiave di find -print0 .

echo "file with space.txt" | xargs -L 1 ls
ls: file: No such file or directory
ls: space.txt: No such file or directory
ls: with: No such file or directory

Una soluzione migliore è usare tr per convertire i newline in caratteri null ( \ 0 ), e quindi usare l'argomento xargs -0 .

echo "file with space.txt" | tr '\n' '\0' | xargs -0 ls
file with space.txt

Se è quindi necessario limitare il numero di chiamate, è possibile utilizzare l'argomento -n 1 per effettuare una chiamata al programma per ciascun input:

echo "file with space.txt" | tr '\n' '\0' | xargs -0 -n 1 ls

Ciò consente anche di filtrare l'output di find prima convertendo le interruzioni in valori null.

find . -name \*.xml | grep -v /workspace/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar

Un'altra alternativa ...

find /path -type f | while read ln; do echo "processing $ln"; done
find path -type f | xargs -L1 command 

è tutto ciò di cui hai bisogno.

Questi due modi funzionano anche e funzioneranno con altri comandi che non usano find!

xargs -I '{}' rm '{}'
xargs -i rm '{}'

esempio di utilizzo:

find . -name "*.pyc" | xargs -i rm '{}

eliminerà tutti i file pyc in questa directory anche se i file pyc contengono spazi.

Il seguente comando troverà tutti i file (-type f) in / path e poi li copierà usando cp nella cartella corrente. Si noti l'uso se -I% per specificare un carattere segnaposto nella riga di comando cp in modo che gli argomenti possano essere inseriti dopo il nome del file.

find / path -type f -print0 | xargs -0 -I% cp%.

Testato con xargs (GNU findutils) 4.4.0

Puoi limitare il numero di righe o argomenti (se ci sono spazi tra ogni argomento) usando rispettivamente i flag --max-lines o --max-args.

  -L max-lines
         Use at most max-lines nonblank input lines per command line.  Trailing blanks cause an input line to be logically continued on the next  input
         line.  Implies -x.

  --max-lines[=max-lines], -l[max-lines]
         Synonym  for  the -L option.  Unlike -L, the max-lines argument is optional.  If max-args is not specified, it defaults to one.  The -l option
         is deprecated since the POSIX standard specifies -L instead.

  --max-args=max-args, -n max-args
         Use at most max-args arguments per command line.  Fewer than max-args arguments will be used if the size (see  the  -s  option)  is  exceeded,
         unless the -x option is given, in which case xargs will exit.

Sembra che non abbia abbastanza reputazione per aggiungere un commento a la risposta di Tobia sopra , quindi sto aggiungendo questo " risposta " per aiutare quelli di noi che desiderano sperimentare xargs allo stesso modo sulle piattaforme Windows.

Ecco un file batch di Windows che fa la stessa cosa di Tobia con la codifica rapida " show " script:

@echo off
REM
REM  cool trick of using "set" to echo without new line
REM  (from:  http://www.psteiner.com/2012/05/windows-batch-echo-without-new-line.html)
REM
if "%~1" == "" (
    exit /b
)

<nul set /p=Args:  "%~1"
shift

:start
if not "%~1" == "" (
    <nul set /p=, "%~1"
    shift
    goto start
)
echo.

Le risposte di @Draemon sembrano essere corrette con " -0 " anche con spazio nel file.

Stavo provando il comando xargs e ho scoperto che " -0 " funziona perfettamente con " -L " ;. anche gli spazi vengono trattati (se l'input è stato terminato con null). il seguente è un esempio:

#touch "file with space"
#touch "file1"
#touch "file2"

Quanto segue dividerà i valori null ed eseguirà il comando su ciascun argomento nell'elenco:

 #find . -name 'file*' -print0 | xargs -0 -L1
./file with space
./file1
./file2

quindi -L1 eseguirà l'argomento su ciascun carattere nullo se usato con " -0 " ;. Per vedere la differenza prova:

 #find . -name 'file*' -print0 | xargs -0 | xargs -L1
 ./file with space ./file1 ./file2

anche questo verrà eseguito una volta:

 #find . -name 'file*' -print0  | xargs -0  | xargs -0 -L1
./file with space ./file1 ./file2

Il comando verrà eseguito una volta come " -L " ora non si divide su byte null. devi fornire sia " -0 " e " -L " lavorare.

Nel tuo esempio, il punto di reindirizzare l'output di find a xargs è che il comportamento standard dell'opzione -exec di find è quello di eseguire il comando una volta per ogni file trovato. Se stai usando find e vuoi il suo comportamento standard, allora la risposta è semplice: non usare xargs per cominciare.

esegue il task di formica clean-all su ogni build.xml nella cartella corrente o in quella secondaria.

find . -name 'build.xml' -exec ant -f {} clean-all \;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top