我使用以下行(希望这是最好的做法,如果不能纠正我)来处理命令行选项:
#!/usr/bin/bash
read -r -d '' HELP <<EOF
OPTIONS:
-c Enable color output
-d Enable debug output
-v Enable verbose output
-n Only download files (mutually exclusive with -r)
-r Only remove files (mutually exclusive with -n)
-h Display this help
EOF
# DECLARE VARIABLES WITH DEFAULT VALUES
color=0
debug=0
verbose=0
download=0
remove=0
OPTIND=1 # Reset in case getopts has been used previously in the shell
invalid_options=(); # Array for invalid options
while getopts ":cdvnrh" opt; do
echo "Actual opt: $opt"
case $opt in
c)
color=1
;;
d)
debug=1
;;
v)
verbose=1
;;
n)
download=1
;;
r)
remove=1
;;
h)
echo "$HELP"
exit 1
;;
\?)
invalid_options+=($OPTARG)
;;
*)
invalid_options+=($OPTARG)
;;
esac
done
# HANDLE INVALID OPTIONS
if [ ${#invalid_options[@]} -ne 0 ]; then
echo "Invalid option(s):" >&2
for i in "${invalid_options[@]}"; do
echo $i >&2
done
echo "" >&2
echo "$HELP" >&2
exit 1
fi
# SET $1 TO FIRST MASS ARGUMENT, $2 TO SECOND MASS ARGUMENT ETC
shift $((OPTIND - 1))
# HANDLE CORRECT NUMBER OF MASS OPTIONS
if [ $# -ne 2 ]; then
echo "Correct number of mass arguments are 2"
echo "" >&2
echo "$HELP" >&2
exit 1
fi
# HANDLE MUTUALLY EXCLUSIVE OPTIONS
if [ $download -eq 1 ] && [ $remove -eq 1 ]; then
echo "Options for download and remove are mutually exclusive" >&2
echo "$HELP" >&2
exit 1
fi
echo "color: $color"
echo "debug: $debug"
echo "verbose: $verbose"
echo "download: $download"
echo "remove: $remove"
echo "\$1: $1"
echo "\$2: $2"
如果我调用脚本方式mass arguments(那些不是开关的开关或参数)是最后一个参数,一切都正常工作:
$ ./getopts.sh -c -d -v -r a b
Actual opt: c
Actual opt: d
Actual opt: v
Actual opt: r
color: 1
debug: 1
verbose: 1
download: 0
remove: 1
$1: a
$2: b
问题是当我想调用脚本时所以质量参数是第一个(或者在不使用参数的开关中间的某个地方)
$ ./getopts.sh a b -c -d -v -r
Correct number of mass arguments are 2
OPTIONS:
-c Enable color output
-d Enable debug output
-v Enable verbose output
-n Only download files (mutually exclusive with -r)
-r Only remove files (mutually exclusive with -d)
-h Display this help
或
$ ./getopts.sh -c a b -d -v -r
Actual opt: c
Correct number of mass arguments are 2
OPTIONS:
-c Enable color output
-d Enable debug output
-v Enable verbose output
-n Only download files (mutually exclusive with -r)
-r Only remove files (mutually exclusive with -d)
-h Display this help
我认为根据(POSIX)标准这应该没问题,因为基本相同的语法在我的系统上按预期工作:
$ cp test1/ test2/ -r
$ cp test1/ -r test2/
我在互联网上搜索,但只有与我的问题接近的是与{C}相关的this one。
答案 0 :(得分:3)
getopts
一旦检测到非破折号参数(不包括赋予参数的破折号参数的参数),就会自动中断while循环。 POSIX标准是首先使用虚线参数,然后使用文件。也没有这个--
和+
废话。这很简单。
但是,Linux不符合Unix或POSIX标准。与标准的Unix实用程序相比,GNU实用程序的本质就是“更好”。更多功能,更多选项和处理方式略有不同。
在Linux上,命令行参数可以在许多GNU实用程序中的文件之后。
例如:
$ cp -R foo bar
在我的Unix认证的Mac OS X和Linux上工作,但是,
$ cp foo bar -R
仅适用于Linux。
如果您希望getopts
像许多Linux实用程序一样工作,那么您需要做一些工作。
首先,您必须自己处理您的参数,而不是依靠$OPTIND
来解析它们。您还需要验证您是否有参数。
我想出了这个做你想做的事的例子。
#! /bin/bash
while [[ $* ]]
do
OPTIND=1
echo $1
if [[ $1 =~ ^- ]]
then
getopts :a:b:cd parameter
case $parameter in
a) echo "a"
echo "the value is $OPTARG"
shift
;;
b) echo "b"
echo "the value is $OPTARG"
shift
;;
c) echo "c"
;;
d) echo "d"
;;
*) echo "This is an invalid argument: $parameter"
;;
esac
else
other_arguments="$other_arguments $1"
fi
shift
done
echo "$other_arguments"
只要设置$*
,我现在就循环播放。 (也许我应该使用$@
?)我必须在循环结束时执行shift
。我每次都将$OPTIND
重置为1
,因为我正在自行改变论点。 $OPTARG
仍然设置,但我必须做另一个shift
以确保一切正常。
我还必须在我的if
声明中使用正则表达式验证参数是否以破折号开头。
基本测试显示它有效,但我不能说它没有错误,但它确实让你知道如何处理你的程序。
你仍然可以从getopts
获得足够的力量,但它确实需要更多的工作。
答案 1 :(得分:1)
Bash提供了两种参数解析方法。
内置命令getopts
是一种更新,易于使用的机制,如何解析参数,但它不是很灵活。 getopts
不允许混合选项和大量参数。
外部命令getopt
是一种较旧且更复杂的解析参数的机制。它允许长/短选项,gnu扩展允许混合选项和质量参数。