Qual é o C
valor para LC_ALL
sistemas Unix?
Eu sei que ele força o mesmo local para todos os aspectos, mas o que C
faz?
Qual é o C
valor para LC_ALL
sistemas Unix?
Eu sei que ele força o mesmo local para todos os aspectos, mas o que C
faz?
Respostas:
Força os aplicativos a usar o idioma padrão para saída:
$ LC_ALL=es_ES man
¿Qué página de manual desea?
$ LC_ALL=C man
What manual page do you want?
e força a classificação a bytes:
$ LC_ALL=en_US sort <<< $'a\nb\nA\nB'
a
A
b
B
$ LC_ALL=C sort <<< $'a\nb\nA\nB'
A
B
a
b
LC_ALL
é a variável de ambiente que substitui todas as outras configurações de localização ( exceto $LANGUAGE
em algumas circunstâncias ).
Diferentes aspectos das localizações (como o separador de mil caracteres ou o ponto decimal, o conjunto de caracteres, a ordem de classificação, o mês, os nomes dos dias, o idioma ou as mensagens do aplicativo, como mensagens de erro, símbolo da moeda) podem ser definidos usando algumas variáveis de ambiente.
Você normalmente definirá $LANG
sua preferência com um valor que identifique sua região (como fr_CH.UTF-8
se você estiver na Suíça de língua francesa, usando UTF-8). As LC_xxx
variáveis individuais substituem um determinado aspecto. LC_ALL
substitui todos eles. O locale
comando, quando chamado sem argumento, fornece um resumo das configurações atuais.
Por exemplo, em um sistema GNU, recebo:
$ locale
LANG=en_GB.UTF-8
LANGUAGE=
LC_CTYPE="en_GB.UTF-8"
LC_NUMERIC="en_GB.UTF-8"
LC_TIME="en_GB.UTF-8"
LC_COLLATE="en_GB.UTF-8"
LC_MONETARY="en_GB.UTF-8"
LC_MESSAGES="en_GB.UTF-8"
LC_PAPER="en_GB.UTF-8"
LC_NAME="en_GB.UTF-8"
LC_ADDRESS="en_GB.UTF-8"
LC_TELEPHONE="en_GB.UTF-8"
LC_MEASUREMENT="en_GB.UTF-8"
LC_IDENTIFICATION="en_GB.UTF-8"
LC_ALL=
Posso substituir uma configuração individual por, por exemplo:
$ LC_TIME=fr_FR.UTF-8 date
jeudi 22 août 2013, 10:41:30 (UTC+0100)
Ou:
$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€
Ou substitua tudo por LC_ALL.
$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory
Em um script, se você deseja forçar uma configuração específica, como não sabe quais configurações o usuário forçou (possivelmente LC_ALL também), sua melhor opção, mais segura e geralmente única é forçar LC_ALL.
O C
código de idioma é um código de idioma especial que deve ser o código de idioma mais simples. Você também pode dizer que, enquanto os outros locais são para humanos, o local C é para computadores. No código C, os caracteres são bytes únicos, o conjunto de caracteres é ASCII (bem, não é necessário, mas na prática estará nos sistemas que a maioria de nós utilizará), a ordem de classificação é baseada nos valores de bytes, o idioma geralmente é inglês dos EUA (embora para mensagens do aplicativo (em oposição a itens como nomes de mês ou dia ou mensagens das bibliotecas do sistema), fique a critério do autor do aplicativo) e itens como símbolos de moeda não estejam definidos.
Em alguns sistemas, há uma diferença com o código do idioma POSIX em que, por exemplo, a ordem de classificação para caracteres não ASCII não está definida.
Você geralmente executa um comando com LC_ALL = C para evitar que as configurações do usuário interfiram no seu script. Por exemplo, se você deseja [a-z]
combinar os 26 caracteres ASCII de a
para z
, você deve definir LC_ALL=C
.
Nos sistemas GNU, LC_ALL=C
e LC_ALL=POSIX
(ou LC_MESSAGES=C|POSIX
) substituem $LANGUAGE
, enquanto LC_ALL=anything-else
não.
Alguns casos em que você normalmente precisa definir LC_ALL=C
:
sort -u
ou sort ... | uniq...
. Em muitos locais diferentes de C, em alguns sistemas (principalmente os GNU), alguns caracteres têm a mesma ordem de classificação . sort -u
não relata linhas exclusivas, mas uma de cada grupo de linhas que têm a mesma ordem de classificação. Portanto, se você quiser linhas exclusivas, precisará de um código de idioma em que os caracteres sejam byte e todos os caracteres terão uma ordem de classificação diferente (que o C
código de idioma garante).=
operador compatível com POSIX expr
ou ao ==
operador compatível com POSIX awk
( mawk
e gawk
não é POSIX a esse respeito), que não verifica se duas cadeias são idênticas, mas se elas são iguais.grep
. Se você deseja corresponder uma letra no idioma do usuário, use grep '[[:alpha:]]'
e não modifique LC_ALL
. Mas se você quiser combinar os a-zA-Z
caracteres ASCII, precisará de um LC_ALL=C grep '[[:alpha:]]'
ou de LC_ALL=C grep '[a-zA-Z]'
¹. [a-z]
corresponde aos caracteres que ordenam a
antes e depois z
(embora com muitas APIs seja mais complicado que isso). Em outros locais, você geralmente não sabe o que são. Por exemplo, alguns códigos de idioma ignoram os casos de classificação, portanto, [a-z]
em algumas APIs, como bash
padrões, podem incluir [B-Z]
or [A-Y]
. Em muitos locais UTF-8 (incluindo en_US.UTF-8
na maioria dos sistemas), [a-z]
incluirá as letras latinas de a
para y
com diacríticos, mas não as de z
(desdez
tipos antes deles) que eu não consigo imaginar seria o que você quer (por que você gostaria de incluir é
e não ź
?).ponto aritmético de ponto flutuante ksh93
. ksh93
homenageia o decimal_point
cenário LC_NUMERIC
. Se você escrever um script que contenha a=$((1.2/7))
, ele deixará de funcionar quando executado por um usuário cuja localidade possui vírgula como separador decimal:
$ ksh93 -c 'echo $((1.1/2))'
0.55
$ LANG=fr_FR.UTF-8 ksh93 -c 'echo $((1.1/2))'
ksh93: 1.1/2: arithmetic syntax error
Então você precisa de coisas como:
#! /bin/ksh93 -
float input="$1" # get it as input from the user in his locale
float output
arith() { typeset LC_ALL=C; (($@)); }
arith output=input/1.2 # use the dot here as it will be interpreted
# under LC_ALL=C
echo "$output" # output in the user's locale
Como observação lateral: o ,
separador decimal entra em conflito com o ,
operador aritmético, o que pode causar ainda mais confusão.
grep '<.*>'
procurar linhas contendo a <
, >
pair não funcionará se você estiver em um código de idioma UTF-8 e a entrada estiver codificada em um conjunto de caracteres de 8 bits de byte único como iso8859-15. Isso .
ocorre porque apenas os caracteres correspondentes e caracteres não ASCII em iso8859-15 provavelmente não formarão um caractere válido no UTF-8. Por outro lado, LC_ALL=C grep '<.*>'
funcionará porque qualquer valor de byte forma um caractere válido no C
código do idioma.A qualquer momento em que você processa dados de entrada ou dados de saída que não são destinados a / para humanos. Se estiver conversando com um usuário, convém usar a convenção e o idioma, mas, por exemplo, se você gerar alguns números para alimentar outro aplicativo que espera pontos decimais no estilo inglês ou nomes de meses em inglês, convém defina LC_ALL = C:
$ printf '%g\n' 1e-2
0,01
$ LC_ALL=C printf '%g\n' 1e-2
0.01
$ date +%b
août
$ LC_ALL=C date +%b
Aug
Isso também se aplica a coisas como comparação sem distinção entre maiúsculas e minúsculas (como em grep -i
) e conversão de maiúsculas ( awk
's toupper()
, dd conv=ucase
...). Por exemplo:
grep -i i
não é garantido que ele corresponda na I
localidade do usuário. Em algumas localidades turcas por exemplo, não faz como maiúsculas i
é İ
(note o ponto) lá e minúsculas I
é ı
(observe o ponto em falta).
¹ Dependendo da codificação do texto, isso não é necessariamente a coisa certa a se fazer. Isso é válido para conjuntos de caracteres UTF-8 ou de byte único (como iso-8859-1), mas não necessariamente conjuntos de caracteres multibyte que não sejam UTF-8.
Por exemplo, se você estiver em uma zh_HK.big5hkscs
localidade (Hong Kong, usando a variante Hong Kong da codificação de caracteres chineses BIG5) e desejar procurar letras em inglês em um arquivo codificado nesses conjuntos de caracteres, faça o seguinte:
LC_ALL=C grep '[[:alpha:]]'
ou
LC_ALL=C grep '[a-zA-Z]'
estaria errado, porque nesse conjunto de caracteres (e muitos outros, mas pouco usado desde que o UTF-8 foi lançado), muitos caracteres contêm bytes que correspondem à codificação ASCII dos caracteres A-Za-z. Por exemplo, todos A䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽
(e muitos mais) contêm a codificação de A
. 䨝
é 0x96 0x41 e A
é 0x41 como em ASCII. Portanto, o nosso LC_ALL=C grep '[a-zA-Z]'
corresponderia às linhas que contêm esses caracteres, pois interpretaria mal essas seqüências de bytes.
LC_COLLATE=C grep '[A-Za-z]'
funcionaria, mas somente se LC_ALL
não estiver definido de outra forma (o que substituiria LC_COLLATE
). Então você pode ter que fazer:
grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'
se você quiser procurar letras em inglês em um arquivo codificado na codificação da localidade.
C
localidade é necessária apenas para suportar o "conjunto de caracteres portátil" (ASCII 0-127), e o comportamento para caracteres> 127 é tecnicamente não especificado . Na prática, a maioria dos programas os trata como dados opacos e os repassa como você descreveu. Mas não todos: em particular, Ruby pode engasgar com dados de caracteres com bytes> 127 se estiver executando no C
local. Sinceramente, não sei se isso é tecnicamente "compatível", mas já vimos isso na natureza .
perl
's \x{7FFFFFFFFFFFFFFF}
) e enquanto o intervalo de pontos de código Unicode foi arbitrariamente restrito a U + 10FFFF (devido à limitação de design UTF-16), algumas ferramentas ainda reconhecem / produzem caracteres de 6 bytes. Isso é o que eu quis dizer com caracteres de 6 bytes. Na semântica do Unix, um caractere é um ponto de código. Seus mais de um "código" de ponto de código são geralmente referenciados como clusters de graphem para desambiguar os caracteres.
C
é o código de idioma padrão, "POSIX" é o alias de "C". Eu acho que "C" é derivado de ANSI-C. Talvez o ANSI-C defina o código do idioma "POSIX".
C
nome da localidade derive de "ANSI C".
Até onde eu sei, o OS X usa a ordem de intercalação de pontos de código nos códigos de idioma UTF-8, portanto é uma exceção a alguns dos pontos mencionados na resposta de Stéphane Chazelas.
Isso imprime 26 no OS X e 310 no Ubuntu:
export LC_ALL=en_US.UTF-8
printf %b $(printf '\\U%08x\\n' $(seq $((0x11)) $((0x10ffff))))|grep -a '[a-z]'|wc -l
O código abaixo não imprime nada no OS X, indicando que a entrada está classificada. Os seis caracteres substitutos removidos causam um erro ilegal na sequência de bytes.
export LC_ALL=en_US.UTF-8
for ((i=1;i<=0x1fffff;i++));do
x=$(printf %04x $i)
[[ $x = @(000a|d800|db7f|db80|dbff|dc00|dfff) ]]&&continue
printf %b \\U$x\\n
done|sort -c
O código abaixo não imprime nada no OS X, indicando que não há dois pontos de código consecutivos (pelo menos entre U + 000B e U + D7FF) que tenham a mesma ordem de intercalação.
export LC_ALL=en_US.UTF-8
for ((i=0xb;i<=0xd7fe;i++));do
printf %b $(printf '\\U%08x\\n' $((i+1)) $i)|sort -c 2>/dev/null&&echo $i
done
(Os exemplos acima são usados %b
porque printf \\U25
resultam em um erro no zsh.)
Alguns caracteres e sequências de caracteres que têm a mesma ordem de intercalação nos sistemas GNU não têm a mesma ordem de intercalação no OS X. Isso imprime ① primeiro no OS X (usando o OS X sort
ou GNU sort
), mas Ubuntu primeiro no Ubuntu:
export LC_ALL=en_US.UTF-8;printf %s\\n ② ①|sort
Isso imprime três linhas no OS X (usando o OS X sort
ou o GNU sort
), mas uma linha no Ubuntu:
export LC_ALL=en_US.UTF-8;printf %b\\n \\u0d4c \\u0d57 \\u0d46\\u0d57|sort -u
Parece que LC_COLLATE
controla a "ordem alfabética" usada por ls também. A localidade dos EUA classificará da seguinte maneira:
a.C
aFilename.C
aFilename.H
a.H
basicamente ignorando os períodos. Você pode preferir:
a.C
a.H
aFilename.C
aFilename.H
Eu certamente faço. Configuração LC_COLLATE
para C
realizar isso. Observe que ele também classificará minúsculas depois de todas as maiúsculas:
A.C
A.H
AFilename.C
a.C
a.H
xclock
aviso (Missing charsets in String to FontSet conversion
), será melhor usar issoLC_ALL=C.UTF-8
para evitar problemas com o cirílico. Para definir essa variável de ambiente, você deve adicionar a seguinte linha ao final do~/.bashrc
arquivo -export LC_ALL=C.UTF-8