我正在尝试构建一个具有两种模式的程序,每种模式都采用一组不同的参数。我尝试实现嵌套的 case 语句,如 @geekosaur 中所述这里,通过case "$1"
模式和case "$2"
论证。
我有一个--help
描述可用模式的程序的通用选项,以及--help
描述参数的每种模式的单独选项。
如果我运行:
./program.sh --help
作品
./program.sh mode1 --help
作品
./program.sh mode1 --unknown
有效(它正确捕获未知选项并调用模式1的使用函数)
然而:
./program.sh mode1 --option1 file
ERROR: unknown parameter file
即,它将“file”识别为参数,而不是键“option1”的值。
我怎样才能做到这一点?我是否搞乱了我的“班次”,或者我是否需要嵌套循环?
(为了简单起见,下面的代码中仅显示“mode1”)
#!/bin/bash
usage_general() {
echo "Usage: ProgramName [modes]"
echo ""
printf "%-10s %s\n" "mode1" "Run subprogram 1."
printf "%-10s %s\n" "mode2" "Run subprogram 2."
}
usage_mode1() {
echo "Usage: ProgramName mode1 [options]"
echo ""
printf "%-10s %s\n" "-1 | --option1" "Arg 1 for mode1"
printf "%-10s %s\n" "-2 | --option2" "Arg 2 for mode1."
}
while [[ $# -gt 0 ]]
do
case "$1" in
-h | --help)
usage_general
exit
;;
mode1)
case "$2" in
-h | --help)
usage_mode1
exit
;;
-1 | --option1)
val1="$3"
shift 2
;;
-2 | --option2)
val2="$3"
shift 2
;;
*)
echo "ERROR: unknown parameter $2"
usage_mode1
exit 1
;;
esac
;;
*)
echo "ERROR: unknown parameter $1"
usage_general
exit 1
;;
esac
done
答案1
当您shift 2
在内部使用时case
,您会移走$1
和$2
,但不会移走$3
文件名。
您需要执行一个单独的循环来解析mode1
andmode2
子命令的选项。
假设当在脚本的命令行参数中找到子命令时,其余选项和选项参数属于该子命令,您可以像这样分割解析:
run_mode1 () {
while [ "$#" -gt 0 ]; do
case "$1" in
-h | --help)
usage_mode1
exit
;;
-1 | --option1)
val1="$2"
shift 2
;;
-2 | --option2)
val2="$2"
shift 2
;;
*)
echo "ERROR: unknown parameter $1"
usage_mode1
exit 1
;;
esac
done
# code for actually running mode1 goes here
}
while [[ $# -gt 0 ]]
do
case "$1" in
-h | --help)
usage_general
exit
;;
mode1)
shift
run_mode1 "$@"
break
;;
*)
echo "ERROR: unknown parameter $1"
usage_general
exit 1
;;
esac
done
在这里,一旦遇到mode1
命令行参数,我们就运行 shell 函数。该函数负责解析参数列表的其余部分。
显然,这仅在特定情况下才有效全部选项剧本(不是子命令)发生前命令行上的任何给定子命令,并且在脚本的任何一次调用中只能有一个带有选项的子命令。
以脚本能够同时接受两个或多个带选项的子命令的方式实现命令行解析并非不可能,如下所示
./script.sh ...options... mode1 ...options... mode2 ...options...
但我暂时先不谈这个。