Bash 脚本中的可选参数
Optional arguments in Bash script
我正在尝试编写一个具有可选参数的函数,使得可选参数后跟 -x
之类的东西,例如
my_function man_arg1 man_arg2 -n opt_arg1 -o opt_arg2 -x opt_arg3
我希望它也支持像
这样的调用
my_function man_arg1 man_arg2 -x opt_arg
在其他问题中,我看到有人建议使用 getopts,但在这些答案中,您似乎必须在调用函数时指定所有可选参数?此外,我仍然不清楚您将如何使用 getopts。
我不确定我是否正确理解了问题,如果我没有回答,抱歉...
您可以使用(例如)getopt(1)
,如下所示,这将允许 -x
选项位于任何位置。
请注意,可选参数 (man_arg*
) 也可以在任何地方。
#! /usr/bin/bash
# CMD is the shell-script name without directory (basename)
CMD="${0##*/}"
my_function() {
# Some comments added per OP request
# below variable is used by getopt's "-o" option (short options).
# each letter is a possible option; colon following a letter means this
# option will take a parameter. See getopt(1) for more details.
SOPTS="n:o:x:"
# output of getopt is assigned to TMP. For example, when calling :
# my_function -n n1 a b -o o1 -x x1 c d
# TMP will contain: "-n 'n1' -o 'o1' -x 'x1' -- 'a' 'b' 'c' 'd'"
TMP=$(getopt -o "$SOPTS" -n "$CMD" -- "$@") || exit 1
# assign TMP to positional parameters , , etc...
eval set -- "$TMP"
unset TMP
while true; do
case "" in
-n|-o)
printf "[%s] argument: %s\n" "" ""
shift
;;
-x)
printf "[-x] argument: %s\n" ""
shift
;;
--) # end of options
shift
break
;;
esac
shift
done
nargs=$#
printf "remaining %d args :\n" "$nargs"
for ((i=0; i<nargs; ++i)); do
printf "%d: %s\n" $((i + 1)) ""
shift
done
}
my_function "$@"
示例:
br@lorien:~$ ./test-getopt.bash man_arg1 man_arg2 -n opt_arg1 -o opt_arg2 -x opt_arg3
[-n] argument: opt_arg1
[-o] argument: opt_arg2
[-x] argument: opt_arg3
remaining 2 args :
1: man_arg1
2: man_arg2
br@lorien:~$ ./test-getopt.bash man_arg1 man_arg2 -n opt_arg1 -o opt_arg2 -x opt_arg3 man_arg3 man_arg4
[-n] argument: opt_arg1
[-o] argument: opt_arg2
[-x] argument: opt_arg3
remaining 4 args :
1: man_arg1
2: man_arg2
3: man_arg3
4: man_arg4
br@lorien:~$ ./test-getopt.bash man_arg1 man_arg2 -x opt_arg
[-x] argument: opt_arg
remaining 2 args :
1: man_arg1
2: man_arg2
br@lorien:~$ ./test-getopt.bash -x opt_arg4 man_arg2 -n opt_arg1 -x opt_arg3 man_arg3 man_arg4
[-x] argument: opt_arg4
[-n] argument: opt_arg1
[-x] argument: opt_arg3
remaining 3 args :
1: man_arg2
2: man_arg3
3: man_arg4
编辑:将代码重写为函数,如问题所述。
POSIX 约定是命令的 non-option 参数必须在 在 所有选项和选项参数之后。 POSIX getopts
实用程序是围绕此约定设计的,因此 如果您不想坚持约定俗成的参数顺序,那么 getopts
并不适合.在那种情况下,getopts
可能仍然可以工作,但我不会尝试这样做。
如果您愿意依赖 the GNU version of the getopt
utility(不要与 getopts
混淆,与 s
混淆),那么它可以容纳您。默认情况下,它可以识别命令行中任何位置的选项,包括 non-option 参数之后的选项。这可能看起来像这样:
args=$(getopt --name "[=10=]" --options n:o:x: -- "$@")
eval set -- "$args"
while [[ $# -gt 0 ]]; do
case "" in
-n) n_argument=; shift 2;;
-o) o_argument=; shift 2;;
-x) x_argument=; shift 2;;
*)
# Handle non-option argument ...
shift
;;
esac
done
但请注意,您可以在没有 getopt
的情况下做同样的事情。 getopt
(或getopts
)为您做的是:
- 标准化联合选项(
-abc
等同于 -a -b -c
;仅适用于不需要参数的选项)
- 正常化选项 /参数分离(
-xfoo
等于-x foo
当option x
获取参数)
- 认识到并适应参数
--
的重要性,因为它表明只有 non-option 个参数遵循
- 识别参数中的错误,尤其是在需要的地方遗漏了选项参数
- 类似于上面的 GNU-style 长选项(仅限 GNU
getopt
)
如果你对这些都不感兴趣,或者如果你愿意为你想要的那些人推出自己的东西,或者如果你不能依赖 GNU 版本的 getopt
然后你可以使用类似于上面的循环,而不首先使用 getopt
来处理参数列表,并且不涉及 getopts
.
我正在尝试编写一个具有可选参数的函数,使得可选参数后跟 -x
之类的东西,例如
my_function man_arg1 man_arg2 -n opt_arg1 -o opt_arg2 -x opt_arg3
我希望它也支持像
这样的调用my_function man_arg1 man_arg2 -x opt_arg
在其他问题中,我看到有人建议使用 getopts,但在这些答案中,您似乎必须在调用函数时指定所有可选参数?此外,我仍然不清楚您将如何使用 getopts。
我不确定我是否正确理解了问题,如果我没有回答,抱歉...
您可以使用(例如)getopt(1)
,如下所示,这将允许 -x
选项位于任何位置。
请注意,可选参数 (man_arg*
) 也可以在任何地方。
#! /usr/bin/bash
# CMD is the shell-script name without directory (basename)
CMD="${0##*/}"
my_function() {
# Some comments added per OP request
# below variable is used by getopt's "-o" option (short options).
# each letter is a possible option; colon following a letter means this
# option will take a parameter. See getopt(1) for more details.
SOPTS="n:o:x:"
# output of getopt is assigned to TMP. For example, when calling :
# my_function -n n1 a b -o o1 -x x1 c d
# TMP will contain: "-n 'n1' -o 'o1' -x 'x1' -- 'a' 'b' 'c' 'd'"
TMP=$(getopt -o "$SOPTS" -n "$CMD" -- "$@") || exit 1
# assign TMP to positional parameters , , etc...
eval set -- "$TMP"
unset TMP
while true; do
case "" in
-n|-o)
printf "[%s] argument: %s\n" "" ""
shift
;;
-x)
printf "[-x] argument: %s\n" ""
shift
;;
--) # end of options
shift
break
;;
esac
shift
done
nargs=$#
printf "remaining %d args :\n" "$nargs"
for ((i=0; i<nargs; ++i)); do
printf "%d: %s\n" $((i + 1)) ""
shift
done
}
my_function "$@"
示例:
br@lorien:~$ ./test-getopt.bash man_arg1 man_arg2 -n opt_arg1 -o opt_arg2 -x opt_arg3
[-n] argument: opt_arg1
[-o] argument: opt_arg2
[-x] argument: opt_arg3
remaining 2 args :
1: man_arg1
2: man_arg2
br@lorien:~$ ./test-getopt.bash man_arg1 man_arg2 -n opt_arg1 -o opt_arg2 -x opt_arg3 man_arg3 man_arg4
[-n] argument: opt_arg1
[-o] argument: opt_arg2
[-x] argument: opt_arg3
remaining 4 args :
1: man_arg1
2: man_arg2
3: man_arg3
4: man_arg4
br@lorien:~$ ./test-getopt.bash man_arg1 man_arg2 -x opt_arg
[-x] argument: opt_arg
remaining 2 args :
1: man_arg1
2: man_arg2
br@lorien:~$ ./test-getopt.bash -x opt_arg4 man_arg2 -n opt_arg1 -x opt_arg3 man_arg3 man_arg4
[-x] argument: opt_arg4
[-n] argument: opt_arg1
[-x] argument: opt_arg3
remaining 3 args :
1: man_arg2
2: man_arg3
3: man_arg4
编辑:将代码重写为函数,如问题所述。
POSIX 约定是命令的 non-option 参数必须在 在 所有选项和选项参数之后。 POSIX getopts
实用程序是围绕此约定设计的,因此 如果您不想坚持约定俗成的参数顺序,那么 getopts
并不适合.在那种情况下,getopts
可能仍然可以工作,但我不会尝试这样做。
如果您愿意依赖 the GNU version of the getopt
utility(不要与 getopts
混淆,与 s
混淆),那么它可以容纳您。默认情况下,它可以识别命令行中任何位置的选项,包括 non-option 参数之后的选项。这可能看起来像这样:
args=$(getopt --name "[=10=]" --options n:o:x: -- "$@")
eval set -- "$args"
while [[ $# -gt 0 ]]; do
case "" in
-n) n_argument=; shift 2;;
-o) o_argument=; shift 2;;
-x) x_argument=; shift 2;;
*)
# Handle non-option argument ...
shift
;;
esac
done
但请注意,您可以在没有 getopt
的情况下做同样的事情。 getopt
(或getopts
)为您做的是:
- 标准化联合选项(
-abc
等同于-a -b -c
;仅适用于不需要参数的选项) - 正常化选项 /参数分离(
-xfoo
等于-x foo
当optionx
获取参数) - 认识到并适应参数
--
的重要性,因为它表明只有 non-option 个参数遵循 - 识别参数中的错误,尤其是在需要的地方遗漏了选项参数
- 类似于上面的 GNU-style 长选项(仅限 GNU
getopt
)
如果你对这些都不感兴趣,或者如果你愿意为你想要的那些人推出自己的东西,或者如果你不能依赖 GNU 版本的 getopt
然后你可以使用类似于上面的循环,而不首先使用 getopt
来处理参数列表,并且不涉及 getopts
.