คำสั่งซ้อนกันแบบง่าย ๆ — เช่น การเรียงคำสั่งหลายคำสั่งต่อเนื่องบนบรรทัดคำสั่ง — ใช้กันอย่างแพร่หลาย คำสั่งเหล่านี้จะคั่นด้วย semicolon ซึ่งระบุถึงจุดสิ้นสุดของคำสั่ง ในการสร้างชุดคำสั่ง shell เรียบง่ายบนบรรทัดเดียว ให้คั่นแต่ละคำสั่งด้วย semicolon ดังนี้:
command1 ; command2 ; command3 ; command4 ;
คุณไม่จำเป็นต้องใส่ semicolon ตัวสุดท้าย เพราะการกด Enter หมายถึงการจบคำสั่งสุดท้ายแล้ว แต่อย่างไรก็ตาม การใส่ไว้เพื่อความสม่ำเสมอก็ได้ไม่เป็นไร
คำสั่งทั้งหมดจะทำงานโดยไม่มีปัญหา — ตราบใดที่ไม่มีข้อผิดพลาดเกิดขึ้น แต่ถ้ามีข้อผิดพลาดจะเกิดอะไรขึ้น? เราสามารถคาดการณ์และจัดการข้อผิดพลาดได้โดยใช้ control operators && และ || ที่สร้างไว้ใน Bash ทั้งสองตัวให้การควบคุมโฟลว์และช่วยให้เราเปลี่ยนลำดับการรันโค้ดได้ ตัว semicolon และตัวอักขระ newline ก็ถือเป็น Bash control operators เช่นกัน
ตัวดำเนินการ && หมายถึงว่า "ถ้า command1 สำเร็จ ให้รัน command2" หาก command1 ล้มเหลวด้วยเหตุผลใดก็ตาม command2 จะไม่ถูกรัน ไวยากรณ์เป็นดังนี้:
command1 && command2
สิ่งนี้ทำงานได้เพราะทุกคำสั่งจะส่งคืนรหัสกลับ (return code) ให้ shell บ่งบอกว่าทำงานสำเร็จหรือล้มเหลว ตามแนวปฏิบัติ รหัสกลับ (RC) เป็น 0 (ศูนย์) แสดงว่าสำเร็จ และเลขบวกใด ๆ แสดงถึงความล้มเหลวบางประการ เครื่องมือ sysadmin บางอย่างคืนค่า 1 เพื่อแจ้งความล้มเหลวทั่วไป แต่หลายตัวใช้รหัสตัวเลขบวกอื่น ๆ เพื่อระบุประเภทของความล้มเหลว
ตัวแปร $? ของ Bash shell สามารถตรวจสอบได้ง่ายโดยสคริปต์ โดยคำสั่งถัดไปในรายการ หรือโดย sysadmin โดยตรง มาดู RC กัน เราสามารถรันคำสั่งง่าย ๆ และตรวจสอบ RC ทันที ซึ่งจะอ้างถึงคำสั่งล่าสุดที่รันเสมอ
[student@studentvm1 ~]$ ll ; echo "RC = $?" total 284 -rw-rw-r-- 1 student student 130 Sep 15 16:21 ascii-program.sh drwxrwxr-x 2 student student 4096 Nov 10 11:09 bin <snip> drwxr-xr-x. 2 student student 4096 Aug 18 10:21 Videos RC = 0 [student@studentvm1 ~]$
RC นี้เป็น 0 หมายถึงคำสั่งทำงานสำเร็จ ตอนนี้ลองคำสั่งเดียวกันกับไดเรกทอรีที่เราไม่มีสิทธิ์เข้าถึง
[student@studentvm1 ~]$ ll /root ; echo "RC = $?" ls: cannot open directory '/root': Permission denied RC = 2 [student@studentvm1 ~]$
ความหมายของ RC นี้สามารถหาได้จาก man page ของคำสั่ง ls
ลองใช้ control operator && ตามที่อาจใช้ในโปรแกรมบรรทัดคำสั่ง เริ่มจากสิ่งง่าย ๆ: สร้างไดเรกทอรีใหม่ และถ้าสำเร็จ ให้สร้างไฟล์ใหม่ภายใน
เราต้องการไดเรกทอรีที่สร้างไดเรกทอรีอื่นได้ เริ่มต้นด้วยการสร้างไดเรกทอรีชั่วคราวในโฮมไดเรกทอรีสำหรับทดสอบ
[student@studentvm1 ~]$ cd ; mkdir testdir
สร้างไดเรกทอรีใหม่ใน ~/testdir (ซึ่งควรว่างเพราะเพิ่งสร้าง) จากนั้นสร้างไฟล์ว่างในไดเรกทอรีใหม่นั้น คำสั่งต่อไปนี้จะทำทั้งสองงาน
[student@studentvm1 ~]$ mkdir ~/testdir/testdir2 && touch ~/testdir/testdir2/testfile1 [student@studentvm1 ~]$ ll ~/testdir/testdir2/ total 0 -rw-rw-r-- 1 student student 0 Nov 12 14:13 testfile1 [student@studentvm1 ~]$
เรารู้ว่าทุกอย่างทำงานปกติ เพราะไดเรกทอรี testdir เข้าถึงและเขียนได้ เปลี่ยน permission ของ testdir ให้ผู้ใช้ student เข้าถึงไม่ได้ ดังนี้:
[student@studentvm1 ~]$ chmod 076 testdir ; ll | grep testdir d---rwxrw-. 3 student student 4096 Nov 12 14:13 testdir [student@studentvm1 ~]$
การใช้ grep หลัง ll แสดงรายการของ testdir สังเกตว่าผู้ใช้ student ไม่มีสิทธิ์เข้าถึง testdir แล้ว ตอนนี้ลองรันคำสั่งเกือบเหมือนเดิม แต่เปลี่ยนชื่อไดเรกทอรีภายใน testdir
[student@studentvm1 ~]$ mkdir ~/testdir/testdir3 && touch ~/testdir/testdir3/testfile1 mkdir: cannot create directory ‘/home/student/testdir/testdir3’: Permission denied [student@studentvm1 ~]$
แม้จะได้ข้อความผิดพลาด การใช้ control operator && ป้องกันไม่ให้ touch รัน เพราะมีข้อผิดพลาดในการสร้าง testdir3 การควบคุมโฟลว์ตรรกะบรรทัดคำสั่งแบบนี้ช่วยป้องกันไม่ให้ข้อผิดพลาดสะสมและทำให้สถานการณ์แย่ลง แต่มาทำให้ซับซ้อนขึ้นนิดหน่อย
Control operator || ช่วยให้เราเพิ่มคำสั่งอีกตัวที่ทำงานเมื่อคำสั่งแรกคืนค่ามากกว่าศูนย์
[student@studentvm1 ~]$ mkdir ~/testdir/testdir3 && touch ~/testdir/testdir3/testfile1 || echo "An error occurred while creating the directory." mkdir: cannot create directory ‘/home/student/testdir/testdir3’: Permission denied An error occurred while creating the directory. [student@studentvm1 ~]$
ไวยากรณ์คำสั่งซ้อนที่ใช้ flow control ด้วย && และ || มีรูปแบบทั่วไปดังนี้:
preceding commands ; command1 && command2 || command3 ; following commands
คำสั่งซ้อนที่ใช้ control operators อาจมีคำสั่งอื่นก่อนและหลังส่วน flow-control ซึ่งเกี่ยวข้องกับคำสั่งในส่วนนั้นแต่ไม่ได้รับผลกระทบจาก flow control คำสั่งเหล่านั้นจะรันทั้งหมดโดยไม่สนใจสิ่งที่เกิดขึ้นภายในคำสั่งซ้อน flow-control
Flow-control operators เหล่านี้ทำให้การทำงานบนบรรทัดคำสั่งมีประสิทธิภาพมากขึ้น โดยจัดการการตัดสินใจและแจ้งเตือนเมื่อมีปัญหา ผมใช้ทั้งบนบรรทัดคำสั่งโดยตรงและในสคริปต์
คุณสามารถทำความสะอาดได้ในฐานะ root user เพื่อลบไดเรกทอรีและเนื้อหาภายใน
[root@studentvm1 ~]# rm -rf /home/student/testdir
คุณใช้ Bash control operators อย่างไร? บอกเราในส่วนความคิดเห็นได้เลย