2012-07-31 26 views
35

Tôi muốn thiết kế kịch bản lệnh shell làm trình bao bọc cho một vài tập lệnh. Tôi muốn chỉ định tham số cho myshell.sh bằng cách sử dụng getopts và chuyển các tham số còn lại theo cùng thứ tự cho tập lệnh được chỉ định.Shell Script: đang trộn các getopts với các tham số vị trí có thể?

Nếu myshell.sh được thực hiện như:

myshell.sh -h hostname -s test.sh -d waittime param1 param2 param3 

myshell.sh param1 param2 -h hostname param3 -d waittime -s test.sh 

myshell.sh param1 -h hostname -d waittime -s test.sh param2 param3 

Tất cả những điều trên sẽ có thể gọi như

test.sh param1 param2 param3 

Có thể sử dụng các thông số tùy chọn trongmyshell.shvà bài các tham số còn lại cho tập lệnh cơ bản?

+0

bạn đang cố gắng làm gì đây? Bạn muốn gọi 'test.sh param1 param2 param3' vào' myshell.sh'? –

+0

Xin lỗi nếu nó không rõ ràng từ câu hỏi. Vâng. Tôi muốn cho phép kịch bản của tôi xử lý kết hợp các tham số vị trí và các giá trị getopt. tất cả mọi thứ còn lại từ getopt phải được truyền với kịch bản shell bên dưới. – SiB

+1

Chỉ dòng đầu tiên tuân thủ các tiêu chuẩn unix (xem bên dưới) để xử lý tùy chọn. Làm như vậy nếu không sẽ có nhiều công việc hơn để có được quyền, và để duy trì. –

Trả lời

65

Xin lỗi vì bình luận về một chủ đề cũ, nhưng nghĩ rằng tôi muốn gửi cho những người, như tôi những người đang tìm kiếm về cách để làm điều này ...

tôi muốn làm một cái gì đó tương tự như OP, và tôi tìm thấy các thông tin liên quan tôi cần herehere

về cơ bản nếu bạn muốn làm một cái gì đó như:

script.sh [options] ARG1 ARG2 

Sau đó được lựa chọn của bạn như thế này:

while getopts "h:u:p:d:" flag; do 
case "$flag" in 
    h) HOSTNAME=$OPTARG;; 
    u) USERNAME=$OPTARG;; 
    p) PASSWORD=$OPTARG;; 
    d) DATABASE=$OPTARG;; 
esac 
done 

Và sau đó bạn có thể nhận được đối số vị trí của bạn như thế này:

ARG1=${@:$OPTIND:1} 
ARG2=${@:$OPTIND+1:1} 

biết thêm thông tin và chi tiết có sẵn thông qua các liên kết ở trên.

Hy vọng điều đó sẽ giúp ích !!

+24

Nhưng điều này không cho phép các đối số vị trí đặt trước cờ, là một phần của câu hỏi OP. Một cách tiêu chuẩn khác để xử lý vị trí/sau/cờ là chỉ cần thay đổi $ ((OPTIND-1)) sau esac của bạn và sau đó xử lý vị trí bình thường. – Chinasaur

+1

@Chinasaur Khi tôi sử dụng 'ARG1 = $ {@: $ OPTIND: 1}' sau khi nó làm việc cho tôi cho cả 'script.sh -h localhost abc' và' script.sh abc -h localhost' = trong ARG1 I có giá trị 'abc' trong cả hai trường hợp. Bạn có thể cụ thể hơn những gì không làm việc (những gì tôi hiểu lầm)? Cảm ơn! – Betlista

+0

Tôi không thể nhận được «ARG1'. Nó trống rỗng. – Sigur

3

getopts sẽ không phân tích cú pháp kết hợp của các tùy chọn param1-n.

Tốt hơn hết nên đặt param1-3 vào các tùy chọn như những người khác.

Ngoài ra, bạn có thể sử dụng các thư viện hiện có như shflags. Nó khá thông minh và dễ sử dụng.

Và cách cuối cùng là viết hàm của riêng bạn để phân tích cú pháp các tham số không có getopts, chỉ cần lặp lại tất cả các thông số thông qua việc xây dựng case. Đó là cách khó nhất nhưng đó là cách duy nhất để phù hợp với kỳ vọng của bạn một cách chính xác.

