我知道我可以很容易地在bash中获得这样的定位参数:

$0或$1

我希望能够使用这样的标志选项来指定每个参数的使用:

mysql -u user -h host

获得-u参数值和-h参数值的最佳方法是通过标志而不是通过位置?


当前回答

我建议一个简单的TLDR:;非初始化的例子。

创建一个名为greeting .sh的bash脚本

#!/bin/bash

while getopts "n:" arg; do
  case $arg in
    n) Name=$OPTARG;;
  esac
done

echo "Hello $Name!"

然后可以在执行脚本时传递一个可选参数-n。

执行脚本如下:

$ bash greeter.sh -n 'Bob'

输出

$ Hello Bob!

笔记

如果你想使用多个参数:

扩展while getops "n:" arg: do使用更多参数,例如 而getops“n:o:p:”arg: do 用额外的变量赋值扩展大小写开关。如o) Option=$OPTARG和p) Parameter=$OPTARG

要使脚本可执行:

chmod u+x greeter.sh

其他回答

这个例子使用了Bash内置的getopts命令,来自谷歌Shell样式指南:

a_flag=''
b_flag=''
files=''
verbose='false'

print_usage() {
  printf "Usage: ..."
}

while getopts 'abf:v' flag; do
  case "${flag}" in
    a) a_flag='true' ;;
    b) b_flag='true' ;;
    f) files="${OPTARG}" ;;
    v) verbose='true' ;;
    *) print_usage
       exit 1 ;;
  esac
done

注意:如果一个字符后面跟着一个冒号(例如f:),该选项应该有一个参数。

使用示例:./script -v -a -b -f filename . txt

使用getopts比接受的答案有几个优点:

while条件可读性更强,并显示了接受的选项是什么 清洁代码;不计算参数个数和移位 您可以连接选项(例如-a -b -c→-abc)

然而,一个很大的缺点是它不支持长选项,只支持单字符选项。

另一种选择是使用类似下面例子的东西,它允许你使用长——image或短的-i标签,还允许编译-i="example.jpg"或单独的-i example.jpg方法来传递参数。

# 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";

# $@ here represents all arguments passed in
for i in "$@"  
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";

我认为这可以作为一个简单的例子来说明你想要达到的目标。不需要使用外部工具。Bash内置的工具可以为您完成这项工作。

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";
 }

这将允许您使用标志,因此无论您以何种顺序传递参数,都将获得正确的行为。

例子:

 DOSOMETHING -last "Adios" -first "Hola"

输出:

 First argument : Hola
 Last argument : Adios

您可以将此函数添加到概要文件中,也可以将其放入脚本中。

谢谢!

编辑: 将其保存为一个文件,然后将其作为你的文件执行。

#!/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";

我在使用带有多个标志的getopts时遇到了麻烦,所以我编写了这段代码。它使用一个模态变量来检测标志,并使用这些标志为变量分配参数。

注意,如果一个标志不应该有参数,除了设置CURRENTFLAG之外,还可以执行其他操作。

    for MYFIELD in "$@"; do

        CHECKFIRST=`echo $MYFIELD | cut -c1`

        if [ "$CHECKFIRST" == "-" ]; then
            mode="flag"
        else
            mode="arg"
        fi

        if [ "$mode" == "flag" ]; then
            case $MYFIELD in
                -a)
                    CURRENTFLAG="VARIABLE_A"
                    ;;
                -b)
                    CURRENTFLAG="VARIABLE_B"
                    ;;
                -c)
                    CURRENTFLAG="VARIABLE_C"
                    ;;
            esac
        elif [ "$mode" == "arg" ]; then
            case $CURRENTFLAG in
                VARIABLE_A)
                    VARIABLE_A="$MYFIELD"
                    ;;
                VARIABLE_B)
                    VARIABLE_B="$MYFIELD"
                    ;;
                VARIABLE_C)
                    VARIABLE_C="$MYFIELD"
                    ;;
            esac
        fi
    done

我建议一个简单的TLDR:;非初始化的例子。

创建一个名为greeting .sh的bash脚本

#!/bin/bash

while getopts "n:" arg; do
  case $arg in
    n) Name=$OPTARG;;
  esac
done

echo "Hello $Name!"

然后可以在执行脚本时传递一个可选参数-n。

执行脚本如下:

$ bash greeter.sh -n 'Bob'

输出

$ Hello Bob!

笔记

如果你想使用多个参数:

扩展while getops "n:" arg: do使用更多参数,例如 而getops“n:o:p:”arg: do 用额外的变量赋值扩展大小写开关。如o) Option=$OPTARG和p) Parameter=$OPTARG

要使脚本可执行:

chmod u+x greeter.sh