【发布时间】:2019-02-15 13:34:38
【问题描述】:
我花了整整一周的时间在网上搜索并尝试了许多不同的方法来解决一个棘手的问题。基本上我想使用 vim 来编辑我的 $PATH 中的自定义命令/脚本,而不必先实际 cd 到它们的给定目录或在命令行上手动键入它们的 完整路径。
本质上,当将我的 $PATH 中的脚本指定为 vim 文件参数时,我希望能够将常用的 bash 命令完成 (compgen -c) 与同时路径扩展结合起来。顺便说一句,我用大写字母来说明什么是棘手的主题,而不是大喊大叫。
向您展示我正在尝试做什么然后解释它可能更容易。假设我在 $PATH 上的目录中有脚本
~/bin/x/y/cmd1.sh
~/bin/a/b/cmd2.sh
/ppp/n/m/cmd3.sh
有时这些脚本会提供其他目录中存在的文件的功能,因此我希望能够从文件系统中的任何位置轻松编辑它们。有时我只想能够从其他目录编辑这些脚本,因为它更方便。假设我目前在以下目录中。
/completely/different/dir
但现在我需要 vim 编辑
~/bin/a/b/cmd2.sh
仅使用默认 bash 功能实现此目的的选项是执行以下操作之一,这需要很长时间
cd ~/bin/a/b/; vim cmd.sh
vim ~/<tab-complete-my-way-to-file>
open a new terminal window plus some combination of the above
因为我知道我的自定义脚本的名称,所以只需执行以下操作就容易多了我的语境!!!
vim cmd2.sh
但这在默认情况下不起作用 b/c vim 需要脚本的完整路径
我的第一个想法是编写一个 vim 包装函数,它基本上使用 which 为我进行 $PATH 扩展,然后将 bash 命令完成与我的 vc 函数联系起来,如下所示:
vc () { vim $(which "$@"); }
complete -c vc
我可以在shell中运行以下命令来完成cmd1.sh, cmd2.sh, cmd3.sh选项中以“c”开头的部分脚本名称
vc c<tab>
直到我在这里得到我想要的,这很棒
vc cmd2.sh
当我按 Enter 并执行命令时,一切正常,但它不会将扩展路径注入 READLINE 命令行,因此 'cmd2.sh' 的完整扩展路径永远不会在我的命令中结束历史!我的历史会证明这一点
vc cmd2.sh
而不是
vc ~/bin/a/b/cmd2.sh
或 vim ~/bin/a/b/cmd2.sh
我希望在我的命令历史记录中使用该扩展路径,因为在重用命令历史记录时,它使以后对该脚本文件的操作变得超级容易。即我可以 ls、file、diff、mv、cp 扩展路径比为 ls、file、diff、mv、cp 等编写更多的包装脚本更容易重用历史记录。就像我在上面对 vc 所做的那样。
问题:
选项 1
有没有办法将我的 vc 函数中的 which 提供的完整扩展路径直接重新注入到原始 vc READLINE 中,或者只注入实际执行的整个“vim”命令vc 代替原来的vc 命令变成READLINE?任何允许我将扩展的 vim 命令放入历史记录的方法,即使它是除了原始 vc 命令之外的任何方法,我都可以。
基本上你如何在 bash 中以编程方式访问和编辑当前的 READLINE?
选项 2
注意,我也可以直接在命令行上实时执行类似的操作
vim $(which cmd2.sh) C-x-e
这给了我我想要的东西(它扩展了路径,然后将其放入历史记录)但我必须在每次迭代时输入额外的子外壳和文本以及 C-x-e(扩展行)命令同时失去了命令完成功能,这基本上使它无用。换句话说,有没有使用绑定键自动执行上述操作,以便
vc cmd2.sh
首先自动转换为
vim $(which cmd2.sh)
然后自动跟进C-x-e,使其扩展为
vim ~/bin/a/b/cmd2.sh
但是所有的编辑动作、文本插入和最终的命令行扩展都发生在同一个 bindkey 宏中吗?这可能是最好的解决方案。
选项 3
另外,由于 bash 命令完成自动在 READLINE 中结束,因此在历史记录中,自定义完成功能可以解决我的问题。有没有办法让 vc 使用完成函数,如上所述,当用作 vim 参数时,$PATH 中的两个命令都会完成 并且同时将它们扩展到它们的完整路径?
我知道如何编写一个基本的完成函数。无数小时的尝试(我选择不放在这里以保持混乱/缩短帖子长度)都失败了,原因很简单,我不确定命令完成是否与同时全路径扩展兼容 b/c 它打破了传统的完成。
使用自定义完成功能,当我尝试在“vim ~/bin/a/b/cmd2.sh”中找到我的一个脚本“cmd2.sh”但以“c”开头并且点击“”。
vim c<tab>
而不是让我选择这些补全
cmd1.sh cmd2.sh cmd3.sh
它完成它在 $PATH 中找到的第一个,并将其插入到可能是 READLINE 的 READLINE 中
/ppp/n/m/cmd3.sh
当我真正想要的时候
~/bin/a/b/cmd2.sh
这有效地终止了完成查找,因为 READLINE 中光标之前的单词现在以 /ppp/n/m/cmd3.sh 开头,并且无法返回到 cmd2.sh
我希望这很清楚。
谢谢
【问题讨论】:
-
有趣的问题。我个人会对
vc别名感到满意,并且可能将另一个别名添加到cd到目录中,然后在那里编辑文件。然后,您有两个别名,一个仅用于编辑,另一个用于对文件进行编辑和执行其他操作(现在在本地)。缺点是你需要事先知道你打算做什么,但这可以避免你以同样的方式重载所有其他命令。 -
一个真正不同的看法是,如果您发现自己需要经常编辑
PATH目录中的脚本,它们就不够通用。你需要的是让脚本更有用,而不是更容易编辑。 -
@chepner 我明白你在说什么,在某些方面你是对的。问题是 1) 一个人正在开发你所说的那些更有用和更通用的脚本,我在这篇文章中要求的内容仍然非常有用和实用,可以帮助你实现目标。 2)我写了很多脚本,其中一些寿命很短,所以花在使它们更通用和有用上的时间不值得额外的投资......也就是说,我想做的事情具有真正的价值和只是解决问题的另一种方式:)
-
@IngoKarkat 我可以做到这一点,但我会在我不记得的太多其他别名首字母缩写词中设置更多别名和函数,所以我从不使用其中的一半;)即只是另一个级别的间接性使我无法轻松实现自动化,因此它可以在许多情况下仅使用一个功能即可重用。谢谢你的建议!
标签: bash readline bash-completion