วิธีใช้การทดสอบแบบมีเงื่อนไข Double Bracket ใน Linux
เผยแพร่แล้ว: 2022-01-29การทดสอบแบบมีเงื่อนไขจะแยกกระแสการดำเนินการของสคริปต์ Linux Bash ตามผลลัพธ์ของนิพจน์เชิงตรรกะ การทดสอบแบบมีเงื่อนไขวงเล็บคู่ทำให้ไวยากรณ์ง่ายขึ้นมาก—แต่ยังมี gotchas ของตัวเอง
วงเล็บเดี่ยวและคู่
Bash ให้คำสั่ง test
ซึ่งช่วยให้คุณทดสอบนิพจน์เชิงตรรกะได้ นิพจน์จะส่งกลับคำตอบที่ระบุการตอบสนองจริงหรือเท็จ การตอบสนองที่แท้จริงจะถูกระบุด้วยค่าที่ส่งกลับเป็นศูนย์ สิ่งใดที่ไม่ใช่ศูนย์แสดงว่าเป็นเท็จ
การโยงคำสั่งบนบรรทัดคำสั่งด้วยตัวดำเนินการ &&
จะใช้คุณสมบัตินี้ คำสั่งจะดำเนินการได้ก็ต่อเมื่อคำสั่งก่อนหน้าเสร็จสมบูรณ์เท่านั้น
หากการทดสอบเป็นจริง คำว่า "ใช่" จะถูกพิมพ์ออกมา
ทดสอบ 15 -eq 15 && echo "ใช่"
ทดสอบ 14 -eq 15 && echo "ใช่"
การทดสอบแบบมีเงื่อนไขวงเล็บเดียวเลียนแบบคำสั่ง test
พวกเขาใส่นิพจน์ในวงเล็บ " [ ]
” และดำเนินการเหมือนกับคำสั่ง test
อันที่จริงมันเป็นโปรแกรมเดียวกัน ซึ่งสร้างจากซอร์สโค้ดเดียวกัน ความแตกต่างในการปฏิบัติงานเพียงอย่างเดียวคือวิธีที่เวอร์ชัน test
และ [
เวอร์ชันจัดการคำขอความช่วยเหลือ
นี่คือจากซอร์สโค้ด:
/* รับรู้ --help หรือ --version แต่เมื่อเรียกใช้ใน .เท่านั้น แบบฟอร์ม "[" เมื่ออาร์กิวเมนต์สุดท้ายไม่ใช่ "]" ใช้โดยตรง แยกวิเคราะห์ แทนที่จะ parse_long_options เพื่อหลีกเลี่ยงการยอมรับ ตัวย่อ POSIX อนุญาต "[ --help" และ "[ --version" ถึง มีพฤติกรรม GNU ตามปกติ แต่ต้องใช้ "test --help" และ "test --version" เพื่อออกอย่างเงียบ ๆ ด้วยสถานะ 0 */
เราสามารถเห็นผลของสิ่งนี้ได้โดยขอ test
และ [
เพื่อขอความช่วยเหลือและตรวจสอบรหัสตอบกลับที่ส่งไปยัง Bash
ทดสอบ --help
เสียงสะท้อน $?
[ --ช่วย
เสียงสะท้อน $?
ทั้ง test
และ [
เป็น shell buildins ซึ่งหมายความว่าพวกมันถูกอบใน Bash แต่ยังมีเวอร์ชันไบนารีแบบสแตนด์อโลนของ [
.
แบบทดสอบ
พิมพ์ [
อยู่ไหน [
ในทางตรงกันข้าม การทดสอบเงื่อนไขวงเล็บคู่ [[
และ ]]
คือ คีย์เวิร์ด [[
และ ]]
ทำการทดสอบเชิงตรรกะเช่นกัน แต่ไวยากรณ์ต่างกัน เนื่องจากเป็นคีย์เวิร์ด คุณจึงใช้ฟีเจอร์ที่เรียบร้อยซึ่งใช้ไม่ได้ในเวอร์ชันวงเล็บปีกกาเดียว
คำหลักวงเล็บคู่ได้รับการสนับสนุนโดย Bash แต่ไม่มีอยู่ในทุกเชลล์อื่น ตัวอย่างเช่น Korn เชลล์สนับสนุนพวกเขา แต่เชลล์แบบเก่าธรรมดา sh ไม่สนับสนุน สคริปต์ทั้งหมดของเราเริ่มต้นด้วยบรรทัด:
#!/bin/bash
เพื่อให้แน่ใจว่าเรากำลังเรียกใช้ Bash shell เพื่อเรียกใช้สคริปต์
ที่เกี่ยวข้อง: วิธีสร้างและเรียกใช้ Bash Shell Scripts บน Windows 10
บิวอินและคีย์เวิร์ด
เราสามารถใช้โปรแกรม compgen
เพื่อแสดงรายการบิวด์อิน:
compgen -b | fmt -w 70
หากไม่มีการวางท่อเอาต์พุตผ่าน fmt
เราจะได้รับรายการยาว ๆ ที่แต่ละบิวด์อินอยู่ในบรรทัดของตัวเอง ในกรณีนี้จะสะดวกกว่าในการดูบิวด์อินที่จัดกลุ่มเข้าด้วยกันเป็นย่อหน้า
เราสามารถเห็น test
และ [
ในรายการ แต่ ]
ไม่อยู่ในรายการ คำสั่ง [
ค้นหาการปิด ]
เพื่อตรวจจับเมื่อถึงจุดสิ้นสุดของนิพจน์ แต่ ]
ไม่ใช่บิวด์อินแยกต่างหาก เป็นเพียงสัญญาณที่เราให้กับ [
เพื่อระบุจุดสิ้นสุดของรายการพารามิเตอร์
หากต้องการดูคำหลัก เราสามารถใช้:
compgen -k | fmt -w 70
คีย์เวิร์ด [[
และ ]]
อยู่ในรายการ เนื่องจาก [[
เป็นคีย์เวิร์ดเดียวและ ]]
เป็นคีย์เวิร์ดอื่น เป็นคู่ที่ตรงกัน เช่นเดียวกับ if
และ fi
และ case
และ esac
เมื่อ Bash กำลังแยกวิเคราะห์สคริปต์หรือบรรทัดคำสั่ง และตรวจพบคีย์เวิร์ดที่มีคีย์เวิร์ดปิดที่ตรงกัน คีย์เวิร์ดปิดจะรวบรวมทุกอย่างที่ปรากฏระหว่างคีย์เวิร์ดและใช้การดูแลพิเศษที่คีย์เวิร์ดรองรับ
ด้วย buildin สิ่งที่ตามมาหลังคำสั่ง buildin จะถูกส่งต่อเหมือนกับพารามิเตอร์ของโปรแกรมบรรทัดคำสั่งอื่นๆ ซึ่งหมายความว่าผู้เขียนสคริปต์ต้องใช้ความระมัดระวังเป็นพิเศษเกี่ยวกับสิ่งต่าง ๆ เช่นช่องว่างในค่าตัวแปร
Shell Globbing
การทดสอบแบบมีเงื่อนไขวงเล็บคู่สามารถใช้เปลือกโลกกลมได้ ซึ่งหมายความว่าเครื่องหมายดอกจัน “ *
” จะขยายเพื่อหมายถึง “อะไรก็ได้”
พิมพ์หรือคัดลอกข้อความต่อไปนี้ลงในโปรแกรมแก้ไขและบันทึกลงในไฟล์ชื่อ "whelkie.sh"
#!/bin/bash stringvar="เวลกี บรูคส์" ถ้า [[ "$stringvar" == *elk* ]]; แล้ว echo "คำเตือนมีอาหารทะเล" อื่น echo "ปราศจากหอย" fi
ในการทำให้สคริปต์ทำงานได้ เราจำเป็นต้องใช้คำสั่ง chmod
พร้อมตัวเลือก -x
(ดำเนินการ) คุณจะต้องทำเช่นนี้กับสคริปต์ทั้งหมดในบทความนี้หากต้องการทดลองใช้
chmod +x whelkie.sh
เมื่อเราเรียกใช้สคริปต์ เราจะเห็นสตริง "elk" ที่พบในสตริง "Whelkie" โดยไม่คำนึงถึงอักขระอื่นที่อยู่ล้อมรอบ
./whelkie.sh
ประเด็นหนึ่งที่ควรทราบคือ เราไม่ตัดสตริงการค้นหาด้วยเครื่องหมายคำพูดคู่ ถ้าคุณทำเช่นนั้น globbing จะไม่เกิดขึ้น สตริงการค้นหาจะได้รับการปฏิบัติอย่างแท้จริง
อนุญาตให้ใช้เปลือกหอยรูปแบบอื่นได้ เครื่องหมายคำถาม “ ?
” จะจับคู่อักขระเดี่ยว และใช้วงเล็บเหลี่ยมเดี่ยวเพื่อระบุช่วงของอักขระ ตัวอย่างเช่น หากคุณไม่ทราบว่าจะใช้กรณีใด คุณสามารถครอบคลุมเหตุการณ์ทั้งสองด้วยช่วง
#!/bin/bash stringvar="ฌอง-คล็อด ฟาน แคลม" ถ้า [[ "$stringvar" == *[cC]lam* ]]; แล้ว echo "คำเตือนมีอาหารทะเล" อื่น echo "ปราศจากหอย" fi
บันทึกสคริปต์นี้เป็น "damme.sh" และทำให้สามารถเรียกใช้งานได้ เมื่อเราเรียกใช้คำสั่งเงื่อนไขจะแก้ไขเป็นจริง และประโยคแรกของคำสั่ง if จะถูกดำเนินการ
./damme.sh
สตริงอ้างอิง
เราพูดถึงการห่อสตริงด้วยเครื่องหมายคำพูดคู่ก่อนหน้านี้ หากคุณทำเช่นนั้น เปลือกโลกจะไม่เกิดขึ้น แม้ว่าแบบแผนจะบอกว่าเป็นแนวปฏิบัติที่ดี คุณไม่ จำเป็นต้อง ใส่ตัวแปรสตริงในเครื่องหมายคำพูดเมื่อใช้ [[
และ ]]
แม้ว่าจะมีการเว้นวรรคก็ตาม ดูตัวอย่างต่อไป ทั้งตัวแปรสตริง $stringvar
และ $surname
มีการเว้นวรรค แต่ไม่มีการอ้างอิงในคำสั่งเงื่อนไข
#!/bin/bash stringvar="แวน Damme" นามสกุล = "แวน Damme" ถ้า [[ $stringvar == $นามสกุล ]]; แล้ว echo "นามสกุลตรงกัน" อื่น echo "นามสกุลไม่ตรงกัน" fi
บันทึกสิ่งนี้ลงในไฟล์ชื่อ “surname.sh” และทำให้สามารถเรียกใช้งานได้ เรียกใช้โดยใช้:
./นามสกุล.sh
แม้ว่าสตริงทั้งสองจะมีช่องว่าง แต่สคริปต์ก็สำเร็จและคำสั่งแบบมีเงื่อนไขจะแก้ไขเป็นจริง สิ่งนี้มีประโยชน์เมื่อต้องจัดการกับพาธและชื่อไดเร็กทอรีที่มีช่องว่าง ในที่นี้ อ็อพชัน -d
คืนค่า จริง หากตัวแปรมีชื่อไดเร็กทอรีที่ถูกต้อง
#!/bin/bash dir="/home/dave/Documents/Needs Work" ถ้า [[ -d ${dir} ]]; แล้ว echo "ไดเร็กทอรีได้รับการยืนยัน" อื่น echo "ไม่พบไดเร็กทอรี" fi
หากคุณเปลี่ยนเส้นทางในสคริปต์เพื่อให้สะท้อนถึงไดเร็กทอรีบนคอมพิวเตอร์ของคุณเอง ให้บันทึกข้อความลงในไฟล์ชื่อ "dir.sh" และทำให้เป็นไฟล์เรียกทำงาน คุณจะเห็นว่าวิธีนี้ใช้ได้ผล
./dir.sh
ที่เกี่ยวข้อง: วิธีทำงานกับตัวแปรใน Bash
ชื่อไฟล์ Globbing Gotchas
ความแตกต่างที่น่าสนใจระหว่าง [ ]
และ [[ ]]
เกี่ยวข้องกับชื่อไฟล์ที่มีการวนซ้ำ แบบฟอร์ม “*.sh” จะตรงกับไฟล์สคริปต์ทั้งหมด การใช้วงเล็บเดียว [ ]
จะล้มเหลว เว้นแต่จะมีไฟล์สคริปต์เดียว การค้นหาสคริปต์มากกว่าหนึ่งรายการทำให้เกิดข้อผิดพลาด
นี่คือสคริปต์ที่มีเงื่อนไขวงเล็บเดียว
#!/bin/bash ถ้า [ -a *.sh ]; แล้ว echo "พบไฟล์สคริปต์" อื่น echo "ไม่พบไฟล์สคริปต์" fi
เราบันทึกข้อความนี้ลงใน "script.sh" และทำให้ใช้งานได้ เราตรวจสอบจำนวนสคริปต์ในไดเร็กทอรี จากนั้นรันสคริปต์
ลส
./script.sh
Bash เกิดข้อผิดพลาด เราลบไฟล์สคริปต์ทั้งหมดยกเว้นไฟล์เดียวและเรียกใช้สคริปต์อีกครั้ง
ลส
./script.sh
การทดสอบตามเงื่อนไขคืนค่าเป็น true และสคริปต์ไม่ทำให้เกิดข้อผิดพลาด การแก้ไขสคริปต์เพื่อใช้วงเล็บคู่ทำให้เกิดการทำงานประเภทที่สาม
#!/bin/bash ถ้า [[ -a *.sh ]]; แล้ว echo "พบไฟล์สคริปต์" อื่น echo "ไม่พบไฟล์สคริปต์" fi
เราบันทึกสิ่งนี้ลงในไฟล์ชื่อ “dscript.sh” และทำให้สามารถเรียกใช้งานได้ การเรียกใช้สคริปต์นี้ในไดเร็กทอรีที่มีสคริปต์จำนวนมากไม่มีข้อผิดพลาด แต่สคริปต์ไม่รู้จักไฟล์สคริปต์ใดๆ
คำสั่งแบบมีเงื่อนไขโดยใช้วงเล็บคู่จะแก้ไขเฉพาะค่า true ในกรณีที่คุณมีไฟล์ชื่อ “*.sh” ในไดเร็กทอรี
./dscript.sh
ตรรกะ AND และ OR
วงเล็บคู่ให้คุณใช้ &&
และ ||
เป็นโอเปอเรเตอร์ตรรกะ AND และ OR
สคริปต์นี้ควรแก้ไขข้อความสั่งตามเงื่อนไขเป็นจริงเพราะ 10 มีค่าเท่ากับ 10 และ 25 น้อยกว่า 26
#!/bin/bash แรก=10 วินาที=25 ถ้า [[ แรก -eq 10 && วินาที -lt 26 ]]; แล้ว echo "ตรงตามเงื่อนไข" อื่น echo "เงื่อนไขล้มเหลว" fi
บันทึกข้อความนี้ลงในไฟล์ชื่อ "and.sh" ทำให้ใช้งานได้ และเรียกใช้ด้วย:
./และ.sh
สคริปต์ทำงานตามที่เราคาดหวัง
คราวนี้เราจะใช้ ||
โอเปอเรเตอร์ คำสั่งแบบมีเงื่อนไขควรแก้ไขเป็นจริงเพราะแม้ว่า 10 จะไม่เกิน 15 แต่ 25 ยังน้อยกว่า 26 ตราบใดที่การเปรียบเทียบครั้งแรก หรือ การเปรียบเทียบครั้งที่สองเป็นจริง คำสั่งแบบมีเงื่อนไขทั้งหมดจะแก้ไขเป็นจริง
บันทึกข้อความนี้เป็น "or.sh" และทำให้ใช้งานได้
#!/bin/bash แรก=10 วินาที=25 ถ้า [[ แรก -gt 15 || วินาที -lt 26 ]]; แล้ว echo "ตรงตามเงื่อนไข" อื่น echo "เงื่อนไขล้มเหลว" fi
./or.sh
Regexes
คำสั่งแบบมีเงื่อนไขวงเล็บคู่อนุญาตให้ใช้ตัวดำเนินการ =~
ซึ่งใช้รูปแบบการค้นหา regex ในสตริงกับอีกครึ่งหนึ่งของคำสั่ง หาก regex เป็นที่พอใจ คำสั่งแบบมีเงื่อนไขจะถือว่าเป็นจริง หาก regex พบว่าไม่ตรงกับคำสั่งเงื่อนไขจะแก้ไขเป็นเท็จ
ที่เกี่ยวข้อง: วิธีใช้นิพจน์ทั่วไป (regexes) บน Linux
บันทึกข้อความนี้ลงในไฟล์ชื่อ “regex.sh” และทำให้ใช้งานได้
#!/bin/bash คำ = "หนึ่งสองสาม" WordsandNumbers="หนึ่ง 1 สอง 2 สาม 3" email="[email protected]" หน้ากาก1="[0-9]" mask2="[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,4}" ถ้า [[ $words =~ $mask1 ]]; แล้ว echo "\"$words\" มีตัวเลข" อื่น echo "ไม่พบตัวเลขใน \"$words\"" fi ถ้า [[ $WordsandNumbers =~ $mask1 ]]; แล้ว echo "\"$WordsandNumbers\" มีตัวเลข" อื่น echo "ไม่พบตัวเลขใน \"$WordsandNumbers\"" fi ถ้า [[ $email =~ $mask2 ]]; แล้ว echo "\"$email\" เป็นที่อยู่อีเมลที่ถูกต้อง" อื่น echo "ไม่สามารถแยกวิเคราะห์ \"$email\"" fi
วงเล็บคู่ชุดแรกใช้ตัวแปรสตริง $mask1
เป็น regex ซึ่งมีรูปแบบสำหรับตัวเลขทั้งหมดในช่วงศูนย์ถึงเก้า ใช้ regex นี้กับตัวแปรสตริง $words
วงเล็บคู่ชุดที่สองใช้ตัวแปรสตริง $mask1
เป็น regex อีกครั้ง แต่คราวนี้ใช้กับตัวแปรสตริง $WordsandNumbers
วงเล็บคู่ชุดสุดท้ายใช้มาสก์ regex ที่ซับซ้อนมากขึ้นในตัวแปรสตริง $mask2
- [A-Za-z0-9._%+-]+ : ตรงกับอักขระที่เป็นอักษรตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็ก หรือตัวเลขใดๆ ตั้งแต่ศูนย์ถึงเก้า หรือจุด ขีดล่าง เครื่องหมายเปอร์เซ็นต์ หรือเครื่องหมายบวกหรือลบ . เครื่องหมาย “
+
” ด้านนอกของ “[]
” หมายถึงการจับคู่ซ้ำสำหรับอักขระจำนวนมากเท่าที่พบ - @ : ตรงกับอักขระ “@” เท่านั้น
- [A-Za-z0-9.-]+ : ใช้กับอักขระที่เป็นอักษรตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็ก หรือตัวเลขตั้งแต่ศูนย์ถึงเก้า หรือจุดหรือขีดกลาง เครื่องหมาย “
+
” ด้านนอกของ “[ ]
” หมายถึงการจับคู่ซ้ำสำหรับอักขระจำนวนมากเท่าที่พบ - . : สิ่งนี้ตรงกับ “.” ตัวอักษรเท่านั้น
- [A-Za-z]{2,4} : ตรงกับอักษรตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็ก “
{2,4}
” หมายถึงจับคู่อักขระอย่างน้อยสองตัวและไม่เกินสี่ตัว
เมื่อนำทั้งหมดมารวมกันแล้ว regex mask จะตรวจสอบว่าที่อยู่อีเมลมีรูปแบบถูกต้องหรือไม่
บันทึกข้อความสคริปต์ลงในไฟล์ชื่อ “regex.sh” และทำให้สามารถเรียกใช้งานได้ เมื่อเรารันสคริปต์ เราจะได้ผลลัพธ์นี้
./regex.sh
คำสั่งเงื่อนไขแรกล้มเหลวเนื่องจาก regex กำลังมองหาตัวเลข แต่ไม่มีตัวเลขในค่าที่เก็บไว้ในตัวแปรสตริง $words
คำสั่งเงื่อนไขที่สองสำเร็จเนื่องจากตัวแปรสตริง $WordsandNumbers
มีตัวเลข
คำสั่งเงื่อนไขขั้นสุดท้ายสำเร็จ กล่าวคือ แก้ไขให้เป็นจริง เนื่องจากที่อยู่อีเมลมีรูปแบบที่เหมาะสม
เงื่อนไขเดียวเท่านั้น
การทดสอบแบบมีเงื่อนไขแบบวงเล็บคู่ช่วยให้สคริปต์ของคุณมีความยืดหยุ่นและอ่านง่าย เพียงแค่ใช้ regexes ในการทดสอบแบบมีเงื่อนไขของคุณ ก็ทำให้เรียนรู้วิธีใช้ [[
และ ]]
ได้
เพียงตรวจสอบให้แน่ใจว่าสคริปต์เรียกใช้เชลล์ที่รองรับเช่น Bash
ที่เกี่ยวข้อง: 15 ตัวละครพิเศษที่คุณต้องรู้สำหรับ Bash