List Bash "Bind -X" Bindings

Key binding to go up by one directory (in Bash)

You can do that.
It's not as elegant or straight forward as with zsh but it's doable in bash using bind.

You can not only bind built in Readline functions (listed with bind -l) but other macros and shell functions too.

bind -m emacs -x '"\C-i":"cd .."' will bind a shell command (cd ..) to the keys (Ctrl+i) in emacs mode (the default mode). (Ctrl+i is unbound by default, u isn't)

Note that your prompt will probably not reflect the change.

If you leave out -x the string will instead be typed out for you so "cd ..\n" achieves the same result.

Edit: bind is how you bind keys and macros can accomplish what you want even though no built in thing exists.

If you end your PS1 prompt with \033[K (erase to eol) and can use
bind -m emacs '"\C-i":" cd ..&&echo -e \"\\033[2A\"\n"' to do what you want.
This will first print cd .. then control chars to move the cursor up and run it (with \n).
The end of your PS1 prevents it from showing. This is a hack but it shows that it's doable.

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

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.

Complex keybinding in bash

The trick to this is to call functions which rebinds your keys. In my example I'll use C-b to insert text and to call menu-complete, instead of C-x. You'll have to sacrifice a key, in my example C-t

In .bashrc, or a bash file to be sourced

set_Cb_to_insert_text() {
bind '"\C-m": accept-line'
bind '"\C-b":"ls \C-t1"'
bind -x '"\C-t1":set_Cb_to_complete'
}
set_Cb_to_complete() {
bind '"\C-m":"\C-t2\C-t3"'
bind '"\C-b": menu-complete'
bind '"\C-t2": accept-line'
bind -x '"\C-t3":set_Cb_to_insert_text'
}
set_Cb_to_insert_text

How this works:

With bind, you can bind keys to do one of three things, but no combination of them:

  • Execute a readline command: bind '"key": command'
  • Execute a series of keystrokes: bind '"key":"keystrokes"'
  • Execute a shell command: bind -x '"key": shell-command'

So if you want to combine these three things, you'll need to bind them each to a separate combination of keystrokes (in my example C-t{1,2,3}) and bind a key to execute all these keystrokes.

In the example:

C-b first inserts ls and 'presses' C-t1, which executes set_Cb_to_complete, which in turn rebinds C-b to menu-complete. It also rebinds C-m, carriage return, or Enter, because it now needs to do two things: Accept the line, and reset C-b to insert ls, by calling the set_Cb_to_insert_text function, which also resets Enter to it's normal use.

The reason I said that C-t had to be "sacrificed", is that if you press C-t, readline will wait to see if you are going to press 1, or 2, or any of the bound key sequences, before it takes any action. But when you first have put C-t to this use, you can use it as an initial key for a huge amount of keystrokes to cover all your readline trickery.

Piece of advice: While you are writing and testing these, bind an alternate key to accept-line, because suddenly something breaks the chain at the wrong place, and you are stuck in a terminal without a way to execute commands :)

In a bash script, how can I bind a key to a function?

Key bindings using bind only affect the interactive text input (the readline library). When running a program (even a built-in while) the terminal is switched to standard "cooked" mode and input is given to the currently running program (in this case, sleep would receive the input).

You can read the keys manually:

read -N 1 input

echo "Read '$input'"

However, if you want to run the while loop and read input at the same time, you will have to do it in separate processes (bash does not support threads). Since variables are local to a process, the end result will have to be fairly complicated.

Bash bind command

Have you tried this?

bind '"R":self-insert'

or this, if you can't type "R":

bind '"'`echo -e '\x52'`'":self-insert'

How to make bash's bind commands completely invisible?

This should work for you:

stty susp undef
bind -x '"\C-z":"fg >/dev/null 2>&1"'

Keep in mind though that this might not be such a good idea, since it'll prevent you from suspending most other programs.



Related Topics



Leave a reply



Submit