zshnão é um shell POSIX, ele foi escrito antes do shlançamento da especificação POSIX, pegou recursos e sintaxe de ksh, csh, tcsh, rc e adicionou muitos dos seus próprios. Sua sintaxe é em grande parte semelhante ao Korn, mas isso não significa que seja totalmente compatível com o shell Korn. De qualquer forma, não é e nunca pretendeu ser um interpretador compatível com POSIX para a linguagem sh (pelo menos não em seu modo padrão).
No entanto, ele possui vários modos de emulação (csh, ksh e sh (anteriormente tentando seguir o SysV sh, agora seguindo o POSIX sh)) que podem ser usados para melhorar a compatibilidade com outros shells e interpretar o código escrito para eles. Isso significa que ele pode ter sua própria sintaxe separada daquela de sh ou de qualquer outro shell (como csh, rc, fish, perl, python...) e ainda ser capaz de interpretar código escrito para sh.
Se invocado como sh, csh, ou ksh(ou qualquer coisa que comece com s(ou bpara Bourne), cou k), ou em versões mais recentes com --emulate sh/ksh/csh, ele entrará no modo de emulação correspondente, mas não é assim que você normalmente os usaria. Para interpretar um shscript, você executaria sh, não zsh.
Você prefere executar emulate shdentro zshpara alternar o modo de emulação para shquando quiser interpretar o código sh dentro de zsh, e também pode executar emulate sh -c 'some code'para ter some codeinterpretado na shemulação.
Assim, dentro de zsh:
emulate sh -c 'printf "%d\n" 024'
seria executado printfde uma maneira mais POSIX.
Quanto ao printf, um printfutilitário apareceu pela primeira vez em Research Unix Ninth Edition (da AT&T Research / Bell Labs, não em uso amplo) por volta de 1986, para obter a mesma API de formatação de texto disponível em C com a printffunção libc.
Enquanto Cum leva um primeiro argumento de formato como um ponteiro para uma matriz de bytes delimitada por NUL e argumentos extras de diferentes tipos (ponteiro, inteiro, duplo...), um executável só pode receber argumentos como strings. Portanto, para formatar um número, por exemplo, para %d, ele precisa receber uma representação de texto de um número e convertê-lo de volta em um inteiro binário e convertê- printflo de volta em texto para saída.
Na implementação original em V9 , printfreconhecia os mesmos números que na linguagem C (dec -123, +123, octal 0123, hex 0x123, float 1.2e-2, even 'x'or "foo"(onde é o valor do primeiro caractere usado)).
O SVR4 (descendente do V7) também tinha um printfutilitário muito burro que acabou de fazer:
Portanto, era útil apenas para %sformatação de tipo, pois printf()apenas eram fornecidos ponteiros para os argumentos de string.
POSIX.2 (escrito no final dos anos 80 atrás de portas (principalmente) fechadas e lançado em 1992 (não disponível gratuitamente na época)), especificou um printfcomando. Como o echoutilitário era muito pouco portátil e não confiável, uma alternativa era muito necessária. Por alguma razão, eles não optaram kshpelo printbuilt-in do , mas especificaram um printfutilitário baseado principalmente na implementação da V9 e com uma referência à linguagem C quando se trata de converter strings em números.
ksh88, o shell no qual a shespecificação POSIX é baseada nunca teve um printfbuilt-in (nem seu clone pdksh). Ele tem seu próprio printbuilt-in como uma alternativa confiável para echo. Uma -fopção para printfoi adicionada em ksh93 junto com um printfalias para print -f.
No ksh, a maioria dos builtins ou construções que aceitam números como entrada aceitará qualquer expressão aritmética, não apenas constantes numéricas. Então, em ksh93
printf '%d\n' '1 + 1'
Iria imprimir 2.
E nas primeiras versões, printf '%d\n' 010imprimiria 10, não 8.
Nas expressões aritméticas do shell ksh, inicialmente, os números com 0s iniciais não eram considerados octais porque, em um shell, é muito mais comum lidar com números decimais preenchidos com 0 (como data/hora, nomes de arquivos) do que lidar com números octais.
No entanto, a especificação POSIX meio que exigia que eles fossem tratados como octais, o que a maioria dos shells ignorou (como a implementação original do shell no qual o padrão foi baseado não). No entanto, após a Solicitação de Interpretação do PASC que tornou mais claro, a maioria dos shells começou a mudar seu comportamento (incluindo ksh93 e zsh, embora isso tenha sido revertido ), causando muita dor.
Se você observar o histórico de lançamentos de ksh93 , você notará que o tratamento de números com prefixo 0 como octal foi ativado e desativado. Ainda hoje, você descobrirá que 010 em expressões aritméticas é 8 dentro de ((...))ou $((...)), mas 10 na maioria dos outros lugares, incluindo let '...', array[...], [[ ... -eq ... ]]e... printf. set -o posixfaz com que mude para 8 na maioria dos lugares, sendo uma exceção notável... printfnovamente .
Um printfbuiltin foi adicionado mais tarde em 2001, inicialmente usandostrtod() para converter texto em números, tratando números com 0 à esquerda como octal, mas depois alterado para aceitar qualquer expressão aritmética como em ksh93, sujeito às octal_zeroesopções e permitindo mais formatos numéricos, como 0b10010, ksh -style números baseados arbitrários ( 12#A001, 2#10010...), 1_000_000...
Então, em zsh, para passar um número octal para printf, as opções são:
emular she usar 0 inicial:emulate sh -c 'printf %d 024'
defina a octalzeroesopção:set -o octalzeroes; printf %d 024
mesmo em um escopo local apenas: (){ set -o localoptions -o octalzeroes; printf %d 024; }(aqui em uma função anônima).
use a 8#oooonotação que é sempre reconhecida:printf %d '8#24'
desabilite o printfbuilt-in e assuma que o printfutilitário do sistema é compatível com POSIX a esse respeito: disable printf; printf %d 024.
Outras maneiras de invocar esse autônomo printf: command printf %d 024(não em shemulação), =printf %d 024(não em shemulação).
Use command printf ...para executar o utilitário printf padrão. printf de zsh tem suas próprias interpretações de argumentos que entram em conflito com o padrão POSIX, %d interpreta argumentos como expressões aritméticas, então você pode converter um valor de octal com printf %d '8#24'.
zsh não é compatível com POSIX por padrão e os desvios não são apenas pequenos.
Este é um problema geral com o uso de zsh.
Tentar:
zsh --emulate sh -c 'printf "%d\n" 024'
e imprimirá 20
Mas note que isso só funcionará com uma zshversão recente.
Se você gosta de um método que funcione mesmo com zshversões mais antigas, existe uma maneira de fazer isso. Crie um arquivo $HOME/.zshenvcom o seguinte conteúdo:
if [ -n "$ZSH_EMULATION" ]; then
emulate "$ZSH_EMULATION"
fi
Se você tiver esse arquivo, você pode chamar:
ZSH_EMULATION=sh zsh -c 'printf "%d\n" 024'
e isso funcionará com qualquer versão do zsh.
BTW: o texto atual relacionado ZSH_EMULATIONfoi introduzido após uma discussão nos comentários.
zsh
não é um shell POSIX, ele foi escrito antes dosh
lançamento da especificação POSIX, pegou recursos e sintaxe de ksh, csh, tcsh, rc e adicionou muitos dos seus próprios. Sua sintaxe é em grande parte semelhante ao Korn, mas isso não significa que seja totalmente compatível com o shell Korn. De qualquer forma, não é e nunca pretendeu ser um interpretador compatível com POSIX para a linguagem sh (pelo menos não em seu modo padrão).No entanto, ele possui vários modos de emulação (csh, ksh e sh (anteriormente tentando seguir o SysV sh, agora seguindo o POSIX sh)) que podem ser usados para melhorar a compatibilidade com outros shells e interpretar o código escrito para eles. Isso significa que ele pode ter sua própria sintaxe separada daquela de sh ou de qualquer outro shell (como csh, rc, fish, perl, python...) e ainda ser capaz de interpretar código escrito para sh.
Se invocado como
sh
,csh
, ouksh
(ou qualquer coisa que comece coms
(oub
para Bourne),c
ouk
), ou em versões mais recentes com--emulate sh/ksh/csh
, ele entrará no modo de emulação correspondente, mas não é assim que você normalmente os usaria. Para interpretar umsh
script, você executariash
, nãozsh
.Você prefere executar
emulate sh
dentrozsh
para alternar o modo de emulação parash
quando quiser interpretar o código sh dentro de zsh, e também pode executaremulate sh -c 'some code'
para tersome code
interpretado nash
emulação.Assim, dentro de
zsh
:seria executado
printf
de uma maneira mais POSIX.Quanto ao
printf
, umprintf
utilitário apareceu pela primeira vez em Research Unix Ninth Edition (da AT&T Research / Bell Labs, não em uso amplo) por volta de 1986, para obter a mesma API de formatação de texto disponível em C com aprintf
função libc.Enquanto
C
um leva um primeiro argumento de formato como um ponteiro para uma matriz de bytes delimitada por NUL e argumentos extras de diferentes tipos (ponteiro, inteiro, duplo...), um executável só pode receber argumentos como strings. Portanto, para formatar um número, por exemplo, para%d
, ele precisa receber uma representação de texto de um número e convertê-lo de volta em um inteiro binário e convertê-printf
lo de volta em texto para saída.Na implementação original em V9 ,
printf
reconhecia os mesmos números que na linguagem C (dec-123
,+123
, octal0123
, hex0x123
, float1.2e-2
, even'x'
or"foo"
(onde é o valor do primeiro caractere usado)).O SVR4 (descendente do V7) também tinha um
printf
utilitário muito burro que acabou de fazer:Portanto, era útil apenas para
%s
formatação de tipo, poisprintf()
apenas eram fornecidos ponteiros para os argumentos de string.POSIX.2 (escrito no final dos anos 80 atrás de portas (principalmente) fechadas e lançado em 1992 (não disponível gratuitamente na época)), especificou um
printf
comando. Como oecho
utilitário era muito pouco portátil e não confiável, uma alternativa era muito necessária. Por alguma razão, eles não optaramksh
peloprint
built-in do , mas especificaram umprintf
utilitário baseado principalmente na implementação da V9 e com uma referência à linguagem C quando se trata de converter strings em números.ksh88, o shell no qual a
sh
especificação POSIX é baseada nunca teve umprintf
built-in (nem seu clone pdksh). Ele tem seu próprioprint
built-in como uma alternativa confiável paraecho
. Uma-f
opção paraprint
foi adicionada em ksh93 junto com umprintf
alias paraprint -f
.No ksh, a maioria dos builtins ou construções que aceitam números como entrada aceitará qualquer expressão aritmética, não apenas constantes numéricas. Então, em ksh93
Iria imprimir
2
.E nas primeiras versões,
printf '%d\n' 010
imprimiria 10, não 8.Nas expressões aritméticas do shell ksh, inicialmente, os números com 0s iniciais não eram considerados octais porque, em um shell, é muito mais comum lidar com números decimais preenchidos com 0 (como data/hora, nomes de arquivos) do que lidar com números octais.
No entanto, a especificação POSIX meio que exigia que eles fossem tratados como octais, o que a maioria dos shells ignorou (como a implementação original do shell no qual o padrão foi baseado não). No entanto, após a Solicitação de Interpretação do PASC que tornou mais claro, a maioria dos shells começou a mudar seu comportamento (incluindo ksh93 e
zsh
, embora isso tenha sido revertido ), causando muita dor.Se você observar o histórico de lançamentos de ksh93 , você notará que o tratamento de números com prefixo 0 como octal foi ativado e desativado. Ainda hoje, você descobrirá que 010 em expressões aritméticas é 8 dentro de
((...))
ou$((...))
, mas 10 na maioria dos outros lugares, incluindolet '...'
,array[...]
,[[ ... -eq ... ]]
e...printf
.set -o posix
faz com que mude para 8 na maioria dos lugares, sendo uma exceção notável...printf
novamente .Como o zsh nunca afirmou ser um shell POSIX, ele apenas adicionou uma nova opção (
octal_zeroes
) em 2000, habilitada nash
emulação, mas não de outra forma.Um
printf
builtin foi adicionado mais tarde em 2001, inicialmente usandostrtod()
para converter texto em números, tratando números com 0 à esquerda como octal, mas depois alterado para aceitar qualquer expressão aritmética como em ksh93, sujeito àsoctal_zeroes
opções e permitindo mais formatos numéricos, como0b10010
, ksh -style números baseados arbitrários (12#A001
,2#10010
...),1_000_000
...Então, em
zsh
, para passar um número octal paraprintf
, as opções são:sh
e usar 0 inicial:emulate sh -c 'printf %d 024'
octalzeroes
opção:set -o octalzeroes; printf %d 024
(){ set -o localoptions -o octalzeroes; printf %d 024; }
(aqui em uma função anônima).8#oooo
notação que é sempre reconhecida:printf %d '8#24'
printf
built-in e assuma que oprintf
utilitário do sistema é compatível com POSIX a esse respeito:disable printf; printf %d 024
.printf
:command printf %d 024
(não emsh
emulação),=printf %d 024
(não emsh
emulação).Use
command printf ...
para executar o utilitário printf padrão. printf de zsh tem suas próprias interpretações de argumentos que entram em conflito com o padrão POSIX, %d interpreta argumentos como expressões aritméticas, então você pode converter um valor de octal comprintf %d '8#24'
.zsh não é compatível com POSIX por padrão e os desvios não são apenas pequenos.
Este é um problema geral com o uso de zsh.
Tentar:
e imprimirá 20
Mas note que isso só funcionará com uma
zsh
versão recente.Se você gosta de um método que funcione mesmo com
zsh
versões mais antigas, existe uma maneira de fazer isso. Crie um arquivo$HOME/.zshenv
com o seguinte conteúdo:Se você tiver esse arquivo, você pode chamar:
e isso funcionará com qualquer versão do
zsh
.BTW: o texto atual relacionado
ZSH_EMULATION
foi introduzido após uma discussão nos comentários.