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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3178604/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 22:17:14  来源:igfitidea点击:

Bash function calling command given as argument

bashevalalias

提问by Wouter Coekaerts

How do you write a function in bash that executes the command that it is given as an argument, where

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

  • The given command may be an alias
  • Arguments must be passed on exactly as given; no evaluating may be done
  • 给定的命令可能是别名
  • 参数必须完全按照给定的方式传递;无法进行评估

In other words, how to write an as-transparent-as-possible wrapperfunction.

换句话说,如何编写尽可能透明的包装函数。

The goal of the wrapper function could for example be to set the current directory before and after the given command, and/or set environment variables, or time how long the given command takes,... As a simple example here I take a function that just prints a line and then executes the given command.

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

A first attempt:

第一次尝试:

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

You could use it like wrap1 echo hello. But the problem is you cannot do alias myalias echoand then call wrap1 myalias hello: it wouldn't resolve the alias.

你可以像wrap1 echo hello. 但问题是你不能做alias myalias echo然后调用wrap1 myalias hello:它不会解决别名。

Another attempt using eval:

另一种尝试使用eval

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

Now calling an alias works. But the problem is it evaluates the arguments too. For example wrap2 echo "\\a"prints just ainstead of \abecause the arguments are evaluated twice.

现在调用别名有效。但问题是它也评估参数。例如wrap2 echo "\\a"版画只是a,而不是\a因为这些论点是两次评估。

shopt -s expand_aliasesdoesn't seem to help here either.

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

Is there a way to both evaluate aliases like wrap2, but still pass on the arguments directly like wrap1?

有没有办法既像 wrap2 一样评估别名,又像 wrap1 一样直接传递参数?

回答by Wouter Coekaerts

You (uh, I) can use printf %q to escape the arguments. At first sight, escaping with printf and then doing eval always gives the same result as passing the arguments directly.

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

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

回答by Philipp

It seems to be possible with a double eval:

似乎可以使用 double 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[@]}"

So maybe your function could be written as follows:

所以也许你的函数可以写成如下:

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

However, evalis evil, and double evalis double evil, and aliases are not expanded in scripts for a reason.

然而,eval是邪恶的,而双eval是双重邪恶的,并且脚本中没有扩展别名是有原因的。