สิ่งที่มีC
คุณค่าสำหรับการLC_ALL
ทำในระบบเหมือน Unix?
ฉันรู้ว่ามันบังคับให้สถานที่เดียวกันทุกด้าน แต่จะC
ทำอย่างไร?
สิ่งที่มีC
คุณค่าสำหรับการLC_ALL
ทำในระบบเหมือน Unix?
ฉันรู้ว่ามันบังคับให้สถานที่เดียวกันทุกด้าน แต่จะC
ทำอย่างไร?
คำตอบ:
มันบังคับให้แอปพลิเคชันใช้ภาษาเริ่มต้นสำหรับเอาต์พุต:
$ LC_ALL=es_ES man
¿Qué página de manual desea?
$ LC_ALL=C man
What manual page do you want?
และกองกำลังการเรียงลำดับให้เป็น byte-wise:
$ 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
เป็นตัวแปรสภาพแวดล้อมที่แทนที่การตั้งค่าการแปลอื่น ๆ ทั้งหมด ( ยกเว้นใน$LANGUAGE
บางสถานการณ์ )
ลักษณะที่แตกต่างกันของการแปลท้องถิ่น (เช่นตัวคั่นหลักพันหรืออักขระจุดทศนิยมชุดอักขระลำดับการเรียงเดือนชื่อวันภาษาหรือข้อความแอปพลิเคชันเช่นข้อความแสดงข้อผิดพลาดสัญลักษณ์สกุลเงิน) สามารถตั้งค่าโดยใช้ตัวแปรสภาพแวดล้อมเล็กน้อย
โดยทั่วไปคุณจะตั้ง$LANG
ค่าตามความชอบด้วยค่าที่ระบุภูมิภาคของคุณ (เช่นfr_CH.UTF-8
ถ้าคุณใช้ภาษาสวิตเซอร์แลนด์ที่พูดภาษาฝรั่งเศสโดยใช้ UTF-8) LC_xxx
ตัวแปรแต่ละตัวจะแทนที่ด้านที่แน่นอน LC_ALL
แทนที่พวกเขาทั้งหมด locale
คำสั่งเมื่อเรียกโดยไม่มีข้อโต้แย้งให้บทสรุปของการตั้งค่าปัจจุบัน
ตัวอย่างเช่นในระบบ GNU ฉันได้รับ:
$ 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=
ฉันสามารถแทนที่การตั้งค่าส่วนบุคคลด้วยเช่น:
$ LC_TIME=fr_FR.UTF-8 date
jeudi 22 août 2013, 10:41:30 (UTC+0100)
หรือ:
$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€
หรือแทนที่ทุกอย่างด้วย LC_ALL
$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory
ในสคริปต์หากคุณต้องการบังคับให้มีการตั้งค่าเฉพาะเนื่องจากคุณไม่ทราบว่าการตั้งค่าใดที่ผู้ใช้บังคับ (อาจเป็น LC_ALL ด้วย) ตัวเลือกที่ดีที่สุดปลอดภัยที่สุดและโดยทั่วไปเท่านั้นคือบังคับให้ LC_ALL
C
สถานที่เกิดเหตุเป็นสถานที่พิเศษที่มีขึ้นเพื่อเป็นสถานที่ที่ง่ายที่สุด คุณสามารถพูดได้ว่าในขณะที่โลแคลอื่นสำหรับมนุษย์โลแคล C สำหรับคอมพิวเตอร์ ในโลแคล C อักขระจะเป็นไบต์เดียวชุดอักขระคือ ASCII (ไม่จำเป็นต้องใช้ แต่ในทางปฏิบัติจะอยู่ในระบบที่เราส่วนใหญ่จะใช้) ลำดับการเรียงจะขึ้นอยู่กับค่าไบต์ ภาษามักจะเป็นภาษาอังกฤษแบบสหรัฐอเมริกา (แม้ว่าจะมีข้อความของแอปพลิเคชัน (ตรงข้ามกับสิ่งต่าง ๆ เช่นชื่อเดือนหรือวันหรือข้อความจากไลบรารีระบบ) ขึ้นอยู่กับดุลยพินิจของผู้เขียนแอปพลิเคชัน) และสิ่งต่างๆเช่นสัญลักษณ์สกุลเงิน
ในบางระบบมีความแตกต่างกับโลแคล POSIX ที่ตัวอย่างการเรียงลำดับสำหรับอักขระที่ไม่ใช่ ASCII ไม่ได้ถูกกำหนดไว้
โดยทั่วไปคุณเรียกใช้คำสั่งด้วย LC_ALL = C เพื่อหลีกเลี่ยงการตั้งค่าของผู้ใช้เพื่อรบกวนสคริปต์ของคุณ ตัวอย่างเช่นถ้าคุณต้องการ[a-z]
เพื่อให้ตรงกับอักขระ ASCII 26 จากa
การที่คุณจะต้องตั้งค่าz
LC_ALL=C
ในระบบ GNU, LC_ALL=C
และLC_ALL=POSIX
(หรือLC_MESSAGES=C|POSIX
) แทนที่$LANGUAGE
ขณะที่LC_ALL=anything-else
จะไม่
บางกรณีที่คุณต้องตั้งค่าโดยทั่วไปLC_ALL=C
:
sort -u
sort ... | uniq...
หรือ ในสถานที่อื่น ๆ อีกมากมายกว่า C ในบางระบบ (สะดุดตาคน GNU) ตัวละครบางตัวมีการเรียงลำดับคำสั่งเดียวกัน sort -u
ไม่ได้รายงานบรรทัดที่ไม่ซ้ำกัน แต่หนึ่งในกลุ่มแต่ละบรรทัดที่มีลำดับการเรียงเท่ากัน ดังนั้นหากคุณต้องการบรรทัดที่ไม่ซ้ำกันคุณต้องมีสถานที่ที่ตัวละครเป็นไบต์และตัวละครทั้งหมดมีลำดับการจัดเรียงที่แตกต่างกัน (ซึ่งC
สถานที่เกิดเหตุรับประกัน)=
ดำเนินการที่เป็นไปตาม POSIX expr
หรือ==
ตัวดำเนินการของ POSIX ที่สอดคล้องawk
กัน ( mawk
และgawk
ไม่ใช่ POSIX ในเรื่องนั้น) ซึ่งไม่ได้ตรวจสอบว่ามีสองสตริงเหมือนกันหรือไม่grep
มา ถ้าคุณหมายถึงเพื่อให้ตรงกับตัวอักษรในภาษาของผู้ใช้ให้ใช้และไม่ได้ปรับเปลี่ยนgrep '[[:alpha:]]'
LC_ALL
แต่ถ้าคุณต้องการจับคู่a-zA-Z
อักขระ ASCII คุณต้องการอย่างใดอย่างหนึ่งLC_ALL=C grep '[[:alpha:]]'
หรือLC_ALL=C grep '[a-zA-Z]'
¹ [a-z]
จับคู่อักขระที่เรียงลำดับหลังa
และก่อนหน้าz
(แม้ว่าจะมี API หลายตัวมันก็ซับซ้อนกว่านั้น) ในสถานที่อื่น ๆ โดยทั่วไปคุณไม่รู้ว่ามันคืออะไร ยกตัวอย่างเช่นบางทำเลไม่สนใจกรณีสำหรับการเรียงลำดับดังนั้น[a-z]
ใน APIs บางอย่างเช่นbash
รูปแบบอาจรวมหรือ[B-Z]
[A-Y]
ในหลายพื้นที่ของ UTF-8 (รวมถึงen_US.UTF-8
ระบบส่วนใหญ่) [a-z]
จะรวมถึงตัวอักษรละตินจากa
ถึงy
กับกำกับ แต่ไม่ใช่ของz
(ตั้งแต่z
เรียงลำดับก่อนหน้าพวกเขา) ซึ่งฉันไม่สามารถจินตนาการได้ว่าจะเป็นสิ่งที่คุณต้องการ (ทำไมคุณต้องการที่จะรวมé
และไม่ได้ź
)ksh93
ลอยเลขคณิตจุดใน ksh93
เกียรตินิยมการตั้งค่าในdecimal_point
LC_NUMERIC
หากคุณเขียนสคริปต์ที่มีa=$((1.2/7))
มันจะหยุดทำงานเมื่อผู้ใช้ที่มีสถานที่เกิดเหตุมีเครื่องหมายจุลภาคเป็นตัวคั่นทศนิยม:
$ 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
จากนั้นคุณต้องการสิ่งต่าง ๆ เช่น:
#! /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
ตามหมายเหตุด้านข้าง: ,
ตัวคั่นทศนิยมขัดแย้งกับตัว,
ดำเนินการทางคณิตศาสตร์ซึ่งอาจทำให้เกิดความสับสนมากยิ่งขึ้น
grep '<.*>'
ที่จะมองหาเส้นที่มี<
, >
คู่จะไม่ทำงานถ้าคุณอยู่ในสถานที่เกิดเหตุ UTF-8 และการป้อนข้อมูลจะถูกเข้ารหัสในตัวเดียวอักขระไบต์ 8 บิตตั้งเช่น iso8859-15 นั่นเป็นเพราะการ.
จับคู่เฉพาะอักขระและอักขระที่ไม่ใช่ ASCII ใน iso8859-15 มีแนวโน้มที่จะไม่สร้างอักขระที่ถูกต้องใน UTF-8 ในทางกลับกันLC_ALL=C grep '<.*>'
จะทำงานได้เนื่องจากค่าไบต์ใด ๆ สร้างอักขระที่ถูกต้องในC
โลแคลเวลาใดก็ตามที่คุณประมวลผลข้อมูลอินพุตหรือข้อมูลเอาต์พุตที่ไม่ได้มีไว้สำหรับมนุษย์ หากคุณกำลังพูดคุยกับผู้ใช้คุณอาจต้องการใช้การประชุมและภาษาของพวกเขา แต่ตัวอย่างเช่นหากคุณสร้างตัวเลขเพื่อป้อนแอปพลิเคชันอื่น ๆ ที่คาดว่าจะได้รับทศนิยมสไตล์อังกฤษหรือชื่อเดือนภาษาอังกฤษ ตั้ง 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
นอกจากนี้ยังใช้กับสิ่งต่าง ๆ เช่นการเปรียบเทียบแบบไม่รู้สึกตัวพิมพ์เล็กและตัวพิมพ์ใหญ่grep -i
( awk
's toupper()
, dd conv=ucase
... ) ตัวอย่างเช่น
grep -i i
ไม่รับประกันว่าจะตรงกับI
ในภาษาของผู้ใช้ ในสถานที่ตุรกีบางตัวอย่างเช่นมันไม่ได้เป็นบนกรณีi
คือİ
(โปรดทราบจุด) และมีกรณีที่ต่ำกว่าI
คือı
(โปรดทราบจุดที่ขาดหายไป)
¹ขึ้นอยู่กับการเข้ารหัสของข้อความนั่นไม่ใช่สิ่งที่ถูกต้องที่จะทำ ถูกต้องสำหรับชุดอักขระ UTF-8 หรือไบต์เดียว (เช่น iso-8859-1) แต่ไม่จำเป็นต้องเป็นชุดอักขระแบบมัลติไบต์ UTF-8
ตัวอย่างเช่นหากคุณอยู่ในzh_HK.big5hkscs
สถานที่ (ฮ่องกงใช้ตัวแปรฮ่องกงของการเข้ารหัสตัวอักษรจีน BIG5) และคุณต้องการค้นหาตัวอักษรภาษาอังกฤษในไฟล์ที่เข้ารหัสในชุดอักขระนั้นโดยทำดังนี้
LC_ALL=C grep '[[:alpha:]]'
หรือ
LC_ALL=C grep '[a-zA-Z]'
จะผิดเพราะในชุดอักขระนั้น (และอื่น ๆ อีกมากมาย แต่แทบจะไม่ได้ใช้ตั้งแต่ UTF-8 ออกมา) อักขระจำนวนมากประกอบด้วยไบต์ที่สอดคล้องกับการเข้ารหัส ASCII ของอักขระ A-Za-z ตัวอย่างทั้งหมดA䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽
(และอื่น ๆ อีกมากมาย) A
มีการเข้ารหัสของ 䨝
คือ 0x96 0x41 และA
0x41 เช่นเดียวกับใน ASCII ดังนั้นเราLC_ALL=C grep '[a-zA-Z]'
จะจับคู่กับบรรทัดเหล่านั้นที่มีอักขระเหล่านั้นเนื่องจากมันจะตีความลำดับของไบต์เหล่านั้นผิด
LC_COLLATE=C grep '[A-Za-z]'
จะใช้งานได้ แต่LC_ALL
ไม่ได้ตั้งค่าไว้เป็นอย่างอื่น (ซึ่งจะแทนที่LC_COLLATE
) ดังนั้นคุณอาจต้องทำ:
grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'
หากคุณต้องการค้นหาตัวอักษรภาษาอังกฤษในไฟล์ที่เข้ารหัสในการเข้ารหัสของโลแคล
C
สถานที่เกิดเหตุจะต้องเฉพาะเพื่อสนับสนุน "ชุดอักขระแบบพกพา" (ASCII 0-127) และพฤติกรรมตัวอักษร> 127 คือไม่ระบุรายละเอียดทางเทคนิค ในทางปฏิบัติโปรแกรมส่วนใหญ่จะถือว่าเป็นข้อมูลทึบแสงและส่งผ่านตามที่คุณอธิบาย แต่ไม่ใช่ทั้งหมด: โดยเฉพาะทับทิมอาจสำลักข้อมูลถ่านด้วยไบต์> 127 หากทำงานในC
โลแคล ฉันสุจริตไม่ทราบว่าในทางเทคนิค "สอดคล้อง" แต่เราได้เห็นมันในป่า
perl
's \x{7FFFFFFFFFFFFFFF}
) และในขณะที่ช่วงของจุดรหัส Unicode ถูก จำกัด โดยพลการ (เนื่องจากข้อ จำกัด ในการออกแบบ UTF-16) เครื่องมือบางอย่างยังคงรับรู้ / สร้างตัวอักษรขนาด 6 ไบต์ นั่นคือสิ่งที่ฉันหมายถึง 6 ตัวอักษรไบต์ ในซีแมนทิกส์ Unix อักขระหนึ่งตัวคือ codepoint หนึ่งตัว "อักขระ" codepointของคุณมากกว่าหนึ่งตัวถูกอ้างถึงโดยทั่วไปว่าเป็นกลุ่มกราฟเพื่อแยกแยะจากตัวละคร
C
เป็นสถานที่เริ่มต้น "POSIX" เป็นนามแฝงของ "C" ฉันเดาว่า "C" มาจาก ANSI-C บางที ANSI-C จะกำหนดโลแคล "POSIX"
C
ชื่อสถานที่นั้นมาจาก "ANSI C"
เท่าที่ฉันสามารถบอกได้ OS X ใช้ลำดับการเรียงโค้ดในโลแคล UTF-8 ดังนั้นจึงเป็นข้อยกเว้นสำหรับบางจุดที่กล่าวถึงในคำตอบโดยStéphane Chazelas
สิ่งนี้พิมพ์ 26 ใน OS X และ 310 ใน Ubuntu:
export LC_ALL=en_US.UTF-8
printf %b $(printf '\\U%08x\\n' $(seq $((0x11)) $((0x10ffff))))|grep -a '[a-z]'|wc -l
โค้ดด้านล่างไม่พิมพ์สิ่งใดใน OS X ซึ่งบ่งชี้ว่ามีการเรียงลำดับอินพุต อักขระตัวแทนหกตัวที่ถูกลบออกทำให้เกิดข้อผิดพลาดลำดับไบต์ที่ผิดกฎหมาย
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
โค้ดด้านล่างไม่พิมพ์สิ่งใดใน OS X ซึ่งบ่งชี้ว่าไม่มีจุดรหัสต่อเนื่องสองจุด (อย่างน้อยระหว่าง U + 000B และ U + D7FF) ที่มีลำดับการเรียงเหมือนกัน
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
(ตัวอย่างข้างต้นใช้%b
เพราะprintf \\U25
ผลลัพธ์มีข้อผิดพลาดเป็น zsh)
อักขระบางตัวและลำดับของอักขระที่มีการเรียงลำดับเดียวกันในระบบ GNU ไม่มีลำดับการเรียงเหมือนกันใน OS X ซึ่งจะพิมพ์①เป็นอันดับแรกใน OS X (ใช้ OS X sort
หรือ GNU sort
) แต่เป็นครั้งแรกใน Ubuntu:
export LC_ALL=en_US.UTF-8;printf %s\\n ② ①|sort
พิมพ์สามบรรทัดใน OS X (โดยใช้ OS X sort
หรือ GNU sort
) แต่หนึ่งบรรทัดใน Ubuntu:
export LC_ALL=en_US.UTF-8;printf %b\\n \\u0d4c \\u0d57 \\u0d46\\u0d57|sort -u
ปรากฏว่าLC_COLLATE
ควบคุม "ลำดับตามตัวอักษร" ที่ใช้โดย ls เช่นกัน สถานที่ของสหรัฐอเมริกาจะเรียงลำดับดังนี้:
a.C
aFilename.C
aFilename.H
a.H
โดยทั่วไปจะไม่สนใจช่วงเวลา คุณอาจชอบ:
a.C
a.H
aFilename.C
aFilename.H
ฉันทำอย่างแน่นอน การตั้งค่าLC_COLLATE
ให้C
สำเร็จนี้ โปรดทราบว่ามันจะเรียงลำดับตัวพิมพ์เล็กหลังจากเมืองหลวงทั้งหมด:
A.C
A.H
AFilename.C
a.C
a.H
xclock
คำเตือน (Missing charsets in String to FontSet conversion
) จะดีกว่าถ้าคุณจะใช้LC_ALL=C.UTF-8
เพื่อหลีกเลี่ยงปัญหาเกี่ยวกับไซริลลิก ในการตั้งค่าตัวแปรสภาพแวดล้อมนี้คุณต้องเพิ่มบรรทัดต่อไปนี้ที่ท้าย~/.bashrc
ไฟล์ -export LC_ALL=C.UTF-8