Emacs: Interactive Abbrev in Shell

By Xah Lee. Date: . Last updated: .

Using Abbrev for Shell Commands

You can define abbrev for frequently used shell commands. For example, i type “3rs ” and it expands to

rsync -z -r -v -t --chmod=Dugo+x --chmod=ugo+r --delete --exclude='*~' --exclude='.bash_history' --exclude='logs/'  --rsh='ssh -l u89150' ~/web/ u89150@s72750.example.com:~/

〔►see Linux: Sync Files Across Machines: rsync Tutorial

Is emacs abbrev better than bash alias?

Emacs abbrev is better, because it expands to the full command. Full commands lets you see what you are actually doing, instead of short abbrev. You can also edit it if you want.

〔►see Emacs Abbrev Tutorial

What about using shell 【Ctrl+r】 backward search feature?

That's great, but for frequently used commands, alias or abbrev is better, because you get EXACTLY the command you want, less keystrokes, and no eye-balling, just muscle memory in typing keys.

With back search, you might have variations of long commands, and you have to eye-ball to be sure it's the command you want. Bash alias or emacs abbrev are muscle memory.

What's the advantage of using shell inside emacs?

Easier copy/paste, full editing power of emacs, no need to switch to terminal, automatic session log. 〔►see Emacs Inferior Shell vs Terminal: What's the advantage of running shell inside emacs?

Interactive Abbrev in Shell!

You can make abbrev to use ido interface. Interactive abbrev.

emacs shell commands abbrev
Shell commands abbrev with ido selection interface. xah-shell-commands.

I have many many shell command abbrevs. For example, these are related to editing image files:

("3im" "convert -quality 85% ")
("3ims" "convert -size  -quality 85% ")
("3im256" "convert +dither -colors 256 ")
("3imf" "find . -name \"*png\" | xargs -l -i basename \"{}\" \".png\" | xargs -l -i  convert -quality 85% \"{}.png\" \"{}.jpg\"")

the problem is, i forgot some of the less used abbrev. So, i have to open my abbrev file to see. 〔►see Emacs: Hotkey to Open File Fast

wouldn't it be great, if all your abbrevs have a ido-like interface that lists all abbrevs? and that you can see them as you type? 〔►see Emacs: Switch Buffer

So, here's a command for interactive abbrev:

(defcustom xah-shell-abbrev-alist nil "alist of xah's shell abbrevs")

(setq xah-shell-abbrev-alist
        ("rsync1" . "rsync -z -r -v -t --chmod=Dugo+x --chmod=ugo+r --delete --exclude='*~' --exclude='.bash_history' --exclude='logs/'  --rsh='ssh -l u80781' ~/web/ u80781@s30097.example.com:~/")

        ("ssh" . "ssh -l u80781 xahlee.org ")
        ("img1" . "convert -quality 85% ")
        ("imgScale" . "convert -scale 50% -quality 85% ")
        ("img256" . "convert +dither -colors 256 ")
        ("imgBatch" . "find . -name \"*png\" | xargs -l -i basename \"{}\" \".png\" | xargs -l -i  convert -quality 85% \"{}.png\" \"{}.jpg\"")
        ("img-bmp2png" . "find . -name \"*bmp\" | xargs -l -i basename \"{}\" \".bmp\" | xargs -l -i  convert \"{}.bmp\" \"{}.png\"")

        ("grep" . "grep -r -F 'xxx' --include='*html' ~/web")

        ("rm empty" . "find . -type f -empty")
        ("chmod file" . "find . -type f -exec chmod 644 {} ';'")
        ("rm~" . "find . -name \"*~\" -exec rm {} ';'")
        ("findEmptyDir" . "find . -depth -empty -type d")
        ("rmEmptyDir" . "find . -depth -empty -type d -exec rmdir {} ';'")
        ("chmod2" . "find . -type d -exec chmod 755 {} ';'")
        ("lynx" . "lynx -dump -assume_local_charset=utf-8 -display_charset=utf-8 -width=100")
        ("vp" . "feh --randomize --recursive --auto-zoom --action \"gvfs-trash '%f'\" --geometry 1600x1000 ~/Pictures/ &")))

(defun xah-shell-commands (*cmd-abbrev)
  "insert shell command from a list of abbrevs.

URL `http://ergoemacs.org/misc/emacs_abbrev_shell_elisp.html'
version 2015-02-05"
    (ido-completing-read "shell abbrevs:" (mapcar (lambda (x) (car x)) xah-shell-abbrev-alist) "PREDICATE" "REQUIRE-MATCH")))
    (insert (cdr (assoc *cmd-abbrev xah-shell-abbrev-alist)))))

i give a easy key for this command. 〔►see Emacs: How to Define Keys〕 When i need a shell command, i press a key, a list comes up showing me all the abbrevs. Then, i type 2 or more keys and press Enter ↵ and my command is inserted.

One thing nice is that you can name your abbrev to be unique (such as adding a digit 1 to 9 in abbrev name), so that, calling a interactive abbrev is about 3 key press of muscle memory, and you can do it blind. For example, on my setup, i press 【▤ Menu b 1 Enter ↵】 (5 key strokes) and a long rysinc command is inserted. Compare this to using emacs abbrev, if your abbrev is “rsync1”, that's 6 key strokes. Similarly for shell alias.

The interactive abbrev system has these advantages:

be warned, that this will take some used to. Like keybinding, you have to kick habit, and that may not be easy.

Like it? Buy Xah Emacs Tutorial.

or, buy something from Best Keyboard for Emacs