old-www/LDP/LG/issue57/eyler.html

259 lines
9.2 KiB
HTML

<!--startcut ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>Variable Mangling in Bash with String Operators LG #57</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->
<CENTER>
<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 *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="correa4.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><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="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue57/eyler.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" 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="eyler2.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
<P>
</CENTER>
<!--endcut ============================================================-->
<H4 ALIGN="center">
"Linux Gazette...<I>making Linux just a little more fun!</I>"
</H4>
<P> <HR> <P>
<!--===================================================================-->
<center>
<H1><font color="maroon">Variable Mangling in Bash with String Operators</font></H1>
<H4>By <a href="mailto:pate@gnu.org">Pat Eyler</a></H4>
</center>
<P> <HR> <P>
<!-- END header -->
<h3>Abstract</h3>
<p>Have you ever wanted to change the names of many files at once?
How about using a default value for a variable if it has no value?
These and many other options are available to you through string
operators in bash and other Bourne shell derived shells.
<p>String operators allow you to manipulate the contents of a variable
without having to write your own shell functions to do so. They are
provided through 'curly brace' syntax. Any variable can be displayed
like this <code>${foo}</code> without changing its meaning. This
functionality is often used to protect a variable name from
surrounding characters.<br>
<code>
<pre>
bash-2.02$ export foo=foo
bash-2.02$ echo ${foo}bar # foo exists so this works
foobar
bash-2.02$ echo $foobar # foobar doesn't exist, so this fails
bash-2.02$
</pre>
</code>
<br>
By the end of this article, you'll be able to use it for a whole lot more.
<hr width="70%">
<p>There are three kinds of variable substitution:<ul>
<li>Pattern Matching,
<li>Substitution,
<li>Command Substitution.
</ul>
I'll talk about the first two and leave command substitution for
another article.
<h3>Pattern Matching</h3>
<p>There are two kinds of pattern matching available, matching from
the left and matching from the right. The operators, with their
functions and an expample, are shown in the following table:
<center>
<table width=70%>
<tr>
<th>Operator</th>
<th>Function</th>
<th>Example</th>
</tr>
<tr valign=top>
<td><code>${foo#t*is}</code></td>
<td>deletes the shortest possible match from the left</td>
<td>
<code>export $foo="this is a test"<br>echo ${foo#t*is}<br>is a test
</code>
</td>
</tr>
<tr valign=top>
<td><code>${foo##t*is}</code></td>
<td>deletes the longest possible match from the left</td>
<td>
<code>export $foo="this is a test"<br>echo ${foo#t*is}<br>a test
</code>
</td>
</tr><tr valign=top>
<td><code>${foo%t*st}</code></td>
<td>deletes the shortest possible match from the right</td>
<td>
<code>export $foo="this is a test"
<br>echo ${foo%t*st}<br>this is a
</code>
</td>
</tr><tr valign=top>
<td><code>${foo%%t*st}</code></td>
<td>deletes the longest possible match from the right</td>
<td>
<code>export $foo="this is a test"<br>echo ${foo#t*is}<br>&nbsp;
</code>
</td>
</tr>
</table>
</center>
<blockquote>
<p><b>Note:</b> <i>While the <code>#</code> and <code>%</code>
identifiers may not seem obvious, they have a convenient mnemonic.
The <code>#</code> key is on the left side of the <code>$</code> key
and operates from the left. The <code>%</code> key is on the right of
the <code>$</code> key and operated from the right.</i>
</blockquote>
<p>These operators can be used to do a variety of things. For example,
the following script will change the extension of all '.html' files to
'.htm'.
<blockquote>
<code>
<pre>
#!/bin/bash
# quickly convert html filenames for use on a dossy system
# only handles file extensions, not file names
for i in *.html; do
if [ -f ${i%l} ]; then
echo ${i%l} already exists
else
mv $i ${i%l}
fi
done
</pre>
</code>
</blockquote>
<h3>Substitution</h3>
<p>Another kind of variable mangling you might want to employ is
substitution. There are four substitution operators in Bash. They
are shown in the following table:
<center>
<table width=70%>
<tr>
<th>Operator</th>
<th>Function</th>
<th>Example</th>
</tr>
<tr valign=top>
<td><code>${foo:-bar}</code></td>
<td>If $foo exists and is not null, return $foo. If it doesn't exist,
or is null, return bar.</td>
<td>
<code>export foo=""<br>echo ${foo:-one}<br>one<br>echo $foo<br>&nbsp;
</code>
</td>
</tr>
<tr valign=top>
<td><code>${foo:=bar}</code></td>
<td>If $foo exists and is not null, return $foo. If it doesn't exist,
or is null, set $foo to bar and return bar</td>
<td>
<code>export foo=""<br>echo ${foo:=one}<br>one<br>echo $foo<br>one
</code>
</td>
</tr><tr valign=top>
<td><code>${foo:+bar}</code></td>
<td>If $foo exists and is not null, return bar. If it doesn't exist,
or is null, return a null.</td>
<td>
<code>export foo="this is a test"
<br>echo ${foo:+bar}<br>bar
</code>
</td>
</tr><tr valign=top>
<td><code>${foo:?"error message"}</code></td>
<td>If $foo exists and isn't null, return it's value. If it doesn't
exist, or is null, print the error message. If no error message is
given, it prints <code>parameter null or not
set</code>.<br><b>Note:</b> <i>In a non-interactive shell, this will
abort the current script. In an interactive shell, this will just
print the error message.</i>
</td>
<td>
<code>
export foo="one"<br>
for i in foo bar baz; do<br>
eval echo \${$foo:?}<br>
one<br>
bash: bar: parameter null or not set<br>
bash: baz: parameter null or not set<br>
</code>
</td>
</tr>
</table>
</center>
<blockquote>
<b>Note:</b> <i>The <code>:</code> in the above operators can be
omitted. Doing so changes the behavior of the operator to only test
for existence of the variable. This will cause the creation of a variable
in the case of</i> <code>${foo=bar}</code>
</blockquote>
<p>These operators can be used in a variety of ways. A good example
would be to give a default value to a variable normally read from the
command line arguments when no arguments are given. This is shown in
the following script.
<blockquote>
<code>
<pre>
#!/bin/bash
export INFILE=${1-"infile"}
export OUTFILE=${2-"outfile"}
cat $INFILE &gt; $OUTFILE
</pre>
</code>
</blockquote>
<p>Hopefully this gives you something to think about and to play with
until the next article. If you're interested in more hints about bash
(or other stuff I've written about), please take a look at <a
href="http://tbr.nailed.org/">my home page</a>. If you've got
questions or comments, please <a
href="mailto:pate@tbr.nailed.org">drop me a line</a>.
<!-- *** BEGIN copyright *** -->
<P> <hr> <!-- P -->
<H5 ALIGN=center>
Copyright &copy; 2000, Pat Eyler<BR>
Published in Issue 57 of <i>Linux Gazette</i>, September 2000</H5>
<!-- *** END copyright *** -->
<!--startcut ==========================================================-->
<HR><P>
<CENTER>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="correa4.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><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="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue57/eyler.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" 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="eyler2.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->