Làm cách nào để xử lý các công tắc trong tập lệnh shell?


17

Có một số công cụ tích hợp sẽ nhận ra -x--xxxxlà các công tắc, và không phải là đối số, hoặc bạn có phải trải qua tất cả các biến đầu vào, kiểm tra dấu gạch ngang và sau đó phân tích các đối số sau đó không?

Câu trả lời:


16

Sử dụng getopts.

Nó khá di động vì nó nằm trong thông số POSIX. Thật không may, nó không hỗ trợ các tùy chọn dài.

Xem thêm getopts hướng dẫn này với sự giúp đỡ của wiki bash-hacker và câu hỏi này từ stackoverflow.

Nếu bạn chỉ cần các tùy chọn ngắn, mẫu sử dụng thông thường cho getopts(sử dụng báo cáo lỗi không im lặng) là:

# 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
Cần phải đề cập rằng getoptphải luôn được xác minh là GNU getopt trước khi bạn sử dụng nó, nhưng dù sao bạn cũng không nên sử dụng nó vì nó dễ mang theo getoptshơn (và nói chung là đẹp hơn). Nếu bạn làm cần phải gọi nó là đối với một số lý do, gọi nó là một cách GNU cụ thể, và đảm bảo rằng GETOPT_COMPATIBLEkhông có trong môi trường.
Chris Xuống

Đại tràng while getopts "ab:" optlàm gì?
dùng394

1
@ user394 Chữ cái :sau tùy chọn biểu thị nó yêu cầu một đối số. A :là ký tự đầu tiên có nghĩa là để chặn các thông báo lỗi.
jw013

22

Tôi giả sử bạn đang sử dụng bash hoặc tương tự. Một ví dụ:

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 để sử dụng +=với một mảng. Không biết bạn có thể làm điều đó. Đẹp!
James Sneeringer

5

Bạn phải viết một chu kỳ để phân tích các tham số. Thật vậy, bạn có thể sử dụng getoptslệnh để làm điều đó một cách dễ dàng.

Đây là một ví dụ đơn giản từ getoptstrang hướng dẫn:

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

Gần đây tôi đã viết một kịch bản cho công việc linh hoạt và được phép cho nhiều loại công tắc theo bất kỳ thứ tự nào. Tôi không thể tiết lộ kịch bản đầy đủ vì lý do pháp lý rõ ràng (không đề cập đến việc tôi không có nó với tôi vào lúc này), nhưng đây là phần thịt của nó .. bạn có thể đặt nó vào chương trình con và gọi nó ở cuối kịch bản của bạn:

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

Tôi khuyên bạn nên giới hạn tập lệnh bash của bạn dưới 400 dòng / 15k ký tự; kịch bản nói trên của tôi đã vượt quá kích thước này và trở nên rất khó để làm việc. Tôi bắt đầu viết lại nó trong Perl, phù hợp hơn cho nhiệm vụ. Hãy ghi nhớ điều đó khi bạn làm việc với các tập lệnh của mình trong bash. Bash là tuyệt vời cho các tập lệnh nhỏ và oneliners, nhưng bất cứ điều gì phức tạp hơn và tốt hơn hết bạn nên viết nó bằng Perl.

Lưu ý, tôi đã không kiểm tra những điều trên, vì vậy nó có thể không hoạt động, nhưng bạn có ý tưởng chung từ nó.


Cách bạn gọi optionsở cuối là không chính xác, nó sẽ trở lại -bash: syntax error near unexpected token $@. Gọi nó là options "$@".
Chris Xuống

Phải, tôi đã trộn lẫn Perl và Bash. Đã sửa.
laebshade

Điều whilekiện đó không nên (($#))thay thế?
manatwork

Tại sao bạn cần hai bộ dấu ngoặc cho $#? Chỉnh sửa: bạn đã đúng. Đã sửa nó thànhwhile (( "$#" ))
laebshade
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.