fox2mike    05/07/14 18:03:09

  Added:       xml/htdocs/doc/en/articles bash-by-example-p2.xml
                        bash-by-example-p3.xml
  Log:
  #99008 - Bash by example, parts 2 and 3, initial version. Thanks to Lukasz 
Damentko.

Revision  Changes    Path
1.1                  xml/htdocs/doc/en/articles/bash-by-example-p2.xml

file : 
http://www.gentoo.org/cgi-bin/viewcvs.cgi/xml/htdocs/doc/en/articles/bash-by-example-p2.xml?rev=1.1&content-type=text/x-cvsweb-markup&cvsroot=gentoo
plain: 
http://www.gentoo.org/cgi-bin/viewcvs.cgi/xml/htdocs/doc/en/articles/bash-by-example-p2.xml?rev=1.1&content-type=text/plain&cvsroot=gentoo

Index: bash-by-example-p2.xml
===================================================================
<?xml version='1.0' encoding="UTF-8"?>
<!-- $Header: 
/var/cvsroot/gentoo/xml/htdocs/doc/en/articles/bash-by-example-p2.xml,v 1.1 
2005/07/14 18:03:09 fox2mike Exp $ -->
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd">

<guide link="/doc/en/articles/bash-by-example-part2.xml">
<title>Bash by example, Part 2</title>

<author title="Author">
  <mail link="[EMAIL PROTECTED]">Daniel Robbins</mail>
</author>
<author title="Editor">
  <mail link="[EMAIL PROTECTED]">Łukasz Damentko</mail>
</author>

<abstract>
In his introductory article on bash, Daniel Robbins walked you through some of
the scripting language's basic elements and reasons for using bash. In this, the
second installment, Daniel picks up where he left off and looks at bash's basic
constructs like conditional (if-then) statements, looping, and more.
</abstract>

<!-- The original version of this article was published on IBM developerWorks,
and is property of Westtech Information Services. This document is an updated
version of the original article, and contains various improvements made by the
Gentoo Linux Documentation team -->

<version>1.0</version>
<date>2005-07-14</date>

<chapter>
<title>More bash programming fundamentals</title>
<section>
<title>Accepting arguments</title>
<body>

<note>
The original version of this article was published on IBM developerWorks, and
is property of Westtech Information Services. This document is an updated
version of the original article, and contains various improvements made by the
Gentoo Linux Documentation team.
</note>

<p>
Let's start with a brief tip on handling command-line arguments, and then look
at bash's basic programming constructs.
</p>

<p>
In the sample program in the <uri
link="/doc/en/articles/bash-by-example-p1.xml">introductory article</uri>, we
used the environment variable "$1", which referred to the first command-line
argument. Similarly, you can use "$2", "$3", etc. to refer to the second and
third arguments passed to your script. Here's an example:
</p>

<pre caption="Referring to arguments passed to the script">
#!/usr/bin/env bash

echo name of script is $0
echo first argument is $1
echo second argument is $2
echo seventeenth argument is $17
echo number of arguments is $#
</pre>

<p>
The example is self explanatory except for two small details. First, "$0" will
expand to the name of the script, as called from the command line, and "$#" will
expand to the number of arguments passed to the script. Play around with the
above script, passing different kinds of command-line arguments to get the hang
of how it works.
</p>

<p>
Sometimes, it's helpful to refer to all command-line arguments at once. For this
purpose, bash features the "$@" variable, which expands to all command-line
parameters separated by spaces. We'll see an example of its use when we take a
look at "for" loops, a bit later in this article.
</p>

</body>
</section>
<section>
<title>Bash programming constructs</title>
<body>

<p>
If you've programmed in a procedural language like C, Pascal, Python, or Perl,
then you're familiar with standard programming constructs like "if" statements,
"for" loops, and the like. Bash has its own versions of most of these standard
constructs. In the next several sections, I will introduce several bash
constructs and demonstrate the differences between these constructs and others
you are already familiar with from other programming languages. If you haven't
programmed much before, don't worry. I include enough information and examples
so that you can follow the text.
</p>

</body>
</section>
<section>
<title>Conditional love</title>
<body>

<p>
If you've ever programmed any file-related code in C, you know that it requires
a significant amount of effort to see if a particular file is newer than
another. That's because C doesn't have any built-in syntax for performing such a
comparison; instead, two stat() calls and two stat structures must be used to
perform the comparison by hand. In contrast, bash has standard file comparison
operators built in, so determining if "<path>/tmp/myfile</path> is readable" is
as easy as checking to see if "<c>$myvar</c> is greater than 4".
</p>

<p>
The following table lists the most frequently used bash comparison operators.
You'll also find an example of how to use every option correctly. The example is
meant to be placed immediately after the "if". For example:
</p>

