Bash:使用自定义键盘快捷键调用脚本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4119991/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash: call script with customized keyboard shortcuts?
提问by sdaau
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.
假设我有一个脚本“ myscript.sh”,内容很简单echo $PWD。我想以某种方式将此脚本绑定到bash( gnome-terminal) 中的组合键- 这样当我按下此组合键时,“ myscript.sh”的输出就会插入(“粘贴”)到终端的光标位置。
Apparently, bashhistory and line manipulation is handled by readline- and the references I got for bashkeyboard shortcuts, do reference readline:
显然,bash历史和行操作是由readline处理的- 我得到的bash键盘快捷键参考,请参考readline:
I've also seen in Bash Reference Manual: Readline Init File Syntaxthat the key bindings for bashcan 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?
我还在Bash 参考手册:Readline Init File Syntax 中看到bash可以使用列出的键绑定bind -p(有关更多信息,请参阅help bind[not 'man bind'])。所以也许这个问题的标题是“_binding macros to custom keyboard shortcuts in readline” :) 但无论如何,我想要做什么?
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.
我想另一种方法是让脚本类似于“ pwd | xsel -b”,然后我在终端上调用它 - 然后我可以粘贴;但我仍然想要一个单一的键盘快捷键,比如 Ctrl-Alt-H(它似乎没有用于任何东西),它会在按下时立即插入/粘贴脚本输出。
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:
编辑:只是为了澄清 - 这是我想要这个设施的用例。我通常cd在一个项目文件夹中,通常命名为类似myproject-folder-0012a,它受svn. 还有一堆这样的文件夹。所以很多时候,我确实提交了消息的第一个单词是目录名称,如下所示:
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:
但这正是我不喜欢的地方——首先我输入 11 个字符,它们输入的速度相当快:
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).
然后,我无法使用自动完成来获取名称(我在文件夹内) - 这意味着我要么必须完全输入它(不可能:)),要么我从提示中复制粘贴(这需要选择 - 按鼠标,拖动,释放鼠标;然后是 Ctrl+Shift+C,然后是 Ctrl+Shift+V,如果我错过了对齐,再加上任何左/右键 - 加上删除等,如果我复制错误)。
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 :)
意思 - 做了这么多工作,只是为了获得血腥提交消息的血腥文件夹名称:(我宁愿按(比如)Ctrl-Alt-H 之类的东西,然后在光标位置自动插入文件夹名称,然后完成它:)
My suggestion for xselis 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 pwdfor my needs), and then I could do:
我的建议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"
... which sort of makes the workload less, but still - then I have to remember what the script name is, and call it, beforeI type the svncommand (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 ??! :)
...哪种方式可以减少工作量,但仍然 - 然后我必须记住脚本名称是什么,并在我输入svn命令之前调用它(我并不总是记得)......而且仍然 -我必须调用一个命令,然后按下一个组合键;为什么我不应该只按一次组合键,然后就完成了??!:)
Well, hope this clarifies my problem a bit better ....
好吧,希望这能更好地澄清我的问题......
EDIT2: However, another reason why a bashkeyboard 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 bashscript or function expansion directly).
EDIT2:然而,bash键盘快捷键有用的另一个原因是,我不仅可以在 shell 命令中“粘贴/插入当前目录名称”,还可以在终端程序中“粘贴/插入当前目录名称”,比如nano(可以说是更难直接使用bash脚本或函数扩展)。
回答by Paused until further notice.
Simple version:
简单版:
This command at a shell prompt:
此命令在 shell 提示符下:
bind '"\ee": "${PWD##*/}\e\C-e"'
or this line added to your ~/.inputrc:
或此行添加到您的~/.inputrc:
"\ee": "${PWD##*/}\e\C-e"
will cause Alt-eto insert the basename of the current directory on the command line. It requires that the default binding of the readline function shell-expand-linewhich is \e\C-ebe present (this could be adapted if it's different). I'm also making the assumption that you're using Bash's emacs mode.
将导致Alt-e在命令行上插入当前目录的基本名称。它要求默认readline的功能的结合shell-expand-line是\e\C-e存在的(这可能是,如果它是不同的改编)。我还假设您正在使用 Bash 的 emacs 模式。
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.
并按Alt- e,引号将消失。有几种方法可以解决这个问题。
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:
一,假设您将失去的只是引用,然后手动将其添加回来或让 readline 宏为您添加它:
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].
这使该行的其余部分保持完整(没有其他任何内容被扩展或删除),但它使用了终止环,因此它可能会使其处于与您预期不同的状态(如果您正在使用它)。它还在插入的目录名称后插入一个空格(宏中的空格用于确保如果在行的开头或结尾执行宏,则旧的 kill-ring 内容不会反刍)。无论光标在行中的位置如何,宏都应该工作。插入将在光标的位置进行,将光标留在相同的位置 [在第一个版本中]。
Edit:The second version leaves the cursor after the dirname and space that are inserted.
编辑:第二个版本在插入的目录名和空格之后留下光标。
Edit 2:
编辑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:
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"'
By the way, you should know that Bash keyboard shortcuts are not active in other programs such as nano.
顺便说一句,您应该知道 Bash 键盘快捷键在其他程序(例如nano.
回答by sdaau
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 :))
好的,不是真正的答案,但我只想总结到目前为止我得到的评论,这些评论对我的问题很有用。然而,目前的问题——关于运行任意脚本的 bash 键盘快捷键——仍然没有得到回答(我仍然更喜欢用一个键组合来完成所有这些:))
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 bashfunctions to my .bashrc(note: make sure you reload bashafter you add these lines to .bashrc- for example, simply by typing bashin your current terminal):
或者,我可以bash向我的.bashrc(注意:确保bash在将这些行添加到后重新加载.bashrc- 例如,只需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
Basically, I misunderstood Reese Moore's suggestion originally - you can indeed use backticks - consider this command session (after the above commands have been ran):
基本上,我最初误解了 Reese Moore 的建议——你确实可以使用反引号——考虑这个命令会话(在运行上述命令之后):
$ 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-mas 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-testfunction:
...或者,我可以遵循 camh 的建议,并将其svnci-m用作函数(在我的情况下,我几乎从不使用 附加参数svn ci,因此我的版本略有不同)。为了测试参数是否正确传递,我可以使用该svnci-test函数:
$ svnci-test "my message"
Desktop: my message\
Thanks for the comments so far,
Cheers!
感谢到目前为止的评论,
干杯!
回答by camh
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.
使用单个按键完成所需操作的一种方法是利用 bash 中的可编程完成功能。您可能使用 bash_completion 工具/包设置了一些可编程完成。如果没有,请查看它以了解它是如何完成的细节。
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).
这个想法是让可编程完成识别您何时点击 svn 提交消息的开头,然后让它返回一个单独的完成,即您要插入的文本(当前目录的基本名称)。
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 scriptmay be a good start.
我只涉足可编程完成,所以我不能给你详细信息,但上面提到的 bash_completion 包或subversion 完成脚本可能是一个好的开始。

