“LC_ALL = C” ne yapar?


324

Unix benzeri sistemlerde bunun Cdeğeri nedir LC_ALL?

Tüm yönler için aynı yerel ayarı zorladığını biliyorum ama ne yapar C?


xclockUyarı ( Missing charsets in String to FontSet conversion) ile ilgili bir sorunu çözmek istiyorsanız LC_ALL=C.UTF-8, kiril ile ilgili sorunları önlemek için kullanacaksanız daha iyi olacaktır . Bu ortam değişkenini ayarlamak için ~/.bashrcdosyanın sonuna şu satırı eklemelisiniz -export LC_ALL=C.UTF-8
fedotsoldier

fededoldier muhtemelen soru sormalı ve cevabı kendin vermelisin, bunun soru ile ilgili olduğunu sanmıyorum. Sadece sahip olduğunuz farklı soruna cevap.
jcubic

Evet, haklısın, tamam
fedotsoldier

Yanıtlar:


209

Uygulamaları çıktı için varsayılan dili kullanmaya zorlar:

$ LC_ALL=es_ES man
¿Qué página de manual desea?

$ LC_ALL=C man
What manual page do you want?

ve byte bilge olmak için sıralama kuvvetleri:

$ 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

20
İyi örnekler için +1, ancak Stephane'in cevabında önemli bilgiler bulunmuyor ...
Olivier Dulac

4
Varsayılan dil ile ne demek istiyorsunuz ?
Stéphane Chazelas 10:14

