我CtrlR经常使用它来搜索我运行过的先前命令,然后编辑它们。我还经常使用它Alt.来循环显示先前命令的最后一个参数。我希望有一个可以同时完成这两件事的东西。
有没有办法搜索前面命令的各个参数并将其插入到当前命令中?例如:
$ run_pipeline --arg1 blah --arg2 blah some/long/path some/other/long/path
... run many other commands ...
$ ls -l <a keystroke that will let me bring up some/long/path>
理想情况下,我希望它是交互式的,例如CtrlR/ CtrlS,这样我可以在插入参数之前预览我将要插入的内容并编辑我的搜索。
答案1
使用以下 zle 小部件,您应该获得靠近你想要的行为:
fzf-last-word-widget() {
local POSITION RECALL_ARGUMENT
if [[ ! -z $NUMERIC ]]; then
POSITION=-${NUMERIC}
else
POSITION=-1
fi
histlist=$(
for histitem ("${(@f)$(fc -l 1)}") {
histwords=(${(z)histitem})
print -- $histwords[$POSITION]
}
)
RECALL_ARGUMENT=$(print $histlist | fzf --tac +s -e)
if [[ ! -z $RECALL_ARGUMENT ]]; then
LBUFFER="${LBUFFER}${(q)RECALL_ARGUMENT}"
zle redisplay
fi
}
zle -N fzf-last-word-widget
bindkey '^Xr' fzf-last-word-widget
- 我用
fzf
呈现历史记录最后参数的漂亮交互列表。因此需要安装它。 - 该小部件尊重数字参数还可以选择倒数第二个、倒数第三个等参数。请
man zshzle
检查数字参数如何在命令行中输入此内容。 - 在示例中,小部件绑定到
CTRL-X R
。
现在,为了更好地解释该小部件的工作原理,让我们将其拆开:
呂是个zsh 行编辑器它负责你在提示时的交互体验(相当于阅读行在狂欢)。
zle 小部件只是一个特殊的 shell 函数,它通过引入 zle
zle -N fzf-last-word-widget
然后可以像任何内置小部件一样绑定到键序列(bindkey '^Xr' fzf-last-word-widget
)。你可以通过数字参数到小部件;引用自
man zshzle
默认情况下,可以在 emacs 模式下按住 alt 键并输入数字,或在每个数字前按 Esc 键来输入;在 vi 命令模式下,可以在输入命令前输入数字。
该数字参数以变量形式传递给小部件$NUMERIC
并可在其中使用。
这是第一个代码块要处理的内容,它通过检查是否
$NUMERIC
不等于空字符串 (! -z $NUMERIC
) 来检查是否传递了数字参数。如果存在,则将其逆存储在local POSITION
名为 的局部变量 ( )中$POSITION
,否则$POSITION
默认为 -1。zle 中有许多特殊变量,其中一些可以更改;请参阅用户定义的小部件
man zshzle
。这里相关的是保存$LBUFFER
您输入的命令行的部分左边到光标(因此L
名称中为;还有$RBUFFER
)。如果您编辑它,光标会相应地移动,就在完整缓冲区(还有$BUFFER
)被重新绘制之后zle redisplay
。在这里,我将(本地)字符串附加$RECALL_ARGUMENT
到$LBUFFER
,但让嘚小心使用引用(q)
扩展标志(参见man zshexpn
),因此像 这样的参数path with spaces/foobar
最终会变成。 (如果为空,path\ with\ spaces/foobar
则会进行检查,例如当您中止 时。否则,您的命令行上最终会出现两个单引号。)$RECALL_ARGUMENT
fzf
''
现在任务就简化为根据您的需要构建 $RECALL_ARGUMENT。如前所述,我使用了
fzf
呈现一个漂亮的交互式列表,您可以轻松搜索并选择所需的内容fzf
。标准输入并把你的选择写给标准输出。参数禁用列表排序(+s
),反转列表(--tac
,我个人更喜欢)并启用精确匹配(-e
)。为了使其更具可读性,我拒绝编写一行代码,因此fzf
在数组中单独构建输入$histlist
。因此我们通过管道传递$histlist
给并通过命令替换fzf
将输出读入。$RECALL_ARGUMENT
$()
我们需要历史记录,因此我们从第一行开始通过 获取它
fc -l 1
,在换行符上将其拆分为数组(扩展标志(@f)
),然后使用 循环遍历每一行for
。我们确实需要用"${(@f)$(fc -l 1)}"
引号括起来,以防止在空格处拆分。现在
$histline
包含历史记录中的一行,例如1 echo foo
。我们将这一行拆分成壳字通过(z)
扩展标志。外壳词意味着echo foo\ bar
只拆分成echo
&foo\ bar
而不拆分成echo
,foo\
&bar
并将结果存储到 中$histwords
;这应该是一个数组,这就是为什么值用括号括起来的原因(...)
。拆分后,我们挑选出想要的外壳词,例如
$POSITION
日一(因为$POSITION
是负数,所以从后面开始计算),然后打印出来。(如果您想要单独选择所有参数,您可以使用命令,printf '%s\n' "${histwords[@]:1}"
或者使用print -l -- $histwords[2,-1]
应该相等的命令。)所有打印的字符串都聚集在数组中,然后按照上面的说明
$histlist
进行传递。fzf