วิธีใช้การทดสอบแบบมีเงื่อนไข 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
