2011-08-15 30 views
176

Tôi biết rằng tôi có thể dễ dàng nhận được các thông số vị trí như thế này trong bash:Làm thế nào để có được tranh cãi với cờ trong kịch bản bash

$0 hoặc $1

Tôi muốn để có thể sử dụng tùy chọn lá cờ như thế này để xác định cho những gì mỗi tham số được sử dụng:

mysql -u user -h host 

cách tốt nhất để có được -u param giá trị và giá trị bằng cách -h param cờ thay vì bởi vị trí là gì?

+2

Nó có thể là một ý tưởng tốt để hỏi/kiểm tra tại http://unix.stackexchange.com/ cũng như – MRR0GERS

+6

google cho "bash getopts" - rất nhiều hướng dẫn. –

+48

@ glenn-jackman: Tôi chắc chắn sẽ google ngay bây giờ khi tôi biết tên. Điều về google là - để đặt câu hỏi - bạn đã biết 50% câu trả lời. – Stann

Trả lời

202

Đây là thành ngữ tôi thường sử dụng:

while test $# -gt 0; do 
     case "$1" in 
       -h|--help) 
         echo "$package - attempt to capture frames" 
         echo " " 
         echo "$package [options] application [arguments]" 
         echo " " 
         echo "options:" 
         echo "-h, --help    show brief help" 
         echo "-a, --action=ACTION  specify an action to use" 
         echo "-o, --output-dir=DIR  specify a directory to store output in" 
         exit 0 
         ;; 
       -a) 
         shift 
         if test $# -gt 0; then 
           export PROCESS=$1 
         else 
           echo "no process specified" 
           exit 1 
         fi 
         shift 
         ;; 
       --action*) 
         export PROCESS=`echo $1 | sed -e 's/^[^=]*=//g'` 
         shift 
         ;; 
       -o) 
         shift 
         if test $# -gt 0; then 
           export OUTPUT=$1 
         else 
           echo "no output dir specified" 
           exit 1 
         fi 
         shift 
         ;; 
       --output-dir*) 
         export OUTPUT=`echo $1 | sed -e 's/^[^=]*=//g'` 
         shift 
         ;; 
       *) 
         break 
         ;; 
     esac 
done 

Những điểm mấu chốt là:

  • $# là số đối số
  • Vòng lặp while nhìn vào tất cả các đối số cung cấp, phù hợp về giá trị của chúng bên trong một tuyên bố trường hợp
  • ca làm mất lần đầu tiên. Bạn có thể thay đổi nhiều lần bên trong câu lệnh trường hợp để nhận nhiều giá trị.
+2

Các trường hợp '--action *' và '--output-dir *' làm gì? – Lucio

+1

Họ chỉ lưu các giá trị mà họ nhận được vào môi trường. – Flexo

+3

Tôi đoán @Lucio có nghĩa là gì '*' cho ... – arod

35

getopt là bạn của bạn .. một ví dụ đơn giản:

function f() { 
TEMP=`getopt --long -o "u:h:" "[email protected]"` 
eval set -- "$TEMP" 
while true ; do 
    case "$1" in 
     -u) 
      user=$2 
      shift 2 
     ;; 
     -h) 
      host=$2 
      shift 2 
     ;; 
     *) 
      break 
     ;; 
    esac 
done; 

echo "user = $user, host = $host" 
} 

f -u myself -h some_host 

Nên có những ví dụ khác nhau trong thư mục/usr/bin của bạn.

+1

Một ví dụ rộng hơn có thể được tìm thấy trong thư mục '/ usr/share/doc/util-linux/example', ít nhất là trên các máy Ubuntu. –

209

Ví dụ này sử dụng Bash tích hợp trong getopts lệnh và là từ Google Shell Style Guide:

verbose='false' 
aflag='' 
bflag='' 
files='' 

while getopts 'abf:v' flag; do 
    case "${flag}" in 
    a) aflag='true' ;; 
    b) bflag='true' ;; 
    f) files="${OPTARG}" ;; 
    v) verbose='true' ;; 
    *) error "Unexpected option ${flag}" ;; 
    esac 
done 

