สิ่งที่มี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การที่คุณจะต้องตั้งค่าzLC_ALL=C
ในระบบ GNU, LC_ALL=CและLC_ALL=POSIX(หรือLC_MESSAGES=C|POSIX) แทนที่$LANGUAGEขณะที่LC_ALL=anything-elseจะไม่
บางกรณีที่คุณต้องตั้งค่าโดยทั่วไปLC_ALL=C:
sort -usort ... | 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 และA0x41 เช่นเดียวกับใน 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