tl; dr
A única stuffseria provavelmente trabalhar para você.
Resposta completa
O que acontece
Quando você executa foo $(stuff), é isso que acontece:
stuff corre;
- sua saída (stdout), em vez de ser impressa, substitui
$(stuff)na chamada de foo;
- depois
fooé executado, seus argumentos de linha de comando obviamente dependem do que stuffretornou.
Esse $(…)mecanismo é chamado "substituição de comando". No seu caso, o comando principal é o echoque basicamente imprime seus argumentos de linha de comando no stdout. Portanto, tudo o que stufftenta imprimir no stdout é capturado, passado echoe impresso no stdout echo.
Se você deseja que a saída stuffseja impressa em stdout, basta executar a sola stuff.
A `…`sintaxe serve ao mesmo propósito que $(…)(sob o mesmo nome: "substituição de comando"), porém existem poucas diferenças, portanto você não pode trocá-las cegamente. Veja este FAQ e esta pergunta .
Devo evitar, echo $(stuff)não importa o quê?
Há uma razão que você pode querer usar echo $(stuff)se souber o que está fazendo. Pela mesma razão, você deve evitar echo $(stuff)se realmente não sabe o que está fazendo.
O ponto é stuffe echo $(stuff)não é exatamente equivalente. O último significa chamar o operador split + glob na saída de stuffcom o valor padrão de $IFS. Citar duas vezes a substituição de comando evita isso. A citação única da substituição de comando faz com que não seja mais uma substituição de comando.
Para observar isso quando se trata de divisão, execute estes comandos:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
E para globbing:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
Como você pode ver, echo "$(stuff)"é equivalente (-ish *) a stuff. Você poderia usá-lo, mas qual é o objetivo de complicar as coisas dessa maneira?
Por outro lado, se você quer a saída de stuffse submeter a divisão + englobamento, então você pode encontrar echo $(stuff)útil. Tem que ser sua decisão consciente.
Existem comandos que geram resultados que devem ser avaliados (incluindo divisão, globbing e mais) e executados pelo shell, portanto, eval "$(stuff)"é uma possibilidade (consulte esta resposta ). Eu nunca vi um comando que precise que sua saída sofra divisão + globbing adicionais antes de ser impressa . O uso deliberado echo $(stuff)parece muito incomum.
Que tal var=$(stuff); echo "$var"?
Bom ponto. Este trecho:
var=$(stuff)
echo "$var"
deve ser equivalente a echo "$(stuff)"(-ish *) a stuff. Se for o código inteiro, basta executar stuff.
Se, no entanto, você precisar usar a saída de stuffmais de uma vez, essa abordagem
var=$(stuff)
foo "$var"
bar "$var"
geralmente é melhor que
foo "$(stuff)"
bar "$(stuff)"
Mesmo que fooseja echoe você entra echo "$var"em seu código, pode ser melhor mantê-lo dessa maneira. Coisas a considerar:
- Com
var=$(stuff) stuffcorre uma vez; mesmo que o comando seja rápido, evitar a computação da mesma saída duas vezes é a coisa certa. Ou talvez stufftenha outros efeitos além de gravar no stdout (por exemplo, criar um arquivo temporário, iniciar um serviço, iniciar uma máquina virtual, notificar um servidor remoto), para que você não queira executá-lo várias vezes.
- Se
stuffgerar uma saída dependente do tempo ou algo aleatória, você poderá obter resultados inconsistentes de foo "$(stuff)"e bar "$(stuff)". Após var=$(stuff)o valor de $varser corrigido, você pode ter certeza foo "$var"e bar "$var"obter um argumento de linha de comando idêntico.
Em alguns casos, em vez de foo "$var"você querer (precisar) usar foo $var, especialmente se stuffgerar vários argumentos para foo(uma variável de matriz pode ser melhor se o seu shell suportar). Mais uma vez, saiba o que está fazendo. Quando se trata echoda diferença entre echo $vare echo "$var"é o mesmo que entre echo $(stuff)e echo "$(stuff)".
* Equivalente ( -ish )?
Eu disse que echo "$(stuff)"é equivalente (-ish) a stuff. Há pelo menos dois problemas que o tornam não exatamente equivalente:
$(stuff)é executado stuffem um subshell, então é melhor dizer que echo "$(stuff)"é equivalente (-ish) a (stuff). Os comandos que afetam o shell em que são executados, se estiverem em um subshell, não afetam o shell principal.
Neste exemplo stuffé a=1; echo "$a":
a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"
Compare com
a=0
a=1; echo "$a" # stuff
echo "$a"
e com
a=0
(a=1; echo "$a") # (stuff)
echo "$a"
Outro exemplo, comece stuffsendo cd /; pwd:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
e teste stuffe (stuff)versões.
echonão é uma boa ferramenta para exibir dados não controlados . Isso echo "$var"estávamos falando sobre deveria ter sido printf '%s\n' "$var". Mas como a pergunta menciona echoe como a solução mais provável é não usar echoem primeiro lugar, decidi não apresentar printfaté agora.
stuffou (stuff)intercalará a saída stdout e stderr, enquanto echo $(stuff)imprimirá toda a saída stderr de stuff(que roda primeiro) e somente então a saída stdout digerida por echo(que roda por último).
$(…)retira qualquer nova linha à direita e a echoadiciona novamente. Então, echo "$(printf %s 'a')" | xxddá saída diferente de printf %s 'a' | xxd.
Alguns comandos ( lspor exemplo) funcionam de maneira diferente, dependendo se a saída padrão é um console ou não; por isso ls | catnão o mesmo lsfaz. Da mesma forma echo $(ls)irá funcionar de forma diferente do que ls.
Deixando de lslado, em um caso geral, se você precisar forçar esse outro comportamento, stuff | caté melhor echo $(ls)ou echo "$(ls)"porque não aciona todos os outros problemas mencionados aqui.
Possivelmente status de saída diferente (mencionado para completar esta resposta da wiki; para detalhes, veja outra resposta que merece crédito).