Bind makes bash faster
bind
is a bash builtin used for displaying and setting readline mappings.
simple use
With it you can map keys like:
bind '"\C-gr": "ssh remote@192.168.1.102"'
This will type into your terminal ssh remote@192.168.1.102
whenever you type Ctrl-g+r. If you want it to execute immedietly after typing just use
bind '"\C-gr": "ssh remote@192.168.1.102\n"'
If you won't quote the second part it will be treated as readline command or function.
bind '",": print-last-kbd-macro'
key syntax
Mapped keys can have special keys like \C-'",e": "echo "'
, '"\C-xC-b": "vim ~/.bashrc\n"'
, '"\e\C-t": "transmission-remote -l"'
(Ctrl-Alt-t).
If you type keys partially and wait over 500ms or type one wrong character the mapping will be ignored and previously typed keys will be typed to the terminal normally. This can be used to define mapping based on normal characters that are not common like ,
you can create many easy to type bindings for common commands like ",t": "transmission-remote -l\n"
with practically no cost.
Even if characters used are not rare they might be an easy to type gibberish like "cPp": "cd $PROJECTS/python\n"
which you won't have to even worry about when typing as you just never type such things normally, and when you do you can just wait a little.
Above that you can use
set keyseq-timeout 500
in your ~/.inputrc
to change key sequence timeout (in miliseconds) to your preference.
Finding other special keys
If you want to use functional keys like F11
you can press Ctrl-v + F11
which will give you ^[[23~
and this sequence can be used directly as part of a key.
Ctrl-v + Del -> ^[[P
Ctrl-v + Ctrl-F11 -> ^[[23;2~
Ctrl-v + Ctrl-a -> ^A
Ctrl-v + Alt-a -> ^[a
Ctrl-v + a -> a
-x
This option specifies command to be executed, contrary to previous examples this option makes binded value executed as a command and it's not just typed.
Current path and previously typed keys will not be affected nor will be the cursor position.
Executed command isn't saved to history, and is working in current session so all functions and variables defined are available, also all changes to them are saved.
For example
bind -x '"\C-gm": exit'
will exit the current shell.
-x '"\C-gm": "cd /; ls"'
will not change current directory but will print ls
at /.
-x '"\C-gm": "x=2"'
will set x
to 2 without any visible changes in the terminal.
This option works great for seamlessly opening files, opening your file manager or listing information while writing commands.
It can also be used for avoiding of adding your bindings to history.
This option also sets some special variables, more on in copying current/last command.
main key
Assuming you use the default emacs style keybinding you really don't have much space to add your own Ctrl bindings without changing everything or mapping everything with Ctrl+Alt.
But there exists a key binding that serves no purpose and that's \C-g
which is binded to abort
. When was the last time that you have used this? Were you even aware of it's existance? The only time i've used it was to cancel the \C-r
history search, and even after remapping it seems to be working for that.
g
is in the middle of the keyboard so it's a very accessible key and I encourage you to use it similar to vim leader
key.
You could go with the ,
as the leader but why not both.
removing key bindings
If you want to change default key binding you can use the -r
option
bind -r '\C-y'
This will delete all mapping to \C-y
listing your mappings
Bind has a lot of options but 80% of them is just for listing currently set mappings.
-l
all of readline functions.
-P
same as previous but with their binded keys.
-p
same as previous but can be used as input for .inputrc
.
-S
key sequences bound to macros (things you set).
-s
same as previous but can be used as input for .inputrc
.
-V
readline variable names and their values.
-v
same as previous but can be used as input for .inputrc
.
-X
everything set with -x
option.
-f FILENAME
exports all set things for .inputrc
.
my bindings
I hope you'll find inspiration in here.
quick moving between directories and opening files
fcd() { jaP="$(find "$1" -type d | fzf)"; [ -n "$jaP" ] && cd "$jaP"; }
frf() { t="$1"; shift; jaP="$(find -type f | fzf)"; [ -n "$jaP" ] && "$@" "$jaP"; }
frd() { t="$1"; shift; jaP="$(find -type d | fzf)"; [ -n "$jaP" ] && "$@" "$jaP"; }
bind -x '"\C-gm": frf . mpv'
bind -x '"\C-gs": frd . sxiv -r'
bind -x '"\C-gz": frf . zathura'
bind -x '"\C-gU": frf . nvim'
bind '"\C-gc": "fcd .\n"'
It's better to define complex things in functions.
file manager switching
bind -x '"\C-gg": csas'
With this even if you are halfway in writing a complex line you can open your file manager and come back to the same state. I use csas but you can use ranger or lf.
bind -x '"\C-gg": ranger'
copying current/last command
This one is very useful and quite special. The -x
option sets additional variables about the current state of the edited line.
READLINE_ARGUMENT
holds argument to keys ( set with Alt-1
, ... , Alt-9
key binding).
READLINE_MARK
holds position of mark ( set with \C-@
key binding).
READLINE_LINE
holds edited line.
READLINE_POINT
holds position in edited line.
Changing any of them also changes state e.g.
bind -r '\C-a'
go_to_beginning() {
READLINE_POINT=0
}
bind -x '"\C-a": go_to_beginning'
This will completely emulate the default \C-a
mapping.
copylastcomm(){
if [ -n "$READLINE_LINE" ]
then
tr -d '\n' <<< "$READLINE_LINE" | xclip -sel clip
else
history 1 | sed 's/^ *[0-9]\+ *//;q' | tr -d '\n' | xclip -sel clip
fi
}
bind -x '"\C-g1": copylastcomm'
This wonderful shortcut copies current line if it's not empty, or last typed command into clipboard.
SSH/mounting directories
I have a convention of starting ssh connection with e
letter and mounting remote directories with E
(I have a lot of old computers).
bind '"\C-gem": "ssh maisto@192.168.1.103\n"'
bind '"\C-geM": "ssh maisto@192.168.1.59\n"'
bind '"\C-geu": "ssh natka@192.168.1.4\n"'
bind '"\C-gen": "ssh nanar@192.168.5.135\n"'
bind '"\C-gep": "ssh pi@rasp.ves\n"'
bind '"\C-geP": "ssh -p 7822 pi@127.0.0.1\n"'
bind '"\C-gea": "ssh -p 8022 192.168.34.155\n"'
bind '"\C-geA": "ssh -p 8022 192.168.1.37\n"'
bind '"\C-gec": "ssh -p 8022 192.168.5.68\n"'
bind '"\C-gel": "sshpass -p/6248 ssh user1@192.168.5.65\n"'
bind '"\C-gev": "ssh vereo@192.168.1.240\n"'
bind '"\C-gEm": "sshfs maisto@192.168.1.103:/home/maisto/"'
bind '"\C-gEkm": "sshfs maisto@192.168.1.103:/home/maisto/ktc1/ ~/ktc1/\n"'
bind '"\C-gEhm": "sshfs maisto@192.168.1.103:/home/maisto/hre/ ~/hre/\n"'
bind '"\C-gEzm": "sshfs maisto@192.168.1.103:/home/maisto/zeh/ ~/zeh/\n"'
bind '"\C-gEM": "sshfs maisto@192.168.1.103:/home/maisto/"'
bind '"\C-gEkM": "sshfs maisto@192.168.1.103:/home/maisto/ktc1/ ~/ktc1/\n"'
bind '"\C-gEhM": "sshfs maisto@192.168.1.103:/home/maisto/hre/ ~/hre/\n"'
bind '"\C-gEzM": "sshfs maisto@192.168.1.103:/home/maisto/zeh/ ~/zeh/\n"'
bind '"\C-gEv": "sshfs vereo@192.168.1.240:/home/vereo/ "'
torrents
This one quickly shows me the current state of my torrents
bind '"\C-gt": "transmission-remote -l\n"'
And this one calls my script for adding torrents on input from clipboard
bind '"\C-ga": "transadd \"$(xclip -o -sel clip)\"\n"'
screen/tmux
Allows for choice to which session to reattach
bind '"\C-gi": "screen -r "'
Starts new session
bind '"\C-gI": "screen\n"'
translation
I have an alias to translate-shell, I've stopped using these binding because i've made a better dmenu script.
bind '"\C-gTs": "trans -s spa -t en "'
bind '"\C-gTe": "trans -s en -t spa "'
editing files
I have convention of starting these with u
letter.
bind '"\C-gus": "$EDITOR ~/.config/sunt\n"'
bind '"\C-guu": "$EDITOR ~/.config/newsboat/urls\n"'
bind '"\C-gux": "$EDITOR ~/.config/Xresources\n"'
bind '"\C-gue": "$EDITOR $G/eng\n"'
bind '"\C-gug": "$EDITOR $G/g\n"'
bind '"\C-gul": "$EDITOR $G/linux\n"'
bind '"\C-guf": "$EDITOR $G/f\n"'
bind '"\C-gub": "$EDITOR ~/.bashrc\n"'
bind '"\C-guv": "$EDITOR ~/.config/vars\n"'
bind '"\C-gud": "$EDITOR ~/.config/dirshortcuts\n"'
bind '"\C-gun": "$EDITOR ~/.config/nvim/init.vim\n"'
bind '"\C-guN": "$EDITOR $G/notes\n"'
bind '"\C-guc": "$EDITOR ~/.config/csasrc\n"'
bind '"\C-gum": "$EDITOR $TO/magnets\n"'
bind '"\C-gup": "$EDITOR $PR/sh/pugna-arch\n"'
changing directory
I actually generate them automatically for bash and my file manager with a script.
bind '"\C-gh": "cd $HOME\n"'
#movies, shows, etc
bind '"\C-gff": "cd $FIL\n"'
bind '"\C-gfv": "cd $FILV\n"'
bind '"\C-gfs": "cd $FILS\n"'
bind '"\C-gfy": "cd $FILY\n"'
bind '"\C-gfc": "cd $FILC\n"'
bind '"\C-gfa": "cd $FILA\n"'
bind '"\C-gf0": "cd $FILY/000\n"'
#folder for archiving
bind '"\C-gC": "cd $CB\n"'
bind '"\C-gfFs": "cd $CB/fil/s\n"'
bind '"\C-gfFa": "cd $CB/fil/a\n"'
bind '"\C-gfFv": "cd $CB/fil/v\n"'
bind '"\C-gfFc": "cd $CB/fil/c\n"'
bind '"\C-gfm": "cd $MUSIC\n"'
bind '"\C-gfk": "cd $BOOKS\n"'
bind '"\C-gG": "cd $G\n"'
bind '"\C-gD": "cd $DOWNLOADS\n"'
bind '"\C-gFf": "cd $FILES\n"'
bind '"\C-gFF": "cd $FILES\n"'
bind '"\C-gFd": "cd $DATASETS\n"'
bind '"\C-gFx": "cd $XF\n"'
bind '"\C-gFi": "cd $IV\n"'
bind '"\C-gFm": "cd $FILES/mirrors\n"'
bind '"\C-gFs": "cd $FILES/shots\n"'
#projects
bind '"\C-gpp": "cd $PR\n"'
bind '"\C-gpa": "cd $PR/asm\n"'
bind '"\C-gpc": "cd $PR/c\n"'
bind '"\C-gpx": "cd $PR/c/x86_64\n"'
bind '"\C-gpm": "cd $PR/c/msp430\n"'
bind '"\C-gpq": "cd $PR/quickc\n"'
bind '"\C-gps": "cd $PR/sh\n"'
bind '"\C-gpP": "cd $PR/python\n"'
bind '"\C-gpj": "cd $PR/js\n"'
bind '"\C-gS": "cd $SYSISO\n"'
bind '"\C-gk": "cd $KPP\n"'
bind '"\C-gM": "cd $MEMES\n"'
bind '"\C-gdd": "cd $HOME/Downloads\n"'
#~/.local/bin - my script folder
bind '"\C-gL": "cd $LBIN\n"'
more about bind
If you want to learn about bind
in depth you can run info bash bind
or go to https://www.computerhope.com/unix/bash/bind.htm.
I also recommend reading about readline and looking at bash bindings with
info bash -n bind