Como fornecer uma lista separada por vírgula como argumentos para o próximo comando


9

Eu tenho um script s1que gera uma lista de números separados por ',' por exemplo 1,2,3,4. Agora, quero atribuir esses números ao script s2como argumentos, para que o s2 seja executado em cada um deles e produza o resultado em uma linha separada. Por exemplo, se s2 multiplica números por dois, este seria o resultado que estou procurando:

2
4
6
8

O que estou fazendo agora é:

s1 | xargs -d "," | xargs -n1 s2

Mas sinto que estou fazendo isso de uma maneira tão tola! Então, minha pergunta é:

Qual é a maneira correta de fazer isso?

Meu problema com a minha solução é que ele está chamando xargs duas vezes e iterando sobre a entrada duas vezes, o que não é razoável para meus olhos, é claro, por meio do desempenho! A resposta xargs -d "," -n1parece boa, mas não tenho certeza se está apenas repetindo uma vez. Caso isso aconteça, verifique isso em sua resposta e eu aceito. A propósito, prefiro não usar o Perl, pois ele ainda está iterando duas vezes e também o Perl pode não existir em muitos sistemas.


1
Se está funcionando, por que chamar isso de tolo? Se o tempo de execução é importante, então isso é outra licença importa mais aqui
— George Udosen

2
Tente istos1 | xargs -d "," -n1 s2
— George Udosen

1
Suspeito que parte do problema esteja entendendo mal o impacto da iteração. A iteração sobre os elementos em algo como uma matriz associativa é ruim por causa da despesa de caminhar nessa estrutura de dados, mas "iterar" em geral não é inerentemente ruim. Especificamente, a leitura de dados linha por linha, conforme aparece no STDIN, não é um grande problema de desempenho. A questão do desempenho aqui é mais o custo de gerar um novo processo e configurar o pipeline. Desde que você não faça isso com frequência (como em um loop), se preocupar com o desempenho do xargs é provavelmente um exemplo de otimização prematura.
— dannysauer

Respostas:


18

Isso deve funcionar igualmente:

s1 | xargs -d "," -n1 s2

Caso de teste:

printf 1,2,3,4 | xargs -d ',' -n1 echo

Resultado:

1
2
3
4

Se s1gerar essa lista seguida por um caractere de nova linha, você deverá removê-la, caso contrário a última chamada estaria com em 4\nvez de 4:

s1 | tr -d '\n' | xargs -d , -n1 s2

6

Se s2puder aceitar vários argumentos, você poderá:

(IFS=,; ./s2 $(./s1))

que substitui temporariamente o IFS por vírgula, tudo em um subshell, para que s2a saída seja s1dividida por vírgulas. O subshell é uma maneira abreviada de alterar o IFS sem salvar o valor anterior ou redefini-lo.

Uma versão anterior desta resposta estava incorreta, provavelmente devido a uma configuração restante do IFS, corrompendo os resultados. Obrigado a ilkkachu por apontar meu erro .

Para fazer um loop manual sobre as saídas e fornecê-las individualmente s2, demonstrando aqui a economia e a redefinição do IFS:

oIFS="$IFS"
IFS=,
for output in $(./s1); do ./s2 "$output"; done
IFS="$oIFS"

ou execute os bits IFS em um subshell como antes:

(
IFS=,
for output in $(./s1); do ./s2 "$output"; done
)

1
Você tem certeza sobre o primeiro? bash -c 'IFS=, printf "%s\n" $(echo 1,2,3)'imprime 1,2,3no meu sistema, ou seja, não há divisão.
— Ilkkachu

Vou testar novamente um pouco, mas suspeito de comportamento diferente com base em programas internos versus externos.
— Jeff Schaller

mesmo com /usr/bin/printfe/bin/echo
— ilkkachu

1
@ilkkachu Você está correto, a divisão de palavras ocorre antes que o IFS seja reatribuído. Nesse caso (IFS=,; printf "%s\n" $(echo 1,2,3)), por outro lado, deve funcionar.
— undercat aplaude Monica

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.