Bash - 如何避免命令" eval set - "评估变量

时间:2016-02-06 00:19:30

标签: bash variables unix cmd eval

我只是编写一个小的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'
  1. cmd应分配给echo $HOSTNAME,但由于eval set cmd实际上已分配给echo server1(变量的值)

  2. 如果我对该行eval set -- $args发表评论,则我无法使用长期选项(--cmd),但cmd会按预期分配给echo $HOSTNAME

  3. 是否有任何解决方案可以避免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
    

1 个答案:

答案 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扩展等影响而产生评估或不良行为的风险。