How to create an alias that actually extends another alias of the same name in Bash?


I used to have GREP_OPTIONS set on .bashrc to something like this:

GREP_OPTIONS="-I --exclude=\*~"

I also had a script (let us say, setup-java.sh) which I would call before working on some Java projects. It would contain the line:

GREP_OPTIONS="$GREP_OPTIONS --exclude-dir=classes"

If I also use Sass, then I would call setup-sass.sh which contains the line:

GREP_OPTIONS="$GREP_OPTIONS --exclude-dir=\*/.sass-cache"

But GREP_OPTIONS was deprecated and apparently the standard solution is either create an alias or some script...

  • What about bash functions?
    – Jakuje
    Jan 10, 2016 at 10:49
  • 2
    I quite agree -- using a function is a much better option than an alias. Jan 10, 2016 at 17:38

3 Answers 3


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

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

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
  • 8
    This is horrifying beautiful. Jan 10, 2016 at 2:45
  • 2
    @Wildcard: fnmatch(){ alias fnmatch='case $1 in '; while "${1:+:}" 2>&-; do eval 'fnmatch pattern list ;; esac'; shift; done; unalias fnmatch; }; alias pattern='${1:+*}) ' list=': do stuff '; fnmatch "$@". Doing it with aliases allows you to use the patterns' expansions more directly and more safely. You do need a second context w/ eval when called from within a function, but it's not inherently unsafe as long as the pattern and list names are controlled by you. They can only break in most cases even when they're not unless some attacker knowingly correctly ends your case.
    – mikeserv
    Jan 10, 2016 at 11:32
  • 1
    I use this pattern in my .bashrc: alias sudo='sudo ', this lets me call all my aliased commands after a sudo. Without the space it wouldn't work
    – arainone
    Jan 10, 2016 at 17:46
  • 1
    Wow, a lot of nice tricks!
    – brandizzi
    Jan 14, 2016 at 1:05
  • 2
    @Wildcard - I wasn't exactly advocating such use, but it's true you can, and it's also true you'd have to be at least a little crazy to try.
    – mikeserv
    Jan 15, 2016 at 6:02

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:


# 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} "$@"

You must log in to answer this question.

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