2011-10-05 27 views
9

Tôi đang sử dụng getopt (không phải getops) để cung cấp khả năng cho tập lệnh bash của tôi xử lý các tùy chọn và chuyển mạch (cả dạng dài và dạng ngắn).Trapping getopt invalid options

Tôi muốn có thể bẫy các tùy chọn không hợp lệ và xử lý chúng, thường phản hồi lại rằng người dùng nên thử cmd --help và sau đó thoát khỏi tập lệnh.

Thing là, các tùy chọn không hợp lệ đang được đánh bắt bằng getopt, mà là chính nó xuất ra một thông điệp như "getopt: tùy chọn không hợp lệ - 'x'"

Dưới đây là mô hình tôi đang sử dụng để thiết lập getopt của tôi thông số:

set -- $(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "[email protected]") 

trong đó cả $ LONG_OPTIONS và $ SHORT_OPTIONS là danh sách tùy chọn được phân tách bằng dấu phẩy.

Đây là cách tôi xử lý chế biến các tùy chọn:

while [ $# -gt 0 ] 
    do 
     case "$1" in 
      -h|--help) 
       cat <<END_HELP_OUTPUT 

    Help 
    ---- 

    Usage: ./cmd.sh 

    END_HELP_OUTPUT 

       shift; 
       exit 
       ;; 
      --opt1) 
       FLAG1=true 
       shift 
       ;; 
      --opt2) 
       FLAG2=true 
       shift 
       ;; 
      --) 
       shift 
       break 
       ;; 
      *) 
       echo "Option $1 is not a valid option." 
       echo "Try './cmd.sh --help for more information." 
       shift 
       exit 
       ;; 
     esac 
    done 

getopt -q sẽ ngăn chặn đầu ra, nhưng kế hoạch bẫy của tôi trong báo cáo kết quả case vẫn thất bại trong việc làm những gì tôi mong đợi. Thay vào đó, chương trình chỉ thực hiện, mặc dù các đối số không hợp lệ.

Trả lời

8

This loại phong cách làm việc cho tôi:

params="$(getopt -o d:h -l diff:,help --name "$cmdname" -- "[email protected]")" 

if [ $? -ne 0 ] 
then 
    usage 
fi 

eval set -- "$params" 
unset params 

while true 
do 
    case $1 in 
     -d|--diff) 
      diff_exec=(${2-}) 
      shift 2 
      ;; 
     -h|--help) 
      usage 
      exit 
      ;; 
     --) 
      shift 
      break 
      ;; 
     *) 
      usage 
      ;; 
    esac 
done 
+0

Trong trường hợp nào *) đạt được? – jarno

+0

@jarno Nếu bạn có sự không khớp giữa câu lệnh 'case' và lệnh gọi getopt', nó sẽ bị bắt ở đó. Nó chỉ là lập trình phòng thủ. – l0b0

0

Tôi không chắc chắn nếu điều này có thể giúp đỡ, nhưng getopt (1) sử dụng getopt (3) và nếu tôi nhớ chính xác getopt (3) báo cáo lỗi đàn áp nếu nhân vật nắm đấm của OPTSTRING là dấu hai chấm.

+0

Sử dụng ':' như ký tự đầu tiên trong vòng OPTSTRING ức chế thông báo đầu ra. Tuy nhiên, mã trả về từ getopt (1) vẫn không phải là nonzero và tùy chọn không được nhận ra không nhận được kết quả đầu ra bằng getopt (1). –

1

Đây không phải là giải pháp mạnh mẽ nhất, nhưng đó là hợp lý; nó dựa trên những điều sau đây:

  • Thông điệp lỗi getopt in được bắt đầu bằng "getopt:"
  • Giả định là nó có thể chấp nhận để vượt qua thông qua một phiên bản sạch-up thông báo lỗi getopt 's, tăng cường với thông tin tùy chỉnh.

đoạn Code:

# Invoke getopt; suppress its stderr initially. 
args=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "[email protected]" 2>/dev/null) 
if [[ $? -ne 0 ]]; then # getopt reported failure 
    # Rerun the same getopt command so we can capture stderr output *only* this time. 
    # Inefficient (and a potential maintenance headache, if literals were involved), but this will only execute in case of invalid input. 
    # Alternatively, redirect the first getopt invocation's stderr output to a temp. file and read it here. 
    errmsg=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "[email protected]" 2>&1 1>&-) 
    # Strip getopt's prefix and augment with custom information. 
    echo -e "${errmsg#getopt: }\nTry './cmd.sh --help for more information." 1>&2 
    exit 1 
fi 
+0

Có thể hoạt động, eh? Như bạn đã nói, khá mong manh. –

+0

@TomAuger: Nếu bạn cho rằng các cụm từ "khá mong manh" đầy đủ "không mạnh mẽ nhất, nhưng nó hợp lý", bạn phải chạy một trình bao bằng tiếng Anh không tương thích. Luôn luôn, cố gắng để có được thông tin ra khỏi 'getopt' đáng tin cậy rằng nó không được thiết kế để báo cáo lập trình sẽ được khôn lanh. Điều đó nói rằng, một phần về giả định rằng đầu ra stderr đến đầu tiên thực sự là run rẩy, vì vậy tôi đã sửa đổi mã để giải quyết điều đó. Nếu bạn làm thế nào để nắm bắt stdout và stderr thành các biến riêng biệt từ một lệnh thực thi đơn lẻ (không liên quan đến việc tạo các tệp tạm thời), hãy cho tôi biết. – mklement0

1

Bạn phải sử dụng getopt ở tất cả? Nếu bạn chỉ sử dụng

while [ $# -gt 0 ]; do 
    case "$1" in 
    -d|--diff) 
     diff_exec=(${2-}) 
     shift 
     ;; 
    -h|--help) 
     usage 
     exit 
     ;; 
    --) 
     break 
     ;; 
    *) 
     usage 
     ;; 
    esac 
    shift 
done 

Sau đó, bạn sở hữu mã đang thực hiện kiểm tra.

1

Tôi thấy điều này để làm việc như mục cuối cùng trong báo cáo kết quả getopts trường hợp:

*) eval echo "Không nhận ra arg \ $$ [OPTIND-1]"; sử dụng; lối thoát ;;

0

Đây là phân tích cú pháp dòng lệnh tôi đã sử dụng. Nó có thể được cải thiện với nhiều phân tích logic hơn để xử lý các tùy chọn và tham số bị thiếu.

Đối với dòng lệnh: -a -b AA BB -c CC,/ba = AA b = kết quả của BB c = CC

OPT=("[email protected]") # Parses the command line into words. 

for [[ I=0;I<${#OPT[@]};I++ ]] 
    do 
     case "${OPT[$I]}" in   
     -a) a=${OPT[$I+1]} ;;   
     -b) b=${OPT[$I+1]} ;;   
     -c) c=${OPT[$I+1]} ;;  
     esac 
    done 
Các vấn đề liên quan