อะไรคือความแตกต่างระหว่าง `a [bc] d` (วงเล็บ) และ` a {b, c} d` (เครื่องหมายปีกกา)?


28

ความแตกต่างระหว่างa[bc]dและa{b,c}dคืออะไร? ทำไมคนใช้a{b,c}dเมื่อมีอยู่แล้วa[bc]d?


ที่บอกให้คุณใช้command a[bc]d?
Jesse_b

3
มันมีประโยชน์อย่างแน่นอนหากเข้าใจถูกต้อง
Weijun Zhou

7
ฉันเดาว่าฉันไม่เข้าใจว่าความสับสนระหว่างคนทั้งสองเกิดขึ้นได้อย่างไร
Jesse_b

ฉันได้รับการถามอย่างชัดเจนจากผู้ร่วมงานที่ไม่ค่อยคุ้นเคยกับ Linux ในเรื่องนี้ถึงแม้จะไม่นานมานี้
Weijun Zhou

@Jesse_b หากคุณเคยลองใช้การดำเนินการกับไฟล์เช่นlsและคุณเคยลองใช้อักขระตัวเดียวพวกเขาจะปรากฏขึ้นเพื่อใช้งานเหมือนกัน
Nacht - Reinstate Monica

คำตอบ:


43

ทั้งสองแตกต่างกันมาก

a[bc]dเป็นรูปแบบชื่อไฟล์ (ในเชลล์อื่นที่ไม่ใช่fish) มันจะขยายไปยังชื่อไฟล์ ทั้งสองabdและacdหากเป็นชื่อของไฟล์ที่มีอยู่ในไดเรกทอรีปัจจุบัน

  • [...]ส่วนหนึ่งคือการแสดงออกในวงเล็บที่ตรงกับตัวอักษรตัวเดียวจากที่ระบุไว้ (หรือเรียงองค์ประกอบเมื่อช่วงที่จะถูกรวม) เพื่อให้ตรงกับรูปแบบa[bc]dตัวอักษรระหว่างสตริงaและdในชื่อไฟล์ต้องเป็นอย่างใดอย่างหนึ่งหรือbc

  • หากabdมีอยู่ แต่acdไม่มีอยู่ก็จะขยายไปถึงabdและกลับกันเท่านั้น

  • หากไม่มีabdหรือacdมีอยู่ขึ้นอยู่กับเปลือกและตัวเลือกก็จะก่อให้เกิดข้อผิดพลาด (เดิม Unix sh, (t)csh, zsh, fish, bash -O failglob) และอาจจะออกจากเปลือกหรือปล่อยunexpanded¹รูปแบบ (บอร์นเหมือนและrcเหมือนเปลือกหอย) หรือขยายตัวออกไป ไม่มีอะไร ( bash/zsh/yash -o nullglobบางรุ่นที่เก่ากว่าของfishUnix ดั้งเดิมshและ(t)cshหากมีการจับคู่อื่น globs ในคำสั่งเดียวกัน)

a{b,c}dเป็นการยืดส่วนขยาย (ในเชลล์ที่สนับสนุนสิ่งเหล่านี้) มันจะขยายไปยังทั้งสองสาย และabdacd

  • {...}ส่วนหนึ่งเป็นชุดที่คั่นด้วยจุลภาคของสตริง (ในตัวอย่างนี้ในเปลือกบางอย่างมันก็อาจจะเป็นช่วงเช่นa..kหรือ20..25หรือสูงขึ้นคนที่ชอบ00..20..2หรือ0..20..2%02d) และการขยายตัวที่มีการคำนวณโดยรวมของแต่ละสายเหล่านี้ด้วยขนาบข้าง สตริงและa dสตริงเหล่านี้อาจมีความยาวมากกว่าหนึ่งอักขระและยังสามารถขยายการรั้งได้ด้วยตนเอง

  • การขยายตัวเกิดขึ้นไม่ว่าสตริงเหล่านี้จะสอดคล้องกับชื่อไฟล์ที่มีอยู่หรือไม่ก็ตาม

หากคุณกำลังสร้างสตริงใช้การขยายรั้ง หากคุณกำลังจับคู่ชื่อไฟล์ให้ใช้รูปแบบชื่อไฟล์


¹ในกรณีนี้a[bc]dอาจเป็นชื่อของไฟล์ที่มีอยู่ซึ่งเป็นสาเหตุที่อาจเป็นอันตรายที่จะใช้สิ่งต่าง ๆ เช่นrm -f ./*.[ch]ในเชลล์เหล่านั้นและrm -f ./*.{c,h}มีปัญหาน้อยกว่า


ขอบคุณสำหรับคำชี้แจง "ถ้ามี Abd อยู่ แต่ไม่ได้เป็น acd มันจะขยายเป็นอับเท่านั้น" ฉันเดาว่าเป็นสิ่งที่ขาดหายไปจากคำตอบของฉัน
Weijun Zhou

9
อีกความแตกต่างที่สำคัญคือว่าในa{b,c}dที่bและcชิ้นส่วนที่ไม่จำเป็นต้องเป็นตัวอักษรเดียว; ex{ten,ci}sionเช่น ในขณะที่ex[tenci]sionหรืออะไรก็ตามที่จะตรงกับหนึ่งในตัวอักษรเหล่านี้
อเล็กซิส

7

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}ที่ปรากฏหลังbash3.0 เท่านั้นและมีการเพิ่มเครื่องหมายเพิ่มเติมในbash4.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เช่น


2
การขยายรั้งไม่ได้เป็น "bashism"; มันปรากฏตัวครั้งแรกในนานก่อนcsh bashมันยังมีอยู่ในฟังก์ชันไลบรารี glob (3) ความแตกต่างคือbashมันถูกใช้งานก่อนการขยายตัวอื่น: a=A; ab=A/B; ac=A/C; echo $a{b,c}จะทำงานใน bash ต่างจาก shell อื่น ๆ
mosvy

ขอขอบคุณ. ฉันจะอัปเดตคำตอบ
Weijun Zhou
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.