Passando vários parâmetros via xargs


17

Eu gostaria de poder usar xargspara executar vários parâmetros em diferentes partes de um comando.

Por exemplo, o seguinte:

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

Eu espero que ele volte

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

... etc

Isso é possível? Eu suspeito que meu uso múltiplo de -Iestá incorreto.

Respostas:


29

Eu acredito que você não pode usar -Idessa maneira. Mas você pode obter o efeito / comportamento desejado dizendo:

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

Essencialmente, isso cria um script de shell de uma linha ad hoc , que é xargsexecutado via sh -c. Os dois valores que xargsanalisam a entrada são passados ​​para esse "script". O shell atribui esses valores a $1e $2, aos quais você pode fazer referência no "script".


4
Obrigado - isso é ótimo. Eu tenho lido o homem por sh e estou lutando para entender o que a segunda chamada para sh faz e, por extensão, por que sua omissão produz "metade" do resultado.
Damien Sawyer

6
@DamienSawyer Não há segunda chamada para sh. A trilha shno final é o que é colocado $0. $0geralmente é o que contém o nome do intérprete ou do script.
Kusalananda

Acabei de substituir o trailing shpelo echo $shqual ele funciona. Então shfunções finais como espaço reservado
kenn

Bem, isso é uma simplificação excessiva do que Kusalananda disse.
Scott

6

No caso específico de printf, você sempre pode fazer:

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

porque printfpossui uma xargscapacidade intrínseca de executar várias vezes se receber mais argumentos do que o necessário para uma única invocação. Embora isso tenha pouca vantagem sobre

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

E para listas grandes, o xargscomando simples pode resultar na xargsexecução de várias instâncias printf, algumas das quais podem ter números ímpares de argumentos. Você pode passar -n 1000para xargsse proteger contra isso, onde 1000 é um número par que deve ser pequeno o suficiente para não atingir o limite muito longo da lista de argumentos e grande o suficiente para evitar a execução de tantos printfs.

Observe que xargschamaria, não o built-in do seu shell printf, mas o externo printf, com cada chamada em um novo processo separado.

Observe também que, para uma entrada vazia, exceto em alguns BSDs, ela ainda seria executada printfuma vez sem argumento. GNU xargse compatível têm uma opção -r (ou --no-run-if-empty) para evitar isso.

Para ficar claro, essa resposta simples é específica para o seu printfexemplo e não funcionaria no caso geral em que você deve passar dois parâmetros de cada vez ao seu comando (como seria o caso diff, por exemplo). Para resolver o problema geral zsh, você pode usar:

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

(1) IMHO, a zshparte acima é uma resposta real, e a xargsparte sem opções é apenas uma esquisitice. Nesse caso, eu consideraria colocar a resposta real em primeiro lugar. (2) Presumo que você tenha uma razão para não usar aspas em seu zshcomando. Em caso afirmativo, convém declarar, para que as pessoas não leiam o texto acima e pensem que as aspas não são importantes. (Ou simplesmente incluí-los, já que eles não se machucar.)
Scott

Isso é muito legal. Cheguei aqui procurando por algo semelhante, onde não tinha certeza antecipada de quantos argumentos eu receberia que precisariam ser colocados na linha de comando do próximo argumento. fez algo comoawk -F'\t' '/match/{printf $1"\0"$2"\0"}' | xargs -0 printf -- '-args1 "%s" -args2 "%s"' | xargs mycommand
keithpjolley 19/04

@keithpjolley, seu uso -0no primeiro xargspara torná-lo mais confiável é derrotado por você não usá-lo no segundo. Além disso, o primeiro argumento para printf(tanto o utilitário independente quanto awka printf()função) é o formato, você não deve usar variáveis ​​lá. Aqui, você poderia fazer awk -F'\t' '/match/{printf "-args1\0%s\0-args2\0%s\0", $1, $2}' | xargs -n400 -r0 mycommand. Novamente, -n400necessário para garantir a xargsaprovação de vários argumentos com um múltiplo de 4. (observe que nem todas as awkimplementações suportam o uso \0aqui).
Stéphane Chazelas

não usei -0para torná-lo mais confiável, usei para fazer o que eu queria fazer, o que faz.
keithpjolley 20/04

2

tente isto:

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

2
Isso funcionaria nesse caso, mas é melhor executar o sh -cscript com sh(ou o que seja) no $0. Observe que isso $0não está incluído $@se for usado pelo sh -cscript, por exemplo, se o script forecho "the two numbers were $@"
Kusalananda
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.