15

背景:

我正在尝试制作一个以设定的时间间隔运行命令的函数,因为我无权访问“监视”程序。简化为最基本的功能,我要编写的函数是runit() { $1; }.

什么有效:

当我将不是别名的东西传递给它时,这很好用。例如,runit "ls -l"工作正常。我得到了ls -l命令的完整输出。

什么不起作用:

当我将别名传递给它时,问题就开始了。例如,设置alias ll="ls -l"然后调用runit "ll"将导致-bash: ll: command not found.

我尝试过的事情:

当我对 alias 进行硬编码时runit() { ll; },它可以正常工作并给我我所期望的。


我觉得我可能忽略了某些东西,但我不能完全把手指放在上面。
为什么硬编码别名可以正常工作,但将其传递给函数会失败?
有没有办法完成我正在尝试做的事情?

4

3 回答 3

8

bash别名的手册页讨论(强调我的):

别名在读取命令时扩展,而不是在执行命令时扩展。因此,与另一个命令出现在同一行的别名定义在读取下一行输入之前不会生效。该行别名定义之后的命令不受新别名的影响。执行函数时,此行为也是一个问题。 别名在读取函数定义时扩展,而不是在执行函数时扩展,因为函数定义本身就是一个复合命令。因此,在函数中定义的别名在该函数执行之前不可用。为了安全起见,请始终将别名定义放在单独的行中,并且不要在复合命令中使用别名。

您可以使用 type 命令在函数中观察到这种效果:

$ run_it () { ll; }
$ type run_it

您应该看到函数的主体包含对 的调用ls -l,而不是ll

别名部分的最后一句话:

对于几乎所有用途,别名都被 shell 函数所取代。

我对该行的解释是:如果您认为要使用别名,请先尝试编写一个函数。不要使用别名,除非该功能明显无法满足您的需求。

于 2013-01-25T18:16:10.473 回答
7

你可以eval这样使用:

$ runit() { eval $1; }
$ alias ll="ls -l"
$ runit "ll"

eval将在执行之前展开任何别名$1

于 2015-06-23T03:14:17.590 回答
4

解决这个问题的一种方法是定义一个 shell 函数而不是一个别名。

ll () {
  ls -l "$@"
}

别名在命令输入时扩展为宏,而 shell 函数在命令执行时匹配。这是一个完美的例子,说明了 shell 的宏处理器语言如何有利于交互式优雅,但却使实际编程变得复杂。

于 2013-01-25T18:00:18.210 回答