2
Evet, yazarın kalayda söylediklerini yapmamak da dahil olmak üzere istediğini yapabileceğini biliyorum. Şey. ABD İngilizcesi, LC_ALL = C'deki karakter kümesi ile doğru şekilde temsil edilebilen tek dildir, LC_ALL = C (LC_COLLATE) içindeki sıralama düzeninin anlamlı olduğu tek dildir, LC_ALL = C (LC_TIME), İngilizce ay ve gün adlarına sahiptir. LC_ALL = C'nin LC_ALL = en LANGUAGE = en dilden farklı bir dilde mesaj gönderdiği uygulamaları görmedim. Öyleyse durum böyle değilse bir programa karşı bir hata bildirme hakkım var mı? (burada İngilizce'ye çevrilmemiş uygulamalar hakkında konuşmamak).
Stéphane Chazelas 10:14

2
Sorun "ABD İngilizcesi, LC_ALL = C'deki karakter kümesiyle doğru şekilde temsil edilebilecek tek dildir". Bu genellikle dar karakterler kullanırken C / C ++ programlarında geçerlidir, ancak o zaman bile istisnalar vardır (çünkü yalnızca ASCII'de bulunan karakterleri ve simgeleri kullanan birkaç dil vardır). Varsayılan dil İngilizce değilken bir hatayı bildirmek sizi görünmez yapacaktır.
Ignacio Vazquez-Abrams,

3
İngilizce dilinde (LANG = en_US.utf8 anlamına gelir) mesajların, tırnak işaretleri için “” gibi unicode karakterler kullanabileceğini (ve olması gerektiğini) unutmayın. LANG = C iken, sadece ASCII olanlar (çift tırnak, geri tırnak ve kesme işaretleri) vardır.
Ángel,

332

LC_ALLdiğer yerelleştirme ayarlarını geçersiz kılan ortam değişkenidir ( bazı durumlar hariç$LANGUAGE ).

Yerelleştirmelerin farklı yönleri (bin ayırıcı veya ondalık nokta karakteri, karakter kümesi, sıralama düzeni, ay, gün adları, dil veya hata mesajları, para birimi simgesi gibi uygulama mesajları gibi) birkaç ortam değişkeni kullanılarak ayarlanabilir.

Genellikle $LANGbölgenizi tanımlayan bir değere tercih edersiniz (örneğin fr_CH.UTF-8, Fransızca konuşan İsviçre'de, UTF-8 kullanarak). Bireysel LC_xxxdeğişkenler belirli bir yönü geçersiz kılar. LC_ALLhepsini geçersiz kılar. localeArgüman olmadan denilen komut, geçerli ayarların bir özetini verir.

Örneğin, bir GNU sisteminde, şunu alıyorum:

$ 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=

Örneğin tek bir ayarı geçersiz kılabilirim:

$ LC_TIME=fr_FR.UTF-8 date
jeudi 22 août 2013, 10:41:30 (UTC+0100)

Veya:

$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€

Veya LC_ALL ile herşeyi geçersiz kıl.

$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory

Bir komut dosyasında, belirli bir ayarı zorlamak istiyorsanız, kullanıcının hangi ayarları zorladığını bilmiyorsanız (muhtemelen LC_ALL), en iyi, en güvenli ve genellikle tek seçenek LC_ALL'ı zorlamaktır.

CYerel basit yerel olması gerekiyordu özel yerel bir. Ayrıca, diğer yerel ayarlar insanlar için olsa da, C yerel ayarının bilgisayarlar için olduğunu söyleyebiliriz. C yerelinde, karakterler tek bayttır, karakter kümesi ASCII'dir (buna gerek yoktur, ancak pratikte çoğumuzun kullanacağı sistemlerde olacaktır), sıralama düzeni bayt değerlerine dayanır, dil genellikle ABD İngilizcesidir (uygulama mesajları için (ay veya gün adları veya sistem kitaplıklarıyla ilgili mesajların aksine), uygulama yazarının takdirindedir) ve para birimi simgeleri gibi şeyler tanımlanmaz.

Bazı sistemlerde, örneğin ASCII dışı karakterler için sıralama düzeninin tanımlanmadığı POSIX yerel ayarlarında bir fark vardır.

Kullanıcı ayarlarının komut dosyanızı engellemesini önlemek için genellikle LC_ALL = C ile bir komut çalıştırırsınız. İsterseniz Örneğin, [a-z]26 ASCII karakterleri eşleştirmek için aiçin z, ayarlamak zorunda LC_ALL=C.

GNU sistemlerinde LC_ALL=Cve LC_ALL=POSIX(veya LC_MESSAGES=C|POSIX) geçersiz kılmakla $LANGUAGE, geçersiz kılıyorlardı LC_ALL=anything-else.

Genellikle ayarlamanız gereken birkaç durum LC_ALL=C:

  • sort -uveya sort ... | uniq.... C dışındaki birçok yerel yerde, bazı sistemlerde (özellikle GNU olanlar), bazı karakterler aynı sıralama düzenine sahiptir . sort -ubenzersiz satırlar bildirmiyor, ancak eşit sıralama düzenine sahip her satır grubundan biri. Bu nedenle, benzersiz satırlar istiyorsanız, karakterlerin bayt olduğu ve tüm karakterlerin farklı sıralama düzenine sahip olduğu bir Cyerel ayar gerekir ( yerel ayarın garanti ettiği).
  • Aynısı =, POSIX uyumlu operatör exprveya ==POSIX uyumlu awks operatörü için geçerlidir ( mawkve gawkbu konuda POSIX değildir).
  • Karakter aralıkları gibi grep. Kullanıcının dilinde bir harfle eşleşmek istiyorsan kullan grep '[[:alpha:]]'ve değiştir LC_ALL. Ancak a-zA-ZASCII karakterlerini eşleştirmek istiyorsanız , ya LC_ALL=C grep '[[:alpha:]]'da LC_ALL=C grep '[a-zA-Z]'¹ işaretine ihtiyacınız vardır . Önce ve [a-z]sonra sıralanan karakterleri eşleştirir (birçok API'de ondan daha karmaşık olmasına rağmen). Diğer yerlerde, bunların ne olduğunu genellikle bilmiyorsunuz. Örneğin, bazı yerel ayarlar , kalıplar gibi bazı API'lerde ya da içerebilir, sıralama için büyük / küçük harfleri görmezden gelirler . Birçok UTF-8 yerellerde (dahil çoğu sistemlerde), latin harfleri içerecektir için aksan ile değil olanlar (bu yanaaz[a-z]bash[B-Z][A-Y]en_US.UTF-8[a-z]ayzzBen düşünemiyorum önlerinde türlü) dahil etmek isteyeyim neden (istediğini olurdu édeğil ź?).
  • kayan nokta aritmetiği ksh93. ksh93onur decimal_pointayarı LC_NUMERIC. İçeren bir komut dosyası yazarsanız a=$((1.2/7)), yerel ayarı ondalık ayırıcı olarak virgülleri olan bir kullanıcı tarafından çalıştırıldığında çalışmayı durdurur:

    $ 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
    

    O zaman şöyle bir şeye ihtiyacın var:

    #! /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
    

    Bir yandan not: ,Ondalık ayırıcı, ,daha da fazla karışıklığa neden olabilecek aritmetik operatörle çakışır.

  • Karakterlerin bayt olması gerektiğinde. Günümüzde, çoğu yerel ayar UTF-8'dir; bu, karakterlerin 1 - 6 bayt alabildiği anlamına gelir. Bayt olması gereken verilerle, metin yardımcı programlarıyla çalışırken, LC_ALL = C olarak ayarlamak isteyeceksiniz. UTF-8 verilerinin ayrıştırılmasının bir maliyeti olduğundan, performansı önemli ölçüde artıracaktır.
  • önceki noktanın bir sonucu: girişin hangi karakter kümesini yazdığını bilmediğiniz bir metni işlerken, ancak ASCII ile uyumlu olduğunu varsayabilir (neredeyse tüm karakter gruplarında olduğu gibi). Örneğin için grep '<.*>'bir içeren hatları aramaya <, >çifti mısın UTF-8 yerel ayarda konum ve giriş iso8859-15 gibi ayarlanmış bir tek bayt 8 bit karakter kodlanmış olması durumunda hiçbir iş. Bunun nedeni ., iso8859-15'deki yalnızca karakterlerle ASCII olmayan karakterlerin eşleşmesi UTF-8'de geçerli bir karakter oluşturmamasıdır. Öte yandan, LC_ALL=C grep '<.*>'herhangi bir bayt değeri Cyerel olarak geçerli bir karakter oluşturduğu için çalışacaktır .
  • Giriş verilerini işlediğiniz veya bir insan için / amaçlanmayan çıktı verilerini işlediğiniz zaman. Bir kullanıcıyla konuşuyorsanız, kongre ve dillerini kullanmak isteyebilirsiniz, ancak örneğin, İngiliz tarzı ondalık basamağı bekleyen başka bir uygulamayı beslemek için bazı numaralar oluşturursanız veya İngilizce ay adlarını kullanırsanız, LC_ALL = C'yi ayarla:

    $ 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
    

    Bu da (olduğu gibi harf duyarsız karşılaştırma gibi şeyler için de geçerlidir grep -i) ve vaka dönüşüm ( awk'ın toupper(), dd conv=ucase...). Örneğin:

    grep -i i
    

    Ikullanıcının yerel ayarlarında eşleşme garantisi yoktur . Örneğin bazı Türk lokallerinde, orada büyük harf iolduğu İ(noktaya dikkat etmeyin ) ve küçük harf Iolduğu gibi ı(eksik noktayı not edin).


¹ Metnin kodlamasına bağlı olarak, mutlaka yapılması gereken doğru bir şey yoktur. Bu UTF-8 veya tek baytlık karakter kümeleri için geçerlidir (iso-8859-1 gibi), ancak UTF-8 olmayan çok baytlı karakter kümeleri için geçerli değildir.

Örneğin, bir zh_HK.big5hkscsyerel ayardaysanız (Hong Kong, BIG5 Çince karakter kodlamasının Hong Kong varyantını kullanarak) ve bu karakter gruplarında kodlanmış bir dosyada İngilizce harfleri aramak istiyorsanız, aşağıdakilerden birini yapın:

LC_ALL=C grep '[[:alpha:]]'

veya

LC_ALL=C grep '[a-zA-Z]'

yanlış olurdu, çünkü o karakter dizisinde (ve diğerleri ancak UTF-8'in ortaya çıkmasından bu yana pek kullanılmıyordu), A-Za-z karakterlerinin ASCII kodlamasına karşılık gelen baytlar içeriyordu . Örneğin, tümü A䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽(ve daha pek çoğu), kodlamasını içerir A. 0x96 0x41 ve A0x41 ASCII'deki gibidir. Böylece LC_ALL=C grep '[a-zA-Z]', bu karakterleri içeren satırlarda, bu bayt dizilerini yanlış yorumlayacağı için eşleştireceğiz.

LC_COLLATE=C grep '[A-Za-z]'

işe yarayacaktı, ancak yalnızca LC_ALLbaşka türlü ayarlanmadığında (bu geçersiz kılacaktı LC_COLLATE). Yani yapmak zorunda kalabilirsin:

grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'

Yerel kodlamada kodlanmış bir dosyada İngilizce harfleri aramak istiyorsanız.


12
+1, en iyi cevap (geçersiz kılmayı işaret etmek, vb. İçin). Ama Ignacio'nun cevabının (güzel) örneklerinden yoksun ^^ ^^
Olivier Dulac 11

1
Küçük bir nitpick: CYerel ayar yalnızca "taşınabilir karakter setini" (ASCII 0-127) desteklemek için gereklidir ve karakter> 127 için davranış teknik olarak belirtilmez . Uygulamada, çoğu program onlara opak veri olarak davranacak ve tanımladığınız şekilde iletecektir. Ancak hepsi değil: özellikle, Ruby Cyerel ayarlarda çalışıyorsa bayt> 127 baytlık char verilerini boğabilir. Gerçekten teknik olarak "uygun" olup olmadığını bilmiyorum, ama vahşi doğada gördük .
Andrew Janke

2
@JreweJanke, evet. Taşınabilir karakter kümesinin ASCII veya 0-127 anlamına gelmediğini unutmayın. Austin grubu posta listesinde "C" yerel karakter kümesinin özelliklerinin ne olacağı ve genel fikir birliğinin (ve bir sonraki spesifikasyonda açıklığa kavuşturulacağı), karakter grubunun bekar olacağı konusunda çok fazla tartışma yapıldı. Bayt ve tam 8bit aralığı kapsar (burada açıklanan özelliklerle). Bu arada, evet, bazı sapmalar olabilir (böcek olarak veya şartname yeterince açık olmadığı için). Her durumda LC_ALL = C, aklı başında bir davranışa sahip olabileceğinize en yakın olanıdır.
Stéphane Chazelas,

1
UTF-8'deki bir Unicode kod noktası, en fazla 4 oktete (veya bayt) sahip olabilir, ancak bazı Karakterler, 6 oktetten daha uzun sekanslara yol açabilecek bir kod noktasından daha fazlasına ihtiyaç duyar.
12431234123412341234123

1
@ 12431234123412341234123, orijinal UTF-8 kodlama U +, 7FFFFFFF kadar kapsar (6 bayt ve bu gibi 13 bayta kadar gitmek için bazı uzantılar perls' \x{7FFFFFFFFFFFFFFF}Unicode kod noktalarına aralığı keyfi U +, 10FFFF değerinden ile sınırlı iken) ve (UTF-16 tasarım sınırlaması nedeniyle), bazı araçlar hala 6 bayt karakterleri tanıyor / üretiyor. Bunu 6 byte karakterle kastettim. Unix anlamında, bir karakter bir kod noktasıdır. Sizin birden fazla kod noktası "karakterler" daha genel karakterlerinden belirsizliği giderecek graphem kümeleri gibi başvurulur.
Stéphane Chazelas

7

Cvarsayılan yerel ayardır, "POSIX", "C" nin diğer adıdır. Sanırım "C", ANSI-C'den türetilmiş. Belki ANSI-C "POSIX" yerel ayarını tanımlar.


C ve bugüne kadar UNIX Hem öncesine ANSI C.
Bir CVn

@ MichaelKjörling: Yani? ANSI öncesi belgeleri gördüm ve yerel ayarları yoktu. Dahili olarak AT&T Bell Labs'de herkes İngilizce biliyordu.
MSalters

C dili için ön ANSI belgeleri olabilir veya bu ön ANSI ima edilemez, C yerel kavramı yok oldu yerel ayarları (söz etmez gerçeği @MSalters; sonuçta, ben eminim dil hala yok , ancak bu, noktanın yanında), Cyerel ayar adının "ANSI C" den geldiği anlamına gelmez .
bir CVn

2
@ MichaelKjörling: Bu noktayı kaçırıyorsunuz. Yereller tanıtıldığında, "C" zaten "ANSI C" anlamına geliyordu. Geçmişte K & R C olması önemli değil.
MSalters

3

Söyleyebileceğim kadarıyla, OS X UTF-8 yerel ayarlarında kod noktası harmanlama sırasını kullanıyor, bu yüzden Stéphane Chazelas'ın cevabında belirtilen noktaların bir istisnası.

Bu, OS X'te 26 ve Ubuntu'da 310 yazdırır:

export LC_ALL=en_US.UTF-8
printf %b $(printf '\\U%08x\\n' $(seq $((0x11)) $((0x10ffff))))|grep -a '[a-z]'|wc -l

Aşağıdaki kod, girişin sıralandığını gösteren OS X'te hiçbir şey yazdırmaz. Kaldırılan altı yedek karakter, geçersiz bir bayt dizisi hatasına neden oluyor.

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

Aşağıdaki kod, OS X'te hiçbir şeyi yazdırmaz; bu, aynı harmanlama sırasına sahip iki ardışık kod noktasının (en azından U + 000B ve U + D7FF arasında) olmadığını gösterir.

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

(Yukarıdaki örnekler, %bçünkü printf \\U25zsh'da bir hatayla sonuçlandığından kullanılır .)

GNU sistemlerinde aynı harmanlama düzeni var karakterlerden bazıları karakterler ve diziler aynı harmanlama Bu baskılar (OS X olduğunu kullanılarak OS X ilk ① OS X sırasını yok sortya da GNU'ya sort) ama ② ilk Ubuntu:

export LC_ALL=en_US.UTF-8;printf %s\\n ② ①|sort

Bu, OS X’te üç satır yazdırır (OS X’ler sortveya GNU’yu kullanarak sort) ancak bir satır Ubuntu’da:

export LC_ALL=en_US.UTF-8;printf %b\\n \\u0d4c \\u0d57 \\u0d46\\u0d57|sort -u

Bu farkın neden olduğunu bilen var mı?
1.61803

3

Görünüşe LC_COLLATEgöre ls tarafından kullanılan "alfabetik sıra" da kontrol ediliyor. ABD yerel ayarı şu şekilde sıralanacaktır:

a.C
aFilename.C
aFilename.H
a.H

temelde dönemleri görmezden geliyor. Tercih edebilirsiniz:

a.C
a.H
aFilename.C
aFilename.H

Kesinlikle yaparım. Bunu başarmak LC_COLLATEiçin ayar C. Tüm harflerden sonra küçük harfleri de sıralayacağını unutmayın:

A.C
A.H
AFilename.C
a.C
a.H
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.