Expressão de suporte (sem intervalos) correspondendo a caractere inesperado no bash

18

Estou usando o bash no Linux. Estou obtendo sucesso com a seguinte declaração, mas isso não deve retornar um código de falha?

if [[ ■ = [⅕⅖⅗] ]] ; then echo yes ; fi

O quadrado NÃO é igual a nenhum dos caracteres, então não vejo por que recebo um código de sucesso.

É importante para mim manter os colchetes duplos no meu caso.

Existe alguma outra maneira de fazer um intervalo neste cenário ou quaisquer outras sugestões?

    
por TuxForLife 03.04.2015 / 09:05

2 respostas

28

Isso é uma conseqüência desses personagens terem a mesma ordem de classificação.

Você também notará que

sort -u << EOF
■
⅕
⅖
⅗
EOF

retorna apenas uma linha.

Ou isso:

expr ■ = ⅕

retorna verdadeiro (conforme exigido pelo POSIX).

A maioria dos locais fornecidos com sistemas GNU tem vários caracteres (e até sequências de caracteres (seqüências de intercalação)) que possuem a mesma ordem de classificação. No caso destes, é porque a ordem não está definida e os caracteres cuja ordem não está definida acabam tendo a mesma ordem de classificação nos sistemas GNU. Existem caracteres que são explicitamente definidos como tendo a mesma ordem de classificação, como Ș e Ş (embora não exista uma lógica ou consistência aparente (para mim, de qualquer maneira) real sobre como isso é feito).

Essa é a fonte de comportamentos bastante surpreendentes e falsos. Eu tenho levantado a questão muito recentemente sobre o grupo de Austin (o órgão por trás do POSIX ea lista de discussão Single UNIX Specification) e a discussão ainda está em andamento a partir de 2015-04-03.

Neste caso, se [y] deve corresponder a x , em que x e y ordenam o mesmo não está claro para mim, mas como uma expressão de colchetes deve corresponder a um elemento de intercalação, isso sugere que% o comportamentobash é esperado.

De qualquer forma, suponho que [⅕-⅕] ou pelo menos [⅕-⅖] correspondam a .

Você notará que diferentes ferramentas se comportam de maneira diferente. O ksh93 se comporta como bash , GNU grep ou sed não. Algumas outras shells têm comportamentos diferentes, como yash , com mais bugs.

Para ter um comportamento consistente, você precisa de uma localidade em que todos os caracteres sejam classificados de maneira diferente. O local C é o típico. No entanto, o conjunto de caracteres na localidade C na maioria dos sistemas é ASCII. Nos sistemas GNU, você geralmente tem acesso a um C.UTF-8 locale que pode ser usado para trabalhar em caracteres UTF-8.

Então:

(export LC_ALL=C.UTF-8; [[ ■ = [⅕⅖⅗] ]])

ou o equivalente padrão:

(export LC_ALL=C.UTF-8
 case ■ in ([⅕⅖⅗]) true;; (*) false; esac)

deve retornar falso.

Outra alternativa seria definir apenas LC_COLLATE para C, o que funcionaria nos sistemas GNU, mas não necessariamente em outros, onde poderia falhar em especificar a ordem de classificação do caractere de múltiplos bytes.

Uma lição disso é que igualdade não é uma noção tão clara quanto se esperaria quando se trata de comparar strings. A igualdade pode significar, do estrito ao menos estrito.

  1. O mesmo número de bytes e todos os componentes de byte têm o mesmo valor.
  2. O mesmo número de caracteres e todos os caracteres são os mesmos (por exemplo, consulte o mesmo codepoint no conjunto de caracteres atual).
  3. As duas cadeias têm a mesma ordem de classificação que o algoritmo de intercalação da localidade (isto é, nem uma < b nem b > a é verdadeira).

Agora, para 2 ou 3, isso pressupõe que as duas sequências contenham caracteres válidos. Em UTF-8 e algumas outras codificações, algumas seqüências de bytes não formam caracteres válidos.

1 e 2 não são necessariamente equivalentes por causa disso, ou porque alguns caracteres podem ter mais de uma codificação possível. Esse é tipicamente o caso de codificações com informações de estado como ISO-2022-JP, em que A pode ser expresso como 41 ou 1b 28 42 41 ( 1b 28 42 sendo a sequência para alternar para ASCII e você pode inserir quantos você quiser , isso não fará diferença), embora eu não espere que esses tipos de codificação ainda estejam em uso, e as ferramentas GNU, pelo menos, geralmente não funcionam adequadamente com elas.

Tenha também em atenção que a maioria dos utilitários não-GNU não consegue lidar com o valor de 0 bytes (o caracter NUL em ASCII).

Qual dessas definições é usada depende da implementação ou versão do utilitário e do utilitário. O POSIX não é 100% claro sobre isso. Na localidade C, todos os 3 são equivalentes. Fora desse YMMV.

    
por 03.04.2015 / 11:02
-3

Você está fazendo isso errado, = e == não são iguais.

Experimente estes exemplos:

if [[ "■" == "[⅕⅖⅗]" ]] ; then echo yes ; else echo no ; fi

if [[ "1" == "1" ]] ; then echo yes ; else echo no ; fi

if [[ "■" == "■" ]] ; then echo yes ; else echo no ; fi
    
por 03.04.2015 / 09:45