ไม่มีเหตุผลที่ดีว่าทำไม
[[ $a = a|b ]]
ควรรายงานข้อผิดพลาดแทนที่จะทดสอบว่า $ a เป็นa|bสตริงหรือ[[ $a =~ a|b ]]ไม่ในขณะที่ไม่ส่งคืนข้อผิดพลาด
เหตุผลเดียวก็|คือโดยทั่วไปแล้ว (ภายนอกและภายใน[[ ... ]]) เป็นอักขระพิเศษ ใน[[ $a =ตำแหน่งนั้นbashคาดว่าจะมีโทเค็นประเภทหนึ่งซึ่งเป็นWORDปกติเช่นอาร์กิวเมนต์หรือเป้าหมายของการเปลี่ยนเส้นทางในบรรทัดคำสั่งเชลล์ปกติ (แต่ราวกับว่าextglobมีการเปิดใช้งานตัวเลือกตั้งแต่ทุบตี 4.1)
(โดยWORDที่นี่ฉันหมายถึงคำในไวยากรณ์เชลล์สมมุติฐานเช่นที่อธิบายโดยข้อกำหนด POSIXซึ่งเป็นสิ่งที่เชลล์จะแยกวิเคราะห์เป็นโทเค็นเดียวในบรรทัดคำสั่งเชลล์แบบง่ายไม่ใช่คำจำกัดความอื่น ๆ เช่นภาษาอังกฤษ หนึ่งในลำดับของตัวอักษรหรือลำดับของอักขระที่ไม่ใช่ระยะห่างที่. foo"bar baz", $(echo x y)มีสองเช่นWORD s)
ในบรรทัดคำสั่งเชลล์ปกติ:
echo a|b
เป็นประปาecho a ไม่ได้เป็นคำก็สามราชสกุลกคำเป็นโทเค็นและคำโทเค็นba|ba |b
เมื่อนำมาใช้[[ $a = a|b ]], bashคาดว่าจะมีคำที่จะได้รับ ( a) แต่แล้วก็พบว่าไม่คาดคิด|โทเค็นซึ่งทำให้เกิดข้อผิดพลาด
ที่น่าสนใจbashไม่บ่นใน:
[[ $a = a||b ]]
เพราะตอนนี้มันเป็นaโทเค็นแล้วตามด้วย||โทเค็นตามด้วยbดังนั้นจึงแยกวิเคราะห์แบบเดียวกับ:
[[ $a = a || b ]]
ซึ่งการทดสอบนั่น$aคือaหรือว่าbสตริงไม่ว่างเปล่า
ตอนนี้ใน:
[[ $a =~ a|b ]]
bashไม่สามารถมีกฎการแยกวิเคราะห์เดียวกัน มีกฎการแยกเดียวกันจะหมายความว่าข้างต้นจะให้ข้อผิดพลาดและที่หนึ่งจะต้องพูดว่า|เพื่อให้แน่ใจว่าa|bเป็นหนึ่งคำ แต่เนื่องจากทุบตี 3.2 หากคุณ:
[[ $a =~ 'a|b' ]]
ไม่ตรงกับa|bregexp อีกต่อไปแต่เทียบกับa\|bregexp นั่นคือการอ้างเปลือกมีผลข้างเคียงของการลบความหมายพิเศษของผู้ประกอบการ regexp มันเป็นคุณสมบัติดังนั้นพฤติกรรมจะคล้ายกับ[[ $a = "?" ]]รูปแบบหนึ่ง แต่รูปแบบสัญลักษณ์ (ใช้ใน[[ $a = pattern ]]) คือเชลล์WORDS (ใช้ในตัวอย่างเช่น) ในขณะที่ regexps ไม่ใช่
ดังนั้นbashมีการรักษาทุกผู้ประกอบการ regexp ขยายที่เป็นอย่างอื่นได้ตามปกติอักขระพิเศษเปลือกเช่น|, (, )แตกต่างกันเมื่อแยกวิเคราะห์ข้อโต้แย้งของที่=~ผู้ประกอบการ
ยังทราบว่าในขณะที่
[[ $a =~ (ab)*c ]]
ตอนนี้ใช้งานได้
[[ $a =~ [)}] ]]
ไม่ คุณต้องการ:
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
ซึ่งในเวอร์ชันก่อนหน้านี้bashจะจับคู่กับแบ็กสแลชไม่ถูกต้อง อันนั้นได้รับการแก้ไขแล้ว แต่
[[ $a =~ [^]')'] ]]
ไม่ได้ตรงกับในทับขวาอย่างที่ควรเช่น เพราะbashล้มเหลวที่จะตระหนักว่า)อยู่ภายในวงเล็บเพื่อหนี)ที่จะส่งผลใน[^]\)]regexp ที่ตรงกับตัวอักษรใด ๆ แต่], และ\)
ksh93 มีข้อบกพร่องที่เลวร้ายกว่ามากที่ด้านหน้า
ในzshมันเป็นคำของเชลล์ปกติที่คาดหวังและการอ้างอิงตัวดำเนินการ regexp ไม่มีผลต่อความหมายของตัวดำเนินการ regexp
[[ $a =~ 'a|b' ]]
คือการจับคู่กับa|bregexp
นั่นหมายความว่า=~สามารถเพิ่มไปยังคำสั่ง[/ ได้test:
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(ยังใช้งานyashได้=~ต้องมีการอ้างถึงในzshฐานะที่=somethingเป็นตัวดำเนินการเชลล์พิเศษที่นั่น)
ทุบตี 3.1 zshใช้ในการประพฤติชอบ มันเปลี่ยนใน 3.2 สันนิษฐานว่าเพื่อให้สอดคล้องกับksh93(แม้ว่าbashเป็นเปลือกที่แรกขึ้นมาด้วย[[ =~ ]]) แต่คุณยังสามารถทำBASH_COMPAT=31หรือshopt -s compat31จะกลับไปสู่พฤติกรรมที่ผ่านมา (ยกเว้นในขณะที่[[ $a =~ a|b ]]จะกลับข้อผิดพลาดในbash3.1 ก็ไม่ได้อีกต่อไป ในbash -O compat31ด้วยรุ่นที่ใหม่กว่าbash)
หวังว่ามันจะอธิบายได้อย่างชัดเจนว่าทำไมฉันถึงพูดว่ากฎนั้นสับสนและทำไมต้องใช้
[[ $a =~ $var ]]
ช่วยรวมกับความสามารถในการพกพาไปยังเชลล์อื่น ๆ
|เป็นพิเศษ) อยู่บนโดยค่าเริ่มต้น[[ $var = $pattern ]]ในด้านขวามือของ มันจะน่าสนใจที่จะแยกรุ่นและshoptการกำหนดค่าตัวเลือกที่พฤติกรรมนี้เห็น - ถ้าเป็นเพียงที่ที่extglobเปิดอยู่โดยค่าเริ่มต้นหรือการกำหนดค่าที่ชัดเจนดีเรามี