เหตุใด [AZ] จึงตรงกับอักษรตัวพิมพ์เล็กใน bash


43

ในเชลล์ทั้งหมดที่ฉันรู้จักrm [A-Z]*ลบไฟล์ทั้งหมดที่ขึ้นต้นด้วยตัวอักษรตัวพิมพ์ใหญ่ แต่ด้วยการทุบตีสิ่งนี้จะลบไฟล์ทั้งหมดที่ขึ้นต้นด้วยตัวอักษร

เนื่องจากปัญหานี้มีอยู่บน Linux และ Solaris ที่มี bash-3 และ bash-4 จึงไม่สามารถเป็นข้อบกพร่องที่เกิดจากตัวจับรูปแบบ buggy ใน libc หรือนิยามที่ตั้งที่พลาดไป

พฤติกรรมที่แปลกและเสี่ยงนี้มีจุดประสงค์หรือเป็นเพียงข้อผิดพลาดที่มีอยู่ซึ่งไม่ได้ผสมกันมาหลายปีหรือไม่?


3
สิ่งที่ไม่localeเอาท์พุท? ฉันไม่สามารถทำซ้ำสิ่งนี้ ( touch foo; echo [A-Z]*แสดงรูปแบบตัวอักษรไม่ใช่ "foo" ในไดเรกทอรีว่างเปล่า)
chepner

4
พิจารณาว่ามีกี่คนที่บอกว่ามันใช้งานได้ดีกับพวกเขาหรือแสดงตัวอย่างว่า LC_COLLATE มีผลต่อเรื่องนี้อย่างไรคุณอาจแก้ไขคำถามของคุณเพื่อเพิ่มเซสชัน bash ตัวอย่างซึ่งแสดงให้เห็นถึงสถานการณ์ที่คุณถาม โปรดระบุรุ่นทุบตีที่คุณใช้
Kenster

หากคุณอ่านข้อความทั้งหมดที่นี่คุณจะรู้ว่าฉันใช้ bash รุ่นใดและทำอะไรตั้งแต่ที่โพสต์คำตอบไปยังคำถามของฉัน ให้ฉันทำซ้ำวิธีการแก้ปัญหา: ทุบตีไม่ได้จัดการสถานที่ของตัวเองเพื่อให้การตั้งค่า LC_COLLATE ไม่เปลี่ยนแปลงอะไรจนกว่าคุณจะเริ่มกระบวนการทุบตีอีกครั้งด้วยสภาพแวดล้อมใหม่
schily

1
ดูเพิ่มเติมLC_COLLATE (ควร) มีผลกับช่วงอักขระหรือไม่ (แต่คำถามนั้นไม่ได้เกี่ยวกับการทุบตีโดยเฉพาะ)
Gilles 'หยุดความชั่วร้าย'

"การตั้งค่า LC_COLLATE จะไม่เปลี่ยนแปลงอะไรจนกว่าคุณจะเริ่มกระบวนการทุบตีอีกครั้งด้วยสภาพแวดล้อมใหม่" ไม่ตรงกับพฤติกรรมที่ฉันเห็นด้วย bash-4 บน Solaris มันกำลังเปลี่ยนพฤติกรรมในเชลล์ที่กำลังทำงานอยู่ # echo [A-Z]* ; export LC_COLLATE=C ; echo [A-Z]*A b B z ZABZ
BowlOfRed

คำตอบ:


68

โปรดทราบว่าเมื่อใช้การแสดงออกช่วงเช่น [az] อาจรวมถึงตัวอักษรของอีกกรณีหนึ่งทั้งนี้ขึ้นอยู่กับการตั้งค่า LC_COLLATE

LC_COLLATE เป็นตัวแปรที่กำหนดลำดับการเรียงที่ใช้เมื่อเรียงลำดับผลลัพธ์ของการขยายชื่อพา ธ และกำหนดพฤติกรรมของนิพจน์ช่วงคลาสที่เทียบเท่าและลำดับการเรียงภายในการขยายชื่อพา ธ และการจับคู่รูปแบบ


พิจารณาสิ่งต่อไปนี้:

$ touch a A b B c C x X y Y z Z
$ ls
a  A  b  B  c  C  x  X  y  Y  z  Z
$ echo [a-z] # Note the missing uppercase "Z"
a A b B c C x X y Y z
$ echo [A-Z] # Note the missing lowercase "a"
A b B c C x X y Y z Z

