Ouvi dizer que printf
é melhor que echo
. Só me lembro de uma instância da minha experiência em que tive que usar printf
porque echo
não funcionou para inserir algum texto em algum programa do RHEL 5.8, mas printf
funcionou. Mas, aparentemente, existem outras diferenças, e eu gostaria de saber o que são e se existem casos específicos em que usar um contra o outro.
text-processing
echo
printf
anfíbio
fonte
fonte
echo -e
?echo -e
não funcionash
, apenas embash
(por algum motivo), e o docker, por exemplo, usash
por padrão seusRUN
comandosecho -e
para mim funciona no Android Terminal, que é essencialmentesh
.Respostas:
Basicamente, é um problema de portabilidade (e confiabilidade).
Inicialmente,
echo
não aceitava nenhuma opção e não expandia nada. Tudo o que estava fazendo era apresentar seus argumentos separados por um caractere de espaço e finalizados por um caractere de nova linha.Agora, alguém pensou que seria bom se pudéssemos fazer coisas como
echo "\n\t"
gerar nova linha ou caracteres de tabulação ou ter uma opção para não gerar o caractere de nova linha à direita.Eles então pensaram mais, mas em vez de adicionar essa funcionalidade ao shell (como
perl
onde aspas duplas,\t
na verdade significa um caractere de tabulação), eles o adicionaramecho
.David Korn percebeu o erro e introduziu uma nova forma de citações de shell:
$'...'
que depois foi copiadabash
ezsh
que era muito tarde para isso.Agora, quando um UNIX padrão
echo
recebe um argumento que contém os dois caracteres\
et
, em vez de produzi-los, gera um caractere de tabulação. E assim que aparece\c
em um argumento, ele para de produzir (portanto, a nova linha à direita também não é produzida).Outros shells / fornecedores / versões do Unix escolheram fazer de maneira diferente: eles adicionaram uma
-e
opção para expandir as seqüências de escape e uma-n
opção para não gerar a nova linha final. Alguns têm-E
que desativar sequências de escape, outros têm,-n
mas-e
a lista de seqüências de escape suportadas por umaecho
implementação não é necessariamente a mesma que a suportada por outra.Sven Mascheck tem uma boa página que mostra a extensão do problema .
Pelos
echo
implementações que suportam opções, há geralmente nenhum apoio de um--
para marcar o fim de opções (oecho
builtin de algumas conchas não-Bourne-como fazer, e zsh suporta-
para que embora), assim, por exemplo, é difícil para a saída"-n"
comecho
no muitas conchas.Em alguns shells como
bash
¹ ouksh93
² ouyash
($ECHO_STYLE
variável), o comportamento depende até de como o shell foi compilado ou do ambiente (echo
o comportamento do GNU também mudará se$POSIXLY_CORRECT
estiver no ambiente e com a versão 4 ,zsh
com suabsd_echo
opção, alguns baseados em pdksh com suaposix
opção ou se são chamados comosh
ou não). Portanto, doisbash
echo
s, mesmo da mesma versão do,bash
não garantem o mesmo comportamento.O POSIX diz: se o primeiro argumento é
-n
ou qualquer argumento contém barras invertidas, o comportamento não é especificado .bash
O eco nesse sentido não é POSIX, pois, por exemplo,echo -e
não está sendo emitido-e<newline>
conforme o POSIX exige. A especificação UNIX é mais rígida, proíbe-n
e exige a expansão de algumas seqüências de escape, incluindo a\c
que interrompe a saída.Essas especificações não são realmente úteis aqui, pois muitas implementações não são compatíveis. Mesmo alguns sistemas certificados como o macOS 5 não são compatíveis.
Para realmente representar a realidade atual, o POSIX deve realmente dizer : se o primeiro argumento corresponder ao
^-([eEn]*|-help|-version)$
regexp estendido ou se algum argumento contiver barras invertidas (ou caracteres cuja codificação contenha a codificação do caractere de barra invertida, comoα
nos códigos de idioma usando o conjunto de caracteres BIG5), o comportamento será não especificado.Em suma, você não sabe o
echo "$var"
que produzirá, a menos que possa ter certeza de que$var
não contém caracteres de barra invertida e não começa com-
. A especificação POSIX realmente nos diz para usarprintf
nesse caso.Então, o que isso significa é que você não pode usar
echo
para exibir dados não controlados. Em outras palavras, se você estiver escrevendo um script e estiver recebendo entradas externas (do usuário como argumentos ou nomes de arquivos do sistema de arquivos ...), não poderá usáecho
-lo para exibi-lo.Isso é bom:
Isso não é:
(Embora funcione bem com algumas
echo
implementações (não compatíveis com UNIX), comobash
as quando axpg_echo
opção não foi ativada de uma maneira ou de outra como no momento da compilação ou através do ambiente).file=$(echo "$var" | tr ' ' _)
não é OK na maioria das implementações (excepções sãoyash
comECHO_STYLE=raw
(com a ressalva de queyash
's variáveis não pode conter seqüências arbitrárias de bytes por isso não nomes de arquivos arbitrários) ezsh
' secho -E - "$var"
6 ).printf
, por outro lado, é mais confiável, pelo menos quando está limitado ao uso básico deecho
.Produzirá o conteúdo de
$var
seguido por um caractere de nova linha, independentemente de qual caractere ele possa conter.A saída será sem o caractere de nova linha à direita.
Agora, também existem diferenças entre
printf
implementações. Há um núcleo de recursos especificado pelo POSIX, mas há muitas extensões. Por exemplo, alguns suportam a%q
para citar os argumentos, mas como isso é feito varia de shell para shell, algum suporte\uxxxx
para caracteres unicode. O comportamento variaprintf '%10s\n' "$var"
em locais de vários bytes, existem pelo menos três resultados diferentes paraprintf %b '\123'
Mas, no final, se você se ater ao conjunto de recursos do POSIX
printf
e não tentar fazer algo muito sofisticado com ele, estará sem problemas.Mas lembre-se de que o primeiro argumento é o formato, portanto, não deve conter dados variáveis / não controlados.
Um mais confiável
echo
pode ser implementado usandoprintf
, como:O subshell (que implica gerar um processo extra na maioria das implementações de shell) pode ser evitado usando-se
local IFS
com muitos shells ou escrevendo-o como:Notas
1. como
bash
oecho
comportamento pode ser alterado.Com
bash
, no tempo de execução, há duas coisas que controlam o comportamento deecho
(ao ladoenable -n echo
ou redefinindoecho
como uma função ou alias): axpg_echo
bash
opção e sebash
está no modo posix.posix
O modo pode ser ativado sebash
for chamado comosh
ou sePOSIXLY_CORRECT
estiver no ambiente ou com aposix
opção:Comportamento padrão na maioria dos sistemas:
xpg_echo
expande seqüências conforme o UNIX exige:Ainda honra
-n
e-e
(e-E
):Com
xpg_echo
e modo POSIX:Desta vez,
bash
é compatível com POSIX e UNIX. Observe que, no modo POSIX,bash
ainda não é compatível com POSIX, pois não é produzido-e
em:Os valores padrão para xpg_echo e POSIX pode ser definida em tempo de compilação com os
--enable-xpg-echo-default
e--enable-strict-posix-default
opções para oconfigure
script. Isso é tipicamente o que as versões recentes do OS / X fazem para criar as suas/bin/sh
.No Unix / Linux implementação / distribuição no seu perfeito juízo normalmente faria isso por. Na verdade, isso não é verdade, o/bin/bash
embora/bin/bash
que o Oracle envia com o Solaris 11 (em um pacote opcional) parece ter sido construído--enable-xpg-echo-default
(não era o caso no Solaris 10).2. Como
ksh93
oecho
comportamento pode ser alterado.Em
ksh93
, seecho
expande seqüências de escape ou não e reconhece opções depende do conteúdo das variáveis de ambiente$PATH
e / ou$_AST_FEATURES
.Se
$PATH
contiver um componente que contenha/5bin
ou/xpg
antes do componente/bin
ou/usr/bin
, ele se comportará da maneira SysV / UNIX (expande seqüências, não aceita opções). Se encontrar/ucb
ou/bsd
primeiro ou se$_AST_FEATURES
7 contiverUNIVERSE = ucb
, ele se comportará da maneira BSD 3 (-e
para ativar a expansão, reconhece-n
).O padrão é dependente do sistema, BSD no Debian (veja a saída de
builtin getconf; getconf UNIVERSE
nas versões recentes do ksh93):3. BSD para eco -e?
A referência ao BSD para o manuseio da
-e
opção é um pouco enganosa aqui. A maioria dessesecho
comportamentos diferentes e incompatíveis foram todos introduzidos na AT&T:\n
,\0ooo
,\c
No Banco do programador Trabalho UNIX (baseado em Unix V6), eo restante (\b
,\r
...) em Unix System III Ref .-n
no Unix V7 (por Dennis Ritchie Ref )-e
no Unix V8 (por Dennis Ritchie Ref )-E
possivelmente veio inicialmentebash
(CWRU / CWRU.chlog na versão 1.13.5 menciona Brian Fox adicionando-o em 18/10/1992, GNUecho
copiando-o logo depois no sh-utils-1.8 lançado 10 dias depois)Embora o
echo
built-in dosh
ou BSDs tenha suportado-e
desde o dia em que começaram a usar o shell Almquist no início dos anos 90, oecho
utilitário independente até hoje não o suporta por lá (o FreeBSDecho
ainda não suporta-e
, embora suporte-n
como Unix V7 (e também\c
mas apenas no final do último argumento)).A manipulação de
-e
foi adicionada aksh93
secho
no universo BSD na versão ksh93r lançada em 2006 e pode ser desativada no momento da compilação.4. Mudança de comportamento do GNU eco em 8.31
Desde coreutils 8.31 (e este cometem ), GNU
echo
agora expande seqüências de escape por padrão quando POSIXLY_CORRECT está no ambiente, para coincidir com o comportamento debash -o posix -O xpg_echo
'secho
incorporado (ver relatório de erro ).5. macOS
echo
A maioria das versões do macOS recebeu certificação UNIX do OpenGroup .
Seu
sh
embutidoecho
é compatível, pois ébash
(uma versão muito antiga) criada comxpg_echo
ativado por padrão, mas seuecho
utilitário independente não é.env echo -n
não produz nada em vez de-n<newline>
,env echo '\n'
gera em\n<newline>
vez de<newline><newline>
.Essa
/bin/echo
é a do FreeBSD que suprime a saída de nova linha se o primeiro argumento for-n
ou (desde 1995) se o último argumento terminar\c
, mas não suporta nenhuma outra sequência de barra invertida exigida pelo UNIX, nem mesmo\\
.6.
echo
implementações que podem gerar dados arbitrários literalmenteEstritamente falando, você também pode contar que o FreeBSD / macOS
/bin/echo
acima (não o shell delesecho
), ondezsh
secho -E - "$var"
ouyash
'sECHO_STYLE=raw echo "$var"
(printf '%s\n' "$var"
) podem ser escritos:As implementações suportadas
-E
e-n
(ou podem ser configuradas para) também podem:E
zsh
'secho -nE - "$var"
(printf %s "$var"
) poderia ser escrito7.
_AST_FEATURES
e o ASTUNIVERSE
Ele
_AST_FEATURES
não deve ser manipulado diretamente, é usado para propagar as definições de configuração AST pela execução do comando. A configuração deve ser feita através daastgetconf()
API (não documentada) . Por dentroksh93
, ogetconf
built-in (ativado combuiltin getconf
ou chamandocommand /opt/ast/bin/getconf
) é a interface paraastgetconf()
Por exemplo, você faria
builtin getconf; getconf UNIVERSE = att
para alterar aUNIVERSE
configuração paraatt
(causando oecho
comportamento do SysV entre outras coisas). Depois de fazer isso, você notará que a$_AST_FEATURES
variável de ambiente contémUNIVERSE = att
.fonte
echo
expandir as\x
seqüências em oposição ao shell como parte da sintaxe de citação é que você pode gerar um byte NUL (outro design indiscutivelmente incorreto do Unix são aqueles delimitados por nulos cordas, onde metade das chamadas de sistema (comoexecve()
) não podem tomar seqüências arbitrárias de bytes)printf
parece ser um problema, já que a maioria das implementações faz isso errado. A única implementação correta que eu conheço estábosh
e a página de Sven Maschek não lista os problemas com bytes nulos via\0
.Você pode querer usar
printf
para suas opções de formatação.echo
é útil quando se trata de imprimir o valor de uma variável ou de uma linha (simples), mas é tudo o que existe.printf
pode basicamente fazer o que a versão C pode fazer.Exemplo de uso e recursos:
Echo
:printf
:Fontes:
fonte
echo
para imprimir uma variável pode falhar se o valor da variável contiver metacaracteres.Uma "vantagem", se você quiser chamar assim, seria não precisar dizer que gostaria
echo
de interpretar certas seqüências de escape, como\n
. Ele sabe interpretá-los e não precisará-e
disso.(Nota: o último
\n
é necessário,echo
implica, a menos que você dê a-n
opção)versus
Observe a última
\n
emprintf
. No final do dia, é uma questão de gosto e requisitos o que você usa:echo
ouprintf
.fonte
/usr/bin/echo
ebash
embutido. Odash
,ksh
ezsh
builtinecho
não precisam ser-e
alternados para expandir caracteres com escape de barra invertida.printf '%s\n' 'foo\bar
.Uma desvantagem
printf
é o desempenho, porque o shell internoecho
é muito mais rápido. Isso ocorre principalmente no Cygwin, onde cada instância de um novo comando causa uma sobrecarga pesada do Windows. Quando mudei meu programa de eco pesado de usar/bin/echo
para eco do shell, o desempenho quase dobrou. É uma troca entre portabilidade e desempenho. Não é um slam dunk para sempre usarprintf
.fonte
printf
atualmente é construído na maioria dos shells (bash, dash, ksh, zsh, yash, alguns derivados do pdksh ... então inclui os shells normalmente encontrados no cygwin). As únicas exceções notáveis são algunspdksh
derivativos.printf
para gerar nul bytes, mas algumas implementações interpretam `\ c 'na string de formato, mesmo que não devam.printf
não é especificado pelo POSIX se você usar\c
a string format, para que asprintf
implementações possam fazer o que quiserem nesse sentido. Por exemplo, alguns tratam da mesma forma que no PWBecho
(faz com que printf saia), o ksh o usa para\cA
caracteres de controle (para o argumento do formato printf e para$'...'
mas não paraecho
nemprint
!). Não tenho certeza o que isso tem a ver com a impressão de bytes NUL, ou talvez você está se referindo aksh
'sprintf '\c@'
?