ความแตกต่างระหว่างa[bc]d
และa{b,c}d
คืออะไร? ทำไมคนใช้a{b,c}d
เมื่อมีอยู่แล้วa[bc]d
?
ls
และคุณเคยลองใช้อักขระตัวเดียวพวกเขาจะปรากฏขึ้นเพื่อใช้งานเหมือนกัน
ความแตกต่างระหว่างa[bc]d
และa{b,c}d
คืออะไร? ทำไมคนใช้a{b,c}d
เมื่อมีอยู่แล้วa[bc]d
?
ls
และคุณเคยลองใช้อักขระตัวเดียวพวกเขาจะปรากฏขึ้นเพื่อใช้งานเหมือนกัน
คำตอบ:
ทั้งสองแตกต่างกันมาก
a[bc]d
เป็นรูปแบบชื่อไฟล์ (ในเชลล์อื่นที่ไม่ใช่fish
) มันจะขยายไปยังชื่อไฟล์ ทั้งสองabd
และacd
หากเป็นชื่อของไฟล์ที่มีอยู่ในไดเรกทอรีปัจจุบัน
[...]
ส่วนหนึ่งคือการแสดงออกในวงเล็บที่ตรงกับตัวอักษรตัวเดียวจากที่ระบุไว้ (หรือเรียงองค์ประกอบเมื่อช่วงที่จะถูกรวม) เพื่อให้ตรงกับรูปแบบa[bc]d
ตัวอักษรระหว่างสตริงa
และd
ในชื่อไฟล์ต้องเป็นอย่างใดอย่างหนึ่งหรือb
c
หากabd
มีอยู่ แต่acd
ไม่มีอยู่ก็จะขยายไปถึงabd
และกลับกันเท่านั้น
หากไม่มีabd
หรือacd
มีอยู่ขึ้นอยู่กับเปลือกและตัวเลือกก็จะก่อให้เกิดข้อผิดพลาด (เดิม Unix sh
, (t)csh
, zsh
, fish
, bash -O failglob
) และอาจจะออกจากเปลือกหรือปล่อยunexpanded¹รูปแบบ (บอร์นเหมือนและrc
เหมือนเปลือกหอย) หรือขยายตัวออกไป ไม่มีอะไร ( bash/zsh/yash -o nullglob
บางรุ่นที่เก่ากว่าของfish
Unix ดั้งเดิมsh
และ(t)csh
หากมีการจับคู่อื่น globs ในคำสั่งเดียวกัน)
a{b,c}d
เป็นการยืดส่วนขยาย (ในเชลล์ที่สนับสนุนสิ่งเหล่านี้) มันจะขยายไปยังทั้งสองสาย และabd
acd
{...}
ส่วนหนึ่งเป็นชุดที่คั่นด้วยจุลภาคของสตริง (ในตัวอย่างนี้ในเปลือกบางอย่างมันก็อาจจะเป็นช่วงเช่นa..k
หรือ20..25
หรือสูงขึ้นคนที่ชอบ00..20..2
หรือ0..20..2%02d
) และการขยายตัวที่มีการคำนวณโดยรวมของแต่ละสายเหล่านี้ด้วยขนาบข้าง สตริงและa
d
สตริงเหล่านี้อาจมีความยาวมากกว่าหนึ่งอักขระและยังสามารถขยายการรั้งได้ด้วยตนเอง
การขยายตัวเกิดขึ้นไม่ว่าสตริงเหล่านี้จะสอดคล้องกับชื่อไฟล์ที่มีอยู่หรือไม่ก็ตาม
หากคุณกำลังสร้างสตริงใช้การขยายรั้ง หากคุณกำลังจับคู่ชื่อไฟล์ให้ใช้รูปแบบชื่อไฟล์
¹ในกรณีนี้a[bc]d
อาจเป็นชื่อของไฟล์ที่มีอยู่ซึ่งเป็นสาเหตุที่อาจเป็นอันตรายที่จะใช้สิ่งต่าง ๆ เช่นrm -f ./*.[ch]
ในเชลล์เหล่านั้นและrm -f ./*.{c,h}
มีปัญหาน้อยกว่า
a{b,c}d
ที่b
และc
ชิ้นส่วนที่ไม่จำเป็นต้องเป็นตัวอักษรเดียว; ex{ten,ci}sion
เช่น ในขณะที่ex[tenci]sion
หรืออะไรก็ตามที่จะตรงกับหนึ่งในตัวอักษรเหล่านี้
a[bc]d
คือการจับคู่รูปแบบและเป็นส่วนหนึ่งของมาตรฐาน POSIX ใน POSIX สิ่งนี้ถูกนำมาใช้เป็น "การแสดงออกวงเล็บรูปแบบ" มีการบันทึกไว้ในส่วน 2.13 ของคู่มือ
เมื่อไม่พูดถึงและอยู่นอกนิพจน์วงเล็บอักขระสามตัวต่อไปนี้จะมีความหมายพิเศษในการกำหนดรูปแบบ:
?
เครื่องหมายคำถามเป็นรูปแบบที่จะจับคู่กับตัวละครใด ๆ
* * * *เครื่องหมายดอกจันเป็นรูปแบบที่จะจับคู่อักขระหลายตัวตามที่อธิบายไว้ในรูปแบบที่ตรงกับอักขระหลายตัว
[วงเล็บเปิดจะแนะนำนิพจน์วงเล็บของลวดลาย
ส่วนที่ 2.13.3 ยังกล่าวถึงสิ่งที่มันทำงานแตกต่างจากสิ่งที่เราคาดหวังสำหรับ regex ปกติเมื่อมันถูกใช้สำหรับการขยายชื่อไฟล์ (เน้นโดยฉัน)
กฎที่อธิบายไว้ในรูปแบบการจับคู่อักขระเดี่ยวและรูปแบบการจับคู่หลายอักขระมีคุณสมบัติตามกฎต่อไปนี้ที่ใช้เมื่อใช้สัญกรณ์การจับคู่รูปแบบสำหรับการขยายชื่อไฟล์:
อักขระเครื่องหมายทับในชื่อพา ธ ต้องจับคู่อย่างชัดเจนโดยใช้เครื่องหมายทับหนึ่งหรือหลายเครื่องหมายในรูปแบบ มันจะต้องไม่ถูกจับคู่โดยเครื่องหมายดอกจันหรือเครื่องหมายคำถามเครื่องหมายคำถามหรือโดยการแสดงออกวงเล็บ เครื่องหมายทับในรูปแบบจะต้องระบุก่อนที่จะแสดงออกวงเล็บ; ดังนั้นเครื่องหมายสแลชไม่สามารถรวมอยู่ในนิพจน์วงเล็บรูปแบบที่ใช้สำหรับการขยายชื่อไฟล์ หากพบเครื่องหมายทับตามอักขระวงเล็บเหลี่ยมเปิดที่ไม่ใช้ค่า Escape ก่อนพบวงเล็บเหลี่ยมปิดที่สอดคล้องกันวงเล็บเหลี่ยมเปิดจะต้องถือเป็นอักขระทั่วไป ตัวอย่างเช่นรูปแบบ
"a[b/c]d"
ไม่ตรงกับ pathnames เช่นหรือabd
a/d
มันตรงกับชื่อพา ธ ของตัวอักษรa[b/c]d
เท่านั้น
a{b,c}d
เป็นการจัดฟันส่วนขยายไม่อยู่ในข้อมูลจำเพาะโดย POSIX นี่คือส่วนที่เกี่ยวข้องจากคู่มือทุบตี(เน้นโดยฉัน):
การขยายรั้งเป็นกลไกที่อาจสร้างสตริงโดยพลการ กลไกนี้จะคล้ายกับการขยายตัวของชื่อไฟล์ (ดูการขยายตัวชื่อไฟล์) แต่ชื่อไฟล์ที่สร้างขึ้นไม่จำเป็นต้องมีอยู่ รูปแบบที่จะรั้งขยายในรูปแบบของคำนำตัวเลือก ตามด้วยชุดของสตริงที่คั่นด้วยเครื่องหมายจุลภาคหรือการแสดงออกตามลำดับระหว่างคู่ของวงเล็บปีกกาตามด้วยคำลงท้ายเสริม คำนำจะถูกนำหน้าไปยังแต่ละสตริงที่มีอยู่ภายในเครื่องหมายปีกกาและจากนั้นคำลงท้ายจะต่อท้ายแต่ละสตริงผลลัพธ์โดยขยายจากซ้ายไปขวา
ตามความเห็นของ @mosvy สิ่งนี้ปรากฏตัวครั้งแรกcsh
แต่พฤติกรรมในbash
นั้นแตกต่างจากcsh
และเชลล์อื่น ๆ การขยายเครื่องมือจัดฟันชนิดนี้ก็มีอยู่glob(3)
เช่นกัน
มีการขยายเครื่องหมายปีกกาประเภทอื่น{a..z}
ที่ปรากฏหลังbash
3.0 เท่านั้นและมีการเพิ่มเครื่องหมายเพิ่มเติมในbash
4.0
ในเชลล์ที่เปิด globbing ดำเนินการในโฟลเดอร์ว่างผลลัพธ์ต่อไปนี้จะถูกส่งกลับ
$ echo a[bc]d
a[bc]d
$ echo a{b,c}d
abd acd
ในการตอบสนองต่อความคิดเห็นของ @ Jesse_b หากคุณอยู่ในเชลล์เชิงโต้ตอบและทั้งคู่นำไปใช้a[bc]d
จะเป็นการพิมพ์ปัญหาน้อยลง grep pattern [ab][12].txt
เช่น
csh
bash
มันยังมีอยู่ในฟังก์ชันไลบรารี glob (3) ความแตกต่างคือbash
มันถูกใช้งานก่อนการขยายตัวอื่น: a=A; ab=A/B; ac=A/C; echo $a{b,c}
จะทำงานใน bash ต่างจาก shell อื่น ๆ
command a[bc]d
?