[Edit: cố định hai lỗi chính tả]

+0

Cảm ơn bạn. Cách tôi chọn ở đây là phân tích các tham số 'getopts' và sau đó là' shift' và chuyển các tham số tới tập lệnh cơ bản. – SiB

0

Có một số tiêu chuẩn để chế biến tùy chọn unix, và trong lập trình shell, getopts là cách tốt nhất để thực thi chúng. Hầu như bất kỳ ngôn ngữ hiện đại nào (perl, python) đều có một biến thể trên getopts.

Đây chỉ là một ví dụ nhanh:

command [ options ] [--] [ words ] 
  1. Mỗi tùy chọn phải bắt đầu với một dấu gạch ngang, -, và phải bao gồm một nhân vật duy nhất.

  2. Dự án GNU đã giới thiệu Tùy chọn dài, bắt đầu bằng hai dấu gạch ngang --, theo sau là toàn bộ từ, --long_option. Dự án AST KSH có một getopts cũng hỗ trợ các tùy chọn dài, các tùy chọn dài bắt đầu bằng một dấu gạch ngang, -, như trong find(1).

  3. Tùy chọn có thể hoặc không thể mong đợi đối số.

  4. Bất kỳ từ nào không bắt đầu bằng dấu gạch ngang, -, sẽ kết thúc xử lý tùy chọn.

  5. Chuỗi -- phải được bỏ qua và sẽ kết thúc xử lý tùy chọn.

  6. Bất kỳ đối số nào còn lại đều được để lại dưới dạng thông số vị trí.

The Open Group có một phần trên Utility Argument Syntax

Eric Raymond của The Art of Unix Programming has a chapter trên sự lựa chọn unix truyền thống cho chữ tùy chọn và ý nghĩa của chúng.

1

Tôi đã nghĩ ra một cách mà getopts có thể được mở rộng đến các tùy chọn kết hợp thực sự và thông số vị trí. Ý tưởng là để luân phiên giữa gọi getopts và gán bất kỳ tham số vị trí tìm thấy n1, n2, n3, v.v .:

parse_args() { 
    _parse_args 1 "[email protected]" 
} 

_parse_args() { 
    local n="$1" 
    shift 

    local options_func="$1" 
    shift 

    local OPTIND 
    "$options_func" "[email protected]" 
    shift $((OPTIND - 1)) 

    if [ $# -gt 0 ]; then 
     eval test -n \${n$n+x} 
     if [ $? -eq 0 ]; then 
      eval n$n="\$1" 
     fi 

     shift 
     _parse_args $((n + 1)) "$options_func" "[email protected]" 
    fi 
} 

Sau đó, trong trường hợp của OP, bạn có thể sử dụng nó như:

main() { 
    local n1='' n2='' n3='' 
    local duration hostname script 

    parse_args parse_main_options "[email protected]" 

    echo "n1 = $n1" 
    echo "n2 = $n2" 
    echo "n3 = $n3" 
    echo "duration = $duration" 
    echo "hostname = $hostname" 
    echo "script = $script" 
} 

parse_main_options() { 
    while getopts d:h:s: opt; do 
     case "$opt" in 
      d) duration="$OPTARG" ;; 
      h) hostname="$OPTARG" ;; 
      s) script="$OPTARG" ;; 
     esac 
    done 
} 

main "[email protected]" 

Chạy nó cho thấy kết quả đầu ra:

$ myshell.sh param1 param2 -h hostname param3 -d waittime -s test.sh 
n1 = param1 
n2 = param2 
n3 = param3 
duration = waittime 
hostname = hostname 
script = test.sh 

Chỉ là bằng chứng về khái niệm, nhưng có thể hữu ích cho người nào.

Lưu ý: có một Gotcha nếu một chức năng sử dụng parse_args gọi một chức năng sử dụng parse_args chức năng bên ngoài tuyên bố ví dụlocal n4='', nhưng một trong những nội không 4 hoặc nhiều tham số vị trí được truyền cho hàm nội

1

