I’ve touched on shell aliases and functions a few times, today I wanted to get in to a little more detail on passing arguments to them.

BASH aliases don’t actually take arguments, but they will automatically append any argument to the underlying command line.

1
2
3
alias t=tail -f
t /var/log/apache/access.log
# expands to tail -f /var/log/apache/access.log

Likewise for TCSH:

1
2
3
alias t tail -f
t /var/log/apache/access.log
# expands to tail -f /var/log/apache/access.log

However, TCSH aliases can move the arguments around. Consider this alias which tails an Apache log looking for 404 not found errors:

1
2
3
alias 404 'tail -f \!* | egrep " 404 "'
404 /var/log/apache/access.log
# expands to tail -f /var/log/apache/access.log | egrep " 404 "

TCSH overloads the history substitutions ! (bang) operators. Normally these refer to the previous command line and in:

1
2
3
touch foo bar baz
ls -l !*
# expands to ls -l foo bar baz

Which is identical to what BASH does with !* when used interactively.

In the context of an alias, they refer to the current line. !* means the command line arguments. The backslash is needed because in TCSH ! is not escaped by quotes. Without the backslash, !* is parsed and will refer to the previous command line. If you forget to escape ! in your .cshrc file, you’ll see spurious 0: Event not found. errors.

Of course, most of you use BASH, and to handle arguments in BASH you need to use a function instead of an alias:

1
2
3
function t404() { tail -f $@ | egrep " 404 "; }
t404 /var/log/apache/access.log
# expands to tail -f /var/log/apache/access.log | egrep " 404 "

In this case $@ means all of the arguments, it can also be represented as $*.

(BASH functions can’t start with a number, hence the “t”.)

What about positional arguments? Looking at BASH first, say we want to specify the HTTP response code we’re searching for:

1
2
3
function watch-log() { tail -f $2 | egrep " $1 "; }
watch-log 500 /var/log/apache/access.log
# expands to tail -f /var/log/apache/access.log | egrep " 500 "

As you can see $1 is the first argument, $2 the second and so on. What’s $0? It’s the name of the script that’s being run or, in the case of functions, just “bash”.

For TCSH, you can again use an alias. TCSH’s positional parameters are !:1, !:2, !:3, etc. More usefully than BASH, !:0 returns the name of alias, if you need it.

1
2
3
alias watch-log 'tail -f \!:2 | egrep " \!:1 "'
watch-log 500 /var/log/apache/access.log
# expands to tail -f /var/log/apache/access.log | egrep " 500 "

TCSH also has a shorthand for the first and last arguments, so the alias could also be written as:

1
alias watch-log 'tail -f \!$ | egrep " \!^ "'

As with the other ! commands, these work interactive in both BASH and TCSH referring to the previous line:

1
2
3
chown spike foo
chmod g+w !$
# expands to chmod g+w foo

Hopefully, this will help you write some powerful aliases. Next time, we’ll look at some of the shells’ build in options for manipulating functions/alias arguments before passing them to the commands.

Comments