แจ้งให้ทราบเมื่อecho [a-z]มีการเรียกคำสั่งเอาต์พุตที่คาดหวังจะเป็นไฟล์ทั้งหมดที่มีตัวอักษรพิมพ์เล็ก นอกจากนี้ยังecho [A-Z]คาดว่าจะมีไฟล์ที่มีอักขระตัวพิมพ์ใหญ่ด้วย


การเปรียบเทียบมาตรฐานกับโลแคลเช่นen_USมีลำดับต่อไปนี้:

aAbBcC...xXyYzZ
  • ระหว่างaและz(ใน[a-z]) Zเป็นตัวพิมพ์ใหญ่ตัวอักษรยกเว้น
  • ระหว่างAและZ(ใน[A-Z]) aเป็นอักษรตัวพิมพ์เล็กทั้งหมดยกเว้น

ดู:

     aAbBcC[...]xXyYzZ
     |              |
from a      to      z

     aAbBcC[...]xXyYzZ
      |              |
from  A     to       Z

หากคุณเปลี่ยนLC_COLLATEตัวแปรให้Cเป็นตามที่คาดไว้:

$ export LC_COLLATE=C
$ echo [a-z]
a b c x y z
$ echo [A-Z]
A B C X Y Z

ดังนั้นจึงไม่ได้เป็นปัญหาก็เป็นปัญหาการเปรียบเทียบ


แทนที่จะแสดงออกช่วงที่คุณสามารถใช้ POSIX กำหนดชั้นเรียนตัวอักษรเช่นหรือupper lowerพวกเขาทำงานที่แตกต่างกันนอกจากนี้ยังมีLC_COLLATEการกำหนดค่าและแม้จะมีตัวละครสำเนียง :

$ echo [[:lower:]]
a b c x y z à è é
$ echo [[:upper:]]
A B C X Y Z

หากพฤติกรรมนี้สามารถควบคุมได้โดยตัวแปรสภาพแวดล้อม LC_ * ฉันไม่ได้ถาม ฉันทำงานในคณะกรรมการมาตรฐาน POSIX และฉันรู้ว่าการเรียงปัญหาด้วยเช่นtrนี้คือสิ่งที่ฉันตรวจสอบก่อน
schily

@schily ฉันไม่สามารถทำซ้ำปัญหาของคุณด้วยไม่ใช่ bash-3 เก่าหรือ bash-4; ทั้งสองสามารถควบคุมได้ผ่านLC_COLLATEซึ่งมีการบันทึกไว้ในคู่มือ
ความโกลาหล

ขออภัยฉันไม่สามารถทำซ้ำสิ่งที่คุณเชื่อ แต่ดูคำตอบของฉันเอง ... จากแนวคิดในการสนทนานี้ฉันค้นพบสาเหตุของปัญหา
schily

25

[A-Z]ในbashการแข่งขันทั้งหมดเรียงองค์ประกอบ (ตัวละคร แต่ยังเรียกเป็นลำดับของตัวอักษรเช่นDszในตำแหน่งที่ฮังการี) ที่จัดเรียงหลังและจัดเรียงก่อนA Zในสถานที่ของคุณcอาจเรียงลำดับระหว่าง B และ C

$ printf '%s\n' A a á b B c C Ç z Z  | sort
a
A
á
b
B
c
C
Ç
z
Z

ดังนั้นcหรือzจะได้รับการจับคู่โดย[A-Z]แต่ไม่ได้หรือa

$ printf '%s\n' A a á b B c C Ç z Z  |
pipe>  bash -c 'while IFS= read -r x; do case $x in [A-Z]) echo "$x"; esac; done'
A
á
b
B
c
C
Ç
z
Z

ในโลแคล C ลำดับจะเป็น:

$ printf '%s\n' A a á b B c C Ç z Z  | LC_COLLATE=C sort
A
B
C
Z
a
b
c
z
Ç
á

ดังนั้น[A-Z]จะตรงกับA, B, C, Zแต่ไม่ได้และยังไม่Ç

หากคุณต้องการจับคู่กับตัวอักษรตัวพิมพ์ใหญ่ (ในสคริปต์ใด ๆ ) คุณสามารถใช้[[:upper:]]แทน ไม่มีวิธีในตัวในbashการจับคู่ตัวอักษรตัวพิมพ์ใหญ่ในสคริปต์ละตินเท่านั้น (ยกเว้นการแสดงรายการเป็นรายบุคคล)