Lưu ý: Nếu một nhân vật được theo sau bởi dấu hai chấm (ví dụ f:), tùy chọn đó dự kiến ​​sẽ có một cuộc tranh cãi .

Ví dụ sử dụng: ./script -v -a -b -f filename

Sử dụng getopts có một số ưu điểm so với các câu trả lời được chấp nhận:

  • điều kiện trong khi rất nhiều dễ đọc hơn và cho thấy những gì các tùy chọn chấp nhận được mã
  • sạch; không đếm số lượng các thông số và chuyển
  • bạn có thể tham gia lựa chọn (ví dụ -a -b -c-abc)

Tuy nhiên, một nhược điểm lớn là nó không hỗ trợ tùy chọn dài, chỉ có lựa chọn duy nhất nhân vật.

+16

Người ta tự hỏi tại sao câu trả lời này, sử dụng bash nội trang, không phải là câu trả lời hàng đầu –

+5

thì đây phải là câu trả lời được chấp nhận – woens

+2

Đối với hậu thế: dấu hai chấm sau trong 'abf: v' biểu thị rằng -f nhận thêm đối số (tên tệp trong trường hợp). – zahbaz

4

Một lựa chọn khác là sử dụng một cái gì đó giống như ví dụ dưới đây mà sẽ cho phép bạn sử dụng lâu --image hay ngắn -i thẻ và cũng cho phép biên soạn -i = "example.jpg" hoặc riêng -i example.jpg phương thức truyền trong đối số.

# declaring a couple of associative arrays 
declare -A arguments=(); 
declare -A variables=(); 

# declaring an index integer 
declare -i index=1; 

# any variables you want to use here 
# on the left left side is argument label or key (entered at the command line along with it's value) 
# on the right side is the variable name the value of these arguments should be mapped to. 
# (the examples above show how these are being passed into this script) 
variables["-gu"]="git_user"; 
variables["--git-user"]="git_user"; 
variables["-gb"]="git_branch"; 
variables["--git-branch"]="git_branch"; 
variables["-dbr"]="db_fqdn"; 
variables["--db-redirect"]="db_fqdn"; 
variables["-e"]="environment"; 
variables["--environment"]="environment"; 

# [email protected] here represents all arguments passed in 
for i in "[email protected]" 
do 
    arguments[$index]=$i; 
    prev_index="$(expr $index - 1)"; 

    # this if block does something akin to "where $i contains =" 
    # "%=*" here strips out everything from the = to the end of the argument leaving only the label 
    if [[ $i == *"="* ]] 
    then argument_label=${i%=*} 
    else argument_label=${arguments[$prev_index]} 
    fi 

    # this if block only evaluates to true if the argument label exists in the variables array 
    if [[ -n ${variables[$argument_label]} ]] 
    then 
     # dynamically creating variables names using declare 
     # "#$argument_label=" here strips out the label leaving only the value 
     if [[ $i == *"="* ]] 
      then declare ${variables[$argument_label]}=${i#$argument_label=} 
      else declare ${variables[$argument_label]}=${arguments[$index]} 
     fi 
    fi 

    index=index+1; 
done; 

# then you could simply use the variables like so: 
echo "$git_user"; 
3

Tôi nghĩ rằng máy chủ sẽ là ví dụ đơn giản về những gì bạn muốn đạt được. Không cần sử dụng các công cụ bên ngoài. Bash xây dựng nó các công cụ có thể thực hiện công việc cho bạn.

function DOSOMETHING { 

    while test $# -gt 0; do 
      case "$1" in 
       -first) 
        shift 
        first_argument=$1 
        shift 
        ;; 
       -last) 
        shift 
        last_argument=$1 
        shift 
        ;; 
       *) 
        echo "$1 is not a recognized flag!" 
        return 1; 
        ;; 
      esac 
    done 

    echo "First argument : $first_argument"; 
    echo "Last argument : $last_argument"; 
} 

Điều này sẽ cho phép bạn sử dụng cờ, cho dù bạn đang đi qua các thông số nào bạn sẽ nhận được hành vi thích hợp.

Ví dụ:

DOSOMETHING -last "Adios" -first "Hola" 

