如何在bash脚本中使用标志获取参数

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

$0$1

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

 mysql -u user -h host 

获得-u param值和-h param值的最好方法是通过标志而不是按位置?

这是我通常使用的习语:

 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 

要点是:

  • $#是参数的数量
  • while循环查看提供的所有参数,在case语句中匹配它们的值
  • 转移拿走了第一个。 您可以在case语句中多次移动以获取多个值。

这个例子使用Bash内置的getopts命令,来自Google Shell风格指南 :

 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 

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

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

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

  • while条件更具可读性,并显示接受的选项是什么
  • 更清洁的代码 不计算参数数量和移位
  • 你可以join选项(例如-a -b -c-abc

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

getopt是你的朋友..一个简单的例子:

 function f () { TEMP=`getopt --long -o "u:h:" "$@"` 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 

/ usr / bin目录中应该有各种不同的例子。

另一种方法是使用类似下面的例子,这将允许您使用long -image或short -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 

您可以将此function添加到您的configuration文件或将其放在脚本中。

谢谢!