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.