Bash:使用自定义键盘快捷键调用脚本?

发布于 2024-10-01 05:33:43 字数 2385 浏览 1 评论 0原文

假设我有一个脚本“myscript.sh”,其内容只是echo $PWD。我想以某种方式将此脚本绑定到 bash (gnome-terminal) 中的组合键 - 这样,当我按下此组合键时,输出“myscript.sh”被插入(“粘贴”)到终端中的光标位置。

显然, bash 历史记录和行操作由 readline 处理 - 并且我获得的关于 bash 键盘快捷键的参考,请参考 readline:

我还在 Bash 参考手册:Readline Init File Syntax 中看到了关键可以使用 bind -p 列出 bash 的绑定(请参阅 help bind [not 'man bind'] 了解更多信息)。所以也许这个问题的标题最好是“_将宏绑定到readline中的自定义键盘快捷键”:)但无论如何,我想要做的事情是可能的吗?

我想另一种选择是让脚本类似于“pwd | xsel -b”,然后我在终端上调用它 - 然后我可以粘贴;但我仍然想要一个键盘快捷键,比如 Ctrl-Alt-H (似乎没有用于任何用途),按下时它将立即插入/粘贴脚本输出。

预先感谢,
干杯!

 
编辑:只是为了澄清 - 这是我的用例,我想要这个设施。我通常将 cd 放在项目文件夹中,通常命名为 myproject-folder-0012a,该文件夹由 svn 进行修订控制。还有很多这样的文件夹。因此,我经常提交消息的第一个单词是目录名称的情况,如下所示:

svn ci -m "myproject-folder-0012a: here a commit message"

但这就是我不喜欢的 - 首先我输入 11 个字符,速度相当快:

svn ci -m "

然后,我无法使用自动完成获取名称(我在文件夹内) - 这意味着我要么必须完全输入它(不可能:)),或者我从提示中复制粘贴它(这需要选择 - 按鼠标,拖动,释放鼠标;然后 Ctrl+Shift+C,然后 Ctrl+Shift+V,如果我错过了对齐,则加上任何左/右键 - 如果我复制错误,则加上删除等)。

意思是——这么多的工作,只是为了获取该死的提交消息的该死的文件夹名称:(我宁愿按(例如)Ctrl-Alt-H之类的东西,并让文件夹名称自动插入到光标位置,然后完成了:)

我对 xsel 的建议只是因为我可以将它放入“全局”脚本中 - 将其符号链接为 /usr/bin/myscript (显然,脚本的内容是 echo $(basename $PWD) 而不仅仅是满足我的需要的 pwd ),然后我可以这样做:

$ myscript       # this puts directory name in clipboard
$ svn ci -m "[CTRL+SHIFT+V TO PASTE HERE]myproject-folder-0012a[NOW TYPE]: here a commit message"

...这使得工作量减少,但仍然 - 然后我必须记住脚本名称是什么,并调用它,之前我输入svn命令(我并不总是记得这一点)...而且 - 我必须调用命令,然后按组合键;为什么我不应该只按一次组合键,然后就完成了??! :)

好吧,希望这能更好地澄清我的问题....

 
EDIT2:然而, bash 键盘快捷键有用的另一个原因是,我不仅可以在 shell 命令中“粘贴/插入当前目录名称”,而且还可以在终端程序中“粘贴/插入当前目录名称”,比如nano(可以说,直接使用 bash 脚本或函数扩展会更困难)。

Lets say I have a script, "myscript.sh", with contents being simply echo $PWD. I'd like to bind somehow this script to a key combo in bash (gnome-terminal) - so that when I press this key combination, the output of "myscript.sh" is inserted ("pasted") at the cursor position in the terminal.

Apparently, bash history and line manipulation is handled by readline - and the references I got for bash keyboard shortcuts, do reference readline:

I've also seen in Bash Reference Manual: Readline Init File Syntax that the key bindings for bash can be listed by using bind -p (see help bind [not 'man bind'] for more). So maybe this question would better be titled as "_binding macros to custom keyboard shortcuts in readline" :) But in any case, is what I want possible to do?

