xan*_*adu 7 bash command-history alias history-expansion
我在系统/etc/bashrc
文件中设置了这个别名:
alias root="sudo !!"
Run Code Online (Sandbox Code Playgroud)
这样做的目的是运行最后使用的命令sudo
,当然。使用时,它当然似乎是在 shell 初始化时将最后一个命令替换history
到bashrc
文件中,而不是sudo !!
在交互式 shell 中运行时将获得的实际命令。我也试过alias root="sudo fc -s"
没有用。
我意识到这可能与 BASH 如何执行命令替换有关,但有人可以解释为什么会这样,并提供一个可用的替换吗?
我正在运行 BASH 版本 3.2.51(1)-release (x86_64-apple-darwin13)。
此行为的关键部分由 bash 联机帮助页中的 2 位解释:
在该HISTORY EXPANSION
部分:
读完一行后立即执行历史扩展,然后 shell 将其分解为单词。
在该ALIASES
部分:
每个简单命令的第一个单词,如果没有被引用,则检查它是否有别名。
所以基本上历史扩展发生在分词之前。别名扩展发生在之后。
我能想到的最好的方法是:
alias root='sudo $(fc -ln -1)'
Run Code Online (Sandbox Code Playgroud)
这适用于简单的命令,但对于更复杂的命令,我们需要对其进行调整。
alias root='sudo sh -c "$(fc -ln -1)"'
Run Code Online (Sandbox Code Playgroud)
改变的原因是因为这样的事情:
alias root='sudo $(fc -ln -1)'
Run Code Online (Sandbox Code Playgroud)
如您所见,没有完成任何外壳解析。通过将其更改为使用sh -c "..."
,它会执行 shell 解释。
alias root='sudo sh -c "$(fc -ln -1)"'
Run Code Online (Sandbox Code Playgroud)
另一种方式(我首先想到了这个,因此将其保留在答案中,但不如上面的好):
alias root='fc -e "sed -i -e \"s/^/sudo /\""'
Run Code Online (Sandbox Code Playgroud)
该fc -e
命令将运行指定的命令,并传递一个包含先前执行的命令的文件。我们只是sed
在该文件上运行,在命令前加上sudo
.
您不能以这种方式使用别名。别名不能传递诸如 之类的参数!!
。为了达到你想要的效果,你可以使用函数来代替。
function root() {
sudo $(history | tail -2 | head -1 | awk '{$1=$2=$3=""; print $0}');
}
Run Code Online (Sandbox Code Playgroud)
但这是一个粗略的想法,可能会存在一些问题。我的历史命令的输出如下所示:
$ history
1081 20131205 08:00:12 ls
1082 20131205 08:00:13 history
Run Code Online (Sandbox Code Playgroud)
所以我需要解析这个输出。在上面,我正在运行历史记录,获取最后 2 个命令,然后获取最后 2 个命令中的第一个,这是之前运行的命令。然后我用来awk
删除前 4 列,留下之前运行的命令行。
鉴于我们使用的是 的输出history
,实际上没有任何理由再使用 Bash 函数。如果您尝试将上一个命令作为参数传递,则需要这样做,但我们history
现在通过该命令获取它。
$ alias root="sudo \$(history | tail -2 | head -1 | awk '{\$1=\$2=\$3=\"\"; print \$0}')"
Run Code Online (Sandbox Code Playgroud)
除了将其转换为别名所需的更棘手的转义之外,上面的工作原理与该函数类似。