คำสั่งเทอร์มินัลปกติจะมีตัวเลือก (options) หรือสวิตช์ (switches) ที่คุณสามารถใช้เพื่อปรับเปลี่ยนวิธีการทำงานของคำสั่ง ตัวเลือกถูกรวมอยู่ในข้อกำหนด POSIX สำหรับอินเทอร์เฟซบรรทัดคำสั่ง นี่ยังเป็นข้อตกลงที่สืบมาตั้งแต่แอปพลิเคชัน UNIX เริ่มต้น จึงเป็นเรื่องดีที่ควรรู้วิธีรวมพวกมันในสคริปต์ Bash ของคุณเมื่อคุณสร้างคำสั่งของตัวเอง
เหมือนกับภาษาส่วนใหญ่ มีหลายวิธีในการแก้ปัญหาการ parse options ใน Bash จนถึงวันนี้ วิธีที่ผมชอบมากที่สุดยังคงเป็นวิธีที่ผมเรียนรู้จากสคริปต์สร้าง Slackware ของ Patrick Volkerding ซึ่งเป็นการแนะนำสู่ shell scripting ของผม ตอนที่ผมค้นพบ Linux และกล้าเข้าไปดูไฟล์ข้อความธรรมดาที่มาพร้อมกับ OS
การ Parse Options ใน Bash
กลยุทธ์สำหรับการ parse options ใน Bash คือ วนลูปผ่านอาร์กิวเมนต์ทั้งหมดที่ส่งให้ shell script ตรวจสอบว่าพวกมันเป็น option หรือไม่ แล้ว shift ไปยังอาร์กิวเมนต์ถัดไป ทำซ้ำกระบวนการนี้จนกว่าจะไม่มี options เหลือ
เริ่มต้นด้วยตัวเลือก Boolean แบบง่าย (บางครั้งเรียกว่า switch หรือ flag):
#!/bin/bash while [ True ]; do if [ "$1" = "--alpha" -o "$1" = "-a" ]; then ALPHA=1 shift 1 else break fi done echo $ALPHA
ในโค้ดนี้ ผมสร้างลูป while ซึ่งทำงานเป็นลูปไม่รู้จบจนกว่าจะไม่มีอาร์กิวเมนต์เหลือให้ประมวลผล คำสั่ง if พยายามจับคู่อาร์กิวเมนต์ที่พบในตำแหน่งแรก ($1) กับ --alpha หรือ -a (นี่คือชื่อตัวเลือก tùy ý ไม่มีความหมายพิเศษ ในสคริปต์จริง คุณอาจใช้ --verbose และ -v เพื่อเปิดโหมด verbose output)
คีย์เวิร์ด shift ทำให้อาร์กิวเมนต์ทั้งหมดเลื่อนที่ 1 ตำแหน่ง ทำให้อาร์กิวเมนต์ในตำแหน่ง 2 ($2) ย้ายไปตำแหน่ง 1 ($1) คำสั่ง else จะถูกกระตุ้นเมื่อไม่มีอาร์กิวเมนต์เหลือให้ประมวลผล ซึ่งทำให้ลูป while หยุด
ที่ท้ายของสคริปต์ ค่าของ $ALPHA จะถูกพิมพ์ไปยังเทอร์มินัล
ทดสอบสคริปต์:
$ bash ./test.sh --alpha 1 $ bash ./test.sh $ bash ./test.sh -a 1
ตัวเลือกถูกตรวจจับถูกต้อง
การตรวจจับอาร์กิวเมนต์ใน Bash
มีปัญหา อย่างไรก็ตาม: อาร์กิวเมนต์เพิ่มเติมถูกละเลย
$ bash ./test.sh --alpha foo 1 $
เพื่อจับอาร์กิวเมนต์ที่ไม่ได้ตั้งใจเป็นตัวเลือก คุณสามารถทิ้งอาร์กิวเมนต์ที่เหลือลงในอาร์เรย์ Bash
#!/bin/bash
while [ True ]; do
if [ "$1" = "--alpha" -o "$1" = "-a" ]; then
ALPHA=1
shift 1
else
break
fi
done
echo $ALPHA
ARG=( "${@}" )
for i in ${ARG[@]}; do
echo $i
done
ทดสอบเวอร์ชันใหม่ของสคริปต์:
$ bash ./test.sh --alpha foo 1 foo $ bash ./test.sh foo foo $ bash ./test.sh --alpha foo bar 1 foo bar
ตัวเลือกที่มีอาร์กิวเมนต์
บางตัวเลือกต้องการอาร์กิวเมนต์ของตัวเอง ตัวอย่างเช่น คุณอาจต้องการให้ผู้ใช้ตั้งค่าแอตทริบิวต์ เช่น สี หรือความละเอียดของกราฟิก หรือชี้แอปพลิเคชันไปยังไฟล์กำหนดค่าแบบกำหนดเอง
เพื่อนำสิ่งนี้มาใช้ใน Bash คุณสามารถใช้คีย์เวิร์ด shift เหมือนกับ boolean switches แต่ shift อาร์กิวเมนต์ 2 ตำแหน่ง แทนที่จะเป็น 1
#!/bin/bash
while [ True ]; do
if [ "$1" = "--alpha" -o "$1" = "-a" ]; then
ALPHA=1
shift 1
elif [ "$1" = "--config" -o "$1" = "-c" ]; then
CONFIG=$2
shift 2
else
break
fi
done
echo $ALPHA
echo $CONFIG
ARG=( "${@}" )
for i in ${ARG[@]}; do
echo $i
done
ในโค้ดนี้ ผมเพิ่มเงื่อนไข elif เพื่อเปรียบเทียบแต่ละอาร์กิวเมนต์กับ --config และ -c ในกรณีที่ตรงกัน ค่าของตัวแปรชื่อ CONFIG จะถูกตั้งค่าเป็นค่าของอาร์กิวเมนต์ที่สอง (นี่หมายความว่าตัวเลือก --config ต้องการอาร์กิวเมนต์) อาร์กิวเมนต์ทั้งหมดเลื่อนที่ 2 ตำแหน่ง: 1 เพื่อเลื่อน --config หรือ -c และ 1 เพื่อเลื่อนอาร์กิวเมนต์ของมัน ตามปกติ ลูปจะทำซ้ำจนไม่มีอาร์กิวเมนต์ที่ตรงกันเหลือ
นี่คือการทดสอบเวอร์ชันใหม่ของสคริปต์:
$ bash ./test.sh --config my.conf foo bar my.conf foo bar $ bash ./test.sh -a --config my.conf baz 1 my.conf baz
การ Parse Options อย่างง่ายดาย
มีวิธีอื่นๆ ในการ parse options ใน Bash คุณสามารถใช้คำสั่ง case หรือคำสั่ง getopt ได้เช่นกัน 无论你选择使用什么,选项对于您的用户来说都是任何应用程序的重要功能,而 Bash 使其变得简单。