在不介绍getopts
的情况下,我想像这样解析表达式:
./cli.sh data i -f -f="./path/to/file.txt" --flags="--a --b"
其变体/组合:
./cli.sh -file="./path/to/file.txt" data --flags="--a --b" -f i
不幸的是,我很难阅读所提交的长期选项的所有可选值,例如:--flags="--a --b"
仅返回--a
作为长选项--flags
的值。
我创建了一个解析器的最小化版本,它展示了我当前的问题:
#!/usr/bin/env bash
__init_system () {
CMD_SED="sed"
CMD_SED_EXT="sed -E"
}
__init_system_Darwin () {
__init_system
CMD_SED="gsed"
CMD_SED_EXT="gsed -E"
}
invoke_func () {
SYSTEM=$(uname)
FUNC=$1 && shift 1
declare -f ${FUNC}_${SYSTEM} >/dev/null
[ $? -eq 0 ] && { ${FUNC}_${SYSTEM} "$@"; return $?; } || { ${FUNC} "$@"; return $?; }
}
handle_cli_harmonizing () {
cli_adjusted=$(echo "$@" | ${CMD_SED_EXT} \
-e 's@([ ])+@ @g'\
-e 's@\<h\>@help@g'\
-e 's@\<e\>@enable@g'\
-e 's@\<d\>@disable@g'\
-e 's@\<i\>@import@g'\
-e 's@\<sl\>@showlog@g'\
-e 's@\<st\>@status@g'\
| tr ' ' '\n' | sort -u | xargs
)
#echo ">>> Original: <$@>"
#echo ">>> Adjusted: <$cli_adjusted>"
}
handle_cli_parsing () {
for param in $@; do
case ${param} in
start|stop|status|enable|disable|data|showlog)
CMD=$param
;;
help|app|stats|import|export|dbinfo|exec)
SPEC=$param
;;
--*|-*)
#echo ">>> Found param: <$param>"
OPT="$OPT $param"
;;
*)
echo ">>> Parsing mismatch: $param"
;;
esac
done
}
handle_cli_optparams () {
for opt in $OPT; do
case "$opt" in
--force|-f)
OPT_FORCE=1
;;
--file=*|-f=*)
OPT_FILE=1
FILE=${opt#*=}
;;
--flags=*)
OPT_FLAGS=1
FLAGS=${opt#*=}
;;
*)
echo ">>> Unknown/unimplemented option specifier: $opt"
;;
esac
done
}
invoke_func __init_system
invoke_func handle_cli_harmonizing "$@"
invoke_func handle_cli_parsing ${cli_adjusted}
invoke_func handle_cli_optparams
echo "DEBUG[ CLI]: CMD=$CMD SPEC=$SPEC"
echo "DEBUG[TOGGLE]: FORCE=$OPT_FORCE FILE=$OPT_FILE FLAGS=$OPT_FLAGS"
echo "DEBUG[ OPTS]: FILE=$FILE FLAGS=$FLAGS"
预期的输出:
$ ./cli.sh data i -f -f="./path/to/file.txt" --flags="--a --b"
DEBUG[ CLI]: CMD=data SPEC=import
DEBUG[TOGGLE]: FORCE=1 FILE=1 FLAGS=1
DEBUG[ OPTS]: FILE=./path/to/file.txt FLAGS=--a --b
当前输出:
$ ./cli.sh data i -f -f="./path/to/file.txt" --flags="--a --b"
>>> Unknown/unimplemented option specifier: --b
DEBUG[ CLI]: CMD=data SPEC=import
DEBUG[TOGGLE]: FORCE=1 FILE=1 FLAGS=1
DEBUG[ OPTS]: FILE=./path/to/file.txt FLAGS=--a
这可能是一些引用问题或遗失set
,但我似乎被困在这里,而且我真的更喜欢保持我采取的简单方法。
如果有人另外提供仅限shell(没有bashims)版本的便携性问题,我会特别放养,但这是锦上添花。请注意,这只是我编写的整个解析器中非常简单的部分;足以展示我目前的挑战。
在撰写此问题时,我已阅读了所有建议的相关问题,我在How do I parse command line arguments in Bash?上思考了一段时间。
答案 0 :(得分:0)
问题的根源在于:
OPT="$OPT $param"
这是$param
中嵌入的空格与用于附加到$OPT
末尾的空间无法区分的地方。
您可以通过将OPT
数组添加到数组中来正确地附加值来避免此问题:
OPT+=("$param")
...然后使用数组语法迭代数组的值:
for opt in "${OPT[@]}"; do
...等等,始终如一,无处不在,并注意正确的双引号。
答案 1 :(得分:0)
即使经过多年的遗弃,我也想描述上面提出的问题的解决方案。
尽管janos为我提供了指针,但该解决方案实际上要简单得多,并且可以保持预期的原始灵活性:
#!/usr/bin/env bash
handle_cli_parsing () {
while [ $# -ne 0 ]; do
param=$1
[ x"$param" = x"sl" ] && param=showlog
[ x"$param" = x"sh" ] && param=showlog
[ x"$param" = x"h" ] && param=help
[ x"$param" = x"i" ] && param=import
[ x"$param" = x"e" ] && param=enable
[ x"$param" = x"d" ] && param=disable
case ${param} in
start|stop|status|enable|disable|data|showlog)
CMD=$param
;;
help|app|stats|import|export|dbinfo|exec)
SPEC=$param
;;
--force|-f)
OPT_FORCE=1
;;
--file=*|-f=*)
OPT_FILE=1
FILE=${param#*=}
;;
--flags=*)
OPT_FLAGS=1
FLAGS=${param#*=}
;;
--*|-*)
echo ">>> New param: <$param>"
;;
*)
echo ">>> Parsing mismatch: $param"
;;
esac
shift 1
done
}
handle_cli_parsing "$@"
echo "DEBUG[ CLI]: CMD=$CMD SPEC=$SPEC"
echo "DEBUG[TOGGLE]: FORCE=$OPT_FORCE FILE=$OPT_FILE FLAGS=$OPT_FLAGS"
echo "DEBUG[ OPTS]: FILE=$FILE FLAGS=$FLAGS"
现在输出符合预期,并且解析具有预期的灵活性:
$ ./cli.sh data i -f -f="./path/to/file.txt" --flags="--a --b"
DEBUG[ CLI]: CMD=data SPEC=import
DEBUG[TOGGLE]: FORCE=1 FILE=1 FLAGS=1
DEBUG[ OPTS]: FILE=./path/to/file.txt FLAGS=--a --b