Por que o zsh e o ksh93 optaram por não serem compatíveis com a correspondência de padrões?

5

Documentação POSIX para correspondência de padrões disse que:

An ordinary character is a pattern that shall match itself. It can be any character in the supported character set except for NUL, those special shell characters in Quoting that require quoting, and the following three special pattern characters. Matching shall be based on the bit pattern used for encoding the character, not on the graphic representation of the character. If any character (ordinary, shell special, or pattern special) is quoted, that pattern shall match the character itself. The shell special characters always require quoting.

Pelo que entendi, o padrão ["!"a] corresponderá a ! e a . Esse também é o comportamento na maioria dos shells que eu tentei, exceto zsh e ksh93 :

$ for shell in /bin/*[^c]sh; do
  printf '=%-17s=\n' "$shell"
  "$shell" -c 'case a in ["!"a]) echo 1;; esac'
done
=/bin/ash         =
1
=/bin/bash        =
1
=/bin/dash        =
1
=/bin/heirloom-sh =
1
=/bin/ksh         =
=/bin/lksh        =
1
=/bin/mksh        =
1
=/bin/pdksh       =
1
=/bin/posh        =
1
=/bin/schily-osh  =
1
=/bin/schily-sh   =
1
=/bin/yash        =
1
=/bin/zsh         =

zsh e ksh93 parecem tratar ["!"a] igual a [!a] , que corresponde a qualquer caractere, exceto a :

$ for shell in ksh93 zsh; do
  printf '=%-6s=\n' "$shell"
  "$shell" -c 'case b in ["!"a]) echo 1;; esac'
done
=ksh93 =
1
=zsh   =
1

Existe algum motivo (histórico, desenvolvimento, ...) para zsh e ksh93 se comportarem assim?

zsh faz o mesmo em ksh e sh emulação.

busybox sh , Solaris /usr/xpg4/bin/sh e FreeBSD sh também se comportam como a documentação POSIX.

ksh88 também se comporta como a maioria dos outros shells, o comportamento mudou entre kssh88 e ksh93 :

$ ksh88 -c 'case a in ["!a"]) echo yes; esac'
yes
$ ksh88 -c 'case b in ["a-c"]) echo yes; esac' 
$
    
por cuonglm 24.02.2016 / 08:26

3 respostas

4

A passagem que você cita não significa o que você diz que significa.

Patterns Matching a Single Character

(…) An ordinary character is a pattern that shall match itself. (…) If any character (ordinary, shell special, or pattern special) is quoted, that pattern shall match the character itself.

Tudo isso se aplica apenas aos caracteres que se destacam em um padrão. Isso não se aplica a caracteres que aparecem em um contexto diferente daquele em que um caractere de padrão é esperado. Em particular, não se aplica dentro de uma expressão de colchetes. A sintaxe das expressões de colchetes é descrita na entrada para [ :

If an open bracket introduces a bracket expression as in XBD RE Bracket Expression, (…)

(Eu omiti o bit sobre ! vs ^ para complementação.) A descrição das expressões de colchetes RE não diz nada sobre aspas (o que não é de surpreender, já que é sobre expressões de colchetes em geral, não sobre expressões de colchetes em um padrão em um script de shell).

Indo por uma interpretação estrita do POSIX.1-2008, não está claro qual deve ser o padrão ["!"a] . Uma interpretação é que deve corresponder a qualquer um dos caracteres " , ! ou a : o caractere " não tem nenhum significado especial dentro de uma expressão de colchetes. Não consigo encontrar nada na especificação que possa invalidar essa interpretação. Outra interpretação é que " mantém seu comportamento de cotação, mas isso significa que o conteúdo da expressão de colchetes é !a e, como não há tratamento específico de caracteres citados dentro de expressões de colchetes, o conjunto é all-but- a . Eu não consigo encontrar nenhum suporte para sua interpretação (e o comportamento de dash, bash e outros shells) na especificação POSIX. Faz sentido, claro, mas não é o que o texto diz.

Faz sentido que uma futura versão do POSIX imponha sua interpretação, adicionando algumas palavras a esse efeito. Por exemplo, a descrição de [ pode ser alterada para

If an open bracket introduces a bracket expression as in XBD RE Bracket Expression, except that the \ character ('!') shall replace the \ character ('^') in its role in a non-matching list in the regular expression notation, it shall introduce a pattern bracket expression, and that any character that is quoted shall stand for itself as an element of the enclosing bracket expression, collating element or class expression. A bracket expression starting with an unquoted \ character produces unspecified results. Otherwise, '[' shall match the character itself.

Dado que o POSIX é mais descritivo do que normativo, eu esperaria que uma mudança como essa que quebra o ksh (geralmente o shell de referência) seja incluída apenas em uma grande atualização do padrão, e qualquer defeito na versão existente permitir pelo menos as diferentes interpretações existentes.

    
por 28.02.2016 / 23:21
2

Esse é um bug em zsh , que foi relatado nesta discussão [BUG] entre colchetes padrões não tem efeito :

case b in
  ( ['a-c'] ) echo 'false match' ;;
  ( [a-c] )   echo 'correct match' ;;
esac

imprimirá false match em vez de correct match .

A correção está programada para ser lançada com zsh versão 5.3 .

    
por 26.02.2016 / 12:23
1

O que você está lendo é aplicável apenas a caracteres simples. Não são personagens dentro de um Bracket expression .

Na verdade, isso é claramente indicado um pouco adiante:

When unquoted and outside a bracket expression, the following three characters shall have special meaning in the specification of patterns:

? A <question-mark> ...
* An <asterisk> ...
[ If an open bracket introduces a bracket expression ...

O que você precisa ler para um Bracket Expression está aqui .

De acordo com a especificação; Dentro de um "Bracket Expression", não há nenhum conceito de citar (por padrões).

No entanto, a maioria dos shell remove as aspas em qualquer string, mesmo que essa string esteja dentro de uma "Expressão de colchetes". É por isso que um ["!"a] se torna [!a] para o caso de comando.

No entanto, o shell mantém um conhecimento de que a string foi citada para a maioria dos shell e, portanto, a negação não tem efeito (em oposição à especificação não ter um conceito de cotação dentro de "Bracket Expression"). ").

Em ksh e zsh, esse conhecimento não é usado para avaliar o padrão.

Por que isso acontece ?, acredito que são apenas erros.

No entanto, o ksh e o zsh agem de forma diferente da maioria das shells.

Usando este código (o caso é repetido para testar todos os valores em todos os shells):

whichsh="'ps -o pid,args| awk '$1=='"$$"'{print $2}''"
[ ${whichsh##*/} = zsh  ] && setopt GLOB_SUBST
[ ${whichsh##*/} = zsh4 ] && setopt GLOB_SUBST

a="$1"; printf '%s\t' "testing $a"

case $a in ['!a'])    printf 1 ;; esac
case $a in ["!a"])    printf 2 ;; esac
case $a in ['!'a])    printf 3 ;; esac
case $a in ["!"a])    printf 4 ;; esac
case $a in [\"!\"a])  printf 5 ;; esac
case $a in [!a])      printf 6 ;; esac
printf "\t --"

