ฉันจะตรวจจับได้อย่างไรว่าไม่มีตัวเลือกใดถูกส่งผ่านด้วย getopts


19

ฉันมีรหัสนี้ -

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
done
print 'hi'$name

เมื่อผมทำงานbash getoptDemos.sh(ไม่มีตัวเลือก) จะพิมพ์แทนการเรียกฟังก์ชั่นhi usageมันเรียกการใช้งานเมื่อตัวเลือกอื่นนอกเหนือจาก w, h และ l จะได้รับ จากนั้นไม่สามารถใช้งานได้เมื่อไม่มีการระบุตัวเลือก

ผมได้ลองใช้?, \?, :ในสถานที่ของ*แต่ฉันไม่สามารถบรรลุสิ่งที่ผมอยากจะ ผมหมายถึงทั้งหมดที่docsเกี่ยวกับการบอกว่ามันกับการใช้งานgetopt?

ผมทำอะไรผิดหรือเปล่า?


คุณใช้เปลือกอะไรอยู่?
Julian

ฉันกำลังใช้งานภายใต้/bin/bash
Hussain Tamboli

ทางเลือกอื่น ๆ : wiki.bash-hackers.org/howto/getopts_tutorial
slm

คำตอบ:


15

เมื่อคุณรันสคริปต์นี้โดยไม่มีตัวเลือกใด ๆ getopt จะคืนค่าเท็จดังนั้นมันจะไม่เข้าสู่ลูปเลย มันจะเลื่อนลงไปที่การพิมพ์ - นี่คือ ksh / zsh หรือไม่?

หากคุณต้องมีตัวเลือกคุณเป็นวิธีที่ดีที่สุดคือทดสอบ $ name หลังลูป

if [ -z "$name" ]
then
   usage
   exit
fi

แต่ตรวจสอบให้แน่ใจว่า$nameว่างเปล่าก่อนที่จะโทรgetopts(เนื่องจากอาจมี$nameสภาพแวดล้อมที่เชลล์ได้รับเมื่อเริ่มต้น) ด้วย

unset name

(ก่อนgetoptsลูป)


ไม่ มันทุบตี ดังนั้นฉันจะบรรลุสิ่งที่ฉันต้องการได้อย่างไร - จัดการกับno argumentเงื่อนไขโดยใช้ bash
Hussain Tamboli

หากคุณต้องการตัวเลือกที่จำเป็นฉันไม่คิดว่าเป็นไปได้ - อาจเป็นเหตุผลว่าทำไมพวกเขาถึงเรียกตัวเลือก :) คุณสามารถทดสอบชื่อ $ แม้ว่าหลังจากวนรอบเพื่อให้แน่ใจว่าได้ตั้งค่าไว้แล้ว ถ้า [-z "$ name"]; จากนั้นใช้งาน ทางออก; fi
Julian

ขอบคุณ รหัสข้างต้นช่วยได้จริงๆ มันเลวร้ายเกินไปgetoptsไม่ได้มีบทบัญญัติดังกล่าว มีอะไรที่แย่ไปกว่านั้นคือไม่สามารถโหวตคุณได้
Hussain Tamboli

ถ้าฉันใช้เชลล์ตัวอื่นล่ะ zsh, sh. เชลล์อื่นที่ไม่ใช่ bash ดูแลเงื่อนไขนี้หรือไม่?
Hussain Tamboli

20

getoptsประมวลผลตัวเลือกในทางกลับกัน นั่นคืองานของมัน หากผู้ใช้ไม่มีตัวเลือกเกิดขึ้นการเรียกใช้ครั้งแรกของการgetoptsออกจากลูป while

หากไม่มีตัวเลือกใด ๆ ที่จะโต้แย้งค่าของOPTINDบ่งชี้จำนวนตัวเลือกที่ถูกส่งผ่าน โดยทั่วไปOPTINDคือจำนวนอาร์กิวเมนต์ที่เป็นตัวเลือกหรืออาร์กิวเมนต์ของตัวเลือกซึ่งตรงข้ามกับอาร์กิวเมนต์ที่ไม่ใช่ตัวเลือก (ตัวถูกดำเนินการ)

while getopts …; do …; done
if [ $OPTIND -eq 1 ]; then echo "No options were passed"; fi
shift $((OPTIND-1))
echo "$# non-option arguments"

ไม่ว่าในกรณีใดคุณจะไม่พยายามตรวจสอบว่าไม่มีตัวเลือกหรือไม่ แต่ไม่มีการnameส่งผ่านตัวเลือกการตั้งค่าใด ๆ ดังนั้นการตรวจสอบว่าnameไม่มีการตั้งค่า (และดูแลเพื่อล้างค่ามันเป็นครั้งแรก)


1
ขอบคุณ +1 สำหรับคุณ เมื่อฉันใส่ช่วง 3 บรรทัดจากรหัสของคุณใน sample.sh และเรียกใช้bash sample.sh -abc file.txtมันให้ 1 non-option arguments- ฉันจะทราบได้อย่างไรว่ามีตัวเลือกกี่ตัวเลือก (ที่นี่ 3)
Hussain Tamboli

1
แปลกไม่มีใครได้แสดงความคิดเห็นในข้อผิดพลาดเล็กน้อยนี้ - ถ้าไม่มีตัวเลือกจะได้รับ OPTIND จะเป็น 1 หลังจากนั้นในขณะที่ 'ห่วง getopts ... ' ดังนั้นการตรวจสอบถ้าควรตรวจสอบความเท่าเทียมกันกับ 1 ไม่เป็นศูนย์
แดเนียล

4

หากสคริปต์ของคุณต้องได้รับอาร์กิวเมนต์ตัวเลือกเป็นกรณีใด ๆ วางบล็อกนี้ในจุดเริ่มต้น (ก่อนที่จะ getops)

if [[ ! $@ =~ ^\-.+ ]]
then
  #display_help;
fi

บล็อกตรวจสอบว่าสตริงพารามิเตอร์ไม่เริ่มต้นด้วย-สัญลักษณ์สิ่งที่บ่งชี้ว่าพารามิเตอร์แรกไม่ใช่อาร์กิวเมนต์ตัวเลือก


2

ฉันจะตรวจสอบกับตัวแปร ถ้า getopts ไม่ผ่านลูปในกรณีที่ไม่มีอาร์กิวเมนต์คุณสามารถใช้สิ่งนั้นเช่นนี้:

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}

no_args="true"
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
    no_args="false"
done

[[ "$no_args" == "true" ]] && { usage; exit 1; }

print 'hi'$name

0

ก่อนถึงgetoptsบล็อกตรวจสอบเพื่อดูว่า$1(อาร์กิวเมนต์แรก / ตัวเลือกที่คุณส่งผ่านบรรทัดคำสั่ง) เท่ากับสตริงว่างเปล่า หากเป็นเช่นนั้นให้พิมพ์ข้อความการใช้งานและออก (หรือเรียกใช้ฟังก์ชัน "ไม่มีตัวเลือก" บางอย่างหากคุณเป็นผู้นิยมอนาธิปไตย) มิฉะนั้นให้getoptsแยกวิเคราะห์ตัวเลือกเช่นปกติ

เหตุผลที่คุณสมบัตินี้ไม่รวมอยู่ใน getopts เป็นเพราะคุณสามารถทำให้สำเร็จด้วยการทุบตีด้วย "if-else" ตัวอย่าง:

if [[ $1 == "" ]]; then
    Your_Usage_Function;
    exit;
else
   #parse options with getopts code block here;
fi

ทำให้รู้สึก?

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.