<pre caption="Bash comparison operator">
if [ -z "$myvar" ]
then
     echo "myvar is not defined"
fi
</pre>

<p>
Sometimes, there are several different ways that a particular comparison can be
made. For example, the following two snippets of code function identically:
</p>

<pre caption="Two ways of making comparison">
if [ "$myvar" -eq 3 ]
then 
     echo "myvar equals 3"
fi

if [ "$myvar" = "3" ]
then
     echo "myvar equals 3"
fi
</pre>

<p>
In the above two comparisons do exactly the same thing, but the first uses
arithmetic comparison operators, while the second uses string comparison
operators.
</p>

</body>
</section>
<section>
<title>String comparison caveats</title>
<body>

<p>
Most of the time, while you can omit the use of double quotes surrounding
strings and string variables, it's not a good idea. Why? Because your code will
work perfectly, unless an environment variable happens to have a space or a tab
in it, in which case bash will get confused. Here's an example of a fouled-up
comparison:
</p>

<pre caption="Fouled-up comparison example">
if [ $myvar = "foo bar oni" ]
then
     echo "yes"
fi
</pre>

<p>
In the above example, if myvar equals "foo", the code will work as expected and
not print anything. However, if myvar equals "foo bar oni", the code will fail
with the following error:
</p>

<pre caption="Error when variable contains spaces">
[: too many arguments
</pre>

<p>
In this case, the spaces in "$myvar" (which equals "foo bar oni") end up
confusing bash. After bash expands "$myvar", it ends up with the following
comparison:
</p>

<pre caption="Ending comparison">
[ foo bar oni = "foo bar oni" ]
</pre>

<p>
Because the environment variable wasn't placed inside double quotes, bash thinks
that you stuffed too many arguments in-between the square brackets. You can
easily eliminate this problem by surrounding the string arguments with
double-quotes. Remember, if you get into the habit of surrounding all string
arguments and environment variables with double-quotes, you'll eliminate many
similar programming errors. Here's how the "foo bar oni" comparison should have
been written:
</p>



1.1                  xml/htdocs/doc/en/articles/bash-by-example-p3.xml

file : 
http://www.gentoo.org/cgi-bin/viewcvs.cgi/xml/htdocs/doc/en/articles/bash-by-example-p3.xml?rev=1.1&content-type=text/x-cvsweb-markup&cvsroot=gentoo
plain: 
http://www.gentoo.org/cgi-bin/viewcvs.cgi/xml/htdocs/doc/en/articles/bash-by-example-p3.xml?rev=1.1&content-type=text/plain&cvsroot=gentoo

Index: bash-by-example-p3.xml
===================================================================
<?xml version='1.0' encoding="UTF-8"?>
<!-- $Header: 
/var/cvsroot/gentoo/xml/htdocs/doc/en/articles/bash-by-example-p3.xml,v 1.1 
2005/07/14 18:03:09 fox2mike Exp $ -->
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd">

<guide link="/doc/en/articles/bash-by-example-part3.xml">
<title>Bash by example, Part 3</title>

<author title="Author">
  <mail link="[EMAIL PROTECTED]">Daniel Robbins</mail>
</author>
<author title="Editor">
  <mail link="[EMAIL PROTECTED]">Łukasz Damentko</mail>
</author>

<abstract>
In his final Bash by example article, Daniel Robbins takes a good look at the
Gentoo Linux ebuild system, an excellent example of the power of bash. Step by
step, he shows you how the ebuild system was implemented, and touches on many
handy bash techniques and design strategies. By the end of the article, you'll
have a good grasp of what's involved in producing a full-blown bash-based
application, as well as a start at coding your own auto-build system.
</abstract>

<!-- The original version of this article was published on IBM developerWorks,
and is property of Westtech Information Services. This document is an updated
version of the original article, and contains various improvements made by the
Gentoo Linux Documentation team -->

<version>1.0</version>
<date>2005-07-14</date>

<chapter>
<title>Exploring the ebuild system</title>
<section>
<title>Enter the ebuild system</title>
<body>

<note>
The original version of this article was published on IBM developerWorks, and
is property of Westtech Information Services. This document is an updated
version of the original article, and contains various improvements made by the
Gentoo Linux Documentation team.
</note>

<p>
I've really been looking forward to this third and final <e>Bash by example</e>
article, because now that we've already covered bash programming fundamentals in
<uri link="/doc/en/articles/bash-by-example-p1.xml">Part 1</uri> and <uri
link="/doc/en/articles/bash-by-example-p2.xml">Part 2</uri>, we can focus on
more advanced topics, like bash application development and program design. For
this article, I will give you a good dose of practical, real-world bash
development experience by presenting a project that I've spent many hours coding
and refining: The Gentoo Linux ebuild system.
</p>

<p>
I'm the chief architect of Gentoo Linux, a next-generation Linux OS currently in
beta. One of my primary responsibilities is to make sure that all of the binary
packages (similar to RPM packages) are created properly and work together. As
you probably know, a standard Linux system is not composed of a single unified
source tree (like BSD), but is actually made up of about 25+ core packages that
work together. Some of the packages include:
</p>

<table>
  <tr>
    <th>Package</th>
    <th>Description</th>
  </tr>
  <tr>
    <ti>linux</ti>
    <ti>The actual kernel</ti>
  </tr>
  <tr>
    <ti>util-linux</ti>
    <ti>A collection of miscellaneous Linux-related programs</ti>
  </tr>
  <tr>
    <ti>e2fsprogs</ti>
    <ti>A collection of ext2 filesystem-related utilities</ti>
  </tr>
  <tr>
    <ti>glibc</ti>
    <ti>The GNU C library</ti>
  </tr>
</table>

<p>
Each package is in its own tarball and is maintained by separate independent
developers, or teams of developers. To create a distribution, each package has
to be separately downloaded, compiled, and packaged. Every time a package must
be fixed, upgraded, or improved, the compilation and packaging steps must be
repeated (and this gets old really fast). To help eliminate the repetitive steps
involved in creating and updating packages, I created the ebuild system, written
almost entirely in bash. To enhance your bash knowledge, I'll show you how I
implemented the unpack and compile portions of the ebuild system, step by step.
As I explain each step, I'll also discuss why certain design decisions were
made. By the end of this article, not only will you have an excellent grasp of
larger-scale bash programming projects, but you'll also have implemented a good
portion of a complete auto-build system.
</p>

</body>
</section>
<section>
<title>Why bash?</title>
<body>

<p>
Bash is an essential component of the Gentoo Linux ebuild system. It was chosen
as ebuild's primary language for a number of reasons. First, it has an
uncomplicated and familiar syntax that is especially well suited for calling
external programs. An auto-build system is "glue code" that automates the
calling of external programs, and bash is very well suited to this type of
application. Second, Bash's support for functions allowed the ebuild system to
have modular, easy-to-understand code. Third, the ebuild system takes advantage
of bash's support for environment variables, allowing package maintainers and
developers to configure it easily, on-the-fly.
</p>

</body>
</section>
<section>
<title>Build process review</title>
<body>

<p>
Before we look at the ebuild system, let's review what's involved in getting a
package compiled and installed. For our example, we will look at the "sed"
package, a standard GNU text stream editing utility that is part of all Linux
distributions. First, download the source tarball (<path>sed-3.02.tar.gz</path>)
(see <uri link="#resources">Resources</uri>). We will store this archive in
<path>/usr/src/distfiles</path>, a directory we will refer to using the
environment variable <c>$DISTDIR</c>. <c>$DISTDIR</c> is the directory where all
of our original source tarballs live; it's a big vault of source code.
</p>

<p>
Our next step is to create a temporary directory called <path>work</path>, which
houses the uncompressed sources. We'll refer to this directory later using the
<c>$WORKDIR</c> environment variable. To do this, change to a directory where we
have write permission and type the following:
</p>

<pre caption="Uncompressing sed into a temporary directory">
$ <i>mkdir work</i>
$ <i>cd work</i>
$ <i>tar xzf /usr/src/distfiles/sed-3.02.tar.gz</i>
</pre>

<p>
The tarball is then decompressed, creating a directory called
<path>sed-3.02</path> that contains all of the sources. We'll refer to the
<path>sed-3.02</path> directory later using the environment variable
<c>$SRCDIR</c>. To compile the program, type the following:
</p>

<pre caption="Uncompressing sed into a temporary directory">
$ <i>cd sed-3.02</i>
$ <i>./configure --prefix=/usr</i>
<comment>(autoconf generates appropriate makefiles, this can take a 
while)</comment>

$ <i>make</i>

<comment>(the package is compiled from sources, also takes a bit of 
time)</comment>
</pre>

<p>
We're going to skip the "make install" step, since we are just covering the
unpack and compile steps in this article. If we wanted to write a bash script to
perform all these steps for us, it could look something like this:
</p>

<pre caption="Sample bash script to perform the unpack/compile process">
#!/usr/bin/env bash

if [ -d work ]
then
<comment># remove old work directory if it exists</comment>
      rm -rf work
fi
mkdir work
cd work
tar xzf /usr/src/distfiles/sed-3.02.tar.gz
cd sed-3.02
./configure --prefix=/usr
make
</pre>

</body>
</section>
<section>
<title>Generalizing the code</title>
<body>

<p>
Although this autocompile script works, it's not very flexible. Basically, the
bash script just contains the listing of all the commands that were typed at the
command line. While this solution works, it would be nice to make a generic



-- 
[email protected] mailing list

Reply via email to