我的脚本包含几个具有必需参数的参数:
while [ "$1" != "" ]; do
case $1 in
-f | --first ) shift
first=$1
;;
-s | --second ) shift
second=$1
;;
* ) break
esac
shift
done
echo "first: "$first" second: "$second
这可以正常工作:
$ ./script.sh --first a --second b
first: a second: b
但是,当有人忘记参数的参数时,获取参数就会出错。
例如,这不起作用:
$ ./script.sh --first --second a
first: --second second:
这很糟糕(第一个是 get,但第二个强制未处理):
$ ./script.sh --first a --second
first: a second:
我尝试修改:
* ) break
到:
* ) echo "Bad arguments"
exit 1
在这种情况下有效(首先处理强制):
$./script.sh --first --second b
Bad arguments
但在这种情况下无法正常工作(不处理第二个):
$ ./script.sh --first a --second
first: a second:
答案1
使用内置的外壳getopts
。这使用 optstring,您可以在其中列出所有有效的选项字符以及它们是否需要参数(通过在选项字符后面加上:
)。例如:
while getopts 'f:s:' opt; do
case "$opt" in
f) first="$OPTARG" ;;
s) second="$OPTARG" ;;
:) usage 1 "-$OPTARG requires an argument" ;;
?) usage 1 "Unknown option '$opt'" ;;
esac
done
shift $((OPTIND -1))
请注意,内置getopts
不支持 --long 选项。如果这是一个要求,请使用包getopt
中的程序util-linux
- 不要使用任何其他版本,其他版本都有严重的缺陷。
TEMP=$(getopt -o 'f:s:' --long 'first:,second:' -n "$0" -- "$@")
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
eval set -- "$TEMP"
while true ; do
case "$1" in
-f|--first) first="$2" ; shift 2 ;;
-s|--second) second="$2" ; shift 2 ;;
--) shift ; break ;;
*) echo 'Internal error!' ; exit 1 ;;
esac
done
笔记:
getopts
(带有s
)内置于 POSIX shell,是可移植的和标准的。getopt
(没有s
)是非标准的,有几个相互冲突的版本,其中大多数都有严重的缺陷。util-linux
如果您不关心可移植性,则可以安全地使用包中的版本。- 如果没有给出需要参数的选项,它们都会抛出错误。
答案2
发生这种情况是因为 无论案例的文本是什么,shift
都会转移到$2
。$1
脚本的确切目的尚不清楚,但例如,如果您想避免这种情况,您可以执行以下操作:
while [[ "$1" != "" && "$2" != -* ]]; do
case $1 in
-f | --first ) shift
first=$1
;;
-s | --second ) shift
second=$1
;;
* ) break
esac
shift
done
echo "first: "$first" second: "$second
如果缺少参数,这将避免操纵。
输出示例:
$ ./script.sh --first a --second b
first: a second: b
$ ./script.sh --first --second b
first: second: