¿Para qué sirve el C
valor LC_ALL
en sistemas tipo Unix?
Sé que obliga a la misma configuración regional para todos los aspectos, pero ¿qué hace C
?
¿Para qué sirve el C
valor LC_ALL
en sistemas tipo Unix?
Sé que obliga a la misma configuración regional para todos los aspectos, pero ¿qué hace C
?
Respuestas:
Obliga a las aplicaciones a usar el idioma predeterminado para la salida:
$ LC_ALL=es_ES man
¿Qué página de manual desea?
$ LC_ALL=C man
What manual page do you want?
y obliga a la clasificación a ser byte-sabio:
$ 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
es la variable de entorno que anula todas las demás configuraciones de localización ( excepto $LANGUAGE
en algunas circunstancias ).
Los diferentes aspectos de las localizaciones (como el separador de miles o el carácter de punto decimal, el conjunto de caracteres, el orden de clasificación, los nombres de mes, día, idioma o mensajes de aplicación como mensajes de error, símbolo de moneda) se pueden configurar utilizando algunas variables de entorno.
Por lo general, establecerá $LANG
su preferencia con un valor que identifica su región (como fr_CH.UTF-8
si se encuentra en Suiza francófona, utilizando UTF-8). Las LC_xxx
variables individuales anulan un cierto aspecto. LC_ALL
los anula a todos. El locale
comando, cuando se llama sin argumento, ofrece un resumen de la configuración actual.
Por ejemplo, en un sistema GNU, obtengo:
$ 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=
Puedo anular una configuración individual con, por ejemplo:
$ LC_TIME=fr_FR.UTF-8 date
jeudi 22 août 2013, 10:41:30 (UTC+0100)
O:
$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€
O anule todo con LC_ALL.
$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory
En un script, si desea forzar una configuración específica, ya que no sabe qué configuraciones ha forzado el usuario (posiblemente LC_ALL también), su mejor opción, la más segura y, en general, única es forzar LC_ALL.
La C
configuración regional es una configuración especial que debe ser la configuración regional más simple. También podría decir que si bien las otras configuraciones regionales son para humanos, la configuración regional C es para computadoras. En la configuración regional C, los caracteres son bytes individuales, el conjunto de caracteres es ASCII (bueno, no es obligatorio, pero en la práctica estará en los sistemas que la mayoría de nosotros usará), el orden de clasificación se basa en los valores de bytes, el idioma suele ser el inglés de EE. UU. (aunque para los mensajes de la aplicación (a diferencia de los nombres de mes o día o los mensajes de las bibliotecas del sistema), queda a discreción del autor de la aplicación) y los elementos como los símbolos de moneda no están definidos.
En algunos sistemas, hay una diferencia con la configuración regional POSIX donde, por ejemplo, el orden de clasificación para caracteres no ASCII no está definido.
Generalmente ejecuta un comando con LC_ALL = C para evitar que la configuración del usuario interfiera con su script. Por ejemplo, si desea [a-z]
hacer coincidir los 26 caracteres ASCII de a
a z
, debe configurar LC_ALL=C
.
En sistemas GNU, LC_ALL=C
y LC_ALL=POSIX
(o LC_MESSAGES=C|POSIX
) anular $LANGUAGE
, mientras LC_ALL=anything-else
que no lo haría.
Algunos casos en los que normalmente necesita configurar LC_ALL=C
:
sort -u
o sort ... | uniq...
. En muchos entornos locales distintos de C, en algunos sistemas (especialmente los GNU), algunos caracteres tienen el mismo orden de clasificación . sort -u
no informa líneas únicas, sino una de cada grupo de líneas que tienen el mismo orden de clasificación. Entonces, si desea líneas únicas, necesita una configuración regional donde los caracteres son byte y todos los caracteres tienen un orden de clasificación diferente (lo que C
garantiza la configuración regional).=
operador de POSIX compatible expr
u ==
operador de POSIX compatible awk
s ( mawk
y gawk
no son POSIX en ese sentido), que no comprueban si dos cadenas son idénticas sino si clasifican lo mismo.grep
. Si quiere hacer coincidir una letra en el idioma del usuario, use grep '[[:alpha:]]'
y no modifique LC_ALL
. Pero si desea hacer coincidir los a-zA-Z
caracteres ASCII, necesita LC_ALL=C grep '[[:alpha:]]'
o LC_ALL=C grep '[a-zA-Z]'
¹. [a-z]
coincide con los caracteres que se ordenan después a
y antes z
(aunque con muchas API es más complicado que eso). En otros lugares, generalmente no sabes cuáles son. Por ejemplo algunos locales ignoran caso para clasificar de manera [a-z]
en algunas APIs como bash
patrones, podría incluir [B-Z]
o [A-Y]
. En muchos entornos locales UTF-8 (incluso en_US.UTF-8
en la mayoría de los sistemas), [a-z]
se incluirán las letras latinas de a
a y
con diacríticos pero no los de z
(ya quez
tipo antes que ellos) que no puedo imaginar que sea lo que quieres (¿por qué querrías incluirlo é
y no ź
?).aritmética de coma flotante en ksh93
. ksh93
honra la decimal_point
puesta en escena LC_NUMERIC
. Si escribe un script que contiene a=$((1.2/7))
, dejará de funcionar cuando lo ejecute un usuario cuya configuración regional tenga una coma 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
Entonces necesitas cosas 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 nota al margen: el ,
separador decimal entra en conflicto con el ,
operador aritmético, lo que puede causar aún más confusión.
grep '<.*>'
para buscar líneas que contengan un <
, el >
par no funcionará si está en un entorno local UTF-8 y la entrada está codificada en un conjunto de caracteres de 8 bits de un solo byte como iso8859-15. Esto se debe a que .
solo los caracteres coincidentes y los caracteres no ASCII en iso8859-15 probablemente no formen un carácter válido en UTF-8. Por otro lado, LC_ALL=C grep '<.*>'
funcionará porque cualquier valor de byte forma un carácter válido en la C
configuración regional.Cualquier momento en el que procese datos de entrada o datos de salida que no estén destinados a / para un humano. Si está hablando con un usuario, es posible que desee usar su convención e idioma, pero, por ejemplo, si genera algunos números para alimentar alguna otra aplicación que espere puntos decimales en inglés o nombres de meses en inglés, querrá establecer 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
Eso también se aplica a cosas como la comparación entre mayúsculas y minúsculas (como en grep -i
) y la conversión de mayúsculas y minúsculas ( awk
's toupper()
, dd conv=ucase
...). Por ejemplo:
grep -i i
no se garantiza que coincida I
en la configuración regional del usuario. En algunas configuraciones regionales turcas, por ejemplo, no lo hace, ya que las mayúsculas i
están İ
(tenga en cuenta el punto) y las minúsculas I
están ı
(tenga en cuenta el punto que falta).
¹ Dependiendo de la codificación del texto, eso no es necesariamente lo correcto. Eso es válido para UTF-8 o juegos de caracteres de un solo byte (como iso-8859-1), pero no necesariamente para juegos de caracteres multibyte que no sean UTF-8.
Por ejemplo, si está en un zh_HK.big5hkscs
entorno local (Hong Kong, utilizando la variante de Hong Kong de la codificación de caracteres chinos BIG5), y desea buscar letras en inglés en un archivo codificado en esos conjuntos de caracteres, haciendo lo siguiente:
LC_ALL=C grep '[[:alpha:]]'
o
LC_ALL=C grep '[a-zA-Z]'
estaría mal, porque en ese juego de caracteres (y muchos otros, pero apenas utilizado desde que salió UTF-8), muchos caracteres contienen bytes que corresponden a la codificación ASCII de caracteres A-Za-z. Por ejemplo, todos A䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽
(y muchos más) contienen la codificación de A
. 䨝
es 0x96 0x41, y A
es 0x41 como en ASCII. Entonces nuestro LC_ALL=C grep '[a-zA-Z]'
coincidiría en esas líneas que contienen esos caracteres, ya que malinterpretaría esas secuencias de bytes.
LC_COLLATE=C grep '[A-Za-z]'
funcionaría, pero solo si LC_ALL
no se establece de otra manera (lo que anularía LC_COLLATE
). Entonces puede terminar teniendo que hacer:
grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'
si desea buscar letras en inglés en un archivo codificado en la codificación de la configuración regional.
C
configuración regional solo es necesaria para admitir el "juego de caracteres portátil" (ASCII 0-127), y el comportamiento de los caracteres> 127 no está técnicamente especificado . En la práctica, la mayoría de los programas los tratarán como datos opacos y los pasarán como usted describió. Pero no todos: en particular, Ruby puede ahogarse en los datos de caracteres con bytes> 127 si se ejecuta en la C
configuración regional. Sinceramente, no sé si eso es técnicamente "conforme", pero lo hemos visto en la naturaleza .
perl
's \x{7FFFFFFFFFFFFFFF}
) y aunque el rango de puntos de código Unicode se ha restringido arbitrariamente a U + 10FFFF (debido a la limitación de diseño UTF-16), algunas herramientas aún reconocen / producen caracteres de 6 bytes. Eso es lo que quise decir con caracteres de 6 bytes. En la semántica de Unix, un carácter es un punto de código. Sus más de un "carácter" de punto de código se mencionan más generalmente como grupos de gráficos para desambiguarse de los caracteres.
C
es la configuración regional predeterminada, "POSIX" es el alias de "C". Supongo que "C" se deriva de ANSI-C. Quizás ANSI-C defina la configuración regional "POSIX".
C
nombre de la localidad se derive de "ANSI C".
Por lo que puedo decir, OS X usa el orden de clasificación de puntos de código en las configuraciones regionales UTF-8, por lo que es una excepción a algunos de los puntos mencionados en la respuesta de Stéphane Chazelas.
Esto imprime 26 en OS X y 310 en Ubuntu:
export LC_ALL=en_US.UTF-8
printf %b $(printf '\\U%08x\\n' $(seq $((0x11)) $((0x10ffff))))|grep -a '[a-z]'|wc -l
El siguiente código no imprime nada en OS X, lo que indica que la entrada está ordenada. Los seis caracteres sustitutos que se eliminan provocan un error de secuencia de bytes ilegal.
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
El siguiente código no imprime nada en OS X, lo que indica que no hay dos puntos de código consecutivos (al menos entre U + 000B y U + D7FF) que tengan el mismo orden de clasificación.
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
(Los ejemplos anteriores se usan %b
porque printf \\U25
resultan en un error en zsh).
Algunos caracteres y secuencias de caracteres que tienen el mismo orden de clasificación en los sistemas GNU no tienen el mismo orden de clasificación en OS X. Esto imprime ① primero en OS X (usando OS X sort
o GNU sort
) pero ② primero en Ubuntu:
export LC_ALL=en_US.UTF-8;printf %s\\n ② ①|sort
Esto imprime tres líneas en OS X (usando OS X sort
o GNU sort
) pero una línea en Ubuntu:
export LC_ALL=en_US.UTF-8;printf %b\\n \\u0d4c \\u0d57 \\u0d46\\u0d57|sort -u
Parece que también LC_COLLATE
controla el "orden alfabético" utilizado por ls. La configuración regional de EE. UU. Se ordenará de la siguiente manera:
a.C
aFilename.C
aFilename.H
a.H
básicamente ignorando los períodos. Quizás prefieras:
a.C
a.H
aFilename.C
aFilename.H
Ciertamente lo hago. Establecer LC_COLLATE
para C
lograr esto. Tenga en cuenta que también ordenará minúsculas después de todas las mayúsculas:
A.C
A.H
AFilename.C
a.C
a.H
xclock
advertencia (Missing charsets in String to FontSet conversion
), será mejor si lo utilizaLC_ALL=C.UTF-8
para evitar problemas con cirílico. Para establecer esta variable de entorno, debe agregar la siguiente línea al final del~/.bashrc
archivo -export LC_ALL=C.UTF-8