I guess an alternative would be to have the script be something like "pwd | xsel -b", and then I call it on terminal - and I can paste afterwards; but I'd still like a single keyboard shortcut instead, say like Ctrl-Alt-H (which seems to be not used for anything), which will immediately insert/paste script output when pressed.

Thanks in advance,
Cheers!

 
EDIT: Just to clarify - here is my use case where I'd like this facility. I'm usually cd'd in a project folder, usually named something like myproject-folder-0012a, which is under revision control by svn. And there is a bunch of these folders. So quite often, I do commits where the first word of the message is the directory name, as in:

svn ci -m "myproject-folder-0012a: here a commit message"

But that is what I don't like - first I type 11 characters, which go rather fast:

svn ci -m "

And then, I cannot use autocompletion to get the name (i'm inside the folder) - which means I either have to fully type it (no way :)), or I copy paste it from the prompt (which requires selection - press mouse, drag, release mouse; then Ctrl+Shift+C, and then Ctrl+Shift+V, plus any left/right keys if I miss allignment - plus deletions and such if I make the copy wrong).

Meaning - so much work, just to get the bloody folder name for a bloody commit message :( I'd MUCH rather press something like (say) Ctrl-Alt-H, and have the folder name automatically inserted at cursor position, and be done with it :)

My suggestion for xsel is only because I could put it into a "global" script - say symlink it as /usr/bin/myscript (and obviously, the contents of the script are echo $(basename $PWD) rather than just pwd for my needs), and then I could do:

$ myscript       # this puts directory name in clipboard
$ svn ci -m "[CTRL+SHIFT+V TO PASTE HERE]myproject-folder-0012a[NOW TYPE]: here a commit message"

... which sort of makes the workload less, but still - then I have to remember what the script name is, and call it, before I type the svn command (and I don't always remember that)... And still - I have to call a command, and then press a key combo; why shouldn't I just press a key combo once, and be done with it ??! :)

Well, hope this clarifies my problem a bit better ....

 
EDIT2: However, another reason why a bash keyboard shortcut would be useful, is that then I could also "paste/insert current directory name" not only in shell commands - but also in terminal programs, say like nano (where it would, arguably, be more difficult to use bash script or function expansion directly).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

淡莣 2024-10-08 05:33:43

简单版本:

在 shell 提示符下执行此命令:

bind '"\ee": "${PWD##*/}\e\C-e"'

或将此行添加到您的 ~/.inputrc 中:

"\ee": "${PWD##*/}\e\C-e"

将导致 Alt-e 插入命令行上当前目录的基本名称。它要求存在 readline 函数 shell-expand-line 的默认绑定,即 \e\Ce(如果不同,可以进行调整)。我还假设您正在使用 Bash 的 emacs 模式。

不幸的是,它也会导致已经输入的内容也被扩展。这样做的影响之一是,输入:

svn ci -m "

并按 Alt-e 后,引号将消失。有几种方法可以解决这个问题。

一,假设您将丢失的只是报价,然后手动将其添加回来或让 readline 宏为您添加它:

bind '"\ee": "${PWD##*/}\e\C-e\eb\"\C-e"'

这并不是很令人满意。

高级版本:

或者,二,杀死该行,进行插入,然后将其拉回:

bind '"\ee": " \C-u \C-a\C-k${PWD##*/}\e\C-e\C-y\C-a\C-y\ey\b"'

或者

bind '"\ee": " \C-u \C-a\C-k${PWD##*/}\e\C-e\C-y\C-a\C-y\ey\b\ef\C-f"'

这会使该行的其余部分保持不变(没有其他内容被扩展或删除),但它使用了终止环,因此它可能会留下它的状态与您期望的不同(如果您正在使用它)。它还会在插入的目录名后插入一个空格(宏中的空格用于确保如果在行的开头或结尾执行宏,则旧的终止环内容不会反流)。无论光标在行中的位置如何,宏都应该起作用。插入将在光标的位置进行,使光标保持在相同的位置[在第一个版本中]。

编辑:第二个版本将光标留在插入的目录名和空格之后。

编辑2:

readline函数shell-forward-word(未绑定)比forward-word\ef< /代码>)为此。您可以这样使用它:

bind '"\ew":shell-forward-word'
bind '"\ee": " \C-u \C-a\C-k${PWD##*/}\e\C-e\C-y\C-a\C-y\ey\b\ew\C-f"'

顺便说一下,您应该知道 Bash 键盘快捷键在其他程序(例如 nano)中不活动。

Simple version:

This command at a shell prompt:

bind '"\ee": "${PWD##*/}\e\C-e"'

or this line added to your ~/.inputrc:

"\ee": "${PWD##*/}\e\C-e"

will cause Alt-e to insert the basename of the current directory on the command line. It requires that the default binding of the readline function shell-expand-line which is \e\C-e be present (this could be adapted if it's different). I'm also making the assumption that you're using Bash's emacs mode.

Unfortunately, it causes things that have already been typed to be expanded as well. One of the affects of this is that after having typed:

svn ci -m "

and pressing Alt-e, the quotation mark will have disappeared. There are a couple of ways to deal with this.

One, assume that all you'll lose is the quote and either manually add it back or have the readline macro add it for you:

bind '"\ee": "${PWD##*/}\e\C-e\eb\"\C-e"'

which just isn't very satisfactory.

Advanced version:

Or, two, kill the line, do the insertion, then yank the line back:

bind '"\ee": " \C-u \C-a\C-k${PWD##*/}\e\C-e\C-y\C-a\C-y\ey\b"'

or

bind '"\ee": " \C-u \C-a\C-k${PWD##*/}\e\C-e\C-y\C-a\C-y\ey\b\ef\C-f"'

This leaves the rest of the line intact (nothing else is expanded or deleted), but it uses the kill ring, so it may leave it in a state that's different than you expect (if you're using it). It also inserts a space after the inserted directory name (the spaces in the macro are used to ensure that older kill-ring contents are not regurgitated if the macro is executed at the beginning or end of the line). The macro should work regardless of the position of the cursor in the line. The insertion will be made at the cursor's position, leaving the cursor in the same position [in the first version].

Edit: The second version leaves the cursor after the dirname and space that are inserted.

Edit 2:

The readline function shell-forward-word (unbound) does a better job than forward-word (\ef) for this. You can make use of that like this:

bind '"\ew":shell-forward-word'
bind '"\ee": " \C-u \C-a\C-k${PWD##*/}\e\C-e\C-y\C-a\C-y\ey\b\ew\C-f"'

By the way, you should know that Bash keyboard shortcuts are not active in other programs such as nano.

流年已逝 2024-10-08 05:33:43

好吧,这并不是一个真正的答案,但我只是想总结一下迄今为止收到的评论,这些评论对我的问题很有用。然而,目前的问题 - 关于运行任意脚本的 bash 键盘快捷键 - 仍然没有得到解答(我仍然更喜欢用一个组合键来完成所有这一切:)

 
首先,我可以使用“全局”脚本,例如:

$ sudo bash -c 'cat > /usr/bin/bpwd <<EOF
#!/bin/bash
basepwd=\$(basename \$(pwd))
echo -n \$basepwd                 # suppress line ending
# exec 1>/dev/null               # debug: redir stdout to null
echo -n \$basepwd | xsel -i -b    # suppress LF, and make xsel read from stdin 
# exec 1>/dev/tty                # debug: restore stdout
EOF
chmod +x /usr/bin/bpwd'

或者,我可以将 bash 函数添加到我的 .bashrc注意:请确保重新加载 将这些行添加到 .bashrc 后,执行 bash - 例如,只需在当前终端中输入 bash):

