我很困惑在为以下程序编写 bash 脚本时如何包含可选参数/标志:
该程序需要两个参数:
run_program --flag1 <value> --flag2 <value>
但是,有几个可选标志:
run_program --flag1 <value> --flag2 <value> --optflag1 <value> --optflag2 <value> --optflag3 <value> --optflag4 <value> --optflag5 <value>
我想运行 bash 脚本,以便它接受用户参数。如果用户只按顺序输入两个参数,那么它将是:
#!/bin/sh
run_program --flag1 $1 --flag2 $2
但是如果包含任何可选参数怎么办?我认为会是
if [ --optflag1 "$3" ]; then
run_program --flag1 $1 --flag2 $2 --optflag1 $3
fi
但是如果给了 4 美元而不是 3 美元怎么办?
答案1
本文显示了两种不同的方法 -shift
和getopts
(并讨论了两种方法的优点和缺点)。
使用shift
您的脚本查看$1
,决定采取什么操作,然后执行shift
、移动$2
到$1
、$3
到$2
等。
例如:
while :; do
case $1 in
-a|--flag1) flag1="SET"
;;
-b|--flag2) flag2="SET"
;;
-c|--optflag1) optflag1="SET"
;;
-d|--optflag2) optflag2="SET"
;;
-e|--optflag3) optflag3="SET"
;;
*) break
esac
shift
done
您可以在表达式getopts
中定义(短)选项while
:
while getopts abcde opt; do
case $opt in
a) flag1="SET"
;;
b) flag2="SET"
;;
c) optflag1="SET"
;;
d) optflag2="SET"
;;
e) optflag3="SET"
;;
esac
done
显然,这些只是代码片段,我省略了验证 - 检查是否设置了强制参数 flag1 和 flag2 等。
您使用哪种方法在某种程度上取决于您的喜好 - 您希望脚本的可移植性如何,您是否只能接受短(POSIX)选项,或者是否需要长(GNU)选项,等等。
答案2
使用数组。
#!/bin/bash
args=( --flag1 "$1" --flag2 "$2" )
[ "x$3" = xFALSE ] || args+=( --optflag1 "$3" )
[ "x$4" = xFALSE ] || args+=( --optflag2 "$4" )
[ "x$5" = xFALSE ] || args+=( --optflag3 "$5" )
[ "x$6" = xFALSE ] || args+=( --optflag4 "$6" )
[ "x$7" = xFALSE ] || args+=( --optflag5 "$7" )
program_name "${args[@]}"
这将正确处理其中包含空格的参数。
[编辑] 我使用的是大致等效的语法,args=( "${args[@]}" --optflag1 "$3" )
但 G-Man 提出了更好的方法。
答案3
在 shell 脚本中,参数为“$1”、“$2”、“$3”等。参数的数量为 $#。
如果您的脚本无法识别选项,您可以忽略选项检测并将所有参数视为操作数。
要识别选项,请使用内置的 getopts
答案4
如果你的输入选项是位置性的(你知道它们在哪里),并且没有用标志指定,那么你想要的只是构建命令行。只需为所有这些准备命令参数:
FLAG1="--flag1 $1"
FLAG2="--flag2 $2"
OPTFLAG1=""
OPTFLAG2=""
OPTFLAG3=""
if [ xFALSE != x"$3" ]; then
OPTFLAG1="--optflag1 $3"
fi
if [ xFALSE != x"$4" ]; then
OPTFLAG2="--optflag2 $4"
fi
#the same for other flags
#now just run the program
runprogram $FLAG1 $FLAG2 $OPTFLAG1 $OPTFLAG2 $OPTFLAG3
如果未指定参数,则相应的字符串为空并展开为空。请注意,最后一行中没有引号。这是因为您希望 shell 将参数拆分为单词(将--flag1
和$1
作为程序的单独参数)。当然,如果你的原始参数包含空格,这就会出错。如果您是运行此脚本的人,那么您可以保留它,但如果这是一个通用脚本,如果用户输入带有空格的内容,它可能会出现意外的行为。为了解决这个问题,您需要使代码变得更丑一些。
x
测试中的前缀存在[]
以防万一$3
或$4
为空。在这种情况下,bash 会扩展[ FALSE != $3 ]
为[ FALSE != ]
which is 语法错误,因此可以使用另一个任意字符来防止这种情况。这是一种非常常见的方式,您会在许多脚本中看到它。
我将OPTFLAG1
它们和其余的设置""
在开始只是为了确定(以防它们之前设置为某些内容),但如果它们实际上没有在环境中声明,那么您并不严格需要这样做。
一些补充说明:
- 实际上,您可以按照与以下相同的方式接收参数
runprogram
:使用标志。这就是我们John N
所说的。这就是getopts
有用的地方。 - 使用 FALSE 来达到这个目的有点不标准而且很长。通常,人们会使用单个字符(可能
-
)来表示空值,或者仅传递一个空字符串,例如""
,如果这不是参数的有效值。空字符串也会使测试更短,只需使用if [ -n "$3" ]
. - 如果只有一个可选标志,或者它们是相关的,因此您永远不能有 OPTFLAG2,但不能有 OPTFLAG1,那么您可以简单地跳过您不想设置的标志。如果您使用
""
空参数,就像上面建议的那样,您无论如何都可以跳过所有尾随的空参数。
这种方法几乎就是在 Makefile 中将选项传递给编译器的方式。
再说一次 - 如果输入可能包含空格,它会变得很难看。