Passando più parametri tramite xargs


17

Mi piacerebbe essere in grado di utilizzare xargsper eseguire più parametri in diverse parti di un comando.

Ad esempio, quanto segue:

echo {1..8} | xargs -n2 | xargs -I v1 -I v2 echo the number v1 comes before v2

Spero che possa tornare

the number 1 comes before 2
the number 3 comes before 4 

... eccetera

Questo è realizzabile? Sospetto che il mio uso multiplo di -Isia errato.

Risposte:


29

Credo che non puoi usare in -Iquel modo. Ma puoi ottenere l'effetto / il comportamento che vuoi dicendo:

echo {1..8} | xargs -n2 sh -c 'echo "the number $1 comes before $2"' sh

Questo, in sostanza, crea uno script shell ad una riga ad hoc , che xargsviene eseguito tramite sh -c. I due valori che xargsanalizzano l'input vengono passati a questo "script". La shell quindi assegna quei valori a $1e $2, ai quali è possibile fare riferimento nello "script".


4
Grazie - fantastico. Ho letto l'uomo per sh e sto lottando per capire cosa fa la seconda chiamata a sh e, per estensione, perché la sua omissione produce "metà" del risultato.
Damien Sawyer,

6
@DamienSawyer Non c'è una seconda chiamata a sh. Il finale shalla fine è ciò che viene messo $0. $0è di solito ciò che detiene il nome dell'interprete o della sceneggiatura.
Kusalananda

Ho appena sostituito il finale shcon echo $shcui funziona. Quindi shfunzioni finali come segnaposto
gennaio

Bene, questa è una semplificazione eccessiva di ciò che Kusalananda ha detto.
Scott,

6

Nel caso specifico di printf, puoi sempre fare:

echo {1..8} | xargs printf 'the number %s comes before %s\n'

perché printfha una xargscapacità intrinseca simile a quella di eseguire più volte se gli vengono dati più argomenti di quelli necessari per una singola invocazione. Anche se questo ha poco vantaggio

printf 'the number %s comes before %s\n' {1..8}

E per elenchi di grandi dimensioni, il semplice xargscomando potrebbe comportare l' xargsesecuzione di diverse istanze di printf, alcune delle quali potrebbero avere un numero dispari di argomenti. Potresti passare -n 1000per xargsproteggerti da questo, dove 1000 è un numero pari che dovrebbe essere abbastanza piccolo da non raggiungere la lista arg limite troppo lungo e abbastanza grande da evitare di eseguire così tanti printfs.

Si noti che xargschiamerebbe non l'integrato della shell printf, ma l'esterno printf, con ogni invocazione in un nuovo processo separato.

Si noti inoltre che per un input vuoto, ad eccezione di alcuni BSD, verrebbe comunque eseguito printfuna volta senza argomenti. GNU xargse compatibili hanno un'opzione -r (o --no-run-if-empty) per evitarlo.

Per essere chiari, questa semplice risposta è specifica per il tuo printfesempio e non funzionerebbe nel caso generale in cui devi passare due parametri alla volta al tuo comando (come sarebbe il caso diff, ad esempio). Per risolvere il problema generale con zsh, è possibile utilizzare:

for i j ({1..8}) echo "the number $i comes before $j"

(1) IMHO, la zshparte di cui sopra è una vera risposta, e la parte xargssenza opzioni è solo una stranezza. In tal caso, prenderei in considerazione l'idea di porre prima la vera risposta. (2) Presumo che tu abbia un motivo per non usare le virgolette nel tuo zshcomando. In tal caso, potresti volerlo affermare, affinché la gente non legga quanto sopra e inizi a pensare che le citazioni non siano importanti. (O semplicemente includerli, poiché non fanno male.)
Scott,

Questo è davvero fantastico. Sono atterrato qui alla ricerca di qualcosa di simile in cui non ero sicuro in anticipo di quanti argomenti che avrei ricevuto che dovevano essere inseriti nella riga di comando del prossimo argomento. fatto qualcosa di simileawk -F'\t' '/match/{printf $1"\0"$2"\0"}' | xargs -0 printf -- '-args1 "%s" -args2 "%s"' | xargs mycommand
keithpjolley

@keithpjolley, il tuo utilizzo del -0primo xargsper renderlo più affidabile è sconfitto dal fatto che non lo usi nel secondo. Inoltre, il primo argomento di printf(sia l'utilità standalone che awkla printf()funzione) è il formato, non dovresti usare le variabili lì. Ecco, potresti farlo awk -F'\t' '/match/{printf "-args1\0%s\0-args2\0%s\0", $1, $2}' | xargs -n400 -r0 mycommand. Ancora una volta, è -n400necessario assicurarsi che xargspassi un numero di argomenti che sia un multiplo di 4. (notare che non tutte le awkimplementazioni supportano l'utilizzo \0come quello qui).
Stéphane Chazelas,

non l'ho usato -0per renderlo più affidabile, l'ho usato per farlo fare quello che volevo fare, cosa che fa.
keithpjolley

2

prova questo:

echo {1..8} |xargs -n 2 bash -c 'echo "the number $0 comes before $1"'

2
Funzionerebbe in questo caso, ma è meglio eseguire sh -cscript con sh(o qualunque altra cosa) dentro $0. Nota che $0non è incluso $@se questo doveva essere usato dallo sh -cscript, ad esempio se lo script eraecho "the two numbers were $@"
Kusalananda
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.