Chỉ cần nghiền lên một quickie, mà dễ dàng xử lý một hỗn hợp các tùy chọn và vị trí-thông số (chỉ để lại vị trí-params trong $ @): sản lượng

#!/bin/bash 
while [ ${#} -gt 0 ];do OPTERR=0;OPTIND=1;getopts "p:o:hvu" arg;case "$arg" in 
     p) echo "Path: [$OPTARG]" ;; 
     o) echo "Output: [$OPTARG]" ;; 
     h) echo "Help"    ;; 
     v) echo "Version"   ;; 
    \?) SET+=("$1")           ;; 
    *) echo "Coding error: '-$arg' is not handled by case">&2 ;; 
esac;shift;[ "" != "$OPTARG" ] && shift;done 
[ ${#SET[@]} -gt 0 ] && set "" "${SET[@]}" && shift 

echo -e "=========\nLeftover (positional) parameters (count=$#) are:" 
for i in `seq $#`;do echo -e "\t$i> [${!i}]";done 

mẫu:

[[email protected]:~]$ ./test.sh 'aa bb' -h -v -u -q 'cc dd' -p 'ee ff' 'gg hh' -o ooo 
Help 
Version 
Coding error: '-u' is not handled by case 
Path: [ee ff] 
Output: [ooo] 
========= 
Leftover (positional) parameters (count=4) are: 
     1> [aa bb] 
     2> [-q] 
     3> [cc dd] 
     4> [gg hh] 
[[email protected]:~]$ 
+1

Điều này không cho phép kết hợp một số tùy chọn trong một đối số "-abc" duy nhất. –

1

Mix opts và args:

ARGS="" 
echo "options :" 
while [ $# -gt 0 ] 
do 
    unset OPTIND 
    unset OPTARG 
    while getopts as:c: options 
    do 
    case $options in 
      a) echo "option a no optarg" 
        ;; 
      s) serveur="$OPTARG" 
        echo "option s = $serveur" 
        ;; 
      c) cible="$OPTARG" 
        echo "option c = $cible" 
        ;; 
     esac 
    done 
    shift $((OPTIND-1)) 
    ARGS="${ARGS} $1 " 
    shift 
done 

echo "ARGS : $ARGS" 
exit 1 

Kết quả:

bash test.sh -a arg1 arg2 -s serveur -c cible arg3 
options : 
option a no optarg 
option s = serveur 
option c = cible 
ARGS : arg1 arg2 arg3 
0

Bạn có thể thử mẹo này: sau khi vòng lặp với optargs, chỉ cần sử dụng đoạn mã này

#shift away all the options so that only positional agruments 
#remain in [email protected] 

for ((i=0; i<OPTIND-1; i++)); do 
    shift 
done 

POSITIONAL="[email protected]" 

Tuy nhiên, phương pháp này có một lỗi:

    tất cả các các tùy chọn sau đối số vị trí đầu tiên được nhập bởi các getopts và được coi là các đối số vị trí - sự kiện đó là đúng (xem đầu ra mẫu: -m và -c là một trong các đối số vị trí)

Có lẽ nó thậm chí còn nhiều lỗi ...

Nhìn vào toàn bộ ví dụ:

while getopts :abc opt; do 
    case $opt in 
     a) 
     echo found: -a 
     ;; 
     b) 
     echo found: -b 
     ;; 
     c) 
     echo found: -c 
     ;; 
     \?) echo found bad option: -$OPTARG 
     ;; 
    esac 
done 

#OPTIND-1 now points to the first arguments not beginning with - 

#shift away all the options so that only positional agruments 
#remain in [email protected] 

for ((i=0; i<OPTIND-1; i++)); do 
    shift 
done 

POSITIONAL="[email protected]" 

echo "positional: $POSITIONAL" 

Output:

[[email protected] ~]# ./abc.sh -abc -de -fgh -bca haha blabla -m -c 
found: -a 
found: -b 
found: -c 
found bad option: -d 
found bad option: -e 
found bad option: -f 
found bad option: -g 
found bad option: -h 
found: -b 
found: -c 
found: -a 
positional: haha blabla -m -c 
Các vấn đề liên quan