Bash Shell History – How to Record Wildcard Expansions

bashcommand historyshellwildcardszsh

If I run:

$ ls *
foo bar buzz
$ history | tail -1
ls *

You can see that in my shell history it remembers that I ran ls * rather than ls foo bar buzz. Ideally, I'd like to record both in separate histories. When I wonder, "what the heck happened to file foo?", it would be nice to be able to have a way to go back and figure out that I did rm * in the wrong directory by searching through my history and finding 'foo'.

I'm interested in solutions for both zsh and bash.

Best Answer

I don't think any shell does anything beyond whitespace munging when storing commands into the history. What * expanded to is not recorded, and there doesn't seem to be an option to record it.

Note that it would not be possible to record in full generality anyway. For example, if you run a='foo* bar*'; rm $a (rm $=~a in zsh), the shell is unlikely to detect the wildcard match syntactically. And there's no option to log all glob expansions.

You could cobble something together with preexec (or the bash equivalent). Untested first go (for zsh):

history_wildcards=()
precmd () {
  emulate -LR zsh
  local n tmp
  history -1 | read n tmp
  history_wildcards[$(($n+1))]=$=~1
}

This fills the history_wildcards array to a string with the glob expansion of each word in the command line. Word splitting is performed in the naive way, so something like echo ' /**/* ' will expand /**/* (i.e. traverse your disk). Don't expect anything useful from cd subdir && echo * or anything so mind-bogglingly nontrivial.

If you plan beforehand, you can make zsh expand the wildcards before you submit the command. In the default configuration, just press Tab when your cursor is on the glob. If you've configured completion differently, try ^X * (expand-word).