$ echo '
bpwd2() { basepwd=${PWD##*/} ; echo -n $basepwd | xsel -i -b ; echo -n $basepwd ; }
svnci-test() { echo -n "$(bpwd2): $*" ; }
svnci-m() { svn ci -m "$(bpwd2): $*" ; }' >> ~/.bashrc

 
基本上,我最初误解了 Reese Moore 的建议 - 你确实可以使用反引号 - 考虑这个命令会话(在运行上述命令之后):

$ bpwd
Desktop\
$ bpwd2
Desktop\
$ echo `bpwd`
Desktop
$ echo "`bpwd2` 2"
Desktop 2

这就是我理解 Moore 的“输出”所需要的反引号命令中的内容将用作执行命令的输入”(但是,还需要注意清除输出中的行结尾);或者,就我而言,我可以调用

svn ci -m "`bpwd`: my message here"
# svn ci -m "${PWD##*/}: my message here" # alternatively

...或者,我可以遵循 camh 的建议,并将 svnci-m 用作函数(在我的情况下,我几乎从不使用额外的参数svn ci,所以我的版本略有不同)。为了测试参数是否正确传递,我可以使用 svnci-test 函数:

$ svnci-test "my message"
Desktop: my message\

 
感谢您迄今为止的评论,
干杯!

Ok, not really an answer, but I'd just like to summarize the comments I got so far, which are useful for my problem. However, the question as it stands - in respect to bash keyboard shortcuts running arbitrary scripts - is still not answered (I'd still prefer doing all this with a single key combo :))

 
First, I can use a 'global' script like:

