test, [, และ [[ (2020)
(jmmv.dev)- ในตระกูล Unix อาจมีไฟล์ปฏิบัติการชื่อเป็นสัญลักษณ์ตัวเดียวคือ
/bin/[และไวยากรณ์ที่ดูเหมือนนิพจน์เงื่อนไขของเชลล์นั้น แท้จริงแล้วทำงานอยู่บนการเรียกคำสั่งและรหัสออกจากโปรแกรม testใช้ประเมินนิพจน์และจะคืนค่า 0 ถ้าเป็นจริง หรือ 1 ถ้าเป็นเท็จ และเมื่อถูกเรียกด้วย[ก็จะตรวจด้วยว่าอาร์กิวเมนต์ตัวสุดท้ายเป็น]หรือไม่- เนื่องจากหลายเชลล์มี คำสั่งแบบ built-in สำหรับ
testและ[ด้วย ข้อความผิดพลาดหรือพฤติกรรมระหว่าง/bin/testภายนอกกับ implementation แบบ built-in ของเชลล์จึงอาจต่างกันได้ - ส่วน
[[ซึ่งเป็นส่วนขยายของ Bash ไม่ใช่คำสั่งภายนอกแต่เป็นไวยากรณ์แบบ built-in จึงใช้กฎที่ต่างจาก[เช่น ในตัวอย่างlong*จะไม่ถูกขยายแบบ glob แต่ถูกเปรียบเทียบเป็นสตริงตามตัวอักษร - สำหรับสคริปต์ที่ต้องการพกพาได้ควรใช้
[แต่ถ้าเป็น Bash โดยเฉพาะ การใช้[[อย่างสม่ำเสมอจะเหมาะกว่า ทั้งนี้ควรเลือกโดยเข้าใจความต่างของกฎการขยายระหว่างสองแบบ
ตัวตนของ /bin/[ และ /bin/test
- บนระบบ Unix อาจมีไฟล์ปฏิบัติการชื่อเป็นสัญลักษณ์ตัวเดียวคือ
/bin/[- คำสั่งตัวอย่าง
ls /bin/?จะแสดง/bin/[
- คำสั่งตัวอย่าง
/bin/[และ/bin/testอาจชี้ไปยังไบนารีเดียวกัน- ในตัวอย่าง ทั้งสองพาธแสดงว่าเป็นไฟล์ที่มี inode และขนาดเดียวกัน
- อย่างไรก็ดี ไม่จำเป็นต้องเป็น hard link บนทุกระบบเสมอไป
testเป็นโปรแกรมในเชลล์สำหรับ ประเมินนิพจน์- เปรียบเทียบสตริง
- เปรียบเทียบตัวเลข
- ตรวจสอบเงื่อนไขของไฟล์
- ถ้าผลการประเมินเป็นจริงจะคืนรหัสออกจากโปรแกรม 0 ถ้าเป็นเท็จจะคืน 1
ทำไม [ จึงทำงานเหมือนคำสั่ง
test a = bดูไม่ค่อยเหมือนนิพจน์เงื่อนไข แต่ถ้าเขียนตรรกะเดียวกันเป็น[ a = b ]จะดูคุ้นเคยมากกว่า- แม้
[จะดูเหมือนเป็นไวยากรณ์พิเศษ แต่จริง ๆ แล้วเป็นการเรียกคำสั่งif [ a = b ]; then ... fiคือการรันคำสั่ง[แล้วตรวจรหัสออกจากโปรแกรม- เมื่อเรียกด้วย
[โปรแกรมจะตรวจว่าอาร์กิวเมนต์สุดท้ายเป็นวงเล็บเหลี่ยมปิด]หรือไม่
- คำสั่ง
ifไม่ได้ตีความนิพจน์เงื่อนไขโดยตรง แต่แยกทางตาม รหัสออกจากโปรแกรมของคำสั่ง ที่ส่งเข้าไปtest a = a; echo $?คือ0test a = b; echo $?คือ1[ a = a ]; echo $?คือ0[ a = b ]; echo $?คือ1
- ในบริบทเดียวกัน
trueและfalseก็อาจมองได้ว่าเป็นไบนารีช่วยที่คืนรหัสออกจากโปรแกรม
ความต่างระหว่างไบนารีภายนอกกับคำสั่งแบบ built-in ของเชลล์
testและ[ถูกใช้บ่อยในเชลล์สคริปต์ ดังนั้นเชลล์ส่วนใหญ่จึงมี implementation แบบ built-in ของมันด้วย- แม้รับอินพุตเดียวกัน ไบนารีภายนอกกับคำสั่ง built-in ของเชลล์ก็อาจให้ผลลัพธ์ต่างกัน
/bin/test a bคือtest: a: unexpected operatortest a bคือdash: 2: test: a: unexpected operator
- ความต่างแบบนี้เกิดได้ไม่ใช่แค่กับ
testและ[แต่รวมถึงคำสั่งที่ดูง่ายอย่างechoด้วย - เพราะแต่ละเชลล์มี implementation แบบ built-in ต่างกัน พฤติกรรมของสคริปต์จึงอาจเปลี่ยนไปตามเชลล์ที่ใช้รัน
กฎอีกชุดหนึ่งที่ส่วนขยาย [[ ของ Bash ใช้
[[เป็นส่วนขยายของ Bash และใช้แทน[ได้- ความต่างที่สำคัญที่สุดคือ
[[เป็น ไวยากรณ์แบบ built-in เสมอ- ต่างจาก
[ที่อาจถูกรันเป็นไบนารีภายนอกได้ ใน[[นั้น Bash สามารถเปลี่ยนกฎภาษาภายในนิพจน์ได้
- ต่างจาก
- ในตัวอย่าง glob นั้น
[และ[[ทำงานต่างกัน- หลัง
touch long-nameแล้ว[ long* = long-name ] && echo matchจะพิมพ์match - อาร์กิวเมนต์ของคำสั่ง
[จะถูกใช้กฎการขยายปกติของเชลล์ ทำให้long*ถูกขยายเป็นlong-nameในไดเรกทอรี [[ long* = long-name ]] && echo matchจะไม่พิมพ์อะไร[[จะปฏิบัติกับlong*เป็นสตริงตามตัวอักษรและเปรียบเทียบตรง ๆ กับlong-nameจึงล้มเหลว
- หลัง
- ถ้าเป็นสคริปต์ที่ใช้กับ Bash เท่านั้น ก็ยังใช้ความสามารถอย่างการจับคู่ด้วย regular expression
=~ผ่าน[[ได้ด้วย
ในสคริปต์ควรเลือกอะไร
- ถ้าเป็นเชลล์สคริปต์ที่ต้องการพกพาได้ ควรใช้
[ - จะใช้
testก็ได้ แต่ไม่ใช่ตัวเลือกที่นิยมทั่วไป - ถ้าสคริปต์นั้นใช้กับ Bash เท่านั้น การใช้
[[อย่างสม่ำเสมอจะดีกว่า - ตัวเชลล์เองก็มีตัวดำเนินการนิพจน์อย่าง
!,&&,||- ตัวดำเนินการเหล่านี้ทำงานตามสถานะการจบของคำสั่ง
grep ^hello$ ... && grep ^bye$ ...จะมีรหัสออกจากโปรแกรมรวมเป็น0เมื่อทั้งสองคำสั่งสำเร็จ- ถ้า
grepตัวแรกไม่สำเร็จ คำสั่งหลัง&&ก็จะไม่ทำให้ผลรวมสำเร็จ ดังนั้นรหัสออกจากโปรแกรมรวมจะเป็น1
- เพราะฉะนั้นจึงสามารถผสมนิพจน์
test/[กับตัวดำเนินการตรรกะของเชลล์ในเงื่อนไขเดียวกันได้- ตัวอย่าง:
[ a = b ] || grep -q ^hello$ /usr/share/dict/words
- ตัวอย่าง:
- POSIX ไม่ได้กำหนดว่า
/bin/[และ/bin/testต้องเป็น hard link กัน- บน NetBSD เคยเป็น hard link
- macOS Catalina ให้เป็นสำเนาแยกของไบนารีเดียวกัน
- Debian testing ให้เป็นคนละไบนารี
- ข้อกำหนดของ POSIX ไม่ได้บังคับว่าไฟล์ทั้งสองต้องเป็นลิงก์กัน
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ผมเป็นผู้เขียนต้นฉบับเอง ขอบคุณที่แชร์ และดีใจที่ขึ้นไปถึงหน้าแรกแล้ว ชื่อน่าจะควรมี (2020) ต่อท้าย และ "test" หมายถึงคำสั่งจริง ๆ จึงน่าจะไม่ควรเขียนขึ้นต้นด้วยตัวใหญ่
ผมยังมีบทความที่เกี่ยวข้องซึ่งเขียนในปี 2021 ด้วย โดยพูดถึงไปถึงโอเปอเรเตอร์
[[ของ bash น่าจะอ่านได้สนุกในบริบทนี้: https://jmmv.dev/2021/08/useless-use-of-gnu.html[[ไม่ใช่คำสั่งในตัว แต่โดยพื้นฐานแล้วใกล้เคียงกับ องค์ประกอบทางไวยากรณ์ มากกว่า ภายในอาจใช้คำสั่งในตัวที่แทบเข้าถึงไม่ได้ก็ได้ แต่จุดที่น่าสนใจคือ]]ก็เป็น reserved word เช่นกัน ทั้งที่ไม่สามารถอยู่ในตำแหน่งที่ reserved word มีความหมายได้ในเชลล์บางตัวที่ไม่ใช่ bash หากต้องการประกาศฟังก์ชันบางประเภท ต้องใช้คีย์เวิร์ด
functionส่วน$(shell)ของmakeอาจทำให้วัดความต่างด้านประสิทธิภาพได้เมื่อ build target จำนวนมาก ถึงอย่างนั้น ถ้าเป็นกรณีที่ไม่ได้ทำอะไรเลยก็ถือว่าเสียเปรียบ ดังนั้นโดยทั่วไปถ้าต้องการบังคับให้สร้างใหม่ ควรใช้includeมากกว่า การที่ GNU ไม่สนใจ POSIX นั้นสมเหตุสมผลอย่างยิ่ง เพราะ POSIX ไม่ค่อยมีประโยชน์ในการแก้ปัญหาจริงส่วนใหญ่.อย่างชัดเจนก็มีประโยชน์ และการเติมตัวเลือกต่อท้ายคำสั่งที่เพิ่งพิมพ์ไปก็สะดวกจริง ๆ เวลาเจอคำสั่งที่ไม่รองรับสิ่งพวกนั้นก็มักจะหงุดหงิดเสมอในสคริปต์ โดยทั่วไปการเขียนให้เข้ากับ POSIX
shนั้นสมเหตุสมผล อย่างน้อยก็ควรรู้ว่ากำลังใช้ไวยากรณ์เฉพาะของ Bash อยู่หรือไม่--ignore-case,set -o pipefailทำให้ ความสามารถในการพกพา ของสคริปต์ลดลง เรื่องนั้นเองก็ถูกต้องแต่ไม่ได้อธิบายว่าทำไมผู้ใช้ Linux ต้องใส่ใจกับความสามารถในการพกพาขนาดนั้น OpenBSD และ FreeBSD ยังอยู่ได้ดี แต่จำนวนผู้ใช้น้อยมากจนดูไม่ใช่สิ่งที่ต้องกังวลเป็นพิเศษ อาจบอกได้ว่าเพื่อความเป็นธรรมก็ควรคำนึงถึงระบบปฏิบัติการเหล่านั้นด้วย แต่เกณฑ์นั้นควรหยุดที่ตรงไหน? ต้องคำนึงถึงของ obscure อย่าง
vxWorksด้วยไหม? ฝั่ง BusyBox, Alpine น่าสนใจกว่า แต่ความเปลี่ยนแปลงใหญ่เสียจนแทบจะต้องพอร์ตแยกอยู่ดี มีเหตุผลอื่นที่โน้มน้าวใจได้ไหมว่าควรใส่ใจกับ ecosystem ที่ไม่ใช่ GNU?if [ a = b ] || grep -q ^hello$ /usr/share/dict/words; then echo "test failed and grep succeeded"; fiก็เป็นแค่ วิธีใช้เชลล์ ธรรมดาในชีวิตประจำวันไม่ใช่หรือ?make $(shell …) expansionแต่เดิมควรเป็นmake $(shell ...) expansionอย่างที่ในเนื้อหาเขียนถูกต้อง มันเป็นจุดสามจุด ไม่ใช่เครื่องหมายจุดไข่ปลาเดี่ยว ดังนั้น
mldrเองก็ไม่ถูก น่าจะเป็นบั๊กที่ไม่เกี่ยวกันสองตัวส่งผลพร้อมกันถ้าดันประเด็นสุดท้ายไปอีกขั้น ก็ลบตัวบล็อก
ifออกได้ด้วยif [ a = b ]; then echo "Oops!"; else echo "Expected; phew!"; fiจะกลายเป็น[ a = b ] && echo "Oops!" || echo "Expected; phew!"ไม่รู้ว่าควรทำแบบนี้บ่อยแค่ไหน แต่บางครั้งก็มีประโยชน์เวลาพิมพ์ output สำหรับดีบักไปยัง standard error แบบมีเงื่อนไข เช่น
[ "$debug" ] && echo "what's going on" >&2ความจริงที่ว่าบล็อกifตรวจสอบคำสั่งทั่วไป ทำให้ทำแบบif grep -q 'debug' /var/log/nginx/access.log; then echo "Debug request found!"; fiได้ด้วย สิ่งที่ยังไม่ได้ดูคือควรเขียนเป็น[ $(expr 1 + 1) -eq 2 ] && [ $(expr 2 + 2) -eq 3 ]หรือควรใช้ logical AND ในตัวของtestอย่าง[ $(expr 1 + 1) -eq 2 -a $(expr 2 + 2) -eq 4 ]ถ้าประสิทธิภาพไม่ใช่ปัญหา ทั้งสองฝั่งก็ดูสมเหตุสมผลด้วยเหตุผลคล้ายกัน[ a = b ] && echo "Oops!" || echo "Expected; phew!"เป็นกฎทั่วไป bash น่าจะตีความบรรทัดนี้เป็น([ a = b ] && echo "Oops!") || echo "Expected; phew!"ดังนั้นถ้าชุดคำสั่งหลัง
&&ล้มเหลว โค้ดหลัง||ก็จะถูกเรียกอยู่ดี เช่น ถ้า>/dev/full echo "strings match"ล้มเหลวเพราะเขียนไม่ได้ ก็จะพิมพ์"strings don't match"ออกมา ทั้งที่สตริงตรงกัน ซึ่งต่างจากความหมายของบล็อกifset -eซึ่งเป็นสิ่งที่ควรใช้if [ a = b ]; then echo "Oops!"; fiจะทำงานตามที่คาด แต่[ a = b ] && echo "Oops!"จะจบด้วย error เมื่อ expressionaไม่เท่ากับb-a,-oและโอเปอเรเตอร์(,)ถูกระบุว่า เลิกแนะนำให้ใช้ ดูรายละเอียดได้ใน "Application Usage" ของ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/t...-aหรือใช้ test สองตัวกับ&&ถ้าใช้ arithmetic evaluation ของ bash ได้ ก็ไม่จำเป็นต้องออกไปเรียกexpr:[ $((1+1)) -eq 2 ]ตั้งแต่หลายปีก่อน ผมเลิกใช้
[แล้วtestช่วยตอกย้ำว่านี่ไม่ใช่ไวยากรณ์ แต่เป็นแค่ คำสั่ง เหมือนคำสั่งอื่น ๆ และman testก็สะดวกกว่าไปคุ้ยman bashมากman testแต่ยังมีman [ด้วยใน Bash มี
help testเป็นชีตสรุปเร็ว ๆ คำสั่ง[เก่ามาก และมีอยู่แล้วใน Version 7 Unix ตั้งแต่ปี 1979เห็นด้วย
[และ[[ที่เป็นของ bash โดยเฉพาะทำให้เกิดความสับสนมากว่าแท้จริงแล้วเกิดอะไรขึ้น จนยากจะมั่นใจได้แต่การที่
[[รับประกันว่าเป็นคำสั่ง built-in นั้นย่อมมีเหตุผลในยุคที่ประสิทธิภาพของ shell script ยังมีความหมาย และก็ไม่ได้นานขนาดนั้นtestต่อไป ไม่ค่อยได้เขียนสคริปต์ bash บ่อย เลยสะดุดกับคำสั่งifอยู่เสมอ โดยเฉพาะ กฎเรื่องช่องว่าง พอเห็นเหตุผลแล้วก็ชัดเจนมาก และการใช้testทำให้เห็นชัดกว่าว่ามันเป็นเพียงการส่งอาร์กิวเมนต์เข้าไปเท่านั้นกับ
[และtestหลุมพรางที่ใหญ่ที่สุดคือ พฤติกรรมเมื่อมีอาร์กิวเมนต์เดียว เช่น ถ้าต้องการตรวจว่าตัวแปรไม่ว่าง อาจเขียนว่า[ -n $FOO ]แต่ถ้า
FOOไม่ได้ถูกตั้งค่าไว้ มันจะ expand เป็นไม่มีอะไรเลย ไม่ใช่สตริงว่าง จึงกลายเป็นเหมือน[ -n ]POSIX กำหนดว่ารูปแบบของ[ที่มีอาร์กิวเมนต์เดียว ถ้าอาร์กิวเมนต์นั้น ซึ่งในที่นี้คือ"-n"ไม่ว่าง จะต้องสำเร็จ ดังนั้นจึงรายงานผิดว่า$FOOไม่ว่าง ต้องใส่เครื่องหมายคำพูดครอบตัวแปรเสมอtestเองมีหลุมพราง แต่หลุมพรางอยู่ที่ตัว shell เองพฤติกรรมที่พูดถึงนั้นสมเหตุสมผล
[ "$FOO" ]เป็นรูปแบบที่ตรวจว่าเนื้อหาไม่ว่างเสมอ ไม่ว่าเนื้อหาจะเป็นอะไรก็ตาม แม้จะเป็น"-n"ก็ตาม$FOOมีช่องว่างอยู่ มันจะ expand เป็นหลายอาร์กิวเมนต์ แค่ ใส่เครื่องหมายคำพูดครอบตัวแปรเสมอ[ x"$FOO" != x"" ][ -n "${FOO?}" ]เพื่อให้สคริปต์หยุดทันทีเมื่อ$FOOเป็น null หรือไม่ได้ถูกตั้งค่าchubot เคยเขียนเอกสารที่น่าสนใจซึ่งเจาะลึกส่วนที่ละเอียดอ่อนกว่าของ
test/[/[[บทความอื่น ๆ ในบล็อกนั้นก็อธิบายความแปลกของ shell ได้ค่อนข้างน่าสนใจเช่นกัน¹ https://www.oilshell.org/blog/2017/08/31.html
² https://www.oilshell.org/blog/2016/11/18.html
ไม่เคยรู้เลยว่า
[เป็นโปรแกรม และข้อเท็จจริงที่ว่ามันตรวจว่าอาร์กิวเมนต์สุดท้ายเป็นวงเล็บเหลี่ยมปิดก็น่าขำอยู่ถึงอย่างนั้นก็อธิบายได้ว่าทำไมต้องมี ช่องว่าง ทั้งสองข้างของวงเล็บเหลี่ยม
[[เป็นของ bash โดยเฉพาะ ถ้ารู้ว่าจะใช้แต่ bash ก็ใช้ได้ รายละเอียดบทความอธิบายไว้ดีแล้วhttps://zsh.sourceforge.io/Doc/Release/Conditional-Expressio...
[[ตลอดก็ได้zsh กับ ksh ก็มี และจริง ๆ แล้วค่อนข้างมั่นใจว่าเริ่มมาจาก ksh ตั้งแต่ปี 1988 หรือก่อนหน้านั้น
testและ[ถูกระบุไว้ใน POSIX และปกติมักมีอยู่เป็นไบนารีจริง ๆ เพียงแต่คำสั่ง built-in ของ shell อาจบังไว้ได้ส่วน
[[ไม่ได้ถูกระบุไว้ใน POSIX และปกติมักมีอยู่แค่เป็น built-in ของ shell เท่านั้นการมุ่งรองรับแค่ shell ตัวร่วมต่ำสุดดูเหมือนเป็น ความกังวลแบบโบราณ ไปแล้ว
ไม่ค่อยเข้าใจว่าทำไมคำสั่ง
ifสุดท้ายถึงทำให้งง ถ้าเป็นเพราะตอนเริ่มเรียน shell script คนมักสมมติว่า[เป็นส่วนหนึ่งของภาษา bash script ไม่ใช่โปรแกรมอีกตัวหนึ่ง แบบนี้ก็เข้าใจได้แล้ว ถ้าไม่ใช่ก็อยากให้ช่วยอธิบายว่ามันน่าประหลาดใจตรงไหน[เป็นไบนารี ก็ยังไม่ค่อยเห็นว่าทำไมถึงน่างง มันดูเป็น bash ธรรมดามากมีรสนิยมแรง ๆ เรื่อง shell ซึ่งไม่ค่อยเข้ากับคนส่วนใหญ่ในโลก
ผมคิดว่าไม่ควรใช้
[เลย และควรใช้แต่testเท่านั้น[ทำให้เข้าใจผิดว่ากลไกของมันเป็นส่วนหนึ่งของไวยากรณ์ภาษา แต่จริง ๆ แล้วมันเป็นแค่ "โปรแกรม" อีกตัวหนึ่ง ในที่นี้ "โปรแกรม" รวมถึงคำสั่ง built-in และฟังก์ชันด้วยif/||/&&ดูที่สถานะการจบการทำงาน และโปรแกรมไม่สามารถดูสถานะการจบการทำงานของอย่างอื่นได้ นอกจากดูตัวแปรวิเศษ$?ซึ่งหลังจาก expand แล้วก็เป็นแค่สตริงcaseดูสตริง แต่ไม่ได้ทำงานโดยอิงสถานะการจบการทำงาน และก็ไม่ได้ตั้งค่าสถานะการจบการทำงานเป็นส่วนหนึ่งของการทำงานcase ... esacด้วย "โปรแกรม" เป็นสิ่งที่ตั้งค่าสถานะการจบการทำงาน อีกอย่าง[/testควรใช้เฉพาะเมื่อต้องประเมินโครงสร้างของ filesystem เช่นtest -f /dev/nullเท่านั้น การประเมินสตริงควรใช้caseแน่นอนว่าพอเห็นสคริปต์ส่วนใหญ่แล้วมันคันไม้คันมือ และสคริปต์ที่ผมเขียน คนอื่นก็มองว่าแปลกเวลาผมใช้ shell ผมชอบรูปแบบที่วางโปรแกรมหลัง
ifไว้คนละบรรทัด แล้วค่อยไปthenเพื่อเน้นว่าสิ่งหลังifคือ "ดูสถานะการจบการทำงานของคำสั่งสุดท้ายก่อน then" เช่น ในโครงสร้างอย่างif; ls /tmp/goober; test -d /tmp/goober; echo "I'll always execute the then clause because echo will always return a 0 return code"; then ... fiนั้นifจะดูแค่สถานะการจบการทำงานของechoสุดท้าย ดังนั้น then clause จึงถูกรันเสมอtestมา 8 ปีเป็นหลักฐานว่าผมเห็นด้วย เป็นเส้นทางที่โดดเดี่ยว... โทษ Google shell style guideนิสัยชอบใช้
testเกิดจากการเขียนสคริปต์ที่ต้องรันได้ทั้งในshและbashแต่ผมก็ยังใช้ต่อ เพราะในเชิงความหมายมันเข้าใจได้มากกว่าการปฏิบัติกับตัวอักษร[เหมือนเป็นคำสั่ง การที่]ไม่ใช่ไบนารีแยกต่างหาก แต่เป็นอาร์กิวเมนต์ของ[ก็แปลกเหมือนกัน เข้าใจเหตุผลทางเทคนิค แต่ให้ความรู้สึกเหมือน hacktestยังไงก็ไม่เปลี่ยนอยู่หลายสิบคน หลายสิบคนเลย!ผมถูกสอนให้ใช้
[[เฉพาะเวลาต้องการทำ regex matching เท่านั้น เช่นif [[ "${foo}" =~ ^bar$ ]]; then echo Yes; fiนอกนั้นก็ใช้แค่
"test"หรือ"["ตอนนี้เขียน bash ไป 85,000 บรรทัดแล้ว ไม่ได้จะบอกว่า bash ยอดเยี่ยม แต่จนถึงตอนนี้มันยังตอบโจทย์งานหลายอย่างของผมได้exprสามารถ match basic regular expression ได้ และยังคืนค่า capture group ได้ด้วย1: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/e...
[ "$foo" = bar ] && echo Yesก็พอสำหรับการ match substring แค่
[กับ glob*โดยมากก็เพียงพอแล้ว เช่น[ "$bar" = extra* ] && echo '$bar began with extra'ประมาณนี้ dialect ของ regex ใน Bash ค่อนข้างดิบ จึงแทบไม่คุ้มที่จะฝืนใช้ งานที่ซับซ้อนควรใช้เครื่องมืออื่นอย่างgrep,awk,perlจะถูกกว่า ถ้ายึดติดว่าจะทำทุกอย่างด้วย bash แม้กระทั่งงานซับซ้อนที่ต้องการการนำกลับมาใช้ซ้ำที่สูงขึ้น ความเป็นโมดูลมากขึ้น และชนิดข้อมูลในตัว ผลตอบแทนก็จะลดลงอย่างรวดเร็ว