我希望使用shell脚本调用长形式和短形式的命令行选项。
我知道可以使用getopts,但是像在Perl中一样,我不能用shell做同样的事情。
关于如何做到这一点的任何想法,这样我就可以使用如下选项:
./shell.sh --copyfile abc.pl /tmp/
./shell.sh -c abc.pl /tmp/
在上面,这两个命令对我的shell意味着同样的事情,但使用getopts,我还不能实现这些?
我希望使用shell脚本调用长形式和短形式的命令行选项。
我知道可以使用getopts,但是像在Perl中一样,我不能用shell做同样的事情。
关于如何做到这一点的任何想法,这样我就可以使用如下选项:
./shell.sh --copyfile abc.pl /tmp/
./shell.sh -c abc.pl /tmp/
在上面,这两个命令对我的shell意味着同样的事情,但使用getopts,我还不能实现这些?
当前回答
例如,如果所有长选项都有唯一且匹配的首字符作为短选项
./slamm --chaos 23 --plenty test -quiet
和
./slamm -c 23 -p test -q
你可以在getopts重写$args之前使用它:
# change long options to short options
for arg; do
[[ "${arg:0:1}" == "-" ]] && delim="" || delim="\""
if [ "${arg:0:2}" == "--" ];
then args="${args} -${arg:2:1}"
else args="${args} ${delim}${arg}${delim}"
fi
done
# reset the incoming args
eval set -- $args
# proceed as usual
while getopts ":b:la:h" OPTION; do
.....
谢谢mtvee的灵感;-)
其他回答
公认的答案很好地指出了bash内置getopts的所有缺点。答案以:
因此,虽然可以编写更多的代码来解决长选项支持不足的问题,但工作量要大得多,并且在一定程度上违背了使用getopt解析器来简化代码的目的。
尽管我原则上同意这种说法,但我觉得我们在各种脚本中实现这个特性的次数证明,我们应该花一些精力来创建一个“标准化”的、经过良好测试的解决方案。
因此,我通过在纯bash中实现getopts_long“升级”了内置在getopts中的bash,没有外部依赖。该函数的使用与内置的getopts 100%兼容。
通过在脚本中包含getopts_long(在GitHub上托管),可以简单地实现原始问题的答案:
source "${PATH_TO}/getopts_long.bash"
while getopts_long ':c: copyfile:' OPTKEY; do
case ${OPTKEY} in
'c'|'copyfile')
echo 'file supplied -- ${OPTARG}'
;;
'?')
echo "INVALID OPTION -- ${OPTARG}" >&2
exit 1
;;
':')
echo "MISSING ARGUMENT for option -- ${OPTARG}" >&2
exit 1
;;
*)
echo "Misconfigured OPTSPEC or uncaught option -- ${OPTKEY}" >&2
exit 1
;;
esac
done
shift $(( OPTIND - 1 ))
[[ "${1}" == "--" ]] && shift
如果这就是您想要调用脚本的方式
myscript.sh --input1 "ABC" --input2 "PQR" --input2 "XYZ"
然后,您可以使用getopt和——longoptions来实现这个最简单的方法
试试这个,希望对你有用
# Read command line options
ARGUMENT_LIST=(
"input1"
"input2"
"input3"
)
# read arguments
opts=$(getopt \
--longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")" \
--name "$(basename "$0")" \
--options "" \
-- "$@"
)
echo $opts
eval set --$opts
while true; do
case "$1" in
--input1)
shift
empId=$1
;;
--input2)
shift
fromDate=$1
;;
--input3)
shift
toDate=$1
;;
--)
shift
break
;;
esac
shift
done
在ksh93中,getopts支持长名字…
while getopts "f(file):s(server):" flag
do
echo "$flag" $OPTIND $OPTARG
done
至少我找到的教程是这么说的。试试看。
Getopts“可以用来”解析长选项,只要你不希望它们有参数……
以下是如何:
$ cat > longopt
while getopts 'e:-:' OPT; do
case $OPT in
e) echo echo: $OPTARG;;
-) #long option
case $OPTARG in
long-option) echo long option;;
*) echo long option: $OPTARG;;
esac;;
esac
done
$ bash longopt -e asd --long-option --long1 --long2 -e test
echo: asd
long option
long option: long1
long option: long2
echo: test
如果尝试使用OPTIND获取长选项的参数,getopts将把它作为第一个不可选的位置参数,并停止解析任何其他参数。 在这种情况下,您最好使用简单的case语句手动处理它。
这将“总是”工作:
$ cat >longopt2
while (($#)); do
OPT=$1
shift
case $OPT in
--*) case ${OPT:2} in
long1) echo long1 option;;
complex) echo comples with argument $1; shift;;
esac;;
-*) case ${OPT:1} in
a) echo short option a;;
b) echo short option b with parameter $1; shift;;
esac;;
esac
done
$ bash longopt2 --complex abc -a --long -b test
comples with argument abc
short option a
short option b with parameter test
尽管它不像getopts那么灵活,而且你必须在用例实例中自己做很多错误检查代码……
但这是一种选择。
如果你不想要getopt依赖,你可以这样做:
while test $# -gt 0
do
case $1 in
# Normal option processing
-h | --help)
# usage and help
;;
-v | --version)
# version info
;;
# ...
# Special cases
--)
break
;;
--*)
# error unknown (long) option $1
;;
-?)
# error unknown (short) option $1
;;
# FUN STUFF HERE:
# Split apart combined short options
-*)
split=$1
shift
set -- $(echo "$split" | cut -c 2- | sed 's/./-& /g') "$@"
continue
;;
# Done with options
*)
break
;;
esac
# for testing purposes:
echo "$1"
shift
done
当然,这样你就不能使用长样式选项。如果你想添加缩短的版本(例如——verbos而不是——verbose),那么你需要手动添加这些。
但是如果您希望获得getopts功能和长选项,这是一种简单的方法。
我也把这个片段作为一个主旨。