作为参数给出的Bash函数调用命令

时间:2010-07-05 10:02:21

标签: bash eval alias

如何在bash中编写一个函数来执行作为参数给出的命令,其中

  • 给定的命令可能是别名
  • 参数必须完全按照给定的方式传递;没有评估可以

换句话说,如何编写as-transparent-as-possible wrapper 函数。

包装函数的目标可以是例如在给定命令之前和之后设置当前目录,和/或设置环境变量,或者给定命令花费的时间,...这里的一个简单示例我获取一个只打印一行的函数,然后执行给定的命令。

第一次尝试:

function wrap1 {
   echo Starting: "$@"
   "$@"
}

您可以像wrap1 echo hello一样使用它。但问题是您无法执行alias myalias echo然后调用wrap1 myalias hello:它无法解析别名。

使用eval的另一次尝试:

function wrap2 {
   echo Starting: "$@"
   eval "$@"
}

现在调用别名有效。但问题是它也会对参数进行评估。例如,wrap2 echo "\\a"只打印a而不是\a,因为参数会被评估两次。

shopt -s expand_aliases似乎也没有帮助。

有没有办法同时评估像wrap2这样的别名,但是仍然像wrap1那样直接传递参数?

2 个答案:

答案 0 :(得分:7)

你(呃,我)可以使用printf%q来转义参数。 乍一看,使用printf转义然后执行eval总是会产生与直接传递参数相同的结果。

wrap() {
    echo Starting: "$@"
    eval $(printf "%q " "$@")
}

答案 1 :(得分:0)

似乎可以使用双eval

eval "eval x=($(alias y | cut -s -d '=' -f 2))"
# now the array x contains the split expansion of alias y
"${x[@]}" "${other_args[@]}"

所以也许你的功能可以编写如下:

wrap() {
    eval "eval prefix=($(alias $1 | cut -s -d '=' -f 2))"
    shift
    "${prefix[@]}" "$@"
}

然而,eval是邪恶的,双eval是双重邪恶,并且由于某种原因,别名不会在脚本中扩展。