ฉันจะจัดการสวิตช์ในเชลล์สคริปต์ได้อย่างไร


17

มีเครื่องมือในตัวที่จะรับรู้-xและ--xxxxเป็นสวิตช์และไม่ขัดแย้งหรือคุณต้องผ่านตัวแปรอินพุททั้งหมดทดสอบการขีดกลางแล้วจึงแยกอาร์กิวเมนต์หลังจากนั้น

คำตอบ:


16

getoptsใช้

มันค่อนข้างพกพาได้เหมือนใน POSIX spec น่าเสียดายที่มันไม่รองรับตัวเลือกที่ยาว

ดูเพิ่มเติมนี้getopts กวดวิชามารยาทของทุบตีแฮกเกอร์วิกิพีเดียและคำถามจาก StackOverflow

หากคุณต้องการตัวเลือกสั้น ๆ รูปแบบการใช้งานทั่วไปสำหรับgetopts(โดยใช้การรายงานข้อผิดพลาดที่ไม่เงียบ) คือ:

# process arguments "$1", "$2", ... (i.e. "$@")
while getopts "ab:" opt; do
    case $opt in
    a) aflag=true ;; # Handle -a
    b) barg=$OPTARG ;; # Handle -b argument
    \?) ;; # Handle error: unknown option or missing required argument.
    esac
done

3
ควรกล่าวถึงว่าgetoptควรได้รับการยืนยันว่าเป็น GNU getopt ก่อนที่คุณจะใช้ แต่คุณไม่ควรใช้ต่อไปเนื่องจากgetoptsมีความสะดวกในการพกพามากกว่า ถ้าคุณทำจำเป็นต้องเรียกมันว่าด้วยเหตุผลบางอย่างเรียกมันในทางที่ GNU เฉพาะและให้แน่ใจว่าGETOPT_COMPATIBLEไม่ได้อยู่ในสภาพแวดล้อม
Chris Down

ลำไส้ใหญ่while getopts "ab:" optทำอะไร
user394

1
@ user394 :ตัวอักษรหลังหมายถึงต้องมีอาร์กิวเมนต์ A :เป็นตัวอักษรตัวแรกหมายถึงการระงับข้อความผิดพลาด
jw013

22

ฉันคิดว่าคุณกำลังใช้ bash หรือคล้ายกัน ตัวอย่าง:

all=false
long=false

while getopts ":hal" option; do
  case $option in
    h) echo "usage: $0 [-h] [-a] [-l] file ..."; exit ;;
    a) all=true ;;
    l) long=true ;;
    ?) echo "error: option -$OPTARG is not implemented"; exit ;;
  esac
done

# remove the options from the positional parameters
shift $(( OPTIND - 1 ))

ls_opts=()
$all && ls_opts+=( -a )
$long && ls_opts+=( -l )

# now, do it
ls "${ls_opts[@]}" "$@"

1
+1 สำหรับใช้+=กับอาเรย์ ไม่ทราบว่าคุณสามารถทำได้ ดี!
James Sneeringer

5

คุณต้องเขียนวงจรเพื่อวิเคราะห์พารามิเตอร์ แน่นอนคุณสามารถใช้getoptsคำสั่งเพื่อทำมันได้อย่างง่ายดาย

นี่เป็นตัวอย่างง่ายๆจากgetoptsหน้าคู่มือ:

aflag=
bflag=
while getopts ab: name
do
    case $name in
    a)    aflag=1;;
    b)    bflag=1
          bval="$OPTARG";;
    ?)    printf "Usage: %s: [-a] [-b value] args\n" $0
          exit 2;;
    esac
done
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"

2

ฉันเขียนสคริปต์เมื่อเร็ว ๆ นี้สำหรับงานที่หลากหลายและได้รับอนุญาตสำหรับสวิตช์หลายประเภทในลำดับใด ๆ ฉันไม่สามารถเปิดเผยสคริปต์เต็มได้ด้วยเหตุผลทางกฎหมายที่ชัดเจน (ไม่ต้องพูดถึงฉันไม่ได้มีอยู่กับฉันในขณะนี้) แต่นี่คือเนื้อของมัน .. คุณสามารถใส่ไว้ในรูทีนย่อยและเรียกมันได้ในตอนท้าย ของสคริปต์ของคุณ:

options () {

    if [ -n "$1" ]; then # test if any arguments passed - $1 will always exist
        while (( "$#" )); do  # process ALL arguments
            if [ "$1" = ^-t$ ]; then # -t short for "test"
                # do something here THEN shift the argument
                # shift removes it from $@ and reduces $# by
                # one if you supply no argument
                shift

            # we can also process multiple arguments at once
            elif [[ "$1" =~ ^--test=[:alnum:]{1,8}$ ]] && [[ "$2" =~ ^-t2$ ]] && [[ -n "$3" ]]; then # check for 3 arguments
                # do something more then remove them ALL from the arg list    
                shift 3
            else
                echo "No matching arguments!"
                echo "Usage: [script options list here]"
            fi
        done
    else
        echo "Usage: [script options list here]"
        exit 0
    fi
}

options "$@" # run options and loop through/process ALL arguments

ฉันแนะนำให้ จำกัด สคริปต์ bash ของคุณให้เหลือน้อยกว่า 400 บรรทัด / 15k ตัวอักษร สคริปต์ดังกล่าวของฉันเติบโตขึ้นขนาดนี้และกลายเป็นเรื่องยากมากที่จะทำงาน ฉันเริ่มเขียนใหม่ใน Perl ซึ่งเหมาะกับงานมากขึ้น จำไว้ว่าเมื่อคุณทำงานกับสคริปต์ของคุณในการทุบตี Bash นั้นยอดเยี่ยมสำหรับสคริปต์ขนาดเล็กและผู้บุกรุกออนไลน์ แต่มีอะไรที่ซับซ้อนกว่านี้และคุณควรเขียนมันใน Perl

หมายเหตุฉันยังไม่ได้ทดสอบข้างต้นดังนั้นมันอาจไม่ทำงาน แต่คุณได้รับแนวคิดทั่วไปจากมัน


วิธีที่คุณโทรหาที่สิ้นสุดไม่ถูกต้องก็จะกลับoptions เรียกว่าเป็น-bash: syntax error near unexpected token $@ options "$@"
Chris Down

ใช่ฉันผสม Perl กับ Bash แล้ว การแก้ไข
laebshade

ที่whileสภาพไม่ควรจะ(($#))แทน?
จัดการ

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