How to extend bash aliases

Bash stores the values of aliases in an array called BASH_ALIASES:

$ alias foo=bar
$ echo ${BASH_ALIASES[foo]}
bar

With parameter expansion we can get the either the last set alias (if exists) or the default value:

alias grep="${BASH_ALIASES[grep]:-grep} -I --exclude=\*~"

Now just do it on setup-java.sh:

alias grep="${BASH_ALIASES[grep]:-grep} -I --exclude=\*~  --exclude-dir=classes"

...and finally on setup-sass.sh:

alias grep="${BASH_ALIASES[grep]:-grep} -I --exclude=\*~ --exclude-dir=\*/.sass-cache"

If the three lines are called, we get what we want:

$ echo ${BASH_ALIASES[grep]:-grep}
grep -I --exclude=\*~ -I --exclude=\*~ --exclude-dir=classes -I --exclude=\*~ --exclude-dir=\*/.sass-cache

aliases chain if you end them with spaces.

alias print='printf %s\\n ' hey='"hello, fine fellow" '
print hey

hello, fine fellow

You can write entire scripts that way, if you're crazy enough. Anyway, if you want to extend an alias, then just make sure the alias you want to extend ends in a space, and tack another on.

alias grep='printf "%s " -I --exclude=\*~ '    \
      exdir=' --exclude-dir=classes '          \
      exsass='--exclude-dir=\*/.sass-cache '
grep exdir exsass exdir exsass

-I --exclude=*~ --exclude-dir=classes --exclude-dir=*/.sass-cache --exclude-dir=classes --exclude-dir=*/.sass-cache

A function is a better option than an extendable alias here.

grep_options=( )
grep() {
  exec /usr/bin/grep "${grep_options[@]}" ${GREP_OPTIONS} "$@"
}

That way, you have two options to add options to the environment:

  • Amend the grep_options array; this correctly supports options with spaces, literal glob characters, and other corner cases:

    grep_options+=( --exclude-dir=classes --exclude-dir='*/.sass-cache' )
    
  • Use the traditional GREP_OPTIONS scalar variable, despite its pitfalls (see BashFAQ #50 to understand some of these):

    GREP_OPTIONS+=' --exclude-dir=classes '
    

That said, if you want your options to be reflected by grep instances invoked outside the shell, neither an alias nor a function will do. Instead, you'll want a wrapper script placed earlier in your PATH than the real grep command. For instance:

# in ~/.bash_profile
[[ -e ~/bin ]] && PATH=$HOME/bin:$PATH

...and, in ~/bin/grep:

#!/bin/bash

# load overrides to grep_options on GREP_OPTIONS from local dotfiles
source ~/.bash_profile
source ~/.bashrc

# ...and use them:
exec /usr/bin/grep "${grep_options[@]}" ${GREP_OPTIONS} "$@"

Tags:

Bash

Alias

Grep