หากคุณต้องการจับคู่AกับตัวอักษรZ ภาษาอังกฤษโดยไม่มีการออกเสียงคุณสามารถใช้[A-Z]หรือ[[:upper:]]แต่ในCโลแคล (สมมติว่าข้อมูลไม่ได้เข้ารหัสในชุดอักขระเช่น BIG5 หรือ GB18030 ซึ่งมีอักขระหลายตัวซึ่งการเข้ารหัสประกอบด้วยการเข้ารหัสของตัวอักษรเหล่านั้น) หรือรายการ พวกเขาเป็นรายบุคคล ( [ABCDEFGHIJKLMNOPQRSTUVWXYZ])

โปรดทราบว่ามีการเปลี่ยนแปลงบางอย่างระหว่างเปลือกหอย

สำหรับzsh, bash -O globasciiranges(ตัวเลือกชื่อแปลกแนะนำในทุบตี-4.3), schily-shและyash, [A-Z]ตรงกับตัวอักษรที่มีจุดรหัสอยู่ระหว่างที่Aและที่ของZเพื่อจะเทียบเท่ากับการทำงานของbashในภาษาซี

สำหรับเถ้า, mksh และกระสุนโบราณเช่นเดียวกับzshข้างบน แต่ จำกัด อยู่ที่ charsets ไบต์เดียว นั่นคือในโลแคล UTF-8 [É-Ź]จะไม่ตรงกันÓแต่เนื่องจาก[<c3><89>-<c5><b9>]นั่นจะตรงกับค่าไบต์ 0x89 ถึง 0xc5!

ksh93ประพฤติตัวเหมือนbashยกเว้นว่ามันจะถือว่าเป็นกรณีพิเศษช่วงที่ปลายทั้งสองเริ่มต้นด้วยตัวอักษรตัวพิมพ์เล็กหรือตัวอักษรตัวพิมพ์ใหญ่ ในกรณีนั้นมันจะจับคู่เฉพาะกับองค์ประกอบการเรียงที่เรียงลำดับระหว่างปลายเหล่านั้น แต่นั่นคือ (หรืออักขระตัวแรกของพวกเขาสำหรับองค์ประกอบการเรียงหลายตัวละคร) ยังตัวพิมพ์เล็ก (หรือตัวพิมพ์ใหญ่ตามลำดับ) ดังนั้น[A-Z]ก็จะตรงกับในÉแต่ไม่ได้อยู่ในeฐานะeที่ไม่เรียงลำดับระหว่างAและZได้ แต่ไม่เป็นตัวพิมพ์ใหญ่เหมือนและAZ

สำหรับfnmatch()รูปแบบ (ในfind -name '[A-Z]') หรือนิพจน์ทั่วไปของระบบ (ดังในgrep '[A-Z]') มันขึ้นอยู่กับระบบและสถานที่ ตัวอย่างเช่นในระบบ GNU ที่นี่[A-Z]ไม่ตรงกับxในen_GB.UTF-8ภาษา แต่จะอยู่ในระบบth_TH.UTF-8เดียว มันไม่ชัดเจนสำหรับฉันเกี่ยวกับข้อมูลที่ใช้ในการพิจารณา แต่เห็นได้ชัดว่าอิงจากตารางการค้นหาที่ได้มาจากข้อมูลโลแคล LC_COLLATE )

ลักษณะการทำงานทั้งหมดได้รับอนุญาตจาก POSIX เนื่องจาก POSIX จะหยุดการทำงานของช่วงที่ไม่ได้ระบุไว้ในสถานที่อื่นนอกเหนือจากภาษา C ตอนนี้เราสามารถโต้แย้งข้อดีของแต่ละวิธีได้

bashวิธีการ 's ทำให้ความรู้สึกมากเช่นเดียวกับ[C-G]ที่เราต้องการตัวอักษรในระหว่างและC Gและการใช้ลำดับการจัดเรียงของผู้ใช้สำหรับสิ่งที่กำหนดว่าอะไรที่อยู่ในระหว่างนั้นเป็นแนวทางที่มีเหตุผลที่สุด

