Was macht der C
Wert für LC_ALL
in Unix-ähnlichen Systemen?
Ich weiß, dass es das gleiche Gebietsschema für alle Aspekte erzwingt, aber was macht C
das?
Was macht der C
Wert für LC_ALL
in Unix-ähnlichen Systemen?
Ich weiß, dass es das gleiche Gebietsschema für alle Aspekte erzwingt, aber was macht C
das?
Antworten:
Es erzwingt, dass Anwendungen die Standardsprache für die Ausgabe verwenden:
$ LC_ALL=es_ES man
¿Qué página de manual desea?
$ LC_ALL=C man
What manual page do you want?
und zwingt die Sortierung, byteweise zu sein:
$ 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
ist die Umgebungsvariable, die alle anderen Lokalisierungseinstellungen überschreibt ( außer $LANGUAGE
unter bestimmten Umständen ).
Verschiedene Aspekte von Lokalisierungen (z. B. Tausendertrennzeichen oder Dezimalzeichen, Zeichensatz, Sortierreihenfolge, Monat, Tagesnamen, Sprach- oder Anwendungsnachrichten wie Fehlermeldungen, Währungssymbol) können mithilfe weniger Umgebungsvariablen festgelegt werden.
In der Regel legen Sie $LANG
Ihre Präferenz mit einem Wert fest, der Ihre Region kennzeichnet (z. B. fr_CH.UTF-8
wenn Sie sich in der französischsprachigen Schweiz befinden und UTF-8 verwenden). Die einzelnen LC_xxx
Variablen überschreiben einen bestimmten Aspekt. LC_ALL
überschreibt sie alle. Der locale
Befehl, wenn ohne Argument aufgerufen gibt einen Überblick über die aktuellen Einstellungen.
Zum Beispiel bekomme ich auf einem GNU-System:
$ 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=
Ich kann eine individuelle Einstellung überschreiben, zum Beispiel mit:
$ LC_TIME=fr_FR.UTF-8 date
jeudi 22 août 2013, 10:41:30 (UTC+0100)
Oder:
$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€
Oder alles mit LC_ALL überschreiben.
$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory
Wenn Sie in einem Skript eine bestimmte Einstellung erzwingen möchten, da Sie nicht wissen, welche Einstellungen der Benutzer erzwungen hat (möglicherweise auch LC_ALL), ist die beste, sicherste und allgemein einzige Option, LC_ALL zu erzwingen.
Das C
Gebietsschema ist ein spezielles Gebietsschema, das das einfachste Gebietsschema sein soll. Man könnte auch sagen, dass die anderen Ländereinstellungen für Menschen sind, die Ländereinstellung C jedoch für Computer. Im Gebietsschema C sind Zeichen Einzelbytes, der Zeichensatz ist ASCII (nun ja, dies ist nicht erforderlich, wird aber in der Praxis in den Systemen verwendet, die die meisten von uns jemals verwenden werden). Die Sortierreihenfolge basiert auf den Bytewerten. Die Sprache ist in der Regel US-Englisch (bei Anwendungsnachrichten (im Gegensatz zu Monats- oder Tagesnamen oder Nachrichten von Systembibliotheken) liegt es im Ermessen des Anwendungsautors) und Währungssymbole sind nicht definiert.
Auf einigen Systemen gibt es einen Unterschied zum POSIX-Gebietsschema, bei dem beispielsweise die Sortierreihenfolge für Nicht-ASCII-Zeichen nicht definiert ist.
Im Allgemeinen führen Sie einen Befehl mit LC_ALL = C aus, um zu vermeiden, dass die Einstellungen des Benutzers Ihr Skript beeinträchtigen. Wenn Sie beispielsweise [a-z]
die 26 ASCII-Zeichen von a
bis abgleichen möchten z
, müssen Sie festlegen LC_ALL=C
.
Auf GNU-Systemen LC_ALL=C
und LC_ALL=POSIX
(oder LC_MESSAGES=C|POSIX
) außer Kraft setzen $LANGUAGE
, während LC_ALL=anything-else
nicht.
Einige Fälle, in denen Sie normalerweise festlegen müssen LC_ALL=C
:
sort -u
oder sort ... | uniq...
. In vielen anderen Gebietsschemas als C haben auf einigen Systemen (insbesondere GNU-Systemen) einige Zeichen dieselbe Sortierreihenfolge . sort -u
meldet keine eindeutigen Zeilen, sondern eine aus jeder Gruppe von Zeilen mit gleicher Sortierreihenfolge. Wenn Sie also eindeutige Zeilen wünschen, benötigen Sie ein Gebietsschema, bei dem die Zeichen Byte sind und alle Zeichen eine unterschiedliche Sortierreihenfolge haben (was das C
Gebietsschema garantiert).=
Betreiber von POSIX-konformen expr
oder den ==
Betreiber von POSIX-konformen awk
( mawk
und gawk
diesbezüglich nicht POSIX-konformen ) Zeichenketten, die nicht prüfen, ob zwei Zeichenketten identisch sind, sondern ob sie gleich sortieren.grep
. Wenn Sie einen Buchstaben in der Sprache des Benutzers suchen möchten, verwenden Sie grep '[[:alpha:]]'
und ändern Sie ihn nicht LC_ALL
. Wenn Sie jedoch die a-zA-Z
ASCII-Zeichen abgleichen möchten , benötigen Sie entweder LC_ALL=C grep '[[:alpha:]]'
oder LC_ALL=C grep '[a-zA-Z]'
¹. [a-z]
stimmt mit den Zeichen überein, die nach a
und vor sortiert werden z
(obwohl es bei vielen APIs komplizierter ist). In anderen Regionen wissen Sie im Allgemeinen nicht, was das ist. Beispielsweise ignorieren einige Gebietsschemas die Groß- und Kleinschreibung für die Sortierung, so dass [a-z]
in einigen APIs wie bash
Mustern [B-Z]
oder enthalten sein können [A-Y]
. In vielen UTF-8-Sprachumgebungen (einschließlich der en_US.UTF-8
meisten Systeme) [a-z]
werden die lateinischen Buchstaben von a
bis y
mit diakritischen Zeichen eingeschlossen, nicht jedoch die von z
(seit)z
Ich kann mir nicht vorstellen, was Sie wollen (warum sollten Sie einbeziehen é
und nicht ź
?).Gleitkomma-Arithmetik in ksh93
. ksh93
ehrt die decimal_point
Einstellung in LC_NUMERIC
. Wenn Sie ein Skript schreiben, das Folgendes enthält a=$((1.2/7))
, funktioniert es nicht mehr, wenn es von einem Benutzer ausgeführt wird, dessen Gebietsschema Komma als Dezimaltrennzeichen hat:
$ 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
Dann brauchen Sie Dinge wie:
#! /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
Als Randnotiz: Das ,
Dezimaltrennzeichen steht in Konflikt mit dem ,
arithmetischen Operator, was noch mehr Verwirrung stiften kann.
grep '<.*>'
nach Zeilen suchen, die ein enthalten <
, >
funktioniert pair nicht, wenn Sie sich in einem UTF-8-Gebietsschema befinden und die Eingabe in einem Einzelbyte-8-Bit-Zeichensatz wie iso8859-15 codiert ist. .
Dies liegt daran, dass nur Übereinstimmungen und Nicht-ASCII-Zeichen in ISO8859-15 wahrscheinlich kein gültiges Zeichen in UTF-8 bilden. Funktioniert jedoch, LC_ALL=C grep '<.*>'
da jeder Byte-Wert im C
Gebietsschema ein gültiges Zeichen bildet .Jedes Mal, wenn Sie Eingabedaten oder Ausgabedaten verarbeiten, die nicht für einen Menschen bestimmt sind. Wenn Sie mit einem Benutzer sprechen, möchten Sie möglicherweise dessen Konvention und Sprache verwenden. Wenn Sie jedoch beispielsweise Zahlen generieren, um eine andere Anwendung zu unterstützen, die englische Dezimalstellen oder englische Monatsnamen erwartet, möchten Sie dies setze 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
Das gilt auch für Dinge wie case insensitive compare (wie in grep -i
) und case conversion ( awk
's toupper()
, dd conv=ucase
...). Zum Beispiel:
grep -i i
Es wird nicht garantiert, dass die Übereinstimmung I
im Gebietsschema des Benutzers vorliegt. In einigen türkischen Gegenden zum Beispiel tut es nicht als Großbuchstabe i
ist İ
( man beachte den Punkt) gibt und Klein I
ist ı
( man beachte den fehlenden Punkt).
¹ Abhängig von der Kodierung des Textes ist dies jedoch nicht unbedingt das Richtige. Dies gilt für UTF-8- oder Einzelbyte-Zeichensätze (wie iso-8859-1), jedoch nicht unbedingt für Nicht-UTF-8-Multibyte-Zeichensätze.
Wenn Sie sich beispielsweise in einem zh_HK.big5hkscs
Gebietsschema befinden (Hongkong mit der Hongkong-Variante der chinesischen BIG5-Zeichencodierung) und in einer in diesen Zeichensätzen codierten Datei nach englischen Buchstaben suchen möchten, gehen Sie folgendermaßen vor:
LC_ALL=C grep '[[:alpha:]]'
oder
LC_ALL=C grep '[a-zA-Z]'
wäre falsch, da in diesem Zeichensatz (und vielen anderen, die seit dem Erscheinen von UTF-8 kaum mehr verwendet wurden) viele Zeichen Bytes enthalten , die der ASCII-Codierung von A-Za-Z-Zeichen entsprechen. Beispielsweise enthalten alle A䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽
(und viele weitere) die Codierung von A
. 䨝
ist 0x96 0x41 und A
ist 0x41 wie in ASCII. Also LC_ALL=C grep '[a-zA-Z]'
würden wir in den Zeilen, die diese Zeichen enthalten, übereinstimmen, da dies die Folgen von Bytes falsch interpretieren würde.
LC_COLLATE=C grep '[A-Za-z]'
würde funktionieren, aber nur wenn LC_ALL
nichts anderes eingestellt ist (was übersteuern würde LC_COLLATE
). Sie müssen also möglicherweise Folgendes tun:
grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'
Wenn Sie nach englischen Buchstaben in einer Datei suchen möchten, die in der Codierung des Gebietsschemas codiert ist.
C
Gebietsschema wird nur benötigt, um den "portablen Zeichensatz" (ASCII 0-127) zu unterstützen, und das Verhalten für Zeichen> 127 ist technisch nicht spezifiziert . In der Praxis behandeln die meisten Programme sie als undurchsichtige Daten und leiten sie wie beschrieben weiter. Aber nicht alle: Insbesondere kann Ruby char-Daten mit Bytes> 127 verschlucken, wenn es in der C
Ländereinstellung ausgeführt wird. Ich weiß ehrlich gesagt nicht, ob das technisch "konform" ist, aber wir haben es in der Natur gesehen .
perl
's \x{7FFFFFFFFFFFFFFF}
), und während der Bereich der Unicode-Codepunkte willkürlich auf U + 10FFFF beschränkt wurde (Aufgrund der UTF-16-Designbeschränkung) erkennen / produzieren einige Tools immer noch 6-Byte-Zeichen. Das habe ich mit 6-Byte-Zeichen gemeint. In der Unix-Semantik ist ein Zeichen ein Codepunkt. Ihre mehr als einen Codepunkt "Zeichen" werden allgemeiner als Graphem-Cluster bezeichnet, um sie von Zeichen zu unterscheiden.
C
ist das Standardgebietsschema, "POSIX" ist der Alias von "C". Ich denke, "C" ist von ANSI-C abgeleitet. Möglicherweise definiert ANSI-C das Gebietsschema "POSIX".
C
Name des Gebietsschemas von "ANSI C" abgeleitet ist.
Soweit ich das beurteilen kann, verwendet OS X die Codepunkt-Sortierreihenfolge in UTF-8-Gebietsschemata, so dass dies eine Ausnahme zu einigen der in der Antwort von Stéphane Chazelas genannten Punkten darstellt.
Dies druckt 26 in OS X und 310 in Ubuntu:
export LC_ALL=en_US.UTF-8
printf %b $(printf '\\U%08x\\n' $(seq $((0x11)) $((0x10ffff))))|grep -a '[a-z]'|wc -l
Der folgende Code gibt in OS X nichts aus, was darauf hinweist, dass die Eingabe sortiert ist. Die sechs entfernten Ersatzzeichen verursachen einen unzulässigen Bytefolgenfehler.
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
Der folgende Code gibt in OS X nichts aus, was darauf hinweist, dass es keine zwei aufeinander folgenden Codepunkte (mindestens zwischen U + 000B und U + D7FF) mit derselben Sortierreihenfolge gibt.
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
(Die obigen Beispiele werden verwendet, %b
da dies printf \\U25
zu einem Fehler in zsh führt.)
Einige Zeichen und Zeichenfolgen, die in GNU-Systemen dieselbe Sortierreihenfolge haben, haben in OS X nicht dieselbe Sortierreihenfolge. Dies druckt ① zuerst in OS X (unter Verwendung von OS X sort
oder GNU sort
), aber but zuerst in Ubuntu:
export LC_ALL=en_US.UTF-8;printf %s\\n ② ①|sort
Dies druckt drei Zeilen in OS X (entweder mit OS X sort
oder GNU sort
), aber eine Zeile in Ubuntu:
export LC_ALL=en_US.UTF-8;printf %b\\n \\u0d4c \\u0d57 \\u0d46\\u0d57|sort -u
Es scheint, dass es LC_COLLATE
die "alphabetische Reihenfolge" steuert, die auch von ls verwendet wird. Das US-Gebietsschema wird wie folgt sortiert:
a.C
aFilename.C
aFilename.H
a.H
im Grunde ignorieren die Perioden. Vielleicht bevorzugen Sie:
a.C
a.H
aFilename.C
aFilename.H
Das tue ich sicher. Einstellen LC_COLLATE
, C
um dies zu erreichen. Beachten Sie, dass auch Kleinbuchstaben nach allen Großbuchstaben sortiert werden:
A.C
A.H
AFilename.C
a.C
a.H
xclock
warning (Missing charsets in String to FontSet conversion
) lösen möchten , ist es besserLC_ALL=C.UTF-8
, Probleme mit kyrillischer Sprache zu vermeiden. Um diese Umgebungsvariable festzulegen, müssen Sie die folgende Zeile am Ende der~/.bashrc
Datei hinzufügen -export LC_ALL=C.UTF-8