7

I want to get the expansion of an alias.

For example, if I have:

alias g=hub
alias cdh='cd $HOME'

I want to have:

expand_alias g == hub

expand_alias cdh == cd $HOME

The tricky thing is that the two shells have different output: bash:

$ alias g cdh
alias g='git'
alias cdh='cd $HOME'

zsh:

% alias g cdh
g=hub
cdh='cd $HOME'

Note no alias prefix and no quotes around hub.

8
  • 1
    So what exactly are you missing?
    – RudiC
    Aug 18, 2018 at 10:16
  • 2
    Note that the zsh output is the standard one. bash will give you that one as well when in POSIX mode. Aug 18, 2018 at 18:06
  • why are the single quotes a problem? Aug 19, 2018 at 6:04
  • @HennoBrandsma I want to define an alias based on the contents of an existing one.
    – Tom Hale
    Aug 19, 2018 at 7:03
  • 1
    Note that cd without arguments already brings you to $HOME Aug 20, 2018 at 15:56

5 Answers 5

9

In zsh, you can just use

get_alias() {
  printf '%s\n' $aliases[$1]
}

With bash (assuming it's not in POSIX mode in which case its alias would give an output similar to zsh's), you could do:

get_alias() (
  eval '
    alias() { printf "%s\n" "${1#*=}"; }'"
    $(alias -- "$1")"
)

Basically, we evaluate the output of alias after having redefined alias as a function that prints what's on the right of the first = in its first argument.

You could use a similar approach for something compatible with most POSIX shells, zsh and bash:

get_alias() {
  eval "set -- $(alias -- "$1")"
  eval 'printf "%s\n" "${'"$#"'#*=}"'
}
2
  • I wondered why parentheses are used instead of the usual braces... a function body can be a single statement, and in this case that's a subshell.
    – Tom Hale
    Aug 19, 2018 at 5:50
  • 1
    @TomHale, that's to limit the scope of that alias function we declare. Aug 19, 2018 at 6:35
3

Based on Stéphane Chazelas' answer, I came up with:

function alias_expand {
  if [[ $ZSH_VERSION ]]; then
    # shellcheck disable=2154  # aliases referenced but not assigned
    [ ${aliases[$1]+x} ] && printf '%s\n' "${aliases[$1]}" && return
  else  # bash
    [ "${BASH_ALIASES[$1]+x}" ] && printf '%s\n' "${BASH_ALIASES[$1]}" && return
  fi
  false  # Error: alias not defined
}

(with bash 4.0 or newer).

2
  • 1
    function force-expand { local e="$(expand_alias "$1")" ; test -z "$e" && e="$1" ; echo "$e" }
    – HappyFace
    Jun 19, 2019 at 13:28
  • @HappyFace Cheers for pointing out the issue with the return value. Answer updated.
    – Tom Hale
    Aug 10, 2020 at 11:07
0

How about defining a shell function:

EXA() { alias $@ | sed 's/^/expand_/; s/=/ == /; s/\o047//g; '; }
5
  • Syntax error when I copy and paste
    – Tom Hale
    Aug 19, 2018 at 5:12
  • show the syntax error.
    – RudiC
    Aug 19, 2018 at 6:48
  • unmatched '. How will this remove single quotes?
    – Tom Hale
    Aug 19, 2018 at 8:34
  • Rats! Corrected typo...
    – RudiC
    Aug 19, 2018 at 10:57
  • Breaks with: alias ls='colourify ls -CF --block-size=\'\''1 --color=always --quoting-style=shell-escape'
    – Tom Hale
    Aug 22, 2018 at 8:23
0

My zsh had this bound to a key combo:

_expand_alias () {
    local word expl tmp pre sel what
    local -a tmpa suf
    eval "$_comp_setup"
    if [[ -n $funcstack[2] ]]
    then
        if [[ "$funcstack[2]" = _prefix ]]
        then
            word="$IPREFIX$PREFIX$SUFFIX"
        else
            word="$IPREFIX$PREFIX$SUFFIX$ISUFFIX"
        fi
        pre=()
    else
        local curcontext="$curcontext"
        if [[ -z "$curcontext" ]]
        then
            curcontext="expand-alias-word:::"
        else
            curcontext="expand-alias-word:${curcontext#*:}"
        fi
        word="$IPREFIX$PREFIX$SUFFIX$ISUFFIX"
        pre=(_main_complete - aliases)
    fi
    zstyle -s ":completion:${curcontext}:" regular tmp || tmp=yes
    case $tmp in
        (always) sel=r  ;;
        (yes | 1 | true | on) [[ CURRENT -eq 1 ]] && sel=r  ;;
    esac
    zstyle -T ":completion:${curcontext}:" global && sel="g$sel"
    zstyle -t ":completion:${curcontext}:" disabled && sel="${sel}${(U)sel}"
    tmp=
    [[ $sel = *r* ]] && tmp=$aliases[$word]
    [[ -z $tmp && $sel = *g* ]] && tmp=$galiases[$word]
    [[ -z $tmp && $sel = *R* ]] && tmp=$dis_aliases[$word]
    [[ -z $tmp && $sel = *G* ]] && tmp=$dis_galiases[$word]
    if [[ -n $tmp ]]
    then
        tmp=${tmp%%[[:blank:]]##}
        if [[ $tmp[1] = [[:alnum:]_] ]]
        then
            tmpa=(${(z)tmp})
            if [[ $tmpa[1] = $word && $tmp = $aliases[$word] ]]
            then
                tmp="\\$tmp"
            fi
        fi
        zstyle -T ":completion:${curcontext}:" add-space || suf=(-S '')
        $pre _wanted aliases expl alias compadd -UQ "$suf[@]" -- ${tmp%%[[:blank:]]##}
    elif (( $#pre )) && zstyle -t ":completion:${curcontext}:" complete
    then
        $pre _aliases -s "$sel" -S ''
    else
        return 1
    fi
}
0

In my zsh environment, when I type alias with no command I get on stdout a list of all aliases. The same happens in bash (on MacOS both). These are in a form alias=expansion

So you could filter further with sed: alias | sed -ne 's/cdh=\(.*\)$/\1/p' if "cdh" is the alias you want to know. You could make a shell function in your profile for this, if this is a common task for you: like

expand_alias() { alias $@ | sed -ne 's/^'$@'=\(.*\)$/\1/p' }
4
  • This leaves the single quotes in. Please re-read the question.
    – Tom Hale
    Aug 19, 2018 at 5:10
  • @TomHale Inthe OP's example, it's not quite clear to me why the single quotes are a problem. They don't hurt for single commands, or one word substitutions; they are needed for commands with spaces. So that's why I left in the spaces, as I don't want to complicate things by adding logic to remove unnecessary single quotes. If they always have to go, just add ` | tr -d \' ` to the pipe. Aug 19, 2018 at 6:04
  • Fair enough assumption. I can't upvote you again now. The | tr wouldn't allow for a ' in the middle of an alias though.
    – Tom Hale
    Aug 19, 2018 at 7:06
  • this does not work as intended if there are = inside the alias. I will edit the answer with a fix for this :) Oct 14, 2021 at 13:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.