ตอนนี้ปัญหาคือว่ามันทำลายความคาดหวังของผู้คนจำนวนมากโดยเฉพาะอย่างยิ่งคนที่เคยชินกับพฤติกรรมดั้งเดิมของ pre-Unicode แม้กระทั่งวันก่อนสากล ขณะที่จากผู้ใช้ปกติก็อาจทำให้รู้สึกว่า[C-I]รวมถึงhเป็นhตัวอักษรที่อยู่ในระหว่างCและIและ[A-g]ไม่รวมZมันเป็นเรื่องที่แตกต่างกันสำหรับคนที่มีการจัดการกับ ASCII เพียงมานานหลายทศวรรษ

ว่าbashพฤติกรรมยังจะแตกต่างจาก[A-Z]การจับคู่ในช่วงเครื่องมือ GNU อื่น ๆ เช่นในการแสดงออกปกติ GNU (ในgrep/ sed... ) หรือในขณะที่fnmatch()find -name

นอกจากนี้ยังหมายความว่าสิ่งที่[A-Z]ตรงกันต่างกันไปตามสภาพแวดล้อมกับระบบปฏิบัติการและรุ่นของระบบปฏิบัติการ ความจริงที่[A-Z]ตรงกับÁ แต่ไม่ใช่Źนั้นก็ไม่ได้ผลเช่นกัน

สำหรับzsh/ yashเราใช้ลำดับการจัดเรียงที่แตกต่างกัน แทนที่จะพึ่งพาความคิดของผู้ใช้เกี่ยวกับลำดับตัวอักษรเราใช้ค่ารหัสจุดอักขระ มันมีประโยชน์ในการเข้าใจง่าย แต่จากจุดที่มีประโยชน์น้อยนอกเหนือจาก ASCII มันไม่ได้มีประโยชน์มาก [A-Z]ตรงกับตัวอักษรตัวพิมพ์ใหญ่ภาษาอังกฤษแบบอเมริกัน 26 ตัว[0-9]ตรงกับตัวเลขทศนิยม มีจุดรหัสใน Unicode ที่เป็นไปตามลำดับของตัวอักษรบางตัว แต่นั่นไม่ใช่แบบทั่วไปและไม่สามารถเป็นแบบทั่วไปได้อย่างไรก็ตามคนอื่นที่ใช้สคริปต์เดียวกันไม่จำเป็นต้องเห็นด้วยกับลำดับตัวอักษร

สำหรับเชลล์แบบดั้งเดิมและ mksh ให้ใช้งานไม่ได้ (ตอนนี้คนส่วนใหญ่ใช้อักขระหลายไบต์) แต่ส่วนใหญ่เป็นเพราะพวกเขายังไม่รองรับหลายไบต์ การเพิ่มการสนับสนุนหลายไบต์ให้กับเชลล์เช่นนี้bashและzshเป็นความพยายามอย่างมากและยังคงดำเนินอยู่ yash(เชลล์ญี่ปุ่น) เริ่มแรกด้วยการสนับสนุนหลายไบต์ตั้งแต่เริ่มต้น

วิธีการของ ksh93 มีประโยชน์ที่จะสอดคล้องกับการแสดงออกปกติของระบบหรือ fnmatch () (หรืออย่างน้อยก็ปรากฏเป็นอย่างน้อยในระบบ GNU) ที่นั่นจะไม่ทำลายความคาดหวังของบางคนเนื่องจาก[A-Z]ไม่มีตัวอักษรตัวพิมพ์เล็ก[A-Z]รวมถึงÉ(และÁ แต่ไม่ใช่Ź) มันไม่สอดคล้องกับคำสั่งsortหรือโดยทั่วไปstrcoll()


1
หากคุณพูดถูกสิ่งนี้สามารถควบคุมผ่านตัวแปร LC_ * ดูเหมือนจะมีเหตุผลที่แตกต่าง
schily

1
@cuonglm ชอบมากกว่าmksh(ทั้งคู่มาจาก pdksh) posh -c $'case Ó in [É-Ź]) echo yes; esac'ไม่มีอะไรคืน
Stéphane Chazelas

2
@ schily ฉันพูดถึงsortเพราะbashglobs จะขึ้นอยู่กับการเรียงลำดับตัวอักษร ขณะนี้ฉันไม่สามารถเข้าถึงเวอร์ชันเก่าbashได้ แต่ฉันสามารถตรวจสอบได้ในภายหลัง มันแตกต่างกันแล้ว?
Stéphane Chazelas

1
ให้ฉันพูดถึงอีกครั้ง: zsh, POSIX-ksh88, ksh93t + Bourne Shell ทั้งหมดทำงานในลักษณะเดียวกับที่ฉันคาดไว้ Bash เป็นเชลล์เพียงตัวเดียวที่ทำงานแตกต่างกันและ bash ไม่สามารถควบคุมได้ผ่านโลแคลในกรณีนี้
schily