t1="['!a']";t2='["!a"]';t3="['!'a]";t4='["!"a]';t5='[\"!\"a]'
case $a in $t1)     printf 1 ;; esac
case $a in $t2)     printf 2 ;; esac
case $a in $t3)     printf 3 ;; esac
case $a in $t4)     printf 4 ;; esac
case $a in $t5)     printf 5 ;; esac
case $a in [!a])    printf 6 ;; esac
echo

Para um teste com "a", ./script.sh a , os resultados são:

/bin/dash       : testing a     12345    --12345
/bin/sh         : testing a     12345    --12345
/bin/b43sh      : testing a     12345    --12345
/bin/b44sh      : testing a     12345    --12345
/bin/bash       : testing a     12345    --12345
/bin/ksh        : testing a     5        --12345
/bin/ksh93      : testing a     5        --12345
/bin/lksh       : testing a     12345    --12345
/bin/mksh       : testing a     12345    --12345
/bin/zsh        : testing a     5        --12345
/bin/zsh4       : testing a     5        --12345

E um teste para "b", ./script.sh b , os resultados são:

/bin/dash       : testing b     6        --6
/bin/sh         : testing b     6        --6
/bin/b43sh      : testing b     6        --6
/bin/b44sh      : testing b     6        --6
/bin/bash       : testing b     6        --6
/bin/ksh        : testing b     12346    --6
/bin/ksh93      : testing b     12346    --6
/bin/lksh       : testing b     6        --6
/bin/mksh       : testing b     6        --6
/bin/zsh        : testing b     12346    --6
/bin/zsh4       : testing b     12346    --6

Quando os padrões de teste têm cotas dentro de variáveis, as cotações não são removidas e afetam o resultado. Quando as aspas são usadas diretamente no padrão, ksh e zsh removem as aspas e avaliam [!a] .

O que todas as shells devem fazer é manter as aspas dentro dos parênteses como parte dos caracteres testados.

Para obter aspas "cotadas", o ksh e o zsh precisam de um padrão como [\"!\"a] . Então ambos correspondem a a , ! e " .

    
por 24.02.2016 / 09:59

Tags