In bash, how do I bind a function key to a command?
Asked Answered
M

4

119

Example: I want to bind the F12 key to the command echo "foobar" such that every time I hit F12 the message "foobar" will be printed to screen. Ideally it could be any arbitrary shell command, not just builtins. How does one go about this?

Meador answered 17/11, 2010 at 1:48 Comment(0)
P
206

You can determine the character sequence emitted by a key by pressing Ctrl-v at the command line, then pressing the key you're interested in. On my system for F12, I get ^[[24~. The ^[ represents Esc. Different types of terminals or terminal emulators can emit different codes for the same key.

At a Bash prompt you can enter a command like this to enable the key macro so you can try it out.

bind '"\e[24~":"foobar"'

Now, when you press F12, you'll get "foobar" on the command line ready for further editing. If you wanted a keystroke to enter a command immediately, you can add a newline:

bind '"\e[24~":"pwd\n"'

Now when you press F12, you'll get the current directory displayed without having to press Enter. What if you've already typed something on the line and you use this which automatically executes? It could get messy. However, you could clear the line as part of your macro:

bind '"\e[24~":"\C-k \C-upwd\n"'

The space makes sure that the Ctrl-u has something to delete to keep the bell from ringing.

Once you've gotten the macro working the way you want, you can make it persistent by adding it to your ~/.inputrc file. There's no need for the bind command or the outer set of single quotes:

"\e[24~":"\C-k \C-upwd\n"

Edit:

You can also create a key binding that will execute something without disturbing the current command line.

bind -x '"\eW":"who"'

Then while you're typing a command that requires a username, for example, and you need to know the names of user who are logged in, you can press Alt-Shift-W and the output of who will be displayed and the prompt will be re-issued with your partial command intact and the cursor in the same position in the line.

Unfortunately, this doesn't work properly for keys such as F12 which output more than two characters. In some cases this can be worked around.

The command (who in this case) could be any executable - a program, script or function.

Pilocarpine answered 17/11, 2010 at 3:42 Comment(13)
What if i want to add a binding to "ctrl+q"?Nahamas
@kubudi: bind '"\C-q": menu-complete' for example (or in your ~/.inputrc: "\C-q": menu-complete). You may also need stty -ixon in your ~/.bashrc to disable flow control and make ^S and ^Q available.Pilocarpine
You say that ^[ represents esc and then you seem to substitute it for \e in your example. Could you explain why please?Alamein
@Remover: The ^[ is the output representation. The \e is one way to enter it (^[ doesn't work for that).Pilocarpine
How can I bind "\C-z"? I'd love to get something like what's described for zsh on sheerun.net/2014/03/21/how-to-boost-your-vim-productivityEade
How can I output (not bind) Ctrl-C (interrupt)? I tried doing bind '"\e[24~":"\C-cpwd\n"' but it just didn't do anything. My goal is, if I have something partially typed, and I press F12, the partially typed command is ^Ced and the pwd command is executed. That way while the partial command is not executed, it remains on the screen (for my reference). I can do this manually, but I want to do it as bind output for the F12 key.Radie
BTW, it's ~/.inputrc not ~/inputrc. After seeing the answer I created the file without the . and was wondering why it doesn't work.Radie
@ADTC: I fixed the typo in my answer, thanks. One way to do something like what you're trying to do would be to do bind '"^[[24~":"\C-apwd #\n"'. This inserts pwd and a space and a comment character at the beginning of the line which changes your partially typed command into a comment. Similarly, bind '"^[[24~":"\e#pwd\n"' which makes the partially typed command a comment on its own line and the pwd executed at a prompt of its own. If you ask this as a separate question and include what you're trying to accomplish, I can post an example that would allow you to do the pwd without...Pilocarpine
@DennisWilliamson Thanks! These options to comment the current line are good enough for what I need :) I think I'll prefer the second variant. Oh, maybe you can add them both to your answer :)Radie
@DennisWilliamson "Unfortunately, this doesn't work properly for keys such as F12 which output more than two characters. In some cases this can be worked around." Interesting, in my case bind -x '"\e[24~":"who"' worked with no difficulty or modification. (Readline 6.3, bash 4.3.11(1).)Muck
Here is documentation about key binding in GNU readline: tiswww.cwru.edu/php/chet/readline/rluserman.htmlSealer
How can I use this for more complex commands? For instance, I am trying to create a keybinding that will extract a ticket number from my current git branch and paste it. I'm trying: bind -x '"\eb":"git branch --show-current | egrep -o 'ABC-\d+'"'. However, this doesn't work because of the quotes around the regular expression. Anyway around this?Grammer
@user1427380: There are two solutions: 1) if you define the binding in your ~/.inputrc file you only enter the key and command, each in double quotes without the outer single quotes (or the command and option); 2) you can use escapes for the inner single quotes in the command form, unfortunately it's ugly: bind -x '"\eb":"git branch --show-current | egrep -o '\''ABC-\d+'\''"'Pilocarpine
S
22

You can define bash key bindings in ~/.inputrc (configuration file for the GNU Readline library). The syntax is

<keysym or key name>: macro

for example:

Control-o: "> output"

will create a macro which inserts "> output" when you press ControlO

 "\e[11~": "echo foobar"

will create a macro which inserts "echo foobar" when you press F1... I don't know what the keysym for F11 is off hand.

Edit:

.inputrc understands the \n escape sequence for linefeed, so you can use

 "\e[11~": "echo foobar\n"

Which will effectively 'press enter' after the command is issued.

Stephniestepladder answered 17/11, 2010 at 3:14 Comment(7)
you can use "\n" within a macro, to add a newline character:Stephniestepladder
This works better for me as it defines the key mapping on opening a terminal.Stick
For Alt, use \e, e.g. "\eo": "> output".Torietorii
For a more in-depth tutorial on using .inputrc see hackaday.com/2018/01/19/linux-fu-custom-bash-command-completionInspiration
Where can I find .inputrc file?Giacopo
@ArthurHenriqueDellaFraga I've edited the answer; it will be in your home directory. If it doesn't exist, you can create it.Stephniestepladder
I made a related question in head to keep looking about learn more from this subjectGiacopo
V
7

This solution is specific to X11 environments and has nothing to do with bash, but adding the following to your .Xmodmaps

 % loadkeys
 keycode 88 = F12
 string F12 = "foobar"
 %

will send the string "foobar" to the terminal upon hitting F12.

Vermination answered 17/11, 2010 at 1:59 Comment(2)
Keep in mind that this isn't the same as the shell running a command. If you actually want to run a command, you'll have have to hit enter (or have the string sent do that for you). Probably also want to be safe and clear the line first.Dotted
This would be awesome, but it doesn't seem to work as of Fedora 20 anyway. I even tried using xev to find the proper keycode for F12 first (in my case, 96) and using it instead of 88. Neither one works.Gibbet
T
4

I wanted to bind Ctrl+B to a command. Inspired by an answer above, I tried to use bind but could not figure out what series of cryptic squiggles (\e[24~ ?) translate to Ctrl+B.

On a Mac, go to Settings of the Terminal app, Profiles -> Keyboard -> + then press the keyboard shortcut you're after and it comes out. For me Ctrl+B resulted in \002 which i successfully bound to command

bind '"\002":"echo command"'

Also, if you want the command to be executed right-away (not just inserted in to the prompt), you can add the Enter to the end of your command, like so:

bind '"\002":"echo command\015"'

Try answered 20/7, 2018 at 9:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.