Por que echo “bar” é diferente de echo -n “bar”?

10

Compare

echo -n "bar"

com

echo "bar" -n

O primeiro faz o que eu pensa que deve fazer (imprime "barra" sem uma nova linha), enquanto o segundo não. Isso é um bug ou por design? Por que é diferente de muitos programas cli em que você não pode mover as opções? Por exemplo, tail -f /var/log/messages é exatamente igual a tail /var/log/messages -f . Eu às vezes faço o último quando esqueço que queria o primeiro, porque internamente as opções e os argumentos são rearranjados, geralmente por getopt .

Atualização: sim, eu originalmente nerf-ed minha pergunta. Eu removi o nerf você terá que ver o histórico para fazer algumas das respostas fazer sentido.

    
por xenoterracide 20.01.2011 / 04:16

4 respostas

18

Como a maioria dos outros observou, "-n" é interpretado literalmente se colocado em qualquer lugar, mas imediatamente após o comando echo .

Historicamente, os utilitários UNIX eram todos assim - eles procuravam opções apenas imediatamente após o nome do comando. Era provável que o BSD ou o GNU tivessem sido pioneiros no estilo mais flexível (embora eu possa estar errado), como até agora POSIX especifica a maneira antiga como correta (consulte a Diretriz 9 e também man 3 getopt em um sistema Linux). De qualquer forma, mesmo que a maioria dos utilitários Linux usem o novo estilo, existem alguns itens como echo .

Echo é uma bagunça, segundo os padrões, em que havia pelo menos dois fundamentalmente versões conflitantes em jogo no momento em que POSIX surgiu. Por um lado, você tem estilo SYSV, que interpreta caracteres com escape de barra invertida, mas, de outra forma, trata seus argumentos literalmente, não aceitando opções. Por outro lado, você tem o estilo BSD, que trata um -n inicial como um caso especial e produz literalmente todo o resto. E como echo é tão conveniente, você tem milhares de scripts de shell que dependem de um comportamento ou outro:

echo Usage: my_awesome_script '[-a]' '[-b]' '[-c]' '[-n]'
echo -a does a thing.
echo -b does something else.
echo -c makes sure -a works right.
echo -- DON\'T USE -n -- it\'s not finished! --

Por causa da semântica do "tratar tudo literalmente", é impossível adicionar uma nova opção ao echo sem quebrar as coisas. Se o GNU usasse o esquema de opções flexíveis, o inferno iria se soltar.

Incidentalmente, para melhor compatibilidade entre as implementações do shell Bourne, use printf em vez de echo .

ATUALIZADO para explicar por que echo em particular não usa opções flexíveis.

    
por 20.01.2011 / 08:56
9

As outras respostas chegam ao ponto em que você pode olhar a página man para ver que -n está se tornando parte da string para fazer eco. No entanto, eu só quero ressaltar que é fácil investigar isso sem o md5sum e torna o que está acontecendo um pouco menos enigmático.

[11:07:44][dasonk@Chloe:~]: echo -n "bar"
bar[11:07:48][dasonk@Chloe:~]: echo "bar" -n
bar -n
    
por 20.01.2011 / 06:09
6

Uau, as explicações de todos são demoradas.

É simples assim:

-n é uma opção se aparecer antes da string, caso contrário, é apenas outra string a ser ecoada.

Remova o | md5sum e você verá que a saída é diferente.

    
por 20.01.2011 / 06:14
5

A partir de uma simples inspeção, isso não é um bug por design ...

echo "bar" -n | md5sum

a3f8efa5dd10e90aee0963052e3650a1

Experimente você mesmo:

echo "bar -n" | md5sum

Você notará que o md5 resultante é

a3f8efa5dd10e90aee0963052e3650a1

Você acabou de confundir o uso de -n no echo.

No seu primeiro código de amostra

echo -n "bar" | md5sum

-n é usado para dizer NÃO para colocar uma nova linha após esse eco.

Seu segundo exemplo

echo "bar" -n | md5sum

está tratando -n como um texto literal.

Espero que essa explicação ajude:)

Ismael Casimpan

    
por 20.01.2011 / 04:36