Search code examples
command-linezshzshrc

Echo all aliases in zsh


Is it possible to force zsh to echo the actual commands referred to by all aliases when they are used?

For example, say that I have the following aliases set:

# List direcory contents
alias lsa='ls -lah'
alias l='ls -la'
alias ll='ls -l'

When I execute them I would like to see each of them print the actual command that's executed. For example, I would like to see the following:

$ ll
executing: 'ls -l'
total 0
-rw-r--r--  1 person  staff  0 Feb 15 13:46 cool.txt
-rw-r--r--  1 person  staff  0 Feb 15 13:46 sweet.html
-rw-r--r--  1 person  staff  0 Feb 15 13:46 test.md

Rather than the following:

$ ll
total 0
-rw-r--r--  1 person  staff  0 Feb 15 13:46 cool.txt
-rw-r--r--  1 person  staff  0 Feb 15 13:46 sweet.html
-rw-r--r--  1 person  staff  0 Feb 15 13:46 test.md

Is there one command that I can add to my zshrc to get this to happen for all aliases? I would prefer not to have to modify every alias.


Solution

  • If you are fine with having aliases displayed if alias is the first word present on the command-line you can try to put the following code into your .zshrc:

    _-accept-line () {
        emulate -L zsh
        local -a WORDS
        WORDS=( ${(z)BUFFER} )
        # Unfortunately ${${(z)BUFFER}[1]} works only for at least two words,
        # thus I had to use additional variable WORDS here.
        local -r FIRSTWORD=${WORDS[1]}
        local -r GREEN=$'\e[32m' RESET_COLORS=$'\e[0m'
        [[ "$(whence -w $FIRSTWORD 2>/dev/null)" == "${FIRSTWORD}: alias" ]] &&
            echo -nE $'\n'"${GREEN}Executing $(whence $FIRSTWORD)${RESET_COLORS}"
        zle .accept-line
    }
    zle -N accept-line _-accept-line
    

    Description (some trivial things skipped):

    emulate -L zsh # Reset some options to zsh defaults (locally).
                   # Makes function immune to user setup.
    
    local -a WORDS # Declare WORDS as an array local to function
    
    ${(z)VARNAME}  # Split VARNAME using command-line parser.
                   # Things like “"first word" "second word"” get split into 2 words:
                   # “"first word"” “"second word"”
    
    $BUFFER        # Variable containing the whole command-line. Can be modified
    
    local -r V     # Declare variable “V” as read-only
    
    $'\e[32m'      # Escape code for green foreground color in most terminals
    $'\e[0m'       # Sequence that being echoed to terminal clears out color information
    
    whence -w cmd  # Display type of the command in format “cmd: type”
    whence cmd     # If “cmd” is an alias, then this command outputs alias value
    
    zle .accept-line # Call internal zle “accept-line” widget. This must be done or 
                   # every command will turn to no-op. You can, of course, replace
                   # this with “eval $BUFFER” but I can’t say what will break in this case
    
    zle -N accept-line _-accept-line # Associate widget “accept-line” with function
                   # “_-accept-line”. This makes this function responsible for accepting
                   # lines.
    

    More info in man zshbuiltins (emulate, whence, local), man zshzle (zle, $BUFFER), man zshparam (${(z)}).