2013-02-09 42 views
9

Sau vài ngày research, tôi vẫn không thể tìm ra phương pháp tốt nhất để phân tích cú pháp cmdline args trong tập lệnh .sh. Theo tài liệu tham khảo của tôi getopts cmd là con đường để đi vì nó "chiết xuất và kiểm tra công tắc mà không làm phiền các tham số vị trí variables.Unexpected bị chuyển mạch, hoặc công tắc đang thiếu lập luận, được công nhận và reportedas lỗi."Cách tốt nhất để phân tích cú pháp dòng lệnh args trong Bash là gì?

Positional params (Ví dụ 2 - $ @, $ #, vv) dường như không hoạt động tốt khi không gian được tham gia nhưng có thể nhận ra các tham số thường xuyên và dài (-p và --longparam). Tôi nhận thấy rằng cả hai phương thức đều thất bại khi truyền các tham số với các dấu ngoặc lồng nhau ("đây là một Ex. Of" "dấu ngoặc kép" "."). Một trong ba mẫu mã nào tốt nhất minh họa cách xử lý cmdline args? Chức năng getopt không được khuyến khích bởi rất kinh nghiệm, vì vậy tôi đang cố gắng tránh nó!

Ví dụ 1:

#!/bin/bash 
for i in "[email protected]" 
do 
case $i in 
    -p=*|--prefix=*) 
    PREFIX=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` 

    ;; 
    -s=*|--searchpath=*) 
    SEARCHPATH=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` 
    ;; 
    -l=*|--lib=*) 
    DIR=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` 
    ;; 
    --default) 
    DEFAULT=YES 
    ;; 
    *) 
      # unknown option 
    ;; 
esac 
done 
exit 0 

Ví dụ 2:

#!/bin/bash 
echo ‘number of arguments’ 
echo "\$#: $#" 
echo ” 

echo ‘using $num’ 
echo "\$0: $0" 
if [ $# -ge 1 ];then echo "\$1: $1"; fi 
if [ $# -ge 2 ];then echo "\$2: $2"; fi 
if [ $# -ge 3 ];then echo "\$3: $3"; fi 
if [ $# -ge 4 ];then echo "\$4: $4"; fi 
if [ $# -ge 5 ];then echo "\$5: $5"; fi 
echo ” 

echo ‘using [email protected]’ 
let i=1 
for x in [email protected]; do 
echo "$i: $x" 
let i=$i+1 
done 
echo ” 

echo ‘using $*’ 
let i=1 
for x in $*; do 
echo "$i: $x" 
let i=$i+1 
done 
echo ” 

let i=1 
echo ‘using shift’ 
while [ $# -gt 0 ] 
do 
echo "$i: $1" 
let i=$i+1 
shift 
done 

[/bash] 

output: 

bash> commandLineArguments.bash 
number of arguments 
$#: 0 

using $num 
$0: ./commandLineArguments.bash 

using [email protected] 

using $* 

using shift 
#bash> commandLineArguments.bash "abc def" g h i j* 

Ví dụ 3:

#!/bin/bash 

while getopts ":a:" opt; do 
    case $opt in 
    a) 
     echo "-a was triggered, Parameter: $OPTARG" >&2 
     ;; 
    \?) 
     echo "Invalid option: -$OPTARG" >&2 
     exit 1 
     ;; 
    :) 
     echo "Option -$OPTARG requires an argument." >&2 
     exit 1 
     ;; 
    esac 
done 

exit 0 
+1

bản sao có thể có của [Làm cách nào để phân tích đối số dòng lệnh trong bash?] (Http://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash) –

Trả lời

18

tôi thấy việc sử dụng các getopt là cách dễ nhất. Nó cung cấp xử lý chính xác các đối số mà là khôn lanh khác. Ví dụ: getopt sẽ biết cách xử lý đối số cho một tùy chọn dài được chỉ định trên dòng lệnh là --arg=option hoặc --arg option.

Điều gì hữu ích khi phân tích cú pháp bất kỳ đầu vào nào được chuyển đến tập lệnh hệ vỏ là sử dụng biến số "[email protected]". Xem trang bash man để biết cách này khác với [email protected]. Nó đảm bảo rằng bạn có thể xử lý các đối số bao gồm dấu cách.

Dưới đây là một ví dụ về làm thế nào tôi có thể viết s kịch bản để phân tích một số đối số dòng lệnh đơn giản:

#!/bin/bash 

args=$(getopt -l "searchpath:" -o "s:h" -- "[email protected]") 

eval set -- "$args" 

while [ $# -ge 1 ]; do 
     case "$1" in 
       --) 
        # No more options left. 
        shift 
        break 
        ;; 
       -s|--searchpath) 
         searchpath="$2" 
         shift 
         ;; 
       -h) 
         echo "Display some help" 
         exit 0 
         ;; 
     esac 

     shift 
done 

echo "searchpath: $searchpath" 
echo "remaining args: $*" 

Và sử dụng như thế này để chứng minh rằng không gian và dấu ngoặc kép được bảo quản:

[email protected]:~/bin$ ./getopt_test --searchpath "File with spaces and \"quotes\"." 
searchpath: File with spaces and "quotes". 
remaining args: other args 

Một số thông tin cơ bản về việc sử dụng getopt có thể được tìm thấy here

+2

Đó là một ví dụ tốt về getopt Austin. Chủ đề cụ thể này đã được thảo luận rộng rãi trên [stackoverflow] (http://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line- tùy chọn/7680682 # 7680682). Sự khác biệt là getopt đồng bằng cũ không phải là mạnh mẽ như getopts và không hoạt động trên các hệ thống cũ. Getopts có thể phân tích các công tắc dài chỉ miễn là có một phiên bản ngắn của cùng một công tắc, do đó, nó đòi hỏi một chút tinh chỉnh. Tôi sẽ dính w/getopts. Tôi thay vì sử dụng một chức năng được xây dựng trong hơn là và exec cũ (getopt) cho các kịch bản chuyên nghiệp. – LogicalConfusion

0

Nếu bạn muốn tránh sử dụng getopt bạn ca n sử dụng phương pháp tiếp cận nhanh đẹp này:
- Xác định trợ giúp với tất cả các tùy chọn là ## nhận xét (tùy chỉnh theo ý bạn);
- Xác định cho mỗi tùy chọn một hàm có cùng tên;
- Sao chép năm dòng cuối của tập lệnh này vào tập lệnh của bạn (ma thuật).

Ví dụ: nhật ký.sh

#!/bin/sh 
## $PROG 1.0 - Print logs [2017-10-01] 
## Compatible with bash and dash/POSIX 
## 
## Usage: $PROG [OPTION...] [COMMAND]... 
## Options: 
## -i, --log-info   Set log level to info (default) 
## -q, --log-quiet  Set log level to quiet 
## -l, --log MESSAGE  Log a message 
## Commands: 
## -h, --help    Displays this help and exists 
## -v, --version   Displays output version and exists 
## Examples: 
## $PROG -i myscrip-simple.sh > myscript-full.sh 
## $PROG -r myscrip-full.sh > myscript-simple.sh 
PROG=${0##*/} 
LOG=info 
die() { echo [email protected] >&2; exit 2; } 

log_info() { 
    LOG=info 
} 
log_quiet() { 
    LOG=quiet 
} 
log() { 
    [ $LOG = info ] && echo "$1"; return 1 ## number of args used 
} 
help() { 
    grep "^##" "$0" | sed -e "s/^...//" -e "s/\$PROG/$PROG/g"; exit 0 
} 
version() { 
    help | head -1 
} 

[ $# = 0 ] && help 
while [ $# -gt 0 ]; do 
    CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" go.sh | sed -e "s/-/_/g") 
    if [ -z "$CMD" ]; then echo "ERROR: Command '$1' not supported"; exit 1; fi 
    shift; eval "$CMD" [email protected] || shift $? 2> /dev/null 
done 

Thử nghiệm:

./log.sh --log yep --log-quiet -l nop -i -l yes sẽ sản xuất:

yep 
yes 

Bằng cách này: Nó tương thích với POSIX!

Các vấn đề liên quan