The scenario is currently, I have defined some aliases in .zshrc
like
alias gco='git checkout'
alias cdp='cd ..'
and lots like that. My question is How to print out the command each time I typed an alias and press enter?
ex:
$> gco master
> Command: git checkout master
> Git process ...
something like that, if the solution also works in bash would be better! Thanks!
This is a neat question. We can do it by defining a couple of functions to expand out the aliases, and then use a preexec
hook to run the functions before we execute them.
I've taken the answer from here.
_aliases="$(alias -Lr 2>/dev/null || alias)"
alias_for() {
[[ $1 =~ '[[:punct:]]' ]] && return
local found="$( echo "$_aliases" | sed -nE "/^alias ${1}='?(.+)/s//\\1/p" )"
[[ -n $found ]] && echo "${found%\'}"
}
First, store all aliases in a variable. alias -r
prints all the regular
aliases (not global or suffix), and alias -L
prints them "in a manner suitable for use in startup scripts".
The alias_for()
function does some cleaning, removing quotes and putting alias
in front of the lines. When we do echo ${_aliases}
, we get something like this:
alias history='fc -l 1'
alias ls='ls -F -G'
alias lsdf='ls -1l ~/.*(@)'
alias mv='mv -v'
Compare this to the output of alias
:
history='fc -l 1'
ls='ls -F -G'
lsdf='ls -1l ~/.*(@)'
mv='mv -v'
If there was an alias entered, we can now detect it, and thus print it:
expand_command_line() {
[[ $# -eq 0 ]] && return # If there's no input, return. Else...
local found_alias="$(alias_for $1)" # Check if there's an alias for the comand.
if [[ -n $found_alias ]]; then # If there was
echo ${found_alias} # Print it.
fi
}
The preexec
function is perfect for this. It's a function that is:
Executed just after a command has been read and is about to be executed. If the history mechanism is active (and the line was not discarded from the history buffer), the string that the user typed is passed as the first argument, otherwise it is an empty string. The actual command that will be executed (including expanded aliases) is passed in two different forms: the second argument is a single-line, size-limited version of the command (with things like function bodies elided); the third argument contains the full text that is being executed.
from the zsh Manual, chapter 9.
Note, we could probably just use the preeexec function to display what's being run.
To add our function to the preexec, we use a hook using this example:
autoload -U add-zsh-hook # Load the zsh hook module.
add-zsh-hook preexec expand_command_line # Adds the hook
To remove the hook later, we can use:
# add-zsh-hook -d preexec expand_command_line # Remove it for this hook.
This is what my shell looks like when I run it:
$ 1
cd -
$ rake
bundle exec rake
^C
$ chmod
usage: chmod [-fhv] [-R [-H | -L | -P]] [-a | +a | =a [i][# [ n]]] mode|entry file ...
chmod [-fhv] [-R [-H | -L | -P]] [-E | -C | -N | -i | -I] file ...
$ git lg1
fatal: Not a git repository (or any of the parent directories): .git
As we can see from my shell example, when a command that is not aliased is run (like chmod
), the full command is not displayed. When an aliased command (like 1
or rake
) is run, the full command is displayed.
When a git
alias is run (git lg1
, for example), the git
alias is not expanded. If you look at my first link, the full example there does use git
alias expansion - you should take that and modify if git aliases are vital to you.