myshell.sh:
#!/bin/bash
script_args=()
while [ $OPTIND -le "$#" ]
do
if getopts h:d:s: option
then
case $option
in
h) host_name="$OPTARG";;
d) wait_time="$OPTARG";;
s) script="$OPTARG";;
esac
else
script_args+=("${!OPTIND}")
((OPTIND++))
fi
done
"$script" "${script_args[@]}"
测试.sh:
#!/bin/bash
echo "$0 $@"
测试 OP 的案例:
$ PATH+=:. # Use the cases as written without prepending ./ to the scripts
$ myshell.sh -h hostname -s test.sh -d waittime param1 param2 param3
./test.sh param1 param2 param3
$ myshell.sh param1 param2 -h hostname param3 -d waittime -s test.sh
./test.sh param1 param2 param3
$ myshell.sh param1 -h hostname -d waittime -s test.sh param2 param3
./test.sh param1 param2 param3
这是怎么回事:
getopts
如果遇到位置参数将失败。如果将其用作循环条件,则只要位置参数出现在选项之前,循环就会提前中断,就像在两个测试用例中所做的那样。
因此,只有在处理完所有参数后,此循环才会中断。如果getopts
无法识别某些东西,我们只是假设它是一个位置参数,并在手动递增getopts
计数器的同时将其填充到一个数组中。
可能的改进:
如所写,子脚本不能接受选项(仅位置参数),因为getopts
在包装脚本中会吃掉这些选项并打印错误消息,同时将任何参数视为位置参数:
$ myshell.sh param1 param2 -h hostname -d waittime -s test.sh -a opt1 param3
./myshell.sh: illegal option -- a
./test.sh param1 param2 opt1 param3
如果我们知道子脚本只能接受位置参数,那么myshell.sh
可能应该在无法识别的选项上停止。这可以像在case
块末尾添加默认的最后一个案例一样简单:
\?) exit 1;;
$ myshell.sh param1 param2 -h hostname -d waittime -s test.sh -a opt1 param3
./myshell.sh: illegal option -- a
如果子脚本需要接受选项(只要它们不与 中的选项冲突myshell.sh
),我们可以getopts
通过在选项字符串前面加上冒号来切换到静默错误报告:
if getopts :h:d:s: option
然后我们将使用默认的最后一种情况将任何无法识别的选项填充到script_args
:
\?) script_args+=("-$OPTARG");;
$ myshell.sh param1 param2 -h hostname -d waittime -s test.sh -a opt1 param3
./test.sh param1 param2 -a opt1 param3