2
@ schily โปรดทราบว่า\xFFมีไบต์ 0xFF ไม่ใช่ตัวอักษร U + 00FF ( ÿตัวเองเข้ารหัสเป็น 0xC3 0xBF) เพียงอย่างเดียวไม่ได้รูปแบบอักขระที่ถูกต้องดังนั้นฉันไม่สามารถดูว่าทำไมมันควรจะจับคู่โดย\xFF [É-Ź]
Stéphane Chazelas

9

มันตั้งใจและบันทึกไว้ในbashเอกสารส่วนรูปแบบที่ตรงกัน การแสดงออกช่วง[X-Y]จะรวมตัวละครใด ๆ ระหว่างXและการYใช้ลำดับการเรียงและชุดอักขระปัจจุบันของสถานที่:

LC_ALL=en_US.utf8 bash -c 'case b in [A-Z]) echo yes; esac' 
yes

คุณสามารถดูbเรียงลำดับระหว่างAและZในen_US.utf8โลแคล

คุณมีตัวเลือกเพื่อป้องกันพฤติกรรมนี้:

# Setting LC_ALL or LC_COLLATE to C
LC_ALL=C bash -c 'echo [A-Z]*'

# Or using POSIX character class
LC_ALL=C bash -c 'echo [[:upper:]]*'

หรือเปิดใช้งานglobasciiranges(ด้วย bash 4.3 ขึ้นไป):

bash -O globasciiranges -c 'echo [A-Z]*'

6

ฉันสังเกตพฤติกรรมนี้ในอินสแตนซ์ Amazon EC2 ใหม่ เนื่องจาก OP ไม่ได้เสนอMCVEฉันจะโพสต์หนึ่งรายการ:

$ cd $(mktemp -d)
$ touch foo
$ echo [A-Z]*     # prepare for a surprise!
foo

$ echo $BASH_VERSION
4.1.2(1)-release
$ uname -a
Linux spinup-tmp12 3.14.27-25.47.amzn1.x86_64 #1 SMP Wed Dec 17 18:36:15 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

$ env | grep LC_  # no locale, let's set one
$ LC_ALL=C
$ echo [A-Z]*
[A-Z]*

$ unset LC_ALL    # ok, good. what if we go back to no locale?
$ echo [A-Z]*
foo

ดังนั้นการไม่มีLC_*ชุดของฉันนำไปสู่ทุบตี 4.1.2 (1) - ปล่อยบน Linux เพื่อสร้างพฤติกรรมที่ผิดปกติอย่างเห็นได้ชัด ฉันสามารถสลับพฤติกรรมแปลก ๆ ได้อย่างน่าเชื่อถือโดยการตั้งค่าและยกเลิกการตั้งค่าตัวแปรโลแคลที่เกี่ยวข้อง ไม่น่าแปลกใจพฤติกรรมนี้ปรากฏขึ้นอย่างสม่ำเสมอผ่านการส่งออก:

$ export LC_ALL=C
$ bash
$ echo [A-Z]*
[A-Z]*
$ exit
$ echo $SHLVL
1
$ unset LC_ALL
$ bash
$ echo [A-Z]*
foo

ในขณะที่ฉันเห็นทุบตีพฤติกรรมตามที่Stéphane "Shellshock" Chazelas ตอบฉันคิดว่าเอกสารทุบตีเกี่ยวกับการจับคู่รูปแบบนั้นมีข้อผิดพลาด:

ตัวอย่างเช่นในโลแคลC เริ่มต้น '[a-dx-z]' เทียบเท่ากับ '[abcdxyz]'

ฉันอ่านประโยคนั้น (เน้นการเน้นของฉัน) ว่า "ถ้าไม่ได้ตั้งค่าตัวแปรที่เกี่ยวข้องนั้น bash จะใช้ค่าเริ่มต้นเป็น C locale" Bash ดูเหมือนจะไม่ทำเช่นนั้น แต่ดูเหมือนว่าจะเป็นการกำหนดค่าเริ่มต้นให้กับโลแคลซึ่งอักขระจะถูกเรียงลำดับตามพจนานุกรมที่มีการพับส่วนของ diacritic:

