我只是编写一个小的bash脚本来管理多个parallels ssh命令。 为了解析参数,我使用了这段代码:
#!/bin/bash
# replace long arguments
for arg in "$@"; do
case "$arg" in
--help) args="${args}-h ";;
--host|-hS) args="${args}-s ";;
--cmd) args="${args}-c ";;
*) [[ "${arg:0:1}" == "-" ]] && delim='' || delim="\""
args="${args}${delim}${arg}${delim} ";;
esac
done
echo "args before eval : $args"
eval set -- $args
echo "args after eval : $args"
while getopts "hs:c:" OPTION; do
echo "optarg : $OPTARG"
case $OPTION in
h) usage; exit 0;;
s) servers_array+=("$OPTARG");;
c) cmd="$OPTARG";;
esac
done
所以我可以使用例如-s, - host或-hS来获得相同的结果。 除了一件事,一切都很好。
如果我在变量中加入一个变量,它将被评估。
./test.sh -s SERVER -c 'echo $HOSTNAME'
cmd
应分配给echo $HOSTNAME
,但由于eval set
cmd实际上已分配给echo server1
(变量的值)
如果我对该行eval set -- $args
发表评论,则我无法使用长期选项(--cmd),但cmd
会按预期分配给echo $HOSTNAME
是否有任何解决方案可以避免eval set / getopts来评估变量? 所以要有与2相同的行为,但有很长的选择。
使用eval set
./test.sh -s SERVER -c 'echo $HOSTNAME'
args before eval : -s "SERVER" -c "echo $HOSTNAME"
args after eval : -s "SERVER" -c "echo $HOSTNAME"
optarg : SERVER
optarg : echo server1
没有评估集(行eval set -- $args
注释)
./test.sh -s SERVER -c 'echo $HOSTNAME'
args before eval : -s "SERVER" -c "echo $HOSTNAME"
args after eval : -s "SERVER" -c "echo $HOSTNAME"
optarg : SERVER
optarg : echo $HOSTNAME
答案 0 :(得分:8)
正如您所说,eval
is evil - 并且此处无需使用它。
#!/bin/bash
# make args an array, not a string
args=( )
# replace long arguments
for arg; do
case "$arg" in
--help) args+=( -h ) ;;
--host|-hS) args+=( -s ) ;;
--cmd) args+=( -c ) ;;
*) args+=( "$arg" ) ;;
esac
done
printf 'args before update : '; printf '%q ' "$@"; echo
set -- "${args[@]}"
printf 'args after update : '; printf '%q ' "$@"; echo
while getopts "hs:c:" OPTION; do
: "$OPTION" "$OPTARG"
echo "optarg : $OPTARG"
case $OPTION in
h) usage; exit 0;;
s) servers_array+=("$OPTARG");;
c) cmd="$OPTARG";;
esac
done
也就是说:在构建命令行时,将单个项目附加到数组中;然后,您可以扩展该引用的数组,而不会因为字符串拆分,glob扩展等影响而产生评估或不良行为的风险。