Eu usei um dos seguintes
echo $(stuff)
echo `stuff`
(onde stuff
é, por exemplo, pwd
ou date
ou algo mais complicado).
Foi-me dito que esta sintaxe está errada, é uma prática ruim, não elegante, excessiva, redundante, excessivamente complicada, uma programação de culto de carga, noobish, ingênua etc.
Mas o comando não trabalho, então o que exatamente está errado com ele?
shell-script
sh
echo
Kamil Maciorowski
fonte
fonte
echo $(echo $(echo $(echo$(echo $(stuff)))))
também faz o trabalho, e ainda você provavelmente não iria utilizá-lo, certo? ;-)stuff
. : DRespostas:
tl; dr
A única
stuff
seria provavelmente trabalhar para você.Resposta completa
O que acontece
Quando você executa
foo $(stuff)
, é isso que acontece:stuff
corre;$(stuff)
na chamada defoo
;foo
é executado, seus argumentos de linha de comando obviamente dependem do questuff
retornou.Esse
$(…)
mecanismo é chamado "substituição de comando". No seu caso, o comando principal é oecho
que basicamente imprime seus argumentos de linha de comando no stdout. Portanto, tudo o questuff
tenta imprimir no stdout é capturado, passadoecho
e impresso no stdoutecho
.Se você deseja que a saída
stuff
seja impressa em stdout, basta executar a solastuff
.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 evitarecho $(stuff)
se realmente não sabe o que está fazendo.O ponto é
stuff
eecho $(stuff)
não é exatamente equivalente. O último significa chamar o operador split + glob na saída destuff
com 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:
E para globbing:
Como você pode ver,
echo "$(stuff)"
é equivalente (-ish *) astuff
. Você poderia usá-lo, mas qual é o objetivo de complicar as coisas dessa maneira?Por outro lado, se você quer a saída de
stuff
se submeter a divisão + englobamento, então você pode encontrarecho $(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 deliberadoecho $(stuff)
parece muito incomum.Que tal
var=$(stuff); echo "$var"
?Bom ponto. Este trecho:
deve ser equivalente a
echo "$(stuff)"
(-ish *) astuff
. Se for o código inteiro, basta executarstuff
.Se, no entanto, você precisar usar a saída de
stuff
mais de uma vez, essa abordagemgeralmente é melhor que
Mesmo que
foo
sejaecho
e você entraecho "$var"
em seu código, pode ser melhor mantê-lo dessa maneira. Coisas a considerar:var=$(stuff)
stuff
corre uma vez; mesmo que o comando seja rápido, evitar a computação da mesma saída duas vezes é a coisa certa. Ou talvezstuff
tenha 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.stuff
gerar uma saída dependente do tempo ou algo aleatória, você poderá obter resultados inconsistentes defoo "$(stuff)"
ebar "$(stuff)"
. Apósvar=$(stuff)
o valor de$var
ser corrigido, você pode ter certezafoo "$var"
ebar "$var"
obter um argumento de linha de comando idêntico.Em alguns casos, em vez de
foo "$var"
você querer (precisar) usarfoo $var
, especialmente sestuff
gerar vários argumentos parafoo
(uma variável de matriz pode ser melhor se o seu shell suportar). Mais uma vez, saiba o que está fazendo. Quando se trataecho
da diferença entreecho $var
eecho "$var"
é o mesmo que entreecho $(stuff)
eecho "$(stuff)"
.* Equivalente ( -ish )?
Eu disse que
echo "$(stuff)"
é equivalente (-ish) astuff
. Há pelo menos dois problemas que o tornam não exatamente equivalente:$(stuff)
é executadostuff
em um subshell, então é melhor dizer queecho "$(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"
:Compare com
e com
Outro exemplo, comece
stuff
sendocd /; pwd
:e teste
stuff
e(stuff)
versões.echo
não é uma boa ferramenta para exibir dados não controlados . Issoecho "$var"
estávamos falando sobre deveria ter sidoprintf '%s\n' "$var"
. Mas como a pergunta mencionaecho
e como a solução mais provável é não usarecho
em primeiro lugar, decidi não apresentarprintf
até agora.stuff
ou(stuff)
intercalará a saída stdout e stderr, enquantoecho $(stuff)
imprimirá toda a saída stderr destuff
(que roda primeiro) e somente então a saída stdout digerida porecho
(que roda por último).$(…)
retira qualquer nova linha à direita e aecho
adiciona novamente. Então,echo "$(printf %s 'a')" | xxd
dá saída diferente deprintf %s 'a' | xxd
.Alguns comandos (
ls
por exemplo) funcionam de maneira diferente, dependendo se a saída padrão é um console ou não; por issols | cat
não o mesmols
faz. Da mesma formaecho $(ls)
irá funcionar de forma diferente do quels
.Deixando de
ls
lado, em um caso geral, se você precisar forçar esse outro comportamento,stuff | cat
é melhorecho $(ls)
ouecho "$(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).
fonte
stuff
caminho entrelaçarástdout
estderr
produzirá, enquantoecho `stuff`
imprimirá toda astderr
saídastuff
e somente então astdout
saída.echo $(stuff)
pode colocá-lo em muito mais problemas, comoecho "$(stuff)"
se você não quisesse explicações e expansão explicitamente.$(…)
retira qualquer nova linha à direita e aecho
adiciona de volta. Então,echo "$(printf %s 'a')" | xxd
dá saída diferente deprintf %s 'a' | xxd
.ls
por exemplo) funcionam de maneira diferente, dependendo se a saída padrão é um console ou não; por issols | cat
não o mesmols
faz. E, claroecho $(ls)
, funcionará de maneira diferentels
.Outra diferença: o código de saída do sub-shell é perdido e, portanto, o código de saída
echo
é recuperado.fonte
$?
será o código de retorno deecho
(paraecho $(stuff)
) em vez do códigoreturn
edstuff
. Astuff
funçãoreturn 1
(código de saída), mas aecho
define como "0", independentemente do código de retorno destuff
. Ainda deve estar na resposta.