getopt
และgetopts
เป็นสัตว์ที่แตกต่างกันและผู้คนดูเหมือนจะมีความเข้าใจผิดบ้างเกี่ยวกับสิ่งที่พวกเขาทำ getopts
เป็นคำสั่งในตัวbash
เพื่อประมวลผลตัวเลือกบรรทัดคำสั่งในลูปและกำหนดตัวเลือกและค่าที่พบแต่ละตัวให้กับตัวแปรบิวด์อินดังนั้นคุณจึงสามารถประมวลผลได้ getopt
อย่างไรก็ตามเป็นโปรแกรมอรรถประโยชน์ภายนอกและไม่ได้ประมวลผลตัวเลือกของคุณสำหรับคุณเช่น bash getopts
, Getopt
โมดูลPerl หรือ Python optparse
/ argparse
modules ทำ สิ่งที่getopt
ทำคือกำหนดตัวเลือกที่ส่งผ่าน - ให้แปลงเป็นรูปแบบมาตรฐานมากขึ้นเพื่อให้เชลล์สคริปต์ประมวลผลได้ง่ายขึ้น ตัวอย่างเช่นแอปพลิเคชันgetopt
อาจแปลงสิ่งต่อไปนี้:
myscript -ab infile.txt -ooutfile.txt
เป็นนี้
myscript -a -b -o outfile.txt infile.txt
คุณต้องทำการประมวลผลจริงด้วยตัวเอง คุณไม่จำเป็นต้องใช้getopt
เลยหากคุณมีข้อ จำกัด ต่าง ๆ เกี่ยวกับวิธีที่คุณสามารถระบุตัวเลือก:
- ใส่เพียงหนึ่งตัวเลือกต่อการโต้แย้ง;
- ตัวเลือกทั้งหมดไปข้างหน้าพารามิเตอร์ตำแหน่งใด ๆ (เช่นอาร์กิวเมนต์ที่ไม่ใช่ตัวเลือก);
- สำหรับตัวเลือกที่มีค่า (เช่น
-o
ด้านบน) ค่าจะต้องเป็นอาร์กิวเมนต์แยกต่างหาก (หลังจากเว้นวรรค)
ทำไมต้องใช้getopt
แทนgetopts
? เหตุผลพื้นฐานคือมีเพียง GNU ที่getopt
ให้การสนับสนุนตัวเลือกบรรทัดคำสั่งที่มีชื่อยาว 1 (GNU getopt
เป็นค่าเริ่มต้นบน Linux Mac OS X และ FreeBSD มาพร้อมกับรุ่นพื้นฐานและไม่มีประโยชน์มากgetopt
แต่สามารถติดตั้งรุ่น GNU ได้ดูด้านล่าง)
ตัวอย่างเช่นนี่คือตัวอย่างของการใช้ GNU getopt
จากสคริปต์ของฉันที่เรียกว่าjavawrap
:
# NOTE: This requires GNU getopt. On Mac OS X and FreeBSD, you have to install this
# separately; see below.
TEMP=`getopt -o vdm: --long verbose,debug,memory:,debugfile:,minheap:,maxheap: \
-n 'javawrap' -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
VERBOSE=false
DEBUG=false
MEMORY=
DEBUGFILE=
JAVA_MISC_OPT=
while true; do
case "$1" in
-v | --verbose ) VERBOSE=true; shift ;;
-d | --debug ) DEBUG=true; shift ;;
-m | --memory ) MEMORY="$2"; shift 2 ;;
--debugfile ) DEBUGFILE="$2"; shift 2 ;;
--minheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MinHeapFreeRatio=$2"; shift 2 ;;
--maxheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MaxHeapFreeRatio=$2"; shift 2 ;;
-- ) shift; break ;;
* ) break ;;
esac
done
สิ่งนี้ช่วยให้คุณระบุตัวเลือกเช่น--verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"
หรือคล้ายกัน ผลกระทบของการเรียกไปยังgetopt
คือกำหนดตัวเลือกให้เป็นมาตรฐานเพื่อ--verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"
ให้คุณสามารถดำเนินการได้ง่ายขึ้น การอ้างถึง"$1"
และ"$2"
มีความสำคัญเนื่องจากทำให้มั่นใจได้ว่าข้อโต้แย้งที่มีช่องว่างในนั้นจะได้รับการจัดการอย่างถูกต้อง
หากคุณลบ 9 บรรทัดแรก (ทุกอย่างจนถึงeval set
บรรทัด) รหัสจะยังใช้งานได้ ! อย่างไรก็ตามรหัสของคุณจะเป็นตัวเลือกที่ดีกว่าในประเภทตัวเลือกที่ยอมรับ: โดยเฉพาะอย่างยิ่งคุณจะต้องระบุตัวเลือกทั้งหมดในแบบฟอร์ม "มาตรฐาน" ตามที่อธิบายไว้ข้างต้น อย่างไรก็ตามด้วยการใช้งานgetopt
คุณสามารถจัดกลุ่มตัวเลือกแบบตัวอักษรเดียวใช้แบบยาวแบบไม่คลุมเครือของตัวเลือกแบบยาวใช้แบบ--file foo.txt
หรือ--file=foo.txt
แบบใช้แบบ-m 4096
หรือ-m4096
แบบตัวเลือกแบบผสมและแบบไม่มีตัวเลือกในลำดับใด ๆ ฯลฯ getopt
เอาท์พุทข้อความแสดงข้อผิดพลาดหากพบตัวเลือกที่ไม่รู้จักหรือคลุมเครือ
หมายเหตุ : จริง ๆ แล้วมีสองรุ่นที่แตกต่างกันโดยสิ้นเชิงของgetopt
พื้นฐานgetopt
และ GNU ที่getopt
มีคุณสมบัติที่แตกต่างกันและการประชุมที่แตกต่างกัน 2พื้นฐานgetopt
ค่อนข้างเสียหาย: ไม่เพียงจัดการกับตัวเลือกที่ยาว แต่ยังไม่สามารถจัดการช่องว่างที่ฝังอยู่ภายในอาร์กิวเมนต์หรือว่างเปล่าในขณะที่getopts
ทำสิ่งนี้ถูกต้อง getopt
รหัสข้างต้นจะไม่ทำงานในขั้นพื้นฐาน GNU ได้getopt
รับการติดตั้งตามค่าเริ่มต้นบน Linux แต่สำหรับ Mac OS X และ FreeBSD จะต้องติดตั้งแยกต่างหาก บน Mac OS X ให้ติดตั้ง MacPorts ( http://www.macports.org ) จากนั้นทำการsudo port install getopt
ติดตั้ง GNU getopt
(โดยทั่วไป/opt/local/bin
) และตรวจสอบให้แน่ใจว่า/opt/local/bin
อยู่ในเส้นทางเชลล์ของคุณก่อน/usr/bin
และให้แน่ใจว่า บน FreeBSD ให้ติดตั้งmisc/getopt
.
คู่มือรวดเร็วในการปรับเปลี่ยนโค้ดตัวอย่างสำหรับโปรแกรมของคุณเอง: ในไม่กี่บรรทัดแรกทั้งหมดคือ "ต้นแบบ" getopt
ที่ควรจะอยู่เหมือนกันยกเว้นสายที่โทร คุณควรเปลี่ยนชื่อโปรแกรมหลังจาก-n
ระบุตัวเลือกสั้น ๆ หลังจากและตัวเลือกนานหลังจากที่-o
--long
ใส่เครื่องหมายจุดคู่หลังตัวเลือกที่รับค่า
สุดท้ายหากคุณเห็นรหัสที่ได้มาเพียงแค่set
แทนeval set
มันถูกเขียนขึ้นสำหรับ getopt
BSD คุณควรเปลี่ยนไปใช้eval set
รูปแบบซึ่งทำงานได้ดีกับทั้งสองรุ่นgetopt
ในขณะที่ธรรมดาset
ไม่ได้ทำงานที่ถูกต้องกับ getopt
GNU
1อันที่จริงgetopts
ในksh93
การสนับสนุนระยะยาวที่มีชื่อตัวเลือก bash
แต่เปลือกนี้จะไม่ใช้บ่อยเท่า ในzsh
ใช้zparseopts
เพื่อรับฟังก์ชั่นนี้
2 ในทางเทคนิค "GNU getopt
" เป็นชื่อเรียกที่ไม่ถูกต้อง รุ่นนี้เขียนขึ้นจริงสำหรับ Linux มากกว่าโครงการ GNU อย่างไรก็ตามมันเป็นไปตามอนุสัญญา GNU ทั้งหมดและgetopt
มักใช้คำว่า "GNU " (เช่นใน FreeBSD)