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