Bash - 如何避免命令“eval set --”评估变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35235707/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash - how to avoid command "eval set --" evaluating variables
提问by BDR
I just write a little bash script for managing multiple parallels ssh commands. In order to parse arguments I use this piece of code :
我只是写了一个小 bash 脚本来管理多个并行的 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
So I can use for instance -s, --host or -hS for the same result. Everything works fine except one thing.
所以我可以使用 -s、--host 或 -hS 来获得相同的结果。除了一件事,一切都很好。
If I put a variable in argument it will be evaluated.
如果我在参数中放入一个变量,它将被评估。
Explanations
说明
./test.sh -s SERVER -c 'echo $HOSTNAME'
cmd
should be assigned toecho $HOSTNAME
but because of theeval set
cmd is in fact assigned toecho server1
(the value of the variable)If I comment the line
eval set -- $args
I cannot use long options (--cmd) butcmd
is assigned toecho $HOSTNAME
as expected
cmd
应该分配给echo $HOSTNAME
但因为eval set
cmd实际上分配给echo server1
(变量的值)如果我评论该行,
eval set -- $args
我不能使用长选项(--cmd)但按预期cmd
分配echo $HOSTNAME
Is there any solution to avoid eval set / getopts to evaluate variables ? So to to have the same behavior as 2. but with long options available.
是否有任何解决方案可以避免使用 eval set/getopts 来评估变量?所以要具有与 2. 相同的行为,但有很长的选项可用。
Examples
例子
with 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
without eval set (line eval set -- $args
commented)
没有评估集(行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
回答by Charles Duffy
As you note, eval
is evil-- and there's no need to use it here.
正如你所指出的,eval
是邪恶的——这里没有必要使用它。
#!/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
That is to say: When building up a command line, append individual items to an array; you can then expand that array, quoted, without risking either evaluation or undesired behavior via effects of string-splitting, glob expansion, etc.
也就是说:在构建命令行时,将单个项附加到数组中;然后,您可以扩展该数组,引用,而不会因字符串拆分、全局扩展等的影响而冒评估或不良行为的风险。