Resolve all aliases in a zsh command line

aliaszsh

I have nested aliases and I want to resolve all of them before executing the command. How do I do that?

If there is a function that is not bound to any keys then M-x foobar is fine for me too. I could even use external command (type, command, which, whatever). I tried everything from the thread Why not use "which"? What to use then? but nothing works.

Best Answer

Note that Ctrl-Alt-E in bash does not only expand aliases. It also expands variables, command substitution (!), process substitution (!), arithmetic expand and removes quotes (it doesn't do filename generation (globbing) or tilde expansion).

It doesn't always manage to expand aliases. So while it has its uses, it's important to realise its outcome potentially changes the meaning of the command line, has side effects and is potentially dangerous.

For instance in:

$ a=';w' b=1
$ alias foo=bar
$ b=2; echo $b $a; cd /tmp/dir && for i do foo $(pwd) <(ls); done

If I press M-C-E here, that gives me:

$ b=2; echo 1 ;w; cd /tmp/dir && for i do foo / /dev/fd/63; done

Which gives me a completely different command line altogether (and imagine what would have happened if I had had rm -rf * instead of pwd above) and doesn't expand the foo alias.

With zsh, to build up on Gilles' note on aliases expanded inside functions, you could do:

expand-aliases() {
  unset 'functions[_expand-aliases]'
  functions[_expand-aliases]=$BUFFER
  (($+functions[_expand-aliases])) &&
    BUFFER=${functions[_expand-aliases]#$'\t'} &&
    CURSOR=$#BUFFER
}

zle -N expand-aliases
bindkey '\e^E' expand-aliases

That will expand the aliases only if the current command line is syntactically valid (so it doubles as a syntax checker).

Contrary to bash's M-C-E, it also resolves the aliases fully. For instance if you have:

$ alias ll='ls -l'; alias ls='ls --color'
$ ll

Will be expanded to:

$ ls --color -l

Note that it also canonicalises the syntax so things like:

$ for i (*) cmd $i; foo

will be changed to:

$ for i in *
        do
                cmd $i
        done
        foo
Related Question