* Multiline Command Editing With Support In Keybindings And History File Format

For me, the killer feature is multiline command editing. Sometimes there is a need to do an ad-hoc complex set of actions, and it's nice to keep everything together in 1 command you can incrementally test and develop. Note, I'm not talking about hitting enter on an incomplete command and getting a PS2 prompt. That sucks because each of those lines is separate in the history, and you have to navigate for each line in turn when you want to reuse it. I'm talking about multiline commands that stay as one in the history and are comfortably editable on the command line. Here is an example with my prompt:

/ 2018.04.30 16:06:50
| 0 - !71361 - %0 - jol@vento - ~some_project
for ip in 10.1.{1..10}0.5; do
ssh some_user@$ip '
cp things places
ed files << EOF
i
things
.
/others/d
w
EOF
# other tedious stuff
'
done
\ 2018.04.30 16:10:42
output if there's any
/ 2018.04.30 16:10:42
| 0 - !71362 - %0 - jol@vento - ~some_project

It's got vi keybindings that are meant for multiple lines like 'o' inserts a new line below, 'O' inserts a new line above, 'dd' deletes a line, etc. You can kind of do the same in bash, by pressing Ctrl-V Ctrl-J you can insert a newline and continue editing, but pressing up/down (or j/k if on vi keybindings) won't move between the lines, but rather navigates the history. Vi keybindings in bash don't implement those that are meant for multiline editing. Also the history format for bash doesn't seem to support multiline commands. If I make one and get the last command from history, it's all been joined in one line. bash will even insert ';' where needed to replace the newlines.

* Temporary Regular File `=(cmd)` Process Substitution

Both bash and zsh have process substitution of the form `<(cmd)` and `>(cmd)`, which substitute themselves with the path of a named pipe to communicate with the subprocess that runs concurrently. However, zsh additionally has `=()` which is a subprocess that runs before the substitution and whose output is collected in a temporary regular file which path is substituted in place after it finishes, and destroys it when the process which received the path dies. This is really useful for programs that need more than one pass when reading the file. I've used it, for example on `viewnior =(maim -s)` to display in an image viewer the window that I select with the mouse.

* Very Feature-Rich Extended Glob

I know bash has extended globs too, but I don't know how they compare. Here is something I found in my history for a yesod project:

printf "%s\n" **/^(.*|*[~#])~(front-end|config|dist|yesod-devel|static)*(.oe[REPLY=\${REPLY:#*/*}]on)

I can't remember exactly what I was looking for when I did this, but this lists all regular files (not directories or symlinks, etc.) under a tree that do not begin in '.' or end in a '~' or '#' and that are not part of the top-level directories front-end, config, etc. ordered first by being under another directory (not top-level from the search; so I'd get top-level files at the end) and then by name.

A more common glob that I do is '* (oc[1])' to get the newest file in a directory or '* (oc[1,5])' to get the newest 5 or so. Neither should have a space between the asterisk and the brace, I added so HN would not turn it into italics.

* Timestamps In History File

Now that I mentioned the history, I notice that zsh has each command time-stamped in the history file while bash does not. I remember using this before to look for a command I remember doing in a time-range of a month of so years back from then.

* By Default Enabled Terminal Paste Protection By Bracket Escape Sequences

By default if you paste stuff in a terminal with bash and it contains, for example, newlines, it will execute it. zsh on the other hand will put everything as a multiline command and wait for you to hit Enter, allowing you to edit, before executing. There's been times when I've accidently pasted paragraphs of text and this saved me from executing who knows what. If you use a terminal that asides from bracketing pastes in a special escape sequence, also ensures that what you paste cannot include the closing bracket by e.g. filtering it out, then you can paste code from the browser directly without worries of css or javascript shenanigans causing you to run hidden code without seeing it first. I wrote an SE answer showing how to configure urxvt for that once:

https://security.stackexchange.com/questions/39118/how-can-i...

* Short-hand compound statements

You can for example skip the do-done in a for loop and the then-fi in an if conditional if you only got one command to run:

for p in *; if [[ $p == *-yesod ]] echo "==$p" && git -C "$p" remote -v

* Dynamic directories

I can't find support for this in bash. Basically, you can extend the use of '~' to not only be shortcuts to home directories, but also directories of your chosing as if they were bookmarks. For example, say I have my software projects in directories like ~/work-for/client/some_client/some_project, I can refer to it simply as ~some_project. The neat thing about this over, say, a simple variable is that file completion recognizes it and allows me to work with it without having to expand it.

* Others

I've also found use in anonymous functions, menu complete, and other stuff, but I think I've covered the most important for me.