$ echo [A-E]*
[A-E]*
$ echo [A-F]*
foo
$ touch "évocateur"
$ echo [A-F]*
foo évocateur

ฉันคิดว่ามันจะดีสำหรับการทุบตีเพื่อบันทึกว่ามันจะทำงานอย่างไรเมื่อไม่ได้กำหนดไว้LC_*(โดยเฉพาะLC_CTYPEและLC_COLLATE) แต่ในเวลาเดียวกันฉันจะแบ่งปันภูมิปัญญา :

... คุณต้องระมัดระวังอย่างมากกับ [ช่วงของตัวละคร] เพราะพวกเขาจะไม่ให้ผลลัพธ์ที่คาดหวังเว้นแต่จะได้รับการกำหนดค่าอย่างเหมาะสม สำหรับตอนนี้คุณควรหลีกเลี่ยงการใช้และใช้คลาสของตัวละครแทน

และ

หากคุณเหมาะสมจริง ๆ และ / หรือกำลังเขียนสคริปต์สำหรับสภาพแวดล้อมแบบหลายตำแหน่งที่ตั้งอาจเป็นวิธีที่ดีที่สุดเพื่อให้แน่ใจว่าคุณทราบตัวแปรโลแคลของคุณเมื่อคุณจับคู่ไฟล์หรือเพื่อให้แน่ใจว่าคุณกำลังเข้ารหัส วิธีทั่วไปอย่างสมบูรณ์


อัปเดตตามความคิดเห็น @ G-Man เรามาดูสิ่งที่เกิดขึ้นอย่างลึกซึ้ง:

$ env | grep LANG
LANG=en_US.UTF-8

อ้า! นั่นอธิบายการเปรียบเทียบที่เห็นก่อนหน้านี้ เอาตัวแปรโลแคลทั้งหมดออก:

$ unset LANG LANGUAGE LC_ALL
$ env | grep 'LC_|LANG'
$ echo [A-Z]*
[A-Z]*

เราจะไปที่นั่น. ตอนนี้ทุบตีทำงานอย่างสอดคล้องกับเอกสารในระบบ Linux นี้ ถ้าใด ๆ ของตัวแปรที่เกิดเหตุมีการตั้งค่า ( LANGUAGE, LANG, LC_COLLATE, LC_CTYPE, LC_ALLฯลฯ ) แล้วทุบตีใช้เหล่านั้นตามคู่มือของมัน มิฉะนั้น bash จะกลับไปที่ C

Wooledge ทุบตีคำถามที่พบบ่อยได้นี้จะพูดว่า:

ในระบบ GNU เมื่อเร็ว ๆ นี้ตัวแปรจะถูกใช้ตามลำดับนี้ หากตั้งค่า LANGUAGE ให้ใช้สิ่งนั้นยกเว้น LANG จะถูกตั้งค่าเป็น C ซึ่งในกรณีนี้ LANGUAGE จะถูกละเว้น นอกจากนี้บางโปรแกรมก็ไม่ได้ใช้ LANGUAGE เลย มิฉะนั้นหากตั้งค่า LC_ALL ให้ใช้สิ่งนั้น มิฉะนั้นหากมีการตั้งค่าตัวแปร LC_ * เฉพาะที่ครอบคลุมการใช้งานนี้ให้ใช้สิ่งนั้น (ตัวอย่างเช่น LC_MESSAGES ครอบคลุมข้อความแสดงข้อผิดพลาด) มิฉะนั้นให้ใช้ LANG

ดังนั้นปัญหาที่ชัดเจนทั้งในการใช้งานและเอกสารสามารถอธิบายได้โดยดูที่ผลรวมทั้งหมดของตัวแปรการขับขี่ในที่เกิดเหตุ


หากไม่มี LC_variable และ bash ไม่ทำงานตามที่บันทึกไว้สำหรับCโลแคลนี่เป็นข้อผิดพลาด
schily

1
@bishop: (1) Typo: MVCE ควรเป็น MCVE (2) ถ้าคุณต้องการตัวอย่างของคุณจะเสร็จสมบูรณ์คุณควรเพิ่มหรือenv | grep LANG echo "$LANG"
G-Man กล่าวว่า 'Reinstate Monica'

@schily การตรวจสอบเพิ่มเติมทำให้ฉันมั่นใจว่าไม่มีข้อผิดพลาดในเอกสารหรือการดำเนินการในระบบ Linux นี้
บิชอป

