Ordem de substituição de comando do Linux

5

Estou confuso com a substituição do comando. Eu acho que a substituição de comandos é como uma macro de linguagem de programação. O sub shell é executado primeiro e o $(...) é substituído por sua saída padrão, antes que o comando pai seja avaliado. Mas isso é tudo verdade?

Quando tento executar o seguinte comando

echo {0..9} | xargs -n 2 $(echo 'echo | tac')

Eu gostaria de ver a seguinte saída

8 9
6 7
4 5
2 3
0 1

Mas, em vez disso, pegue isso

| tac 0 1
| tac 2 3
| tac 4 5
| tac 6 7
| tac 8 9

Então, o que faz com que | tac seja capturado como um argumento para o eco, e não como parte da linha de comando? Qual é o mecanismo e a ordem exatos, como a linha de comando e a substituição de comando são analisadas, escopo e avaliadas? É possível construir dinamicamente linhas de comando no Linux em um estilo de metaprogramação?

Editar

Eu sei que posso usar apenas echo {0..9}| xargs -n 2 | tac . Esta questão é teórica, estou interessado porque o exemplo de sub shell não produz o mesmo resultado

    
por Tuomas Toivonen 12.08.2017 / 17:30

2 respostas

5

A gênese do problema que você está vendo se deve à forma como a tokenização acontece em uma linha de comando. Nesse caso em particular, muito antes de o $(echo 'echo | tac') ser expandido, o shell já descobriu que você pretende executar um comando ( echo {…} ) e passar sua saída por meio de um canal ( | ) para outro comando ( xargs -n 2 $(…) ).

Em seguida, no próximo estágio, o preenchimento de $(…) e a expansão de suporte {…} geram os comandos reais a serem executados. E nesse estágio se resulta em um caractere de pipe, então, é tarde demais e é claramente perdido o ônibus.

Agora ele será tratado como não como um metacaractere especial, mas será incluído na linha de comando xargs como qualquer caractere comum (= > não-metachar).

Se você quiser dar outra chance, precisará eval .

eval "echo {0..9} | xargs -n 2 $(echo 'echo | tac')"

Isso produzirá o que você espera.

    
por 12.08.2017 / 19:32
3

além de Roman disse, sua comunidade deveria ser assim

echo {0..9}| xargs -n 2 | tac

isso produz

8 9
6 7 
4 5
2 3
0 1

com o inútil $ (echo 'echo') isso causa o erro

espero que ajude,

PS. Para a resposta longa, | redireciona a saída de um comando para o próximo, então echo {0..9} produz:

0 1 2 3 4 5 6 7 8 9

xargs -n 2 recebe essa entrada e produz

0 1
2 3
4 5 
6 7
8 9

e finalmente tac recebe essa entrada e produz a expressão inversa:

8 9
6 7
4 5
2 3
0 1

Espero que isso seja um pouco mais claro.

EDITAR:

echo {0..9} | xargs -n 2 $(echo 'echo | tac')
+ echo 0 1 2 3 4 5 6 7 8 9
++ echo 'echo | tac'
+ xargs -n 2 echo '|' tac
| tac 0 1
| tac 2 3
| tac 4 5
| tac 6 7
| tac 8 9

Este é o comando que você está enviando para bash com sua sintaxe inicial, está bem claro o que está acontecendo, no final você está enviando xargs -n 2 echo '|' tac

    
por 12.08.2017 / 17:59