$ sudo bash -c 'cat > /usr/bin/bpwd <<EOF
#!/bin/bash
basepwd=\$(basename \$(pwd))
echo -n \$basepwd                 # suppress line ending
# exec 1>/dev/null               # debug: redir stdout to null
echo -n \$basepwd | xsel -i -b    # suppress LF, and make xsel read from stdin 
# exec 1>/dev/tty                # debug: restore stdout
EOF
chmod +x /usr/bin/bpwd'

Or, I can add bash functions to my .bashrc (note: make sure you reload bash after you add these lines to .bashrc - for example, simply by typing bash in your current terminal):

$ echo '
bpwd2() { basepwd=${PWD##*/} ; echo -n $basepwd | xsel -i -b ; echo -n $basepwd ; }
svnci-test() { echo -n "$(bpwd2): $*" ; }
svnci-m() { svn ci -m "$(bpwd2): $*" ; }' >> ~/.bashrc

 
Basically, I misunderstood Reese Moore's suggestion originally - you can indeed use backticks - consider this command session (after the above commands have been ran):

$ bpwd
Desktop\
$ bpwd2
Desktop\
$ echo `bpwd`
Desktop
$ echo "`bpwd2` 2"
Desktop 2

This is what I needed to understand Moore's "the output from the backticked commands will be used as input on the executed command" (however, one also needs to take care to clean the line endings from the output); or, in my case, I can call

svn ci -m "`bpwd`: my message here"
# svn ci -m "${PWD##*/}: my message here" # alternatively

... or, I could follow camh's suggestion, and use svnci-m as a function (in my case, I almost never use additional arguments to svn ci, and so my version is slightly different). And to test whether arguments are passed correctly, I can use the svnci-test function:

$ svnci-test "my message"
Desktop: my message\

 
Thanks for the comments so far,
Cheers!

野侃 2024-10-08 05:33:43

只需按一下按键即可完成所需操作的一种方法是利用 bash 中的可编程完成功能。您可能使用 bash_completion 工具/包设置了一些可编程完成。如果没有,请研究一下它的具体操作方式。

这个想法是让可编程补全识别您何时点击了 svn 提交消息的开头,然后让它返回一个补全,即您想要插入的文本(当前目录的基本名称)。

我只涉足可编程完成,所以我不能给你详细信息,但是上面提到的 bash_completion 包或 subversion 完成脚本 可能是一个好的开始。

One way to do what you want with a single key press is to take advantage of programmable completion in bash. You possibly have some programmable completion set up with the bash_completion tool/package. If not, look into that to see the specifics of how it is done.

The idea is to have the programmable completion recognise when you have hit at the start of a svn commit message and then have it return a single completion which is the text you want to insert (the basename of the current directory).

I've only dabbled with programmable completion so I can't give you the details, but the above-mentioned bash_completion package or the subversion completion script may be a good start.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文