@ G-Man ขอบคุณ! ฉันลืมไปLANGแล้ว ด้วยคำใบ้นั้นทุกคำอธิบาย
บิชอป

LANG ได้รับการแนะนำในปี 1988 โดย Sun สำหรับความพยายามในการแปลครั้งแรกก่อนที่พวกเขาจะค้นพบว่าตัวแปรตัวเดียวนั้นไม่เพียงพอ วันนี้มันใช้เป็นทางเลือกและ LC_ALL ถูกใช้เป็นบังคับเขียนทับ
schily

3

โลแคลสามารถเปลี่ยนแปลงสิ่งที่จับคู่อักขระ[A-Z]ได้ ใช้

(LC_ALL=C; rm [A-Z]*)

เพื่อกำจัดอิทธิพล (ฉันใช้ subshell เพื่อ จำกัด การเปลี่ยนแปลง)


มันใช้งานไม่ได้มันยังคงตรงกับตัวอักษรทั้งหมด
schily

7
สิ่งนี้จะไม่ทำงานเพราะ glob เสร็จสิ้นก่อนดำเนินการ rm ลองexport LC_ALL=Cก่อน
cuonglm

ขออภัยคุณเข้าใจคำถามที่เกี่ยวข้องกับการทุบตีและไม่ตอบคำถาม
schily

@schily: ใช่ฉันผิดคุณต้องแยกงบ ตรวจสอบการอัปเดต
choroba

2

ดังที่ได้กล่าวไปแล้วนี่เป็นปัญหา "การเรียงลำดับ"

ช่วง az อาจมีตัวอักษรตัวพิมพ์ใหญ่ในบางแห่ง:

     aAbBcC[...]xXyYzZ
     |              |
from a      to      z

วิธีการแก้ไขที่ถูกต้องเนื่องจากทุบตี 4.3 คือการตั้งค่าตัวเลือกglobasciiranges:

shopt -s globasciiranges

เพื่อให้ทุบตีการกระทำราวกับว่าLC_COLLATE=Cได้รับการตั้งค่าในช่วงglob กลม


-6

ดูเหมือนว่าฉันพบคำตอบที่ถูกต้องสำหรับคำถามของฉันเอง:

Bash เป็นรถบั๊กกี้เนื่องจากไม่สามารถจัดการได้ด้วยภาษาของตนเอง ดังนั้นการตั้งค่า LC_ * ในกระบวนการ bash จึงไม่มีผลกระทบในกระบวนการเชลล์นั้น

หากคุณตั้งค่า LC_COLLATE = C จากนั้นเริ่มการทุบตีอีกครั้งการทำงานแบบกลมจะเป็นไปตามที่คาดไว้ในกระบวนการทุบตีใหม่


2
ไม่อยู่ในข้อผิดพลาดใด ๆ ของฉัน
ความโกลาหล

2
ฉันไม่ทำซ้ำสิ่งนี้ใน bash ทุกรุ่นบนเครื่องของฉันดูเหมือนว่าคุณจะทำไม่exportถูกต้อง
Chris Down

ดังนั้นคุณเชื่อว่าสิ่งที่ถูกส่งออกอย่างถูกต้องดังนั้นมันส่งผลกระทบต่อกระบวนการทุบตีใหม่จะไม่ถูกส่งออกอย่างถูกต้อง?
schily

4
การจัดการสภาพแวดล้อมของ Solaris นั้นมีข้อบกพร่องฉาวโฉ่ดังนั้นฉันจะไม่แปลกใจหาก "ข้อบกพร่อง" ในการทุบตีคือการขาดวิธีแก้ปัญหาเฉพาะของ Solaris
ฮอบส์

1
@schily: คุณมีการอ้างอิงที่ต้องการเปลี่ยนแปลงตัวแปร LC_ * ภายในเชลล์หรือไม่เพื่อให้เชลล์อัพเดตสถานะโลแคลของตนเอง ฉันจะคิดตรงกันข้าม โดยเฉพาะอย่างยิ่งสำหรับเชลล์ที่รันสคริปต์การเปลี่ยนโลแคลกลางทางผ่านการวิเคราะห์ / การดำเนินการของสคริปต์จะไม่ได้มีพฤติกรรมที่กำหนดไว้อย่างดีเนื่องจากสคริปต์เป็นไฟล์ข้อความและ "ไฟล์ข้อความ" มีความหมายเฉพาะในบริบทของ การเข้ารหัสอักขระเดี่ยว
..
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.