Por que as 'Character Classes' devem ser preferidas em relação a 'Character Ranges' em Shell (Bash)?

5

A linha de comando do Linux (Contagem de páginas - livro 47) diz:

... you have to be very careful with them [character ranges] because they will not produce the expected results unless properly configured. For now, you should avoid using them and use character classes instead.

O livro não dá nenhuma razão, além disso.

Pergunta - 1: Então, por que exatamente Classes de caracteres (por exemplo, [:alnum:] , [:alpha:] , [:digit:] , etc) devem ser preferidas sobre Intervalos de caracteres (por exemplo, [a-z] , [A-Z] , [0-9] , etc)?

Pergunta 2: O [:alpha:] representa [a-z] , [A-Z] e letras maiúsculas e minúsculas de outros idiomas também ? E da mesma forma, [:digit:] inclui numerais de outras linguagens também? Se eles combinam, é isso.

(Duas perguntas, eu sei, mas neste caso, elas são praticamente inter-relacionadas, IMO.)

    
por its_me 17.04.2013 / 13:47

3 respostas

4

De acordo com a% man_de% manpage, a variável de ambiente bash afeta os intervalos de caracteres, exatamente como a resposta de Hauke Laging:

LC_COLLATE This variable determines the collation order used when sorting the results of pathname expansion, and determines the behavior of range expressions, equivalence classes, and collating sequences within pathname expansion and pattern matching.

Por outro lado, LC_COLLATE afeta as classes de caracteres:

LC_CTYPE This variable determines the interpretation of characters and the behavior of character classes within pathname expansion and pattern matching.

O que isto significa é que ambos casos são potencialmente problemáticos se você estiver pensando em um contexto em inglês, da esquerda para a direita, alfabeto latino, dígito árabe.

Se você for realmente adequado e / ou estiver criando scripts para um ambiente com várias localidades, provavelmente será melhor confirmar quais são suas variáveis de localidade ao corresponder arquivos ou ter certeza de que está codificando de uma forma completamente genérica.

É muito difícil prever algumas situações, a menos que você tenha estudado lingüística.

No entanto, eu não sei de uma localidade que usa latim que mude a ordem de letras, então [a-z] funcionaria. Existem extensões para o alfabeto latino que agrupam ligaduras e diacríticos de maneira diferente. No entanto, aqui está um pequeno experimento:

<!-- language: lang-bash -->
mkdir /tmp/test
cd /tmp/test
export LC_CTYPE=de_DE.UTF-8
export LC_COLLATE=de_DE.UTF-8
touch Grüßen
ls G* # This says ‘Grüßen’
ls *[a-z]en # This says nothing!
ls *[a-zß]en # This says ‘Grüßen’
ls Gr[a-z]*en # This says nothing!

Isso é interessante: pelo menos para o alemão, nem diacríticos como ü nem ligaduras como ß são dobrados em caracteres latinos. (ou isso, ou eu estraguei a mudança do local!)

Isso pode ser ruim para você, é claro, se você estiver tentando encontrar nomes de arquivos que começam com uma letra, use LC_CTYPE e aplique-a em um arquivo que comece com "Ä".

    
por 17.04.2013 / 14:52
1

"Outras línguas", é isso. Locais diferentes podem ter ordens de classificação diferentes. Então, em teoria, pode ser que a-z não seja o mesmo com outra localidade. Os intervalos tornam-se difíceis de combinar com tudo. Qual é o primeiro, qual o último char?

As pessoas do openSUSE são tão paranóicas quanto a verificar nomes de usuários / senhas que eles fazem isso da seguinte forma: [abcdefghi ...]

Eu nunca pensei em numerais em outras linguagens / conjuntos de caracteres. Ponto interessante.

    
por 17.04.2013 / 14:26
0

Ao usar o bash 4.2 no OS X, as localidades UTF-8 parecem usar a ordem de intercalação ASCII, mas as localidades ISO 8859-1 não o fazem em alguns contextos:

$ LC_ALL=en_US.UTF-8 tr A-C 1-9 <<< B
2
$ LC_ALL=en_US.ISO8859-1 tr A-C 1-9 <<< B
6
$ LC_ALL=en_US.UTF-8 grep [A-Z] <<< ä
$ LC_ALL=en_US.ISO8859-1 grep [A-Z] <<< ä
ä

Em alguns ambientes, as localidades UTF-8 também usam ordens de agrupamento diferentes.

[: upper:] e [: lower:] também incluem caracteres não-ASCII em muitas localidades. Se você quiser apenas corresponder caracteres ASCII, use algo assim:

LC_ALL=C tr a-zA-Z n-za-mN-ZA-M

Se LC_ALL foi definido para outra coisa, LC_COLLATE = C ou LANG = C não funcionaria.

    
por 17.04.2013 / 18:32