Força de agrupamento do Bash (caracteres de capital versus pequenos)

2

Eu tenho um script que lê a entrada e conta a ocorrência de caracteres. É baseado em uma matriz:

parse_stream () {
    while read -n 1 char; do
        if [[ -n $char ]]; then
            ((count++))
            ((chars[\$char]++))
        fi
    done
}

Imprime um relatório simples lendo a matriz:

print_results () {
    { for i in "${!chars[@]}"; do
        echo -e "$i" "\t"  ${chars["$i"]}
    done } | sort
}

Os resultados que obtenho estão em ordem alfabética, mas com letras maiúsculas e minúsculas misturadas:

0    3362
[    1
/    1213
:    1628
_    168
1    7282
*    2337
2    3922
+    24
3    2261
4    2042
.    508
5    1624
>    575
6    1879
-    7128
7    1345
8    1895
9    853
A    1
a    2610
b    578
c    1430
C    2
D    1
d    1179
E    2
e    3166
F    1
f    853
G    1
g    962
H    1
h    633
I    11
i    2955
j    254
k    1157
l    2619
M    13
m    1915
n    1590
O    1
o    10983
p    2127
P    3
Q    11
q    118
r    14003
S    1
s    2559
T    2
t    8165
u    1067
v    595
w    4556
X    4
x    7802
y    660
z    193
ź    48

Uma vez, a maiúscula vem em primeiro lugar, outra é a minúscula. Existe alguma maneira de corrigir isso?

Os números estão em desordem também ... Mas isso pode ser classificado com sort (às vezes ... por quê? ...). Ubuntu aqui, se isso importa.

Você pode ver o script inteiro aqui .

UPDATE

Eu apliquei LANG=pl_PL.UTF-8 sort à função no script. Não é tão confuso agora, mas ainda ocorre com letras maiúsculas e minúsculas.

0    3359
1    7281
2    3931
3    2258
4    2046
5    1624
6    1882
7    1346
8    1892
9    846
A    1         #upper
a    2607      #then lower
b    578
c    1430      #lower
C    2         #then upper
D    1

...etc...

Minhas configurações normais são diferentes, mas herdadas pelo subshell:

tomasz@tomasz-Latitude-E4200:~$ echo $LANG
en_US.UTF-8
tomasz@tomasz-Latitude-E4200:~$ (echo $LANG)
en_US.UTF-8

O que coloca o comportamento "normal" ou anterior de sort sob uma luz difícil.

De qualquer forma, as maiúsculas e minúsculas também ficam truncadas depois que eu uso a definição LANG explicitamente na classificação adicional, ou seja:

ll /usr/bin | charstat | LANG=pl_PL.UTF-8 sort

Isso novamente produz essa sequência:

A    1
a    2607
b    578
c    1430
C    2

UPDATE

$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=pl_PL.UTF-8
LC_TIME=pl_PL.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=pl_PL.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=pl_PL.UTF-8
LC_NAME=pl_PL.UTF-8
LC_ADDRESS=pl_PL.UTF-8
LC_TELEPHONE=pl_PL.UTF-8
LC_MEASUREMENT=pl_PL.UTF-8
LC_IDENTIFICATION=pl_PL.UTF-8
LC_ALL=
    
por Tomasz 04.08.2016 / 02:06

1 resposta

4

O problema não é bash , o problema é sort .

Agora, sort é localidade ciente.

Se você executar o comando locale , ele poderá dizer algo como en_US ou similar (se você estiver nos EUA; outros idiomas terão outros locais). Também pode haver uma codificação ( en_US.UTF8 ).

Agora as localidades também afetam o pedido.

Vamos dar um exemplo simples:

$ x="a\nA\nc\nC\nb\nB\n"

$ echo -ne "$x" | LANG=C sort
A
B
C
a
b
c

Isso parece exatamente o que queremos. Mas ...

$ echo -ne "$x" | LANG=en_US sort
a
A
b
B
c
C

Uh oh!

sort não é o único programa que pode alterar o comportamento com base na localidade.

Se você quiser um comportamento consistente tradicional em todas as configurações, precisará definir LANG .

Isso não é incomum e seu sistema operacional já pode fazer isso como parte de seu próprio script.

Por exemplo ...

No RedHat / CentOS, muitos scripts /etc/rc.d/init.d fazem isso; Por exemplo, /etc/rc.d/init.d/network tem

interfaces=$(ls ifcfg* | \
            LANG=C sed -e "$__sed_discard_ignored_files" \
                       -e '/\(ifcfg-lo$\|:\|ifcfg-.*-range\)/d' \
                       -e '/ifcfg-[A-Za-z0-9#\._-]\+$/ { s/^ifcfg-//g;s/[0-9]/ & /}' | \
            LANG=C sort -k 1,1 -k 2n | \
            LANG=C sed 's/ //')

No debian, /etc/init.d/exim4 define LANG=C no início, bem como vários programas em /usr/bin .

    
por 04.08.2016 / 02:41