Output:

First argument : Hola 
Last argument : Adios 

Bạn có thể thêm chức năng này vào hồ sơ của bạn hoặc đặt nó bên trong một kịch bản.

Cảm ơn!

Edit: Lưu này như aa tập tin và sau đó thực hiện nó như yourfile.sh -last "Adios" -first "Hola"

#!/bin/bash 
while test $# -gt 0; do 
      case "$1" in 
       -first) 
        shift 
        first_argument=$1 
        shift 
        ;; 
       -last) 
        shift 
        last_argument=$1 
        shift 
        ;; 
       *) 
        echo "$1 is not a recognized flag!" 
        return 1; 
        ;; 
      esac 
    done 

    echo "First argument : $first_argument"; 
    echo "Last argument : $last_argument"; 
+0

Tôi sử dụng mã trên và khi chạy nó không in bất cứ thứ gì. './hello.sh DOSOMETHING -last" Adios "-first" Hola "' – dinu0101

+0

@ dinu0101 Đây là một hàm. Không phải là một kịch bản. Bạn nên sử dụng nó như DOSOMETHING -last "Adios" -first "Hola" –

+0

Cảm ơn @Matias. Hiểu. làm thế nào để chạy bên trong kịch bản. – dinu0101

0

Tôi thích câu trả lời Robert McMahan của tốt nhất ở đây là có vẻ như đơn giản nhất để làm thành thể chia sẻ bao gồm file cho bất kỳ kịch bản của bạn để sử dụng. Nhưng có vẻ như có một lỗ hổng với dòng if [[ -n ${variables[$argument_label]} ]] ném thông báo, "biến: chỉ số mảng xấu". Tôi không có đại diện để bình luận, và tôi nghi ngờ đây là 'sửa chữa' đúng đắn, nhưng gói rằng if trong if [[ -n $argument_label ]] ; then làm sạch nó.

Đây là mã tôi đã kết thúc, nếu bạn biết cách tốt hơn, hãy thêm nhận xét vào câu trả lời của Robert.

Bao gồm File "flags-declares.sh"

# declaring a couple of associative arrays 
declare -A arguments=(); 
declare -A variables=(); 

# declaring an index integer 
declare -i index=1; 

Bao gồm File "flags-arguments.sh"

# [email protected] here represents all arguments passed in 
for i in "[email protected]" 
do 
    arguments[$index]=$i; 
    prev_index="$(expr $index - 1)"; 

    # this if block does something akin to "where $i contains =" 
    # "%=*" here strips out everything from the = to the end of the argument leaving only the label 
    if [[ $i == *"="* ]] 
    then argument_label=${i%=*} 
    else argument_label=${arguments[$prev_index]} 
    fi 

    if [[ -n $argument_label ]] ; then 
    # this if block only evaluates to true if the argument label exists in the variables array 
    if [[ -n ${variables[$argument_label]} ]] ; then 
     # dynamically creating variables names using declare 
     # "#$argument_label=" here strips out the label leaving only the value 
     if [[ $i == *"="* ]] 
     then declare ${variables[$argument_label]}=${i#$argument_label=} 
     else declare ${variables[$argument_label]}=${arguments[$index]} 
     fi 
    fi 
    fi 

    index=index+1; 
done; 

"script.sh" của bạn

. bin/includes/flags-declares.sh 

# any variables you want to use here 
# on the left left side is argument label or key (entered at the command line along with it's value) 
# on the right side is the variable name the value of these arguments should be mapped to. 
# (the examples above show how these are being passed into this script) 
variables["-gu"]="git_user"; 
variables["--git-user"]="git_user"; 
variables["-gb"]="git_branch"; 
variables["--git-branch"]="git_branch"; 
variables["-dbr"]="db_fqdn"; 
variables["--db-redirect"]="db_fqdn"; 
variables["-e"]="environment"; 
variables["--environment"]="environment"; 

. bin/includes/flags-arguments.sh 

# then you could simply use the variables like so: 
echo "$git_user"; 
echo "$git_branch"; 
echo "$db_fqdn"; 
echo "$environment"; 
Các vấn đề liên quan