295 lines
11 KiB
HTML
295 lines
11 KiB
HTML
<!--startcut ==============================================-->
|
|
<!-- *** BEGIN HTML header *** -->
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
<HTML><HEAD>
|
|
<title>Functions and aliases in bash LG #53</title>
|
|
</HEAD>
|
|
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
|
|
ALINK="#FF0000">
|
|
<!-- *** END HTML header *** -->
|
|
|
|
<A HREF="http://www.linuxgazette.com/">
|
|
<H1><IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.jpg"
|
|
WIDTH="600" HEIGHT="124" border="0"></H1></A>
|
|
|
|
<!-- *** BEGIN navbar *** -->
|
|
<A HREF="correa3.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A>
|
|
<IMG ALT=""
|
|
SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom" >
|
|
<A HREF="index.html"><IMG ALT="[ Table of Contents ]"
|
|
SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A>
|
|
<A HREF="../index.html"><IMG ALT="[ Front Page ]"
|
|
SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A>
|
|
<A HREF="../faq/index.html"><IMG ALT="[ FAQ ]"
|
|
SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A>
|
|
<A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue53/eyler.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A>
|
|
<IMG ALT=""
|
|
SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom" >
|
|
<A HREF="lamb.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A>
|
|
<!-- *** END navbar *** -->
|
|
<P>
|
|
<!-- A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue53/eyler.html">
|
|
<FONT SIZE="+2"><EM>Talkback:</EM> Discuss this article with peers</FONT></A -->
|
|
|
|
<!--endcut ============================================================-->
|
|
|
|
<H4>
|
|
"Linux Gazette...<I>making Linux just a little more fun!</I>"
|
|
</H4>
|
|
|
|
<P> <HR> <P>
|
|
<!--===================================================================-->
|
|
|
|
<center>
|
|
<H1><font color="maroon">Functions and aliases in bash</font></H1>
|
|
<H4>By <a href="mailto:pate@gnu.org">Pat Eyler</a></H4>
|
|
</center>
|
|
<P> <HR> <P>
|
|
|
|
<!-- END header -->
|
|
|
|
|
|
|
|
|
|
Many tutorials and introductions to bash talk about using aliases.
|
|
Unfortunately most of them don't cover functions. This is a real
|
|
loss, because functions offer many values that aliases don't.
|
|
|
|
<h3>Aliases</h3>
|
|
<p>Aliases are simple string substitutions. The shell looks at the first
|
|
word of a command and compares it against it's current list of
|
|
aliases. Further, if the last character of an alias is a space, it
|
|
looks at the next word as well. For example:
|
|
<blockquote><code>
|
|
<br>$ alias 1='echo '
|
|
<br>$ alias 2='this is an alias'
|
|
<br>$ 1 2
|
|
<br>this is an alias
|
|
<br>$
|
|
</code></blockquote>
|
|
<p>Aliases don't allow for control-flow, command line arguments, or
|
|
additional trickery that makes the command line so useful.
|
|
Additionally, the rules surrounding alias expansion are a bit tricky,
|
|
enough so that the bash(1) manpage recommends "[t]o be safe, always
|
|
put alias definitions on a separate line, and do not use alias in
|
|
compound commands".
|
|
|
|
<h3>An Intro to Functions</h3>
|
|
<p>Functions are really scripts run in the current context of the shell.
|
|
(This bit of techspeak means that a second shell is not forked to run
|
|
the function, it is run within the current shell.) Functions really
|
|
are full scripts in and of themselves, and allow all the flexibility
|
|
and capability that entails.
|
|
|
|
<p>You can create a functions a couple of different ways. You can just
|
|
enter it into a file and source the file with the '.' command (either
|
|
from the command line or in your start-up scripts). You can also just
|
|
enter the function into at the command line. A function is only
|
|
available in a session where it has been made available through one of
|
|
these methods (or has inherited it from its parent shell).
|
|
|
|
<p>To create a function from the command line you would do something
|
|
like this:
|
|
|
|
<blockquote><code><pre>
|
|
$ gla() {
|
|
> ls -la | grep $1
|
|
> }
|
|
</blockquote></code></pre>
|
|
|
|
<p>This is a pretty simple function, and could be implemented as an
|
|
alias as well. (There are reasons you might not want to do this,
|
|
we'll get to those later.) As written, it does a long listing of the
|
|
local directory and greps for any matches for the first argument. You
|
|
could make it more interesting by punching it through awk to find any
|
|
matching files that are larger than 1024 bytes. This would look like:
|
|
|
|
<blockquote><code><pre>
|
|
$ gla() {
|
|
> ls -la | grep $1 | awk ' { if ( $5 > 1024 ) print $0 } '
|
|
> }
|
|
</blockquote></code></pre>
|
|
|
|
<p>You can't do this as an alias, you're no longer just replacing gla
|
|
with the 'ls -la | grep'. Since its written as a function, there is
|
|
no problem using the $1 (referring to the first argument to gla)
|
|
anywhere in the body of your commands.
|
|
|
|
<p>For a larger example (well, okay it's a fair amount larger),
|
|
suppose you are working on two projects with two different CVS
|
|
repositories. You might want to be able to write a function that
|
|
allows you to set appropriate CVSROOT and CVS_ROOT variables, or clear
|
|
any values from these variables if the argument unset is given. It
|
|
would also be nice if it would run 'cvs update' for you if given the
|
|
argument 'update'. With aliases, you could approximate this, but only
|
|
by running multiple aliases from the command line. Using functions,
|
|
you could create a text file containing the following:
|
|
(<A HREF="misc/eyler/setcvs.sh.txt">text version</A>)
|
|
|
|
<blockquote><code><pre>
|
|
setcvs() {
|
|
export done="no"
|
|
if [ "$1" = "unset" ]
|
|
# we want to clear all of the variables
|
|
then
|
|
echo -n "Clearing cvs related variables: "
|
|
export CVSROOT=""
|
|
export CVS_RSH=""
|
|
export done="yes"
|
|
echo "done"
|
|
fi
|
|
if ( pwd | grep projects/reporting > /dev/null && \
|
|
[ "$done" != "yes" ] )
|
|
# if we're in the reporting area, and we're not already done
|
|
then
|
|
echo -n "Setting up cvs for reporting project: "
|
|
export CVSROOT="issdata:/usr/local/cvs/"
|
|
export CVS_RSH="ssh"
|
|
export done="yes"
|
|
echo "done"
|
|
fi
|
|
if ( pwd | grep projects/nightly > /dev/null && \
|
|
[ "$done" != "yes" ] )
|
|
# if we're in the nightly area, and we're not already done
|
|
then
|
|
echo -n "Setting up cvs for nightly project: "
|
|
export CVSROOT="/home/cvs/"
|
|
export done="yes"
|
|
echo "done"
|
|
fi
|
|
if [ "$1" = "update" ]
|
|
# we want to update the current tree from the cvs server after
|
|
# setting up the right variables
|
|
then
|
|
if [ -z "$CVSROOT" ]
|
|
# if there is a zero length $CVSROOT (it has already been
|
|
# cleared or was never set) throw an error and do nothing
|
|
then
|
|
echo "no cvs variables set ... check your cwd and try again"
|
|
elif [ -n "$CVSROOT" ]
|
|
# if there is a $CVSROOT try and do the update
|
|
then
|
|
echo "updating local tree"
|
|
cvs -q update
|
|
echo "done"
|
|
fi
|
|
fi
|
|
}
|
|
</pre></code></blockquote>
|
|
<p>Then you could enable the function and use it like this:
|
|
<blockquote><code>
|
|
<br>$ . ~/scripts/setcvs
|
|
<br>$ cd
|
|
<br>$ pwd
|
|
<br>/home/a257455
|
|
<br>$ setcvs unset
|
|
<br>Clearing cvs related variables: done
|
|
<br>$ echo $CVSROOT
|
|
<br>
|
|
<br>$ echo $CVS_RSH
|
|
<br>
|
|
<br>$ cd projects/reporting/htdocs/
|
|
<br>$ setcvs
|
|
<br>Setting up cvs for reporting project: done
|
|
<br>$ echo $CVSROOT
|
|
<br>issdata:/usr/local/cvs/
|
|
<br>$ echo $CVS_RSH
|
|
<br>ssh
|
|
<br>$ cd ../../nightly/
|
|
<br>$ setcvs
|
|
<br>Setting up cvs for nightly project: done
|
|
<br>$ setcvs update
|
|
<br>Setting up cvs for nightly project: done
|
|
<br>updating local tree
|
|
<br>done
|
|
<br>$ cd
|
|
<br>$ setcvs unset
|
|
<br>Clearing cvs related variables: done
|
|
<br>$ setcvs update
|
|
<br>no cvs variables set ... check your cwd and try again
|
|
<br>$
|
|
</code></blockquote>
|
|
|
|
<p>Functions can do a lot more than aliases, the function above shows a
|
|
little bit of flow control, some error handling, and the ability to
|
|
use variables. Certainly it could be improved, but it shows the
|
|
point. Another big win is that functions can be re-used in scripts,
|
|
while aliases can't. For example, because the function above is saved in
|
|
a file called '~/scripts/setcvs' you can write a script like:
|
|
<blockquote><code><pre>
|
|
#!/bin/bash
|
|
|
|
# a sample script
|
|
|
|
# first source the functions
|
|
. ~/scripts/setcvs
|
|
|
|
# now go to the project directories and update them from cvs
|
|
cd ~/projects/reporting/htdocs
|
|
setcvs update
|
|
cd -
|
|
cd ~/projects/nightly
|
|
setcvs update
|
|
|
|
# now go back to where you were and unset any cvs variables.
|
|
cd -
|
|
setcvs unset
|
|
</pre></code></blockquote>
|
|
|
|
<h3>A Final Warning</h3>
|
|
<p>Aliases are very useful little things, but I hope that after this
|
|
introduction, you find functions at least as interesting (and probably
|
|
even more useful). A final caveat to both aliases and functions is
|
|
that you should never replace a standard command with an alias or a
|
|
function. It is too easy to really hurt yourself by trying to execute
|
|
your alias when it doesn't exist. Imagine the difference between:
|
|
<blockquote><code><pre>
|
|
$ alias rm='rm -i'
|
|
$ cd ~/scratch
|
|
$ rm * # here the rm alias catches you and interactively
|
|
# deletes the contents of your current directory
|
|
</pre></code></blockquote>
|
|
<br>and then later in the same session doing:
|
|
<blockquote><code><pre>
|
|
$ su -
|
|
# cd /tmp
|
|
# rm # here the rm alias no longer exists, and you whack
|
|
# a bunch of stuff out of /tmp
|
|
</pre></code></blockquote>
|
|
|
|
<p>Happy hacking!<BR>
|
|
-pate
|
|
|
|
|
|
|
|
<!-- *** BEGIN copyright *** -->
|
|
<P> <hr> <!-- P -->
|
|
<H5 ALIGN=center>
|
|
|
|
Copyright © 2000, Pat Eyler<BR>
|
|
Published in Issue 53 of <i>Linux Gazette</i>, May 2000</H5>
|
|
<!-- *** END copyright *** -->
|
|
|
|
<!--startcut ==========================================================-->
|
|
<!-- P --> <HR> <!-- P -->
|
|
<!-- A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue53/eyler.html">
|
|
<FONT SIZE="+2"><EM>Talkback:</EM> Discuss this article with peers</FONT></A -->
|
|
<P>
|
|
<!-- *** BEGIN navbar *** -->
|
|
<A HREF="correa3.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A>
|
|
<IMG ALT=""
|
|
SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom" >
|
|
<A HREF="index.html"><IMG ALT="[ Table of Contents ]"
|
|
SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A>
|
|
<A HREF="../index.html"><IMG ALT="[ Front Page ]"
|
|
SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A>
|
|
<A HREF="../faq/index.html"><IMG ALT="[ FAQ ]"
|
|
SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A>
|
|
<A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue53/eyler.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A>
|
|
<IMG ALT=""
|
|
SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom" >
|
|
<A HREF="lamb.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A>
|
|
<!-- *** END navbar *** -->
|
|
</BODY></HTML>
|
|
<!--endcut ============================================================-->
|