12

In my .profile (sourced in sh emulation mode from my .zshrc) I have the following snippet:

if [ -f /usr/bin/pacmatic ]; then
    alias pacman=pacmatic
fi

# Colorized Pacman output
alias pacman="pacman --color auto"

However, the second alias always overrides the first:

% type pacman
pacman is an alias for pacman --color auto

How can I make it so that the second alias assignment "inherits" the first assignment, so that if /usr/bin/pacmatic exists, the alias becomes pacmatic --color auto?

I'm not averse to using functions instead of aliases, but I'd prefer it if the logic wasn't performed every time pacman is invoked (I want pacmatic checked for once, at shell startup, not every time pacman is run). I'd also prefer an sh-portable script, but if this isn't possible, you can use full zsh syntax.

(Yes, I'm aware that this could easily be solved by appending --color auto to the pacmatic alias. But I want to do it the Right Way™.)

I've tried Googling and looking through the manpages, but to no avail.

1
  • I thought the Right Way was to use functions instead of aliases. I've heard that they're faster than aliases (at least in bash), and they can easily call each other.
    – Wutaz
    Commented Apr 13, 2014 at 15:37

5 Answers 5

6

Alias substitution is only performed when reading lines from interactive sources. So the second alias is not affected by the first, hence the literal replacement.

Perhaps something similar:

PACMAN=pacman
if [ -f /usr/bin/pacmatic ]; then
    PACMAN=pacmatic
fi

# Colorized Pacman output
alias pacman="${PACMAN} --color auto"

This'll set 'pacman' to the proper value, the PACMAN env variable is not exported, so it'll go away when the script finishes, and using "double quotes" will ensure that variable substitution occurs at the declaration of the alias, not for each invocation.

I use a similar method:

PACMAN=pacman
which pacmatic &>/dev/null && PACMAN=pacmatic
alias pacman="${PACMAN} --color auto"

Basically, set the env var PACMAN, test for pacmatic in path, if found, set PACMAN, then define alias.

Hmm, you could optimize a bit more...

which pacmatic &>/dev/null && PACMAN=pacmatic
alias pacman="${PACMAN:-pacman} --color auto"

Taa Daa! Set to 'pacman' if PACMAN is unset or null, otherwise, set to value of PACMAN, set to pacmatic by the 'which' line.

2
  • Why would aliases only work for "interactive sources"?
    – Mikel
    Commented Apr 14, 2014 at 2:37
  • You're right that by default, bash doesn't expand aliases in non-interactive mode, but how is that the same as "interactive sources"?
    – Mikel
    Commented Apr 14, 2014 at 3:09
5

A shell alias behaves pretty similarly to a #define, i.e. redefining a shell alias would override the previous one.

I'm not sure what would be the Right WayTM, but one approach would be making use a shell function that accepts parameters and using that to create an alias. Your code snippet could be rewritten as:

if [ -f /usr/bin/pacmatic ]; then
    pacman() { pacmatic "$@"; }
fi

# Colorized Pacman output
alias pacman="pacman --color auto"

 


Moreover, even if you were using different aliases and were trying to use one for defining the other, it would not work as aliases are not expanded in non-interactive mode by default. You need to enable it by setting expand_aliases:

shopt -s expand_aliases

Quoting from the manual:

   Aliases are not expanded when the shell is not interactive, unless  the
   expand_aliases  shell option is set using shopt (see the description of
   shopt under SHELL BUILTIN COMMANDS below).
3
  • this appears to be the closest to what I want, but it doesn't work. type pacman returns pacman is an alias for pacman --color auto, both in sh emulation mode and in native zsh mode. however, looks like the edit you just made is what I need.
    – strugee
    Commented Apr 14, 2014 at 2:49
  • FWIW, the zsh equivalent is setopt aliases.
    – strugee
    Commented Apr 14, 2014 at 3:00
  • OP is using zsh. And the shell appears to be interactive anyway.
    – Mikel
    Commented Apr 14, 2014 at 19:15
2

In zsh, you can easily append to an alias by using the aliases associative array:

alias pacman="${aliases[pacman]-pacman} --color auto"

In other shells, you need to use the output of the alias command to find out about existing aliases.

current_pacman_alias=$(alias pacman 2>/dev/null)
alias pacman="${current_pacman_alias:-pacman} --color auto"

While I'm offering this as a possibility, I'd go with using a variable as already suggested by other answers. It's clearer, and you can discriminate on the value of the variable if you want to configure some things differently based on which one of pacmatic or pacman is in use.

pacman==pacmatic 2>/dev/null || pacman=pacman
alias pacman='$pacman --color auto'
0

A short version for the 2nd alias would be:

alias pacman=$PACMAN' --color auto'
0
pacman() ( def_args="--color auto" bin=
    [ -x ${bin:=/usr/bin/pacmatic} ] || bin=
    [ -x ${bin:=/usr/bin/pacman} ] || bin= 
    ${bin:?WHERE THE HELL IS PACMAN????} \
        $def_args "$@"
)

Aliases are for the birds.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .