我试图将_!
替换为sudo
最后一个命令,但我遇到了障碍。 !!
似乎无法在我的.zshrc
文件中运行,并且sed给了我一再重复的问题。我尝试使用以下命令及其中的几个变体,但无济于事。
history | tail -1 | sed -e 's/[^0-9\*\ ]+/\0/g'
但是,这仍然将管道输入解释为文件,而不是文本字符串。我还尝试了使用awk
的变体:
history | tail -1 | awk '{ gsub("/[^0-9\*\ ]+", "") ; system( "echo" $1 ) }'
我确定我在将命令正确输入时遇到了一些麻烦,但我们会感激一些帮助。
答案 0 :(得分:6)
您可以使用fc
内置程序以编程方式访问历史记录。例如,我相信这会按照您的意愿行事:
alias _!='fc -e "sed -i -e \"s/^/sudo /\""'
没有参数,fc
("修复命令"的缩写)会激活前一个命令的$EDITOR
并运行编辑结果。您可以使用-e
选项指定其他编辑器;在这里,我以sed
命令的形式指定一个非交互式命令,它将sudo
插入命令行前面。
该命令假定GNU为sed。如上所述,它也适用于现代BSD / macOS上的版本,但是通过hackcident:它将-e
视为-i
的参数而不是新选项。由于-e
是可选的,只有一个表达式,这样可以正常工作,但这意味着sed
在最后使用-e
对临时文件进行备份,这将在命令完成。您可以在这些系统上使用此备用版本来使其更清洁:
alias _!='fc -e "sed -i \"\" -e \"s/^/sudo /\""'
(赢得' 使用GNU sed,它将空字符串参数视为要操作的文件名...)
在较旧的系统上,更便携的解决方案可以使用ed
:
alias _!="fc -e 'ed -s <<<$'\''s/^/sudo /\nw\nq'\'"
你可以经常使用更简单的东西,比如sudo $(fc -ln -1)
(-l
=列表命令,-n
=没有数字,-1
=只有最后一个命令),但是一般情况下,您会遇到引用问题,因为命令是按fc
输入的方式输出的:
% touch '/etc/foo bar'
touch: /etc/foo bar: Permission denied
% sudo $(fc -ln -1)
touch: '/etc/foo: No such file or directory
以上都不限于zsh,btw; fc
与ksh的原始版本保持一致,因此它也适用于bash等。
答案 1 :(得分:3)
此fc
命令将始终在zsh
和bash
中提供最近执行的命令:
fc -ln -1
根据help fc
:
-l (letter el) list lines instead of editing
-n omit line numbers when listing
-1
(减1)获得刚刚执行的命令。
答案 2 :(得分:1)
为sudo找到了一个惊人的小部件:
sudo-command-line() {
[[ -z $BUFFER ]] && zle up-history
[[ $BUFFER != sudo\ * ]] && {
typeset -a bufs
bufs=(${(z)BUFFER})
if (( $+aliases[$bufs[1]] )); then
bufs[1]=$aliases[$bufs[1]]
fi
bufs=(sudo $bufs)
BUFFER=$bufs
}
zle end-of-line
}
zle -N sudo-command-line
bindkey "\e\e" sudo-command-line
作者:lilydjwg
以下是在命令中运行最后一个命令的方法:
fc -ln -1
是最简单的方法,但有一个问题,当在命令开头运行某些空格时,此命令将不会显示在历史记录中,基于历史记录的任何内容都不会正常工作。
因此我们需要ZLE(Zsh Line Editor)手动存储命令。
Store_Your_Command () {
if [[ -z $BUFFER ]]
then
# If nothing input, just clear the screen
zle clear-screen
else
zle accept-line
# Remember the last command, useful in some alias
# Add space at the beginning of a command, this command wont
# show up in history, so use variables to store the command
LAST_COMMAND=$CURRENT_COMMAND
CURRENT_COMMAND=$BUFFER
fi
}
# Create a user-defined widget
zle -N Store_Your_Command
# Bind it to the **Enter** key
bindkey "^M" Store_Your_Command
然后每当我们按Enter键运行命令时,此命令将存储在$ CURRENT_COMMAND中,最后一个命令将存储在$ LAST_COMMAND中。
想要运行最后一个命令?只需运行eval $LAST_COMMAND
,您也可以将其添加到别名中。
当在最后一个命令中使用某个别名时,zsh不会正确运行最后一个命令,因此我们需要扩展别名:当我们输入别名时,在内置zle的帮助下将别名替换为原始命令/内容: _expand_alias。
首先,删除我们刚刚添加的小部件。 将它们添加到.zshrc:
# When input space, expand alias -----------------------------------{{{
expand_alias_space () {
zle _expand_alias
zle self-insert
}
zle -N expand_alias_space
bindkey " " expand_alias_space
# }}}
# When input enter, expand alias -----------------------------------{{{
expand_alias_enter () {
if [[ -z $BUFFER ]]
then
zle clear-screen
else
zle _expand_alias
zle accept-line
# Remember the last command, useful in some alias
# Add space at the beginning of a command, this command won't
# show up in history, so use variables to store the command
LAST_COMMAND=$CURRENT_COMMAND
CURRENT_COMMAND=$BUFFER
fi
}
zle -N expand_alias_enter
bindkey "^M" expand_alias_enter
# }}}
现在我们可以通过按Space
键将别名扩展到原始命令/内容,或者只需按Enter
键即可运行命令,并使用eval $LAST_COMMAND
运行最后一个命令而不执行任何操作问题。
但是,当运行命令使用eval $LAST_COMMAND
两次时,它会调用另一个问题:
zsh: job table full or recursion limit exceeded
我们需要将eval $LAST_COMMAND
替换为真实命令,因为$LAST_COMMAND
总是会改变。
我们写一个函数运行像这样的最后一个命令
# Echo the last command
fun()
{
# The command we need to run in this function
CURRENT_COMMAND="echo \[`echo $LAST_COMMAND`\]"
# run the command
eval $CURRENT_COMMAND
}
$CURRENT_COMMAND
中存储的命令不会像eval $LAST_COMMAND
那样改变。
问题解决了。
我希望没有更多问题