<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [


<!ENTITY INDEX00 SYSTEM "INDEX00.sgml">
<!ENTITY ex1 SYSTEM "ex1.sh">
<!ENTITY ex1a SYSTEM "ex1a.sh">
<!ENTITY ex2 SYSTEM "ex2.sh">
<!ENTITY ex3 SYSTEM "ex3.sh">
<!ENTITY ex4 SYSTEM "ex4.sh">
<!ENTITY ex5 SYSTEM "ex5.sh">
<!ENTITY ex6 SYSTEM "ex6.sh">
<!ENTITY ex7 SYSTEM "ex7.sh">
<!ENTITY ex8 SYSTEM "ex8.sh">
<!ENTITY ex9 SYSTEM "ex9.sh">
<!ENTITY ex10 SYSTEM "ex10.sh">
<!ENTITY ex11 SYSTEM "ex11.sh">
<!ENTITY ex12 SYSTEM "ex12.sh">
<!ENTITY ex13 SYSTEM "ex13.sh">
<!ENTITY ex14 SYSTEM "ex14.sh">
<!ENTITY ex15 SYSTEM "ex15.sh">
<!ENTITY ex16 SYSTEM "ex16.sh">
<!ENTITY ex17 SYSTEM "ex17.sh">
<!ENTITY ex18 SYSTEM "ex18.sh">
<!ENTITY ex19 SYSTEM "ex19.sh">
<!ENTITY ex20 SYSTEM "ex20.sh">
<!ENTITY ex21 SYSTEM "ex21.sh">
<!ENTITY ex22 SYSTEM "ex22.sh">
<!ENTITY ex22a SYSTEM "ex22a.sh">
<!ENTITY ex23 SYSTEM "ex23.sh">
<!ENTITY ex24 SYSTEM "ex24.sh">
<!ENTITY ex25 SYSTEM "ex25.sh">
<!ENTITY ex26 SYSTEM "ex26.sh">
<!ENTITY ex26a SYSTEM "ex26a.sh">
<!ENTITY ex27 SYSTEM "ex27.sh">
<!ENTITY ex28 SYSTEM "ex28.sh">
<!ENTITY ex29 SYSTEM "ex29.sh">
<!ENTITY ex30 SYSTEM "ex30.sh">
<!ENTITY ex30a SYSTEM "ex30a.sh">
<!ENTITY ex31 SYSTEM "ex31.sh">
<!ENTITY ex32 SYSTEM "ex32.sh">
<!ENTITY ex33 SYSTEM "ex33.sh">
<!ENTITY ex33a SYSTEM "ex33a.sh">
<!ENTITY ex34 SYSTEM "ex34.sh">
<!ENTITY ex35 SYSTEM "ex35.sh">
<!ENTITY ex36 SYSTEM "ex36.sh">
<!ENTITY ex37 SYSTEM "ex37.sh">
<!ENTITY ex38 SYSTEM "ex38.sh">
<!ENTITY ex38bis SYSTEM "data-file">
<!ENTITY ex39 SYSTEM "ex39.sh">
<!ENTITY ex40 SYSTEM "ex40.sh">
<!ENTITY ex41 SYSTEM "ex41.sh">
<!ENTITY ex42 SYSTEM "ex42.sh">
<!ENTITY ex43 SYSTEM "ex43.sh">
<!ENTITY ex44 SYSTEM "ex44.sh">
<!ENTITY ex45 SYSTEM "ex45.sh">
<!ENTITY ex45a SYSTEM "ex45a.sh">
<!ENTITY ex46 SYSTEM "ex46.sh">
<!ENTITY ex47 SYSTEM "ex47.sh">
<!ENTITY ex48 SYSTEM "ex48.sh">
<!ENTITY ex49 SYSTEM "ex49.sh">
<!ENTITY ex50 SYSTEM "ex50.sh">
<!ENTITY ex51 SYSTEM "ex51.sh">
<!ENTITY ex52 SYSTEM "ex52.sh">
<!ENTITY ex53 SYSTEM "ex53.sh">
<!ENTITY ex54 SYSTEM "ex54.sh">
<!ENTITY ex55 SYSTEM "ex55.sh">
<!ENTITY ex56 SYSTEM "ex56.sh">
<!ENTITY ex57 SYSTEM "ex57.sh">
<!ENTITY ex58 SYSTEM "ex58.sh">
<!ENTITY ex59 SYSTEM "ex59.sh">
<!ENTITY ex60 SYSTEM "ex60.sh">
<!ENTITY ex61 SYSTEM "ex61.sh">
<!ENTITY ex62 SYSTEM "ex62.sh">
<!ENTITY ex63 SYSTEM "ex63.sh">
<!ENTITY ex64 SYSTEM "ex64.sh">
<!ENTITY ex65 SYSTEM "ex65.sh">
<!ENTITY ex66 SYSTEM "ex66.sh">
<!ENTITY ex67 SYSTEM "ex67.sh">
<!ENTITY ex68 SYSTEM "ex68.sh">
<!ENTITY ex68a SYSTEM "ex68a.sh">
<!ENTITY ex69 SYSTEM "ex69.sh">
<!ENTITY ex70 SYSTEM "ex70.sh">
<!ENTITY ex71 SYSTEM "ex71.sh">
<!ENTITY ex71a SYSTEM "ex71a.sh">
<!ENTITY ex71b SYSTEM "ex71b.sh">
<!ENTITY ex71c SYSTEM "ex71c.sh">
<!ENTITY ex72 SYSTEM "ex72.sh">
<!ENTITY ex73 SYSTEM "ex73.sh">
<!ENTITY ex74 SYSTEM "ex74.sh">
<!ENTITY ex75 SYSTEM "ex75.sh">
<!ENTITY ex76 SYSTEM "ex76.sh">
<!ENTITY ex77 SYSTEM "ex77.sh">
<!ENTITY ex78 SYSTEM "ex78.sh">
<!ENTITY cards SYSTEM "cards.sh">
<!ENTITY andor SYSTEM "and-or.sh">
<!ENTITY lnum SYSTEM "line-number.sh">
<!ENTITY manview SYSTEM "manview.sh">
<!ENTITY rfe SYSTEM "rfe.sh">
<!ENTITY behead SYSTEM "behead.sh">
<!ENTITY ftpget SYSTEM "ftpget.sh">
<!ENTITY encryptedpw SYSTEM "encryptedpw.sh">
<!ENTITY rpmcheck SYSTEM "rpm-check.sh">
<!ENTITY subshell SYSTEM "subshell.sh">
<!ENTITY lowercase SYSTEM "lowercase.sh">
<!ENTITY online SYSTEM "online.sh">
<!ENTITY reply SYSTEM "reply.sh">
<!ENTITY seconds SYSTEM "seconds.sh">
<!ENTITY numbers SYSTEM "numbers.sh">
<!ENTITY indref SYSTEM "ind-ref.sh">
<!ENTITY bubble SYSTEM "bubble.sh">
<!ENTITY paramsub SYSTEM "param-sub.sh">
<!ENTITY restricted SYSTEM "restricted.sh">
<!ENTITY pw SYSTEM "pw.sh">
<!ENTITY rn SYSTEM "rn.sh">
<!ENTITY coltotaler SYSTEM "col-totaler.sh">
<!ENTITY coltotaler2 SYSTEM "col-totaler2.sh">
<!ENTITY coltotaler3 SYSTEM "col-totaler3.sh">
<!ENTITY tmdin SYSTEM "timed-input.sh">
<!ENTITY fifo SYSTEM "fifo.sh">
<!ENTITY tree SYSTEM "tree.sh">
<!ENTITY tree2 SYSTEM "tree2.sh">
<!ENTITY secretpw SYSTEM "secret-pw.sh">
<!ENTITY stripc SYSTEM "strip-comments.sh">
<!ENTITY al SYSTEM "alias.sh">
<!ENTITY unal SYSTEM "unalias.sh">
<!ENTITY redir1 SYSTEM "redir1.sh">
<!ENTITY redir2 SYSTEM "redir2.sh">
<!ENTITY redir2a SYSTEM "redir2a.sh">
<!ENTITY redir3 SYSTEM "redir3.sh">
<!ENTITY redir4 SYSTEM "redir4.sh">
<!ENTITY redir4a SYSTEM "redir4a.sh">
<!ENTITY redir5 SYSTEM "redir5.sh">
<!ENTITY wipedir SYSTEM "wipedir.sh">
<!ENTITY grp SYSTEM "grp.sh">
<!ENTITY killprocess SYSTEM "kill-process.sh">
<!ENTITY killbyname SYSTEM "kill-byname.sh">
<!ENTITY strtest SYSTEM "str-test.sh">
<!ENTITY colm SYSTEM "colm.sh">
<!ENTITY lookup SYSTEM "lookup.sh">
<!ENTITY arglist SYSTEM "arglist.sh">
<!ENTITY rot13 SYSTEM "rot13.sh">
<!ENTITY rot13a SYSTEM "rot13a.sh">
<!ENTITY rot14 SYSTEM "rot14.sh">
<!ENTITY filecomp SYSTEM "file-comparison.sh">
<!ENTITY adddrv SYSTEM "add-drive.sh">
<!ENTITY whloopc SYSTEM "wh-loopc.sh">
<!ENTITY forloopc SYSTEM "for-loopc.sh">
<!ENTITY forloopcmd SYSTEM "for-loopcmd.sh">
<!ENTITY cvars SYSTEM "c-vars.sh">
<!ENTITY bingrep SYSTEM "bin-grep.sh">
<!ENTITY mailformat SYSTEM "mail-format.sh">
<!ENTITY symlinks SYSTEM "symlinks.sh">
<!ENTITY symlinks2 SYSTEM "symlinks2.sh">
<!ENTITY string SYSTEM "string.sh">
<!ENTITY nestedloop SYSTEM "nested-loop.sh">
<!ENTITY casecmd SYSTEM "case-cmd.sh">
<!ENTITY uns SYSTEM "unset.sh">
<!ENTITY base SYSTEM "base.sh">
<!ENTITY allprofs SYSTEM "allprofs.sh">
<!ENTITY pidid SYSTEM "pid-identifier.sh">
<!ENTITY constat SYSTEM "connect-stat.sh">
<!ENTITY subpit SYSTEM "subshell-pitfalls.sh">
<!ENTITY readredir SYSTEM "read-redir.sh">
<!ENTITY andlist2 SYSTEM "and-list2.sh">
<!ENTITY qfunction SYSTEM "q-function.sh">
<!ENTITY viewdata SYSTEM "viewdata.sh">
<!ENTITY VIEWDAT SYSTEM "VIEWDATA.BAT">
<!ENTITY what SYSTEM "what.sh">
<!ENTITY max SYSTEM "max.sh">
<!ENTITY max2 SYSTEM "max2.sh">
<!ENTITY findstring SYSTEM "findstring.sh">
<!ENTITY listglob SYSTEM "list-glob.sh">
<!ENTITY realname SYSTEM "realname.sh">
<!ENTITY escaped SYSTEM "escaped.sh">
<!ENTITY fileinfo SYSTEM "file-info.sh">
<!ENTITY weirdvars SYSTEM "weirdvars.sh">
<!ENTITY breaklevels SYSTEM "break-levels.sh">
<!ENTITY copycd SYSTEM "copy-cd.sh">
<!ENTITY arithops SYSTEM "arith-ops.sh">
<!ENTITY continuelevels SYSTEM "continue-nlevel.sh">
<!ENTITY timeout SYSTEM "timeout.sh">
<!ENTITY randomtest SYSTEM "random-test.sh">
<!ENTITY seedingrandom SYSTEM "seeding-random.sh">
<!ENTITY pattmatching SYSTEM "patt-matching.sh">
<!ENTITY isalpha SYSTEM "isalpha.sh">
<!ENTITY rnd SYSTEM "rnd.sh">
<!ENTITY du SYSTEM "Du.sh">
<!ENTITY refparams SYSTEM "ref-params.sh">
<!ENTITY indfunc SYSTEM "ind-func.sh">
<!ENTITY primes SYSTEM "primes.sh">
<!ENTITY primes2 SYSTEM "primes2.sh">
<!ENTITY vartrace SYSTEM "vartrace.sh">
<!ENTITY amiroot SYSTEM "am-i-root.sh">
<!ENTITY twodim SYSTEM "twodim.sh">
<!ENTITY arithtests SYSTEM "arith-tests.sh">
<!ENTITY incompat SYSTEM "incompat.sh">
<!ENTITY ifsh SYSTEM "ifs.sh">
<!ENTITY ifsempty SYSTEM "ifs-empty.sh">
<!ENTITY logevents SYSTEM "logevents.sh">
<!ENTITY keypress SYSTEM "keypress.sh">
<!ENTITY ddkeypress SYSTEM "dd-keypress.sh">
<!ENTITY objoriented SYSTEM "obj-oriented.sh">
<!ENTITY emptyarray SYSTEM "empty-array.sh">
<!ENTITY length SYSTEM "length.sh">
<!ENTITY monthlypmt SYSTEM "monthlypmt.sh">
<!ENTITY derpm SYSTEM "de-rpm.sh">
<!ENTITY blotout SYSTEM "blot-out.sh">
<!ENTITY readr SYSTEM "read-r.sh">
<!ENTITY cryptoquote SYSTEM "crypto-quote.sh">
<!ENTITY erase SYSTEM "erase.sh">
<!ENTITY returntest SYSTEM "return-test.sh">
<!ENTITY daysbetween SYSTEM "days-between.sh">
<!ENTITY varmatch SYSTEM "var-match.sh">
<!ENTITY recurse SYSTEM "recurse.sh">
<!ENTITY assert SYSTEM "assert.sh">
<!ENTITY intorstring SYSTEM "int-or-string.sh">
<!ENTITY ramdisk SYSTEM "ramdisk.sh">
<!ENTITY m4 SYSTEM "m4.sh">
<!ENTITY idelete SYSTEM "idelete.sh">
<!ENTITY matchstring SYSTEM "match-string.sh">
<!ENTITY bashandperl SYSTEM "bashandperl.sh">
<!ENTITY cvt SYSTEM "cvt.sh">
<!ENTITY wf SYSTEM "wf.sh">
<!ENTITY wf2 SYSTEM "wf2.sh">
<!ENTITY hypot SYSTEM "hypotenuse.sh">
<!ENTITY random2 SYSTEM "random2.sh">
<!ENTITY altbc SYSTEM "alt-bc.sh">
<!ENTITY substringex SYSTEM "substring-extraction.sh">
<!ENTITY stupscr SYSTEM "stupid-script-tricks.sh">
<!ENTITY resistor SYSTEM "resistor-inventory.sh">
<!ENTITY stackex SYSTEM "stack.sh">
<!ENTITY gcd SYSTEM "gcd.sh">
<!ENTITY selfmailer SYSTEM "self-mailer.sh">
<!ENTITY collatz SYSTEM "collatz.sh">
<!ENTITY wstrings SYSTEM "wstrings.sh">
<!ENTITY multiplication SYSTEM "multiplication.sh">
<!ENTITY sumproduct SYSTEM "sum-product.sh">
<!ENTITY userlist SYSTEM "userlist.sh">
<!ENTITY bgloop SYSTEM "background-loop.sh">
<!ENTITY tout SYSTEM "t-out.sh">
<!ENTITY csubloop SYSTEM "csubloop.sh">
<!ENTITY arrfunc SYSTEM "array-function.sh">
<!ENTITY lifeslow SYSTEM "life.sh">
<!ENTITY commentblock SYSTEM "commentblock.sh">
<!ENTITY selfdocument SYSTEM "self-document.sh">
<!ENTITY hf SYSTEM "here-function.sh">
<!ENTITY fileintegrity SYSTEM "file-integrity.sh">
<!ENTITY readnovar SYSTEM "read-novar.sh">
<!ENTITY setpos SYSTEM "set-pos.sh">
<!ENTITY revposparams SYSTEM "revposparams.sh">
<!ENTITY badread SYSTEM "badread.sh">
<!ENTITY selfexec SYSTEM "self-exec.sh">
<!ENTITY selfdestruct SYSTEM "self-destruct.sh">
<!ENTITY reassignstdout SYSTEM "reassign-stdout.sh">
<!ENTITY upperconv SYSTEM "upperconv.sh">
<!ENTITY pbook SYSTEM "pb.sh">
<!ENTITY makedict SYSTEM "makedict.sh">
<!ENTITY missingkeyword SYSTEM "missing-keyword.sh">
<!ENTITY blankrename SYSTEM "blank-rename.sh">
<!ENTITY scriptdetector SYSTEM "script-detector.sh">
<!ENTITY hexconvert SYSTEM "hexconvert.sh">
<!ENTITY factr SYSTEM "factr.sh">
<!ENTITY cannon SYSTEM "cannon.sh">
<!ENTITY agram SYSTEM "agram.sh">
<!ENTITY agram2 SYSTEM "agram2.sh">
<!ENTITY poem SYSTEM "poem.sh">
<!ENTITY soundex SYSTEM "soundex.sh">
<!ENTITY tempfilename SYSTEM "tempfile-name.sh">
<!ENTITY unitconversion SYSTEM "unit-conversion.sh">
<!ENTITY usagemessage SYSTEM "usage-message.sh">
<!ENTITY colorecho SYSTEM "color-echo.sh">
<!ENTITY selfsource SYSTEM "self-source.sh">
<!ENTITY selfcopy SYSTEM "self-copy.sh">
<!ENTITY arrowdetect SYSTEM "arrow-detect.sh">
<!ENTITY paragraphspace SYSTEM "paragraph-space.sh">
<!ENTITY brokenlink SYSTEM "broken-link.sh">
<!ENTITY continuenex SYSTEM "continue-n.example">
<!ENTITY pickcard SYSTEM "pick-card.sh">
<!ENTITY copyarray SYSTEM "CopyArray.sh">
<!ENTITY directoryinfo SYSTEM "directory-info.sh">
<!ENTITY embarr SYSTEM "embedded-arrays.sh">
<!ENTITY generatescript SYSTEM "generate-script.sh">
<!ENTITY scriptarray SYSTEM "script-array.sh">
<!ENTITY randombetween SYSTEM "random-between.sh">
<!ENTITY arrayops SYSTEM "array-ops.sh">
<!ENTITY arraystrops SYSTEM "array-strops.sh">
<!ENTITY arrayappend SYSTEM "array-append.bash">
<!ENTITY arrayassign SYSTEM "array-assign.bash">
<!ENTITY lettercount SYSTEM "letter-count.sh">
<!ENTITY lettercount2 SYSTEM "letter-count2.sh">
<!ENTITY protectliteral SYSTEM "protect_literal.sh">
<!ENTITY unprotectliteral SYSTEM "unprotect_literal.sh">
<!ENTITY usbinst SYSTEM "usb.sh">
<!ENTITY basicsreviewed SYSTEM "basics-reviewed.bash">
<!ENTITY readpipe SYSTEM "readpipe.sh">
<!ENTITY usrmnt SYSTEM "usrmnt.sh">
<!ENTITY stopwatch SYSTEM "sw.sh">
<!ENTITY dialog SYSTEM "dialog.sh">
<!ENTITY hellol SYSTEM "hello.sh">
<!ENTITY hanoi SYSTEM "hanoi.bash">
<!ENTITY horserace SYSTEM "horserace.sh">
<!ENTITY remote SYSTEM "remote.bash">
<!ENTITY musicscr SYSTEM "music.sh">
<!ENTITY prependex SYSTEM "prepend.sh">
<!ENTITY setnewpw SYSTEM "setnew-passwd.sh">
<!ENTITY badop SYSTEM "bad-op.sh">
<!ENTITY dereferencecl SYSTEM "dereference.sh">
<!ENTITY archiveweblogs SYSTEM "archiveweblogs.sh">
<!ENTITY devtcp SYSTEM "dev-tcp.sh">
<!ENTITY multipleproc SYSTEM "multiple-processes.sh">
<!ENTITY funccmdlinearg SYSTEM "func-cmdlinearg.sh">
<!ENTITY isspammer SYSTEM "is-spammer.sh">
<!ENTITY isspammer2 SYSTEM "is_spammer.bash">
<!ENTITY wgetter2 SYSTEM "wgetter2.bash">
<!ENTITY exercisingdd SYSTEM "exercising-dd.sh">
<!ENTITY quotefetch SYSTEM "quote-fetch.sh">
<!ENTITY avoidsubshell SYSTEM "avoid-subshell.sh">
<!ENTITY loggingwrapper SYSTEM "logging-wrapper.sh">
<!ENTITY dictlookup SYSTEM "dict-lookup.sh">
<!ENTITY bashpodder SYSTEM "bashpodder.sh">
<!ENTITY drawbox SYSTEM "Draw-box.sh">
<!ENTITY evalex SYSTEM "eval.example">
<!ENTITY testcgi SYSTEM "test-cgi.sh">
<!ENTITY spawnscr SYSTEM "spawn.sh">
<!ENTITY iscan SYSTEM "iscan.sh">
<!ENTITY ra2ogg SYSTEM "ra2ogg.sh">
<!ENTITY namesdata SYSTEM "names.data">
<!ENTITY hashlib SYSTEM "Hash.lib">
<!ENTITY hashexample SYSTEM "hash-example.sh">
<!ENTITY hashex2 SYSTEM "ha.sh">
<!ENTITY getoptsimple SYSTEM "getopt-simple.sh">
<!ENTITY usegetopt SYSTEM "UseGetOpt.sh">
<!ENTITY insertionsort SYSTEM "insertion-sort.bash">
<!ENTITY findsplit SYSTEM "find-splitpara.sh">
<!ENTITY prasc SYSTEM "pr-asc.sh">
<!ENTITY whx SYSTEM "whx.sh">
<!ENTITY spamlookup SYSTEM "spam-lookup.sh">
<!ENTITY mailboxgrep SYSTEM "mailbox_grep.sh">
<!ENTITY fc4upd SYSTEM "fc4upd.sh">
<!ENTITY ipscript SYSTEM "ip.sh">
<!ENTITY nightlybackup SYSTEM "nightly-backup.sh">
<!ENTITY echoparams SYSTEM "echo-params.sh">
<!ENTITY randstring SYSTEM "rand-string.sh">
<!ENTITY splitcopy SYSTEM "splitcopy.sh">
<!ENTITY padsw SYSTEM "pad.sh">
<!ENTITY soundcardon SYSTEM "soundcard-on.sh">
<!ENTITY recursiondemo SYSTEM "recursion-demo.sh">
<!ENTITY recursiondemo2 SYSTEM "recursion-def.sh">
<!ENTITY cwsolver SYSTEM "cw-solver.sh">
<!ENTITY progressbar SYSTEM "progress-bar.sh">
<!ENTITY tohtml SYSTEM "tohtml.sh">
<!ENTITY datecalc SYSTEM "date-calc.sh">
<!ENTITY brownian SYSTEM "brownian.sh">
<!ENTITY fromsh SYSTEM "from.sh">
<!ENTITY fibo SYSTEM "fibo.sh">
<!ENTITY homework SYSTEM "homework.sh">
<!ENTITY asciish SYSTEM "ascii.sh">
<!ENTITY petals SYSTEM "petals.sh">
<!ENTITY qky SYSTEM "qky.sh">
<!ENTITY maned SYSTEM "maned.sh">
<!ENTITY nim SYSTEM "nim.sh">
<!ENTITY stddev SYSTEM "sd.sh">
<!ENTITY gen0data SYSTEM "gen0">
<!ENTITY cdll SYSTEM "cdll">
<!ENTITY bashrc SYSTEM "bashrc">
<!ENTITY opprectable SYSTEM "opprec-table.sgml">
]>

<book>
  <bookinfo>
    <title>Advanced Bash-Scripting Guide</title>
    <subtitle>An in-depth exploration of the art of shell scripting</subtitle>


    <author>
      <firstname>Mendel</firstname>
      <surname>Cooper</surname>
      <affiliation>
	<orgname></orgname>
	<address><email>thegrendel@theriver.com</email></address>
      </affiliation>
    </author>


    <releaseinfo>5.4.12</releaseinfo>
    <pubdate>23 September 2008</pubdate>
    <isbn>978-1-4357-5219-1</isbn>



    <revhistory>

      <revision>
        <revnumber>5.2</revnumber>
        <date>16 Mar 2008</date>
        <authorinitials>mc</authorinitials>
	<revremark>'SILVERBERRY' release: Important Update.</revremark>
      </revision>

      <revision>
        <revnumber>5.3</revnumber>
        <date>05 May 2008</date>
        <authorinitials>mc</authorinitials>
	<revremark>'GOLDENBERRY' release: Minor Update.</revremark>
      </revision>

      <revision>
        <revnumber>5.4</revnumber>
        <date>21 July 2008</date>
        <authorinitials>mc</authorinitials>
	<revremark>'ANGLEBERRY' release: Major Update.</revremark>
      </revision>

    </revhistory>


    <abstract>

      <para>This tutorial assumes no previous knowledge of
	scripting or programming, but progresses rapidly toward an
	intermediate/advanced level of instruction <emphasis>. . . all
	the while sneaking in little nuggets of <trademark
	class=registered>UNIX</trademark> wisdom and lore</emphasis>. It
	serves as a textbook, a manual for self-study, and a reference and
	source of knowledge on shell scripting techniques. The exercises
	and heavily-commented examples invite active reader participation,
	under the premise that <userinput>the only way to really learn
	scripting is to write scripts</userinput>.</para>

      <para>This book is suitable for classroom use as a general
        introduction to programming concepts.</para>


      <para><anchor id="where_tarball"></para>

      <para><ulink
        url="http://personal.riverusers.com/~thegrendel/abs-guide-5.4.tar.bz2">
        The latest update of this document</ulink>, as an archived, <link
	linkend="bzipref">bzip2-ed</link> <quote>tarball</quote>
	including both the SGML source and rendered HTML, may
	be downloaded from the author's home site. A <ulink
	url="http://www.tldp.org/LDP/abs/abs-guide.pdf">pdf
	version</ulink> is also available (<ulink
	url="http://personal.riverusers.com/~thegrendel/abs-guide.pdf"> pdf mirror
	site</ulink>). See the <ulink
	url="http://personal.riverusers.com/~thegrendel/Change.log">change
	log</ulink> for a revision history.</para>

    </abstract>
  </bookinfo>

  <dedication>
    <para>For Anita, the source of all the magic</para>
  </dedication>



  <part label="Part 1" id="part1">
    <title>Introduction</title>

  <partintro>  

    <para><anchor id="whatsascript"></para>

    <para>The shell is a command interpreter. More than just the
      insulating layer between the operating system kernel and the user,
      it's also a fairly powerful programming language.  A shell program,
      called a <firstterm>script</firstterm>, is an easy-to-use tool for
      building applications by <quote>gluing together</quote> system
      calls, tools, utilities, and compiled binaries.  Virtually the
      entire repertoire of UNIX commands, utilities, and tools is
      available for invocation by a shell script. If that were
      not enough, internal shell commands, such as testing and loop
      constructs, lend additional power and flexibility to scripts.
      Shell scripts are especially well suited for administrative
      system tasks and other routine repetitive tasks not requiring the
      bells and whistles of a full-blown tightly structured programming
      language.</para>

  </partintro>  

  <chapter id="why-shell">
    <title>Why Shell Programming?</title>

    <epigraph>
      <para>No programming language is perfect. There is not even a single
        best language; there are only languages well suited or perhaps poorly
	suited for particular purposes.</para>
      <para>--Herbert Mayer</para>
    </epigraph>
    
    
    <para>A working knowledge of shell scripting is essential to anyone
      wishing to become reasonably proficient at system administration,
      even if they do not anticipate ever having to actually write a
      script. Consider that as a Linux machine boots up, it executes the
      shell scripts in <filename class="directory">/etc/rc.d</filename>
      to restore the system configuration and set up services. A detailed
      understanding of these startup scripts is important for analyzing
      the behavior of a system, and possibly modifying it.</para>

    <para>The craft of scripting is not hard to master,
      since the scripts can be built in bite-sized sections and there
      is only a fairly small set of shell-specific operators and options

      <footnote><para>These are referred to as <link
        linkend="builtinref">builtins</link>, features internal to the
        shell.</para></footnote>

      to learn. The syntax is simple and straightforward, similar to
      that of invoking and chaining together utilities at the command
      line, and there are only a few <quote>rules</quote> governing
      their use. Most short scripts work right the first time, and
      debugging even the longer ones is straightforward.</para>

    <para>A shell script is a quick-and-dirty method of prototyping
      a complex application. Getting even a limited subset of
      the functionality to work in a script is often a useful
      first stage in project development. This way, the structure
      of the application can be tested and played with, and the
      major pitfalls found before proceeding to the final coding
      in <firstterm>C</firstterm>, <firstterm>C++</firstterm>,
      <firstterm>Java</firstterm>, <link linkend="perlref">Perl</link>,
      or <firstterm>Python</firstterm>.</para>

    <para>Shell scripting hearkens back to the classic UNIX philosophy
      of breaking complex projects into simpler subtasks, of chaining
      together components and utilities. Many consider this a better,
      or at least more esthetically pleasing approach to problem solving
      than using one of the new generation of high powered all-in-one
      languages, such as <firstterm>Perl</firstterm>, which attempt to
      be all things to all people, but at the cost of forcing you to
      alter your thinking processes to fit the tool.</para>

    <para>According to <link linkend="mayerref">Herbert Mayer</link>,
      <quote>a useful language needs arrays, pointers,
	and a generic mechanism for building data structures.</quote>
	By these criteria, shell scripting falls somewhat short of being
	<quote>useful.</quote> Or, perhaps not. . . .</para>


   <sidebar>

    <para>When not to use shell scripts

      <itemizedlist>

	<listitem>
	  <para>Resource-intensive tasks, especially where speed is
	    a factor (sorting, hashing, recursion

            <footnote><para>Although <link linkend="recursionref0">recursion
	      <emphasis>is</emphasis> possible in a shell script</link>,
	      it tends to be slow and its implementation is often
	      an <link linkend="fiboref">ugly kludge</link>.</para></footnote>
	    
	    ...)</para>

	</listitem> <listitem>
	  <para>Procedures involving heavy-duty math operations,
	    especially floating point arithmetic, arbitrary
	    precision calculations, or complex numbers (use
	    <firstterm>C++</firstterm> or <firstterm>FORTRAN</firstterm>
	    instead)</para>
	</listitem> <listitem>
	  <para>Cross-platform portability required (use
	    <firstterm>C</firstterm> or <firstterm>Java</firstterm>
	    instead)</para>
	</listitem> <listitem>
	  <para>Complex applications, where structured programming is
	    a necessity (type-checking of variables, function
	    prototypes, etc.)</para>
	</listitem> <listitem>
	  <para>Mission-critical applications upon which you are betting the
	     future of the company</para>
	</listitem> <listitem>
	  <para>Situations where <emphasis>security</emphasis> is
	    important, where you need to guarantee the integrity of
	    your system and protect against intrusion, cracking, and
	    vandalism</para>
	</listitem> <listitem>
	  <para>Project consists of subcomponents with interlocking
	    dependencies</para>
	</listitem> <listitem>
	  <para>Extensive file operations required
	    (<firstterm>Bash</firstterm> is limited to serial file access,
	    and that only in a particularly clumsy and inefficient
	    line-by-line fashion.)</para>
	</listitem> <listitem>
	  <para>Need native support for multi-dimensional arrays</para>
	</listitem> <listitem>
	  <para>Need data structures, such as linked lists or trees</para>
	</listitem> <listitem>
	  <para>Need to generate / manipulate graphics or GUIs</para>
	</listitem> <listitem>
	  <para>Need direct access to system hardware</para>
	</listitem> <listitem>
	  <para>Need port or <link linkend="socketref">socket</link> I/O</para>
	</listitem> <listitem>
	  <para>Need to use libraries or interface with legacy code</para>
	</listitem> <listitem>
	  <para>Proprietary, closed-source applications (Shell scripts
	    put the source code right out in the open for all the world
	    to see.)</para>
	    
	</listitem>
      </itemizedlist></para>

    <para>If any of the above applies, consider a more powerful scripting
      language -- perhaps <firstterm>Perl</firstterm>,
      <firstterm>Tcl</firstterm>, <firstterm>Python</firstterm>,
      <firstterm>Ruby</firstterm> -- or possibly a
      compiled language such as <firstterm>C</firstterm>,
      <firstterm>C++</firstterm>, or <firstterm>Java</firstterm>. Even
      then, prototyping the application as a shell script might still
      be a useful development step.</para>

   </sidebar>


    <para><anchor id="bashdef"></para>
    <para>We will be using <acronym>Bash</acronym>, an acronym for
      <quote>Bourne-Again shell</quote> and a pun on Stephen Bourne's
      now classic <firstterm>Bourne</firstterm> shell. Bash has become
      a <foreignphrase>de facto</foreignphrase> standard for shell
      scripting on most flavors of UNIX. Most of the principles this
      book covers apply equally well to scripting with other shells,
      such as the <firstterm>Korn Shell</firstterm>, from which Bash
      derives some of its features,

       <footnote><para>Many of the features of <firstterm>ksh88</firstterm>,
	 and even a few from the updated <firstterm>ksh93</firstterm>
	 have been merged into Bash.</para></footnote>

      and the <firstterm>C Shell</firstterm> and its variants. (Note that
      <firstterm>C Shell</firstterm> programming is not recommended due to
      certain inherent problems, as pointed out in an October, 1993 <ulink
      url="http://www.etext.org/Quartz/computer/unix/csh.harmful.gz">Usenet
      post</ulink> by Tom Christiansen.)  </para>

    <para>What follows is a tutorial on shell scripting. It relies
      heavily on examples to illustrate various features of the shell.
      The example scripts work -- they've been tested, insofar as was
      possible -- and some of them are even useful in real life. The
      reader can play with the actual working code of the examples
      in the source archive (<filename>scriptname.sh</filename> or
      <filename>scriptname.bash</filename>),

         <footnote><para>By convention, user-written shell scripts that are
	 Bourne shell compliant generally take a name with a
	 <filename>.sh</filename> extension.  System scripts, such as
	 those found in <filename class="directory">/etc/rc.d</filename>,
	 do not conform to this nomenclature.</para></footnote>

      give them <firstterm>execute</firstterm> permission
      (<userinput>chmod u+rx scriptname</userinput>),
      then run them to see what happens. Should the source
      archive not be available, then cut-and-paste from the <ulink
      url="http://www.tldp.org/LDP/abs/abs-guide.html.tar.gz">HTML</ulink> or
      <ulink url="http://www.tldp.org/LDP/abs/abs-guide.pdf">pdf</ulink>
      rendered versions. Be aware that some of the scripts presented here
      introduce features before they are explained, and this may require
      the reader to temporarily skip ahead for enlightenment.</para>

    <para>Unless otherwise noted, <ulink
       url="mailto:thegrendel@theriver.com">the author</ulink> of this
       book wrote the example scripts that follow.</para>

    <epigraph>
      <para>His countenance was bold and bashed not.</para>
      <para>--Edmund Spenser</para>
    </epigraph>

  </chapter> <!-- Why Shell Programming? -->


  <chapter id="sha-bang">
    <title>Starting Off With a Sha-Bang</title>

    <epigraph>
      <para>Shell programming is a 1950s juke box . . .</para> 
      <para>--Larry Wall</para>
    </epigraph>

    <para>In the simplest case, a script is nothing more than a list of system
      commands stored in a file. At the very least, this saves the
      effort of retyping that particular sequence of commands each time
      it is invoked.</para>

    <example id="ex1">
      <title><firstterm>cleanup</firstterm>: A script to clean up the log
      files in /var/log </title> <programlisting>&ex1;</programlisting>
    </example>

    <para>There is nothing unusual here, only a set of commands that
      could just as easily be invoked one by one from the command line on
      the console or in an <firstterm>xterm</firstterm>. The advantages of
      placing the commands in a script go beyond not having to retype them
      time and again. The script becomes a <emphasis>tool</emphasis>,
      and can easily be modified or customized for a particular
      application.</para>

    <example id="ex1a">
      <title><firstterm>cleanup</firstterm>: An improved clean-up
      script</title> <programlisting>&ex1a;</programlisting>
    </example>

    <para>Now that's beginning to look like a real script. But we can
      go even farther . . .</para>

    <example id="ex2">
      <title><firstterm>cleanup</firstterm>: An enhanced
      and generalized version of above scripts.</title>
      <programlisting>&ex2;</programlisting>
    </example>

    <para>Since you may not wish to wipe out the entire system log,
      this version of the script keeps the last section of the message
      log intact. You will constantly discover ways of fine-tuning
      previously written scripts for increased effectiveness.</para>

    <para><anchor id="shabangref"></para>
    <para><anchor id="magnumref">The
      <firstterm><indexterm>
	  <primary>sha-bang</primary>
	</indexterm> sha-bang</firstterm>
      (<token>
	<indexterm>
	  <primary>#!</primary>
	</indexterm> #!</token>)
	  <footnote><para>Also seen in the literature as
	  <firstterm>she-bang</firstterm> or <firstterm>sh-bang</firstterm>.
	  This derives from the concatenation of the tokens
	  <firstterm>sharp</firstterm> (<token>#</token>) and
	  <firstterm>bang</firstterm> (<token>!</token>).</para></footnote>
	at the head of a script
      tells your system that this file is a set of commands to be fed
      to the command interpreter indicated. The <token>#!</token> is
      actually a two-byte

        <footnote>
	  <para>Some flavors of UNIX (those based on 4.2 BSD)
          allegedly take a four-byte magic number, requiring
          a blank after the <token>!</token> --
	  <userinput>#! /bin/sh</userinput>. <ulink
	  url="http://www.in-ulm.de/~mascheck/various/shebang/#details">
	  According to Sven Mascheck</ulink> this is probably a myth.</para>
	  </footnote>

	<indexterm>
	  <primary>magic number</primary>
	</indexterm>
	<firstterm>magic number</firstterm>, a special marker that
	designates a file type, or in this case an executable shell
	script (type <userinput>man magic</userinput> for more
	details on this fascinating topic). Immediately following
	the <firstterm>sha-bang</firstterm> is a <firstterm>path
	name</firstterm>. This is the path to the program that interprets
	the commands in the script, whether it be a shell, a programming
	language, or a utility. This command interpreter then executes
	the commands in the script, starting at the top (line following
	the <firstterm>sha-bang</firstterm> line), ignoring comments.

	  <footnote>
	    <para>The <token>#!</token> line in a shell script
	      will be the first thing the command interpreter
	      (<command>sh</command> or <command>bash</command>)
	      sees. Since this line begins with a <token>#</token>,
	      it will be correctly interpreted as a comment when the
	      command interpreter finally executes the script. The
	      line has already served its purpose - calling the command
	      interpreter.</para>
	    <para>If, in fact, the script includes an
	      <emphasis>extra</emphasis> <token>#!</token> line, then
	      <command>bash</command> will interpret it as a comment.
	        <programlisting>#!/bin/bash

echo "Part 1 of script."
a=1

#!/bin/bash
# This does *not* launch a new script.

echo "Part 2 of script."
echo $a  # Value of $a stays at 1.</programlisting></para>
	   </footnote>

	</para>


    <para><programlisting>#!/bin/sh
#!/bin/bash
#!/usr/bin/perl
#!/usr/bin/tcl
#!/bin/sed -f
#!/usr/awk -f</programlisting></para>

    <para>Each of the above script header lines calls a different command
      interpreter, be it <filename>/bin/sh</filename>, the default shell
      (<command>bash</command> in a Linux system) or otherwise.

        <footnote>
	  <para>This allows some cute tricks.</para>
	  <para><programlisting>#!/bin/rm
# Self-deleting script.

# Nothing much seems to happen when you run this... except that the file disappears.

WHATEVER=65

echo "This line will never print (betcha!)."

exit $WHATEVER  # Doesn't matter. The script will not exit here.
                # Try an echo $? after script termination.
                # You'll get a 0, not a 65.</programlisting></para>
      <para>Also, try starting a <filename>README</filename> file with a
        <userinput>#!/bin/more</userinput>, and making it executable.
        The result is a self-listing documentation file. (A <link
	linkend="heredocref">here document</link> using
	<link linkend="catref">cat</link> is possibly a better alternative
	-- see <xref linkend="ex71">).</para>
	</footnote>

      Using <userinput>#!/bin/sh</userinput>, the default Bourne shell
      in most commercial variants of UNIX, makes the script <link
      linkend="portabilityissues">portable</link> to non-Linux machines,
      though you <link linkend="binsh">sacrifice Bash-specific
      features</link>.  The script will, however, conform to the
      <acronym>POSIX</acronym>

	 <footnote>
	 <para><anchor id="posix2ref"><emphasis role="strong">P</emphasis>ortable
	 <emphasis role="strong">O</emphasis>perating
	 <emphasis role="strong">S</emphasis>ystem <emphasis
	 role="bold">I</emphasis>nterface, an attempt to
	 standardize UNI<emphasis role="strong">X</emphasis>-like
	 OSes. The POSIX specifications are listed on the <ulink
	 url="http://www.opengroup.org/onlinepubs/007904975/toc.htm">Open
	 Group site</ulink>.</para>
	 </footnote>

      <command>sh</command> standard.</para>

    <para>Note that the path given at the <quote>sha-bang</quote> must
      be correct, otherwise an error message -- usually <quote>Command
      not found.</quote> -- will be the only result of running the
      script.
        <footnote><para>To avoid this possibility, a script may begin
	  with a <link linkend="envv2ref">#!/bin/env bash</link>
	  <firstterm>sha-bang</firstterm> line. This may be
	  useful on UNIX machines where <firstterm>bash</firstterm>
	  is not located in <filename
	  class="directory">/bin</filename></para></footnote>
      
      </para>

    <para><token>#!</token> can be omitted if the script consists only
      of a set of generic system commands, using no internal
      shell directives.  The second example, above, requires the
      initial <token>#!</token>, since the variable assignment line,
      <userinput>lines=50</userinput>, uses a shell-specific construct.
	<footnote><para>If <firstterm>Bash</firstterm> is your default
	shell, then the <token>#!</token> isn't necessary at the
	beginning of a script.	However, if launching a script from
	a different shell, such as <firstterm>tcsh</firstterm>,
	then you <emphasis>will</emphasis> need the
	<token>#!</token>.</para></footnote>
      Note again that <userinput>#!/bin/sh</userinput> invokes the default
      shell interpreter, which defaults to <filename>/bin/bash</filename>
      on a Linux machine.</para>


      <tip>
      <para>This tutorial encourages a modular approach
	to constructing a script. Make note of and collect
	<quote>boilerplate</quote> code snippets that might be useful
	in future scripts. Eventually you will build quite an extensive
	library of nifty routines. As an example, the following script
	prolog tests whether the script has been invoked with the correct
	number of parameters.</para>

	<para><programlisting>E_WRONG_ARGS=65
script_parameters="-a -h -m -z"
#                  -a = all, -h = help, etc.

if [ $# -ne $Number_of_expected_args ]
then
  echo "Usage: `basename $0` $script_parameters"
  # `basename $0` is the script's filename.
  exit $E_WRONG_ARGS
fi</programlisting>
      </para>

      <para>Many times, you will write a script that carries out one
        particular task. The first script in this chapter is an
        example of this. Later, it might occur to you to generalize
        the script to do other, similar tasks. Replacing the literal
        (<quote>hard-wired</quote>) constants by variables is a step in
        that direction, as is replacing repetitive code blocks by <link
        linkend="functionref">functions</link>.</para>

      </tip>



    <sect1 id="invoking">
      <title>Invoking the script</title>

      <para>Having written the script, you can invoke it by <userinput>sh
	scriptname</userinput>,

	  <footnote><para>Caution: invoking a <firstterm>Bash</firstterm>
	  script by <userinput>sh scriptname</userinput> turns off
	  Bash-specific extensions, and the script may therefore fail
	  to execute.</para></footnote>

	or alternatively <userinput>bash scriptname</userinput>. (Not
	recommended is using <userinput>sh &lt;scriptname</userinput>,
	since this effectively disables reading from
	<link linkend="stdinoutdef"><filename>stdin</filename></link>
	within the script.) Much more convenient is to make
	the script itself directly executable with a <link
	linkend="chmodref">chmod</link>.

	<variablelist>
	  <varlistentry>
	    <term>Either:</term> <listitem>
	      <para><userinput>chmod 555 scriptname</userinput> (gives
	      everyone read/execute permission)
	        <footnote><para>A script needs <firstterm>read</firstterm>, as
		well as execute permission for it to run, since the shell
		needs to be able to read it.</para></footnote>
	      </para>
	    </listitem>
	  </varlistentry> <varlistentry>
	    <term>or</term> <listitem>
	      <para><userinput>chmod +rx scriptname</userinput> (gives
	      everyone read/execute permission)</para> <para><userinput>chmod
	      u+rx scriptname</userinput> (gives only the
		script owner read/execute permission)</para>
	    </listitem>
	  </varlistentry>
	</variablelist>
      </para>

      <para>Having made the script executable, you may now test it by
	<userinput>./scriptname</userinput>.
	
	  <footnote><para>Why not simply invoke the script with
	  <userinput>scriptname</userinput>? If the directory you
	  are in (<link linkend="pwdref">$PWD</link>) is where
	  <filename>scriptname</filename> is located, why doesn't
	  this work? This fails because, for security reasons, the
	  current directory (<filename class="directory">./</filename>)
	  is not by default included in a user's <link
	  linkend="pathref">$PATH</link>. It is therefore necessary to
	  explicitly invoke the script in the current directory with
	  a <userinput>./scriptname</userinput>.</para></footnote>

	If it begins with a <quote>sha-bang</quote> line, invoking the
	script calls the correct command interpreter to run it.</para>

      <para>As a final step, after testing and debugging,
	you would likely want to move it to <filename
	class="directory">/usr/local/bin</filename> (as
	<firstterm>root</firstterm>, of course), to make the script
	available to yourself and all other users as a systemwide
	executable.  The script could then be invoked by simply typing
	<command>scriptname</command> <keycap>[ENTER]</keycap> from the
	command line.</para>

    </sect1> <!-- Invoking the script -->


    <sect1 id="prelimexer">
      <title>Preliminary Exercises</title>

      <orderedlist>

        <listitem>
	<para>System administrators often write scripts to automate common
	  tasks. Give several instances where such scripts would be
	  useful.</para>
	</listitem>  

	<listitem>  
	<para>Write a script that upon invocation shows the
	  <link linkend="dateref">time and date</link>, <link
	  linkend="whoref">lists all logged-in users</link>, and gives
	  the system <link linkend="uptimeref">uptime</link>. The script
	  then <link linkend="ioredirref">saves this information</link>
	  to a logfile.</para>
	</listitem>

      </orderedlist>

    </sect1> <!-- Preliminary Exercises -->

  </chapter> <!-- Starting Off With a Sha-Bang -->


  </part> <!-- Part 1 (Introduction) -->



  <part label="Part 2" id="part2">
    <title>Basics</title>


  <chapter id="special-chars">
    <title>Special Characters</title>

      <para>What makes a character <firstterm>special</firstterm>?
        If it has a meaning beyond its <firstterm>literal
        meaning</firstterm>, a <link
	linkend="metameaningref">meta-meaning</link>, then we
	refer to it as a <firstterm>special character</firstterm>.</para>

      <variablelist id="scharlist">
        <title><anchor id="scharlist1">Special Characters Found In
          Scripts and Elsewhere</title>

	<varlistentry><term><anchor id="hashmarkref"><token>#</token></term>
	  <indexterm>
	    <primary>#</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>#</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>comment</primary>
	  </indexterm>	  
	  <listitem>
	    <formalpara><title>Comments</title>
	      <para>Lines beginning with a <token>#</token>
	      (with the exception of <link linkend="magnumref">
	      <token>#!</token></link>) are comments and will
	      <emphasis>not</emphasis> be executed.</para>
	    </formalpara>

	    <para><programlisting># This line is a comment.</programlisting></para>

	    <para>Comments may also occur following the end of a command.</para>
	    
	    <para><programlisting>echo "A comment will follow." # Comment here.
#                            ^ Note whitespace before #</programlisting></para>

	    <para><anchor id="wsbcomm"></para>
	    <para>Comments may also follow <link
	    linkend="whitespaceref">whitespace</link> at the beginning
	    of a line.</para>

	    <para><programlisting>	# A tab precedes this comment.</programlisting></para>

	    <caution><para>A command may not follow a comment on the
	      same line. There is no method of terminating the comment,
	      in order for <quote>live code</quote> to begin on the same
	      line. Use a new line for the next command.</para></caution>

	    <note><para>Of course, a <link linkend="quotingref">quoted</link>
	    or an <link linkend="escp">escaped</link> <token>#</token>
	    in an <link linkend="echoref">echo</link> statement does
	    <emphasis>not</emphasis> begin a comment. Likewise, a
	    <token>#</token> appears in <link linkend="psub2">certain
	    parameter-substitution constructs</link> and in <link
	    linkend="numconstants"> numerical constant expressions</link>.

	    <programlisting>echo "The # here does not begin a comment."
echo 'The # here does not begin a comment.'
echo The \# here does not begin a comment.
echo The # here begins a comment.

echo ${PATH#*:}       # Parameter substitution, not a comment.
echo $(( 2#101011 ))  # Base conversion, not a comment.

# Thanks, S.C.</programlisting>

	  The standard <link linkend="quotingref">quoting and
	  escape</link> characters (&quot; ' \) escape the #.
	  </para></note>

	  <para>Certain <link linkend="psorex1">pattern matching
	    operations</link> also use the <token>#</token>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry><term><anchor id="semicolonref"><token>;</token></term>
	  <indexterm>
	    <primary>;</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>;</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>separator</primary>
	  </indexterm>	  
	  
	  <listitem>
	    <formalpara><title>Command separator [semicolon]</title>
	      <para>Permits putting two or more commands on the same
	        line.</para>
	    </formalpara>

	    <para>
	      <programlisting>echo hello; echo there


if [ -x "$filename" ]; then    #  Note that "if" and "then" need whitespace
                               #+ separation. Why?
  echo "File $filename exists."; cp $filename $filename.bak
else
  echo "File $filename not found."; touch $filename
fi; echo "File test complete."</programlisting>
</para>
	    
	    <para>Note that the <quote><token>;</token></quote>
	      <link linkend="findref0">sometimes needs to be
	      <firstterm>escaped</firstterm></link>.</para>

	    </listitem>
	</varlistentry>

	<varlistentry><term><token>;;</token></term>
	  <indexterm>
	    <primary>;;</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>case</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>;;</primary>
	  </indexterm>	  
	  
	  <listitem>
	    <formalpara><title>Terminator in a <link
	      linkend="caseesac1">case</link> option [double semicolon]</title>
	      <para><anchor id="doublesemicolon"></para>
	    </formalpara>

	    <para><programlisting>case "$variable" in
  abc)  echo "\$variable = abc" ;;
  xyz)  echo "\$variable = xyz" ;;
esac</programlisting></para>

	    </listitem>
	</varlistentry>


	<varlistentry><term><token>.</token></term>
	  <indexterm>
	    <primary>.</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>.</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>dot command</primary>
	  </indexterm>	  
	  <indexterm>
	    <primary>source</primary>
	  </indexterm>	  

	  <listitem>
	    <para><anchor id="dotref"></para>
	    <formalpara><title><quote>dot</quote> command [period]</title>
	      <para>Equivalent to <link
		linkend="sourceref">source</link> (see
		<xref linkend="ex38">). This is a bash <link
		linkend="builtinref">builtin</link>.</para>
	    </formalpara>

	    </listitem>
	</varlistentry>


	<varlistentry><term><token>.</token></term>
	  <indexterm>
	    <primary>.</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>.</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>filename</primary>
	  </indexterm>	  
	  <indexterm>
	    <primary>part of a filename</primary>
	  </indexterm>	  

	  <listitem>
	    <formalpara><title><quote>dot</quote>, as a component of a filename</title>
              <para>When working with filenames, a leading dot is the prefix
		of a <quote>hidden</quote> file, a file that an
		<link linkend="lsref">ls</link> will not normally show.
	        <screen><prompt>bash$ </prompt><userinput>touch .hidden-file</userinput>
<prompt>bash$ </prompt><userinput>ls -l</userinput>	      
<computeroutput>total 10
 -rw-r--r--    1 bozo      4034 Jul 18 22:04 data1.addressbook
 -rw-r--r--    1 bozo      4602 May 25 13:58 data1.addressbook.bak
 -rw-r--r--    1 bozo       877 Dec 17  2000 employment.addressbook</computeroutput>


<prompt>bash$ </prompt><userinput>ls -al</userinput>	      
<computeroutput>total 14
 drwxrwxr-x    2 bozo  bozo      1024 Aug 29 20:54 ./
 drwx------   52 bozo  bozo      3072 Aug 29 20:51 ../
 -rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 data1.addressbook
 -rw-r--r--    1 bozo  bozo      4602 May 25 13:58 data1.addressbook.bak
 -rw-r--r--    1 bozo  bozo       877 Dec 17  2000 employment.addressbook
 -rw-rw-r--    1 bozo  bozo         0 Aug 29 20:54 .hidden-file</computeroutput>
	        </screen>
	      </para>
	    </formalpara>

	      <para><anchor id="dotdirectory"></para>
	      <para>When considering directory names, <firstterm>a single
		dot</firstterm> represents the current working directory,
		and <firstterm>two dots</firstterm> denote the parent
		directory.</para>

	      <para>
	        <screen>
<prompt>bash$ </prompt><userinput>pwd</userinput>
<computeroutput>/home/bozo/projects</computeroutput>

<prompt>bash$ </prompt><userinput>cd .</userinput>
<prompt>bash$ </prompt><userinput>pwd</userinput>
<computeroutput>/home/bozo/projects</computeroutput>

<prompt>bash$ </prompt><userinput>cd ..</userinput>
<prompt>bash$ </prompt><userinput>pwd</userinput>
<computeroutput>/home/bozo/</computeroutput>
	        </screen>
	      </para>

	      <para>The <firstterm>dot</firstterm> often appears as the
	        destination (directory) of a file movement command,
                in this context meaning <firstterm>current
                directory</firstterm>.</para>
	      
	      <para>
	        <screen>
<prompt>bash$ </prompt><userinput>cp /home/bozo/current_work/junk/* .</userinput>
	        </screen>
		Copy all the <quote>junk</quote> files to
		<link linkend="pwdref">$PWD</link>.</para>

	  </listitem>
	</varlistentry>


	<varlistentry><term><token>.</token></term>
	  <indexterm>
	    <primary>.</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>.</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>character match</primary>
	  </indexterm>	  
	  <indexterm>
	    <primary>match single character</primary>
	  </indexterm>	  

	  <listitem>
	    <formalpara><title><quote>dot</quote> character match</title>
	      <para>When <link linkend="regexdot">matching
	        characters</link>, as part of a <link
	        linkend="regexref">regular expression</link>, a
		<quote>dot</quote> <link linkend="regexdot">matches a
		single character</link>.</para>
	    </formalpara>

	    </listitem>
	</varlistentry>


	<varlistentry>
	  <term><token>"</token></term>
	  <listitem><formalpara><title><link linkend="dblquo">partial
	    quoting</link> [double quote]</title>
	      <para><emphasis>"STRING"</emphasis> preserves (from
	      interpretation) most of the special characters within
	      <emphasis>STRING</emphasis>. See <xref
	      linkend="quoting">.</para>
	    </formalpara> </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>'</token></term>
	  <listitem><formalpara><title><link linkend="snglquo">full
	    quoting</link> [single quote]</title>
	      <para><emphasis>'STRING'</emphasis> preserves all special
	      characters within <emphasis>STRING</emphasis>. This is a
	      stronger form of quoting than <emphasis>"STRING"</emphasis>.
	      See <xref linkend="quoting">.</para>
	    </formalpara> </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>,</token></term>
	  <listitem><formalpara><title><link linkend="commaop">comma
	    operator</link></title>
	      <para>The <firstterm>comma operator</firstterm>

		<footnote><para><anchor id="operatordef">An
		  <firstterm>operator</firstterm> is an agent that carries
		  out an <firstterm>operation</firstterm>. Some examples
		  are the common <link linkend="arops1">arithmetic
		  operators</link>, <command>+ - * /</command>. In
		  Bash, there is some overlap between the concepts
		  of <firstterm>operator</firstterm> and <link
		  linkend="keywordref">keyword</link>.</para></footnote>

	      links together a
		series of arithmetic operations. All are evaluated,
		but only the last one is returned.
	       <programlisting>let "t2 = ((a = 9, 15 / 3))"  # Set "a =
	       9" and "t2 = 15 / 3"</programlisting>
	      </para>
	    </formalpara>

	    <para>The <firstterm>comma</firstterm> operator can also
              concatenate strings.
	       <programlisting>for file in /{,usr/}bin/*calc
#             ^    Find all executable files ending in "calc"
#+                 in /bin and /usr/bin directories.
do
        if [ -x "$file" ]
        then
          echo $file
        fi
done

# /bin/ipcalc
# /usr/bin/kcalc
# /usr/bin/oidcalc
# /usr/bin/oocalc


# Thank you, Rory Winston, for pointing this out.</programlisting>
	      </para>

          </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>\</token></term>
	  <listitem><formalpara><title><link linkend="escp">escape</link> [backslash]</title>
	      <para>A quoting mechanism for single characters.</para>
	    </formalpara>
	      
	      <para><userinput>\X</userinput>
		<firstterm>escapes</firstterm> the character
		<emphasis>X</emphasis>. This has the effect of
		<quote>quoting</quote> <emphasis>X</emphasis>, equivalent
		to <emphasis>'X'</emphasis>.  The <token>\</token> may
		be used to quote <token>"</token> and <token>'</token>,
		so they are expressed literally.</para>
	      <para>See <xref linkend="quoting"> for an in-depth explanation
	        of escaped characters.</para>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>/</token></term>
	  <listitem><formalpara><title>Filename path separator [forward slash]</title>
	      <para>Separates the components of a filename (as in
	        <filename>/home/bozo/projects/Makefile</filename>).</para>
	    </formalpara>
	    <para>This is also the division <link
	      linkend="arops1">arithmetic operator</link>.</para>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="backticksref"><token>`</token></term>
	  <listitem><formalpara><title><link
	  linkend="commandsubref">command substitution</link></title>
	      <para>The <command>`command`</command> construct makes
		available the output of <command>command</command>
		for assignment to a variable. This is also known as
		<link linkend="backquotesref">backquotes</link> or
		backticks.</para></formalpara> </listitem>
	</varlistentry>

	<varlistentry><term><anchor id="colon0ref"><token>:</token></term>
	  <indexterm>
	    <primary>:</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>:</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>null command</primary>
	  </indexterm>	  
	  <indexterm>
	    <primary>true</primary>
	  </indexterm>	  
	  <indexterm>
	    <primary>endless loop</primary>
	  </indexterm>	  

	  <listitem>
	    <para><anchor id="nullref"></para>
	    <formalpara><title>null command [colon]</title>
	      <para>This is the shell equivalent of a
		<quote>NOP</quote> (<replaceable>no op</replaceable>, a
		do-nothing operation). It may be considered a synonym for
		the shell builtin <link linkend="trueref">true</link>. The
		<quote><token>:</token></quote> command is itself a
		<firstterm>Bash</firstterm> <link
		linkend="builtinref">builtin</link>, and its <link
		linkend="exitstatusref">exit status</link> is
		<firstterm>true</firstterm>
		(<returnvalue>0</returnvalue>).</para>
	    </formalpara>

	    <para><programlisting>:
echo $?   # 0</programlisting></para>


	    <para>Endless loop:</para>

	    <para><programlisting>
while :
do
   operation-1
   operation-2
   ...
   operation-n
done

# Same as:
#    while true
#    do
#      ...
#    done</programlisting>
	    </para>

	    <para>Placeholder in if/then test:</para>

	    <para><programlisting>
if condition
then :   # Do nothing and branch ahead
else     # Or else ...
   take-some-action
fi</programlisting>
	    </para>

	    <para>Provide a placeholder where a binary operation is
	      expected, see <xref linkend="arithops"> and <link
	      linkend="defparam">default parameters</link>.</para>

	    <para><programlisting>: ${username=`whoami`}
# ${username=`whoami`}   Gives an error without the leading :
#                        unless "username" is a command or builtin...</programlisting>
</para>

	    <para>Provide a placeholder where a command is expected in a
	      <link linkend="heredocref">here document</link>. See <xref
	      linkend="anonheredoc">.</para>

	    <para>Evaluate string of variables using
		<link linkend="paramsubref">parameter substitution</link>
		(as in <xref linkend="ex6">).

	    <programlisting>: ${HOSTNAME?} ${USER?} ${MAIL?}
#  Prints error message
#+ if one or more of essential environmental variables not set.</programlisting>
</para>
            
            <para><command><link linkend="exprepl1">Variable expansion / substring
	      replacement</link></command>.</para>
	    
	    <para>In combination with the <token>&gt;</token> <link
	      linkend="ioredirref">redirection operator</link>,
	      truncates a file to zero length, without changing its
	      permissions. If the file did not previously exist,
	      creates it.

	      <programlisting>: > data.xxx   # File "data.xxx" now empty.	      

# Same effect as   cat /dev/null >data.xxx
# However, this does not fork a new process, since ":" is a builtin.</programlisting>
              See also <xref linkend="ex12">.</para>

	    <para>In combination with the <token>&gt;&gt;</token>
	      redirection operator, has no effect on a pre-existing
	      target file (<userinput>: &gt;&gt; target_file</userinput>).
	      If the file did not previously exist, creates it.</para>

	    <note><para>This applies to regular files, not pipes,
	      symlinks, and certain special files.</para></note>


	    <para>May be used to begin a comment line, although this is not
	      recommended. Using <token>#</token> for a comment turns
	      off error checking for the remainder of that line, so
	      almost anything may appear in a comment. However,
	      this is not the case with
	      <token>:</token>.
	      <programlisting>: This is a comment that generates an error, ( if [ $x -eq 3] ).</programlisting>
	    </para>

	    <para>The <quote><token>:</token></quote> also serves as a field
	      separator, in <filename>/etc/passwd</filename>, and in the <link
	      linkend="pathref">$PATH</link> variable.
	      <screen><prompt>bash$ </prompt><userinput>echo $PATH</userinput>
<computeroutput>/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games</computeroutput></screen>
	    </para>



	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="notref"><token>!</token></term>
	  <indexterm>
	    <primary>!</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>!</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>not</primary>
	    <secondary>logical</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>not</primary>
	  </indexterm>	  

	  <listitem>
	  <formalpara><title>reverse (or negate) the sense of
	  a test or exit status [bang]</title>

	      <para>The <token>!</token> operator inverts the <link
		linkend="exitstatusref">exit status</link>
		of the command to which it is applied (see
		<xref linkend="negcond">). It also inverts
		the meaning of a test operator. This can, for
		example, change the sense of <firstterm>equal</firstterm>
		( <link linkend="equalsignref">=</link>
		) to <firstterm>not-equal</firstterm> ( != ). The
		<token>!</token> operator is a Bash <link
		linkend="keywordref">keyword</link>.</para>

	    </formalpara>
	      <para>In a different context, the <token>!</token>
	        also appears in <link linkend="ivrref">indirect variable
		references</link>.</para>

	      <para>In yet another context, from the <firstterm>command
		line</firstterm>, the <token>!</token> invokes the
		Bash <firstterm>history mechanism</firstterm> (see <xref
		linkend="histcommands">). Note that within a script,
		the history mechanism is disabled.</para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="asteriskref"><token>*</token></term>
	  <indexterm>
	    <primary>*</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>*</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>wild card</primary>
	    <secondary>globbing</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>regular expression</primary>
	  </indexterm>	  

	  <listitem><formalpara><title>wild card [asterisk]</title>

	      <para>The <token>*</token> character serves as a <quote>wild
	        card</quote> for filename expansion in
		<link linkend="globbingref">globbing</link>. By itself,
		it matches every filename in a given directory.</para>
	    </formalpara>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>echo *</userinput>
<computeroutput>abs-book.sgml add-drive.sh agram.sh alias.sh</computeroutput>
	      </screen>
	    </para>
	
              <para><anchor id="asteriskref2"></para>
	      <para>The <token>*</token> also represents <link
	      linkend="asteriskreg">any number
	      (or zero) characters</link> in a <link
		linkend="regexref">regular expression</link>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>*</token></term>
	  <indexterm>
	    <primary>*</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>*</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>multiplication</primary>
	    <secondary>exponentiation</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>arithmetic operator</primary>
	  </indexterm>	  

	  <listitem><formalpara><title><link linkend="arops1">arithmetic operator</link></title>

	      <para>In the context of arithmetic operations, the
	        <token>*</token> denotes multiplication.</para>

	    </formalpara>

	      <para>A double asterisk, <token>**</token>, is the <link
	        linkend="exponentiationref">exponentiation
	        operator</link>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>?</token></term>
	  <indexterm>
	    <primary>?</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>?</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>test</primary>
	    <secondary>operator</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>test token</primary>
	  </indexterm>	  

	  <listitem><formalpara><title>test operator</title>
	      <para>Within certain expressions, the <token>?</token> indicates
	        a test for a condition.</para>
	    </formalpara>

	      <para><anchor id="cstrinary"></para>
	      <para>In a <link linkend="dblparens">double-parentheses
	        construct</link>, the <token>?</token>
		can serve as an element of a C-style
		<firstterm>trinary</firstterm> operator,
		<varname>?:</varname>.

		<programlisting>(( var0 = var1&lt;98?9:21 ))
#                ^ ^

# if [ "$var1" -lt 98 ]
# then
#   var0=9
# else
#   var0=21
# fi</programlisting></para>


              <para>In a <link linkend="paramsubref">parameter
	        substitution</link> expression, the <token>?</token>
		<link linkend="qerrmsg">tests whether a variable has been
		set</link>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="wildcardqu"><token>?</token></term>
	  <indexterm>
	    <primary>?</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>?</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>wild card</primary>
	    <secondary>globbing</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>regular expression</primary>
	  </indexterm>	  

	  <listitem><formalpara><title>wild card</title>

	      <para><anchor id="quexwc">The <token>?</token> character
		serves as a single-character <quote>wild card</quote>
		for filename expansion in <link
		linkend="globbingref">globbing</link>, as well as <link
		linkend="quexregex">representing one character</link>
		in an <link linkend="extregex">extended regular
		expression</link>.</para>

	    </formalpara>

	  </listitem>
	</varlistentry>

	<varlistentry><term><token>$</token></term>
	  <indexterm>
	    <primary>$</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>$</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>variable substitution</primary>
	  </indexterm>	  
	  <listitem>
            <formalpara><title><link linkend="varsubn">Variable
              substitution</link> (contents of a variable)</title>
             <para>
	       <programlisting>var1=5
var2=23skidoo

echo $var1     # 5
echo $var2     # 23skidoo</programlisting>
	       </para>
	       </formalpara>

	       <para><anchor id="varprefixref"</para>
	       <para>A <token>$</token> prefixing a variable name
		indicates the <firstterm>value</firstterm> the variable
		holds.</para>

	  </listitem>
	</varlistentry>  

	<varlistentry><term><token>$</token></term>
	  <indexterm>
	    <primary>$</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>$</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>regular expression</primary>
	  </indexterm>	  
	  <indexterm>
	    <primary>end of line</primary>
	  </indexterm>	  

	  <listitem>
	    <formalpara><title>end-of-line</title>
	      <para>In a <link linkend="regexref">regular expression</link>, a
		<quote>$</quote> addresses the <link
		linkend="dollarsignref">end of a line</link> of
		text.</para>
	    </formalpara>

	    </listitem>
	</varlistentry>

	<varlistentry><term><token>${}</token></term>
	  <indexterm>
	    <primary>${}</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>${}</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>parameter substitution</primary>
	  </indexterm>	  
	  <listitem>
            <formalpara><title><link linkend="paramsubref">Parameter
              substitution</link></title>
             <para></para></formalpara>
	  </listitem>
	</varlistentry>  

	<varlistentry>
	  <term><token>$*</token></term>
	  <term><token>$@</token></term>
	  <indexterm>
	    <primary>$*</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>$*</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>$@</primary>
	    <secondary>positional parameters</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>$@</primary>
	  </indexterm>	  

	  <listitem><formalpara><title><link linkend="appref">positional
	    parameters</link></title>
	      <para></para>
	    </formalpara>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>$?</token></term>
	  <indexterm>
	    <primary>$?</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>?</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>exit status</primary>
	    <secondary>variable</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>exit status</primary>
	  </indexterm>	  

	  <listitem><formalpara><title>exit status variable</title>
	      <para>The <link linkend="exsref">$? variable</link>
	        holds the <link linkend="exitstatusref">exit status</link>
		of a command, a <link linkend="functionref">function</link>,
		or of the script itself.</para>
	    </formalpara>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="processidref"><token>$$</token></term>
	  <indexterm>
	    <primary>$$</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>$$</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>process ID</primary>
	    <secondary>variable</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>process ID</primary>
	  </indexterm>	  

	  <listitem><formalpara><title>process ID variable</title>
	      <para>The <link linkend="proccid">$$ variable</link>
	        holds the <firstterm>process ID</firstterm>
		  <footnote>  
		    <para><anchor id="processiddef"></para>
		    <para>A <firstterm>PID</firstterm>, or
		      <firstterm>process ID</firstterm>, is a number assigned
		      to a running process. The <firstterm>PID</firstterm>s
		      of running processes may be viewed with a <link
		      linkend="ppssref">ps</link> command.
		      </para>
		      <para><anchor id="processref"></para>
		      <para>
		      Definition: A <firstterm>process</firstterm> is
		      an executing program, sometimes referred to as a
                      <firstterm>job</firstterm>.
		      </para>
		  </footnote>  
                of the script in which it appears.</para>
	    </formalpara>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="parensref"><token>()</token></term>

	  <listitem>
	    <formalpara><title>command group</title>
	      <para><programlisting>(a=hello; echo $a)</programlisting></para>
	    </formalpara>

	  <important>
	  
	    <para>A listing of commands within
	      <replaceable>parentheses</replaceable> starts a <link
	      linkend="subshellsref">subshell</link>.</para>

	    <para>Variables inside parentheses, within the subshell, are not
	      visible to the rest of the script. The parent process,
	      the script, <link linkend="parvis">cannot read variables
	      created in the child process</link>, the subshell.
	      <programlisting>a=123
( a=321; )	      

echo "a = $a"   # a = 123
# "a" within parentheses acts like a local variable.</programlisting></para>
	  </important>


	  <formalpara><title>array initialization</title>
	    <para>
	      <anchor id="arrayinit1">
	      <programlisting>Array=(element1 element2 element3)</programlisting>
	    </para>
	    </formalpara>
	  </listitem>

	</varlistentry>

	<varlistentry>
	  <indexterm>
	    <primary>{xxx,yyy,zzz..}</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>{}</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>brace expansion</primary>
	  </indexterm>	  
	  <term><token>{xxx,yyy,zzz,...}</token></term>
	  <listitem><formalpara><title>Brace expansion</title>
	      <para><anchor id="braceexpref"><programlisting>cat {file1,file2,file3} > combined_file
# Concatenates the files file1, file2, and file3 into combined_file.


cp file22.{txt,backup}
# Copies "file22.txt" to "file22.backup"
</programlisting></para>
	    </formalpara>
	  <para>A command may act upon a comma-separated list of file specs within
	  <replaceable>braces</replaceable>.

	     <footnote><para>The shell does the <firstterm>brace
	       expansion</firstterm>. The command itself acts upon the
	       <emphasis>result</emphasis> of the expansion.</para></footnote>
	  
	  Filename expansion (<link linkend="globbingref">globbing</link>)
	  applies to the file specs between the braces.</para>

	  <caution>
	    <para>No spaces allowed within the braces
	    <emphasis>unless</emphasis> the spaces are quoted or escaped.</para>
	    
	    <para><userinput>echo {file1,file2}\ :{\ A," B",' C'}</userinput></para>
	    <para><computeroutput>file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C</computeroutput></para>

	   </caution>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <indexterm>
	    <primary>{a..z}</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>{}</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>extended brace expansion</primary>
	  </indexterm>	  
	  <term><anchor id="braceexpref33"><token>{a..z}</token></term>
	  <listitem>

	  <formalpara>
	  <title>Extended Brace expansion</title>
	      <para>
<programlisting>echo {a..z} # a b c d e f g h i j k l m n o p q r s t u v w x y z
# Echoes characters between a and z.

echo {0..3} # 0 1 2 3
# Echoes characters between 0 and 3.</programlisting>
	      </para>
	    </formalpara>

	  <para>The <firstterm>{a..z}</firstterm>
	    <link linkend="braceexpref3">extended brace
	    expansion</link> construction is a feature introduced
	    in <link linkend="bash3ref">version 3</link> of
	    <firstterm>Bash</firstterm>.</para>

	  </listitem>
	</varlistentry>




	<varlistentry>
	  <term><anchor id="codeblockref"><token>{}</token></term>
	  <indexterm>
	    <primary>{}</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>{}</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>block of code</primary>
	  </indexterm>	  

	  <listitem>
	  <formalpara><title>Block of code [curly brackets]</title>
	      <para>Also referred to as an <firstterm>inline group</firstterm>,
		this construct, in effect, creates an <firstterm>anonymous
		function</firstterm> (a function without a
		name). However, unlike in a <quote>standard</quote> <link
		linkend="functionref">function</link>, the variables
		inside a code block remain visible to the remainder of the
		script.</para></formalpara>

	      <para> <screen><prompt>bash$ </prompt><userinput>{ local a;
	      a=123; }</userinput>
<computeroutput>bash: local: can only be used in a
function</computeroutput>
	      </screen> </para>

	      <para><programlisting>a=123
{ a=321; }
echo "a = $a"   # a = 321   (value inside code block)

# Thanks, S.C.</programlisting></para>


	    <para><anchor id="blockio"></para>
	    <para>The code block enclosed in braces may have <link
	      linkend="ioredirref">I/O redirected</link> to and from
	      it.</para>

	    <example id="ex8">
	      <title>Code blocks and I/O redirection</title>
	      <programlisting>&ex8;</programlisting>
	    </example>

	    <para><anchor id="blockio2"></para>
	    <example id="rpmcheck">
	      <title>Saving the output of a code block to a file</title>
	      <programlisting>&rpmcheck;</programlisting>
	    </example>

	    <note><para>Unlike a command group within (parentheses),
	      as above, a code block enclosed by {braces} will
	      <emphasis>not</emphasis> normally launch a <link
	      linkend="subshellsref">subshell</link>.

		<footnote>
		  <para>Exception: a code block in braces as
		  part of a pipe <emphasis>may</emphasis> run as a
		  <link linkend="subshellsref">subshell</link>.</para>

        <para><programlisting>ls | { read firstline; read secondline; }
#  Error. The code block in braces runs as a subshell,
#+ so the output of "ls" cannot be passed to variables within the block.
echo "First line is $firstline; second line is $secondline"  # Won't work.

# Thanks, S.C.</programlisting></para>
		</footnote>

	      </para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>{}</token></term>
	  <listitem>

	  <formalpara><title>placeholder for text</title>
	      <para>Used after <link linkend="xargscurlyref">xargs
		<option>-i</option></link> (<firstterm>replace
		strings</firstterm> option). The <token>{}</token> double
		curly brackets are a placeholder for output text.</para>
	    </formalpara>

              <para><programlisting>ls . | xargs -i -t cp ./{} $1
#            ^^         ^^

# From "ex42.sh" (copydir.sh) example.</programlisting></para>
          <para>anchor id="semicolonesc"></para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><token>{} \;</token></term>
	  <listitem>

	  <formalpara><title>pathname</title>
	      <para>Mostly used in <link linkend="findref">find</link>
		constructs. This is <emphasis>not</emphasis> a shell
		<link linkend="builtinref">builtin</link>.</para>
	    </formalpara>

	      <note><para>The <quote><token>;</token></quote> ends
		the <option>-exec</option> option of a
		<command>find</command> command sequence.  It needs
		to be escaped to protect it from interpretation by the
		shell.</para></note>

	  </listitem>
	</varlistentry>



	<varlistentry><term><anchor id="leftbracket"><token>[ ]</token></term>
	  <indexterm>
	    <primary>[]</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>[ ]</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>test</primary>
	  </indexterm>	  
	  <listitem>
            <formalpara><title>test</title>
             <para><anchor id="bracktest"></para></formalpara>
	     <para><link linkend="ifthen">Test</link> expression between
	       <command>[ ]</command>.	Note that <command>[</command>
	       is part of the shell <firstterm>builtin</firstterm> <link
	       linkend="ttestref">test</link> (and a synonym for it),
	       <emphasis>not</emphasis> a link to the external command
	       <filename>/usr/bin/test</filename>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry><term><token>[[ ]]</token></term>
	  <indexterm>
	    <primary>[[]]</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>[[ ]]</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>test</primary>
	  </indexterm>	  
	  <listitem>
            <formalpara><title>test</title>
             <para></para></formalpara>
	     <para>Test expression between <token>[[ ]]</token>. More
	     flexible than the single-bracket <token>[ ]</token> test,
	     this is a shell <link
	     linkend="keywordref">keyword</link>.</para> <para>See the
	     discussion on the <link linkend="dblbrackets">[[ ... ]]
	     construct</link>.</para>
	  </listitem>

	</varlistentry>

	<varlistentry><term><token>[ ]</token></term>
	  <indexterm>
	    <primary>[ ]</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>array_element[ ]</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>array element</primary>
	  </indexterm>	  
	  <listitem>
            <formalpara><title>array element</title>
             <para></para></formalpara>
	     <para>In the context of an <link linkend="arrayref">array</link>,
	       brackets set off the numbering of each element of that array.
	         <programlisting>Array[1]=slot_1
echo ${Array[1]}</programlisting></para>		 
	  </listitem>
	</varlistentry>

	<varlistentry><term><token>[ ]</token></term>
	  <indexterm>
	    <primary>[ ]</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>character range</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>regular expression</primary>
	  </indexterm>	  
	  <listitem>
            <formalpara><title>range of characters</title>
             <para></para></formalpara>
	     <para>As part of a <link linkend="regexref">regular
	       expression</link>, brackets delineate a <link
	       linkend="bracketsref">range of characters</link> to
	       match.</para>
	  </listitem>
	</varlistentry>

	<varlistentry><term><token>(( ))</token></term>
	  <indexterm>
	    <primary>(( ))</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>(( ))</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>integer comparison</primary>
	  </indexterm>	  
	  <listitem>
            <formalpara><title>integer expansion</title>
             <para></para></formalpara>
	     <para>Expand and evaluate integer expression between
	       <token>(( ))</token>.</para>
	     <para>See the discussion on the <link
	     linkend="dblparens">(( ... )) construct</link>.</para>
	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><token>></token> <token>&></token> <token>>&</token> <token>>></token> <token>&lt;</token> <token>&lt;&gt;</token></term>
	  <indexterm>
	    <primary>></primary>
	  </indexterm>
	  <indexterm>
	    <primary>>&</primary>
	  </indexterm>
	  <indexterm>
	    <primary>>></primary>
	  </indexterm>
	  <indexterm>
	    <primary><</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>></secondary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>>&</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>>></secondary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary><</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>redirection</primary>
	  </indexterm>	  

	  <listitem><formalpara><title><link linkend="ioredirref">redirection</link></title>
	      <para></para>
	    </formalpara>

	    <para><userinput>scriptname >filename</userinput> redirects the output of
	      <filename>scriptname</filename> to file
	      <filename>filename</filename>. Overwrite
	      <filename>filename</filename> if it already exists.</para>

	    <para><anchor id="redirouterror"></para>
	    <para><userinput>command &>filename</userinput> redirects
	      both the <link
	      linkend="stdinoutdef"><filename>stdout</filename></link>
	      and the
	      <filename>stderr</filename> of <filename>command</filename>
	      to <filename>filename</filename>.</para>

	    <para><anchor id="redirouterror2"></para>
	    <para><userinput>command >&2</userinput> redirects
	      <filename>stdout</filename> of <filename>command</filename>
	      to <filename>stderr</filename>.</para>

	    <para><userinput>scriptname >>filename</userinput> appends
	      the output of <filename>scriptname</filename>
	      to file <filename>filename</filename>. If
	      <filename>filename</filename> does not already exist,
	      it is created.</para>

	    <para><anchor id="redirrw"></para>
	    <para><userinput>[i]&lt;&gt;filename</userinput>
               opens file <filename>filename</filename> for reading
               and writing, and assigns <link linkend="fdref">file
               descriptor</link> <token>i</token> to it. If
               <filename>filename</filename> does not exist, it is
               created.</para>


	    <formalpara><title><link linkend="processsubref">process substitution</link></title>
	      <para></para>
	    </formalpara>

	    <para><userinput>(command)></userinput></para>
	    <para><userinput><(command)</userinput></para>


	    <para><link linkend="ltref">In a different context</link>,
	      the <quote><token>&lt;</token></quote> and
	      <quote><token>&gt;</token></quote> characters act
	      as <link linkend="scomparison1">string comparison
	      operators</link>.</para>

	    <para><link linkend="intlt">In yet another context</link>,
	      the <quote><token>&lt;</token></quote> and
	      <quote><token>&gt;</token></quote> characters act
	      as <link linkend="icomparison1">integer comparison
	      operators</link>. See also <xref linkend="ex45">.</para>

	  </listitem>


	</varlistentry>

	<varlistentry>
	  <term><anchor id="heredocrrref"><token><<</token></term>
	  <listitem><formalpara><title>redirection used in a <link
	    linkend="heredocref">here document</link></title>
	      <para></para>
	    </formalpara>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="herestringref"><token><<<</token></term>
	  <listitem><formalpara><title>redirection used in a <link
	    linkend="herestringsref">here string</link></title>
	      <para></para>
	    </formalpara>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token><</token></term>
	  <term><token>></token></term>
	  <indexterm>
	    <primary><</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary><</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>></primary>
	    <secondary>ASCII comparison</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>></primary>
	  </indexterm>	  

	  <listitem><formalpara><title><link linkend="ltref">ASCII
	    comparison</link></title>
	      <para><programlisting>veg1=carrots
veg2=tomatoes

if [[ "$veg1" < "$veg2" ]]
then
  echo "Although $veg1 precede $veg2 in the dictionary,"
  echo -n "this does not necessarily imply anything "
  echo "about my culinary preferences."
else
  echo "What kind of dictionary are you using, anyhow?"
fi</programlisting></para>
	    </formalpara>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>\<</token></term>
	  <term><token>\></token></term>
	  <indexterm>
	    <primary>\<</primary>
	  </indexterm>
	  <indexterm>
	    <primary>regular expression</primary>
	    <secondary>\<</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>></primary>
	    <secondary>word boundary</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>></primary>
	  </indexterm>	  

	  <listitem><formalpara><title><link linkend="anglebrac">word
	    boundary</link> in a <link linkend="regexref">regular
	    expression</link></title>
	    <para></para>
	    </formalpara>
	      <para><prompt>bash$ </prompt><userinput>grep '\&lt;the\&gt;' textfile</userinput></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>|</token></term>
	  <indexterm>
	    <primary>|</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>|</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>pipe</primary>
	  </indexterm>	  

	  <listitem>
	  <para><anchor id="piperef"></para>
	  <formalpara><title>pipe</title>
	      <para>Passes the output (<filename>stdout</filename>
		of a previous command to the input
		(<filename>stdin</filename>) of the next one, or
		to the shell. This is a method of chaining commands
		together.</para>
	    </formalpara>

	    <para>
              <programlisting>echo ls -l | sh
#  Passes the output of "echo ls -l" to the shell,
#+ with the same result as a simple "ls -l".


cat *.lst | sort | uniq
# Merges and sorts all ".lst" files, then deletes duplicate lines.</programlisting>
	    </para>

	    <sidebar>

	    <para>
	      A pipe, as a classic method of interprocess
	      communication, sends the <filename>stdout</filename>
	      of one <link linkend="processref">process</link> to the
	      <filename>stdin</filename> of another. In a typical case,
	      a command, such as <link linkend="catref">cat</link> or
	      <link linkend="echoref">echo</link>, pipes a stream of
	      data to a
	      <anchor id="filterdef">
	      <firstterm>filter</firstterm>, a command that
	      transforms its input for processing.
		<footnote><para> Even as in olden times a
		<firstterm>philtre</firstterm> denoted a potion alleged
		to have magical transformative powers, so does a UNIX
		<firstterm>filter</firstterm> transform its target in
		(rougly) analogous fashion. (The coder who comes up with a
		<quote>love philtre</quote> that runs on a Linux machine
		will likely win accolades and honors.)</para></footnote>
	      </para>

	    <para>  
	      <userinput>cat $filename1 $filename2 | grep $search_word</userinput>
            </para>

	    <para>For an interesting note on the complexity of using UNIX
	      pipes, see <ulink
	      url="http://www.faqs.org/faqs/unix-faq/faq/part3/">the UNIX FAQ,
	      Part 3</ulink>.</para>

	    </sidebar>


	    <para><anchor id="ucref">The output of a command or commands
	      may be piped to a script.

	      <programlisting>#!/bin/bash
# uppercase.sh : Changes input to uppercase.

tr 'a-z' 'A-Z'
#  Letter ranges must be quoted
#+ to prevent filename generation from single-letter filenames.

exit 0</programlisting>
              Now, let us pipe the output of <command>ls -l</command> to this
	      script.

	      <screen><prompt>bash$ </prompt><userinput>ls -l | ./uppercase.sh</userinput>
<computeroutput>-RW-RW-R--    1 BOZO  BOZO       109 APR  7 19:49 1.TXT
 -RW-RW-R--    1 BOZO  BOZO       109 APR 14 16:48 2.TXT
 -RW-R--R--    1 BOZO  BOZO       725 APR 20 20:56 DATA-FILE</computeroutput>
	      </screen>
	    </para>

	     <note>

	     <para>The <filename>stdout</filename> of each process in
	       a pipe must be read as the <filename>stdin</filename>
	       of the next. If this is not the case, the data stream
	       will <firstterm>block</firstterm>, and the pipe will not
	       behave as expected.
	         <programlisting>cat file1 file2 | ls -l | sort
# The output from "cat file1 file2" disappears.</programlisting>
             </para>

	     <para>A pipe runs as a <link linkend="childref">child
	       process</link>, and therefore cannot alter script
	       variables.
	         <programlisting>variable="initial_value"
echo "new_value" | read variable
echo "variable = $variable"     # variable = initial_value</programlisting>
             </para>

	     <para>If one of the commands in the pipe
	       aborts, this prematurely terminates execution of the
	       pipe. Called a <firstterm>broken pipe</firstterm>, this
	       condition sends a <replaceable>SIGPIPE</replaceable> <link
	       linkend="signald">signal</link>.</para>

	      </note>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>>|</token></term>
	  <indexterm>
	    <primary>>|</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>>|</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>redirection</primary>
	    <secondary>force</secondary>
	  </indexterm>	  
	  <indexterm>
	    <primary>noclobber</primary>
	  </indexterm>	  

	  <listitem><formalpara><title>force redirection (even if
		the <link linkend="noclobberref">noclobber option</link>
		is set)</title>
	      <para>This will forcibly overwrite an existing file.</para>
	    </formalpara>
	  </listitem>
	</varlistentry>

	<varlistentry><term><token>||</token></term>
	  <indexterm>
	    <primary>||</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>||</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>or</primary>
	  </indexterm>	  
	  <indexterm>
	    <primary>logical operator</primary>
	  </indexterm>	  

	  <listitem>
	    <formalpara><title><link linkend="orref">OR logical operator</link></title>
	      <para>In a <link linkend="testconstructs1">test
		construct</link>, the <token>||</token> operator causes
		a return of <returnvalue>0</returnvalue> (success) if
		<emphasis>either</emphasis> of the linked test conditions
		is true.</para>
	    </formalpara>

	    </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="bgjob"><token>&amp;</token></term>
	  <listitem><formalpara><title>Run job in background</title>
	      <para>A command followed by an <token>&amp;</token>
	        will run in the background.</para>
	    </formalpara>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>sleep 10 &</userinput>
<computeroutput>[1] 850</computeroutput>
<computeroutput>[1]+  Done                    sleep 10</computeroutput>
	      </screen>
	    </para>

	    <para>Within a script, commands and even <link
	      linkend="forloopref1">loops</link> may run in the
	      background.</para>

	    <para><anchor id="bgloop0"></para>
	    <example id="bgloop">
	      <title>Running a loop in the background</title>
	      <programlisting>&bgloop;</programlisting>
	    </example>

	    <caution><para>A command run in the background within a
	      script may cause the script to hang, waiting
	      for a keystroke. Fortunately, there is a <link
	      linkend="waithang">remedy</link> for this.</para></caution>

	    </listitem>
	</varlistentry>

	<varlistentry><term><anchor
	  id="logicaland"><token>&&</token></term>
	  <indexterm>
	    <primary>&&</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>&&</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>and</primary>
	  </indexterm>	  
	  <indexterm>
	    <primary>logical operator</primary>
	  </indexterm>	  

	  <listitem>
	    <formalpara><title><link linkend="logops1">AND logical
	    operator</link></title>

	      <para>In a <link linkend="testconstructs1">test
		construct</link>, the <token>&&</token> operator causes
		a return of <returnvalue>0</returnvalue> (success) only if
		<emphasis>both</emphasis> the linked test conditions
		are true.</para>

	    </formalpara>

	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="dashref"><token>-</token></term>
	  <listitem><formalpara><title>option, prefix</title>
	      <para>Option flag for a command or filter. Prefix for
		an operator. Prefix for a <link
		linkend="defparam1">default parameter</link>
		in <link linkend="paramsubref">parameter
		substitution</link>.</para>
	    </formalpara>
	      <para><userinput>COMMAND -[Option1][Option2][...]</userinput></para>
	      <para><userinput>ls -al</userinput></para>
	      <para><userinput>sort -dfu $filename</userinput></para>



	      <para>
	      <programlisting>if [ $file1 -ot $file2 ]
then #      ^
  echo "File $file1 is older than $file2."
fi

if [ "$a" -eq "$b" ]
then      ^
  echo "$a is equal to $b."
fi

if [ "$c" -eq 24 -a "$d" -eq 47 ]
then      ^              ^
  echo "$c equals 24 and $d equals 47."
fi


param2=${param1:-$DEFAULTVAL}
#               ^</programlisting>  
	      </para>

	      <para><anchor id="doubledashref"></para>
	      <para><command>--</command></para>

	      <para>The <firstterm>double-dash</firstterm>
		<option>--</option> prefixes <firstterm>long</firstterm>
		(verbatim) options to commands.</para>

	      <para><userinput>sort --ignore-leading-blanks</userinput></para>

              <para>Used with a <link linkend="builtinref">Bash
	        builtin</link>, it means the <firstterm>end of
		options</firstterm> to that particular command.</para>

		<tip><para>This provides a handy means of removing
		  files whose <emphasis>names begin with a dash</emphasis>.
	      <screen><prompt>bash$ </prompt><userinput>ls -l</userinput>
<computeroutput>-rw-r--r-- 1 bozo bozo 0 Nov 25 12:29 -badname</computeroutput>


<prompt>bash$ </prompt><userinput>rm -- -badname</userinput>

<prompt>bash$ </prompt><userinput>ls -l</userinput>
<computeroutput>total 0</computeroutput></screen>
	    </para></tip>

	      <para>The <firstterm>double-dash</firstterm> is also used in
	        conjunction with <link linkend="setref">set</link>.</para>

	      <para><userinput>set -- $variable</userinput> (as in <xref
	        linkend="setpos">)</para>

  
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="dashref2"><token>-</token></term>
	  <indexterm>
	    <primary>-</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>-</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>redirection</primary>
	    <secondary>from/to stdin/stdout</secondary>
	  </indexterm>	  
	  <listitem><formalpara><title>redirection from/to <filename>stdin</filename> or <filename>stdout</filename> [dash]</title>
	    <para><anchor id="coxex"></para>
	    </formalpara>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>cat -</userinput>
<userinput>abc</userinput>
<computeroutput>abc</computeroutput>

<computeroutput>...</computeroutput>

<userinput>Ctl-D</userinput></screen>
	    </para>

	    <para>As expected, <userinput>cat -</userinput> echoes
	    <filename>stdin</filename>, in this case keyboarded user input,
	    to <filename>stdout</filename>. But, does I/O redirection using
	    <command>-</command> have real-world applications?</para>

	    <para><programlisting>(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)
# Move entire file tree from one directory to another
# [courtesy Alan Cox &lt;a.cox@swansea.ac.uk&gt;, with a minor change]

# 1) cd /source/directory
#    Source directory, where the files to be moved are.
# 2) &&
#   "And-list": if the 'cd' operation successful,
#    then execute the next command.
# 3) tar cf - .
#    The 'c' option 'tar' archiving command creates a new archive,
#    the 'f' (file) option, followed by '-' designates the target file
#    as stdout, and do it in current directory tree ('.').
# 4) |
#    Piped to ...
# 5) ( ... )
#    a subshell
# 6) cd /dest/directory
#    Change to the destination directory.
# 7) &&
#   "And-list", as above
# 8) tar xpvf -
#    Unarchive ('x'), preserve ownership and file permissions ('p'),
#    and send verbose messages to stdout ('v'),
#    reading data from stdin ('f' followed by '-').
#
#    Note that 'x' is a command, and 'p', 'v', 'f' are options.
#
# Whew!



# More elegant than, but equivalent to:
#   cd source/directory
#   tar cf - . | (cd ../dest/directory; tar xpvf -)
#
#     Also having same effect:
# cp -a /source/directory/* /dest/directory
#     Or:
# cp -a /source/directory/* /source/directory/.[^.]* /dest/directory
#     If there are hidden files in /source/directory.
</programlisting></para>

	    <para><programlisting>bunzip2 -c linux-2.6.16.tar.bz2 | tar xvf -
#  --uncompress tar file--    | --then pass it to "tar"--
#  If "tar" has not been patched to handle "bunzip2",
#+ this needs to be done in two discrete steps, using a pipe.
#  The purpose of the exercise is to unarchive "bzipped" kernel source.
</programlisting></para>
       
          <para>Note that in this context the <quote>-</quote> is not
            itself a Bash operator, but rather an option recognized by
	    certain UNIX utilities that write to
	    <filename>stdout</filename>, such as <command>tar</command>,
	    <command>cat</command>, etc.</para>


	    <para>
	      <screen><prompt>bash$ </prompt><userinput>echo "whatever" | cat -</userinput>
<computeroutput>whatever</computeroutput> </screen>
	    </para>


	    <para>Where a filename is expected,
	      <replaceable>-</replaceable> redirects output to
	      <filename>stdout</filename> (sometimes seen with
	      <userinput>tar cf</userinput>), or accepts input from
	      <filename>stdin</filename>, rather than from a file.
	      <anchor id="filterdash">
	      This is a method of using a file-oriented utility as a
	      filter in a pipe.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>file</userinput>
<computeroutput>Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...</computeroutput>
	      </screen>

	    By itself on the command line, <link
	      linkend="fileref">file</link> fails with an error message.
	    </para>

	    <para>
	    Add a <quote>-</quote> for a more useful result. This causes the
	      shell to await user input.

	      <screen>
<prompt>bash$ </prompt><userinput>file -</userinput>
<userinput>abc</userinput>
<computeroutput>standard input:              ASCII text</computeroutput>



<prompt>bash$ </prompt><userinput>file -</userinput>
<userinput>#!/bin/bash</userinput>
<computeroutput>standard input:              Bourne-Again shell script text executable</computeroutput>
	      </screen>

	      Now the command accepts input from <filename>stdin</filename>
	        and analyzes it.
	    </para>

	    <para>The <quote>-</quote> can be used to pipe
	      <filename>stdout</filename> to other commands. This permits
	      such stunts as <link linkend="prependref">prepending lines
	      to a file</link>.</para>

	    <para>Using <link linkend="diffref">diff</link> to
	      compare a file with a <emphasis>section</emphasis>
	      of another:</para>

<para><userinput>grep Linux file1 | diff file2 -</userinput></para>	      


            <para>Finally, a real-world example using
	      <replaceable>-</replaceable> with <link
	      linkend="tarref">tar</link>.</para>

	    <example id="ex58">
	      <title>Backup of all files changed in last day</title>
	      <programlisting>&ex58;</programlisting>
	    </example>

	    <caution>

	    <para>Filenames beginning with
	      <quote>-</quote> may cause problems when coupled with the
	      <quote>-</quote> redirection operator. A script should
	      check for this and add an appropriate prefix to such
	      filenames, for example <filename>./-FILENAME</filename>,
	      <filename>$PWD/-FILENAME</filename>, or
	      <filename>$PATHNAME/-FILENAME</filename>.</para>

	      <para>If the value of a variable begins with a
	        <replaceable>-</replaceable>, this may likewise create
		problems.
		<programlisting>var="-n"
echo $var		
# Has the effect of "echo -n", and outputs nothing.</programlisting>
              </para>
	      </caution>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><token>-</token></term>
	  <listitem><formalpara><title>previous working directory</title>
	      <para>A <command>cd -</command> command changes to the
		previous working directory. This uses the
		<link linkend="oldpwd">$OLDPWD</link> <link
		linkend="envref">environmental variable</link>.</para>
	    </formalpara>
	      <caution><para>Do not confuse the <quote>-</quote> used in this
		sense with the <quote>-</quote> redirection
		operator just discussed. The interpretation of the
		<quote>-</quote> depends on the context in which it
		appears.</para></caution>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>-</token></term>
	  <listitem><formalpara><title>Minus</title>
	      <para>Minus sign in an <link linkend="arops1">arithmetic
	        operation</link>.</para>
	    </formalpara>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>=</token></term>
	  <listitem><formalpara><title>Equals</title>
	      <para><link linkend="eqref">Assignment operator</link>
	        <programlisting>a=28
echo $a   # 28</programlisting></para>
	    </formalpara>
	    <para>In a <link linkend="equalsignref">different context</link>,
	      the <quote><token>=</token></quote> is a <link
	      linkend="scomparison1">string comparison</link>
	      operator.</para>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>+</token></term>
	  <listitem><formalpara><title>Plus</title>
	      <para>Addition  <link linkend="arops1">arithmetic
	        operator</link>.</para>
	    </formalpara>
	    <para>In a <link linkend="plusref">different context</link>,
	      the <token>+</token> is a <link linkend="regexp">Regular
	      Expression</link> operator.</para>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>+</token></term>
	  <listitem><formalpara><title>Option</title>
	      <para>Option flag for a command or filter.</para>
	    </formalpara>
	    <para>Certain commands and <link
	      linkend="builtinref">builtins</link> use the
	      <option>+</option> to enable certain options and the
	      <option>-</option> to disable them. In <link
	      linkend="paramsubref">parameter substitution</link>,
	      the <option>+</option> prefixes an <link linkend="paramaltv">
	      alternate value</link> that a variable expands to.</para>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="modulo00"><token>%</token></term>
	  <listitem><formalpara><title><link linkend="moduloref">modulo</link></title>
	      <para>Modulo (remainder of a division) <link linkend="arops1">arithmetic
	        operation</link>.</para>
	    </formalpara>
	    <para><programlisting>let "z = 5 % 3"
echo $z  # 2</programlisting></para>
	    <para>In a <link linkend="pctpatref">different context</link>,
	      the <token>%</token> is a <link linkend="psub2">pattern
	      matching</link> operator.</para>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="tilderef"><token>~</token></term>
	  <listitem><formalpara><title>home directory [tilde]</title>

	      <para>This corresponds to the <link
	        linkend="homedirref">$HOME</link> internal variable.

	      <filename>~bozo</filename> is bozo's home directory,
		and <command>ls ~bozo</command> lists the contents of it.
		<token>~/</token> is the current user's home directory,
		and <command>ls ~/</command> lists the contents of it.

	      <screen><prompt>bash$ </prompt><userinput>echo ~bozo</userinput>
<computeroutput>/home/bozo</computeroutput>

<prompt>bash$ </prompt><userinput>echo ~</userinput>
<computeroutput>/home/bozo</computeroutput>

<prompt>bash$ </prompt><userinput>echo ~/</userinput>
<computeroutput>/home/bozo/</computeroutput>

<prompt>bash$ </prompt><userinput>echo ~:</userinput>
<computeroutput>/home/bozo:</computeroutput>

<prompt>bash$ </prompt><userinput>echo ~nonexistent-user</userinput>
<computeroutput>~nonexistent-user</computeroutput>
	      </screen>
	      </para>

	    </formalpara>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="workingdirref"><token>~+</token></term>
	  <listitem><formalpara><title>current working directory</title>
	      <para>This corresponds to the <link
	        linkend="pwdref">$PWD</link> internal variable.</para>
	    </formalpara>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="prevworkingdir"><token>~-</token></term>
	  <listitem><formalpara><title>previous working directory</title>
	      <para>This corresponds to the <link
	        linkend="oldpwd">$OLDPWD</link> internal variable.</para>
	    </formalpara>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>=~</token></term>
	  <listitem><formalpara><title><link linkend="regexmatchref">regular
	  expression match</link></title>
	      <para>This operator was introduced with <link
	        linkend="bash3ref">version 3</link> of Bash.</para>
	    </formalpara>
	    </listitem>
	</varlistentry>

	<varlistentry><term><anchor id="beglineref"><token>^</token></term>
	  <indexterm>
	    <primary>^</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>^</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>regular expression</primary>
	  </indexterm>	  
	  <indexterm>
	    <primary>beginning of line</primary>
	  </indexterm>	  

	  <listitem>
	    <formalpara><title>beginning-of-line</title>
	      <para>In a <link linkend="regexref">regular expression</link>, a
		<quote>^</quote> addresses the <link
		linkend="caretref">beginning of a line</link> of text.</para>
	    </formalpara>

	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="controlcharref">Control Characters</term>
	  <listitem>
	  <formalpara><title> change the behavior of the
	        terminal or text display.</title>

	    <para>A control character is a <keycap>CONTROL</keycap>
	      + <keycap>key</keycap> combination (pressed
	      simultaneously).
	      
	      A control character may also
	      be written in <firstterm>octal</firstterm> or
	      <firstterm>hexadecimal</firstterm> notation,
	      following an <firstterm>escape</firstterm>.</para>
	  </formalpara>
	  <para>Control characters are not normally useful inside a
	    script.</para>


	    <itemizedlist id="ctlchar">

	      <listitem>
	        <para><userinput>Ctl-A</userinput></para>
		<para>Moves cursor to beginning of line of text
		  (on the command-line).</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-B</userinput></para>
		<para><userinput>Backspace</userinput>
		  (nondestructive).</para>
	      </listitem>

	      <listitem>
	        <para><anchor id="ctlcref"></para>
	        <para><userinput>Ctl-C</userinput></para>
		<para><userinput>Break</userinput>.
		  Terminate a foreground job.</para>
	      </listitem>

	      <listitem>

	        <para><anchor id="ctldref"></para>
	        <para><userinput>Ctl-D</userinput></para>
		<para><firstterm>Log out</firstterm> from a shell (similar to
		  <link linkend="exitcommandref">exit</link>).</para>
		<para><userinput>EOF</userinput> (end-of-file). This also
		  terminates input from <filename>stdin</filename>.</para>
                <para>When typing text on the console or in an
                  <firstterm>xterm</firstterm> window,
		  <userinput>Ctl-D</userinput> erases the character under the
		  cursor. When there are no characters present,
		  <userinput>Ctl-D</userinput> logs out of the session, as
		  expected. In an <firstterm>xterm</firstterm> window,
		  this has the effect of closing the window.</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-E</userinput></para>
		<para>Moves cursor to end of line of text
		  (on the command-line).</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-F</userinput></para>
		<para>Moves cursor forward one character position
		  (on the command-line).</para>
	      </listitem>

	      <listitem>
	        <para><anchor id="ctlgref"></para>
	        <para><userinput>Ctl-G</userinput></para>
		<para><userinput>BEL</userinput>. On some
		old-time teletype terminals, this would actually ring
		a bell. In an <firstterm>xterm</firstterm> it might
		beep.</para>
	      </listitem>

	      <listitem>
	        <para><anchor id="ctlhref"></para>
	        <para><userinput>Ctl-H</userinput></para>
		<para><userinput>Rubout</userinput> (destructive backspace).
		  Erases characters the cursor backs over while
		  backspacing.</para>
		<para>
		<programlisting>#!/bin/bash
# Embedding Ctl-H in a string.

a="^H^H"                  # Two Ctl-H's -- backspaces
                          # ctl-V ctl-H, using vi/vim
echo "abcdef"             # abcdef
echo
echo -n "abcdef$a "       # abcd f
#  Space at end  ^              ^  Backspaces twice.
echo
echo -n "abcdef$a"        # abcdef
#  No space at end               ^ Doesn't backspace (why?).
                          # Results may not be quite as expected.
echo; echo

# Constantin Hagemeier suggests trying:
# a=$'\010\010'
# a=$'\b\b'
# a=$'\x08\x08'
# But, this does not change the results.</programlisting>
                </para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-I</userinput></para>
		<para><userinput>Horizontal tab</userinput>.</para>
	      </listitem>

	      <listitem>
	        <para><anchor id="ctljref"></para>
	        <para><userinput>Ctl-J</userinput></para>
		<para><userinput>Newline</userinput> (line feed).
		  In a script, may also be expressed in octal notation --
		  '\012' or in hexadecimal -- '\x0a'.</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-K</userinput></para>
		<para><userinput>Vertical tab</userinput>.</para>
                <para>When typing text on the console or in an
                  <firstterm>xterm</firstterm> window,
		  <userinput>Ctl-K</userinput> erases from the character
		  under the cursor to end of line. Within a script,
		  <userinput>Ctl-K</userinput> may behave differently,
		  as in Lee Lee Maschmeyer's example, below.</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-L</userinput></para>
		<para><userinput>Formfeed</userinput> (clear the terminal
		  screen). In a terminal, this has the same effect as the
		  <link linkend="clearref">clear</link> command. When sent
		  to a printer, a <userinput>Ctl-L</userinput> causes
		  an advance to end of the paper sheet.</para>
	      </listitem>

	      <listitem>
	        <para><anchor id="ctlmref"></para>
	        <para><userinput>Ctl-M</userinput></para>
		<para><userinput>Carriage return</userinput>.</para>
		<para>
		<programlisting>#!/bin/bash
# Thank you, Lee Maschmeyer, for this example.

read -n 1 -s -p \
$'Control-M leaves cursor at beginning of this line. Press Enter. \x0d'
           # Of course, '0d' is the hex equivalent of Control-M.
echo >&2   #  The '-s' makes anything typed silent,
           #+ so it is necessary to go to new line explicitly.

read -n 1 -s -p $'Control-J leaves cursor on next line. \x0a'
           #  '0a' is the hex equivalent of Control-J, linefeed.
echo >&2

###

read -n 1 -s -p $'And Control-K\x0bgoes straight down.'
echo >&2   #  Control-K is vertical tab.

# A better example of the effect of a vertical tab is:

var=$'\x0aThis is the bottom line\x0bThis is the top line\x0a'
echo "$var"
#  This works the same way as the above example. However:
echo "$var" | col
#  This causes the right end of the line to be higher than the left end.
#  It also explains why we started and ended with a line feed --
#+ to avoid a garbled screen.

# As Lee Maschmeyer explains:
# --------------------------
#  In the [first vertical tab example] . . . the vertical tab
#+ makes the printing go straight down without a carriage return.
#  This is true only on devices, such as the Linux console,
#+ that can't go "backward."
#  The real purpose of VT is to go straight UP, not down.
#  It can be used to print superscripts on a printer.
#  The col utility can be used to emulate the proper behavior of VT.

exit 0</programlisting>
		</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-N</userinput></para>
		<para>Erases a line of text recalled from
		  <firstterm>history buffer</firstterm>
		    <footnote><para>Bash stores a list of commands
		    previously issued from the command-line
		    in a <firstterm>buffer</firstterm>, or
		    memory space, for recall with the <link
		    linkend="builtinref">builtin</link>
		    <firstterm>history</firstterm>
		    commands.</para></footnote> (on the
		    command-line).</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-O</userinput></para>
		<para>Issues a <firstterm>newline</firstterm>
		  (on the command-line).</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-P</userinput></para>
		<para>Recalls last command from <firstterm>history
		  buffer</firstterm> (on the command-line).</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-Q</userinput></para>
		<para>Resume (<userinput>XON</userinput>).</para>
		<para>This resumes <filename>stdin</filename> in a terminal.</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-R</userinput></para>
		<para>Backwards search for text in <firstterm>history
		  buffer</firstterm>
		  (on the command-line).</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-S</userinput></para>
		<para>Suspend (<userinput>XOFF</userinput>).</para>
		<para>This freezes <filename>stdin</filename> in a terminal.
		  (Use Ctl-Q to restore input.)</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-T</userinput></para>
		<para>Reverses the position of the character the cursor
		  is on with the previous character (on the
		  command-line).</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-U</userinput></para>
		<para>Erase a line of input, from the cursor backward to
		  beginning of line. In some settings,
		  <userinput>Ctl-U</userinput> erases the entire
		  line of input, <emphasis>regardless of cursor
		  position</emphasis>.</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-V</userinput></para>
		<para>When inputting text, <userinput>Ctl-V</userinput>
		  permits inserting control characters. For example, the
		  following two are equivalent:
		    <programlisting>echo -e '\x0a'
echo &lt;Ctl-V&gt;&lt;Ctl-J&gt;</programlisting></para>
                <para><userinput>Ctl-V</userinput> is primarily useful from
		within a text editor.</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-W</userinput></para>
                <para>When typing text on the console or in an xterm window,
		  <userinput>Ctl-W</userinput> erases from the character
		  under the cursor backwards to the first instance of
		  <link linkend="whitespaceref">whitespace</link>. In
		  some settings, <userinput>Ctl-W</userinput> erases
		  backwards to first non-alphanumeric character.</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-X</userinput></para>
		<para>In certain word processing programs,
		  <firstterm>Cuts</firstterm> highlighted text
		  and copies to <firstterm>clipboard</firstterm>.</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-Y</userinput></para>
		<para><firstterm>Pastes</firstterm> back text previously
		  erased (with <userinput>Ctl-K</userinput> or
		  <userinput>Ctl-U</userinput>).</para>
	      </listitem>

	      <listitem>
	        <para><userinput>Ctl-Z</userinput></para>
		<para><firstterm>Pauses</firstterm> a foreground job.</para>
		<para><firstterm>Substitute</firstterm> operation in certain
		  word processing applications.</para>
		<para><userinput>EOF</userinput> (end-of-file) character
		  in the MSDOS filesystem.</para>
	      </listitem>

	    </itemizedlist>



	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="whitespaceref">Whitespace</term>
	  <listitem>
	  <formalpara><title>functions as a separator, separating commands or variables.</title>
	      <para>Whitespace consists of either
		<firstterm>spaces</firstterm>,
		<firstterm>tabs</firstterm>, <firstterm>blank
		lines</firstterm>, or any combination thereof.

		  <footnote><para>A linefeed (<firstterm>newline</firstterm>)
		    is also a whitespace character. This explains
		    why a <firstterm>blank line</firstterm>,
		    consisting only of a linefeed, is considered
		    whitespace.</para></footnote>

		In some contexts, such as <link linkend="wsbad">variable
		assignment</link>, whitespace is not permitted, and
		results in a syntax error.</para>
	    </formalpara>

	  <para>Blank lines have no effect on the action of a script,
	    and are therefore useful for visually separating functional
	    sections.</para>

	  <para><link linkend="ifsref">$IFS</link>, the special variable
	    separating fields of input to certain commands, defaults
	    to whitespace.</para>

	  <para><anchor id="quotingws"></para>
	  <para>To preserve <firstterm>whitespace</firstterm>
	  within a string or in a variable, use <link
	  linkend="quotingref">quoting</link>.</para>

	  <para>UNIX <link linkend="filterdef">filters</link>
	    can target and operate on <firstterm>whitespace</firstterm>
	    using the <link linkend="posixref">POSIX</link> character class
	    <link linkend="wsposix">[:space:]</link>.</para>

	  </listitem>
	</varlistentry>


      </variablelist>

  </chapter> <!-- Special characters used in shell scripts -->



  <chapter id="variables">
      <title>Introduction to Variables and Parameters</title>

      <para><firstterm>Variables</firstterm> are how programming and
	scripting languages represent data. A variable is nothing
	more than a <firstterm>label</firstterm>, a name assigned to a
	location or set of locations holding an item of data, in computer
	memory.</para>

      <para>Variables appear in arithmetic operations and manipulation of
	quantities, and in string parsing.</para>


     <sect1 id="varsubn">
        <title>Variable Substitution</title>

      <para>The <firstterm>name</firstterm> of a variable is a placeholder
	for its <firstterm>value</firstterm>, the data it holds.
	Referencing (retrieving) its value is called
	<firstterm>variable substitution</firstterm>.</para>

      <variablelist id="dollarsign">

	<varlistentry>
	  <term><token>$</token></term> <indexterm>
	    <primary>$</primary>
	  </indexterm> <indexterm>
	    <primary>variable</primary> <secondary>$</secondary>
	  </indexterm> <indexterm>
	    <primary>variable</primary>
	    <secondary>substitution</secondary>
	  </indexterm>

	  <listitem>

	      <para><anchor id="varnameval"></para>
	      <para>Let us carefully distinguish between the
		<firstterm>name</firstterm> of a variable
		and its <firstterm>value</firstterm>. If
		<userinput>variable1</userinput> is the name of a
		variable, then <userinput>$variable1</userinput>
		is a reference to its <firstterm>value</firstterm>,
		the data item it contains.
		
		  <footnote>

		    <para><anchor id="lvalueref">Technically, the
		      <firstterm>name</firstterm> of a variable is called an
		      <firstterm>lvalue</firstterm>, meaning that it appears
		      on the <emphasis>left</emphasis> side of an assignment
		      statment, as in <userinput>VARIABLE=23</userinput>.
		      A variable's <firstterm>value</firstterm> is
		      an <firstterm>rvalue</firstterm>, meaning that
		      it appears on the <emphasis>right</emphasis>
		      side of an assignment statement, as in
		      <userinput>VAR2=$VARIABLE</userinput>.</para>

		    <para><anchor id="pointerref">A variable's
		      <firstterm>name</firstterm> is, in fact,
		      a <firstterm>reference</firstterm>, a
		      <firstterm>pointer</firstterm> to the memory
		      location(s) where the actual data associated with
		      that variable is kept.</para>

		  </footnote>


		</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>variable1=23</userinput>


<prompt>bash$ </prompt><userinput>echo variable1</userinput>
<computeroutput>variable1</computeroutput>

<prompt>bash$ </prompt><userinput>echo $variable1</userinput>
<computeroutput>23</computeroutput></screen>	      
	      </para>
		
		
              <para>The only time a variable appears <quote>naked</quote>
		-- without the <token>$</token> prefix	-- is when
		declared or assigned, when <firstterm>unset</firstterm>,
		when <link linkend="exportref">exported</link>,
		or in the special case of a variable representing
		a <link linkend="signald">signal</link> (see
		<xref linkend="ex76">). Assignment may be with an
		<token>=</token> (as in <parameter>var1=27</parameter>),
		in a <link linkend="readref">read</link> statement,
		and at the head of a loop (<parameter>for var2 in 1 2
		3</parameter>).</para>


	    <para><anchor id="dblquo">Enclosing a referenced value in
	      <firstterm>double quotes</firstterm> (<token>" ... "</token>)
	      does not interfere with variable substitution. This is
	      called <firstterm>partial quoting</firstterm>, sometimes
	      referred to as <quote>weak quoting.</quote> <anchor
	      id="snglquo">Using single quotes (<token>' ... '</token>)
	      causes the variable name to be used literally, and no
	      substitution will take place. This is <firstterm>full
	      quoting</firstterm>, sometimes referred to as 'strong
	      quoting.' See <xref linkend="quoting"> for a
	      detailed discussion.</para>

	    <para>Note that <userinput>$variable</userinput> is actually a
	      simplified form of
	      <userinput>${variable}</userinput>. In contexts
	      where the <userinput>$variable</userinput> syntax
	      causes an error, the longer form may work (see <xref
	      linkend="Parameter-Substitution">, below).</para>

	    <para><anchor id="varunsetting"></para>
	    <example id="ex9">
	      <title>Variable assignment and substitution</title>
	      <programlisting>&ex9;</programlisting>
	    </example>

	    <caution>

            <para><anchor id="uninitvar1"></para>
	    <para>An uninitialized variable has a
	      <quote>null</quote> value -- no assigned value at all
	      (<emphasis>not</emphasis> zero!).

              <programlisting>if [ -z "$unassigned" ]
then
  echo "\$unassigned is NULL."
fi     # $unassigned is NULL.</programlisting></para>
	      
	    <para>Using a variable before
	      assigning a value to it may cause problems.
	      It is nevertheless possible to perform arithmetic operations
	      on an uninitialized variable.

	        <programlisting>echo "$uninitialized"                                # (blank line)
let "uninitialized += 5"                             # Add 5 to it.
echo "$uninitialized"                                # 5

#  Conclusion:
#  An uninitialized variable has no value,
#+ however it acts as if it were 0 in an arithmetic operation.
#  This is undocumented (and probably non-portable) behavior,
#+ and should not be used in a script.</programlisting>

              See also <xref linkend="selfsource">.</para>

	      </caution>

	  </listitem>
	</varlistentry>
      </variablelist>
    </sect1> <!-- Variable Substitution -->  


    <sect1 id="varassignment">
      <title>Variable Assignment</title>

      <variablelist>
	<varlistentry>
	  <term><anchor id="eqref"><token>=</token></term>
	  <indexterm>
	    <primary>=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>assignment</secondary>
	  </indexterm>
	  <listitem><para>the assignment operator (<emphasis>no space before
	    and after</emphasis>)</para>


	    <caution>
	    <para>Do not confuse this with <link
	      linkend="equalsignref">=</link> and
	      <link linkend="equalref">-eq</link>, which
	      <link linkend="ifthen">test</link>,
	      rather than assign!</para>

	    <para>Note that <token>=</token> can be either
	      an <firstterm>assignment</firstterm> or a
	      <firstterm>test</firstterm> operator, depending on
	      context.</para>
	    </caution>


	<para><anchor id="ex15_0"></para>
	<example id="ex15">
	  <title>Plain Variable Assignment</title>
	  <programlisting>&ex15;</programlisting>
	</example>

	<para><anchor id="ex16_0"></para>
	<example id="ex16">
	  <title>Variable Assignment, plain and fancy</title>
	  <programlisting>&ex16;</programlisting>
	</example>

	    <para><anchor id="commandsubref0"></para>

	    <para>Variable assignment using the <firstterm>$(...)</firstterm>
	      mechanism (a newer method than <link
	      linkend="backquotesref">backquotes</link>). This is
	      actually a form of <link linkend="commandsubref">command
	      substitution</link>.</para>

	    <para><programlisting># From /etc/rc.d/rc.local
R=$(cat /etc/redhat-release)
arch=$(uname -m)</programlisting></para>
	  </listitem>
	</varlistentry>
      </variablelist>

    </sect1> <!-- Variable Assignment -->

    <sect1 id="untyped">
      <title>Bash Variables Are Untyped</title>
      
      <para><anchor id="bvuntyped"></para>
      <para>Unlike many other programming languages, Bash does not segregate
	its variables by <quote>type.</quote> Essentially, <emphasis>Bash
	variables are character strings</emphasis>, but, depending on
	context, Bash permits arithmetic operations and comparisons on
	variables. The determining factor is whether the value of a
	variable contains only digits.</para>

	    <example id="intorstring">
	      <title>Integer or string?</title>
	      <programlisting>&intorstring;</programlisting>
	    </example>	    

      <para>Untyped variables are both a blessing and a curse. They permit
	more flexibility in scripting and make it easier to grind out
	lines of code (and give you enough rope to hang yourself!).
	However, they likewise permit subtle errors to creep in
	and encourage sloppy programming habits.</para>

      <para>To lighten the burden of keeping track of variable
        types in a script, Bash <emphasis>does</emphasis> permit
	<link linkend="declareref">declaring</link> variables.</para>

    </sect1> <!-- Bash Variables Are Untyped-->


    <sect1 id="othertypesv">
      <title>Special Variable Types</title>

      <variablelist>

	<varlistentry>
	  <term><replaceable>local variables</replaceable></term>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>local</secondary>
	  </indexterm>

	  <listitem><para>variables <link
	    linkend="scoperef">visible</link> only within a <link
	    linkend="codeblockref">code block</link> or function (see
	    also <link linkend="localref">local variables</link> in
	    <link linkend="functionref">functions</link>)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="envref"><replaceable>environmental variables</replaceable></term>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>environmental</secondary>
	  </indexterm>
	  <listitem>

	  <para>variables that affect the behavior of the shell and
	      user interface</para>

	      <note>

	      <para>In a more general context, each <link
	      linkend="processref">process</link> has an
		<quote>environment</quote>, that is, a group of
		variables that the process may reference. In this sense,
		the shell behaves like any other process.</para>

	      <para>Every time a shell starts, it creates shell variables that
		correspond to its own environmental variables. Updating
		or adding new environmental variables causes the
		shell to update its environment, and all the shell's
		<firstterm>child processes</firstterm> (the commands it
		executes) inherit this environment.</para>

	      </note>

	      <caution>
	      <para>The space allotted to the environment is limited.
	        Creating too many environmental variables or ones that use up
		excessive space may cause problems.</para>

	      <para>
	          <screen>
<prompt>bash$ </prompt><userinput>eval "`seq 10000 | sed -e 's/.*/export var&=ZZZZZZZZZZZZZZ/'`"</userinput>

<prompt>bash$ </prompt><userinput>du</userinput>
<computeroutput>bash: /usr/bin/du: Argument list too long</computeroutput>
	          </screen>
	      </para>

	      <para>Note: this <quote>error</quote> has been fixed, as of
	        kernel version 2.6.23.</para>
	      <para>(Thank you, St&eacute;phane Chazelas for the clarification,
	        and for providing the above example.)</para>
	      </caution>

	    <para>If a script sets environmental variables, they need to be
	      <quote>exported,</quote> that is, reported to the
	      <firstterm>environment</firstterm> local to
	      the script. This is the function of the <link
	      linkend="exportref">export</link> command.</para>

            <anchor id="childref">
	    <note>
	    <para>A script can <command>export</command> variables only
	      to child <link linkend="processref">processes</link>,
	      that is, only to commands or processes which that
	      particular script initiates. A script invoked from
	      the command line <replaceable>cannot</replaceable>
	      export variables back to the command line environment.
	      <emphasis><link linkend="forkref">Child processes</link>
	      cannot export variables back to the parent processes that
	      spawned them.</emphasis></para>
	    <para><anchor id="childref2">Definition: A <firstterm>child
	      process</firstterm> is a subprocess launched by another
	      process, its <link linkend="parentref">parent</link>.</para>
	      </note>

	      <para>---</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="posparamref1"><replaceable>positional parameters</replaceable></term>
	  <indexterm>
	    <primary>parameter</primary>
	    <secondary>positional</secondary>
	  </indexterm>
	  <listitem>
	    <para>arguments passed to the script from the command
	      line
		<footnote><para>Note that <link
		linkend="passedargs"><firstterm>functions</firstterm>
		also take positional parameters</link>.</para></footnote>
	      : <varname>$0</varname>, <varname>$1</varname>,
	      <varname>$2</varname>, <varname>$3</varname> . . .</para>
	      
	    <para><anchor id="scrnameparam"><varname>$0</varname> is
	       the name of the script itself,
	      <varname>$1</varname> is the first argument,
	      <varname>$2</varname> the second, <varname>$3</varname>
	      the third, and so forth.

	      <footnote>
	      <para><anchor id="arg0">The process calling the
		script sets the <varname>$0</varname> parameter. By
		convention, this parameter is the name of the script. See
		the <link linkend="manref">manpage</link> (manual page)
		for <command>execv</command>.</para>
	      <para>From the <firstterm>command line</firstterm>, however,
	        <varname>$0</varname> is the name of the shell.
	      <screen><prompt>bash$ </prompt><userinput>echo $0</userinput>
<computeroutput>bash</computeroutput>

<prompt>tcsh% </prompt><userinput>echo $0</userinput>
<computeroutput>tcsh</computeroutput></screen></para>
              </footnote>

	      <anchor id="bracketnotation">
	      After <varname>$9</varname>, the arguments must be enclosed
	      in brackets, for example, <varname>${10}</varname>,
	      <varname>${11}</varname>, <varname>${12}</varname>.</para>

	    <para>The special variables <link linkend="appref">$* and $@</link>
	      denote <emphasis>all</emphasis> the positional parameters.</para>

	    <example id="ex17">
	      <title>Positional Parameters</title>
	      <programlisting>&ex17;</programlisting>
	    </example>

	    <para><firstterm>Bracket notation</firstterm> for positional
	      parameters leads to a fairly simple way of referencing
	      the <emphasis>last</emphasis> argument passed to a
	      script on the command line. This also requires <link
	      linkend="varrefnew">indirect referencing</link>.</para>

            <para><anchor id="lastargref"></para>
	    <para><programlisting>args=$#           # Number of args passed.
lastarg=${!args}
# Note: This is an *indirect reference* to $args ...


# Or:       lastarg=${!#}             (Thanks, Chris Monson.)
# This is an *indirect reference* to the $# variable.
# Note that lastarg=${!$#} doesn't work.
</programlisting></para>


	    <para>Some scripts can perform different operations,
	      depending on which name they are invoked with. For this
	      to work, the script needs to check <varname>$0</varname>,
	      the name it was invoked by. There must also exist symbolic
	      links to all the alternate names of the script. See <xref
	      linkend="hellol">.</para>

	      <para><anchor id="nullvar"></para>
	    <tip><para>If a script expects a command line parameter
	      but is invoked without one, this may cause a <firstterm>null
	      variable assignment</firstterm>, generally an undesirable
	      result. One way to prevent this is to append an extra
	      character to both sides of the assignment statement using
	      the expected positional parameter.  </para></tip>

	      <programlisting>variable1_=$1_  # Rather than variable1=$1
# This will prevent an error, even if positional parameter is absent.

critical_argument01=$variable1_

# The extra character can be stripped off later, like so.
variable1=${variable1_/_/}
# Side effects only if $variable1_ begins with an underscore.
# This uses one of the parameter substitution templates discussed later.
# (Leaving out the replacement pattern results in a deletion.)

#  A more straightforward way of dealing with this is
#+ to simply test whether expected positional parameters have been passed.
if [ -z $1 ]
then
  exit $E_MISSING_POS_PARAM
fi


#  However, as Fabian Kreutz points out,
#+ the above method may have unexpected side-effects.
#  A better method is parameter substitution:
#         ${1:-$DefaultVal}
#  See the "Parameter Substition" section
#+ in the "Variables Revisited" chapter.
</programlisting>

	      <para>---</para>

	    <example id="ex18">
	      <title><firstterm>wh</firstterm>, <firstterm>
                whois</firstterm> domain name lookup</title>
	      <programlisting>&ex18;</programlisting>
	    </example>

	      <para>---</para>

	    <para><anchor id="shiftref"></para>
	    <para>
	      <indexterm>
		<primary>shift</primary>
	      </indexterm>
	      <indexterm>
		<primary>command</primary>
		<secondary>shift</secondary>
	      </indexterm>
	      The <command>shift</command> command reassigns the positional
	      parameters, in effect shifting them to the left one notch.</para>
	      
	    <para><varname>$1</varname> <--- <varname>$2</varname>, <varname>$2</varname> <--- <varname>$3</varname>, <varname>$3</varname> <--- <varname>$4</varname>, etc.</para>

	    <para>The old <varname>$1</varname> disappears, but
	      <emphasis><varname>$0</varname> (the script name)
	      does not change</emphasis>. If you use a large number of
	      positional parameters to a script, <command>shift</command>
	      lets you access those past <literal>10</literal>, although
	      <link linkend="bracketnotation">{bracket} notation</link>
	      also permits this.</para>

	    <example id="ex19">
	      <title>Using <firstterm>shift</firstterm></title>
	      <programlisting>&ex19;</programlisting>
	    </example>

          <para>The <command>shift</command> command can take a numerical
	    parameter indicating how many positions to shift.</para>

          <para><programlisting>#!/bin/bash
# shift-past.sh

shift 3    # Shift 3 positions.
#  n=3; shift $n
#  Has the same effect.

echo "$1"

exit 0

# ======================== #


$ sh shift-past.sh 1 2 3 4 5
4

#  However, as Eleni Fragkiadaki, points out,
#+ attempting a 'shift' past the number of
#+ positional parameters ($#) returns an exit status of 1,
#+ and the positional parameters themselves do not change.
#  This means possibly getting stuck in an endless loop. . . .
#  For example:
#      until [ -z "$1" ]
#      do
#         echo -n "$1 "
#         shift 20    #  If less than 20 pos params,
#      done           #+ then loop never ends!
#
# When in doubt, add a sanity check. . . .
#           shift 20 || break
#                    ^^^^^^^^</programlisting></para>

          <note><para>The <command>shift</command> command works in a similar
	    fashion on parameters passed to a <link
	    linkend="functionref">function</link>.  See <xref
	    linkend="multiplication">.</para></note>

	  </listitem>
	</varlistentry>
      </variablelist>

    </sect1> <!-- Special Variable Types -->  


  </chapter> <!-- Variables -->



  <chapter id="quoting">
    <title>Quoting</title>
    
      <para><anchor id="quotingref"></para>

      <indexterm>
	<primary>"</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>"</secondary>
      </indexterm>
      <indexterm>
	<primary>'</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>'</secondary>
      </indexterm>
      <indexterm>
	<primary>quote</primary>
      </indexterm>
      <indexterm>
	<primary>\</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>\</secondary>
      </indexterm>
      <indexterm>
	<primary>escape</primary>
      </indexterm>
      <para>Quoting means just that, bracketing a string in quotes. This
	has the effect of protecting <link linkend="scharlist1">special
	characters</link> in the string from reinterpretation
	or expansion by the shell or shell script. (A character
	is <quote>special</quote> if it has an interpretation
	other than its literal meaning. For example, the <link
	linkend="asteriskref">asterisk *</link> represents
	a <firstterm>wild card</firstterm> character in 
	<link linkend="globbingref">globbing</link> and <link
	linkend="regexref">Regular Expressions</link>).</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>ls -l [Vv]*</userinput>
<computeroutput>-rw-rw-r--    1 bozo  bozo       324 Apr  2 15:05 VIEWDATA.BAT
 -rw-rw-r--    1 bozo  bozo       507 May  4 14:25 vartrace.sh
 -rw-rw-r--    1 bozo  bozo       539 Apr 14 17:11 viewdata.sh
</computeroutput>

<prompt>bash$ </prompt><userinput>ls -l '[Vv]*'</userinput>
<computeroutput>ls: [Vv]*: No such file or directory</computeroutput></screen>	      
	      </para>

      <para><anchor id="quotingdef"></para>
      <sidebar><para>In everyday speech or writing, when we
      <quote>quote</quote> a phrase, we set it apart and give it special
      meaning. In a Bash script, when we <firstterm>quote</firstterm> a
      string, we set it apart and protect its <firstterm>literal</firstterm>
      meaning.</para></sidebar>

      <para>Certain programs and utilities reinterpret or expand
	special characters in a quoted string. An important use of
	quoting is protecting a command-line parameter from the shell,
	but still letting the calling program expand it.</para>

              <para>
	      <screen><prompt>bash$ </prompt><userinput>grep '[Ff]irst' *.txt</userinput>
<computeroutput>file1.txt:This is the first line of file1.txt.
 file2.txt:This is the First line of file2.txt.</computeroutput></screen>
	      </para>

	<para>Note that the unquoted <userinput>grep [Ff]irst *.txt</userinput>
	  works under the Bash shell.
	    <footnote><para>Unless there is a file named
	    <filename>first</filename> in the current working directory. Yet
	    another reason to <firstterm>quote</firstterm>. (Thank you, Harald
	    Koenig, for pointing this out.</para></footnote>
	  </para>


      <para>Quoting can also suppress <link linkend="echoref">echo's</link>
        <quote>appetite</quote> for newlines.</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>echo $(ls -l)</userinput>
<computeroutput>total 8 -rw-rw-r-- 1 bo bo 13 Aug 21 12:57 t.sh -rw-rw-r-- 1 bo bo 78 Aug 21 12:57 u.sh</computeroutput>


<prompt>bash$ </prompt><userinput>echo "$(ls -l)"</userinput>
<computeroutput>total 8
 -rw-rw-r--  1 bo bo  13 Aug 21 12:57 t.sh
 -rw-rw-r--  1 bo bo  78 Aug 21 12:57 u.sh</computeroutput></screen>
	      </para>


      <sect1 id="quotingvar">
	<title>Quoting Variables</title>


      <para>When referencing a variable, it is generally advisable to
	enclose its name in double quotes.
	This prevents reinterpretation of all special characters within
	the quoted string -- the variable name
	    <footnote><para>It also has side-effects on the
	    <firstterm>value</firstterm> of the variable (see
	    below)</para></footnote>
	-- except <token>$</token>, <token>`</token> (backquote), and
	<token>\</token> (escape).

	    <footnote>

	    <para>Encapsulating <quote>!</quote> within double
	      quotes gives an error when used <emphasis>from the command
	      line</emphasis>. This is interpreted as a <link
	      linkend="histcommands">history command</link>. Within a script,
	      though, this problem does not occur, since the Bash history
	      mechanism is disabled then.</para>

	    <para>Of more concern is the <emphasis>apparently</emphasis>
	      inconsistent behavior of <quote>\</quote> within double
	      quotes.</para>

	      <para>
	      <screen>
<prompt>bash$ </prompt><userinput>echo hello\!</userinput>
<computeroutput>hello!</computeroutput>

<prompt>bash$ </prompt><userinput>echo "hello\!"</userinput>
<computeroutput>hello\!</computeroutput>



<prompt>bash$ </prompt><userinput>echo -e x\ty</userinput>
<computeroutput>xty</computeroutput>

<prompt>bash$ </prompt><userinput>echo -e "x\ty"</userinput>
<computeroutput>x       y</computeroutput>
	      </screen>
	      </para>

	    <para>What happens is that double quotes normally
	      <emphasis>escape</emphasis> the <quote>\</quote> escape
	      character, so that it echoes literally.  However, the
	      <option>-e</option> option to <firstterm>echo</firstterm>
	      changes that. It causes the <quote>\t</quote> to be
	      interpreted as a <firstterm>tab</firstterm>.</para>

            <para>(Thank you, Wayne Pollock, for pointing this out, and Geoff
	      Lee for explaining it.) </para>
	      
	      </footnote>
	
	Keeping <token>$</token> as a special character within
	double quotes permits referencing a quoted variable
	(<replaceable>"$variable"</replaceable>), that is, replacing the
	variable with its value (see <xref linkend="ex9">, above).</para>

      <para><anchor id="wsquo"></para>
      <para>Use double quotes to prevent word splitting.
            <footnote><para><quote>Word splitting</quote>, in this context,
	      means dividing a character string into a number of separate and
	      discrete arguments.</para></footnote>
	An argument enclosed in double quotes presents
	itself as a single word, even if it contains <link
	linkend="whitespaceref">whitespace</link> separators.</para>


<para><anchor id="varsplitting"></para>
<para><programlisting>List="one two three"

for a in $List     # Splits the variable in parts at whitespace.
do
  echo "$a"
done
# one
# two
# three

echo "---"

for a in "$List"   # Preserves whitespace in a single variable.
do #     ^     ^
  echo "$a"
done
# one two three</programlisting></para>

      <para>A more elaborate example:</para>

<para><programlisting>variable1="a variable containing five words"
COMMAND This is $variable1    # Executes COMMAND with 7 arguments:
# "This" "is" "a" "variable" "containing" "five" "words"

COMMAND "This is $variable1"  # Executes COMMAND with 1 argument:
# "This is a variable containing five words"


variable2=""    # Empty.

COMMAND $variable2 $variable2 $variable2
                # Executes COMMAND with no arguments. 
COMMAND "$variable2" "$variable2" "$variable2"
                # Executes COMMAND with 3 empty arguments. 
COMMAND "$variable2 $variable2 $variable2"
                # Executes COMMAND with 1 argument (2 spaces). 

# Thanks, St&eacute;phane Chazelas.
</programlisting></para>


      <tip><para>Enclosing the arguments to an <command>echo</command>
	statement in double quotes is necessary only when word splitting
	or preservation of <link linkend="whitespaceref">whitespace</link>
	is an issue.</para></tip>

	    <example id="weirdvars">
	      <title>Echoing Weird Variables</title>
	      <programlisting>&weirdvars;</programlisting>
	    </example>

      <para>Single quotes (<token>' '</token>) operate similarly to double
	quotes, but do not permit referencing variables, since
	the special meaning of <token>$</token> is turned off.
	Within single quotes, <emphasis>every</emphasis> special
	character except <token>'</token> gets interpreted literally.
	Consider single quotes (<quote>full quoting</quote>) to be a
	stricter method of quoting than double quotes (<quote>partial
	quoting</quote>).</para>

      <note><para>Since even the escape character (<token>\</token>)
	gets a literal interpretation within single quotes, trying to
	enclose a single quote within single quotes will not yield the
	expected result.
	<programlisting>echo "Why can't I write 's between single quotes"

echo

# The roundabout method.
echo 'Why can'\''t I write '"'"'s between single quotes'
#    |-------|  |----------|   |-----------------------|
# Three single-quoted strings, with escaped and quoted single quotes between.

# This example courtesy of St&eacute;phane Chazelas.</programlisting>
      </para></note>

      </sect1> <!-- Quoting Variables -->



      <sect1 id="escapingsection">
	<title>Escaping</title>

      <para><anchor id="escp"><firstterm>Escaping</firstterm> is a method
	of quoting single characters. The <token>escape</token>
	(<token>\</token>) preceding a character tells the shell to
	interpret that character literally.</para>

      <caution><para>With certain commands and utilities, such as <link
	linkend="echoref">echo</link> and <link
	linkend="sedref">sed</link>, escaping a character may have the
	opposite effect - it can toggle on a special meaning for that
	character.</para></caution>

      <variablelist id="specialmeanings">
	<title><anchor id="spm">Special meanings of certain
	escaped characters</title>

	<varlistentry>
	<term>used with <command>echo</command> and
	<command>sed</command></term>
	<listitem><para></para></listitem>
	</varlistentry>

	<varlistentry><term><token>\n</token></term>
	  <indexterm>
	    <primary>\n</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\n</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>newline</primary>
	  </indexterm>
	  <listitem><para>means newline</para>
	  </listitem>
	</varlistentry>

	<varlistentry><term><token>\r</token></term>
	  <indexterm>
	    <primary>\r</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\r</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>carriage return</primary>
	  </indexterm>
	  <listitem><para>means return</para>
	  </listitem>
	</varlistentry>

	<varlistentry><term><token>\t</token></term>
	  <indexterm>
	    <primary>\t</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\t</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>tabulation</primary>
	  </indexterm>
	  <listitem><para>means tab</para>
	  </listitem>
	</varlistentry>

	<varlistentry><term><token>\v</token></term>
	  <indexterm>
	    <primary>\v</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\v</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>vertical tabulation</primary>
	  </indexterm>
	  <listitem><para> means vertical tab</para>
	  </listitem>
	</varlistentry>

	<varlistentry><term><token>\b</token></term>
	  <indexterm>
	    <primary>\b</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\b</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>backspace</primary>
	  </indexterm>
	<listitem><para>means backspace</para>
	</listitem>
	</varlistentry>

	<varlistentry><term><token>\a</token></term>
	  <indexterm>
	    <primary>\a</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\a</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>alert</primary>
	  </indexterm>
	  <indexterm>
	    <primary>beep</primary>
	  </indexterm>
	  <indexterm>
	    <primary>flash</primary>
	  </indexterm>
	<listitem><para>means <firstterm>alert</firstterm> (beep or flash)</para>
	</listitem>
	</varlistentry>

	<varlistentry><term><token>\0xx</token></term>
	  <indexterm>
	    <primary>\0xx</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\0nn</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>octal ASCII</primary>
	  </indexterm>
	  <listitem><para><anchor id="octalref">translates to the
	      octal ASCII equivalent of <replaceable>0nn</replaceable>,
	      where <replaceable>nn</replaceable> is a string of
	      digits</para>

      <example id="escaped">
	<title>Escaped Characters</title>
	<programlisting>&escaped;</programlisting>
      </example>

            <para>See <xref linkend="ex77"> for another example of the
              <userinput>$' ... '</userinput> string-expansion
              construct.</para>

	</listitem>
	</varlistentry>

	<varlistentry><term><token>\"</token></term>
	  <indexterm>
	    <primary>\"</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\"</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>quote</primary>
	  </indexterm>
	<listitem><para> gives the quote its literal meaning</para>
	<para><programlisting>echo "Hello"                     # Hello
echo "\"Hello\" ... he said."    # "Hello" ... he said.</programlisting></para>
	</listitem>
	</varlistentry>

	<varlistentry><term><token>\$</token></term>
	  <indexterm>
	    <primary>\$</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\$</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>dollar</primary>
	  </indexterm>
	  <listitem><para>gives the dollar sign its literal meaning
	      (variable name following <token>\$</token> will not be
	      referenced)</para>
            <para><programlisting>echo "\$variable01"           # $variable01
echo "The book cost \$7.98."  # The book cost $7.98.</programlisting></para>
	  </listitem>
	  </varlistentry>

	<varlistentry><term><token>\\</token></term>
	  <indexterm>
	    <primary>\\</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\\</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>double backslash</primary>
	  </indexterm>
	  <listitem><para>gives the backslash its literal meaning</para>
	    <para><programlisting>echo "\\"  # Results in \

# Whereas . . .

echo "\"   # Invokes secondary prompt from the command line.
           # In a script, gives an error message.

# However . . .

echo '\'   # Results in \</programlisting></para>

	  </listitem>
	  </varlistentry>
	</variablelist>

      <note>
      <para>The behavior of <token>\</token> depends on whether
	it is escaped, <link linkend="snglquo">strong-quoted</link>,
	<link linkend="dblquo">weak-quoted</link>, or appearing within
	<link linkend="commandsubref">command substitution</link> or a
	<link linkend="heredocref">here document</link>.

	<programlisting>                      #  Simple escaping and quoting
echo \z               #  z
echo \\z              # \z
echo '\z'             # \z
echo '\\z'            # \\z
echo "\z"             # \z
echo "\\z"            # \z

                      #  Command substitution
echo `echo \z`        #  z
echo `echo \\z`       #  z
echo `echo \\\z`      # \z
echo `echo \\\\z`     # \z
echo `echo \\\\\\z`   # \z
echo `echo \\\\\\\z`  # \\z
echo `echo "\z"`      # \z
echo `echo "\\z"`     # \z

                      # Here document
cat &lt;&lt;EOF              
\z                      
EOF                   # \z

cat &lt;&lt;EOF              
\\z                     
EOF                   # \z

# These examples supplied by St&eacute;phane Chazelas.</programlisting>
      </para>

      <para>Elements of a string assigned to a variable may be escaped, but
        the escape character alone may not be assigned to a variable.
	<programlisting>variable=\
echo "$variable"
# Will not work - gives an error message:
# test.sh: : command not found
# A "naked" escape cannot safely be assigned to a variable.
#
#  What actually happens here is that the "\" escapes the newline and
#+ the effect is        variable=echo "$variable"
#+                      invalid variable assignment

variable=\
23skidoo
echo "$variable"        #  23skidoo
                        #  This works, since the second line
                        #+ is a valid variable assignment.

variable=\ 
#        \^    escape followed by space
echo "$variable"        # space

variable=\\
echo "$variable"        # \

variable=\\\
echo "$variable"
# Will not work - gives an error message:
# test.sh: \: command not found
#
#  First escape escapes second one, but the third one is left "naked",
#+ with same result as first instance, above.

variable=\\\\
echo "$variable"        # \\
                        # Second and fourth escapes escaped.
                        # This is o.k.</programlisting>
      </para>
      
      </note>   



      <para>Escaping a space can prevent word splitting in a command's argument list.
        <programlisting>file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
# List of files as argument(s) to a command.

# Add two files to the list, and list all.
ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list

echo "-------------------------------------------------------------------------"

# What happens if we escape a couple of spaces?
ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
# Error: the first three files concatenated into a single argument to 'ls -l'
#        because the two escaped spaces prevent argument (word) splitting.</programlisting>
</para>


      <para><anchor id="escnewline"></para>
      <para>The <token>escape</token> also provides a means of writing a
	multi-line command. Normally, each separate line constitutes
	a different command, but an <token>escape</token> at the end
	of a line <emphasis>escapes the newline character</emphasis>,
	and the command sequence continues on to the next line.</para>
      <para><programlisting>(cd /source/directory && tar cf - . ) | \
(cd /dest/directory && tar xpvf -)
# Repeating Alan Cox's directory tree copy command,
# but split into two lines for increased legibility.

# As an alternative:
tar cf - -C /source/directory . |
tar xpvf - -C /dest/directory
# See note below.
# (Thanks, St&eacute;phane Chazelas.)</programlisting>
        
	<note><para>If a script line ends with a <token>|</token>, a pipe
	  character, then a <token>\</token>, an escape, is not strictly
	  necessary. It is, however, good programming practice to always
	  escape the end of a line of code that continues to the
	  following line.</para></note></para>

	<para><programlisting>echo "foo
bar" 
#foo
#bar

echo

echo 'foo
bar'    # No difference yet.
#foo
#bar

echo

echo foo\
bar     # Newline escaped.
#foobar

echo

echo "foo\
bar"     # Same here, as \ still interpreted as escape within weak quotes.
#foobar

echo

echo 'foo\
bar'     # Escape character \ taken literally because of strong quoting.
#foo\
#bar

# Examples suggested by St&eacute;phane Chazelas.</programlisting></para>

      </sect1> <!-- Escaping -->


  </chapter> <!-- Quoting -->


  <chapter id="exit-status">
    <title>Exit and Exit Status</title>

    <epigraph>
      <para>... there are dark corners in the Bourne shell, and people use all
      of them.</para>
      <para>--Chet Ramey</para>
    </epigraph>
    
      <para><anchor id="exitcommandref">The 
	<command>
	  <indexterm>
	    <primary>exit</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>exit</secondary>
	  </indexterm>
	  exit
	</command> 
	command terminates a script, just as in a <firstterm>C</firstterm>
	program. It can also return a value, which is available to the
	script's parent process.</para>


      <para><anchor id="exitstatusref">Every command returns an 
	<firstterm>
	  <indexterm>
	    <primary>exit status</primary>
	  </indexterm>
	  exit status
	</firstterm> 
	(sometimes referred to as a 
	<firstterm>
	  <indexterm>
	    <primary>return status</primary>
	  </indexterm>
	  return status
	</firstterm> or <firstterm>exit code</firstterm>).
	<anchor id="exitsuccess">
	A successful command returns a <returnvalue>0</returnvalue>, while
	an unsuccessful one returns a <returnvalue>non-zero</returnvalue>
	value that usually may be interpreted as an <firstterm>error
	code</firstterm>. Well-behaved UNIX commands, programs, and
	utilities return a <returnvalue>0</returnvalue> exit code upon
	successful completion, though there are some exceptions.</para>

      <para>Likewise, functions within a script and the script itself
	return an exit status. The last command executed in the function
	or script determines the exit status. Within a script, an
	<userinput>exit <replaceable>nnn</replaceable></userinput>
	command may be used to deliver an
	<returnvalue><replaceable>nnn</replaceable></returnvalue> exit status
	to the shell (<returnvalue><replaceable>nnn</replaceable></returnvalue>
	must be a decimal number in the <returnvalue>0</returnvalue> -
	<returnvalue>255</returnvalue> range).</para>

      <note>

      <para>When a script ends with an <command>exit</command> that has
	no parameter, the exit status of the script is the exit status
	of the last command executed in the script (previous to the
	<command>exit</command>).</para>

      <para><programlisting>#!/bin/bash

COMMAND_1

. . .

# Will exit with status of last command.
COMMAND_LAST

exit</programlisting></para>

      <para>The equivalent of a bare <command>exit</command> is
        <command>exit $?</command> or even just omitting the
	<command>exit</command>.</para>

      <para><programlisting>#!/bin/bash

COMMAND_1

. . .

# Will exit with status of last command.
COMMAND_LAST

exit $?</programlisting></para>

      <para><programlisting>#!/bin/bash

COMMAND1

. . . 

# Will exit with status of last command.
COMMAND_LAST</programlisting></para>
	
	</note>

      <para><anchor id="exsref"></para>

      <para>
	<varname>
	  <indexterm>
	    <primary>$?</primary>
	  </indexterm> <indexterm>
	    <primary>variable</primary> <secondary>$?</secondary>
	  </indexterm> $?</varname> reads the exit status of the last
	    command executed. After a function returns,
	    <varname>$?</varname> gives the exit status of the last
	    command executed in the function. This is Bash's way of
	    giving functions a <quote>return value.</quote> After a
	    script terminates, a <varname>$?</varname> from the command
	    line gives the exit status of the script, that is, the last
	    command executed in the script, which is, by convention,
	    <userinput>0</userinput> on success or an integer in the
	    range <returnvalue>1 - 255</returnvalue> on error.</para>

      <example id="ex5">
	<title>exit / exit status</title>
	<programlisting>&ex5;</programlisting>
      </example>
      
      <para><link linkend="xstatvarref">$?</link> is especially useful
        for testing the result of a command in a script (see <xref
        linkend="filecomp"> and <xref linkend="lookup">).</para>

      <note>
      <para>The <link linkend="notref">!</link>, the <firstterm>logical
	not</firstterm> qualifier, reverses the outcome of a test or
	command, and this affects its <link linkend="exitstatusref">exit
	status</link>.

	<example id="negcond">
	<title>Negating a condition using <token>!</token></title>
	<programlisting>true    # The "true" builtin.
echo "exit status of \"true\" = $?"     # 0

! true
echo "exit status of \"! true\" = $?"   # 1
# Note that the "!" needs a space between it and the command.
#    !true   leads to a "command not found" error
#
# The '!' operator prefixing a command invokes the Bash history mechanism.

true
!true
# No error this time, but no negation either.
# It just repeats the previous command (true).

# Thanks, St&eacute;phane Chazelas and Kristopher Newsome.</programlisting>
        </example>

      </para>
      </note>


      <caution><para>Certain exit status codes have <link
	linkend="exitcodesref">reserved meanings</link> and should not
	be user-specified in a script.	</para></caution>


  </chapter> <!-- Exit and Exit status -->


  <chapter id="tests">
    <title>Tests</title>

      <para><anchor id="ifthen"></para>

      <indexterm>
	<primary>if</primary>
      </indexterm>
      <indexterm>
	<primary>test</primary>
	<secondary>if</secondary>
      </indexterm>
      <indexterm>
	<primary>then</primary>
      </indexterm>
      <indexterm>
	<primary>else</primary>
      </indexterm>
      <indexterm>
	<primary>else if</primary>
      </indexterm>
      <indexterm>
	<primary>elif</primary>
      </indexterm>

        <para>Every reasonably complete programming language can test
	  for a condition, then act according to the result of the
	  test. Bash has the <link linkend="ttestref">test</link>
	  command, various <link linkend="dblbrackets">bracket</link>
	  and <link linkend="dblparenstst">parenthesis</link> operators,
	  and the <command>if/then</command> construct.</para>

      <sect1 id="testconstructs">
	<title>Test Constructs</title>

	<para><anchor id="testconstructs1"></para>

      <itemizedlist id="testingref">

        <listitem>
	<para>An <command>if/then</command> construct tests whether the
	  <link linkend="exitstatusref">exit status</link> of a list
	  of commands is <returnvalue>0</returnvalue> (since 0 means
	  <quote>success</quote> by UNIX convention), and if so, executes
	  one or more commands.</para>
	</listitem>

        <listitem>
	<para>There exists a dedicated command called <command>
	[</command> (<link linkend="leftbracket">left bracket</link>
	special character). It is a synonym for <command>test</command>,
	and a <link linkend="builtinref">builtin</link> for efficiency
	reasons. This command considers its arguments as comparison
	expressions or file tests and returns an exit status corresponding
	to the result of the comparison (0 for true, 1 for false).</para>
	</listitem>

        <listitem>
	<para>With version 2.02, Bash introduced the <link
	  linkend="dblbrackets">[[ ... ]]</link> <firstterm>extended
	  test command</firstterm>, which performs comparisons
	  in a manner more familiar to programmers from other
	  languages. Note that <command>[[</command> is a <link
	  linkend="keywordref">keyword</link>, not a command.</para>

	<para>Bash sees <userinput>[[ $a -lt $b ]]</userinput> as a
	  single element, which returns an exit status.</para>
        </listitem>

        <listitem>
	<para><anchor id="dblparenstst"></para>
	<para>The <link linkend="dblparens">(( ... ))</link> and <link
	  linkend="letref">let ...</link> constructs also return an
	  exit status, according to whether the arithmetic expressions
	  they evaluate expand to a non-zero value. These <link
	  linkend="arithexpref">arithmetic-expansion</link> constructs
	  may therefore be used to perform <link
	  linkend="icomparison1">arithmetic comparisons</link>.</para>

        <para>
        <programlisting>(( 0 && 1 ))                 # Logical AND
echo $?     # 1     ***
# And so ...
let "num = (( 0 && 1 ))"
echo $num   # 0
# But ...
let "num = (( 0 && 1 ))"
echo $?     # 1     ***


(( 200 || 11 ))              # Logical OR
echo $?     # 0     ***
# ...
let "num = (( 200 || 11 ))"
echo $num   # 1
let "num = (( 200 || 11 ))"
echo $?     # 0     ***


(( 200 | 11 ))               # Bitwise OR
echo $?                      # 0     ***
# ...
let "num = (( 200 | 11 ))"
echo $num                    # 203
let "num = (( 200 | 11 ))"
echo $?                      # 0     ***

# The "let" construct returns the same exit status
#+ as the double-parentheses arithmetic expansion.</programlisting>	    
	  </para>
        </listitem>

        <listitem>
          <para><anchor id="ifgrepref"></para>

	  <para>An <command>if</command> can test any command, not just
	    conditions enclosed within brackets.</para>


   <para><programlisting>if cmp a b &amp;&gt; /dev/null  # Suppress output.
then echo "Files a and b are identical."
else echo "Files a and b differ."
fi

# The very useful "if-grep" construct:
# ----------------------------------- 
if grep -q Bash file
then echo "File contains at least one occurrence of Bash."
fi

word=Linux
letter_sequence=inu
if echo "$word" | grep -q "$letter_sequence"
# The "-q" option to grep suppresses output.
then
  echo "$letter_sequence found in $word"
else
  echo "$letter_sequence not found in $word"
fi


if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED
then echo "Command succeeded."
else echo "Command failed."
fi</programlisting>
          </para>
        </listitem>

        <listitem>


	  <para><emphasis>These last two examples
	  courtesy of St&eacute;phane Chazelas.</emphasis></para>

        </listitem>


      </itemizedlist>



      <example id="ex10">
	<title>What is truth?</title>
	<programlisting>&ex10;</programlisting>
      </example>

      <formalpara><title>Exercise</title>
	<para>Explain the behavior of <xref linkend="ex10">, above.</para>
      </formalpara>
      
      <para><anchor id="elseref"><programlisting>if [ condition-true ]
then
   command 1
   command 2
   ...
else  # Or else ...
      # Adds default code block executing if original condition tests false.
   command 3
   command 4
   ...
fi</programlisting>
      </para>

      <note>
      <para>When <firstterm>if</firstterm> and <firstterm>then</firstterm>
	are on same line in a condition test, a semicolon must
	terminate the <firstterm>if</firstterm> statement.  Both
	<firstterm>if</firstterm> and <firstterm>then</firstterm>
	are <link linkend="keywordref">keywords</link>.  Keywords (or
	commands) begin statements, and before a new statement on the
	same line begins, the old one must terminate.</para>

      <para><programlisting>if [ -x "$filename" ]; then</programlisting></para>
      </note>

      <variablelist id="elifref">
        <title><anchor id="elifref1">Else if and elif</title>
	<varlistentry>
          <term><token>elif</token></term>
	  <listitem>
	    <para><userinput>elif</userinput> is a contraction
	      for <firstterm>else if</firstterm>. The effect is to nest an
	      inner <token>if/then</token> construct within an outer
	      one.</para>

	    <para><programlisting>if [ condition1 ]
then
   command1
   command2
   command3
elif [ condition2 ]
# Same as else if
then
   command4
   command5
else
   default-command
fi</programlisting>
	      </para>
	  </listitem>
	</varlistentry>
      </variablelist>

      <para>
      <indexterm>
	<primary>test</primary>
      </indexterm>
      <indexterm>
	<primary>test</primary>
	<secondary>test</secondary>
      </indexterm>
      <indexterm>
	<primary>[</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>[</secondary>
      </indexterm>
      <indexterm>
	<primary>]</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>]</secondary>
      </indexterm>
	<anchor id="ifref2">
	The <userinput>if test condition-true</userinput> construct is the
	exact equivalent of <userinput>if [ condition-true ]</userinput>.
	As it happens, the left bracket, <command>[</command> , is a token
	which invokes the <command>test</command> command.  The closing
	right bracket, <command>]</command> , in an if/test should not
	therefore be strictly necessary, however newer versions of Bash
	require it.</para>

	<para><anchor id="ttestref"></para>
	<note><para>The <command>test</command> command is a Bash <link
	  linkend="builtinref">builtin</link> which tests file
	  types and compares strings. Therefore, in a Bash script,
	  <command>test</command> does <emphasis>not</emphasis> call
	  the external <filename>/usr/bin/test</filename> binary,
	  which is part of the <firstterm>sh-utils</firstterm>
	  package. Likewise, <command>[</command> does not call
	  <filename>/usr/bin/[</filename>, which is linked to
	  <filename>/usr/bin/test</filename>.</para>

	    <para>
	      <screen>
<prompt>bash$ </prompt><userinput>type test</userinput>
<computeroutput>test is a shell builtin</computeroutput>
<prompt>bash$ </prompt><userinput>type '['</userinput>
<computeroutput>[ is a shell builtin</computeroutput>
<prompt>bash$ </prompt><userinput>type '[['</userinput>
<computeroutput>[[ is a shell keyword</computeroutput>
<prompt>bash$ </prompt><userinput>type ']]'</userinput>
<computeroutput>]] is a shell keyword</computeroutput>
<prompt>bash$ </prompt><userinput>type ']'</userinput>
<computeroutput>bash: type: ]: not found</computeroutput>
	      </screen>
	    </para>
	    
	<para><anchor id="usrbintest"></para>
	<para>If, for some reason, you wish to use
	  <filename>/usr/bin/test</filename> in a Bash script,
	  then specify it by full pathname.</para>
	    
	    </note>
      

      <example id="ex11">
	<title>Equivalence of <firstterm>test</firstterm>,
	  <filename>/usr/bin/test</filename>, <token>[ ]</token>,
	  and <filename>/usr/bin/[</filename></title>
	<programlisting>&ex11;</programlisting>
      </example>


      <indexterm>
	<primary>test</primary>
      </indexterm>
      <indexterm>
	<primary>test</primary>
	<secondary>test</secondary>
      </indexterm>
      <indexterm>
	<primary>[[</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>[[</secondary>
      </indexterm>
      <indexterm>
	<primary>]]</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>]]</secondary>
      </indexterm>


      <sidebar>

      <para><anchor id="dblbrackets">The <token>[[  ]]</token> construct
	is the more versatile Bash version of <token>[	]</token>. This
	is the <firstterm>extended test command</firstterm>, adopted from
	<firstterm>ksh88</firstterm>.</para>

      <para>*  *  *</para>

      <para>No filename expansion or word splitting takes place
	between <token>[[</token> and <token>]]</token>, but there is
	parameter expansion and command substitution.

	<programlisting>file=/etc/passwd

if [[ -e $file ]]
then
  echo "Password file exists."
fi</programlisting>
      </para>


      <para>Using the <command>[[ ... ]]</command> test construct,
	rather than <command>[ ... ]</command> can prevent many
	logic errors in scripts. For example, the <token>&&</token>,
	<token>||</token>, <token>&lt;</token>, and <token>&gt;</token>
	operators work within a <token>[[  ]]</token> test, despite
	giving an error within a <token>[  ]</token> construct.</para>


      <para><anchor id="dblbraev"></para>
      <para><firstterm>Arithmetic evaluation</firstterm> of octal /
        hexadecimal constants takes place automatically within a
	<token>[[ ... ]]</token> construct.
	<programlisting># [[ Octal and hexadecimal evaluation ]]
# Thank you, Moritz Gronbach, for pointing this out.


decimal=15
octal=017   # = 15 (decimal)
hex=0x0f    # = 15 (decimal)

if [ "$decimal" -eq "$octal" ]
then
  echo "$decimal equals $octal"
else
  echo "$decimal is not equal to $octal"       # 15 is not equal to 017
fi      # Doesn't evaluate within [ single brackets ]!


if [[ "$decimal" -eq "$octal" ]]
then
  echo "$decimal equals $octal"                # 15 equals 017
else
  echo "$decimal is not equal to $octal"
fi      # Evaluates within [[ double brackets ]]!

if [[ "$decimal" -eq "$hex" ]]
then
  echo "$decimal equals $hex"                  # 15 equals 0x0f
else
  echo "$decimal is not equal to $hex"
fi      # [[ $hexadecimal ]] also evaluates!</programlisting>
      </para>

      </sidebar>


      <note>
      <para>Following an <command>if</command>, neither the
        <command>test</command> command nor the test brackets ( [ ] or [[ ]] )
	are strictly necessary.

	<programlisting>dir=/home/bozo

if cd "$dir" 2&gt;/dev/null; then   # "2&gt;/dev/null" hides error message.
  echo "Now in $dir."
else
  echo "Can't change to $dir."
fi</programlisting>

        The "if COMMAND" construct returns the exit status of COMMAND.
</para>

	
	<para>Similarly, a condition within test brackets may stand alone
	  without an <command>if</command>, when used in combination
	  with a <link linkend="listconsref">list construct</link>.

	  <programlisting>var1=20
var2=22
[ "$var1" -ne "$var2" ] && echo "$var1 is not equal to $var2"

home=/home/bozo
[ -d "$home" ] || echo "$home directory does not exist."</programlisting></para>
	  </note>


      <indexterm>
	<primary>test</primary>
      </indexterm>
      <indexterm>
	<primary>test</primary>
	<secondary>test</secondary>
      </indexterm>
      <indexterm>
	<primary>((</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>))</secondary>
      </indexterm>
      <indexterm>
	<primary>((</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>))</secondary>
      </indexterm>

      <para><anchor id="dblprx">The <link linkend="dblparens">(( ))
	construct</link> expands and evaluates an arithmetic
	expression. If the expression evaluates as zero, it returns
	an <link linkend="exitstatusref">exit status</link> of
	<returnvalue>1</returnvalue>, or <quote>false</quote>. A non-zero
	expression returns an exit status of <returnvalue>0</returnvalue>,
	or <quote>true</quote>. This is in marked contrast to using
	the <command>test</command> and <token>[ ]</token> constructs
	previously discussed.</para>

        <example id="arithtests">
	  <title>Arithmetic Tests using <token>(( ))</token></title>
	  <programlisting>&arithtests;</programlisting>
        </example>

      </sect1> <!-- Test Constructs -->


      <sect1 id="fto">
	<title>File test operators</title>

	<variablelist>
	  <title><anchor id="rtif">Returns true if...</title>
	  <varlistentry>
	    <term><token>-e</token></term>
	    <listitem><para>file exists</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-a</token></term>
	    <listitem><para>file exists</para>
	    <para>This is identical in effect to <token>-e</token>.
	      It has been <quote>deprecated,</quote>

	        <footnote><para>
		Per the 1913 edition of <emphasis>Webster's
		Dictionary</emphasis>:
		<programlisting>Deprecate
...

To pray against, as an evil;
to seek to avert by prayer;
to desire the removal of;
to seek deliverance from;
to express deep regret for;
to disapprove of strongly.</programlisting>
	        </para></footnote>
	      
	      and its use is
	      discouraged.</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><anchor id="regularfile"><token>-f</token></term>
	    <listitem><para>file is a <replaceable>regular</replaceable>
	      file (not a directory or device file)</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-s</token></term>
	    <listitem><para>file is not zero size</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-d</token></term>
	    <listitem><para>file is a directory</para></listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><token>-b</token></term>
	    <listitem>
	    <para>file is a <link linkend="blockdevref">block
	    device</link></para>
	    <para><anchor id="blockdevtest"></para>
            <para><programlisting>device="/dev/sda2"   # /   (root directory)
if [ -b "$device" ]
then
  echo "$device is a block device."
fi

# /dev/sda2 is a block device.</programlisting></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><token>-c</token></term>
	    <listitem><para>file is a <link linkend="chardevref">character
	    device</link></para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-p</token></term>
	    <listitem><para>file is a <link linkend="piperef">pipe</link></para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-h</token></term>
	    <listitem><para>file is a <link linkend="symlinkref">symbolic
	      link</link></para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-L</token></term>
	    <listitem><para>file is a symbolic link</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-S</token></term>
	    <listitem><para>file is a <link linkend="socketref">socket</link></para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-t</token></term>
	    <listitem>
	    <para>file (<link linkend="fdref">descriptor</link>) is
	      associated with a terminal device</para>
	    <para>This test option may be used to check whether the
	      <filename>stdin</filename> (<userinput>[ -t 0 ]</userinput>)
	      or <filename>stdout</filename> (<userinput>[ -t 1 ]</userinput>)
	      in a given script is a terminal.</para>
	    </listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-r</token></term>
	    <listitem><para>file has read permission (<emphasis>for the
	      user running the test</emphasis>)</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-w</token></term>
	    <listitem><para>file has write permission (for the user running
	      the test)</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-x</token></term>
	    <listitem><para>file has execute permission (for the user running
	    the test)</para></listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><token>-g</token></term>
	    <listitem>
	    <para>set-group-id (sgid) flag set on file or directory</para>
	    <para>If a directory has the <replaceable>sgid</replaceable>
	      flag set, then a file created within that directory belongs
	      to the group that owns the directory, not necessarily to
	      the group of the user who created the file. This may be
	      useful for a directory shared by a workgroup.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><token>-u</token></term>
	    <listitem>
	    <para><anchor id="suidref"></para>
	    <para>set-user-id (suid) flag set on file</para>
	    <para>A binary owned by <firstterm>root</firstterm>
	      with <replaceable>set-user-id</replaceable> flag set
	      runs with <firstterm>root</firstterm> privileges, even
	      when an ordinary user invokes it.
	      
		<footnote><para>Be aware that <firstterm>suid</firstterm>
		  binaries may open security holes. The
		  <firstterm>suid</firstterm> flag has no effect on
		  shell scripts.</para></footnote>

	      This is useful for executables (such as
	      <command>pppd</command> and <command>cdrecord</command>)
	      that need to access system hardware. Lacking the
	      <firstterm>suid</firstterm> flag, these binaries could not
	      be invoked by a <firstterm>non-root</firstterm> user.</para>

	      <para>
	      <screen>
	      <computeroutput>-rwsr-xr-t    1 root       178236 Oct  2  2000 /usr/sbin/pppd</computeroutput>
	      </screen>
	      </para>

	      <para>A file with the <replaceable>suid</replaceable>
		flag set shows an <firstterm>s</firstterm> in its
		permissions.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><token>-k</token></term>
	    <listitem>

	    <para><replaceable>sticky bit</replaceable> set</para>

	    <para>Commonly known as the <firstterm>sticky bit,</firstterm>
	      the <firstterm>save-text-mode</firstterm> flag is a special
	      type of file permission. If a file has this flag set,
	      that file will be kept in cache memory, for quicker access.
	        <footnote><para>On modern UNIX systems, the sticky
		  bit is no longer used for files, only on
		  directories.</para></footnote>
	      If set on a directory, it restricts write permission.
	      Setting the sticky bit adds a <firstterm>t</firstterm>
	      to the permissions on the file or directory listing.</para>

	      <para>
	      <screen>
	      <computeroutput>drwxrwxrwt    7 root         1024 May 19 21:26 tmp/</computeroutput>
	      </screen>
	      </para>
	    
	      <para>If a user does not own a directory that has the sticky
		bit set, but has write permission in that directory, she
		can only delete those files that she owns in it. This
		keeps users from inadvertently overwriting or deleting
		each other's files in a publicly accessible directory,
		such as <filename class="directory">/tmp</filename>.
		(The <firstterm>owner</firstterm> of the directory or
		<firstterm>root</firstterm> can, of course, delete or
		rename files there.)</para>

	    </listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-O</token></term>
	    <listitem><para>you are owner of file</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-G</token></term>
	    <listitem><para>group-id of file same as yours</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>-N</token></term>
	    <listitem><para>file modified since it was last read</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>f1 -nt f2</token></term>
	    <listitem><para>file <replaceable>f1</replaceable> is newer than
		<replaceable>f2</replaceable></para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>f1 -ot f2</token></term>
	    <listitem><para>file <replaceable>f1</replaceable> is older than
		<replaceable>f2</replaceable></para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>f1 -ef f2</token></term>
	    <listitem><para>files <replaceable>f1</replaceable> and
		<replaceable>f2</replaceable> are hard links to the same
		file</para></listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><token>!</token></term>
	    <listitem><para><quote>not</quote> -- reverses the sense of the
	    tests above (returns true if condition absent).</para></listitem>
	  </varlistentry>
	</variablelist>

	<example id="brokenlink">
	  <title>Testing for broken links</title>
	  <programlisting>&brokenlink;</programlisting>
	</example>

	<para><xref linkend="cookies">, <xref linkend="bingrep">,
	  <xref linkend="fileinfo">, <xref linkend="ramdisk">, and <xref
	  linkend="mailformat"> also illustrate uses of the file test
	  operators.</para>


      </sect1> <!-- File test operators -->

      <sect1 id="comparison-ops">
	<title>Other Comparison Operators</title>

	<para>A <firstterm>binary</firstterm> comparison operator
	  compares two variables or quantities. <emphasis>Note
	  that integer and string comparison use a different set of
	  operators.</emphasis></para>

	<variablelist id="icomparison">
	  <title><anchor id="icomparison1">integer comparison</title>

	  <varlistentry>
	    <term><anchor id="equalref"><token>-eq</token></term>
	    <listitem>
	    <para>is equal to</para>
	    <para><userinput>if [ "$a" -eq "$b" ]</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="nequalref"><token>-ne</token></term>
	    <listitem>
	    <para>is not equal to</para>
	    <para><userinput>if [ "$a" -ne "$b" ]</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="gt0ref"><token>-gt</token></term>
	    <listitem>
	    <para>is greater than</para>
	    <para><userinput>if [ "$a" -gt "$b" ]</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="ge0ref"><token>-ge</token></term>
	    <listitem>
	    <para>is greater than or equal to</para>
	    <para><userinput>if [ "$a" -ge "$b" ]</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="lt0ref"><token>-lt</token></term>
	    <listitem>
	    <para>is less than</para>
	    <para><userinput>if [ "$a" -lt "$b" ]</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="le0ref"><token>-le</token></term>
	    <listitem>
	    <para>is less than or equal to</para>
	    <para><userinput>if [ "$a" -le "$b" ]</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="intlt"><token>&lt;</token></term>
	    <listitem>
	    <para>is less than (within <link linkend="dblparens">double
	      parentheses</link>)</para>
	    <para><userinput>(("$a" &lt; "$b"))</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="lteq"><token>&lt;=</token></term>
	    <listitem>
	    <para>is less than or equal to (within double parentheses)</para>
	    <para><userinput>(("$a" &lt;= "$b"))</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="intgt"><token>&gt;</token></term>
	    <listitem>
	    <para>is greater than (within double parentheses)</para>
	    <para><userinput>(("$a" &gt; "$b"))</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="gteq"><token>&gt;=</token></term>
	    <listitem>
	    <para>is greater than or equal to (within double parentheses)</para>
	    <para><userinput>(("$a" &gt;= "$b"))</userinput></para>
	    </listitem>
	  </varlistentry>
	  
	</variablelist>
	
	<variablelist id="scomparison">
	  <title><anchor id="scomparison1">string comparison</title>
	  <varlistentry>
	    <term><token>=</token></term>
	    <listitem>
	    <para><anchor id="equalsignref"></para>
	    <para>is equal to</para>
	    <para><userinput>if [ "$a" = "$b" ]</userinput></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="scomparison2"><token>==</token></term>
	    <listitem>
	      <para>is equal to</para>
	      <para><userinput>if [ "$a" == "$b" ]</userinput></para>
	      <para>This is a synonym for <token>=</token>.</para>

	      <note><para>
	      The <token>==</token> comparison operator behaves differently
	      within a <link linkend="dblbrackets">double-brackets</link>
	      test than within single brackets.
              <programlisting>[[ $a == z* ]]   # True if $a starts with an "z" (regex pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

[ $a == z* ]     # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).

# Thanks, St&eacute;phane Chazelas</programlisting>
              </para></note>

	      </listitem>
	  </varlistentry>
	  <varlistentry>
	    <term><anchor id="notequal"><token>!=</token></term>
	    <listitem>
	    <para>is not equal to</para>
	    <para><userinput>if [ "$a" != "$b" ]</userinput></para>
	    <para>This operator uses pattern matching within a <link
	      linkend="dblbrackets">[[ ... ]]</link> construct.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="ltref"><token>&lt;</token></term>
	    <listitem>
	    <para>is less than, in ASCII alphabetical order</para>
	    <para><userinput>if [[ "$a" &lt; "$b" ]]</userinput></para>
	    <para><userinput>if [ "$a" \&lt; "$b" ]</userinput></para>
	    <para>Note that the <quote>&lt;</quote> needs to be
	      <link linkend="escp">escaped</link> within a
	      <userinput>[  ]</userinput> construct.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="gtref"><token>&gt;</token></term>
	    <listitem>
	    <para>is greater than, in ASCII alphabetical order</para>
	    <para><userinput>if [[ "$a" &gt; "$b" ]]</userinput></para>
	    <para><userinput>if [ "$a" \&gt; "$b" ]</userinput></para>
	    <para>Note that the <quote>&gt;</quote> needs to be
	      escaped within a <userinput>[  ]</userinput> construct.</para>  
	    <para>See <xref linkend="bubble"> for an application of this
	      comparison operator.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="stringnull"><token>-z</token></term>
	    <listitem>
	      <para>string is <firstterm>null</firstterm>,
	        that is, has zero length</para>
                <para><programlisting> String=''   # Zero-length ("null") string variable.

if [ -z "$String" ]
then
  echo "\$String is null."
else
  echo "\$String is NOT null."
fi     # $String is null.</programlisting></para>
	     </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="stringnotnull"><token>-n</token></term>
	    <listitem>
	      <para>string is not <firstterm>null.</firstterm></para>
	    
	      <caution><para>The <userinput>-n</userinput> test
		requires that the string be quoted within the
		test brackets. Using an unquoted string with
		<firstterm>! -z</firstterm>, or even just the
		unquoted string alone within test brackets (see <xref
		linkend="strtest">) normally works, however, this is
		an unsafe practice. <emphasis>Always</emphasis> quote
		a tested string.
		  <footnote><para>As S.C. points out, in a compound test,
		    even quoting the string variable might not
		    suffice. <userinput>[ -n "$string" -o "$a" = "$b" ]</userinput>
		    may cause an error with some versions of Bash if
		    <varname>$string</varname> is empty. The safe way
		    is to append an extra character to possibly empty variables,
		    <userinput>[ "x$string" != x -o "x$a" = "x$b" ]</userinput>
		    (the <quote>x's</quote> cancel out).</para></footnote>
		</para></caution>
            </listitem>
	    </varlistentry>



	</variablelist>
	
	<example id="ex13">
	  <title>Arithmetic and string comparisons</title>
	  <programlisting>&ex13;</programlisting>
	</example>

	<example id="strtest">
	  <title>Testing whether a string is <firstterm>null</firstterm></title>
	  <programlisting>&strtest;</programlisting>
	</example>
      
	<example id="ex14">
	  <title><firstterm>zmore</firstterm></title>
	  <programlisting>&ex14;</programlisting>
	</example>

	<variablelist id="ccomparison">  
	  <title><anchor id="ccomparison1">compound comparison</title>

	  <varlistentry>
	    <term><anchor id="compoundand"><token>-a</token></term>
	    <listitem>
	      <para>logical and</para>
	      <para><replaceable>exp1 -a exp2</replaceable> returns true if
		<emphasis>both</emphasis> exp1 and exp2 are true.</para>
	    </listitem>
            </varlistentry>

	  <varlistentry>
	    <term><anchor id="compoundor"><token>-o</token></term>
	    <listitem>
	      <para>logical or </para>
	      <para><replaceable>exp1 -o exp2</replaceable> returns
		true if either exp1 <emphasis>or</emphasis> exp2 is
		true.</para>
	    </listitem>
	    </varlistentry>
	</variablelist>

       <para>
         These are similar to the Bash comparison operators
	 <command>&&</command> and <command>||</command>, used
	 within <link linkend="dblbrackets">double brackets</link>.
	   <programlisting>[[ condition1 && condition2 ]]</programlisting>
       </para>

       <para>
	 The <command>-o</command> and <command>-a</command> operators
	 work with the <link linkend="ttestref">test</link> command or
	 occur within single test brackets.
	   <programlisting>if [ "$exp1" -a "$exp2" ]</programlisting>
	   </para>

       <para>Refer to <xref linkend="andor">, <xref linkend="twodim">,
	 and <xref linkend="whx"> to see compound comparison operators
	 in action.</para>

      </sect1> <!-- Comparison operators (binary) -->

      <sect1 id="nestedifthen">
        <title>Nested <replaceable>if/then</replaceable> Condition Tests</title>

       <para>Condition tests using the <replaceable>if/then</replaceable>
	 construct may be nested. The net result is equivalent to using the
	 <link linkend="logicaland"><firstterm>&&</firstterm></link> compound
	 comparison operator.</para>

       <para><programlisting>if [ condition1 ]
then
  if [ condition2 ]
  then
    do-something  # But only if both "condition1" AND "condition2" valid.
  fi  
fi</programlisting></para>  

       <para><xref linkend="cards"> demonstrates a nested
	 <replaceable>if/then</replaceable> condition test.</para>

      </sect1> <!-- Nested if/then Tests -->

      <sect1 id="testtest">
        <title>Testing Your Knowledge of Tests</title>

      <para>The systemwide <filename>xinitrc</filename> file can be used
	to launch the X server. This file contains quite a number
	of <firstterm>if/then</firstterm> tests. The following
	is excerpted from an <quote>ancient</quote> version of
	<filename>xinitrc</filename> (<firstterm>Red Hat 7.1</firstterm>,
	or thereabouts).</para>

      <para><programlisting>if [ -f $HOME/.Xclients ]; then
  exec $HOME/.Xclients
elif [ -f /etc/X11/xinit/Xclients ]; then
  exec /etc/X11/xinit/Xclients
else
     # failsafe settings.  Although we should never get here
     # (we provide fallbacks in Xclients as well) it can't hurt.
     xclock -geometry 100x100-5+5 &
     xterm -geometry 80x50-50+150 &
     if [ -f /usr/bin/netscape -a -f /usr/share/doc/HTML/index.html ]; then
             netscape /usr/share/doc/HTML/index.html &
     fi
fi</programlisting></para>     

     <para>Explain the <firstterm>test</firstterm> constructs in the
       above snippet, then examine an updated version of the
       file, <filename>/etc/X11/xinit/xinitrc</filename>, and
       analyze the <firstterm>if/then</firstterm> test constructs
       there. You may need to refer ahead to the discussions of <link
       linkend="grepref">grep</link>, <link linkend="sedref">sed</link>,
       and <link linkend="regexref">regular expressions</link>.</para>


      </sect1> <!-- Testing Your Knowledge of Tests -->

  </chapter> <!-- Tests -->



  <chapter id="operations">
    <title>Operations and Related Topics</title>


     <sect1 id="ops">
      <title>Operators</title>

      <variablelist id="asnop">
        <title><anchor id="asnop1">assignment</title>

	<varlistentry>
	  <term><replaceable>variable assignment</replaceable></term>
	  <listitem><para>Initializing or changing the value of a variable</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <indexterm>
	    <primary>=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>=</secondary>
	  </indexterm>
	  <term>=</term>
	  <listitem>
	  <para>All-purpose assignment operator, which works for both
	    arithmetic and string assignments.</para>

	    <para>
	      <programlisting>var=27
category=minerals  # No spaces allowed after the "=".</programlisting>
	    </para>

            <caution>
	    <para>Do not confuse the <quote>=</quote> assignment
	      operator with the <link linkend="equalsignref">= test
	      operator</link>.</para>

	    <para>
	      <programlisting>#   =  as a test operator

if [ "$string1" = "$string2" ]
then
   command
fi

#  if [ "X$string1" = "X$string2" ] is safer,
#+ to prevent an error message should one of the variables be empty.
#  (The prepended "X" characters cancel out.)</programlisting>
	    </para>
	    </caution>


	  </listitem>
	</varlistentry>
      </variablelist>

	<indexterm>
	  <primary>expr</primary>
	</indexterm>
	<indexterm>
	  <primary>command</primary>
	  <secondary>expr</secondary>
	</indexterm>
	<indexterm>
	  <primary>let</primary>
	</indexterm>
	<indexterm>
	  <primary>command</primary>
	  <secondary>let</secondary>
	</indexterm>


      <variablelist id="arops">
        <title><anchor id="arops1">arithmetic operators</title>

	<varlistentry>
	  <term><token>+</token></term>
	  <indexterm>
	    <primary>+</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>+</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>addition</primary>
	  </indexterm>
	  <indexterm>
	    <primary>plus</primary>
	  </indexterm>
	  <listitem><para>plus</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>-</token></term>
	  <indexterm>
	    <primary>-</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>-</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>subtraction</primary>
	  </indexterm>
	  <indexterm>
	    <primary>minus</primary>
	  </indexterm>
	  <listitem><para>minus</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>*</token></term>
	  <indexterm>
	    <primary>*</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>*</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>multiplication</primary>
	  </indexterm>
	  <listitem><para>multiplication</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>/</token></term>
	  <indexterm>
	    <primary>/</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>/</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>division</primary>
	  </indexterm>
	  <listitem><para>division</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="exponentiationref"><token>**</token></term>
	  <indexterm>
	    <primary>**</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>**</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>exponentiation</primary>
	  </indexterm>
	  <listitem>
	  <para>exponentiation</para>

	  <para>
	    <programlisting># Bash, version 2.02, introduced the "**" exponentiation operator.

let "z=5**3"    # 5 * 5 * 5
echo "z = $z"   # z = 125</programlisting>
          </para>	    

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="moduloref"><token>%</token></term>
	  <indexterm>
	    <primary>%</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>%</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>modulo</primary>
	  </indexterm>
	  <listitem>

	  <para>modulo, or mod (returns the
	    <firstterm>remainder</firstterm> of an integer division
	    operation)</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>expr 5 % 3</userinput>
<computeroutput>2</computeroutput>
	      </screen>
	      <emphasis>5/3 = 1, with remainder 2</emphasis>
	    </para>

	  <para>This operator finds use in, among other things,
	    generating numbers within a specific range (see <xref
	    linkend="ex21"> and <xref linkend="randomtest">) and
	    formatting program output (see <xref linkend="qfunction"> and
	    <xref linkend="collatz">). It can even be used to generate
	    prime numbers, (see <xref linkend="primes">). Modulo turns
	    up surprisingly often in various numerical recipes.</para>

	    <example id="gcd">
	      <title>Greatest common divisor</title>
	      <programlisting>&gcd;</programlisting>
	    </example>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="arithopscomb"><token>+=</token></term>
	  <indexterm>
	    <primary>+=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>+=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>plus-equal</primary>
	  </indexterm>
	  <listitem><para><firstterm>plus-equal</firstterm> (increment
	    variable by a constant)</para>
	    <para><userinput>let "var += 5"</userinput> results in
	      <parameter>var</parameter> being incremented by
	      <literal>5</literal>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>-=</token></term>
	  <indexterm>
	    <primary>-=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>-=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>minus-equal</primary>
	  </indexterm>
	  <listitem><para><firstterm>minus-equal</firstterm> (decrement
	    variable by a constant)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>*=</token></term>
	  <indexterm>
	    <primary>*=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>*=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>times-equal</primary>
	  </indexterm>
	  <listitem><para><firstterm>times-equal</firstterm> (multiply
	    variable by a constant)</para>
	    <para><userinput>let "var *= 4"</userinput> results in <parameter>var</parameter>
	    being multiplied by <literal>4</literal>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>/=</token></term>
	  <indexterm>
	    <primary>/=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>/=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>slash-equal</primary>
	  </indexterm>
	  <listitem><para><firstterm>slash-equal</firstterm> (divide
	    variable by a constant)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>%=</token></term>
	  <indexterm>
	    <primary>%=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>%=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>mod-equal</primary>
	  </indexterm>
	  <listitem><para><firstterm>mod-equal</firstterm>
	    (<firstterm>remainder</firstterm>
	    of dividing variable by a constant)</para>

      <para><emphasis>Arithmetic operators often occur in an
        <link linkend="exprref">expr</link> or <link
        linkend="letref">let</link> expression.</emphasis></para>

	    <example id="arithops">
	      <title>Using Arithmetic Operations</title>
	      <programlisting>&arithops;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

      </variablelist>

      <note>
      <para>Integer variables in Bash are actually signed
	<firstterm>long</firstterm> (32-bit) integers, in the range of
	-2147483648 to 2147483647. An operation that takes a variable
	outside these limits will give an erroneous result.</para>

      <para>
	  <programlisting>a=2147483646
echo "a = $a"      # a = 2147483646
let "a+=1"         # Increment "a".
echo "a = $a"      # a = 2147483647
let "a+=1"         # increment "a" again, past the limit.
echo "a = $a"      # a = -2147483648
                   #      ERROR (out of range)</programlisting>
	</para>
	
	<para>As of version 2.05b, Bash supports 64-bit integers.</para>
	</note>

      <caution>
      
      <para><anchor id="nofloatingpoint"></para>
      <para>Bash does not understand floating point arithmetic. It
        treats numbers containing a decimal point as strings.</para>

      <para>
        <programlisting>a=1.5

let "b = $a + 1.3"  # Error.
# t2.sh: let: b = 1.5 + 1.3: syntax error in expression
#                            (error token is ".5 + 1.3")

echo "b = $b"       # b=1</programlisting>
      </para>

      <para>Use <link linkend="bcref">bc</link> in scripts that that need floating
	point calculations or math library functions.</para></caution>



      <formalpara><title>bitwise operators</title>
      <para>The bitwise operators seldom make an appearance in shell scripts.
	Their chief use seems to be manipulating and testing values read
	from ports or <link linkend="socketref">sockets</link>. <quote>Bit
	flipping</quote> is more relevant to compiled languages, such
	as C and C++, which provide direct access to system
	hardware.</para></formalpara>

      <variablelist id="bitwsops">
        <title><anchor id="bitwsops1">bitwise operators</title>

	<varlistentry>
	  <term><token><<</token></term>
	  <indexterm>
	    <primary><<</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary><<</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>left shift</primary>
	  </indexterm>
	  <listitem><para>bitwise left shift (multiplies by <literal>2</literal>
	      for each shift position)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token><<=</token></term>
	  <indexterm>
	    <primary><<=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary><<=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>left-shift-equal</primary>
	  </indexterm>
	  <listitem><para><firstterm>left-shift-equal</firstterm></para>
	    <para><userinput>let "var <<= 2"</userinput> results in <parameter>var</parameter>
	    left-shifted <literal>2</literal> bits (multiplied by <literal>4</literal>)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>>></token></term>
	  <indexterm>
	    <primary>>></primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>>></secondary>
	  </indexterm>
	  <indexterm>
	    <primary>right shift</primary>
	  </indexterm>
	  <listitem><para>bitwise right shift (divides by <literal>2</literal>
	      for each shift position)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>>>=</token></term>
	  <indexterm>
	    <primary>>>=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>>>=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>right-shift-equal</primary>
	  </indexterm>
	  <listitem><para><firstterm>right-shift-equal</firstterm>
	    (inverse of <token><<=</token>)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>&</token></term>
	  <indexterm>
	    <primary>&</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>&</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>AND</primary>
	    <secondary>bitwise</secondary>
	  </indexterm>
	  <listitem><para>bitwise AND</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>&=</token></term>
	  <indexterm>
	    <primary>&=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>&=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>and-equal</primary>
	  </indexterm>
	  <listitem><para>bitwise <firstterm>AND-equal</firstterm></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>|</token></term>
	  <indexterm>
	    <primary>|</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>|</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>OR</primary>
	    <secondary>bitwise</secondary>
	  </indexterm>
	  <listitem><para>bitwise OR</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>|=</token></term>
	  <indexterm>
	    <primary>|=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>|=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>OR-equal</primary>
	  </indexterm>
	  <listitem><para>bitwise <firstterm>OR-equal</firstterm></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>~</token></term>
	  <indexterm>
	    <primary>~</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>~</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>negate</primary>
	  </indexterm>
	  <listitem><para>bitwise NOT</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>^</token></term>
	  <indexterm>
	    <primary>^</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>^</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>XOR</primary>
	  </indexterm>
	  <listitem><para>bitwise XOR</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>^=</token></term>
	  <indexterm>
	    <primary>^=</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>^=</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>XOR-equal</primary>
	  </indexterm>
	  <listitem><para>bitwise <firstterm>XOR-equal</firstterm></para>
	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="logops">
        <title><anchor id="logops1">logical (boolean) operators</title>

	<varlistentry>
	  <term><token>!</token></term>
	  <indexterm>
	    <primary>!</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operator</primary>
	    <secondary>!</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>NOT</primary>
	  </indexterm>
	  <listitem><para>NOT</para>
           <para><programlisting>if [ ! -f $FILENAME ]
then
  ...</programlisting></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>&&</token></term>
	  <indexterm>
	    <primary>&&</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operator</primary>
	    <secondary>&&</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>AND</primary>
	    <secondary>logical</secondary>
	  </indexterm>
	  <listitem><para>AND</para>
	    <para><programlisting>if [ $condition1 ] && [ $condition2 ]
# Same as:  if [ $condition1 -a $condition2 ]
# Returns true if both condition1 and condition2 hold true...

if [[ $condition1 && $condition2 ]]    # Also works.
# Note that && operator not permitted within [ ... ] construct.</programlisting></para>

	  <note><para><token>&&</token> may also, depending on context, be
	    used in an <link linkend="listconsref">and list</link>
	    to concatenate commands.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="orref"><token>||</token></term>
	  <indexterm>
	    <primary>||</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operator</primary>
	    <secondary>||</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>OR</primary>
	    <secondary>logical</secondary>
	  </indexterm>
	  <listitem><para>OR</para>
	    <para><programlisting>if [ $condition1 ] || [ $condition2 ]
# Same as:  if [ $condition1 -o $condition2 ]
# Returns true if either condition1 or condition2 holds true...

if [[ $condition1 || $condition2 ]]    # Also works.
# Note that || operator not permitted within [ ... ] construct.</programlisting></para>

	  <note><para>Bash tests the <link linkend="exitstatusref">exit
	    status</link> of each statement linked with a logical
	    operator.</para></note>

	<example id="andor">
	  <title>Compound Condition Tests Using && and ||</title>
       	    <programlisting>&andor;</programlisting>
	 </example>   

	    <para>The <token>&&</token> and <token>||</token> operators also
	      find use in an arithmetic context.</para>
	      
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>echo $(( 1 && 2 )) $((3 && 0)) $((4 || 0)) $((0 || 0))</userinput>
<computeroutput>1 0 1 0</computeroutput>
	      </screen>
	    </para>
	      
	  </listitem>
	</varlistentry>

      </variablelist>

      <variablelist id="miscop">
        <title><anchor id="miscop1">miscellaneous operators</title>

	<varlistentry>
	  <term><anchor id="commaop"><token>,</token></term>
	  <indexterm>
	    <primary>,</primary>
	  </indexterm>
	  <indexterm>
	    <primary>operation</primary>
	    <secondary>,</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>linking</primary>
	  </indexterm>
	  <listitem>
	    <para>Comma operator</para>
	    <para>The <command>comma operator</command> chains together
	      two or more arithmetic operations. All the operations are
	      evaluated (with possible <firstterm>side effects</firstterm>
	        <footnote><para><firstterm>Side effects</firstterm>
		are, of course, unintended -- and usually undesirable --
		consequences.</para></footnote>
	      ), but only the last operation is returned.</para>

	     <para>
	     <programlisting>let "t1 = ((5 + 3, 7 - 1, 15 - 4))"
echo "t1 = $t1"               # t1 = 11

let "t2 = ((a = 9, 15 / 3))"  # Set "a" and calculate "t2".
echo "t2 = $t2    a = $a"     # t2 = 5    a = 9</programlisting>
	     </para>

	     <para>The comma operator finds use mainly in <link
	       linkend="forloopref1">for loops</link>. See <xref
	       linkend="forloopc">.</para>

	  </listitem>

	</varlistentry>
      </variablelist>

    </sect1> <!-- Operators -->

    <sect1 id="Numerical-Constants">
      <title>Numerical Constants</title>

      <para><anchor id="numconstants">A shell script interprets a number
	as decimal (base 10), unless that number has a
	special prefix or notation. A number preceded by a
	<replaceable>0</replaceable> is <replaceable>octal</replaceable>
	(base 8). A number preceded by <replaceable>0x</replaceable>
	is <replaceable>hexadecimal</replaceable> (base 16). A number
	with an embedded <replaceable>#</replaceable> evaluates as
	<replaceable>BASE#NUMBER</replaceable> (with range and notational
	restrictions).</para>

	    <example id="numbers">
	      <title>Representation of numerical constants</title>
	      <programlisting>&numbers;</programlisting>
	    </example>

    </sect1> <!-- Numerical-Constants -->

  </chapter> <!-- Operations -->

  </part> <!-- Part 2 (Basics) -->



  <part label="Part 3" id="part3">
    <title>Beyond the Basics</title>

  <chapter id="variables2">
      <title>Variables Revisited</title>


	<para>Used properly, variables can add power and flexibility
	  to scripts. This requires learning their subtleties and
	  nuances.</para>


    <sect1 id="internalvariables">  
      <title>Internal Variables</title>

      <variablelist id="internalvariables1">
	
	<varlistentry>
	  <term><replaceable><link
	  linkend="builtinref">Builtin</link> variables</replaceable></term>
	  <listitem><para>variables affecting bash script behavior</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="bashvarref"><varname>$BASH</varname></term>
	  <indexterm>
	    <primary>$BASH</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$BASH</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>path to bash</primary>
	  </indexterm>
	  <listitem><para>the path to the <firstterm>Bash</firstterm>
	    binary itself
	      <screen><prompt>bash$ </prompt><userinput>echo $BASH</userinput>
<computeroutput>/bin/bash</computeroutput></screen>
	    </para>
	    
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor
	  id="bashenvref"><varname>$BASH_ENV</varname></term>
	  <indexterm>
	    <primary>$BASH_ENV</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$BASH_ENV</secondary>
	  </indexterm>
	  <listitem><para>an <link linkend="envref">environmental
	  variable</link> pointing to a Bash startup file to be read
	  when a script is invoked</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="bashsubshellref"><varname>$BASH_SUBSHELL</varname></term>
	  <indexterm>
	    <primary>$BASH_SUBSHELL</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>subshell</secondary>
	  </indexterm>
	  <listitem>
	    <para>a variable indicating the <link
	      linkend="subshellsref">subshell</link> level. This is a
	      new addition to Bash, <link linkend="bash3ref">version 3</link>.</para>
	    <para>See <xref linkend="subshell"> for usage.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$BASH_VERSINFO[n]</varname></term>
	  <indexterm>
	    <primary>$BASH_VERSINFO</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>version information</secondary>
	  </indexterm>
	  <listitem>
	  <para>a 6-element <link linkend="arrayref">array</link>
	    containing version information about the installed release
	    of Bash. This is similar to <varname>$BASH_VERSION</varname>,
	    below, but a bit more detailed.</para>
	  <para>
	  <programlisting># Bash version info:

for n in 0 1 2 3 4 5
do
  echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"
done  

# BASH_VERSINFO[0] = 3                      # Major version no.
# BASH_VERSINFO[1] = 00                     # Minor version no.
# BASH_VERSINFO[2] = 14                     # Patch level.
# BASH_VERSINFO[3] = 1                      # Build version.
# BASH_VERSINFO[4] = release                # Release status.
# BASH_VERSINFO[5] = i386-redhat-linux-gnu  # Architecture
                                            # (same as $MACHTYPE).</programlisting>
	  </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$BASH_VERSION</varname></term>
	  <indexterm>
	    <primary>$BASH_VERSION</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$BASH_VERSION</secondary>
	  </indexterm>
	  <listitem><para>the version of Bash installed on the system</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
<computeroutput>3.2.25(1)-release</computeroutput>
	      </screen>
	    </para>

	  <para>
	      <screen><prompt>tcsh% </prompt><userinput>echo $BASH_VERSION</userinput>
<computeroutput>BASH_VERSION: Undefined variable.</computeroutput>
	      </screen>
	    </para>

	  <para>Checking $BASH_VERSION is a good method of determining which
	    shell is running. <link linkend="shellvarref">$SHELL</link>
	    does not necessarily give the correct answer.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="dirstackref"><varname>$DIRSTACK</varname></term>
	  <indexterm>
	    <primary>$DIRSTACK</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$DIRSTACK</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>directory stack</primary>
	  </indexterm>
	  <indexterm>
	    <primary>directory</primary>
	    <secondary>stack</secondary>
	  </indexterm>
	  <listitem><para>the top value in the directory stack
	    (affected by <link linkend="pushdref">pushd</link> and <link
	    linkend="popdref">popd</link>)</para> <para>This builtin
	    variable corresponds to the <link linkend="dirsd">dirs</link>
	    command, however <command>dirs</command> shows the entire
	    contents of the directory stack.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$EDITOR</varname></term>
	  <indexterm>
	    <primary>$EDITOR</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$EDITOR</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>editor</primary>
	  </indexterm>
	  <listitem><para>the default editor invoked by a script, usually
	      <command>vi</command> or <command>emacs</command>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="euidref"><varname>$EUID</varname></term>
	  <indexterm>
	    <primary>$EUID</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$EUID</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>effective user ID</primary>
	  </indexterm>
	  <listitem><para><quote>effective</quote> user ID number</para>
	    <para>Identification number of whatever identity the
	      current user has assumed, perhaps by means of <link
	      linkend="suref">su</link>.</para>
	    <caution><para>The <varname>$EUID</varname> is not necessarily
	      the same as the <link
	      linkend="uidref">$UID</link>.</para></caution>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$FUNCNAME</varname></term>
	  <indexterm>
	    <primary>$FUNCNAME</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>function</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>name</primary>
	  </indexterm>
	  <listitem>
	    <para>name of the current function</para>
	    <para><programlisting>xyz23 ()
{
  echo "$FUNCNAME now executing."  # xyz23 now executing.
}

xyz23

echo "FUNCNAME = $FUNCNAME"        # FUNCNAME =
                                   # Null value outside a function.</programlisting>
            </para>

            <para>See also <xref linkend="usegetopt">.</para>

	  </listitem>
	</varlistentry>

        <varlistentry>
	  <term><varname>$GLOBIGNORE</varname></term>
	  <indexterm>
	    <primary>$GLOBIGNORE</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>globbing</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>ignore</primary>
	  </indexterm>
	  <listitem><para>A list of filename patterns to be excluded from
	    matching in <link linkend="globbingref">globbing</link>.</para>
	  </listitem>
	</varlistentry>

        <varlistentry>
	  <term><anchor id="groupsref"><varname>$GROUPS</varname></term>
	  <indexterm>
	    <primary>$GROUPS</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$GROUPS</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>groups</primary>
	  </indexterm>
	  <listitem><para>groups current user belongs to</para>
	    <para>This is a listing (array) of the group id numbers for
	      current user, as  recorded in
	      <filename>/etc/passwd</filename> and
	      <filename>/etc/group</filename>.
	    </para>

	    <para>
	      <screen>
<prompt>root# </prompt><userinput>echo $GROUPS</userinput>
<computeroutput>0</computeroutput>


<prompt>root# </prompt><userinput>echo ${GROUPS[1]}</userinput>
<computeroutput>1</computeroutput>


<prompt>root# </prompt><userinput>echo ${GROUPS[5]}</userinput>
<computeroutput>6</computeroutput>
	      </screen>
	      </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="homedirref"><varname>$HOME</varname></term>
	  <indexterm>
	    <primary>$HOME</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$HOME</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>home directory</primary>
	  </indexterm>
	  <indexterm>
	    <primary>directory</primary>
	    <secondary>home</secondary>
	  </indexterm>
	  <listitem><para>home directory of the user, usually <filename
	    class="directory">/home/username</filename> (see <xref
	    linkend="ex6">)</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="hostnameref"><varname>$HOSTNAME</varname></term>
	  <indexterm>
	    <primary>$HOSTNAME</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$HOSTNAME</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>system name</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>name</secondary>
	  </indexterm>
	  <listitem>
	  <para>The <link linkend="hnameref">hostname</link> command
	    assigns the system host name at bootup in an init script.
	    However, the <function>gethostname()</function> function
	    sets the Bash internal variable <varname>$HOSTNAME</varname>.
	    See also <xref linkend="ex6">.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$HOSTTYPE</varname></term>
	  <indexterm>
	    <primary>$HOSTTYPE</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$HOSTTYPE</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>host type</primary>
	  </indexterm>
	  <listitem><para>host type</para>
	    <para>Like <link linkend="machtyperef">$MACHTYPE</link>,
	      identifies the system hardware.</para>
	    <screen><prompt>bash$ </prompt><userinput>echo $HOSTTYPE</userinput>
<computeroutput>i686</computeroutput></screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="ifsref"><varname>$IFS</varname></term>
	  <indexterm>
	    <primary>$IFS</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$IFS</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>internal field separator</primary>
	  </indexterm>
	  <listitem><para>internal field separator</para>

            <para>This variable determines how Bash recognizes fields, or word
	      boundaries, when it interprets character strings.</para>

	    <para><anchor id="ifsws"></para>
	    <para>$IFS defaults to <link
	      linkend="whitespaceref">whitespace</link> (space,
	      tab, and newline), but may be changed, for example,
	      to parse a comma-separated data file.  Note that
	      <link linkend="appref">$*</link> uses the first
	      character held in <varname>$IFS</varname>.  See <xref
	      linkend="weirdvars">.</para>

	  <para>
	      <screen>
<prompt>bash$ </prompt><userinput>echo "$IFS"</userinput>
<computeroutput>

</computeroutput>
<computeroutput>(With $IFS set to default, a blank line displays.)</computeroutput>
	      


<prompt>bash$ </prompt><userinput>echo "$IFS" | cat -vte</userinput>
<computeroutput> ^I$
 $</computeroutput>
<computeroutput>(Show whitespace -- here space, ^I [horizontal tab],
  and newline -- and display "$" at end-of-line.)</computeroutput>



<prompt>bash$ </prompt><userinput>bash -c 'set w x y z; IFS=":-;"; echo "$*"'</userinput>
<computeroutput>w:x:y:z</computeroutput>
<computeroutput>(Read commands from string and assign any arguments to pos params.)</computeroutput>
	      </screen>
	  </para>

	  <caution><para><varname>$IFS</varname> does not handle whitespace
	    the same as it does other characters.

	  <example id="ifsh">
	    <title>$IFS and whitespace</title>
	    <programlisting>&ifsh;</programlisting>
	  </example>

	  </para></caution>

	  <para>(Many thanks, St&eacute;phane Chazelas, for clarification and examples.)</para> 

	   <para>See also <xref linkend="isspammer">, <xref
	   linkend="bingrep">, and <xref linkend="mailboxgrep">
             for instructive examples of using
             <varname>$IFS</varname>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$IGNOREEOF</varname></term>
	  <indexterm>
	    <primary>$IGNOREEOF</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$IGNOREEOF</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>Ignore EOF</primary>
	  </indexterm>
	  <listitem><para>ignore EOF: how many end-of-files (control-D)
	    the shell will ignore before logging out.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$LC_COLLATE</varname></term>
	  <indexterm>
	    <primary>$LC_COLLATE</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$LC_COLLATE</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>lowercase collate</primary>
	  </indexterm>
	  <listitem>

	  <para>Often set in the <filename>.bashrc</filename> or
	    <filename>/etc/profile</filename> files, this
	    variable controls collation order in filename
	    expansion and pattern matching. If mishandled,
	    <varname>LC_COLLATE</varname> can cause unexpected results
	    in <link linkend="globbingref">filename
	    globbing</link>.</para>

	  <note><para>As of version 2.05 of Bash,
	    filename globbing no longer distinguishes between lowercase
	    and uppercase letters in a character range between
	    brackets. For example, <command>ls [A-M]*</command>
	    would match both <filename>File1.txt</filename>
	    and <filename>file1.txt</filename>. To revert to
	    the customary behavior of bracket matching, set
	    <varname>LC_COLLATE</varname> to <option>C</option>
	    by an <userinput>export LC_COLLATE=C</userinput>
	    in <filename>/etc/profile</filename> and/or
	    <filename>~/.bashrc</filename>.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$LC_CTYPE</varname></term>
	  <indexterm>
	    <primary>$LC_CTYPE</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$LC_CTYPE</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>lowercase character type</primary>
	  </indexterm>
	  <listitem>

	  <para>This internal variable controls character interpretation
	    in <link linkend="globbingref">globbing</link> and pattern
	    matching.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="linenoref"><varname>$LINENO</varname></term>
	  <indexterm>
	    <primary>$LINENO</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$LINENO</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>line number</primary>
	  </indexterm>
	  <listitem><para>This variable is the line number of the shell
	    script in which this variable appears. It has significance only
	    within the script in which it appears, and is chiefly useful for
	    debugging purposes.</para>
	  <para><programlisting># *** BEGIN DEBUG BLOCK ***
last_cmd_arg=$_  # Save it.

echo "At line number $LINENO, variable \"v1\" = $v1"
echo "Last command argument processed = $last_cmd_arg"
# *** END DEBUG BLOCK ***</programlisting></para>
	      
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="machtyperef"><varname>$MACHTYPE</varname></term>
	  <indexterm>
	    <primary>$MACHTYPE</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$MACHTYPE</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>machine type</primary>
	  </indexterm>
	  <listitem><para>machine type</para>
	    <para>Identifies the system hardware.</para>
	    <screen><prompt>bash$ </prompt><userinput>echo $MACHTYPE</userinput>
<computeroutput>i686</computeroutput></screen>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="oldpwd"><varname>$OLDPWD</varname></term>
	  <indexterm>
	    <primary>$OLDPWD</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$OLDPWD</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>previous working directory</primary>
	  </indexterm>
	  <indexterm>
	    <primary>directory</primary>
	    <secondary>working</secondary>
	  </indexterm>
	  <listitem><para>old working directory
	  (<quote>OLD-print-working-directory</quote>,
	    previous directory you were in)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$OSTYPE</varname></term>
	  <indexterm>
	    <primary>$OSTYPE</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$OSTYPE</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>os type</primary>
	  </indexterm>
	  <listitem><para>operating system type</para>
	    <screen><prompt>bash$ </prompt><userinput>echo $OSTYPE</userinput>
<computeroutput>linux</computeroutput></screen>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="pathref"><varname>$PATH</varname></term>
	  <indexterm>
	    <primary>$PATH</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$PATH</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>path to binaries</primary>
	  </indexterm>
	  <listitem><para>path to binaries, usually 
	      <filename class="directory">/usr/bin/</filename>, 
	      <filename class="directory">/usr/X11R6/bin/</filename>, 
	      <filename class="directory">/usr/local/bin</filename>, etc.</para>

	    <para>When given a command, the shell automatically does
	      a hash table search on the directories listed in the
	      <firstterm>path</firstterm> for the executable. The path
	      is stored in the <link linkend="envref">environmental
	      variable</link>, <varname>$PATH</varname>, a list
	      of directories, separated by colons. Normally,
	      the system stores the <varname>$PATH</varname>
	      definition in <filename>/etc/profile</filename>
	      and/or <filename>~/.bashrc</filename> (see <xref
	      linkend="files">).</para>

	      <para><screen><prompt>bash$ </prompt><command>echo $PATH</command>
<computeroutput>/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin</computeroutput></screen>
              </para>

	    <para><userinput>PATH=${PATH}:/opt/bin</userinput> appends
	      the <filename class="directory">/opt/bin</filename>
	      directory to the current path. In a script, it may be
	      expedient to temporarily add a directory to the path
	      in this way. When the script exits, this restores the
	      original <varname>$PATH</varname> (a child process, such
	      as a script, may not change the environment of the parent
	      process, the shell).</para>

	    <para><anchor id="currentwdref"></para>
	    <note><para>The current <quote>working directory</quote>, 
	      <filename class="directory">./</filename>, is usually
	      omitted from the <varname>$PATH</varname> as a security
	      measure.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor
	  id="pipestatusref"><varname>$PIPESTATUS</varname></term>
	  <indexterm>
	    <primary>$PIPESTATUS</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>pipe</secondary>
	  </indexterm>
	  <listitem>
	  <para><link linkend="arrayref">Array</link> variable holding
            <link linkend="exitstatusref">exit status</link>(es) of
	    last executed <firstterm>foreground</firstterm> <link
	    linkend="piperef">pipe</link>.</para>

	      <para>
	      <screen>
<prompt>bash$ </prompt><userinput>echo $PIPESTATUS</userinput>
<computeroutput>0</computeroutput>

<prompt>bash$ </prompt><userinput>ls -al | bogus_command</userinput>
<computeroutput>bash: bogus_command: command not found</computeroutput>
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[1]}</userinput>
<computeroutput>127</computeroutput>

<prompt>bash$ </prompt><userinput>ls -al | bogus_command</userinput>
<computeroutput>bash: bogus_command: command not found</computeroutput>
<prompt>bash$ </prompt><userinput>echo $?</userinput>
<computeroutput>127</computeroutput>
	      </screen>
	      </para>


	      <para>The members of the <varname>$PIPESTATUS</varname>
		array hold the exit status of each respective command
		executed in a pipe. <varname>$PIPESTATUS[0]</varname>
		holds the exit status of the first command in the pipe,
		<varname>$PIPESTATUS[1]</varname> the exit status of
		the second command, and so on.</para>


	      <caution>
	      <para>
	      The <varname>$PIPESTATUS</varname> variable
              may contain an erroneous <errorcode>0</errorcode> value
              in a login shell (in releases prior to 3.0 of Bash).
              </para>

	      <para>
	      <screen>
<prompt>tcsh% </prompt><userinput>bash</userinput>

<prompt>bash$ </prompt><userinput>who | grep nobody | sort</userinput>
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[*]}</userinput>
<computeroutput>0</computeroutput>
	      </screen>
	      </para>


	      <para>
	      The above lines contained in a script would produce the expected
	      <computeroutput>0 1 0</computeroutput> output.
              </para>

	      <para>
	      Thank you, Wayne Pollock for pointing this out and supplying the
	      above example.
	      </para>

	      </caution>


	      <note>

	      <para>The <varname>$PIPESTATUS</varname> variable gives
	        unexpected results in some contexts.</para>

	      <para>
	      <screen>
<prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
<computeroutput>3.00.14(1)-release</computeroutput>

<prompt>bash$ </prompt><userinput>$ ls | bogus_command | wc</userinput>
<computeroutput>bash: bogus_command: command not found
 0       0       0</computeroutput>

<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
<computeroutput>141 127 0</computeroutput>
	      </screen>
	      </para>

	      <para>Chet Ramey attributes the above output to the behavior of
		<link linkend="lsref">ls</link>. If <firstterm>ls</firstterm>
		writes to a <firstterm>pipe</firstterm> whose output is not
		read, then <replaceable>SIGPIPE</replaceable> kills it,
		and its <link linkend="exitstatusref">exit status</link>
		is <returnvalue>141</returnvalue>. Otherwise
		its exit status is <returnvalue>0</returnvalue>,
		as expected. This likewise is the case for <link
		linkend="trref">tr</link>.</para>

		</note>

		<note>
		  <para><varname>$PIPESTATUS</varname> is a
		    <quote>volatile</quote> variable. It needs to be
		    captured immediately after the pipe in question, before
		    any other command intervenes.</para>

	      <para>
	      <screen>
<prompt>bash$ </prompt><userinput>$ ls | bogus_command | wc</userinput>
<computeroutput>bash: bogus_command: command not found
 0       0       0</computeroutput>

<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
<computeroutput>0 127 0</computeroutput>

<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
<computeroutput>0</computeroutput>
	      </screen>
	      </para>
		</note>

		<note>
		  <para>The <link linkend="pipefailref">pipefail option</link>
		    may be useful in cases where
		    <varname>$PIPESTATUS</varname> does not give the desired
		    information.</para>
		</note>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="ppidref"><varname>$PPID</varname></term>
	  <indexterm>
	    <primary>$PPID</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$PPID</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>process ID</primary>
	  </indexterm>
	  <listitem><para></para>
	    <para>The <varname>$PPID</varname> of a process is
	    the process ID (<varname>pid</varname>) of its parent process.

	      <footnote>
	        <para>The PID of the currently running script is
		  <varname>$$</varname>, of course.</para>
              </footnote>
	      </para>

	    <para>Compare this with the <link
	      linkend="pidofref">pidof</link> command.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$PROMPT_COMMAND</varname></term>
	  <indexterm>
	    <primary>$PROMPT_COMMAND</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>prompt</secondary>
	  </indexterm>
	  <listitem>
	    <para>A variable holding a command to be executed
	      just before the primary prompt, <varname>$PS1</varname>
	      is to be displayed.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="ps1ref"><varname>$PS1</varname></term>
	  <indexterm>
	    <primary>$PS1</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$PS1</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>prompt</primary>
	  </indexterm>
	  <listitem><para>This is the main prompt, seen at the command line.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="secpromptref"><varname>$PS2</varname></term>
	  <indexterm>
	    <primary>$PS2</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$PS2</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>prompt</primary>
	    <secondary>secondary</secondary>
	  </indexterm>
	  <listitem>
	    <para>The secondary prompt, seen when additional input is
	      expected. It displays as <quote>&gt;</quote>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$PS3</varname></term>
	  <indexterm>
	    <primary>$PS3</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$PS3</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>prompt</primary>
	    <secondary>tertiary</secondary>
	  </indexterm>
	  <listitem><para>The tertiary prompt, displayed in a
	    <link linkend="selectref">select</link> loop (see <xref
	    linkend="ex31">).</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$PS4</varname></term>
	  <indexterm>
	    <primary>$PS4</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$PS4</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>prompt</primary>
	    <secondary>quartenary</secondary>
	  </indexterm>
	  <listitem>
	  <para>The quartenary prompt, shown at the beginning of
	    each line of output when invoking a script with the
	    <token>-x</token> <link linkend="optionsref">option</link>.
	    It displays as <quote>+</quote>.</para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="pwdref"><varname>$PWD</varname></term>
	  <indexterm>
	    <primary>$PWD</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$PWD</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>working directory</primary>
	  </indexterm>
	  <indexterm>
	    <primary>directory</primary>
	    <secondary>working</secondary>
	  </indexterm>
	  <listitem>
	  <para>working directory (directory you are in at the time)</para>
	  <para>This is the analog to the <link linkend="pwd2ref">pwd</link>
	    builtin command.</para>
          <para><programlisting>&wipedir;</programlisting></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="replyref"><varname>$REPLY</varname></term>
	  <indexterm>
	    <primary>$REPLY</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$REPLY</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>default value of read</primary>
	  </indexterm>
	  <indexterm>
	    <primary>reply</primary>
	    <secondary>read</secondary>
	  </indexterm>
	  <listitem><para>The default value when a variable is not
	    supplied to <link linkend="readref">read</link>. Also
	    applicable to <link linkend="selectref">select</link> menus,
	    but only supplies the item number of the variable chosen,
	    not the value of the variable itself.</para>
	     <para><programlisting>&reply;</programlisting></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$SECONDS</varname></term>
	  <indexterm>
	    <primary>$SECONDS</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$SECONDS</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>seconds execution time</primary>
	  </indexterm>
	  <indexterm>
	    <primary>runtime</primary>
	    <secondary>seconds</secondary>
	  </indexterm>
	  <listitem><para>The number of seconds the script has been running.</para>
	     <para><programlisting>&seconds;</programlisting></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><varname>$SHELLOPTS</varname></term>
	  <indexterm>
	    <primary>$SHELLOPTS</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$SHELLOPTS</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>shell options</primary>
	  </indexterm>
	  <listitem>
	    <para>the list of enabled shell <link
	      linkend="optionsref">options</link>, a readonly variable
	      <screen><prompt>bash$ </prompt><userinput>echo $SHELLOPTS</userinput>
<computeroutput>braceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="shlvlref"><varname>$SHLVL</varname></term>
	  <indexterm>
	    <primary>$SHLVL</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$SHLVL</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>shell level</primary>
	  </indexterm>
	  <listitem>
	  
	    <para>Shell level, how deeply Bash is nested.
	      <footnote><para>
		Somewhat analogous to <link
		linkend="recursionref">recursion</link>, in this context
		<firstterm>nesting</firstterm> refers to a pattern
		embedded within a larger pattern. One of the definitions
		of <firstterm>nest</firstterm>, according to the 1913
		edition of <emphasis>Webster's Dictionary</emphasis>,
		illustrates this beautifully: <quote><emphasis>A collection of
		boxes, cases, or the like, of graduated size, each put
		within the one next larger.</emphasis></quote>
	      </para></footnote>
	    If, at the command line, $SHLVL is 1, then in a script it
	    will increment to 2.</para>

	    <note><para>This variable is <link linkend = "subshnlevref">
	      <emphasis>not</emphasis> affected by
	      subshells</link>. Use <link
	      linkend="bashsubshellref">$BASH_SUBSHELL</link> when you
	      need an indication of subshell nesting.</para></note>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="tmoutref"><varname>$TMOUT</varname></term>
	  <indexterm>
	    <primary>$TMOUT</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$TMOUT</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>timeout interval</primary>
	  </indexterm>
	  <listitem><para>If the <replaceable>$TMOUT</replaceable>
	  environmental variable is set to a non-zero value
	  <varname>time</varname>, then the shell prompt will time out
	  after <varname>$time</varname> seconds. This will cause a
	  logout.</para>


	  <para>As of version 2.05b of Bash, it is now possible to use
	    <replaceable>$TMOUT</replaceable> in a script in combination
	    with <link linkend="readref">read</link>.</para>

	  <para>
	  <programlisting># Works in scripts for Bash, versions 2.05b and later.

TMOUT=3    # Prompt times out at three seconds.

echo "What is your favorite song?"
echo "Quickly now, you only have $TMOUT seconds to answer!"
read song

if [ -z "$song" ]
then
  song="(no answer)"
  # Default response.
fi

echo "Your favorite song is $song."</programlisting>
	  </para>


	  <para><anchor id="timingloop"></para>
	  <para>There are other, more complex, ways of implementing
	    timed input in a script. One alternative is to set up
	    a timing loop to signal the script when it times out.
	    This also requires a signal handling routine to <link
	    linkend="trapref1">trap</link> (see <xref linkend="ex76">)
	    the interrupt generated by the timing loop (whew!).</para>

	    <example id="tmdin">
	      <title>Timed Input</title>
	      <programlisting>&tmdin;</programlisting>
	    </example>	    

	  <para><anchor id="sttyto"></para>
	  <para>An alternative is using <link
	    linkend="sttyref">stty</link>.</para>

	    <example id="timeout">
	      <title>Once more, timed input</title>
	      <programlisting>&timeout;</programlisting>
	    </example>	    

	  <para>Perhaps the simplest method is using the
	    <option>-t</option> option to <link
	    linkend="readref">read</link>.</para>
	    
	    <example id="tout">
	      <title>Timed <firstterm>read</firstterm></title>
	      <programlisting>&tout;</programlisting>
	    </example>	    
	   

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="uidref"><varname>$UID</varname></term>
	  <indexterm>
	    <primary>$UID</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$UID</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>user ID</primary>
	  </indexterm>
	  <listitem><para>user ID number</para>

	    <para>Current user's user identification number, as
	      recorded in <filename>/etc/passwd</filename>
	    </para>

	    <para>This is the current user's real id, even if she has
	      temporarily assumed another identity through <link
	      linkend="suref">su</link>. <varname>$UID</varname> is a
	      readonly variable, not subject to change from the command
	      line or within a script, and is the counterpart to the
	      <link linkend="idref">id</link> builtin.</para>

            <example id="amiroot">
	      <title>Am I root?</title>
	      <programlisting>&amiroot;</programlisting>
            </example>

	    <para>See also <xref linkend="ex2">.</para>


	<!-- Nest note within last entry  -->
	<note>
	<para>The variables <varname>$ENV</varname>,
	  <varname>$LOGNAME</varname>, <varname>$MAIL</varname>,
	  <varname>$TERM</varname>, <varname>$USER</varname>, and
	  <varname>$USERNAME</varname> are <emphasis>not</emphasis>
	  Bash <link linkend="builtinref">builtins</link>. These are,
	  however, often set as <link linkend="envref">environmental
	  variables</link> in one of the Bash <link
	  linkend="filesref1">startup files</link>.  <anchor
	  id="shellvarref"><varname>$SHELL</varname>,
	  the name of the user's login shell, may be set from
	  <filename>/etc/passwd</filename> or in an <quote>init</quote>
	  script, and it is likewise not a Bash builtin.</para>
	      <para>
	      <screen>
<prompt>tcsh% </prompt><userinput>echo $LOGNAME</userinput>
<computeroutput>bozo</computeroutput>
<prompt>tcsh% </prompt><userinput>echo $SHELL</userinput>
<computeroutput>/bin/tcsh</computeroutput>
<prompt>tcsh% </prompt><userinput>echo $TERM</userinput>
<computeroutput>rxvt</computeroutput>

<prompt>bash$ </prompt><userinput>echo $LOGNAME</userinput>
<computeroutput>bozo</computeroutput>
<prompt>bash$ </prompt><userinput>echo $SHELL</userinput>
<computeroutput>/bin/tcsh</computeroutput>
<prompt>bash$ </prompt><userinput>echo $TERM</userinput>
<computeroutput>rxvt</computeroutput>
	      </screen>
	      </para>
	  </note>

	<!-- Nest note after $USER  -->

	  </listitem>
	</varlistentry>


      </variablelist>

	<!-- Last entry of intrinsic BASH variables -->

      <variablelist id="posparmslist">
        <title>Positional Parameters</title>

	<varlistentry>
	  <term><anchor id="posparamref"><varname>$0</varname>, <varname>$1</varname>,
	  <varname>$2</varname>, etc.</term>
	  <indexterm>
	    <primary>$0</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$0</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>positional parameter</primary>
	  </indexterm>
	  <indexterm>
	    <primary>parameter</primary>
	    <secondary>positional</secondary>
	  </indexterm>
	  <listitem>
	    <para>Positional parameters, passed from command
	      line to script, passed to a function, or <link
	      linkend="setref">set</link> to a variable (see <xref
	      linkend="ex17"> and <xref linkend="ex34">)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="clacountref"><varname>$#</varname></term>
	  <indexterm>
	    <primary>$#</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$#</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>positional parameter</primary>
	    <secondary>number of</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>parameter</primary>
	    <secondary>positional</secondary>
	    <tertiary>number of</tertiary>
	  </indexterm>
	  <listitem><para>Number of command line arguments
		<footnote><para>The words <quote>argument</quote>
		and <quote>parameter</quote> are often used
		interchangeably. In the context of this document, they
		have the same precise meaning: <emphasis>a variable passed
		to a script or function.</emphasis></para></footnote>
	    or positional parameters (see <xref linkend="ex4">)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="appref"><varname>$*</varname></term>
	  <indexterm>
	    <primary>$*</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$*</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>positional parameter</primary>
	    <secondary>all</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>parameter</primary>
	    <secondary>positional</secondary>
	    <tertiary>all</tertiary>
	  </indexterm>
	  <listitem>
	  <para>All of the positional parameters, seen as a single word</para>
	  <note><para><quote><varname>$*</varname></quote> must be
	    quoted.</para></note>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="appref2"><varname>$@</varname></term>
	  <indexterm>
	    <primary>$@</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$*</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>positional parameter</primary>
	    <secondary>all</secondary>
	  </indexterm>

	  <listitem>
	  
	  <para>Same as <token>$*</token>, but each parameter is a
	      quoted string, that is, the parameters are passed on
	      intact, without interpretation or expansion. This means,
	      among other things, that each parameter in the argument
	      list is seen as a separate word.</para>

	  <note><para>Of course, <quote><varname>$@</varname></quote>
	    should be quoted.</para></note>

	    <example id="arglist">
	      <title><firstterm>arglist</firstterm>: Listing arguments
	      with $* and $@</title>
	      <programlisting>&arglist;</programlisting>
	    </example>   

	    <para>Following a <command>shift</command>, the
	      <varname>$@</varname> holds the remaining command-line
	      parameters, lacking the previous <varname>$1</varname>,
	      which was lost.
	        <programlisting>#!/bin/bash
# Invoke with ./scriptname 1 2 3 4 5

echo "$@"    # 1 2 3 4 5
shift
echo "$@"    # 2 3 4 5
shift
echo "$@"    # 3 4 5

# Each "shift" loses parameter $1.
# "$@" then contains the remaining parameters.</programlisting>
            </para>


	    <para>The <varname>$@</varname> special parameter finds
	      use as a tool for filtering input into shell scripts. The
	      <command>cat "$@"</command> construction accepts input
	      to a script either from <filename>stdin</filename> or
	      from files given as parameters to the script. See <xref
	      linkend="rot13"> and <xref linkend="cryptoquote">.</para>


	    <caution><para>The <varname>$*</varname> and <varname>$@</varname>
	      parameters sometimes display inconsistent and
	      puzzling behavior, depending on the setting of <link
	      linkend="ifsref">$IFS</link>.</para></caution>

	    <example id="incompat">
	      <title>Inconsistent <varname>$*</varname> and <varname>$@</varname> behavior</title>
	      <programlisting>&incompat;</programlisting>
	    </example>	    

	    <note><para>The <command>$@</command> and <command>$*</command>
	      parameters differ only when between double quotes.</para></note>

	    <example id="ifsempty">
	      <title><varname>$*</varname> and <varname>$@</varname> when
	        <varname>$IFS</varname> is empty</title>
	      <programlisting>&ifsempty;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

    </variablelist>	

      <variablelist id="otherspecparams">
        <title>Other Special Parameters</title>

	<varlistentry>
	  <term><anchor id="flpref"><varname>$-</varname></term>
	  <indexterm>
	    <primary>$-</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$-</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>flags</primary>
	  </indexterm>
	  <listitem>
	    <para>Flags passed to script (using <link
	      linkend="setref">set</link>). See <xref linkend="ex34">.</para>
	    <caution><para>This was originally a <firstterm>ksh</firstterm>
	      construct adopted into Bash, and unfortunately it does not
	      seem to work reliably in Bash scripts. One possible use
	      for it is to have a script <link linkend="iitest">self-test
	      whether it is interactive</link>.</para></caution>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="pidvarref"><varname>$!</varname></term>
	  <indexterm>
	    <primary>$!</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$!</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>PID</primary>
	    <secondary>last job background</secondary>
	  </indexterm>
	  <listitem>

	    <para><link linkend="processiddef">PID</link> (process ID) of last
	      job run in background</para>

	    <para>
	      <programlisting>LOG=$0.log

COMMAND1="sleep 100"

echo "Logging PIDs background commands for script: $0" >> "$LOG"
# So they can be monitored, and killed as necessary.
echo >> "$LOG"

# Logging commands.

echo -n "PID of \"$COMMAND1\":  " >> "$LOG"
${COMMAND1} &
echo $! >> "$LOG"
# PID of "sleep 100":  1506

# Thank you, Jacques Lederer, for suggesting this.</programlisting>
            </para>

            <para>Using <varname>$!</varname> for job control:</para>

            <para>
	      <programlisting>possibly_hanging_job & { sleep ${TIMEOUT}; eval 'kill -9 $!' &> /dev/null; }
# Forces completion of an ill-behaved program.
# Useful, for example, in init scripts.

# Thank you, Sylvain Fourmanoit, for this creative use of the "!" variable.</programlisting>

            </para>

            <para>Or, alternately:</para>

            <para>
              <programlisting># This example by Matthew Sage.
# Used with permission.

TIMEOUT=30   # Timeout value in seconds
count=0

possibly_hanging_job & {
        while ((count < TIMEOUT )); do
                eval '[ ! -d "/proc/$!" ] && ((count = TIMEOUT))'
                # /proc is where information about running processes is found.
                # "-d" tests whether it exists (whether directory exists).
                # So, we're waiting for the job in question to show up.
                ((count++))
                sleep 1
        done
        eval '[ -d "/proc/$!" ] && kill -15 $!'
        # If the hanging job is running, kill it.
}</programlisting>
            </para>


	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="underscoreref"><varname>$_</varname></term>
	  <indexterm>
	    <primary>$_</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$_</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>underscore</primary>
	    <secondary>last argument</secondary>
	  </indexterm>
	  <listitem>
	      <para>Special variable set to last argument of previous command
	        executed.</para>


      <example id="uscref">
	<title>Underscore variable</title>
        <programlisting>#!/bin/bash

echo $_              # /bin/bash
                     # Just called /bin/bash to run the script.

du >/dev/null        # So no output from command.
echo $_              # du

ls -al >/dev/null    # So no output from command.
echo $_              # -al  (last argument)

:
echo $_              # :</programlisting></example>
	    </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="xstatvarref"><varname>$?</varname></term>
	  <indexterm>
	    <primary>$?</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$?</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>exit status</primary>
	  </indexterm>
	  <listitem><para><link linkend="exitstatusref">Exit status</link>
	    of a command, <link linkend="functionref">function</link>,
	    or the script itself (see <xref linkend="max">)</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="proccid"><varname>$$</varname></term>
	  <indexterm>
	    <primary>$$</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$$</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>PID</primary>
	    <secondary>of script</secondary>
	  </indexterm>
	  <listitem><para>Process ID of the script itself. The
	  <varname>$$</varname> variable often finds use
	    in scripts to construct <quote>unique</quote>
	    temp file names (see <xref linkend="ftpget">, <xref
	    linkend="online">, <xref linkend="derpm">, and <xref
	    linkend="selfdestruct">). This is usually simpler than
	    invoking <link linkend="mktempref">mktemp</link>.</para>
	      
	  </listitem>
	</varlistentry>

    </variablelist>	


    </sect1> <!-- Internal Variables -->

    <sect1 id="String-Manipulation">
      <title>Manipulating Strings</title>

            <para><anchor id="stringmanip"></para> 

	    <para>Bash supports a surprising number of string manipulation
	      operations.  Unfortunately, these tools lack
	      a unified focus. Some are a subset of <link
	      linkend="paramsubref">parameter substitution</link>, and
	      others fall under the functionality of the UNIX <link
	      linkend="exprref">expr</link> command. This results in
	      inconsistent command syntax and overlap of functionality,
	      not to mention confusion.</para>

      <variablelist id="stringlength">
        <title>String Length</title>

	<varlistentry>
	  <term>${#string}</term>
	  <indexterm>
	    <primary>string length</primary>
	    <secondary>parameter substitution</secondary>
	  </indexterm>

	  <listitem><para></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>expr length $string</term>
	  <indexterm>
	    <primary>string length</primary>
	    <secondary>expr</secondary>
	  </indexterm>

        <listitem><para><anchor id="strlen">These are the equivalent of
            <firstterm>strlen()</firstterm> in
            <firstterm>C</firstterm>.</para></listitem>
	</varlistentry>

	<varlistentry>
	  <term>expr "$string" : '.*'</term>
	  <indexterm>
	    <primary>string length</primary>
	    <secondary>expr</secondary>
	  </indexterm>

	  <listitem>
	  <para>
	  <programlisting>stringZ=abcABC123ABCabc

echo ${#stringZ}                 # 15
echo `expr length $stringZ`      # 15
echo `expr "$stringZ" : '.*'`    # 15</programlisting>
	  </para>
	  </listitem>

	</varlistentry>

      </variablelist>

	    <example id="paragraphspace">
	      <title>Inserting a blank line between paragraphs in a text file</title>
	      <programlisting>&paragraphspace;</programlisting>
	    </example>

      <variablelist id="lengthsubstring">
        <title>Length of Matching Substring at Beginning of String</title>
	
	<varlistentry>
	  <term><anchor id="exprmatch">expr match "$string"
	  '$substring'</term>
	  <indexterm>
	    <primary>substring length</primary>
	    <secondary>expr</secondary>
	  </indexterm>

	  <listitem>
	  <para><replaceable>$substring</replaceable> is a <link
	    linkend="regexref">regular expression</link>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>expr "$string" : '$substring'</term>
	  <indexterm>
	    <primary>substring length</primary>
	    <secondary>expr</secondary>
	  </indexterm>

	  <listitem>
	  <para><replaceable>$substring</replaceable> is a regular
	    expression.</para>
	  <para>

	  <programlisting>stringZ=abcABC123ABCabc
#       |------|
#       12345678

echo `expr match "$stringZ" 'abc[A-Z]*.2'`   # 8
echo `expr "$stringZ" : 'abc[A-Z]*.2'`       # 8</programlisting>
          </para>
	  </listitem>
	</varlistentry>

      </variablelist>

      <variablelist id="substringindex">
        <title>Index</title>

	<varlistentry>
	  <term><anchor id="substringindex2">expr index $string
	    $substring</term>
	  <indexterm>
	    <primary>substring index</primary>
	    <secondary>expr</secondary>
	  </indexterm>

	  <listitem>

	  <para>Numerical position in $string of first character in 
	    $substring that matches.</para>

	  <para><programlisting>stringZ=abcABC123ABCabc
#       123456 ...
echo `expr index "$stringZ" C12`             # 6
                                             # C position.

echo `expr index "$stringZ" 1c`              # 3
# 'c' (in #3 position) matches before '1'.</programlisting></para>

	  <para>This is the near equivalent of
            <firstterm>strchr()</firstterm> in
            <firstterm>C</firstterm>.</para>
	  </listitem>
	</varlistentry>

      </variablelist>

      <variablelist id="substringextraction">
        <title>Substring Extraction</title>

	<varlistentry>
	  <term><anchor id="substrextr01">${string:position}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>extraction</secondary>
	  </indexterm>

	  <listitem>
	  <para>Extracts substring from <replaceable>$string</replaceable> at
	    <replaceable>$position</replaceable>.</para>
	  <para>If the <varname>$string</varname> parameter is
	    <quote><token>*</token></quote>
	    or <quote><token>@</token></quote>, then this extracts the
	    <link linkend="posparamref">positional parameters</link>,
	       <footnote><para>This applies to either command-line
	       arguments or parameters passed to a <link
	       linkend="functionref">function</link>.</para></footnote>
	    starting at <varname>$position</varname>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="substrextr02">${string:position:length}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>extraction</secondary>
	  </indexterm>

	  <listitem>
	  <para>Extracts <replaceable>$length</replaceable> characters
	    of substring from <replaceable>$string</replaceable> at
	    <replaceable>$position</replaceable>.</para>
	  <para>
	  <programlisting>stringZ=abcABC123ABCabc
#       0123456789.....
#       0-based indexing.

echo ${stringZ:0}                            # abcABC123ABCabc
echo ${stringZ:1}                            # bcABC123ABCabc
echo ${stringZ:7}                            # 23ABCabc

echo ${stringZ:7:3}                          # 23A
                                             # Three characters of substring.



# Is it possible to index from the right end of the string?
    
echo ${stringZ:-4}                           # abcABC123ABCabc
# Defaults to full string, as in ${parameter:-default}.
# However . . .

echo ${stringZ:(-4)}                         # Cabc 
echo ${stringZ: -4}                          # Cabc
# Now, it works.
# Parentheses or added space "escape" the position parameter.

# Thank you, Dan Jacobson, for pointing this out.</programlisting>
	  </para>

          <para>The <firstterm>position</firstterm> and
             <firstterm>length</firstterm> arguments can be
	     <quote>parameterized,</quote> that is, represented as a
	     variable, rather than as a numerical constant.</para>

	    <para><anchor id="randstring0"></para>
	    <example id="randstring">
	      <title>Generating an 8-character <quote>random</quote>
	        string</title>
	      <programlisting>&randstring;</programlisting>
	    </example>

	  <para>If the <varname>$string</varname> parameter is
	    <quote><token>*</token></quote> or
	    <quote><token>@</token></quote>, then this extracts a maximum
	    of <varname>$length</varname> positional parameters, starting
	    at <varname>$position</varname>.</para>

	  <para>
	  <programlisting>echo ${*:2}          # Echoes second and following positional parameters.
echo ${@:2}          # Same as above.

echo ${*:2:3}        # Echoes three positional parameters, starting at second.</programlisting>
	  </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>expr substr $string $position $length</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>extraction expr</secondary>
	  </indexterm>

	  <listitem>
	  
	  <para>Extracts <replaceable>$length</replaceable> characters
	    from <replaceable>$string</replaceable> starting at
	    <replaceable>$position</replaceable>.</para>
	  
	  <para>
	  <programlisting>stringZ=abcABC123ABCabc
#       123456789......
#       1-based indexing.

echo `expr substr $stringZ 1 2`              # ab
echo `expr substr $stringZ 4 3`              # ABC</programlisting>
          </para>

	  <para><anchor id="exprparen"></para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>expr match "$string" '\($substring\)'</term>
	  <indexterm>
	    <primary>substring extraction</primary>
	    <secondary>expr</secondary>
	  </indexterm>

	  <listitem>
	  <para>Extracts <replaceable>$substring</replaceable>
	    at beginning of <replaceable>$string</replaceable>,
	    where <replaceable>$substring</replaceable> is a <link
	    linkend="regexref">regular expression</link>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>expr "$string" : '\($substring\)'</term>
	  <indexterm>
	    <primary>substring extraction</primary>
	    <secondary>expr</secondary>
	  </indexterm>

	  <listitem>

	  <para>Extracts <replaceable>$substring</replaceable>
	    at beginning of <replaceable>$string</replaceable>,
	    where <replaceable>$substring</replaceable> is a regular
	    expression.</para>

	    <para>
	    <programlisting>stringZ=abcABC123ABCabc
#       =======	    

echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'`   # abcABC1
echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'`       # abcABC1
echo `expr "$stringZ" : '\(.......\)'`                   # abcABC1
# All of the above forms give an identical result.</programlisting>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>expr match "$string" '.*\($substring\)'</term>
	  <indexterm>
	    <primary>substring extraction</primary>
	    <secondary>expr</secondary>
	  </indexterm>

	  <listitem>
	  <para>Extracts <replaceable>$substring</replaceable>
	    at <emphasis>end</emphasis> of
	    <replaceable>$string</replaceable>, where
	    <replaceable>$substring</replaceable> is a regular
	    expression.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>expr "$string" : '.*\($substring\)'</term>
	  <indexterm>
	    <primary>substring extraction</primary>
	    <secondary>expr</secondary>
	  </indexterm>

	  <listitem>

	  <para>Extracts <replaceable>$substring</replaceable>
	    at <emphasis>end</emphasis> of <replaceable>$string</replaceable>,
	    where <replaceable>$substring</replaceable> is a regular
	    expression.</para>

	    <para>
	    <programlisting>stringZ=abcABC123ABCabc
#                ======

echo `expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)'`    # ABCabc
echo `expr "$stringZ" : '.*\(......\)'`                       # ABCabc</programlisting>

	    </para>
	  </listitem>
	</varlistentry>

      </variablelist>

      <variablelist id="substringremoval">
        <title>Substring Removal</title>
	
	<varlistentry>
	  <term>${string#substring}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>removal</secondary>
	  </indexterm>

	  <listitem>
	  <para>Deletes shortest match of
	    <replaceable>$substring</replaceable> from
	    <emphasis>front</emphasis> of
	    <replaceable>$string</replaceable>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>${string##substring}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>removal</secondary>
	  </indexterm>

	  <listitem>

	  <para>Deletes longest match of
	    <replaceable>$substring</replaceable> from
	    <emphasis>front</emphasis> of
	    <replaceable>$string</replaceable>.</para>

	  <para>  
	  <programlisting>stringZ=abcABC123ABCabc
#       |----|          shortest
#       |----------|    longest

echo ${stringZ#a*C}      # 123ABCabc
# Strip out shortest match between 'a' and 'C'.

echo ${stringZ##a*C}     # abc
# Strip out longest match between 'a' and 'C'.</programlisting>
	  </para>  
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>${string%substring}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>removal</secondary>
	  </indexterm>

	  <listitem>

	  <para>Deletes shortest match of
	    <replaceable>$substring</replaceable> from
	    <emphasis>back</emphasis> of
	    <replaceable>$string</replaceable>.</para>

	  <para>For example:
	    <programlisting># Rename all filenames in $PWD with "TXT" suffix to a "txt" suffix.
# For example, "file1.TXT" becomes "file1.txt" . . .

SUFF=TXT
suff=txt

for i in $(ls *.$SUFF)
do
  mv -f $i ${i%.$SUFF}.$suff
  #  Leave unchanged everything *except* the shortest pattern match
  #+ starting from the right-hand-side of the variable $i . . .
done ### This could be condensed into a "one-liner" if desired.

# Thank you, Rory Winston.</programlisting>
	  </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term>${string%%substring}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>removal</secondary>
	  </indexterm>

	  <listitem>

	  <para>Deletes longest match of
	    <replaceable>$substring</replaceable> from
	    <emphasis>back</emphasis> of
	    <replaceable>$string</replaceable>.</para>

	  <para>  
	  <programlisting>stringZ=abcABC123ABCabc
#                    ||     shortest
#        |------------|     longest

echo ${stringZ%b*c}      # abcABC123ABCa
# Strip out shortest match between 'b' and 'c', from back of $stringZ.

echo ${stringZ%%b*c}     # a
# Strip out longest match between 'b' and 'c', from back of $stringZ.</programlisting>
	  </para>  

	  <para>This operator is useful for generating filenames.</para>

	    <example id="cvt">
	      <title>Converting graphic file formats, with filename change</title>
	      <programlisting>&cvt;</programlisting>
	    </example>

	    <example id="ra2ogg">
	      <title>Converting streaming audio files to
	      <firstterm>ogg</firstterm></title>
	      <programlisting>&ra2ogg;</programlisting>
	    </example>

	  <para><anchor id="getoptsimple1"></para>
	  <para>A simple emulation of <link linkend="getopty">getopt</link>
	    using substring-extraction constructs.</para>

	    <example id="getoptsimple">
	      <title>Emulating <firstterm>getopt</firstterm></title>
	      <programlisting>&getoptsimple;</programlisting>
	    </example>



	  </listitem>
	</varlistentry>

      </variablelist>

      <variablelist id="substringreplacement">
        <title>Substring Replacement</title>

	<varlistentry>
	  <term><anchor
	  id="substrrepl00">${string/substring/replacement}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>replacement</secondary>
	  </indexterm>

	  <listitem>
	  <para>Replace first match of
	    <replaceable>$substring</replaceable> with
	    <replaceable>$replacement</replaceable>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor
	  id="substrrepl01">${string//substring/replacement}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>replacement</secondary>
	  </indexterm>

	  <listitem>

	  <para>Replace all matches of
	    <replaceable>$substring</replaceable> with
	    <replaceable>$replacement</replaceable>.</para>

	  <para>  
	  <programlisting>stringZ=abcABC123ABCabc

echo ${stringZ/abc/xyz}           # xyzABC123ABCabc
                                  # Replaces first match of 'abc' with 'xyz'.

echo ${stringZ//abc/xyz}          # xyzABC123ABCxyz
                                  # Replaces all matches of 'abc' with # 'xyz'.

# What happens if no $replacement string is supplied?
echo ${stringZ/abc}               # ABC123ABCabc
echo ${stringZ//abc}              # ABC123ABC
# A simple deletion takes place.</programlisting>
	  </para>  

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor
	  id="substrrepl02">${string/#substring/replacement}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>replacement</secondary>
	  </indexterm>

	  <listitem>
	  <para>If <replaceable>$substring</replaceable> matches
	    <emphasis>front</emphasis> end of
	    <replaceable>$string</replaceable>, substitute
	    <replaceable>$replacement</replaceable> for
	    <replaceable>$substring</replaceable>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor
	  id="substrrepl03">${string/%substring/replacement}</term>
	  <indexterm>
	    <primary>substring</primary>
	    <secondary>replacement</secondary>
	  </indexterm>

	  <listitem>

	  <para>If <replaceable>$substring</replaceable> matches
	    <emphasis>back</emphasis> end of
	    <replaceable>$string</replaceable>, substitute
	    <replaceable>$replacement</replaceable> for
	    <replaceable>$substring</replaceable>.</para>

	  <para>  
          <programlisting>stringZ=abcABC123ABCabc

echo ${stringZ/#abc/XYZ}          # XYZABC123ABCabc
                                  # Replaces front-end match of 'abc' with 'XYZ'.

echo ${stringZ/%abc/XYZ}          # abcABC123ABCXYZ
                                  # Replaces back-end match of 'abc' with 'XYZ'.</programlisting>
	  </para>  

	  </listitem>
	</varlistentry>

      </variablelist>

    <sect2 id="awkstringmanip">
      <title>Manipulating strings using awk</title>

	  <para><anchor id="awkstringmanip2"</para>
          <para>A Bash script may invoke the string manipulation facilities of
	    <link linkend="awkref">awk</link> as an alternative to using its
	    built-in operations.</para>

	    <example id="substringex">
	      <title>Alternate ways of extracting and locating substrings</title>
	      <programlisting>&substringex;</programlisting>
	    </example>

    </sect2> <!-- Manipulating strings using awk -->



    <sect2 id="strfdisc">
      <title>Further Reference</title>
   
     <para>For more on string manipulation in scripts, refer to <xref
       linkend="Parameter-Substitution"> and the
       <link linkend="expextrsub">relevant section</link> of the <link
       linkend="exprref">expr</link> command listing.</para>
       
     <para>Script examples:
      <orderedlist>
         <listitem><para><xref linkend="ex45"></para></listitem>
	 <listitem><para><xref linkend="length"></para></listitem>
	 <listitem><para><xref linkend="pattmatching"></para></listitem>
         <listitem><para><xref linkend="rfe"></para></listitem>
         <listitem><para><xref linkend="varmatch"></para></listitem>
         <listitem><para><xref linkend="insertionsort"></para></listitem>
         <listitem><para><xref linkend="qky"></para></listitem>
        </orderedlist>
      </para>	 

    </sect2> <!-- Further Reference-->
    


    </sect1> <!-- Manipulating Strings -->



    <sect1 id="Parameter-Substitution">
      <title>Parameter Substitution</title>

            <para><anchor id="paramsubref"></para> 

            <variablelist id="pssub">
	      <title><anchor id="pssub1">Manipulating and/or expanding variables</title>
	      <varlistentry>
		<term>
		  <userinput>${parameter}</userinput></term>
		<listitem>

		<para>Same as <replaceable>$parameter</replaceable>, i.e.,
		  value of the variable
		  <replaceable>parameter</replaceable>.
		  In certain contexts, only the less ambiguous
		  <replaceable>${parameter}</replaceable> form
		  works.</para>

		<para>May be used for concatenating variables with strings.</para>

	        <para><programlisting>
your_id=${USER}-on-${HOSTNAME}
echo "$your_id"
#
echo "Old \$PATH = $PATH"
PATH=${PATH}:/opt/bin  #Add /opt/bin to $PATH for duration of script.
echo "New \$PATH = $PATH"
</programlisting></para>
		</listitem>
	      </varlistentry>

	      <varlistentry>
		<term><anchor
		id="defparam1"><userinput>${parameter-default}</userinput></term>
		<term><userinput>${parameter:-default}</userinput></term>
		<listitem>
		<para>If parameter not set, use default.</para>
		<para><programlisting>
echo ${username-`whoami`}
# Echoes the result of `whoami`, if variable $username is still unset.</programlisting></para>

		<note><para><replaceable>${parameter-default}</replaceable>
		  and <replaceable>${parameter:-default}</replaceable>
		  are almost equivalent. The extra <token>:</token> makes
		  a difference only when <parameter>parameter</parameter>
		  has been declared, but is null.  </para></note>

		<para><programlisting>&paramsub;</programlisting></para>

		<para>The <firstterm>default parameter</firstterm> construct
		  finds use in providing <quote>missing</quote> command-line
		  arguments in scripts.</para>

		<para>
		  <programlisting>DEFAULT_FILENAME=generic.data
filename=${1:-$DEFAULT_FILENAME}
#  If not otherwise specified, the following command block operates
#+ on the file "generic.data".
#
#  Commands follow.</programlisting>
		</para>

		<para>See also <xref linkend="ex58">, <xref
		  linkend="ex73">, and <xref linkend="collatz">.</para>

                <para>Compare this method with <link
		  linkend="anddefault">using an <firstterm>and
		  list</firstterm> to supply a default command-line
		  argument</link>.</para>

		</listitem>
	      </varlistentry>

	      <varlistentry>
		<term><userinput>${parameter=default}</userinput></term>
		<term><userinput>${parameter:=default}</userinput></term>
		<listitem>
		<para><anchor id="defparam"></para>
		<para>If parameter not set, set it to
		  <firstterm>default</firstterm>.</para>

		<para>Both forms nearly equivalent. The <token>:</token>
		  makes a difference only when <varname>$parameter</varname>
		  has been declared and is null,
		    <footnote>
		    <para>If $parameter is null in a
		      non-interactive script, it will terminate with a <link
		      linkend="exitcodesref"><returnvalue>127</returnvalue>
		      exit status</link> (the Bash error code for
		      <quote>command not found</quote>).</para>
		      </footnote>
		  as above.
		    </para>

		<para><programlisting>
echo ${username=`whoami`}
# Variable "username" is now set to `whoami`.</programlisting></para>
	      </listitem>
	      </varlistentry>

	      <varlistentry>
		<term><anchor
		  id="paramaltv"><userinput>${parameter+alt_value}</userinput></term>
		<term><userinput>${parameter:+alt_value}</userinput></term>
		<listitem>
		  <para>If parameter set, use
		    <userinput>alt_value</userinput>, else use null
		    string.</para>

		  <para>Both forms nearly equivalent. The <token>:</token>
		    makes a difference only when
		    <parameter>parameter</parameter>
		    has been declared and is null, see below.</para>

		  <para><programlisting>echo "###### \${parameter+alt_value} ########"
echo

a=${param1+xyz}
echo "a = $a"      # a =

param2=
a=${param2+xyz}
echo "a = $a"      # a = xyz

param3=123
a=${param3+xyz}
echo "a = $a"      # a = xyz

echo
echo "###### \${parameter:+alt_value} ########"
echo

a=${param4:+xyz}
echo "a = $a"      # a =

param5=
a=${param5:+xyz}
echo "a = $a"      # a =
# Different result from   a=${param5+xyz}

param6=123
a=${param6:+xyz}
echo "a = $a"      # a = xyz</programlisting></para>

		</listitem>
	      </varlistentry>
	      <varlistentry>
		<term><anchor id="qerrmsg"><userinput>${parameter?err_msg}</userinput></term>
		<term><userinput>${parameter:?err_msg}</userinput></term>
		<listitem><para>If parameter set, use it, else print err_msg.</para>
		<para>Both forms nearly equivalent. The <token>:</token>
		  makes a difference only when <parameter>parameter</parameter>
		  has been declared and is null, as above.</para>
		</listitem>
	      </varlistentry>
	    </variablelist>

	    <example id="ex6">
	      <title>Using parameter substitution and error messages</title>
	      <programlisting>&ex6;</programlisting>
	    </example>

	    <example id="usagemessage">
	      <title>Parameter substitution and <quote>usage</quote> messages</title>
	      <programlisting>&usagemessage;</programlisting>
	    </example>

	    
	    
            <formalpara><title>Parameter substitution and/or expansion</title>
	      
	      <para><anchor id="psub2">The following expressions are
		the complement to the <command>match</command>
		<replaceable>in</replaceable> <command>expr</command>
		string operations (see <xref linkend="ex45">).
		These particular ones are used mostly in parsing file
		path names.</para></formalpara>

	    <variablelist id="psorex">
              <title><anchor id="psorex1">Variable length / Substring removal</title>

	      <varlistentry>

		<term><userinput>${#var}</userinput></term>
		<listitem>
		  <para><userinput>String length</userinput> (number
		    of characters in <varname>$var</varname>). For
		    an <link linkend="arrayref">array</link>,
		    <command>${#array}</command> is the length of the
		    first element in the array.</para>

		  <note><para>
		    Exceptions:

		  <itemizedlist>
		    <listitem>
		    <para><anchor id="numposparam"></para>
		    <para>
		      <command>${#*}</command> and
		      <command>${#@}</command> give the <emphasis>number
		      of positional parameters</emphasis>.
		    </para></listitem>
		  
		    <listitem><para>
		      For an array, <command>${#array[*]}</command> and
		      <command>${#array[@]}</command> give the number
		      of elements in the array.
		    </para></listitem>
		  </itemizedlist>
		  </para></note>

	      <example id="length">
	        <title>Length of a variable</title>
	        <programlisting>&length;</programlisting>
	      </example>	    

		</listitem>
	      </varlistentry>

	      <varlistentry>
		<term><anchor
		id="psorex2"><userinput>${var#Pattern}</userinput></term>
		<term><userinput>${var##Pattern}</userinput></term>

		<listitem>

		<para><anchor id="psorexsh"></para>
		<para><command>${var#Pattern} </command>
		  Remove from <varname>$var</varname>
		  the <emphasis>shortest</emphasis> part of
		  <varname>$Pattern</varname> that matches
		  the <replaceable>front end</replaceable> of
		  <varname>$var</varname>.
		</para>

		<para><anchor id="psorexlo"></para>
		<para><command>${var##Pattern} </command>
		  Remove from <varname>$var</varname>
		  the <emphasis>longest</emphasis> part of
		  <varname>$Pattern</varname> that matches
		  the <replaceable>front end</replaceable> of
		  <varname>$var</varname>.
		</para>

		<para>A usage illustration from <xref
		linkend="daysbetween">:
<programlisting># Function from "days-between.sh" example.  # Strips
leading zero(s) from argument passed.

strip_leading_zero () #  Strip possible leading zero(s)
{                     #+ from argument passed.
  return=${1#0}       #  The "1" refers to "$1" -- passed arg.
}                     #  The "0" is what to remove from "$1" -- strips zeros.</programlisting>
		</para>

		<para>Manfred Schwarb's more elaborate variation of the above:
<programlisting>strip_leading_zero2 () # Strip possible leading zero(s), since otherwise
{                      # Bash will interpret such numbers as octal values.
  shopt -s extglob     # Turn on extended globbing.
  local val=${1##+(0)} # Use local variable, longest matching series of 0's.
  shopt -u extglob     # Turn off extended globbing.
  _strip_leading_zero2=${val:-0}
                       # If input was 0, return 0 instead of "".
}</programlisting>
		</para>


		<para>Another usage illustration: 
<programlisting>echo `basename $PWD`        # Basename of current working directory.
echo "${PWD##*/}"           # Basename of current working directory.
echo
echo `basename $0`          # Name of script.
echo $0                     # Name of script.
echo "${0##*/}"             # Name of script.
echo
filename=test.data
echo "${filename##*.}"      # data
                            # Extension of filename.</programlisting>
		</para>
		  
		  </listitem>

	      </varlistentry>
	      
	      <varlistentry>
		<term><anchor id="pctpatref"><userinput>${var%Pattern}</userinput></term>
		<term><userinput>${var%%Pattern}</userinput></term>

		
		<listitem>
		
		<para><anchor id="pctrep1"></para>
		<para><command>{$var%Pattern}</command>
		  Remove from <varname>$var</varname>
		  the <emphasis>shortest</emphasis> part of
		  <varname>$Pattern</varname> that matches
		  the <replaceable>back end</replaceable> of
		  <varname>$var</varname>.  </para>

		<para><anchor id="pctrep2"></para>
	        <para><command>{$var%%Pattern}</command>
		  Remove from <varname>$var</varname>
		  the <emphasis>longest</emphasis> part of
		  <varname>$Pattern</varname> that matches
		  the <replaceable>back end</replaceable> of
		  <varname>$var</varname>.  </para>
		  
		  </listitem>


	      </varlistentry>
	    </variablelist>
	    
	    <para><link linkend="bash2ref">Version 2</link> of Bash added
	      additional options.</para>

	    <example id="pattmatching">
	      <title>Pattern matching in parameter substitution</title>
	      <programlisting>&pattmatching;</programlisting>
	    </example>


	    <example id="rfe">
	      <title>Renaming file extensions<token>:</token></title>
	      <programlisting>&rfe;</programlisting>
	    </example>

	    
	    <variablelist id="exprepl">
	      <title><anchor id="exprepl1">Variable expansion / Substring
	      replacement</title>
	      
	      <varlistentry>
	      <term></term>
	      <listitem>
	        <para>These constructs have been adopted from
		  <firstterm>ksh</firstterm>.</para>
	      </listitem>
	      </varlistentry>

	      <varlistentry>
		<term><userinput>${var:pos}</userinput></term>
		<listitem>
		  <para>Variable <replaceable>var</replaceable> expanded,
		    starting from offset <replaceable>pos</replaceable>.
		  </para>
		  </listitem>
	      </varlistentry>
	      
	      <varlistentry>
		<term><userinput>${var:pos:len}</userinput></term>
		<listitem>
		  <para>Expansion to a max of <replaceable>len</replaceable>
		    characters of variable <replaceable>var</replaceable>, from offset
		    <replaceable>pos</replaceable>. See <xref linkend="pw">
		    for an example of the creative use of this operator.
		  </para>
		  </listitem>
	      </varlistentry>
	      
	      <varlistentry>
		<term><userinput>${var/Pattern/Replacement}</userinput></term>
		<listitem>
		  <para>First match of <replaceable>Pattern</replaceable>,
		    within <replaceable>var</replaceable> replaced with
		    <replaceable>Replacement</replaceable>.</para>
		  <para>If <replaceable>Replacement</replaceable> is
		    omitted, then the first match of
		    <replaceable>Pattern</replaceable> is replaced by
		    <emphasis>nothing</emphasis>, that is, deleted.</para>
		  </listitem>  
	      </varlistentry>
	      
	      <varlistentry>
		<term><userinput>${var//Pattern/Replacement}</userinput></term>
		<listitem>

                  <formalpara><title>Global replacement</title>
		  <para><anchor id="psglob">
		    All matches of <replaceable>Pattern</replaceable>,
		    within <replaceable>var</replaceable> replaced with
		    <replaceable>Replacement</replaceable>.</para>
		    </formalpara>

		  <para>As above, if <replaceable>Replacement</replaceable>
		    is omitted, then all occurrences of
		    <replaceable>Pattern</replaceable> are replaced by
		    <emphasis>nothing</emphasis>, that is, deleted.</para>
	    
	    <example id="ex7">
	      <title>Using pattern matching to parse arbitrary strings</title>
	      <programlisting>&ex7;</programlisting>
	    </example>

		  </listitem>
	      </varlistentry>	

	      <varlistentry>
		<term><userinput>${var/#Pattern/Replacement}</userinput></term>
		<listitem>
		  <para>If <firstterm>prefix</firstterm> of
		  <replaceable>var</replaceable> matches
		  <replaceable>Pattern</replaceable>, then substitute
		  <replaceable>Replacement</replaceable> for
		  <replaceable>Pattern</replaceable>.</para>
		</listitem>
	      </varlistentry>	

	      <varlistentry>
		<term><userinput>${var/%Pattern/Replacement}</userinput></term>
		<listitem>
		  <para>If <firstterm>suffix</firstterm> of
		  <replaceable>var</replaceable> matches
		  <replaceable>Pattern</replaceable>, then substitute
		  <replaceable>Replacement</replaceable> for
		  <replaceable>Pattern</replaceable>.</para>

	    <example id="varmatch">
	      <title>Matching patterns at prefix or suffix of string</title>
	      <programlisting>&varmatch;</programlisting>
	    </example>

		</listitem>
	      </varlistentry>	

	      <varlistentry>
		<term><anchor
		id="varprefixm"><userinput>${!varprefix*}</userinput></term>
		<term><userinput>${!varprefix@}</userinput></term>
		<listitem>
		  <para>Matches <emphasis>names</emphasis> of all
		  previously declared variables beginning
		    with <parameter>varprefix</parameter>.
		      <programlisting># This is a variation on indirect reference, but with a * or @.
# Bash, version 2.04, adds this feature.

xyz23=whatever
xyz24=

a=${!xyz*}         #  Expands to *names* of declared variables
# ^ ^   ^           + beginning with "xyz".
echo "a = $a"      #  a = xyz23 xyz24
a=${!xyz@}         #  Same as above.
echo "a = $a"      #  a = xyz23 xyz24

echo "---"

abc23=something_else
b=${!abc*}
echo "b = $b"      #  b = abc23
c=${!b}            #  Now, the more familiar type of indirect reference.
echo $c            #  something_else</programlisting>
                  </para>

		  </listitem>
	      </varlistentry>	

	    </variablelist>

    </sect1> <!-- Parameter Substitution -->  



      <sect1 id="declareref">

	<indexterm>
	  <primary>declare</primary>
	</indexterm>
	<indexterm>
	  <primary>typeset</primary>
	</indexterm>
	<indexterm>
	  <primary>command</primary>
	  <secondary>declare</secondary>
	</indexterm>
	<indexterm>
	  <primary>command</primary>
	  <secondary>typeset</secondary>
	</indexterm>
	<title>Typing variables: <command>declare</command> or
	  <command>typeset</command></title>
	
	<para><anchor id="declare1ref"></para>

	<para>The <firstterm>declare</firstterm> or
	  <firstterm>typeset</firstterm> <link
	  linkend="builtinref">builtins</link>, which are exact synonyms,
	  permit modifying the properties of variables. This is
	  a very weak form of the <firstterm>typing</firstterm>

	    <footnote>

	    <para><anchor id="typingref">In this context,
	    <firstterm>typing</firstterm>
	    a variable means to classify it and restrict its properties.
	    For example, a variable <firstterm>declared</firstterm>
	    or <firstterm>typed</firstterm> as an integer
	    is no longer available for <link linkend="stringopstab">string
	    operations</link>.</para>

	    <para><programlisting>declare -i intvar

intvar=23
echo "$intvar"   # 23
intvar=stringval
echo "$intvar"   # 0</programlisting></para>

	    </footnote>

	  available in certain programming languages. The
	  <firstterm>declare</firstterm> command is specific to version
	  2 or later of Bash. The <firstterm>typeset</firstterm> command
	  also works in ksh scripts.</para>

	<variablelist id="declareopsref">
	  <title><anchor id="declareopsref1">declare/typeset options</title>

	  <varlistentry>
	    <term><token>-r</token>
	    <replaceable>readonly</replaceable></term>
	    <listitem>
	      <para>(<userinput>declare -r var1</userinput> works the same as
		<userinput>readonly var1</userinput>)</para>
	      <para>This is the rough equivalent of the <command>C</command>
		<firstterm>const</firstterm> type qualifier. An attempt
		to change the value of a <firstterm>readonly</firstterm>
		variable fails with an error message.</para>
	      <para><programlisting>declare -r var1=1
echo "var1 = $var1"   # var1 = 1

(( var1++ ))          # x.sh: line 4: var1: readonly variable</programlisting>
              </para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><token>-i</token> <replaceable>integer</replaceable></term>

	    <listitem>

	      <para><programlisting>declare -i number
# The script will treat subsequent occurrences of "number" as an integer.		

number=3
echo "Number = $number"     # Number = 3

number=three
echo "Number = $number"     # Number = 0
# Tries to evaluate the string "three" as an integer.</programlisting></para>
		
              <para>Certain arithmetic operations are permitted
		for declared integer variables without the need
		for <link linkend="exprref">expr</link> or <link
		linkend="letref">let</link>.</para>

              <para><programlisting>n=6/3
echo "n = $n"       # n = 6/3

declare -i n
n=6/3
echo "n = $n"       # n = 2</programlisting></para>
		
		</listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="arraydeclare"><token>-a</token>
	    <replaceable>array</replaceable></term>
	    <listitem><para><programlisting>declare -a indices</programlisting></para>
	      <para>The variable <parameter>indices</parameter> will be treated as
		an <link linkend="arrayref">array</link>.</para></listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><token>-f</token> <replaceable>function(s)</replaceable></term>
	    <listitem>

	      <para><programlisting>declare -f</programlisting></para>
	      <para>A <userinput>declare -f</userinput> line with no
		arguments in a script causes a listing of all the
		<link linkend="functionref">functions</link> previously
		defined in that script.</para>

	      <para><programlisting>declare -f function_name</programlisting></para>
	      <para>A <userinput>declare -f function_name</userinput>
		in a script lists just the function named.</para>

            </listitem>
	  </varlistentry>
	  
	  <varlistentry>
	    <term><token>-x</token> <link linkend="exportref">export</link></term>
	      <listitem><para><programlisting>declare -x var3</programlisting></para>
	      <para>This declares a variable as available for exporting outside the
		environment of the script itself.</para></listitem>
	  </varlistentry>

	  <varlistentry>
	    <term>-x var=$value</term>
	      <listitem>
	        <para><programlisting>declare -x var3=373</programlisting></para>
		<para>The <command>declare</command> command permits
		  assigning a value to a variable in the same statement
		  as setting its properties.</para>
	      </listitem>
	  </varlistentry>
	      

	</variablelist>

	<example id="ex20">
	  <title>Using <firstterm>declare</firstterm> to type variables</title>
	  <programlisting>&ex20;</programlisting>
	</example>


        <caution>

	<para>Using the <firstterm>declare</firstterm> builtin
	  restricts the <link linkend="scoperef">scope</link>
	  of a variable.


	  <programlisting>foo ()
{
FOO="bar"
}

bar ()
{
foo
echo $FOO
}

bar   # Prints bar.</programlisting></para>

      <para>However . . .

	  <programlisting>foo (){
declare FOO="bar"
}

bar ()
{
foo
echo $FOO
}

bar  # Prints nothing.


# Thank you, Michael Iatrou, for pointing this out.</programlisting></para>

        </caution>

      </sect1> <!-- Typing variables: declare or typeset -->


      <sect1 id="ivr">
        <title>Indirect References</title>

	<para><anchor id="ivrref"></para>

      <para>We have seen that <link linkend="varsubn">referencing
        a variable</link>, <varname>$var</varname>, fetches its
        <firstterm>value</firstterm>. <anchor id="evalindref">But,
        what about the <emphasis>value of a value</emphasis>? What
        about <varname>$$var</varname>?</para>
	
      <para>The actual notation is
	<replaceable>\$$var</replaceable>, usually preceded by
	an <link linkend="evalref">eval</link> (and sometimes an
	<link linkend="echoref">echo</link>). This is called an
	<firstterm>indirect reference</firstterm>.</para>


      <example id="indref">
	<title>Indirect Variable References</title>
	<programlisting>&indref;</programlisting>
      </example>

        <para><anchor id="irrref">Of what practical use is indirect
	  referencing of variables? It gives Bash a little of the
	  functionality of <link linkend="pointerref">pointers</link>
	  in <firstterm>C</firstterm>, for instance, in <link
	  linkend="resistor">table lookup</link>.  And, it also has some
	  other very interesting applications. . . .</para>

        <para>Nils Radtke shows how to build <quote>dynamic</quote>
	  variable names and evaluate their contents. This can be useful
	  when <link linkend="sourceref">sourcing</link> configuration
	  files.</para>

	<para><programlisting>#!/bin/bash


# ---------------------------------------------
# This could be "sourced" from a separate file.
isdnMyProviderRemoteNet=172.16.0.100
isdnYourProviderRemoteNet=10.0.0.10
isdnOnlineService="MyProvider"
# ---------------------------------------------
      

remoteNet=$(eval "echo \$$(echo isdn${isdnOnlineService}RemoteNet)")
remoteNet=$(eval "echo \$$(echo isdnMyProviderRemoteNet)")
remoteNet=$(eval "echo \$isdnMyProviderRemoteNet")
remoteNet=$(eval "echo $isdnMyProviderRemoteNet")

echo "$remoteNet"    # 172.16.0.100

# ================================================================

#  And, it gets even better.

#  Consider the following snippet given a variable named getSparc,
#+ but no such variable getIa64:

chkMirrorArchs () { 
  arch="$1";
  if [ "$(eval "echo \${$(echo get$(echo -ne $arch |
       sed 's/^\(.\).*/\1/g' | tr 'a-z' 'A-Z'; echo $arch |
       sed 's/^.\(.*\)/\1/g')):-false}")" = true ]
  then
     return 0;
  else
     return 1;
  fi;
}

getSparc="true"
unset getIa64
chkMirrorArchs sparc
echo $?        # 0
               # True

chkMirrorArchs Ia64
echo $?        # 1
               # False

# Notes:
# -----
# Even the to-be-substituted variable name part is built explicitly.
# The parameters to the chkMirrorArchs calls are all lower case.
# The variable name is composed of two parts: "get" and "Sparc" . . .</programlisting>
        </para>



      <example id="coltotaler2">
	<title>Passing an indirect reference to <firstterm>awk</firstterm></title>
	<programlisting>&coltotaler2;</programlisting>
      </example>

      <caution><para>This method of indirect referencing is a bit tricky.
	If the second order variable changes its value, then the first
	order variable must be properly dereferenced (as in the above
	example). <anchor id="ivr2">Fortunately, the
	<replaceable>${!variable}</replaceable> notation introduced
	with <link linkend="bash2ref">version 2</link> of Bash
	(see <xref linkend="ex78"> and <xref linkend="hashex2">) makes
	indirect referencing more intuitive.</para></caution>

     
     <sidebar>
       <para>Bash does not support pointer arithmetic, and this severely
	 limits the usefulness of indirect referencing. In fact, indirect
	 referencing in a scripting language is, at best, an afterthought.</para>
     </sidebar>

      </sect1> <!-- Indirect References to Variables -->


      <sect1 id="randomvar">

	<indexterm>
	  <primary>$RANDOM</primary>
	</indexterm>
	<indexterm>
	  <primary>variable</primary>
	  <secondary>$RANDOM</secondary>
	</indexterm>
	<title>$RANDOM: generate random integer</title>
	   <para><anchor id="randomvar01"></para>
	<para><varname>$RANDOM</varname> is an internal Bash <link
	  linkend="functionref">function</link> (not a constant) that
	  returns a <firstterm>pseudorandom</firstterm>

	    <footnote><para>True <quote>randomness,</quote> insofar as
	    it exists at all, can only be found in certain incompletely
	    understood natural phenomena, such as radioactive
	    decay. Computers only <firstterm>simulate</firstterm>
	    randomness, and computer-generated sequences of
	    <quote>random</quote> numbers are therefore referred to as
	    <firstterm>pseudorandom</firstterm>.</para></footnote>

	  integer in the range 0 - 32767. It should
	  <replaceable>not</replaceable> be used to generate an encryption
	  key.</para>

	<example id="ex21">
	  <title>Generating random numbers</title>
	  <programlisting>&ex21;</programlisting>
	</example>

	<example id="pickcard">
	  <title>Picking a random card from a deck</title>
	  <programlisting>&pickcard;</programlisting>
	</example>

	<para><anchor id="brownianref"></para>
	<example id="brownian">
	  <title>Brownian Motion Simulation</title>
	  <programlisting>&brownian;</programlisting>
	</example>



	<para>
	<emphasis>Jipe</emphasis> points out a set of techniques for
	generating random numbers within a range.

	<programlisting>#  Generate random number between 6 and 30.
   rnumber=$((RANDOM%25+6))	

#  Generate random number in the same 6 - 30 range,
#+ but the number must be evenly divisible by 3.
   rnumber=$(((RANDOM%30/3+1)*3))

#  Note that this will not work all the time.
#  It fails if $RANDOM%30 returns 0.

#  Frank Wang suggests the following alternative:
   rnumber=$(( RANDOM%27/3*3+6 ))</programlisting>
	</para>


	<para>
	<emphasis>Bill Gradwohl</emphasis> came up with an improved
	formula that works for positive numbers.
	<programlisting>rnumber=$(((RANDOM%(max-min+divisibleBy))/divisibleBy*divisibleBy+min))</programlisting>
	</para>

	<para>Here Bill presents a versatile function that returns
	  a random number between two specified values.</para>

	<example id="randombetween">
	  <title>Random between values</title>
	  <programlisting>&randombetween;</programlisting>
	</example>



	<para>Just how random is <varname>$RANDOM</varname>? The best
	  way to test this is to write a script that tracks
	  the distribution of <quote>random</quote> numbers
	  generated by <varname>$RANDOM</varname>. Let's roll a
	  <varname>$RANDOM</varname> die a few times . . .</para>

	<example id="randomtest">
	  <title>Rolling a single die with RANDOM</title>
	  <programlisting>&randomtest;</programlisting>
	</example>

	<para>As we have seen in the last example, it is best to
	  <firstterm>reseed</firstterm> the <parameter>RANDOM</parameter>
	  generator each time it is invoked. Using the same seed
	  for <parameter>RANDOM</parameter> repeats the same series
	  of numbers.
	    <footnote>
	    <para>The <firstterm>seed</firstterm> of a
	      computer-generated pseudorandom number series
	      can be considered an identification label. For
	      example, think of the pseudorandom series with a
	      seed of <emphasis>23</emphasis> as <replaceable>Series
	      #23</replaceable>.</para>
	    <para>A property of a pseurandom number series is the length of
	      the cycle before it starts repeating itself. A good pseurandom
	      generator will produce series with very long cycles.</para>
	    </footnote>
	  (This mirrors the behavior of the
	  <replaceable>random()</replaceable> function in
	  <firstterm>C</firstterm>.)</para>

	<example id="seedingrandom">
	  <title>Reseeding RANDOM</title>
	  <programlisting>&seedingrandom;</programlisting>
	</example>

	<para><anchor id="urandomref"></para>
	<note>
	<para>The <filename>/dev/urandom</filename> pseudo-device file
	  provides a method of generating much more <quote>random</quote>
	  pseudorandom numbers than the <varname>$RANDOM</varname>
	  variable.  <userinput>dd if=/dev/urandom of=targetfile
	  bs=1 count=XX</userinput> creates a file of well-scattered
	  pseudorandom numbers.  However, assigning these numbers
	  to a variable in a script requires a workaround, such
	  as filtering through <link linkend="odref">od</link>
	  (as in above example, <xref linkend="rnd">, and
	  <xref linkend="insertionsort">), or even piping to
	  <link linkend="md5sumref">md5sum</link> (see <xref
	  linkend="horserace">).</para>

        <para><anchor id="awkrandomref"></para>
	  
        <para>There are also other ways to generate pseudorandom
          numbers in a script. <command>Awk</command> provides a
	  convenient means of doing this.</para>

	    <example id="random2">
	      <title>Pseudorandom numbers, using <link
	        linkend="awkref">awk</link></title>
	      <programlisting>&random2;</programlisting>
	    </example>

	<para>The <link linkend="dateref">date</link> command also lends
	  itself to <link linkend="daterandref">generating pseudorandom
	  integer sequences</link>.</para>

	  </note>



      </sect1> <!-- RANDOM: generate random integer -->


      <sect1 id="dblparens">
        <title>The Double-Parentheses Construct</title>

	<para><anchor id="dblparensref"></para>

	<para>Similar to the <link linkend="letref">let</link> command,
	  the <command>(( ... ))</command> construct permits
	  arithmetic expansion and evaluation. In its simplest
	  form, <userinput>a=$(( 5 + 3 ))</userinput> would set
	  <userinput>a</userinput> to <userinput>5 + 3</userinput>, or
	  <userinput>8</userinput>. However, this double-parentheses
	  construct is also a mechanism for allowing C-style
	  manipulation of variables in Bash, for example,
	  <varname>(( var++ ))</varname>.</para>

        <para><anchor id="plusplusref"></para>

      <example id="cvars">
	<title>C-style manipulation of variables</title>
	<programlisting>&cvars;</programlisting>
      </example>

        <para>See also <xref linkend="forloopc"> and <xref linkend="numbers">.</para>


      </sect1> <!-- The Double-Parentheses Construct  -->
      

  </chapter> <!-- Variables Revisited -->


  <chapter id="loops">
    <title>Loops and Branches</title>

    <epigraph>
      <para>What needs this iteration, woman?</para>
      <para>--Shakespeare, <command>Othello</command></para>
    </epigraph>


      <para><anchor id="loopref00"></para>
      <para>Operations on code blocks are the key to structured and organized
        shell scripts. Looping and branching constructs provide the tools for
	accomplishing this.</para>

      <sect1 id="loops1">
        <title>Loops</title>

      <para>A <firstterm>loop</firstterm> is a block of code that
	<firstterm>iterates</firstterm>

	  <footnote><para><anchor
	  id="iterationref"><firstterm>Iteration</firstterm>:
	  Repeated execution of a command or group of commands --
	  usually, but not always -- while a given condition holds,
	  or until a given condition is met.</para></footnote>

	a list of commands
	as long as the <firstterm>loop control condition</firstterm>
	is true.</para>


      <variablelist id="forloopref">
        <title><anchor id="forloopref1">for loops</title>

	<varlistentry>
	  <term><command>for <parameter>arg</parameter> in
	    <replaceable>[list]</replaceable></command></term>
	  <indexterm>
	    <primary>for</primary>
	  </indexterm>
	  <indexterm>
	    <primary>in</primary>
	  </indexterm>
	  <indexterm>
	    <primary>do</primary>
	  </indexterm>
	  <indexterm>
	    <primary>done</primary>
	  </indexterm>
	  <indexterm>
	    <primary>loop</primary>
	    <secondary>for</secondary>
	  </indexterm>
	  <listitem>
	    <para>This is the basic looping construct. It differs significantly
	      from its <firstterm>C</firstterm> counterpart.</para>

	    <para><anchor id="doinref"></para>

	    <para><cmdsynopsis>
		<command>for</command>
		<arg choice="plain"><replaceable>arg</replaceable></arg>
		<arg choice="plain">in</arg>
		<arg choice="opt"><replaceable>list</replaceable></arg><sbr>
		<arg choice="plain">do</arg><sbr>
		<arg rep=repeat choice=plain><replaceable>&nbsp;command(s)</replaceable></arg><sbr>
		<arg choice="plain">done</arg>
	      </cmdsynopsis></para>

            <note><para>During each pass through the loop,
	      <replaceable>arg</replaceable> takes on the
	      value of each successive variable in the
	      <replaceable>list</replaceable>.</para></note>

	    <para><programlisting>for arg in "$var1" "$var2" "$var3" ... "$varN"  
# In pass 1 of the loop, arg = $var1	    
# In pass 2 of the loop, arg = $var2	    
# In pass 3 of the loop, arg = $var3	    
# ...
# In pass N of the loop, arg = $varN

# Arguments in [list] quoted to prevent possible word splitting.</programlisting></para>

	    
	    <para>The argument <replaceable>list</replaceable> may
	    contain <link linkend="asteriskref">wild cards</link>.</para>

	    <para><anchor id="needsemicolon"></para>
	    <para>If <firstterm>do</firstterm> is on same line as
	      <firstterm>for</firstterm>, there needs to be a semicolon
	      after list.</para>

	    <para><cmdsynopsis>
		<command>for</command>
		<arg choice="plain"><replaceable>arg</replaceable></arg>
		<arg choice="plain">in</arg>
		<arg choice="opt"><replaceable>list</replaceable></arg>
		<arg choice="plain">;</arg>
		<arg choice="plain">do</arg><sbr>
	      </cmdsynopsis></para>

	    <example id="ex22">
	      <title>Simple <firstterm>for</firstterm> loops</title>
	      <programlisting>&ex22;</programlisting>
	    </example>

            
	    <para><anchor id="multparaml"></para>
	    <para>Each <userinput>[list]</userinput> element
	      may contain multiple parameters. This is useful when
	      processing parameters in groups. In such cases,
	      use the <link linkend="setref">set</link> command
	      (see <xref linkend="ex34">) to force parsing of each
	      <userinput>[list]</userinput> element and assignment of
	      each component to the positional parameters.</para>

	    <example id="ex22a">
	      <title><firstterm>for</firstterm> loop with two parameters in each
	      [list] element</title>
	      <programlisting>&ex22a;</programlisting>
	    </example>


	    <para><anchor id="paramli"></para>
	    <para>A variable may supply the <userinput>[list]</userinput> in a
	      <firstterm>for loop</firstterm>.</para>

	    <example id="fileinfo">
	      <title><emphasis>Fileinfo:</emphasis> operating on a file list
	        contained in a variable</title>
	      <programlisting>&fileinfo;</programlisting>
	    </example>

	    
	    <para><anchor id="liglob"></para>
	    <para>If the <userinput>[list]</userinput> in a
	      <firstterm>for loop</firstterm> contains wild cards
	      (<token>*</token> and <token>?</token>) used in filename
	      expansion, then <link linkend="globbingref">globbing</link>
	      takes place.</para>

	    <example id="listglob">
	      <title>Operating on files with a <firstterm>for</firstterm> loop</title>
	      <programlisting>&listglob;</programlisting>
	    </example>


	    <para><anchor id="omitlist"></para>
	    <para>Omitting the <userinput>in [list]</userinput> part of a
	      <firstterm>for loop</firstterm> causes the loop to operate
	      on <token>$@</token> -- the <link linkend="posparamref">
	      positional parameters</link>. A particularly clever
	      illustration of this is <xref linkend="primes">. See also <xref
	      linkend="revposparams">.</para>

	    <example id="ex23">
	      <title>Missing <userinput>in [list]</userinput> in a
		<firstterm>for</firstterm> loop</title>
	      <programlisting>&ex23;</programlisting>
	    </example>


	    <para><anchor id="loopcs"></para>
	    <para>It is possible to use <link
	      linkend="commandsubref">command substitution</link>
	      to generate the <userinput>[list]</userinput> in a
	      <firstterm>for loop</firstterm>. See also <xref linkend="ex53">,
	      <xref linkend="symlinks"> and <xref linkend="base">.</para>

	    <example id="forloopcmd">
	      <title>Generating the <userinput>[list]</userinput> in
	      a <firstterm>for</firstterm> loop with command substitution</title>
	      <programlisting>&forloopcmd;</programlisting>
	    </example>


	    <para>Here is a somewhat more complex example of using command
	      substitution to create the <userinput>[list]</userinput>.</para>

	    <example id="bingrep">
	      <title>A <firstterm>grep</firstterm> replacement
	        for binary files</title>
	      <programlisting>&bingrep;</programlisting>
	    </example>

	    <para>More of the same.</para>

	    <example id="userlist">
	      <title>Listing all users on the system</title>
	      <programlisting>&userlist;</programlisting>
	    </example>

	    <para>Yet another example of the <userinput>[list]</userinput>
	      resulting from command substitution.</para>

	    <example id="findstring">
	      <title>Checking all the binaries in a directory for
	      authorship</title>
	      <programlisting>&findstring;</programlisting>
	    </example>

	    <para>A final example of <userinput>[list]</userinput>
	       / command substitution, but this time
	       the <quote>command</quote> is a <link
	       linkend="functionref">function</link>.</para>

            <para><programlisting>generate_list ()
{
  echo "one two three"
}

for word in $(generate_list)  # Let "word" grab output of function.
do
  echo "$word"
done

# one
# two
# three</programlisting></para>


	    <para><anchor id="loopredir"></para>
	    <para>The output of a <firstterm>for loop</firstterm> may
	      be piped to a command or commands.</para>

	    <example id="symlinks">
	      <title>Listing the <firstterm>symbolic
	        links</firstterm> in a directory</title>
	      <programlisting>&symlinks;</programlisting>
	    </example>

	    <para>The <filename>stdout</filename> of a loop may be <link
	      linkend="ioredirref">redirected</link> to a file, as this slight
	      modification to the previous example shows.</para>

	    <example id="symlinks2">
	      <title>Symbolic links in a directory, saved to a file</title>
	      <programlisting>&symlinks2;</programlisting>
	    </example>

	    <para><anchor id="loopcstyle"></para>
	    <para>There is an alternative syntax to a <firstterm>for
	      loop</firstterm> that will look very familiar to C
	      programmers. This requires <link
	      linkend="dblparensref">double parentheses</link>.</para>

	    <example id="forloopc">
	      <title>A C-style <firstterm>for</firstterm> loop</title>
	      <programlisting>&forloopc;</programlisting>
	    </example>

	    <para>See also <xref linkend="qfunction">, <xref
	      linkend="twodim">, and <xref linkend="collatz">.</para>

	    <para>---</para>

	    <para>Now, a <firstterm>for loop</firstterm> used in a
	      <quote>real-life</quote> context.</para>

	    <example id="ex24">
	      <title>Using <firstterm>efax</firstterm> in batch mode</title>
	      <programlisting>&ex24;</programlisting>
	    </example>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="whileloopref"><command>while</command></term>
	  <indexterm>
	    <primary>while</primary>
	  </indexterm>
	  <indexterm>
	    <primary>do</primary>
	  </indexterm>
	  <indexterm>
	    <primary>done</primary>
	  </indexterm>
	  <indexterm>
	    <primary>loop</primary>
	    <secondary>while</secondary>
	  </indexterm>
	  <listitem>
	    <para>This construct tests for a condition at the top of a
	      loop, and keeps looping as long as that condition
	      is true (returns a <returnvalue>0</returnvalue> <link
	      linkend="exitstatusref">exit status</link>).  In contrast
	      to a <link linkend="forloopref1">for loop</link>, a
	      <firstterm>while loop</firstterm> finds use in situations
	      where the number of loop repetitions is not known
	      beforehand.</para>

	    <para><cmdsynopsis>
		<command>while</command>
		<arg choice="opt"><replaceable> condition </replaceable></arg><sbr>
		<arg choice="plain">do</arg><sbr>
		<arg choice="plain" rep="repeat"><replaceable>&nbsp;command(s)</replaceable></arg><sbr>
		<arg choice="plain">done</arg>
	      </cmdsynopsis></para>


	    <para>The bracket construct in a <firstterm>while
	      loop</firstterm> is nothing more than our old friend,
	      the <link linkend="testconstructs1">test brackets</link>
	      used in an <firstterm>if/then</firstterm> test. In fact,
	      a <firstterm>while loop</firstterm> can legally use the
	      more versatile <link linkend="dblbrackets">double-brackets
	      construct</link> (while [[ condition ]]).</para>

	    <para><anchor id="whileneedsemi"></para>
	    <para><link linkend="needsemicolon">As is the case with
	      <firstterm>for loops</firstterm></link>, placing the
	      <firstterm>do</firstterm> on the same line as the condition
	      test requires a semicolon.</para>

	    <para><cmdsynopsis>
		<command>while</command>
		<arg choice="opt"><replaceable> condition </replaceable></arg>
		<arg choice="plain">;</arg>
		<arg choice="plain">do</arg>
	      </cmdsynopsis></para>
	    
	    <para>Note that the <firstterm>test brackets</firstterm>
	      <link linkend="whilenobrackets">are <emphasis>not</emphasis>
	      mandatory</link> in a <firstterm>while</firstterm> loop.
	      See, for example,  the <link linkend="getoptsx">getopts
	      construct</link>.</para>

	    <example id="ex25">
	      <title>Simple <firstterm>while</firstterm> loop</title>
	      <programlisting>&ex25;</programlisting>
	    </example>
	    
	    <example id="ex26">
	      <title>Another <firstterm>while</firstterm> loop</title>
	      <programlisting>&ex26;</programlisting>
	    </example>	    


	    <para><anchor id="whmultcond"></para>
            <para>A <firstterm>while loop</firstterm> may have multiple
	      conditions. Only the final condition determines when the loop
	      terminates. This necessitates a slightly different loop syntax,
	      however.</para>

	    <example id="ex26a">
	      <title><firstterm>while</firstterm> loop with multiple conditions</title>
	      <programlisting>&ex26a;</programlisting>
	    </example>	    

	    <para><anchor id="wloopcstyle"></para>
	    <para>As with a <firstterm>for loop</firstterm>, a
	      <firstterm>while loop</firstterm> may employ C-style syntax
	      by using the double-parentheses construct (see also <xref
	      linkend="cvars">).</para>

	    <example id="whloopc">
	      <title>C-style syntax in a <firstterm>while</firstterm> loop</title>
	      <programlisting>&whloopc;</programlisting>
	    </example>

	    <para><anchor id="whilefunc"></para>
	    <para>
	      Inside its test brackets, a <firstterm>while loop</firstterm>
	      can call a <link linkend="functionref">function</link>.

	      <programlisting>t=0

condition ()
{
  ((t++))

  if [ $t -lt 5 ]
  then
    return 0  # true
  else
    return 1  # false
  fi
}

while condition
#     ^^^^^^^^^
#     Function call -- four loop iterations.
do
  echo "Still going: t = $t"
done

# Still going: t = 1
# Still going: t = 2
# Still going: t = 3
# Still going: t = 4</programlisting>
	    
	    
	    
	    </para>


	    <sidebar><para><anchor id="whilenobrackets"></para>
            <para>Similar to the <link linkend="ifgrepref">if-test</link>
	      construct, a <firstterm>while</firstterm> loop can omit the test
	      brackets.
	        <programlisting>while condition
do
   ...
done</programlisting></para></sidebar>

	    <para><anchor id="whilereadref2"></para>
	    <para>By coupling the power of the <link
	      linkend="readref">read</link> command with a
	      <firstterm>while loop</firstterm>, we get the handy <link
	      linkend="whilereadref">while read</link> construct, useful
	      for reading and parsing files.</para>

	    <para><programlisting>cat $filename |   # Supply input from a file.
while read line   # As long as there is another line to read ...
do
  ...
done

# =========== Snippet from "sd.sh" example script ========== #

  while read value   # Read one data point at a time.
  do
    rt=$(echo "scale=$SC; $rt + $value" | bc)
    (( ct++ ))
  done

  am=$(echo "scale=$SC; $rt / $ct" | bc)

  echo $am; return $ct   # This function "returns" TWO values!
  #  Caution: This little trick will not work if $ct > 255!
  #  To handle a larger number of data points,
  #+ simply comment out the "return $ct" above.
} <"$datafile"   # Feed in data file.</programlisting></para>

	    <para><anchor id="whredir"></para>
	    <note>
	    <para>A <firstterm>while loop</firstterm> may have its
	      <filename>stdin</filename> <link
	      linkend="redirref">redirected to a file</link> by a
	      <token>&lt;</token> at its end.</para>

	    <para>A <firstterm>while loop</firstterm> may have its
	      <filename>stdin</filename> <link linkend="readpiperef">
	      supplied by a pipe</link>.</para>
	    </note>

	    </listitem>
	  </varlistentry>



	<varlistentry>
	  <term><anchor id="untilloopref"><command>until</command></term>
	  <indexterm>
	    <primary>until</primary>
	  </indexterm>
	  <indexterm>
	    <primary>do</primary>
	  </indexterm>
	  <indexterm>
	    <primary>done</primary>
	  </indexterm>
	  <indexterm>
	    <primary>loop</primary>
	    <secondary>until</secondary>
	  </indexterm>

	  <listitem>
	    <para>This construct tests for a condition at the top of a loop, and keeps
	      looping as long as that condition is
	      <emphasis>false</emphasis> (opposite of <firstterm>while
	      loop</firstterm>).</para>

	    <para><cmdsynopsis>
		<command>until</command>
		<arg choice="opt"><replaceable> condition-is-true </replaceable></arg><sbr>
		<arg choice="plain">do</arg><sbr>
		<arg choice="plain" rep="repeat"><replaceable>&nbsp;command(s)</replaceable></arg><sbr>
		<arg choice="plain">done</arg>
	      </cmdsynopsis></para>

	    <para>Note that an <firstterm>until loop</firstterm> tests for the
	      terminating condition at the <emphasis>top</emphasis>
	      of the loop, differing from a similar construct in some
	      programming languages.</para>

	    <para>As is the case with <firstterm>for loops</firstterm>,
	      placing the <firstterm>do</firstterm> on the same line as
	      the condition test requires a semicolon.</para>

	    <para><cmdsynopsis>
		<command>until</command>
		<arg choice="opt"><replaceable> condition-is-true </replaceable></arg>
		<arg choice="plain">;</arg>
		<arg choice="plain">do</arg>
	      </cmdsynopsis></para>

	    <example id="ex27">
	      <title><firstterm>until</firstterm> loop</title>
	      <programlisting>&ex27;</programlisting>
	    </example>	    
	    </listitem>
	  </varlistentry>

	</variablelist>

	<para><anchor id="chooseloop"></para>
	<para>How to choose between a <firstterm>for</firstterm> loop or a
	  <firstterm>while</firstterm> loop or
	  <firstterm>until</firstterm> loop? In <command>C</command>,
	  you would typically use a <firstterm>for</firstterm> loop
	  when the number of loop iterations is known beforehand. With
	  <firstterm>Bash</firstterm>, however, the situation is
	  fuzzier. The Bash <firstterm>for</firstterm> loop is more
	  loosely structured and more flexible than its equivalent in
	  other languages. Therefore, feel free to use whatever type
	  of loop gets the job done in the simplest way.</para>

    </sect1> <!-- Loops -->



      <sect1 id="nestedloops">
        <title>Nested Loops</title>

	<para>A <firstterm>nested loop</firstterm> is a loop within a
	  loop, an inner loop within the body of an outer one. How
	  this works is that the first pass of the outer loop triggers
	  the inner loop, which executes to completion. Then the
	  second pass of the outer loop triggers the inner loop
	  again. This repeats until the outer loop finishes. Of course,
	  a <firstterm>break</firstterm> within either the inner or outer
	  loop would interrupt this process.</para>

	    <example id="nestedloop">
	      <title>Nested Loop</title>
	      <programlisting>&nestedloop;</programlisting>
	    </example>	    

	<para>See <xref linkend="bubble"> for an illustration of nested
	  <link linkend="whileloopref">while loops</link>, and <xref
	  linkend="ex68"> to see a while loop nested inside an <link
	  linkend="untilloopref">until loop</link>.</para>

    </sect1> <!-- Nested Loops -->


      <sect1 id="loopcontrol">
        <title>Loop Control</title>

    <epigraph>
      <para>Tournez cent tours, tournez mille tours,</para>
      <para>Tournez souvent et tournez toujours . . .</para>
      <para>--Verlaine, <quote>Chevaux de bois</quote></para>
    </epigraph>

	<variablelist id="brkcont">
	  <title><anchor id="brkcont1">Commands affecting loop behavior</title>

	<varlistentry>
	  <indexterm>
	    <primary>break</primary>
	  </indexterm>
	  <indexterm>
	    <primary>continue</primary>
	  </indexterm>
	  <indexterm>
	    <primary>loop</primary>
	    <secondary>break</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>loop</primary>
	    <secondary>continue</secondary>
	  </indexterm>
	  <term><command>break</command></term>
	  <term><command>continue</command></term>
	  <listitem>
	    <para>The <command>break</command> and <command>continue</command>
	      loop control commands
		<footnote><para>These are shell <link
		linkend="builtinref">builtins</link>,
		whereas other loop commands, such as <link
		linkend="whileloopref">while</link> and <link
		linkend="caseesac1">case</link>, are <link
		linkend="keywordref">keywords</link>.</para></footnote>
	      correspond exactly to their counterparts in other
	      programming languages. The <command>break</command>
	      command terminates the loop (<emphasis>breaks</emphasis>
	      out of it), while <command>continue</command> causes a jump
	      to the next <link linkend="iterationref">iteration</link>
	      of the loop, skipping all the remaining commands in that
	      particular loop cycle.</para>

	    <example id="ex28">
	      <title>Effects of <firstterm>break</firstterm> and
		<command>continue</command> in a loop</title>
	      <programlisting>&ex28;</programlisting>
	    </example>	    

	    <para><anchor id="breakparam"></para>
            <para>The <command>break</command> command may optionally take a
	      parameter. A plain <command>break</command> terminates
	      only the innermost loop in which it is embedded,
	      but a <command>break N</command> breaks out of
	      <parameter>N</parameter> levels of loop.</para>

	    <example id="breaklevels">
	      <title>Breaking out of multiple loop levels</title>
	      <programlisting>&breaklevels;</programlisting>
	    </example>	    

	    <para>The <command>continue</command> command, similar to
	      <command>break</command>, optionally takes a parameter. A
	      plain <command>continue</command> cuts short the
	      current iteration within its loop and begins the next.
	      A <command>continue N</command> terminates all remaining
	      iterations at its loop level and continues with the
	      next iteration at the loop, <option>N</option> levels
	      above.</para>

	    <example id="continuelevels">
	      <title>Continuing at a higher loop level</title>
	      <programlisting>&continuelevels;</programlisting>
	    </example>	    

	    <example id="continuenex">
	      <title>Using <firstterm>continue N</firstterm> in an actual task</title>
	      <programlisting>&continuenex;</programlisting>
	    </example>	    

	    <caution><para>The <command>continue N</command> construct is
	      difficult to understand and tricky to use in any meaningful
	      context. It is probably best avoided.</para></caution>

	  </listitem>
	</varlistentry>

	</variablelist>

    </sect1> <!-- Loop Control Commands -->



      <sect1 id="testbranch">
        <title>Testing and Branching</title>

	<para>The <command>case</command> and <command>select</command>
	  constructs are technically not loops, since they do not iterate the
	  execution of a code block. Like loops, however, they direct
	  program flow according to conditions at the top or bottom of
	  the block.</para>

	<variablelist id="caseesac">
	  <title><anchor id="caseesac1">Controlling program flow in a code
	    block</title>

	<varlistentry>
	  <term><command>case (in) / esac</command></term>
	  <indexterm>
	    <primary>case</primary>
	  </indexterm>
	  <indexterm>
	    <primary>in</primary>
	  </indexterm>
	  <indexterm>
	    <primary>esac</primary>
	  </indexterm>
	  <indexterm>
	    <primary>switch</primary>
	  </indexterm>
	  <indexterm>
	    <primary>;;</primary>
	  </indexterm>
	  <indexterm>
	    <primary>menus</primary>
	  </indexterm>

	  <listitem>
	    <para>The <command>case</command> construct is the shell
	      scripting analog to <firstterm>switch</firstterm> in C/C++.
	      It permits branching to one of a number of code blocks,
	      depending on condition tests. It serves as a kind of
	      shorthand for multiple <token>if/then/else</token>
	      statements and is an appropriate tool for creating
	      menus.</para>

	    <para><cmdsynopsis>
		<command>case</command>
		<arg choice="plain">"$<replaceable>variable</replaceable>"</arg>
		<arg choice="plain">in</arg><sbr><sbr>
		<arg choice="plain">&nbsp;"$<replaceable>condition1</replaceable>" )</arg><sbr>
		<arg choice="plain" rep="repeat">&nbsp;<replaceable>command</replaceable></arg><sbr>
		<arg choice="plain">&nbsp;;;</arg><sbr><sbr>
		<arg choice="plain">&nbsp;"$<replaceable>condition2</replaceable>" )</arg><sbr>
		<arg choice="plain" rep="repeat">&nbsp;<replaceable>command</replaceable></arg><sbr>
		<arg choice="plain">&nbsp;;;</arg><sbr><sbr>
		<arg choice="plain">esac</arg>
	      </cmdsynopsis></para>

	    <note><para>
	      <itemizedlist>
		<listitem><para>Quoting the variables is not mandatory, since
		word splitting does not take place.</para>
		</listitem>
		<listitem>
		  <para><anchor id="caseparen">Each test line
		    ends with a right paren <token>)</token>.</para>
		</listitem>
		<listitem><para>Each condition block ends with a <emphasis>double</emphasis>
		    semicolon <token>;;</token>.</para>
		</listitem>
		<listitem><para>The entire <command>case</command> block terminates with an
	      <command>esac</command> (<wordasword>case</wordasword> spelled
		backwards).</para>
		  </listitem>
	      </itemizedlist>
	    </para></note>

	    <example id="ex29">
	      <title>Using <firstterm>case</firstterm></title>
	      <programlisting>&ex29;</programlisting>
	    </example>	    

	    <example id="ex30">
	      <title>Creating menus using <firstterm>case</firstterm></title>
	      <programlisting>&ex30;</programlisting>
	    </example>	    

	    <para><anchor id="casecl"></para>
	    <para>An exceptionally clever use of <command>case</command>
	      involves testing for command-line parameters.
	      <programlisting>#! /bin/bash

case "$1" in
  "") echo "Usage: ${0##*/} &lt;filename&gt;"; exit $E_PARAM;;
                      # No command-line parameters,
                      # or first parameter empty.
# Note that ${0##*/} is ${var##pattern} param substitution.
                      # Net result is $0.

  -*) FILENAME=./$1;;   #  If filename passed as argument ($1)
                      #+ starts with a dash,
                      #+ replace it with ./$1
                      #+ so further commands don't interpret it
                      #+ as an option.

  * ) FILENAME=$1;;     # Otherwise, $1.
esac</programlisting></para>

	    <para>Here is an more straightforward example of
	      command-line parameter handling:
	      <programlisting>#! /bin/bash


while [ $# -gt 0 ]; do    # Until you run out of parameters . . .
  case "$1" in
    -d|--debug)
              # "-d" or "--debug" parameter?
              DEBUG=1
              ;;
    -c|--conf)
              CONFFILE="$2"
              shift
              if [ ! -f $CONFFILE ]; then
                echo "Error: Supplied file doesn't exist!"
                exit $E_CONFFILE     # File not found error.
              fi
              ;;
  esac
  shift       # Check next set of parameters.
done

#  From Stefano Falsetto's "Log2Rot" script,
#+ part of his "rottlog" package.
#  Used with permission.</programlisting></para>


	    <example id="casecmd">
	      <title>Using <firstterm>command substitution</firstterm>
	      to generate the <firstterm>case</firstterm> variable</title>
	      <programlisting>&casecmd;</programlisting>
	    </example>	    

	    <para><anchor id="csglob"></para>
	    <para>A <command>case</command> construct can filter strings for
	      <link linkend="globbingref">globbing</link> patterns.</para>

	    <example id="matchstring">
	      <title>Simple string matching</title>
	      <programlisting>&matchstring;</programlisting>
	    </example>	    

	    <example id="isalpha">
	      <title>Checking for alphabetic input</title>
	      <programlisting>&isalpha;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>



	<varlistentry>
	  <term><anchor id="selectref"><command>select</command></term>
	  <indexterm>
	    <primary>select</primary>
	  </indexterm>
	  <indexterm>
	    <primary>menus</primary>
	  </indexterm>
	  <listitem>
	    <para>The <command>select</command> construct, adopted from the Korn
	      Shell, is yet another tool for building menus.</para>

	    <para><cmdsynopsis>
		<command>select</command>
		<arg choice="plain"><replaceable>variable</replaceable></arg>
		<arg choice="opt">in <replaceable>list</replaceable></arg><sbr>
		<arg choice="plain">do</arg><sbr>
		<arg choice="plain" rep="repeat">&nbsp;<replaceable>command</replaceable></arg><sbr>
		<arg choice="plain">&nbsp;break</arg><sbr>
		<arg choice="plain">done</arg>
	      </cmdsynopsis></para>
	    
	    <para>This prompts the user to enter one of the choices presented in the
	      variable list.  Note that <command>select</command> uses the
	      <varname>$PS3</varname> prompt (<prompt>#? </prompt>) by default, 
		but this may be changed.</para>
	    
	    <example id="ex31">
	      <title>Creating menus using <firstterm>select</firstterm></title>
	      <programlisting>&ex31;</programlisting>
	    </example>	    

	    <para><anchor id="inlistomit"></para>
	    <para>If <userinput>in <replaceable>list</replaceable></userinput> is
	      omitted, then <command>select</command> uses the list of command
	      line arguments (<varname>$@</varname>) passed to the script or to
	      the function in which the <command>select</command> construct is
	      embedded.</para>
	      
	    <para>Compare this to the behavior of a 
	      <cmdsynopsis>
		<command>for</command>
		<arg choice="plain"><replaceable>variable</replaceable></arg>
		<arg choice="opt">in <replaceable>list</replaceable></arg>
	      </cmdsynopsis>
	      construct with the 
	      <userinput>in <replaceable>list</replaceable></userinput>
	      omitted.</para>

	    <example id="ex32">
	      <title>Creating menus using <firstterm>select</firstterm>
	      in a function</title>
	      <programlisting>&ex32;</programlisting>
	    </example>	    

	    <para>See also <xref linkend="resistor">.</para>

	    </listitem>
	  </varlistentry>

      </variablelist>

    </sect1> <!-- Testing and Branching -->


  </chapter> <!-- Loops -->



  <chapter id="commandsub">
    <title>Command Substitution</title>

      <indexterm>
	<primary>$</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>`</secondary>
      </indexterm>

	   <para>
	     <anchor id="commandsubref"><command>Command
	     substitution</command> reassigns the output of a command
		<footnote><para>For purposes of <firstterm>command
		substitution</firstterm>, a <command>command</command>
		may be an external system command, an internal scripting
		<link linkend="builtinref">builtin</link>, or even <link
		linkend="rvt">a script function</link>.</para></footnote>
	     or even multiple commands; it literally plugs the command
	     output into another context.

	        <footnote><para>In a more technically correct sense,
		<firstterm>command substitution</firstterm> extracts the
		<filename>stdout</filename> of a command, then assigns
		it to a variable using the <token>=</token>
		operator.</para></footnote>
	     </para>


	    <para><anchor id="backquotesref">The classic form of command
	      substitution uses <firstterm>backquotes</firstterm>
	      (`...`). Commands within backquotes (backticks) generate
	      command line text.

	      <programlisting>script_name=`basename $0`
echo "The name of this script is $script_name."</programlisting></para>


	    <formalpara>
	      <title>The output of commands can be used as arguments to
	      another command, to set a variable, and even for generating
	      the argument list in a <link linkend="forloopref1">for</link>
	      loop.</title>
	      <para></para>
	    </formalpara>

            <para>
	      <programlisting>rm `cat filename`   # <quote>filename</quote> contains a list of files to delete.
#
# S. C. points out that "arg list too long" error might result.
# Better is              xargs rm -- < filename 
# ( -- covers those cases where <quote>filename</quote> begins with a <quote>-</quote> )

textfile_listing=`ls *.txt`
# Variable contains names of all *.txt files in current working directory.
echo $textfile_listing

textfile_listing2=$(ls *.txt)   # The alternative form of command substitution.
echo $textfile_listing2
# Same result.

# A possible problem with putting a list of files into a single string
# is that a newline may creep in.
#
# A safer way to assign a list of files to a parameter is with an array.
#      shopt -s nullglob    # If no match, filename expands to nothing.
#      textfile_listing=( *.txt )
#
# Thanks, S.C.</programlisting>
            </para>

              <note><para><anchor id="cssubsh">Command substitution
              invokes a <link
              linkend="subshellsref">subshell</link>.</para></note>



              <caution><para><anchor id="csws">Command substitution may
                result in word splitting.
	        <programlisting>COMMAND `echo a b`     # 2 args: a and b

COMMAND "`echo a b`"   # 1 arg: "a b"

COMMAND `echo`         # no arg

COMMAND "`echo`"       # one empty arg


# Thanks, S.C.</programlisting></para>


	      <para><anchor id="cstrnl"></para>
	      <para>Even when there is no word splitting, command
	        substitution can remove trailing newlines.

		<programlisting># cd "`pwd`"  # This should always work.
# However...

mkdir 'dir with trailing newline
'

cd 'dir with trailing newline
'

cd "`pwd`"  # Error message:
# bash: cd: /tmp/file with trailing newline: No such file or directory

cd "$PWD"   # Works fine.





old_tty_setting=$(stty -g)   # Save old terminal setting.
echo "Hit a key "
stty -icanon -echo           # Disable "canonical" mode for terminal.
                             # Also, disable *local* echo.
key=$(dd bs=1 count=1 2&gt; /dev/null)   # Using 'dd' to get a keypress.
stty "$old_tty_setting"      # Restore old setting. 
echo "You hit ${#key} key."  # ${#variable} = number of characters in $variable
#
# Hit any key except RETURN, and the output is "You hit 1 key."
# Hit RETURN, and it's "You hit 0 key."
# The newline gets eaten in the command substitution.

Thanks, S.C.</programlisting>
              </para>
              </caution>


              <caution>
	      <para>Using <command>echo</command> to output an
		<firstterm>unquoted</firstterm> variable set with command
		substitution removes trailing newlines characters from
		the output of the reassigned command(s). This can cause
		unpleasant surprises.

		<programlisting>dir_listing=`ls -l`
echo $dir_listing     # unquoted

# Expecting a nicely ordered directory listing.

# However, what you get is:
# total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
# bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh

# The newlines disappeared.


echo "$dir_listing"   # quoted
# -rw-rw-r--    1 bozo       30 May 13 17:15 1.txt
# -rw-rw-r--    1 bozo       51 May 15 20:57 t2.sh
# -rwxr-xr-x    1 bozo      217 Mar  5 21:13 wi.sh</programlisting>
              </para>
              </caution>



	     <para>Command substitution even permits setting a variable to the
	       contents of a file, using either <link
	       linkend="ioredirref">redirection</link> or the <link
	       linkend="catref">cat</link> command.</para>

             <para>
	         <programlisting>variable1=`&lt;file1`      #  Set "variable1" to contents of "file1".
variable2=`cat file2`   #  Set "variable2" to contents of "file2".
                        #  This, however, forks a new process,
                        #+ so the line of code executes slower than the above version.

#  Note:
#  The variables may contain embedded whitespace,
#+ or even (horrors), control characters.</programlisting>
             </para>

             <para>
	         <programlisting>#  Excerpts from system file, /etc/rc.d/rc.sysinit
#+ (on a Red Hat Linux installation)


if [ -f /fsckoptions ]; then
        fsckoptions=`cat /fsckoptions`
...
fi
#
#
if [ -e "/proc/ide/${disk[$device]}/media" ] ; then
             hdmedia=`cat /proc/ide/${disk[$device]}/media`
...
fi
#
#
if [ ! -n "`uname -r | grep -- "-"`" ]; then
       ktag="`cat /proc/version`"
...
fi
#
#
if [ $usb = "1" ]; then
    sleep 5
    mouseoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=02"`
    kbdoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=01"`
...
fi</programlisting>
             </para>

	     <caution>
             <para>Do not set a variable to the contents of a
	       <emphasis>long</emphasis> text file unless you have a very good
	       reason for doing so. Do not set a variable to the contents of a
	       <firstterm>binary</firstterm> file, even as a joke.</para>

	    <example id="stupscr">
	      <title>Stupid script tricks</title>
	      <programlisting>&stupscr;</programlisting>
	    </example>

	     <para>Notice that a <firstterm>buffer overrun</firstterm>
	       does not occur. This is one instance where an interpreted
	       language, such as Bash, provides more protection from
	       programmer mistakes than a compiled language.</para>

	     </caution>


	      <para><anchor id="csvl"></para>
	      <para>Command substitution permits setting a variable to the
		output of a <link linkend="forloopref1">loop</link>. The
		key to this is grabbing the output of an <link
		linkend="echoref">echo</link> command within the
		loop.</para>

	    <example id="csubloop">
	      <title>Generating a variable from a loop</title>
	      <programlisting>&csubloop;</programlisting>
	    </example>



	      <para><anchor id="cstoolset"></para>
	      <sidebar>
              <para>Command substitution makes it possible to extend the
		toolset available to Bash. It is simply a matter
		of writing a program or script that outputs to
		<filename>stdout</filename> (like a well-behaved UNIX
		tool should) and assigning that output to a variable.</para>

		<para>
		<programlisting>#include &lt;stdio.h&gt;

/*  "Hello, world." C program  */		

int main()
{
  printf( "Hello, world." );
  return (0);
}</programlisting>
	      <screen><prompt>bash$ </prompt><userinput>gcc -o hello hello.c</userinput>
	      </screen>
		</para>

		<para>
                <programlisting>#!/bin/bash
# hello.sh		

greeting=`./hello`
echo $greeting</programlisting>
	      <screen><prompt>bash$ </prompt><userinput>sh hello.sh</userinput>
<computeroutput>Hello, world.</computeroutput>
	        </screen>
	        </para>
	        </sidebar>
	      
	      <note>

	      <para><anchor id="csparens">The <command>$(...)</command>
		form has superseded backticks for command
		substitution.</para>

	      <para><programlisting>output=$(sed -n /"$1"/p $file)   # From "grp.sh"	example.
	      
# Setting a variable to the contents of a text file.
File_contents1=$(cat $file1)      
File_contents2=$(&lt;$file2)        # Bash permits this also.</programlisting></para>

              <para>The <command>$(...)</command> form of command substitution
	        treats a double backslash in a different way than
		<command>`...`</command>.</para>

              <para>		
	      <screen><prompt>bash$ </prompt><userinput>echo `echo \\`</userinput>
<computeroutput></computeroutput>

<prompt>bash$ </prompt><userinput>echo $(echo \\)</userinput>
<computeroutput>\</computeroutput>
	      </screen>
              </para>		

	      <para><anchor id="csnest"></para>
              <para>The <command>$(...)</command> form of command
                substitution permits nesting.
		  <footnote>
		    <para>
		    In fact, nesting with backticks is also possible,
		    but only by escaping the inner backticks, as John
		    Default points out.
		      <programlisting>word_count=` wc -w \`ls -l | awk '{print $9}'\` `</programlisting>
		    </para>
		  </footnote>
		
		</para>

              <para><programlisting>word_count=$( wc -w $(ls -l | awk '{print $9}') )</programlisting>
              </para>

              <para>Or, for something a bit more elaborate . . .</para>

      <example id="agram2">
	<title>Finding anagrams</title>
	<programlisting>&agram2;</programlisting>
      </example>


              </note>


     <para>Examples of command substitution in shell scripts:
       <orderedlist>
         <listitem><para><xref linkend="bingrep"></para></listitem>
	 <listitem><para><xref linkend="casecmd"></para></listitem>
	 <listitem><para><xref linkend="seedingrandom"></para></listitem>
	 <listitem><para><xref linkend="ex57"></para></listitem>
         <listitem><para><xref linkend="lowercase"></para></listitem>
	 <listitem><para><xref linkend="grp"></para></listitem>
	 <listitem><para><xref linkend="ex53"></para></listitem>
         <listitem><para><xref linkend="ex24"></para></listitem>
	 <listitem><para><xref linkend="symlinks"></para></listitem>
	 <listitem><para><xref linkend="stripc"></para></listitem>
	 <listitem><para><xref linkend="redir4"></para></listitem>
	 <listitem><para><xref linkend="tree"></para></listitem>
	 <listitem><para><xref linkend="pidid"></para></listitem>
	 <listitem><para><xref linkend="monthlypmt"></para></listitem>
	 <listitem><para><xref linkend="base"></para></listitem>
	 <listitem><para><xref linkend="altbc"></para></listitem>
       </orderedlist>
     </para>  

  </chapter> <!-- Command Substitution -->



  <chapter id="arithexp">
    <title>Arithmetic Expansion</title>


      <para><anchor id="arithexpref">Arithmetic expansion provides a
	powerful tool for performing (integer) arithmetic
	operations in scripts. Translating a string into a
	numerical expression is relatively straightforward using
	<firstterm>backticks</firstterm>, <firstterm>double
	parentheses</firstterm>, or <firstterm>let</firstterm>.</para>

      <variablelist id="arithexpvar">
        <title><anchor id="arithexpvar1">Variations</title>

	<varlistentry>
	  <term>Arithmetic expansion with <link linkend="backquotesref">backticks</link> (often used in
	  conjunction with <link linkend="exprref">expr</link>)</term> <indexterm>
	    <primary>arithmetic</primary> <secondary>expansion</secondary>
	  </indexterm> <indexterm>
	    <primary>arithmetic</primary> <secondary>expansion</secondary>
	  </indexterm> <listitem>
	    <para><programlisting>z=`expr $z + 3`          # The 'expr' command performs the expansion.</programlisting></para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term>Arithmetic expansion with <link linkend="dblparens">double
	  parentheses</link></term>
	  <indexterm><primary>double</primary>
	  <secondary>parentheses</secondary></indexterm>
	  <term>and using <link linkend="letref">let</link></term>
	  <indexterm><primary>let</primary>
	  <secondary>let</secondary></indexterm>


	  <listitem>

	   <para>The use of <firstterm>backticks</firstterm>
	      (<firstterm>backquotes</firstterm>) in arithmetic
	      expansion has been superseded by <firstterm>double
	      parentheses</firstterm> --
	      <userinput>((...))</userinput> and
	      <userinput>$((...))</userinput> -- and also by the very
	      convenient <link linkend="letref">let</link> construction.</para>

	    <para>
	      <programlisting>z=$(($z+3))
z=$((z+3))                                  #  Also correct.
                                            #  Within double parentheses,
                                            #+ parameter dereferencing
                                            #+ is optional.

# $((EXPRESSION)) is arithmetic expansion.  #  Not to be confused with
                                            #+ command substitution.



# You may also use operations within double parentheses without assignment.

  n=0
  echo "n = $n"                             # n = 0

  (( n += 1 ))                              # Increment.
# (( $n += 1 )) is incorrect!
  echo "n = $n"                             # n = 1


let z=z+3
let "z += 3"  #  Quotes permit the use of spaces in variable assignment.
              #  The 'let' operator actually performs arithmetic evaluation,
              #+ rather than expansion.</programlisting>
	    </para>

     <para>Examples of arithmetic expansion in scripts:
       <orderedlist>
         <listitem><para><xref linkend="ex45"></para></listitem>
         <listitem><para><xref linkend="ex25"></para></listitem>
         <listitem><para><xref linkend="ex66"></para></listitem>
	 <listitem><para><xref linkend="bubble"></para></listitem>
	 <listitem><para><xref linkend="tree"></para></listitem>
       </orderedlist>
     </para>  

	  </listitem>
	</varlistentry>

      </variablelist>

  </chapter> <!-- Arithmetic Expansion -->




  <chapter id="Recess-Time">
    <title>Recess Time</title>

            <para><emphasis>
	  This bizarre little intermission gives the reader a chance to
	  relax and maybe laugh a bit.
	    </emphasis></para>

      <blockquote>
	<literallayout>  

	  Fellow Linux user, greetings! You are reading something which
	  will bring you luck and good fortune. Just e-mail a copy of
	  this document to 10 of your friends. Before making the copies,
	  send a 100-line Bash script to the first person on the list
	  at the bottom of this letter. Then delete their name and add
	  yours to the bottom of the list.

	  Don't break the chain! Make the copies within 48 hours.
	  Wilfred P. of Brooklyn failed to send out his ten copies and
	  woke the next morning to find his job description changed
	  to "COBOL programmer." Howard L. of Newport News sent
	  out his ten copies and within a month had enough hardware
	  to build a 100-node Beowulf cluster dedicated to playing
	  <emphasis>Tuxracer</emphasis>. Amelia V. of Chicago laughed at this letter
	  and broke the chain. Shortly thereafter, a fire broke out
	  in her terminal and she now spends her days writing
	  documentation for MS Windows.

	  Don't break the chain!  Send out your ten copies today!

	</literallayout>  
      </blockquote>


	    <para><emphasis>Courtesy 'NIX "fortune cookies", with some
	  alterations and many apologies</emphasis></para>
      
  </chapter> <!-- Recess Time -->


  </part> <!-- Part 3 (Beyond the Basics) -->


  <part label="Part 4" id="part4">
    <title>Commands</title>


  <partintro>  

    <para><anchor id="part4A"></para>
    <para>Mastering the commands on your Linux machine is an indispensable
      prelude to writing effective shell scripts.</para>
      
    <para>This section covers the following commands:</para>


            <itemizedlist id="Commandlist">

               <listitem><para><link linkend="dotref">.</link>
	         (See also <link linkend="sourceref">source</link>)</para></listitem>
               <listitem><para><link linkend="acref">ac</link></para></listitem>
               <listitem><para><link linkend="useraddref">adduser</link></para></listitem>
               <listitem><para><link linkend="agettyref">agetty</link></para></listitem>
               <listitem><para><link linkend="agrepref">agrep</link></para></listitem>
               <listitem><para><link linkend="arref">ar</link></para></listitem>
               <listitem><para><link linkend="archref">arch</link></para></listitem>
               <listitem><para><link linkend="atref">at</link></para></listitem>
               <listitem><para><link linkend="autoloadref">autoload</link></para></listitem>
               <listitem><para><link linkend="awkref">awk</link>
		 (See also <link linkend="awkmath">Using
		 <command>awk</command> for
		 math operations</link>)</para></listitem>
               <listitem><para><link linkend="badblocksref">badblocks</link></para></listitem>
               <listitem><para><link linkend="bannerref">banner</link></para></listitem>
               <listitem><para><link linkend="basenameref">basename</link></para></listitem>
               <listitem><para><link linkend="batchref">batch</link></para></listitem>
               <listitem><para><link linkend="bcref">bc</link></para></listitem>
               <listitem><para><link linkend="bgref">bg</link></para></listitem>
               <listitem><para><link linkend="bindref">bind</link></para></listitem>
               <listitem><para><link linkend="bisonref">bison</link></para></listitem>
               <listitem><para><link linkend="bltref">builtin</link></para></listitem>
               <listitem><para><link linkend="bzgrepref">bzgrep</link></para></listitem>
               <listitem><para><link linkend="bzipref">bzip2</link></para></listitem>
               <listitem><para><link linkend="calref">cal</link></para></listitem>
               <listitem><para><link linkend="callerref">caller</link></para></listitem>
               <listitem><para><link linkend="catref">cat</link></para></listitem>
               <listitem><para><link linkend="cdref">cd</link></para></listitem>
               <listitem><para><link linkend="chattrref">chattr</link></para></listitem>
               <listitem><para><link linkend="chfnref">chfn</link></para></listitem>
               <listitem><para><link linkend="chgrpref">chgrp</link></para></listitem>
               <listitem><para><link linkend="chkconfigref">chkconfig</link></para></listitem>
               <listitem><para><link linkend="chmodref">chmod</link></para></listitem>
               <listitem><para><link linkend="chownref">chown</link></para></listitem>
               <listitem><para><link linkend="chrootref">chroot</link></para></listitem>
               <listitem><para><link linkend="cksumref">cksum</link></para></listitem>
               <listitem><para><link linkend="clearref">clear</link></para></listitem>
               <listitem><para><link linkend="clockref">clock</link></para></listitem>
               <listitem><para><link linkend="cmpref">cmp</link></para></listitem>
               <listitem><para><link linkend="colref">col</link></para></listitem>
               <listitem><para><link linkend="colrmref">colrm</link></para></listitem>
               <listitem><para><link linkend="columnref">column</link></para></listitem>
               <listitem><para><link linkend="commref">comm</link></para></listitem>
               <listitem><para><link linkend="commandref">command</link></para></listitem>
               <listitem><para><link linkend="compressref">compress</link></para></listitem>
               <listitem><para><link linkend="cpref">cp</link></para></listitem>
               <listitem><para><link linkend="cpioref">cpio</link></para></listitem>
               <listitem><para><link linkend="cronref">cron</link></para></listitem>
               <listitem><para><link linkend="cryptref">crypt</link></para></listitem>
               <listitem><para><link linkend="csplitref">csplit</link></para></listitem>
               <listitem><para><link linkend="curef">cu</link></para></listitem>
               <listitem><para><link linkend="cutref">cut</link></para></listitem>
               <listitem><para><link linkend="dateref">date</link></para></listitem>
               <listitem><para><link linkend="dcref">dc</link></para></listitem>
               <listitem><para><link linkend="ddref">dd</link></para></listitem>
               <listitem><para><link linkend="debugfsref">debugfs</link></para></listitem>
               <listitem><para><link linkend="declareref">declare</link></para></listitem>
               <listitem><para><link linkend="depmodref">depmod</link></para></listitem>
               <listitem><para><link linkend="dfref">df</link></para></listitem>
               <listitem><para><link linkend="dialogref">dialog</link></para></listitem>
               <listitem><para><link linkend="diffref">diff</link></para></listitem>
               <listitem><para><link linkend="diff3ref">diff3</link></para></listitem>
               <listitem><para><link linkend="diffstatref">diffstat</link></para></listitem>
               <listitem><para><link linkend="digref">dig</link></para></listitem>
               <listitem><para><link linkend="dirnameref">dirname</link></para></listitem>
               <listitem><para><link linkend="dirsd">dirs</link></para></listitem>
               <listitem><para><link linkend="disownref">disown</link></para></listitem>
               <listitem><para><link linkend="dmesgref">dmesg</link></para></listitem>
               <listitem><para><link linkend="doexecref">doexec</link></para></listitem>
               <listitem><para><link linkend="dos2unixref">dos2unix</link></para></listitem>
               <listitem><para><link linkend="duref">du</link></para></listitem>
               <listitem><para><link linkend="dumpref">dump</link></para></listitem>
               <listitem><para><link linkend="dumpe2fsref">dumpe2fs</link></para></listitem>
               <listitem><para><link linkend="e2fsckref">e2fsck</link></para></listitem>
               <listitem><para><link linkend="echoref">echo</link></para></listitem>
               <listitem><para><link linkend="egrepref">egrep</link></para></listitem>
               <listitem><para><link linkend="enableref">enable</link></para></listitem>
               <listitem><para><link linkend="enscriptref">enscript</link></para></listitem>
               <listitem><para><link linkend="envvref">env</link></para></listitem>
               <listitem><para><link linkend="eqnref">eqn</link></para></listitem>
               <listitem><para><link linkend="evalref">eval</link></para></listitem>
               <listitem><para><link linkend="execref">exec</link></para></listitem>
               <listitem><para><link linkend="exitref">exit</link>
		 (Related topic: <link linkend="exitstatusref">exit
		 status</link>)</para></listitem>
               <listitem><para><link linkend="expandref">expand</link></para></listitem>
               <listitem><para><link linkend="exportref">export</link></para></listitem>
               <listitem><para><link linkend="exprref">expr</link></para></listitem>
               <listitem><para><link linkend="factorref">factor</link></para></listitem>
               <listitem><para><link linkend="falseref">false</link></para></listitem>
               <listitem><para><link linkend="fdformatref">fdformat</link></para></listitem>
               <listitem><para><link linkend="fdiskref">fdisk</link></para></listitem>
               <listitem><para><link linkend="fgref">fg</link></para></listitem>
               <listitem><para><link linkend="fgrepref">fgrep</link></para></listitem>
               <listitem><para><link linkend="fileref">file</link></para></listitem>
               <listitem><para><link linkend="findref">find</link></para></listitem>
               <listitem><para><link linkend="fingerref">finger</link></para></listitem>
               <listitem><para><link linkend="flexref">flex</link></para></listitem>
               <listitem><para><link linkend="flockref">flock</link></para></listitem>
               <listitem><para><link linkend="fmtref">fmt</link></para></listitem>
               <listitem><para><link linkend="foldref">fold</link></para></listitem>
               <listitem><para><link linkend="freeref">free</link></para></listitem>
               <listitem><para><link linkend="fsckref">fsck</link></para></listitem>
               <listitem><para><link linkend="ftpref">ftp</link></para></listitem>
               <listitem><para><link linkend="fuserref">fuser</link></para></listitem>
               <listitem><para><link linkend="getopty">getopt</link></para></listitem>
               <listitem><para><link linkend="getoptsx">getopts</link></para></listitem>
               <listitem><para><link linkend="gettextref">gettext</link></para></listitem>
               <listitem><para><link linkend="gettyref">getty</link></para></listitem>
               <listitem><para><link linkend="gnomemountref">gnome-mount</link></para></listitem>
               <listitem><para><link linkend="grepref">grep</link></para></listitem>
               <listitem><para><link linkend="groffref">groff</link></para></listitem>
               <listitem><para><link linkend="groupmodref">groupmod</link></para></listitem>
               <listitem><para><link linkend="groupscmdref">groups</link>
		 (Related topic: the <link linkend="groupsref">$GROUPS</link>
		 variable)</para></listitem>
               <listitem><para><link linkend="gsref">gs</link></para></listitem>
               <listitem><para><link linkend="gzipref">gzip</link></para></listitem>
               <listitem><para><link linkend="haltref">halt</link></para></listitem>
               <listitem><para><link linkend="hashcmdref">hash</link></para></listitem>
               <listitem><para><link linkend="hdparmref">hdparm</link></para></listitem>
               <listitem><para><link linkend="headref">head</link></para></listitem>
               <listitem><para><link linkend="helpref">help</link></para></listitem>
               <listitem><para><link linkend="hexdumpref">hexdump</link></para></listitem>
               <listitem><para><link linkend="hostref">host</link></para></listitem>
               <listitem><para><link linkend="hostidref">hostid</link></para></listitem>
               <listitem><para><link linkend="hnameref">hostname</link>
		 (Related topic: the <link linkend="hostnameref">$HOSTNAME</link>
		 variable)</para></listitem>
               <listitem><para><link linkend="hwclockref">hwclock</link></para></listitem>
               <listitem><para><link linkend="iconvref">iconv</link></para></listitem>
               <listitem><para><link linkend="idref">id</link>
		 (Related topic: the <link linkend="uidref">$UID</link>
	       variable)</para></listitem>
               <listitem><para><link linkend="ifconfigref">ifconfig</link></para></listitem>
               <listitem><para><link linkend="inforef">info</link></para></listitem>
               <listitem><para><link linkend="infocmpref">infocmp</link></para></listitem>
               <listitem><para><link linkend="initref">init</link></para></listitem>
               <listitem><para><link linkend="insmodref">insmod</link></para></listitem>
               <listitem><para><link linkend="installref">install</link></para></listitem>
               <listitem><para><link linkend="ipref">ip</link></para></listitem>
               <listitem><para><link linkend="ipcalcref">ipcalc</link></para></listitem>
               <listitem><para><link linkend="iwconfigref">iwconfig</link></para></listitem>
               <listitem><para><link linkend="jobsref">jobs</link></para></listitem>
               <listitem><para><link linkend="joinref">join</link></para></listitem>
               <listitem><para><link linkend="jotref">jot</link></para></listitem>
               <listitem><para><link linkend="killref">kill</link></para></listitem>
               <listitem><para><link linkend="killallref">killall</link></para></listitem>
               <listitem><para><link linkend="lastref">last</link></para></listitem>
               <listitem><para><link linkend="lastcommref">lastcomm</link></para></listitem>
               <listitem><para><link linkend="lastlogref">lastlog</link></para></listitem>
               <listitem><para><link linkend="lddref">ldd</link></para></listitem>
               <listitem><para><link linkend="lessref">less</link></para></listitem>
               <listitem><para><link linkend="letref">let</link></para></listitem>
               <listitem><para><link linkend="lexref">lex</link></para></listitem>
               <listitem><para><link linkend="lidref">lid</link></para></listitem>
               <listitem><para><link linkend="linkref">ln</link></para></listitem>
               <listitem><para><link linkend="locateref">locate</link></para></listitem>
               <listitem><para><link linkend="lockfileref">lockfile</link></para></listitem>
               <listitem><para><link linkend="loggerref">logger</link></para></listitem>
               <listitem><para><link linkend="lognameref">logname</link></para></listitem>
               <listitem><para><link linkend="logoutref">logout</link></para></listitem>
               <listitem><para><link linkend="logrotateref">logrotate</link></para></listitem>
               <listitem><para><link linkend="lookref">look</link></para></listitem>
               <listitem><para><link linkend="losetupref">losetup</link></para></listitem>
               <listitem><para><link linkend="lpref">lp</link></para></listitem>
               <listitem><para><link linkend="lsref">ls</link></para></listitem>
               <listitem><para><link linkend="lsdevref">lsdev</link></para></listitem>
               <listitem><para><link linkend="lsmodref">lsmod</link></para></listitem>
               <listitem><para><link linkend="lsofref">lsof</link></para></listitem>
               <listitem><para><link linkend="lspciref">lspci</link></para></listitem>
               <listitem><para><link linkend="lsusbref">lsusb</link></para></listitem>
               <listitem><para><link linkend="ltraceref">ltrace</link></para></listitem>
               <listitem><para><link linkend="lynxref">lynx</link></para></listitem>
               <listitem><para><link linkend="lzmaref">lzcat</link></para></listitem>
               <listitem><para><link linkend="lzmaref">lzma</link></para></listitem>
               <listitem><para><link linkend="m4ref">m4</link></para></listitem>
               <listitem><para><link linkend="commmail1">mail</link></para></listitem>
               <listitem><para><link linkend="mailstatsref">mailstats</link></para></listitem>
               <listitem><para><link linkend="mailtoref">mailto</link></para></listitem>
               <listitem><para><link linkend="makeref">make</link></para></listitem>
               <listitem><para><link linkend="MAKEDEVref">MAKEDEV</link></para></listitem>
               <listitem><para><link linkend="manref">man</link></para></listitem>
               <listitem><para><link linkend="mcookieref">mcookie</link></para></listitem>
               <listitem><para><link linkend="md5sumref">md5sum</link></para></listitem>
               <listitem><para><link linkend="mergeref">merge</link></para></listitem>
               <listitem><para><link linkend="mesgref">mesg</link></para></listitem>
               <listitem><para><link linkend="mimencoderef">mimencode</link></para></listitem>
               <listitem><para><link linkend="mkbootdiskref">mkbootdisk</link></para></listitem>
               <listitem><para><link linkend="mkdirref">mkdir</link></para></listitem>
               <listitem><para><link linkend="mke2fsref">mke2fs</link></para></listitem>
               <listitem><para><link linkend="mkfiforef">mkfifo</link></para></listitem>
               <listitem><para><link linkend="mkisofsref">mkisofs</link></para></listitem>
               <listitem><para><link linkend="mknodref">mknod</link></para></listitem>
               <listitem><para><link linkend="mkswapref">mkswap</link></para></listitem>
               <listitem><para><link linkend="mktempref">mktemp</link></para></listitem>
               <listitem><para><link linkend="mmencoderef">mmencode</link></para></listitem>
               <listitem><para><link linkend="modinforef">modinfo</link></para></listitem>
               <listitem><para><link linkend="modproberef">modprobe</link></para></listitem>
               <listitem><para><link linkend="moreref">more</link></para></listitem>
               <listitem><para><link linkend="mountref">mount</link></para></listitem>
               <listitem><para><link linkend="msgfmtref">msgfmt</link></para></listitem>
               <listitem><para><link linkend="mvref">mv</link></para></listitem>
               <listitem><para><link linkend="ncref">nc</link></para></listitem>
               <listitem><para><link linkend="netconfigref">netconfig</link></para></listitem>
               <listitem><para><link linkend="netstatref">netstat</link></para></listitem>
               <listitem><para><link linkend="newgrpref">newgrp</link></para></listitem>
               <listitem><para><link linkend="niceref">nice</link></para></listitem>
               <listitem><para><link linkend="nlref">nl</link></para></listitem>
               <listitem><para><link linkend="nmref">nm</link></para></listitem>
               <listitem><para><link linkend="nmapref">nmap</link></para></listitem>
               <listitem><para><link linkend="nohupref">nohup</link></para></listitem>
               <listitem><para><link linkend="nslookupref">nslookup</link></para></listitem>
               <listitem><para><link linkend="objdumpref">objdump</link></para></listitem>
               <listitem><para><link linkend="odref">od</link></para></listitem>
               <listitem><para><link linkend="passwdref">passwd</link></para></listitem>
               <listitem><para><link linkend="pasteref">paste</link></para></listitem>
               <listitem><para><link linkend="patchref">patch</link>
		 (Related topic: <link linkend="diffref">diff</link>)</para></listitem>
               <listitem><para><link linkend="pathchkref">pathchk</link></para></listitem>
               <listitem><para><link linkend="pgrepref">pgrep</link></para></listitem>
               <listitem><para><link linkend="pidofref">pidof</link></para></listitem>
               <listitem><para><link linkend="pingref">ping</link></para></listitem>
               <listitem><para><link linkend="pkillref">pkill</link></para></listitem>
               <listitem><para><link linkend="dirsd">popd</link></para></listitem>
               <listitem><para><link linkend="prref">pr</link></para></listitem>
               <listitem><para><link linkend="printenvref">printenv</link></para></listitem>
               <listitem><para><link linkend="printfref">printf</link></para></listitem>
               <listitem><para><link linkend="procinforef">procinfo</link></para></listitem>
               <listitem><para><link linkend="ppssref">ps</link></para></listitem>
               <listitem><para><link linkend="pstreeref">pstree</link></para></listitem>
               <listitem><para><link linkend="ptxref">ptx</link></para></listitem>
               <listitem><para><link linkend="dirsd">pushd</link></para></listitem>
               <listitem><para><link linkend="pwd2ref">pwd</link>
		 (Related topic: the <link linkend="pwdref">$PWD</link>
		 variable)</para></listitem>
               <listitem><para><link linkend="quotaref">quota</link></para></listitem>
               <listitem><para><link linkend="rcpref">rcp</link></para></listitem>
               <listitem><para><link linkend="rdevref">rdev</link></para></listitem>
               <listitem><para><link linkend="rdistref">rdist</link></para></listitem>
               <listitem><para><link linkend="readref">read</link></para></listitem>
               <listitem><para><link linkend="readelfref">readelf</link></para></listitem>
               <listitem><para><link linkend="readlinkref">readlink</link></para></listitem>
               <listitem><para><link linkend="readonlyref">readonly</link></para></listitem>
               <listitem><para><link linkend="rebootref">reboot</link></para></listitem>
               <listitem><para><link linkend="recoderef">recode</link></para></listitem>
               <listitem><para><link linkend="nice2ref">renice</link></para></listitem>
               <listitem><para><link linkend="resetref">reset</link></para></listitem>
               <listitem><para><link linkend="resizeref">resize</link></para></listitem>
               <listitem><para><link linkend="restoreref">restore</link></para></listitem>
               <listitem><para><link linkend="revref">rev</link></para></listitem>
               <listitem><para><link linkend="rloginref">rlogin</link></para></listitem>
               <listitem><para><link linkend="rmref">rm</link></para></listitem>
               <listitem><para><link linkend="rmdirref">rmdir</link></para></listitem>
               <listitem><para><link linkend="rmmodref">rmmod</link></para></listitem>
               <listitem><para><link linkend="routeref">route</link></para></listitem>
               <listitem><para><link linkend="rpmref">rpm</link></para></listitem>
               <listitem><para><link linkend="rpm2cpioref">rpm2cpio</link></para></listitem>
               <listitem><para><link linkend="rshref">rsh</link></para></listitem>
               <listitem><para><link linkend="rsyncref">rsync</link></para></listitem>
               <listitem><para><link linkend="runlevelref">runlevel</link></para></listitem>
               <listitem><para><link linkend="runpartsref">run-parts</link></para></listitem>
               <listitem><para><link linkend="rxref">rx</link></para></listitem>
               <listitem><para><link linkend="rzref">rz</link></para></listitem>
               <listitem><para><link linkend="sarref">sar</link></para></listitem>
               <listitem><para><link linkend="scpref">scp</link></para></listitem>
               <listitem><para><link linkend="scriptref">script</link></para></listitem>
               <listitem><para><link linkend="sdiffref">sdiff</link></para></listitem>
               <listitem><para><link linkend="sedref">sed</link></para></listitem>
               <listitem><para><link linkend="seqref">seq</link></para></listitem>
               <listitem><para><link linkend="serviceref">service</link></para></listitem>
               <listitem><para><link linkend="setref">set</link></para></listitem>
               <listitem><para><link linkend="setquotaref">setquota</link></para></listitem>
               <listitem><para><link linkend="setserialref">setserial</link></para></listitem>
               <listitem><para><link linkend="settermref">setterm</link></para></listitem>
               <listitem><para><link linkend="sha1sumref">sha1sum</link></para></listitem>
               <listitem><para><link linkend="sharref">shar</link></para></listitem>
               <listitem><para><link linkend="shoptref">shopt</link></para></listitem>
               <listitem><para><link linkend="shredref">shred</link></para></listitem>
               <listitem><para><link linkend="shutdownref">shutdown</link></para></listitem>
               <listitem><para><link linkend="sizeref">size</link></para></listitem>
               <listitem><para><link linkend="nice2ref">skill</link></para></listitem>
               <listitem><para><link linkend="sleepref">sleep</link></para></listitem>
               <listitem><para><link linkend="slocateref">slocate</link></para></listitem>
               <listitem><para><link linkend="nice2ref">snice</link></para></listitem>
               <listitem><para><link linkend="sortref">sort</link></para></listitem>
               <listitem><para><link linkend="sourceref">source</link></para></listitem>
               <listitem><para><link linkend="soxref">sox</link></para></listitem>
               <listitem><para><link linkend="splitref">split</link></para></listitem>
               <listitem><para><link linkend="sqref">sq</link></para></listitem>
               <listitem><para><link linkend="sshref">ssh</link></para></listitem>
               <listitem><para><link linkend="statref">stat</link></para></listitem>
               <listitem><para><link linkend="straceref">strace</link></para></listitem>
               <listitem><para><link linkend="stringsref">strings</link></para></listitem>
               <listitem><para><link linkend="stripref">strip</link></para></listitem>
               <listitem><para><link linkend="sttyref">stty</link></para></listitem>
               <listitem><para><link linkend="suref">su</link></para></listitem>
               <listitem><para><link linkend="sudoref">sudo</link></para></listitem>
               <listitem><para><link linkend="sumref">sum</link></para></listitem>
               <listitem><para><link linkend="suspendref">suspend</link></para></listitem>
               <listitem><para><link linkend="swaponref">swapoff</link></para></listitem>
               <listitem><para><link linkend="swaponref">swapon</link></para></listitem>
               <listitem><para><link linkend="rxref">sx</link></para></listitem>
               <listitem><para><link linkend="syncref">sync</link></para></listitem>
               <listitem><para><link linkend="rzref">sz</link></para></listitem>
               <listitem><para><link linkend="catref">tac</link></para></listitem>
               <listitem><para><link linkend="tailref">tail</link></para></listitem>
               <listitem><para><link linkend="tarref">tar</link></para></listitem>
               <listitem><para><link linkend="tblref">tbl</link></para></listitem>
               <listitem><para><link linkend="tcpdumpref">tcpdump</link></para></listitem>
               <listitem><para><link linkend="teeref">tee</link></para></listitem>
               <listitem><para><link linkend="telinitref">telinit</link></para></listitem>
               <listitem><para><link linkend="telnetref">telnet</link></para></listitem>
               <listitem><para><link linkend="texref">Tex</link></para></listitem>
               <listitem><para><link linkend="texexecref">texexec</link></para></listitem>
               <listitem><para><link linkend="timref">time</link></para></listitem>
               <listitem><para><link linkend="timesref">times</link></para></listitem>
               <listitem><para><link linkend="tmpwatchref">tmpwatch</link></para></listitem>
               <listitem><para><link linkend="topref">top</link></para></listitem>
               <listitem><para><link linkend="touchref">touch</link></para></listitem>
               <listitem><para><link linkend="tputref">tput</link></para></listitem>
               <listitem><para><link linkend="trref">tr</link></para></listitem>
               <listitem><para><link linkend="tracerouteref">traceroute</link></para></listitem>
               <listitem><para><link linkend="trueref">true</link></para></listitem>
               <listitem><para><link linkend="tsetref">tset</link></para></listitem>
               <listitem><para><link linkend="tsortref">tsort</link></para></listitem>
               <listitem><para><link linkend="ttyref">tty</link></para></listitem>
               <listitem><para><link linkend="tune2fsref">tune2fs</link></para></listitem>
               <listitem><para><link linkend="typeref">type</link></para></listitem>
               <listitem><para><link linkend="declareref">typeset</link></para></listitem>
               <listitem><para><link linkend="ulimitref">ulimit</link></para></listitem>
               <listitem><para><link linkend="umaskref">umask</link></para></listitem>
               <listitem><para><link linkend="umountref">umount</link></para></listitem>
               <listitem><para><link linkend="unameref">uname</link></para></listitem>
               <listitem><para><link linkend="unarcref">unarc</link></para></listitem>
               <listitem><para><link linkend="unarcref">unarj</link></para></listitem>
               <listitem><para><link linkend="uncompressref">uncompress</link></para></listitem>
               <listitem><para><link linkend="expandref">unexpand</link></para></listitem>
               <listitem><para><link linkend="uniqref">uniq</link></para></listitem>
               <listitem><para><link linkend="unitsref">units</link></para></listitem>
               <listitem><para><link linkend="lzmaref">unlzma</link></para></listitem>
               <listitem><para><link linkend="unarcref">unrar</link></para></listitem>
               <listitem><para><link linkend="unsetref">unset</link></para></listitem>
               <listitem><para><link linkend="sqref">unsq</link></para></listitem>
               <listitem><para><link linkend="zipref">unzip</link></para></listitem>
               <listitem><para><link linkend="uptimeref">uptime</link></para></listitem>
               <listitem><para><link linkend="lsusbref">usbmodules</link></para></listitem>
               <listitem><para><link linkend="useraddref">useradd</link></para></listitem>
               <listitem><para><link linkend="useraddref">userdel</link></para></listitem>
               <listitem><para><link linkend="usermodref">usermod</link></para></listitem>
               <listitem><para><link linkend="usersref">users</link></para></listitem>
               <listitem><para><link linkend="usleepref">usleep</link></para></listitem>
               <listitem><para><link linkend="uucpref">uucp</link></para></listitem>
               <listitem><para><link linkend="uudecoderef">uudecode</link></para></listitem>
               <listitem><para><link linkend="uuencoderef">uuencode</link></para></listitem>
               <listitem><para><link linkend="uuxref">uux</link></para></listitem>
               <listitem><para><link linkend="vacationref">vacation</link></para></listitem>
               <listitem><para><link linkend="vdirref">vdir</link></para></listitem>
               <listitem><para><link linkend="vmstatref">vmstat</link></para></listitem>
               <listitem><para><link linkend="vrfyref">vrfy</link></para></listitem>
               <listitem><para><link linkend="wref">w</link></para></listitem>
               <listitem><para><link linkend="waitref">wait</link></para></listitem>
               <listitem><para><link linkend="wallref">wall</link></para></listitem>
               <listitem><para><link linkend="watchref">watch</link></para></listitem>
               <listitem><para><link linkend="wcref">wc</link></para></listitem>
               <listitem><para><link linkend="wgetref">wget</link></para></listitem>
               <listitem><para><link linkend="whatisref">whatis</link></para></listitem>
               <listitem><para><link linkend="whereisref">whereis</link></para></listitem>
               <listitem><para><link linkend="whichref">which</link></para></listitem>
               <listitem><para><link linkend="whoref">who</link></para></listitem>
               <listitem><para><link linkend="whoamiref">whoami</link></para></listitem>
               <listitem><para><link linkend="whoisref">whois</link></para></listitem>
               <listitem><para><link linkend="writeref">write</link></para></listitem>
               <listitem><para><link linkend="xargsref">xargs</link></para></listitem>
               <listitem><para><link linkend="yaccref">yacc</link></para></listitem>
               <listitem><para><link linkend="yesref">yes</link></para></listitem>
               <listitem><para><link linkend="zcatref">zcat</link></para></listitem>
               <listitem><para><link linkend="zdiffref">zdiff</link></para></listitem>
               <listitem><para><link linkend="zdumpref">zdump</link></para></listitem>
               <listitem><para><link linkend="zegrepref">zegrep</link></para></listitem>
               <listitem><para><link linkend="zegrepref">zfgrep</link></para></listitem>
               <listitem><para><link linkend="zegrepref">zgrep</link></para></listitem>
               <listitem><para><link linkend="zipref">zip</link></para></listitem>

	    </itemizedlist>


  </partintro>

  <chapter id="internal">
    <title>Internal Commands and Builtins</title>


      <indexterm>
	<primary>builtin</primary>
      </indexterm>


      <para><anchor id="builtinref">A <firstterm>builtin</firstterm>
	is a <command>command</command> contained within the Bash tool
	set, literally <firstterm>built in</firstterm>. This is either
	for performance reasons -- builtins execute faster than external
	commands, which usually require <firstterm>forking off</firstterm>
	a separate process -- or because a particular builtin needs
	direct access to the shell internals.</para>

      <para><anchor id="forkref"></para>

		 <sidebar>

		 <para><anchor id="parentref">When a command or
		   the shell itself initiates (or
		   <firstterm>spawns</firstterm>) a new
		   subprocess to carry out a task, this is called
		   <firstterm>forking</firstterm>. This new process
		   is the <firstterm>child</firstterm>, and the process
		   that <firstterm>forked</firstterm> it off is the
		   <firstterm>parent</firstterm>. While the <firstterm>child
		   process</firstterm> is doing its work, the
		   <firstterm>parent process</firstterm> is still
		   executing.</para>

		 <para>Note that while a <firstterm>parent
		   process</firstterm> gets the <firstterm>process
		   ID</firstterm> of the <firstterm>child
		   process</firstterm>, and can thus pass arguments to it,
		   <emphasis>the reverse is not true</emphasis>. <link
		   linkend="parchildprobref">This can create problems
		   that are subtle and hard to track down.</link></para>

	    <example id="spawnscr">
	      <title>A script that forks off multiple instances of itself</title>
	      <programlisting>&spawnscr;</programlisting>
	    </example>


		 <para><anchor id="bltinfrk"></para>
		 <para>Generally, a Bash <firstterm>builtin</firstterm>
		   does not fork a subprocess when it executes within
		   a script. An external system command or filter in
		   a script usually <emphasis>will</emphasis> fork a
		   subprocess.</para>

		   </sidebar>


      <para>A builtin may be a synonym to a system command of the same
	name, but Bash reimplements it internally.  For example,
	the Bash <command>echo</command> command is not the same as
	<filename>/bin/echo</filename>, although their behavior is
	almost identical.
	   <programlisting>#!/bin/bash

echo "This line uses the \"echo\" builtin."
/bin/echo "This line uses the /bin/echo system command."</programlisting>
	</para>

      <para><anchor id="keywordref">A <firstterm>keyword</firstterm>
	is a <firstterm>reserved</firstterm> word, token or
	operator. Keywords have a special meaning to the shell,
	and indeed are the building blocks of the shell's
	syntax. As examples, <firstterm>for</firstterm>,
	<firstterm>while</firstterm>, <firstterm>do</firstterm>,
	and <firstterm>!</firstterm> are keywords. Similar to a <link
	linkend="builtinref">builtin</link>, a keyword is hard-coded into
	Bash, but unlike a <firstterm>builtin</firstterm>, a keyword is
	not in itself a command, but <emphasis>a subunit of a command
	construct</emphasis>.

	   <footnote><para>An exception to this is the <link
	     linkend="timref">time</link> command, listed in the
	     official Bash documentation as a keyword (<quote>reserved
	     word</quote>).</para></footnote>

	</para>


      <variablelist id="intio">
        <title><anchor id="intio1">I/O</title>

	<varlistentry>
	  <term><anchor id="echoref"><command>echo</command></term>
	  <indexterm>
	    <primary>echo</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>echo</secondary>
	  </indexterm>
	  <listitem>
	    <para>prints (to <filename>stdout</filename>) an expression
	      or variable (see <xref linkend="ex9">). 
	      <programlisting>echo Hello
echo $a</programlisting></para>
	    
	    <para>An <command>echo</command> requires the
	      <option>-e</option> option to print escaped characters. See
	      <xref linkend="escaped">.</para>

	    <para>Normally, each <command>echo</command> command prints
	      a terminal newline, but the <option>-n</option> option
	      suppresses this.</para>

	    <para><anchor id="echogrepref"></para>
	    <note>
	    <para>An <command>echo</command> can be used to feed a
	      sequence of commands down a pipe.</para>
	    <para><programlisting>if echo "$VAR" | grep -q txt   # if [[ $VAR = *txt* ]]
then
  echo "$VAR contains the substring sequence \"txt\""
fi</programlisting></para>  
	    </note>  

	    <para><anchor id="echocs"></para>
	    <note><para>An <command>echo</command>, in combination with
	      <link linkend="commandsubref">command substitution</link>
	      can set a variable.</para> <para><userinput>a=`echo
	      "HELLO" | tr A-Z a-z`</userinput></para>
	      <para>See also <xref linkend="lowercase">, <xref
	      linkend="ex57">, <xref linkend="monthlypmt">, and <xref
	      linkend="base">.</para></note>


	    <para>Be aware that <command>echo `command`</command>
	      deletes any linefeeds that the output
	      of <replaceable>command</replaceable>
	      generates.</para>
	      
	    <para>The <link linkend="ifsref">$IFS</link> (internal field
	      separator) variable normally contains
	      <token>\n</token> (linefeed) as one of its set of
	      <link linkend="whitespaceref">whitespace</link>
	      characters. Bash therefore splits the output of
	      <replaceable>command</replaceable> at linefeeds
	      into arguments to <command>echo</command>.  Then
	      <command>echo</command> outputs these arguments,
	      separated by spaces.</para>
	      
	    <para>
	      <screen>
<prompt>bash$ </prompt><userinput>ls -l /usr/share/apps/kjezz/sounds</userinput>
<computeroutput>-rw-r--r--    1 root     root         1407 Nov  7  2000 reflect.au
 -rw-r--r--    1 root     root          362 Nov  7  2000 seconds.au</computeroutput>




<prompt>bash$ </prompt><userinput>echo `ls -l /usr/share/apps/kjezz/sounds`</userinput>
<computeroutput>total 40 -rw-r--r-- 1 root root 716 Nov 7 2000 reflect.au -rw-r--r-- 1 root root ...</computeroutput>
	      </screen>
	    </para>

            <para>
              So, how can we embed a linefeed within an
	      <link linkend="echoref">echoed</link> character string?

	     <programlisting># Embedding a linefeed?
echo "Why doesn't this string \n split on two lines?"
# Doesn't split.

# Let's try something else.

echo
	     
echo $"A line of text containing
a linefeed."
# Prints as two distinct lines (embedded linefeed).
# But, is the "$" variable prefix really necessary?

echo

echo "This string splits
on two lines."
# No, the "$" is not needed.

echo
echo "---------------"
echo

echo -n $"Another line of text containing
a linefeed."
# Prints as two distinct lines (embedded linefeed).
# Even the -n option fails to suppress the linefeed here.

echo
echo
echo "---------------"
echo
echo

# However, the following doesn't work as expected.
# Why not? Hint: Assignment to a variable.
string1=$"Yet another line of text containing
a linefeed (maybe)."

echo $string1
# Yet another line of text containing a linefeed (maybe).
#                                    ^
# Linefeed becomes a space.

# Thanks, Steve Parker, for pointing this out.</programlisting>
            </para>

	    <para><anchor id="binecho"></para>
	    <note>
	    <para>This command is a shell builtin, and not the same as
	      <filename>/bin/echo</filename>, although its behavior is
	      similar.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>type -a echo</userinput>
<computeroutput>echo is a shell builtin
 echo is /bin/echo</computeroutput>
	      </screen>
	  </para>
	    </note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="printfref"><command>printf</command></term>
	  <indexterm>
	    <primary>printf</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>printf</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>printf</command>, formatted print, command is an
	      enhanced <command>echo</command>. It is a limited variant
	      of the <firstterm>C</firstterm> language
	      <function>printf()</function> library function, and its
	      syntax is somewhat different.</para>
	    <cmdsynopsis>
	      <command>printf</command>
	      <arg choice=plain rep=repeat><replaceable>format-string</replaceable></arg>
	      <arg choice=plain rep=repeat><replaceable>parameter</replaceable></arg>
	    </cmdsynopsis>

	    <para>This is the Bash <firstterm>builtin</firstterm> version
	      of the <filename>/bin/printf</filename> or
	      <filename>/usr/bin/printf</filename> command. See the
	      <command>printf</command> <link
	      linkend="manref">manpage</link> (of the system command)
	      for in-depth coverage.</para>

	    <caution><para>Older versions of Bash may not support
	      <command>printf</command>.</para></caution>

	    <example id="ex47">
	      <title><firstterm>printf</firstterm> in action</title>
	      <programlisting>&ex47;</programlisting>
	    </example>

	    <para>Formatting error messages is a useful application of
	      <command>printf</command></para>

            <para>
	        <programlisting>E_BADDIR=85

var=nonexistent_directory

error()
{
  printf "$@" >&2
  # Formats positional params passed, and sends them to stderr.
  echo
  exit $E_BADDIR
}

cd $var || error $"Can't cd to %s." "$var"

# Thanks, S.C.</programlisting>
            </para>

            <para>See also <xref linkend="progressbar">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="readref"><command>read</command></term> <indexterm>
	    <primary>read</primary>
	  </indexterm> <indexterm>
	    <primary>command</primary> <secondary>read</secondary>
	  </indexterm> <listitem><para><quote>Reads</quote> the value
	    of a variable from <filename>stdin</filename>, that
	    is, interactively fetches input from the keyboard. The
	    <option>-a</option> option lets <command>read</command>
	    get array variables (see <xref linkend="ex67">).</para>

	    <example id="ex36">
	      <title>Variable assignment, using <firstterm>read</firstterm></title>
	      <programlisting>&ex36;</programlisting>
	    </example>


	    <para>A <command>read</command> without an associated variable
	      assigns its input to the dedicated variable <link
	      linkend="replyref">$REPLY</link>.</para>

	    <example id="readnovar">
	      <title>What happens when <firstterm>read</firstterm> has no
	        variable</title>
	      <programlisting>&readnovar;</programlisting>
	    </example>


	    <para>Normally, inputting a <userinput>\</userinput>
	      suppresses a newline during input to
	      a <command>read</command>. The <option>-r</option>
	      option causes an inputted <userinput>\</userinput> to be
	      interpreted literally.</para>

	    <example id="readr">
	      <title>Multi-line input to <firstterm>read</firstterm></title>
	      <programlisting>&readr;</programlisting>
	    </example>

	    
	    <para><anchor id="readoptions"></para>
	    <para>The <command>read</command> command has some interesting
	      options that permit echoing a prompt and even reading keystrokes
	      without hitting <keycap>ENTER</keycap>.</para>

	    <para><programlisting># Read a keypress without hitting ENTER.

read -s -n1 -p "Hit a key " keypress
echo; echo "Keypress was "\"$keypress\""."

# -s option means do not echo input.
# -n N option means accept only N characters of input.
# -p option means echo the following prompt before reading input.

# Using these options is tricky, since they need to be in the correct order.</programlisting></para>


	    <para><anchor id="readarrow"></para>
	    <para>The <option>-n</option> option to <command>read</command>
	      also allows detection of the <keycap>arrow keys</keycap>
	      and certain of the other unusual keys.</para>

	    <example id="arrowdetect">
	      <title>Detecting the arrow keys</title>
	      <programlisting>&arrowdetect;</programlisting>
	    </example>

	    <note><para>The <option>-n</option> option to <command>read</command>
	      will not detect the <keycap>ENTER</keycap> (newline)
	      key.</para></note>


	    <para><anchor id="readtimed"></para>
	    <para>The <option>-t</option> option to <command>read</command>
	      permits timed input (see <xref linkend="tout"> and <xref
	      linkend="qky">).</para>

	    <para><anchor id="readredir0"></para>
	    <para>The <command>read</command> command may also
	      <quote>read</quote> its variable value from a file
	      <link linkend="ioredirref">redirected</link> to
	      <filename>stdin</filename>.  If the file contains
	      more than one line, only the first line is assigned
	      to the variable. If <command>read</command>
	      has more than one parameter, then each of
	      these variables gets assigned a successive <link
	      linkend="whitespaceref">whitespace-delineated</link>
	      string. Caution!</para>

	    <example id="readredir">
	      <title>Using <firstterm>read</firstterm> with
	        <link linkend="ioredirref">file redirection</link></title>
	      <programlisting>&readredir;</programlisting>
	    </example>

	    <note>

	    <para><link linkend="piperef">Piping</link> output
	      to a <firstterm>read</firstterm>, using <link
	      linkend="echoref">echo</link> to set variables <link
	      linkend="badread0">will fail</link>.</para>

	    <para><anchor id="readpiperef">Yet, piping the output of <link
	      linkend="catref">cat</link> <emphasis>seems</emphasis> to
	      work.</para>

	    <para><anchor id="whilereadref"></para>

	    <para><programlisting>cat file1 file2 |
while read line
do
echo $line
done</programlisting></para>


            <para>However, as Bj&ouml;n Eriksson shows:</para>

    <example id="readpipe">
      <title>Problems reading from a pipe</title>
      <programlisting>&readpipe;</programlisting>
    </example>

            <para>The <firstterm>gendiff</firstterm> script, usually
              found in <filename>/usr/bin</filename> on
              many Linux distros, pipes the output of <link
              linkend="findref">find</link> to a <firstterm>while
              read</firstterm> construct.

	      <programlisting>find $1 \( -name "*$2" -o -name ".*$2" \) -print |
while read f; do
. . .</programlisting>
            </para>

	      </note>

	      <tip>
	      <para>It is possible to <firstterm>paste</firstterm> text into
	        the input field of a <firstterm>read</firstterm> (but
		<emphasis>not</emphasis> multiple lines!). See <xref
		linkend="padsw">.</para>
	      </tip>
	      

	    </listitem>
	  </varlistentry>

      </variablelist>

      <variablelist id="intfilesystem">
        <title><anchor id="intfilesystem1">Filesystem</title>

	<varlistentry>
	  <term><anchor id="cdref"><command>cd</command></term>
	  <indexterm>
	    <primary>cd</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cd</secondary>
	  </indexterm>
	  <listitem>
	    <para>The familiar <command>cd</command> change directory
	      command finds use in scripts where execution of a command
	      requires being in a specified directory.</para>

	    <para>  
	      <programlisting>(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)</programlisting>
	      [from the <link linkend="coxex">previously cited</link>
	      example by Alan Cox]</para>

	    <para>The <option>-P</option> (physical) option to
	      <command>cd</command> causes it to ignore symbolic
	      links.</para>

	    <para><command>cd -</command> changes to <link
	    linkend="oldpwd">$OLDPWD</link>, the previous working
	    directory.</para>

	    <para><anchor id="doubleslashref"></para>

	    <caution><para>The <command>cd</command> command does not function
	      as expected when presented with two forward slashes.

	      <screen>
<prompt>bash$ </prompt><userinput>cd //</userinput>
<prompt>bash$ </prompt><userinput>pwd</userinput>
<computeroutput>//</computeroutput>
	      </screen>
	      The output should, of course, be <computeroutput>/</computeroutput>.
	      This is a problem both from the command line and in a script.</para></caution>

	  </listitem>
	</varlistentry>

      <varlistentry>
	<term><anchor id="pwd2ref"><command>pwd</command></term>
	  <indexterm>
	    <primary>pwd</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>pwd</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>$PWD</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$PWD</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>directory</primary>
	    <secondary>working</secondary>
	  </indexterm>
	  <listitem><para>Print Working Directory. This gives the user's
	      (or script's) current directory (see <xref
	      linkend="ex37">). The effect is identical to
	      reading the value of the builtin variable <link
	      linkend="pwdref">$PWD</link>.</para>

	  </listitem>
	</varlistentry>

      <varlistentry>
	<term><anchor id="dirsd"><command>pushd</command></term>
	<term><command>popd</command></term>
	<term><command>dirs</command></term>
	  <indexterm>
	    <primary>pushd</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>pushd</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>popd</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>popd</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>dirs</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>dirs</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>directory</primary>
	    <secondary>working</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>bookmark</primary>
	  </indexterm>
	  <listitem><para>This command set is a mechanism for bookmarking working directories,
	      a means of moving back and forth through directories in an orderly
	      manner.  A pushdown stack is used to keep track of directory names.
	      Options allow various manipulations of the directory stack.</para>

	    <para><anchor id="pushdref"><userinput>pushd
	      dir-name</userinput> pushes the path
	      <replaceable>dir-name</replaceable> onto the directory
	      stack and simultaneously changes the current working
	      directory to <replaceable>dir-name</replaceable></para>

	    <para><anchor id="popdref"><command>popd</command> removes
	      (pops) the top directory path name off the directory stack
	      and simultaneously changes the current working directory
	      to that directory popped from the stack.</para>
	    
	    <para><anchor id="dirsref"><command>dirs</command> lists
	      the contents of the directory stack (compare this
	      with the <link linkend="dirstackref">$DIRSTACK</link>
	      variable).  A successful <command>pushd</command>
	      or <command>popd</command> will automatically invoke
	      <command>dirs</command>.</para>


	    <para>Scripts that require various changes to the current
	      working directory without hard-coding the directory name
	      changes can make good use of these commands. Note that
	      the implicit <varname>$DIRSTACK</varname> array variable,
	      accessible from within a script, holds the contents of
	      the directory stack.
	    </para>

	    <example id="ex37">
	      <title>Changing the current working directory</title>
	      <programlisting>&ex37;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="intvar">
        <title><anchor id="intvar1">Variables</title>

	<varlistentry>
	  <term><anchor id="letref"><command>let</command></term>
	  <indexterm>
	    <primary>let</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>let</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>let</command> command carries out arithmetic
	      operations on variables. In many cases, it functions as a less
	      complex version of <link linkend="exprref">expr</link>.</para>

	    <example id="ex46">
	      <title>Letting <firstterm>let</firstterm> do arithmetic.</title>
	      <programlisting>&ex46;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="evalref"><command>eval</command></term>
	  <indexterm>
	    <primary>eval</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>eval</secondary>
	  </indexterm>
	  <listitem>
	    
	    <para><userinput>eval arg1 [arg2] ... [argN]</userinput></para>
	    
	    <para>Combines the arguments in an expression or list of
	      expressions and <firstterm>evaluates</firstterm> them. Any
	      variables contained within the expression are expanded. The
	      result translates into a command. This can be useful for
	      code generation from the command line or within a script.</para>


	      <para>
	      <screen>
<prompt>bash$ </prompt><userinput>process=xterm</userinput>
<prompt>bash$ </prompt><userinput>show_process="eval ps ax | grep $process"</userinput>
<prompt>bash$ </prompt><userinput>$show_process</userinput>
<computeroutput>1867 tty1     S      0:02 xterm
 2779 tty1     S      0:00 xterm
 2886 pts/1    S      0:00 grep xterm</computeroutput>
	      </screen>
	      </para>

      <para><anchor id="evalforced"></para>
      <para>Each invocation of <firstterm>eval</firstterm> forces
        a re-<emphasis>evaluation</emphasis> of its arguments.
	<programlisting>a='$b'
b='$c'
c=d

echo $a             # $b
                    # First level.
eval echo $a        # $c
                    # Second level.
eval eval echo $a   # d
                    # Third level.

# Thank you, E. Choroba.</programlisting></para>


	    <para><anchor id="evaleff"></para>
	    <example id="ex43">
	      <title>Showing the effect of <firstterm>eval</firstterm></title>
	      <programlisting>&ex43;</programlisting>
	    </example>	    

	    <example id="echoparams">
	      <title><firstterm>Echoing</firstterm> the
	        <firstterm>command-line parameters</firstterm></title>
	      <programlisting>&echoparams;</programlisting>
	    </example>	    

	    <example id="ex44">
	      <title>Forcing a log-off</title>
	      <programlisting>&ex44;</programlisting>
	    </example>	    

	    <example id="rot14">
	      <title>A version of <firstterm>rot13</firstterm></title>
	      <programlisting>&rot14;</programlisting>
	    </example>	    

	    <para>Rory Winston contributed the following instance of how
	      useful <firstterm>eval</firstterm> can be.</para>

	    <para><anchor id="evalx0"></para>
	    <example id="evalex">
	      <title>Using <firstterm>eval</firstterm> to force variable
	        substitution in a <firstterm>Perl</firstterm> script</title>
	      <programlisting>&evalex;</programlisting>
	    </example>	    

	    <para>The <firstterm>eval</firstterm> command occurs
	      in the older version of <link linkend="ivrref">indirect
	      referencing</link>.
	      <programlisting>eval var=\$$var</programlisting> 
	      </para>


	    <para><anchor id="evalrisk"></para>
	    <caution><para>The <command>eval</command> command can be
	      risky, and normally should be avoided when there
	      exists a reasonable alternative. An <userinput>eval
	      $COMMANDS</userinput> executes the contents of
	      <replaceable>COMMANDS</replaceable>, which may
	      contain such unpleasant surprises as <command>rm -rf
	      *</command>. Running an <command>eval</command> on
	      unfamiliar code written by persons unknown is living
	      dangerously.</para></caution>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="setref"><command>set</command></term>
	  <indexterm>
	    <primary>set</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>set</secondary>
	  </indexterm>
	  <listitem><para>The <command>set</command> command changes
	      the value of internal script variables/options. One use for
	      this is to toggle <link linkend="optionsref">option
	      flags</link> which help determine the behavior of the
	      script. Another application for it is to reset the <link
	      linkend="posparamref">positional parameters</link> that
	      a script sees as the result of a command (<userinput>set
	      `command`</userinput>). The script can then parse the
	      fields of the command output.</para>

	    <example id="ex34">
	      <title>Using <firstterm>set</firstterm> with positional
	        parameters</title>
	      <programlisting>&ex34;</programlisting>
	    </example>

	    <para>More fun with positional parameters.</para>

	    <example id="revposparams">
	      <title>Reversing the positional parameters</title>
	      <programlisting>&revposparams;</programlisting>
	    </example>

	    <para>Invoking <command>set</command> without any options or
	      arguments simply lists all the <link
	      linkend="envref">environmental</link> and other variables
	      that have been initialized.</para>

            <para>
	      <screen>
<prompt>bash$ </prompt><userinput>set</userinput>
<computeroutput>AUTHORCOPY=/home/bozo/posts
 BASH=/bin/bash
 BASH_VERSION=$'2.05.8(1)-release'
 ...
 XAUTHORITY=/home/bozo/.Xauthority
 _=/etc/bashrc
 variable22=abc
 variable23=xzy</computeroutput>
	      </screen>
            </para>


	    <para>Using <command>set</command> with the <option>--</option>
	      option explicitly assigns the contents of a variable to
	      the positional parameters. If no variable follows the
	      <option>--</option> it <firstterm>unsets</firstterm>
	      the positional parameters.</para>

	    <example id="setpos">
	      <title>Reassigning the positional parameters</title>
	      <programlisting>&setpos;</programlisting>
	    </example>

	    <para>See also <xref linkend="ex22a"> and <xref linkend="ex33a">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="unsetref"><command>unset</command></term>
	  <indexterm>
	    <primary>unset</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>unset</secondary>
	  </indexterm>
	  <listitem><para>The <command>unset</command> command deletes a
	      shell variable, effectively setting it to
	      <firstterm>null</firstterm>. Note that this command does
	      not affect positional parameters.</para>

	  <para>
	      <screen>
<prompt>bash$ </prompt><userinput>unset PATH</userinput>

<prompt>bash$ </prompt><userinput>echo $PATH</userinput>
<computeroutput>


</computeroutput>
<prompt>bash$ </prompt></screen>
	    </para>

	    <example id="uns">
	      <title><quote>Unsetting</quote> a variable</title>
	      <programlisting>&uns;</programlisting>
	    </example>

	    </listitem>
	  </varlistentry>

	<varlistentry>
	  <term><anchor id="exportref"><command>export</command></term>
	  <indexterm>
	    <primary>export</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>export</secondary>
	  </indexterm>
	  <listitem>
	  
          <para><anchor id="exportref2"></para>
	  <para>The <command>export</command>

	      <footnote><para>To <firstterm>Export</firstterm>
	      information is to make it available in a more general context.
	      See also <link
	      linkend="scoperef">scope</link>.</para></footnote>
	  
	      command makes available variables to all child processes
	      of the running script or shell. One important use
	      of the <command>export</command> command is in <link
	      linkend="filesref1">startup files</link>, to initialize
	      and make accessible <link linkend="envref">environmental
	      variables</link> to subsequent user processes.</para>

	  <caution><para>Unfortunately, <link linkend="parchildprobref">
	     there is no way to export variables back to the parent
	     process</link>, to the process that called or invoked the
	     script or shell.</para></caution>


	  <para><anchor id="exportawk"></para>
	  <example id="coltotaler3">
	    <title>Using <firstterm>export</firstterm> to pass a variable to an
	      embedded <firstterm>awk</firstterm> script</title>
	    <programlisting>&coltotaler3;</programlisting>
	  </example>



	      <tip>

	        <para>It is possible to initialize and export
		  variables in the same operation, as in <command>export
		  var1=xxx</command>.</para>

		<para>However, as Greg Keraunen points out, in certain
		  situations this may have a different effect than
		  setting a variable, then exporting it.</para>

	        <para>
	        <screen>
<prompt>bash$ </prompt><userinput>export var=(a b); echo ${var[0]}</userinput>
<computeroutput>(a b)</computeroutput>



<prompt>bash$ </prompt><userinput>var=(a b); export var; echo ${var[0]}</userinput>
<computeroutput>a</computeroutput>
	      </screen>
	    </para>

	       	
              </tip>

	    </listitem>
	  </varlistentry>
	
	<varlistentry>
	  <term><anchor id="declare2ref"><command>declare</command></term>
	  <term><command>typeset</command></term>
	  <indexterm>
	    <primary>declare</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>declare</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>typeset</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>typeset</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <link linkend="declareref">declare</link> and
	      <link linkend="declareref">typeset</link> commands specify
	      and/or restrict properties of variables.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="readonlyref"><command>readonly</command></term>
	  <indexterm>
	    <primary>readonly</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>readonly</secondary>
	  </indexterm>
	  <listitem><para>Same as <link linkend="declareref">declare -r</link>,
	      sets a variable as read-only, or, in effect, as a
	      constant. Attempts to change the variable fail with
	      an error message. This is the shell analog of the
	      <firstterm>C</firstterm> language <command>const</command>
	      type qualifier.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="getoptsx"><command>getopts</command></term>
	  <indexterm>
	    <primary>getopts</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>getopts</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>$OPTIND</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$OPTIND</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>$OPTARG</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$OPTARG</secondary>
	  </indexterm>
	  <listitem>
	    <para>This powerful tool parses command-line arguments passed
	      to the script. This is the Bash analog of the <link
	      linkend="getopty">getopt</link> external command and the
	      <firstterm>getopt</firstterm> library function familiar to
	      <firstterm>C</firstterm> programmers. It permits passing
	      and concatenating multiple options

	      <footnote><para>An <firstterm>option</firstterm> is an
		argument that acts as a flag, switching script behaviors
		on or off. The argument associated with a particular
		option indicates the behavior that the option (flag)
		switches on or off.</para></footnote>

	      and associated arguments to a script (for
	      example <userinput>scriptname -abc -e
	      /usr/local</userinput>).</para>

	    <para><anchor id="getoptsopt"></para>
	    <para>The <command>getopts</command> construct uses two implicit
	      variables. <varname>$OPTIND</varname> is the argument
	      pointer (<wordasword>OPTion INDex</wordasword>)
	      and <varname>$OPTARG</varname> (<wordasword>OPTion
	      ARGument</wordasword>) the (optional) argument attached
	      to an option. A colon following the option name in the
	      declaration tags that option as having an associated
	      argument.</para>

	    <para>A <command>getopts</command> construct usually comes
	      packaged in a <link linkend="whileloopref">while
	      loop</link>, which processes the options and
	      arguments one at a time, then increments the implicit
	      <varname>$OPTIND</varname> variable to step to the
	      next.</para>

	    <note>
	      <para>
		<orderedlist>
		  <listitem>

		    <para>The arguments passed from the command line to
		      the script must be preceded by a
		      minus (<option>-</option>). It is the
		      prefixed <option>-</option> that lets
		      <command>getopts</command> recognize command-line
		      arguments as <firstterm>options</firstterm>.
		      In fact, <command>getopts</command> will not process
		      arguments without the prefixed <option>-</option>,
		      and will terminate option processing at the first
		      argument encountered lacking them.</para>

		  </listitem>
		  <listitem><para>The <command>getopts</command> template
		      differs slightly from the standard <link
		      linkend="whileloopref">while loop</link>, in that
		      it lacks condition brackets.</para>
		  </listitem>
		  <listitem>

		  <para>The <command>getopts</command> construct is a highly
		     functional replacement for the traditional
		     <link linkend="getopty">getopt</link> external
		     command.</para>

		   </listitem>
		</orderedlist>
	      </para>
	    </note>

	    <para><programlisting>
while getopts ":abcde:fg" Option
# Initial declaration.
# a, b, c, d, e, f, and g are the options (flags) expected.
# The : after option 'e' shows it will have an argument passed with it.
do
  case $Option in
    a ) # Do something with variable 'a'.
    b ) # Do something with variable 'b'.
    ...
    e)  # Do something with 'e', and also with $OPTARG,
        # which is the associated argument passed with option 'e'.
    ...
    g ) # Do something with variable 'g'.
  esac
done
shift $(($OPTIND - 1))
# Move argument pointer to next.

# All this is not nearly as complicated as it looks &lt;grin&gt;.</programlisting></para>

	    <example id="ex33">
	      <title>Using <firstterm>getopts</firstterm> to read the
	        options/arguments passed to a script</title>
	      <programlisting>&ex33;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="intscrbeh">
        <title><anchor id="intscrbeh1">Script Behavior</title>

      <varlistentry>
	<term><anchor id="sourceref"><command>source</command></term>
	<term><token>.</token> (<link linkend="dotref">dot</link> command)</term>
	  <indexterm>
	    <primary>source</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>source</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>.</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>.</secondary>
	  </indexterm>

	  <listitem>
	  
	  <para>This command, when invoked from the command line,
	      executes a script. Within a script, a
	      <userinput>source file-name</userinput>
	      loads the file <filename>file-name</filename>.
	      <firstterm>Sourcing</firstterm> a file (dot-command)
	      <firstterm>imports</firstterm>
	     code into the script, appending to the script (same effect
	     as the <userinput>#include</userinput> directive in a
	     <firstterm>C</firstterm> program). The net result is the
	     same as if the <quote>sourced</quote> lines of code were
	     physically present in the body of the script. This is useful
	     in situations when multiple scripts use a common data file
	     or function library.</para>

	    <example id="ex38">
	      <title><quote>Including</quote> a data file</title>
	      <programlisting>&ex38;</programlisting>

	      <para>File <filename>data-file</filename> for <xref
		linkend="ex38">, above.  Must be present in same
		directory.</para>

	      <programlisting>&ex38bis;</programlisting>
	    </example>	    

	     <para>If the <firstterm>sourced</firstterm> file is itself
	       an executable script, then it will run, then return
	       control to the script that called it. A
	       <firstterm>sourced</firstterm> executable script may use a
	      <link linkend="returnref">return</link> for this
	      purpose.</para>

	    <para><anchor id="sourceparams"></para>
	    <para>
	      Arguments may be (optionally) passed to the
	      <firstterm>sourced</firstterm> file as <link
	      linkend="posparamref1">positional parameters</link>.
	       <programlisting>source $filename $arg1 arg2</programlisting>
	    </para>



	  <para>It is even possible for a script to
	    <firstterm>source</firstterm> itself, though this does not
	    seem to have any practical applications.</para>

	    <example id="selfsource">
	      <title>A (useless) script that sources itself</title>
	      <programlisting>&selfsource;</programlisting>
	    </example>


	    </listitem>
	  </varlistentry>


	<varlistentry>
	  <term><anchor id="exitref"><command>exit</command></term>
	  <indexterm>
	    <primary>exit</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>exit</secondary>
	  </indexterm>
	  <listitem>
	    <para>Unconditionally terminates a script.
		    <footnote><para>Technically, an
		    <command>exit</command> only terminates the
		    process (or shell) in which it is running,
		    <emphasis>not</emphasis> the <firstterm>parent
		    process</firstterm>.</para></footnote>
	        The <command>exit</command> command may optionally take an
		integer argument, which is returned to the shell as
		the <link linkend="exitstatusref">exit status</link>
		of the script. It is good practice to end all but the
		simplest scripts with an <userinput>exit 0</userinput>,
		indicating a successful run.</para>

	    <note><para>If a script terminates with an <command>exit</command>
	      lacking an argument, the exit status of the script is the exit
	      status of the last command executed in the script, not counting
	      the <command>exit</command>. This is equivalent to an
	      <command>exit $?</command>.</para></note>

	    <note><para>An <command>exit</command> command may also be used to
	      terminate a <link
	      linkend="subshellsref">subshell</link>.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="execref"><command>exec</command></term>
	  <indexterm>
	    <primary>exec</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>exec</secondary>
	  </indexterm>
	  <listitem>

	    <para>
	      This shell builtin replaces the current process with
	      a specified command. Normally, when the shell encounters
	      a command, it <link linkend="forkref">forks off</link> a
	      child process to actually execute the command.  Using the
	      <command>exec</command> builtin, the shell does not fork,
	      and the command <firstterm>exec</firstterm>'ed replaces
	      the shell.  When used in a script, therefore, it forces an
	      exit from the script when the <command>exec</command>'ed
	      command terminates.
		<footnote><para>Unless the <command>exec</command> is used
		   to <link linkend="usingexecref">reassign file
		   descriptors</link>.</para></footnote>
	    </para>

	    <example id="ex54">
	      <title>Effects of <firstterm>exec</firstterm></title>
	      <programlisting>&ex54;</programlisting>
	    </example>	    	   

	    <example id="selfexec">
	      <title>A script that <firstterm>exec's</firstterm> itself</title>
	      <programlisting>&selfexec;</programlisting>
	    </example>	    	   

	    <para>An <command>exec</command> also serves to <link
	    linkend="usingexecref">reassign
	      file descriptors</link>.	For example, <userinput>exec
	      &lt;zzz-file</userinput> replaces <filename>stdin</filename>
	      with the file <filename>zzz-file</filename>.</para>

	    <note><para>The <option>-exec</option> option to
	      <link linkend="findref">find</link> is
	      <replaceable>not</replaceable> the same as the
	      <command>exec</command> shell builtin.</para></note>

	  </listitem>
	</varlistentry>
	

	<varlistentry>
	  <term><anchor id="shoptref"><command>shopt</command></term>
	  <indexterm>
	    <primary>shopt</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>shopt</secondary>
	  </indexterm>
	  <listitem>
	    <para>This command permits changing <firstterm>shell
	      options</firstterm> on the fly (see <xref linkend="al">
	      and <xref linkend="unal">).  It often appears in the Bash
	      <link linkend="filesref1">startup files</link>, but also has
	      its uses in scripts. Needs <link linkend="bash2ref">version
	      2</link> or later of Bash.</para>

	    <para><programlisting>shopt -s cdspell
# Allows minor misspelling of directory names with 'cd'

cd /hpme  # Oops! Mistyped '/home'.
pwd       # /home
          # The shell corrected the misspelling.</programlisting></para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><command>caller</command><anchor id="callerref"></term>
	  <indexterm>
	    <primary>caller</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>caller</secondary>
	  </indexterm>
	  <listitem>
	    <para>Putting a <command>caller</command> command
	       inside a <link linkend="functionref">function</link>
	       echoes to <filename>stdout</filename> information about
	       the <firstterm>caller</firstterm> of that function.</para>


	<para><programlisting>#!/bin/bash

function1 ()
{
  # Inside function1 ().
  caller 0   # Tell me about it.
}

function1    # Line 9 of script.

# 9 main test.sh
# ^                 Line number that the function was called from.
#   ^^^^            Invoked from "main" part of script.
#        ^^^^^^^    Name of calling script.

caller 0     # Has no effect because it's not inside a function.</programlisting></para>

	    <para>A <command>caller</command> command can also return
	      <firstterm>caller</firstterm> information from a script <link
	      linkend="sourceref">sourced</link> within another
	      script. Analogous to a function, this is a <quote>subroutine
	      call.</quote></para>

	    <para>You may find this command useful in debugging.</para>

	  </listitem>
	</varlistentry>



      </variablelist>


      <variablelist id="intcommand">
        <title><anchor id="intcommand1">Commands</title>

      <varlistentry>
	<term><anchor id="trueref"><command>true</command></term>
	  <indexterm>
	    <primary>true</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>true</secondary>
	  </indexterm>
	  <listitem><para>A command that returns a successful
	    (<returnvalue>zero</returnvalue>) <link
	    linkend="exitstatusref">exit status</link>, but does
	    nothing else.
	  </para>

	    <para>
	      <screen>
<prompt>bash$ </prompt><userinput>true</userinput>
<prompt>bash$ </prompt><userinput>echo $?</userinput>
<computeroutput>0</computeroutput>
	      </screen>
	    </para>

	  <para><programlisting># Endless loop
while true   # alias for ":"
do
   operation-1
   operation-2
   ...
   operation-n
   # Need a way to break out of loop or script will hang.
done</programlisting></para>

	    </listitem>
	  </varlistentry>

      <varlistentry>
	<term><anchor id="falseref"><command>false</command></term>
	  <indexterm>
	    <primary>false</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>false</secondary>
	  </indexterm>
	  <listitem><para>A command that returns an unsuccessful <link
	  linkend="exitstatusref">exit status</link>,
	    but does nothing else.</para>

	    <para>
	      <screen>
<prompt>bash$ </prompt><userinput>false</userinput>
<prompt>bash$ </prompt><userinput>echo $?</userinput>
<computeroutput>1</computeroutput>
	      </screen>
	    </para>

	  <para><programlisting># Testing "false" 
if false
then
  echo "false evaluates \"true\""
else
  echo "false evaluates \"false\""
fi
# false evaluates "false"


# Looping while "false" (null loop)
while false
do
   # The following code will not execute.
   operation-1
   operation-2
   ...
   operation-n
   # Nothing happens!
done   
</programlisting></para>

	    </listitem>
	  </varlistentry>

      <varlistentry>
	<term><anchor id="typeref"><command>type [cmd]</command></term>
	  <indexterm>
	    <primary>type</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>type</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>which</secondary>
	  </indexterm>
	  <listitem><para>Similar to the <link
	    linkend="whichref">which</link> external command,
	    <command>type cmd</command> identifies
	    <quote>cmd.</quote> Unlike <command>which</command>,
	    <command>type</command> is a Bash builtin. The useful
	    <option>-a</option> option to <command>type</command>
	    identifies <replaceable>keywords</replaceable>
	    and <replaceable>builtins</replaceable>, and also locates
	    system commands with identical names.</para>

	    <para>
	      <screen>
<prompt>bash$ </prompt><userinput>type '['</userinput>
<computeroutput>[ is a shell builtin</computeroutput>
<prompt>bash$ </prompt><userinput>type -a '['</userinput>
<computeroutput>[ is a shell builtin
 [ is /usr/bin/[</computeroutput>


<prompt>bash$ </prompt><userinput>type type</userinput>
<computeroutput>type is a shell builtin</computeroutput>
	      </screen>
	    </para>

	  </listitem>
	</varlistentry>

      <varlistentry>
	<term><anchor id="hashcmdref"><command>hash [cmds]</command></term>
	  <indexterm>
	    <primary>hash</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>hash</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>$PATH</primary>
	  </indexterm>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>$PATH</secondary>
	  </indexterm>
	  <listitem><para>Record the path name of specified commands -- in the
	      shell hash table

	        <footnote>
		<para><anchor id="hashref"></para>
		<para><firstterm>Hashing</firstterm> is a method of
		creating lookup keys for data stored in a table. The
		<emphasis>data items themselves</emphasis> are
		<quote>scrambled</quote> to create keys, using one of
		a number of simple mathematical
		<firstterm>algorithms</firstterm> (methods, or
		recipes).</para>

		<para>An advantage of <firstterm>hashing</firstterm> is that it
		is fast. A disadvantage is that <quote>collisions</quote> --
		where a single key maps to more than one data item -- are
		possible.</para>

		<para>For examples of hashing see <xref linkend="hashlib"> and
		  <xref linkend="hashexample">.</para>
	        </footnote>
	      
	      -- so the shell or script will not need to search
	      the <varname>$PATH</varname> on subsequent calls to those
              commands. When <command>hash</command> is called with no
	      arguments,  it simply lists the commands that have been hashed.
	      The <option>-r</option> option resets the hash table.</para>
	  </listitem>
	</varlistentry>


      <varlistentry>
	<term><anchor id="bindref"><command>bind</command></term>
	  <indexterm>
	    <primary>bind</primary>
	  </indexterm>
	  <indexterm>
	    <primary>bind</primary>
	    <secondary>key bindings </secondary>
	  </indexterm>
	  <listitem>

	  <para>The <command>bind</command> builtin displays or modifies
	  <firstterm>readline</firstterm>
	    <footnote><para>The <firstterm>readline</firstterm> library
	      is what Bash uses for reading input in an interactive
	      shell.</para></footnote>
	  key bindings.</para>

	  </listitem>
	</varlistentry>

      <varlistentry>
	<term><anchor id="helpref"><command>help</command></term>
	  <indexterm>
	    <primary>help</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary></secondary>
	  </indexterm>
	  <listitem>
	  
	  <para>Gets a short usage summary of a shell builtin. This is
	    the counterpart to <link linkend="whatisref">whatis</link>,
	    but for builtins.</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>help exit</userinput>
<computeroutput>exit: exit [n]
    Exit the shell with a status of N.  If N is omitted, the exit status
    is that of the last command executed.</computeroutput>
	      </screen>
	      </para>
	  </listitem>
	</varlistentry>

      </variablelist>


      <sect1>
	<title>Job Control Commands</title>


	<para>Certain of the following job control commands take a
	  <firstterm>job identifier</firstterm> as an argument. See
	  the <link linkend="jobidtable">table</link> at end of the
	  chapter.</para>

	<variablelist id="jccommandlist">

	  <varlistentry>
	    <term><anchor id="jobsref"><command>jobs</command></term>
	  <indexterm>
	    <primary>jobs</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>jobs</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>ps</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ps</secondary>
	  </indexterm>
	    <listitem>

	      <para>Lists the jobs running in the background, giving
	        the <firstterm>job number</firstterm>.
		Not as useful as <link linkend="ppssref">ps</link>.</para>

              <note>
	      <para>It is all too easy to confuse
		<firstterm>jobs</firstterm> and
		<firstterm>processes</firstterm>.  Certain <link
		linkend="builtinref">builtins</link>, such as
		<command>kill</command>, <command>disown</command>, and
		<command>wait</command> accept either a job number or a
		process number as an argument. The <link linkend="fgref">fg</link>,
		<link linkend="bgref">bg</link> and <command>jobs</command>
		commands accept only a job number.</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>sleep 100 &</userinput>
<computeroutput>[1] 1384</computeroutput>

<prompt>bash $ </prompt><userinput>jobs</userinput>
<computeroutput>[1]+  Running                 sleep 100 &</computeroutput></screen>
	      </para>

	      <para><quote>1</quote> is the job number (jobs are
		maintained by the current shell). <quote>1384</quote>
		is the <link linkend="ppidref">PID</link> or <firstterm>process ID
		number</firstterm> (processes are maintained by the system). To kill
		this job/process, either a <command>kill %1</command>
		or a <command>kill 1384</command> works.</para>

	      <para><emphasis>Thanks, S.C.</emphasis></para>	
               </note>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="disownref"><command>disown</command></term>
	  <indexterm>
	    <primary>disown</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>disown</secondary>
	  </indexterm>
	    <listitem>
	      <para>Remove job(s) from the shell's table of active jobs.</para>
	    </listitem>
	  </varlistentry>


	<varlistentry>
	  <term><anchor id="fgref"><command>fg</command></term>
	  <term><anchor id="bgref"><command>bg</command></term>
	  <indexterm>
	    <primary>fg</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>foreground</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>background</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>bg</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>fg</command> command switches a job
	      running in the background into the foreground.  The
	      <command>bg</command> command restarts a suspended job, and
	      runs it in the background. If no job number is specified,
	      then the <command>fg</command> or <command>bg</command>
	      command acts upon the currently running job.</para>
	  </listitem>
	</varlistentry>

	  <varlistentry>
	    <term><anchor id="waitref"><command>wait</command></term>
	  <indexterm>
	    <primary>wait</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>wait</secondary>
	  </indexterm>
	    <listitem>

	      <para>Suspend script execution until all jobs running in
	        background have terminated, or until the job number or
	        process ID specified as an option terminates. Returns the <link
	        linkend="exitstatusref">exit status</link> of waited-for
	        command.</para>

	      <para>You may use the <command>wait</command> command
		to prevent a script from exiting before a background
		job finishes executing (this would create a dreaded
		<link linkend="zombieref">orphan process</link>).</para>

	    <example id="ex39">
	      <title>Waiting for a process to finish before proceeding</title>
	      <programlisting>&ex39;</programlisting>
	    </example>	    

	      <para>Optionally, <command>wait</command> can take a <firstterm>job
		identifier</firstterm> as an argument, for example,
		<replaceable>wait%1</replaceable> or <replaceable>wait
		$PPID</replaceable>. See the <link linkend="jobidtable">job
		id table</link>.</para>

	      <para><anchor id="waithang"></para>
              <tip>
	      <para>Within a script, running a command in the background
		with an ampersand (&amp;) may cause the script
		to hang until <keycap>ENTER</keycap> is hit. This
		seems to occur with commands that write to
		<filename>stdout</filename>. It can be a major annoyance.
		  <programlisting>#!/bin/bash
# test.sh		  

ls -l &
echo "Done."</programlisting>
	      <screen><prompt>bash$ </prompt><userinput>./test.sh</userinput>
<computeroutput>Done.
 [bozo@localhost test-scripts]$ total 1
 -rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh
 _
</computeroutput>
               </screen>
	       </para>

      <blockquote>
	<literallayout>
    As Walter Brameld IV explains it:

    As far as I can tell, such scripts don't actually hang. It just
    seems that they do because the background command writes text to
    the console after the prompt. The user gets the impression that
    the prompt was never displayed. Here's the sequence of events:

    1. Script launches background command.
    2. Script exits.
    3. Shell displays the prompt.
    4. Background command continues running and writing text to the
       console.
    5. Background command finishes.
    6. User doesn't see a prompt at the bottom of the output, thinks script
       is hanging.
	</literallayout>
      </blockquote>

              <para>Placing a <command>wait</command> after the background
                command seems to remedy this.
		  <programlisting>#!/bin/bash
# test.sh		  

ls -l &
echo "Done."
wait</programlisting>
	      <screen><prompt>bash$ </prompt><userinput>./test.sh</userinput>
<computeroutput>Done.
 [bozo@localhost test-scripts]$ total 1
 -rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh</computeroutput>
               </screen>
	        <link linkend="ioredirref">Redirecting</link> the
                output of the command to a file or even to
		<filename>/dev/null</filename> also takes care of this
		problem.
              </para>
	      </tip>


	    </listitem>
	  </varlistentry>


	  <varlistentry>
	    <term><anchor id="suspendref"><command>suspend</command></term>
	    <indexterm>
	      <primary>suspend</primary>
	    </indexterm>
	    <indexterm>
	      <primary>command</primary>
	      <secondary>suspend</secondary>
	    </indexterm>
	    <listitem>
	      <para>This has a similar effect to
		<keycombo><keycap>Control</keycap><keycap>Z</keycap></keycombo>, 
		but it suspends the shell (the shell's parent process should
		resume it at an appropriate time).</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="logoutref"><command>logout</command></term>
	  <indexterm>
	    <primary>logout</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>log out</secondary>
	  </indexterm>
	    <listitem>
	      <para>Exit a login shell, optionally specifying an <link
	        linkend="exitstatusref">exit status</link>.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="timesref"><command>times</command></term>
	  <indexterm>
	    <primary>times</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>times</secondary>
	  </indexterm>
	    <listitem>
	      <para>Gives statistics on the system time elapsed when
	        executing commands, in the following form:
		<screen><computeroutput>0m0.020s 0m0.020s</computeroutput></screen></para>

              <para>This capability is of relatively limited value, since it is not common to
		profile and benchmark shell scripts.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="killref"><command>kill</command></term>
	  <indexterm>
	    <primary>kill</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>kill</secondary>
	    </indexterm>
	    <listitem>
	      <para>Forcibly terminate a process by sending it an
		appropriate <firstterm>terminate</firstterm> signal
		(see <xref linkend="killprocess">).</para>

	    <example id="selfdestruct">
	      <title>A script that kills itself</title>
	      <programlisting>&selfdestruct;</programlisting>
	    </example>
	      
	      <para><anchor id="zombieref"></para>
	      <note><para><userinput>kill -l</userinput> lists all the
		<link linkend="signald">signals</link> (as does the
		file <filename>/usr/include/asm/signal.h</filename>).
		A <userinput>kill -9</userinput> is a <firstterm>sure
		kill</firstterm>, which will usually terminate a
		process that stubbornly refuses to die with a plain
		<command>kill</command>. Sometimes, a <userinput>kill
		-15</userinput> works. A <firstterm>zombie</firstterm> process,
		that is, a child process that has terminated, but that
		the <link linkend="forkref">parent process</link>
		has not (yet) killed, cannot be killed by a logged-on
		user -- you can't kill something that is already dead --
		but <command>init</command> will generally clean it up
		sooner or later.</para></note>

	    </listitem>
	  </varlistentry>


	<varlistentry>
	  <term><anchor id="killallref"><command>killall</command></term>
	  <indexterm>
	    <primary>killall</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>kill</secondary>
	  </indexterm>
	  <listitem><para>The <command>killall</command> command
	    kills a running process by <firstterm>name</firstterm>,
            rather than by <link linkend="processidref">process ID</link>.
	    If there are multiple instances of a particular command running,
	    then doing a <firstterm>killall</firstterm> on that command will
	    terminate them <emphasis>all</emphasis>.</para>

	    <note><para>This refers to the <command>killall</command>
	      command in <filename class="directory">/usr/bin</filename>,
	      <emphasis>not</emphasis> the <link
	      linkend="killall2ref">killall script</link> in <filename
	      class="directory">/etc/rc.d/init.d</filename>.</para></note>
	    </listitem>
	  </varlistentry>

	<varlistentry>
	  <term><anchor id="commandref"><command>command</command></term>
	  <indexterm>
	    <primary>command</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>command</secondary>
	  </indexterm>
	  <listitem><para>The <command>command</command> directive
	    disables aliases and functions for the command immediately
	    following it.</para>
	    <para>
	      <screen>
<prompt>bash$ </prompt><userinput>command ls</userinput>
              </screen>
	    </para>

	    <note><para>This is one of three shell directives that
	      effect script command processing. The others are
	      <link linkend="bltref">builtin</link> and <link
	      linkend="enableref">enable</link>.</para></note>
	    </listitem>
	  </varlistentry>

	<varlistentry>
	  <term><anchor id="bltref"><command>builtin</command></term>
	  <indexterm>
	    <primary>builtin</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>builtin</secondary>
	  </indexterm>
	  <listitem><para>Invoking <command>builtin
	      BUILTIN_COMMAND</command> runs the command
	      <replaceable>BUILTIN_COMMAND</replaceable> as a shell <link
	      linkend="builtinref">builtin</link>, temporarily disabling
	      both functions and external system commands with the
	      same name.</para>
	    </listitem>
	  </varlistentry>

	<varlistentry>
	  <term><anchor id="enableref"><command>enable</command></term>
	  <indexterm>
	    <primary>enable</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>enable</secondary>
	  </indexterm>
	  <listitem>

	    <para>This either enables or disables a shell
	      builtin command. As an example, <replaceable>enable -n
	      kill</replaceable> disables the shell builtin <link
	      linkend="killref">kill</link>, so that when Bash
	      subsequently encounters <firstterm>kill</firstterm>, it invokes
	      the external command <filename>/bin/kill</filename>.</para>
	      
	    <para><anchor id="enableref1">The <option>-a</option>
	      option to <firstterm>enable</firstterm> lists all the
	      shell builtins, indicating whether or not they
	      are enabled. The <option>-f filename</option>
	      option lets <firstterm>enable</firstterm> load a <link
	      linkend="builtinref">builtin</link> as a shared library
	      (DLL) module from a properly compiled object file.
	        <footnote>
		  <para>The C source for a number of loadable builtins is
		    typically found in the <filename
		    class="directory">/usr/share/doc/bash-?.??/functions</filename>
		    directory.</para>
		  <para>Note that the <option>-f</option> option to
		    <command>enable</command> is not portable to all
		    systems.</para>
		</footnote>.
	     </para>	

	    </listitem>
	  </varlistentry>

	<varlistentry>
	  <term><anchor id="autoloadref"><command>autoload</command></term>
	  <indexterm>
	    <primary>autoload</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>autoloader</secondary>
	  </indexterm>
	  <listitem>

	  <para>This is a port to Bash of the
	    <firstterm>ksh</firstterm> autoloader. With
	    <command>autoload</command> in place, a function with
	    an <firstterm>autoload</firstterm> declaration will load from an
	    external file at its first invocation.
	      <footnote><para>The same effect as
	      <command>autoload</command> can be achieved with <link
	      linkend="declareref">typeset -fu</link>.</para></footnote>
	    This saves system resources.</para>

	  <para>Note that <firstterm>autoload</firstterm> is not a part of the
	    core Bash installation. It needs to be loaded in with
	    <replaceable>enable -f</replaceable> (see above).</para>

	    </listitem>
	  </varlistentry>

	</variablelist>

      <para><anchor id="jobidtable0"></para>
      <table id="jobidtable">
	<title>Job identifiers</title>
	<tgroup cols="2">
	  <thead>
	    <row>
	      <entry>Notation</entry>
	      <entry>Meaning</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>%N</option></entry>
	      <entry>Job number [N]</entry>
	    </row>
	    <row>
	      <entry><option>%S</option></entry>
	      <entry>Invocation (command line) of job begins with string <emphasis>S</emphasis></entry>
	    </row>
	    <row>
	      <entry><option>%?S</option></entry>
	      <entry>Invocation (command line) of job contains within it string <emphasis>S</emphasis></entry>
	    </row>
	    <row>
	      <entry><option>%%</option></entry>
	      <entry><quote>current</quote> job (last job stopped in
	      foreground or started in background)</entry>
	    </row>
	    <row>
	      <entry><option>%+</option></entry>
	      <entry><quote>current</quote> job (last job stopped in
	      foreground or started in background)</entry>
	    </row>
	    <row>
	      <entry><option>%-</option></entry>
	      <entry>Last job</entry>
	    </row>
	    <row>
	      <entry><option>$!</option></entry>
	      <entry>Last background process</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>

      </sect1> <!-- Job Control Commands -->

  </chapter> <!-- Internal Commands and Builtins -->



  <chapter id="external">
      <title>External Filters, Programs and Commands</title>

      <para><anchor id="externalref"></para>

      <para>Standard UNIX commands make shell scripts more versatile. The
	power of scripts comes from coupling system commands and shell
	directives with simple programming constructs.</para>

      <sect1 id="basic">
        <title>Basic Commands</title>

      <variablelist id="basiccommands">
        <title><anchor id="basiccommands1">The first commands a novice learns</title>

	<varlistentry>
	  <term><anchor id="lsref"><command>ls</command></term>
	  <indexterm>
	    <primary>ls</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ls</secondary>
	  </indexterm>
	  <listitem>
	    <para>The basic file <quote>list</quote> command. It is all too easy
	      to underestimate the power of this humble command. For
	      example, using the <option>-R</option>, recursive option,
	      <command>ls</command> provides a tree-like listing of
	      a directory structure. Other useful options are
	      <option>-S</option>, sort listing by file size,
	      <option>-t</option>, sort by file modification time,
	      <option>-b</option>, show escape characters, and
	      <option>-i</option>, show file inodes (see <xref
	      linkend="idelete">).</para>

	    <tip><para>
	      The <firstterm>ls</firstterm> command returns a
	      non-zero <link linkend="exitstatusref">exit status</link> when
	      attempting to list a non-existent file.
	      <screen><prompt>bash$ </prompt><userinput>ls abc</userinput>
<computeroutput>ls: abc: No such file or directory</computeroutput>


<prompt>bash$ </prompt><userinput>echo $?</userinput>
<computeroutput>2</computeroutput></screen>
	    </para></tip>

	    <example id="ex40">
	      <title>Using <firstterm>ls</firstterm> to create a table of contents
		for burning a <abbrev>CDR</abbrev> disk</title>
	      <programlisting>&ex40;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="catref"><command>cat</command></term>
	  <term><command>tac</command></term>
	  <indexterm>
	    <primary>cat</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cat</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>tac</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tac</secondary>
	  </indexterm>
	  <listitem>
	    <para><command>cat</command>, an acronym for
	    <wordasword>concatenate</wordasword>,
	      lists a file to <filename>stdout</filename>. When
	      combined with redirection (<token>></token> or
	      <token>>></token>), it is commonly used to concatenate
	      files.

		<anchor id="catuses">
	        <programlisting># Uses of 'cat'
cat filename                          # Lists the file.

cat file.1 file.2 file.3 &gt; file.123   # Combines three files into one.</programlisting>

	      The <option>-n</option> option to <command>cat</command>
	      inserts consecutive numbers before all lines of the
	      target file(s). The <option>-b</option> option numbers
	      only the non-blank lines. The <option>-v</option> option
	      echoes nonprintable characters, using <token>^</token>
	      notation. The <option>-s</option> option squeezes multiple
	      consecutive blank lines into a single blank line.</para>

            <para>See also <xref linkend="lnum"> and <xref linkend="rot13">.</para>

	    <note>
	    <para><anchor id="catlesseff">
	    In a <link linkend="piperef">pipe</link>, it may be
	    more efficient to <link linkend="ioredirref">redirect</link>
	    the <filename>stdin</filename> to a file, rather than to
            <command>cat</command> the file.
            </para>

            <para>
	    <programlisting>cat filename | tr a-z A-Z

tr a-z A-Z < filename   #  Same effect, but starts one less process,
                        #+ and also dispenses with the pipe.</programlisting>
            </para>
	    </note>


	    <para><command>tac</command>, is the inverse of
	      <wordasword>cat</wordasword>, listing a file backwards from its end.</para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="revref"><command>rev</command></term>
	  <indexterm>
	    <primary>rev</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>rev</secondary>
	  </indexterm>
	  <listitem>
	    <para>reverses each line of a file, and outputs to
	      <filename>stdout</filename>.  This does not have the same effect
	      as <command>tac</command>, as it preserves the order of
	      the lines, but flips each one around (mirror image).</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>cat file1.txt</userinput>
<computeroutput>This is line 1.
 This is line 2.</computeroutput>


<prompt>bash$ </prompt><userinput>tac file1.txt</userinput>
<computeroutput>This is line 2.
 This is line 1.</computeroutput>


<prompt>bash$ </prompt><userinput>rev file1.txt</userinput>
<computeroutput>.1 enil si sihT
 .2 enil si sihT</computeroutput>
	      </screen>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="cpref"><command>cp</command></term>
	  <indexterm>
	    <primary>cp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cp</secondary>
	  </indexterm>
	  <listitem>

	    <para>This is the file copy command. <userinput>cp file1
	      file2</userinput> copies <filename>file1</filename>
	      to <filename>file2</filename>, overwriting
	      <filename>file2</filename> if it already exists (see <xref
	      linkend="ex42">).</para>

	     <tip>
	     <para>Particularly useful are the <option>-a</option>
	       archive flag (for copying an entire directory tree),
	       the <option>-u</option> update flag (which prevents
	       overwriting identically-named newer files), and the
	       <option>-r</option> and <option>-R</option> recursive
	       flags.</para>
	       <para><programlisting>cp -u source_dir/* dest_dir
#  "Synchronize" dest_dir to source_dir
#+  by copying over all newer and not previously existing files.</programlisting></para>
	       </tip>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mvref"><command>mv</command></term>
	  <listitem>
	    <para>This is the file <firstterm>move</firstterm> command.
	      It is equivalent to a combination of <command>cp</command>
	      and <command>rm</command>. It may be used to move multiple
	      files to a directory, or even to rename a directory. For
	      some examples of using <command>mv</command> in a script,
	      see <xref linkend="rfe"> and <xref linkend="rn">.</para>

	    <note>
	    <para>When used in a non-interactive script,
	      <command>mv</command> takes the <option>-f</option>
	      (<firstterm>force</firstterm>) option to bypass user
	      input.</para>

	    <para>When a directory is moved to a preexisting directory,
	      it becomes a subdirectory of the destination directory.</para>
	  <para>
	      <screen>
<prompt>bash$ </prompt><userinput>mv source_directory target_directory</userinput>

<prompt>bash$ </prompt><userinput>ls -lF target_directory</userinput>
<computeroutput>total 1
 drwxrwxr-x    2 bozo  bozo      1024 May 28 19:20 source_directory/</computeroutput>
	      </screen>
	    </para>
	    </note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rmref"><command>rm</command></term>
	  <indexterm>
	    <primary>rm</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>rm</secondary>
	  </indexterm>
	  <listitem>
	    <para>Delete (remove) a file or files. The <option>-f</option>
	      option forces removal of even readonly files, and is useful
	      for bypassing user input in a script.</para>

	    <note>
		<para><anchor id="dashrem"></para>
	      <para>The <firstterm>rm</firstterm> command will, by
		itself,  fail to remove filenames beginning with
		a dash. Why? Because <firstterm>rm</firstterm>
		sees a dash-prefixed filename as an
		<firstterm>option</firstterm>.</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>rm -badname</userinput>
<computeroutput>rm: invalid option -- b
 Try `rm --help' for more information.</computeroutput></screen>
	      </para>

	        
		<para>
		One clever workaround is to precede
		the filename with a <quote> -- </quote> (the
		<firstterm>end-of-options</firstterm> flag).

	      <screen><prompt>bash$ </prompt><userinput>rm -- -badname</userinput></screen>
		</para>

	      <para>
	      Another method to is to preface the filename to be removed
	      with a <filename>dot-slash</filename> .

	      <screen><prompt>bash$ </prompt><userinput>rm ./-badname</userinput></screen>
	      </para>
	    </note>


	    <warning><para><anchor id="rmrecurs">When used with the
	      recursive flag <option>-r</option>, this command removes
	      files all the way down the directory tree from the current
	      directory.  A careless <command>rm -rf *</command> can wipe
	      out a big chunk of a directory structure.</para></warning>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rmdirref"><command>rmdir</command></term>
	  <indexterm>
	    <primary>rmdir</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>rmdir</secondary>
	  </indexterm>
	  <listitem>
	    <para>Remove directory. The directory must be empty of
	      all files -- including <quote>invisible</quote>
	      <firstterm>dotfiles</firstterm>

		<footnote>
		  <para><anchor id="dotfilesref"></para>
		  <para><firstterm>Dotfiles</firstterm> are files whose
		    names begin with a <firstterm>dot</firstterm>, such as
		    <filename>~/.Xdefaults</filename>. Such filenames do
		    not appear in a normal <command>ls</command> listing
		    (although an <command>ls -a</command> will show
		    them), and they cannot be deleted by an accidental
		    <command>rm -rf *</command>. Dotfiles are generally
		    used as setup and configuration files in a user's
		    home directory.</para>
		  </footnote>

	      -- for this command to succeed.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mkdirref"><command>mkdir</command></term>
	  <indexterm>
	    <primary>mkdir</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mkdir</secondary>
	  </indexterm>
	  <listitem>
	    <para>Make directory, creates a new directory. For example,
	      <userinput>mkdir -p project/programs/December</userinput>
	      creates the named directory. The
	      <replaceable>-p</replaceable> option automatically creates
	      any necessary parent directories.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="chmodref"><command>chmod</command></term>
	  <indexterm>
	    <primary>chmod</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>chmod</secondary>
	  </indexterm>
	  <listitem>

	    <para>Changes the attributes of an existing file or directory
	      (see <xref linkend="ex44">).</para>

	    <para><programlisting>chmod +x filename
# Makes "filename" executable for all users.

chmod u+s filename
# Sets "suid" bit on "filename" permissions.
# An ordinary user may execute "filename" with same privileges as the file's owner.
# (This does not apply to shell scripts.)</programlisting></para>

	    <para><programlisting>chmod 644 filename
# Makes "filename" readable/writable to owner, readable to others
# (octal mode).

chmod 444 filename
#  Makes "filename" read-only for all.
#  Modifying the file (for example, with a text editor)
#+ not allowed for a user who does not own the file (except for root),
#+ and even the file owner must force a file-save
#+ if she modifies the file.
#  Same restrictions apply for deleting the file.</programlisting></para>

	    <para><programlisting>chmod 1777 directory-name
#  Gives everyone read, write, and execute permission in directory,
#+ however also sets the "sticky bit".
#  This means that only the owner of the directory,
#+ owner of the file, and, of course, root
#+  can delete any particular file in that directory.

chmod 111 directory-name
#  Gives everyone execute-only permission in a directory.
#  This means that you can execute and READ the files in that directory
#+ (execute permission necessarily includes read permission
#+ because you can't execute a file without being able to read it).
#  But you can't list the files or search for them with the "find" command.
#  These restrictions do not apply to root.

chmod 000 directory-name
#  No permissions at all for that directory.
#  Can't read, write, or execute files in it.
#  Can't even list files in it or "cd" to it.
#  But, you can rename (mv) the directory
#+ or delete it (rmdir) if it is empty.
#  You can even symlink to files in the directory,
#+ but you can't read, write, or execute the symlinks.
#  These restrictions do not apply to root.</programlisting></para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="chattrref"><command>chattr</command></term>
	  <indexterm>
	    <primary>chattr</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>chattr</secondary>
	  </indexterm>
	  <listitem>

	    <para><command>Ch</command>ange file
	      <command>attr</command>ibutes. This is analogous to
	      <command>chmod</command> above, but with different options
	      and a different invocation syntax, and it works only on
	       <firstterm>ext2/ext3</firstterm> filesystems.</para>

	    <para>One particularly interesting <command>chattr</command>
	      option is <option>i</option>. A <command>chattr +i
	      <filename>filename</filename></command> marks the file
	      as immutable. The file cannot be modified, linked to, or
	      deleted, <emphasis>not even by root</emphasis>. This
	      file attribute can be set or removed only by
	      <firstterm>root</firstterm>. In a similar fashion,
	      the <option>a</option> option marks the file as append
	      only.</para>

	    <para>
	      <screen>
<prompt>root# </prompt><userinput>chattr +i file1.txt</userinput>


<prompt>root# </prompt><userinput>rm file1.txt</userinput>

<computeroutput>rm: remove write-protected regular file `file1.txt'? y
 rm: cannot remove `file1.txt': Operation not permitted</computeroutput>
	      </screen>
	    </para>

            <para>If a file has the <option>s</option> (secure)
              attribute set, then when it is deleted its block is zeroed out
	      on the disk.</para>

            <para>If a file has the <option>u</option> (undelete)
              attribute set, then when it is deleted, its contents can still
	      be retrieved (undeleted).</para>

            <para>If a file has the <option>c</option> (compress)
              attribute set, then it will automatically be compressed
	      on writes to disk, and uncompressed on reads.</para>

            <note><para>The file attributes set with
	      <command>chattr</command> do not show in a file listing
	      (<command>ls -l</command>).</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="linkref"><command>ln</command></term>
	  <listitem>

	    <para>Creates links to pre-existings files. A <quote>link</quote>
	      is a reference to a file, an alternate name for it.
	      The <command>ln</command> command permits referencing
	      the linked file by more than one name and is a superior
	      alternative to aliasing (see <xref linkend="ex18">).</para>

            <para>The <command>ln</command> creates only a reference, a
	       pointer to the file only a few bytes in size.</para>
	    
	    <para><anchor id="symlinkref"></para>

	    <para>The <command>ln</command> command is most often used
	      with the <option>-s</option>, symbolic or
	      <quote>soft</quote> link flag. Advantages of using the
	      <option>-s</option> flag are that it permits linking across
	      file systems or to directories.</para>

	    <para>The syntax of the command is a bit tricky. For example:
	      <userinput>ln -s oldfile newfile</userinput> links the
	      previously existing <filename>oldfile</filename> to the
	      newly created link, <filename>newfile</filename>.</para>

	    <caution><para>If a file named <filename>newfile</filename> has
	      previously existed, an error message will
	      result.</para></caution>


	    <sidebar><title>Which type of link to use?</title>

	      <para>As John Macdonald explains it:</para>

	      <para>Both of these [types of links] provide a certain measure of dual reference
		-- if you edit the contents of the file using any name,
		your changes will affect both the original name and either
		a hard or soft new name.  The differences between them
		occurs when you work at a higher level.  The advantage of
		a hard link is that the new name is totally independent
		of the old name -- if you remove or rename the old name,
		that does not affect the hard link, which continues
		to point to the data while it would leave a soft link
		hanging pointing to the old name which is no longer
		there. The advantage of a soft link is that it can refer
		to a different file system (since it is just a reference
		to a file name, not to actual data). And, unlike a hard
		link, a symbolic link can refer to a directory.</para>

		</sidebar>

	    <para><anchor id="linkminvok"></para>
            <para>Links give the ability to invoke a script (or any other type
	      of executable) with multiple names, and having that script
	      behave according to how it was invoked.</para>

	    <example id="hellol">
	      <title>Hello or Good-bye</title>
	      <programlisting>&hellol;</programlisting>
	    </example>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="manref"><command>man</command></term>
	  <term><anchor id="inforef"><command>info</command></term>
	  <indexterm>
	    <primary>man</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>man</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>info</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>info</secondary>
	  </indexterm>
	  <listitem>

	    <para>These commands access the manual and information pages on
	      system commands and installed utilities. When available, the
	      <firstterm>info</firstterm> pages usually contain more detailed
	      descriptions than do the <firstterm>man</firstterm> pages.</para>

            <para>There have been various attempts at
	      <quote>automating</quote> the writing of <firstterm>man
	      pages</firstterm>. For a script that makes a tentative first
	      step in that direction, see <xref linkend="maned">.</para>

	  </listitem>
	</varlistentry>


      </variablelist>


        </sect1> <!-- End Basic Commands -->


      <sect1 id="moreadv">
        <title>Complex Commands</title>

      <variablelist id="cclisting">
        <title><anchor id="cclisting1">Commands for more advanced users</title>

	<varlistentry>
	  <term><anchor id="findref"><command>find</command></term>
	  <indexterm>
	    <primary>find</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>find</secondary>
	  </indexterm>

	  <indexterm>
	    <primary>{}</primary>
	  </indexterm>
	  <indexterm>
	    <primary>special character</primary>
	    <secondary>{}</secondary>
	  </indexterm>

	  <indexterm>
	    <primary>\;</primary>
	  </indexterm>
	  <indexterm>
	    <primary>escaped character</primary>
	    <secondary>\;</secondary>
	  </indexterm>

	  <listitem>
	    <para><anchor id="findref0"></para>
	    <para>-exec <replaceable>COMMAND</replaceable> \;</para>
	    <para>Carries out <replaceable>COMMAND</replaceable> on
	      each file that <command>find</command> matches.  The
	      command sequence terminates with <token>;</token> (the
	      <quote>;</quote> is <link linkend="escp">escaped</link> to
	      make certain the shell passes it to <command>find</command>
	      literally, without interpreting it as a special character).</para>


	  <para>
	      <screen><prompt>bash$ </prompt><userinput>find ~/ -name '*.txt'</userinput>
<computeroutput>/home/bozo/.kde/share/apps/karm/karmdata.txt
 /home/bozo/misc/irmeyc.txt
 /home/bozo/test-scripts/1.txt</computeroutput>
	      </screen>
	  </para>

	    <para><anchor id="curlybracketsref"></para>

	    <para>If <replaceable>COMMAND</replaceable> contains
	      <token>{}</token>, then <command>find</command>
	      substitutes the full path name of the selected file for
	      <quote>{}</quote>.</para>

	  <para>
          <programlisting>find ~/ -name 'core*' -exec rm {} \;
# Removes all core dump files from user's home directory.</programlisting>
	  </para>


	  <para>
	  <programlisting>find /home/bozo/projects -mtime 1
#  Lists all files in /home/bozo/projects directory tree
#+ that were modified within the last day.
#
#  mtime = last modification time of the target file
#  ctime = last status change time (via 'chmod' or otherwise)
#  atime = last access time

DIR=/home/bozo/junk_files
find "$DIR" -type f -atime +5 -exec rm {} \;
#                                      ^^
#  Curly brackets are placeholder for the path name output by "find."
#
#  Deletes all files in "/home/bozo/junk_files"
#+ that have not been accessed in at least 5 days.
#
#  "-type filetype", where
#  f = regular file
#  d = directory
#  l = symbolic link, etc.
#  (The 'find' manpage and info page have complete listings.)</programlisting>
          </para>



	    <para><programlisting>find /etc -exec grep '[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*' {} \;

# Finds all IP addresses (xxx.xxx.xxx.xxx) in /etc directory files.
# There a few extraneous hits. Can they be filtered out?

# Possibly by:

find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
| grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'
#
#  [:digit:] is one of the character classes
#+ introduced with the POSIX 1003.2 standard. 

# Thanks, St&eacute;phane Chazelas. 
</programlisting></para>


            <note><para>The <option>-exec</option> option to
	      <command>find</command> should not be confused with the <link
	      linkend="execref">exec</link> shell builtin.</para></note>

	    <example id="ex57">
	      <title><firstterm>Badname</firstterm>, eliminate file names
		in current directory containing bad characters and <link
		linkend="whitespaceref">whitespace</link>.</title>
	      <programlisting>&ex57;</programlisting>
	    </example>

	    <example id="idelete">
	      <title>Deleting a file by its <firstterm>inode</firstterm>
	        number</title>
	      <programlisting>&idelete;</programlisting>
	    </example>

	    <para>The <command>find</command> command also works
	      without the <option>-exec</option> option.</para>

	    <para>
	    <programlisting>#!/bin/bash
#  Find suid root files.
#  A strange suid file might indicate a security hole,
#+ or even a system intrusion.

directory="/usr/sbin"
# Might also try /sbin, /bin, /usr/bin, /usr/local/bin, etc.
permissions="+4000"  # suid root (dangerous!)


for file in $( find "$directory" -perm "$permissions" )
do
  ls -ltF --author "$file"
done</programlisting>
	    </para>

	    <para>See <xref linkend="ex48">, <xref linkend="ex58">,
	      and <xref linkend="findstring"> for scripts using
	      <command>find</command>. Its <link
	      linkend="manref">manpage</link> provides more detail
	      on this complex and powerful command.</para>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="xargsref"><command>xargs</command></term>
	  <indexterm>
	    <primary>xargs</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>xargs</secondary>
	  </indexterm>
	  <listitem>
	    <para>A filter for feeding arguments to a command, and also
	      a tool for assembling the commands themselves. It breaks
	      a data stream into small enough chunks for filters and
	      commands to process.  Consider it as a powerful replacement
	      for <link linkend="backquotesref">backquotes</link>.
	      In situations where <link linkend="commandsubref">command
	      substitution</link> fails with a <errorname>too
	      many arguments</errorname> error,
	      substituting <command>xargs</command> often
	      works.
	        <footnote><para>And even when <firstterm>xargs</firstterm> is
		not strictly necessary, it can speed up execution of a command
		involving <link
		linkend="batchprocref">batch-processing</link> of multiple
		files.</para></footnote>
	      Normally, <command>xargs</command> reads from
	      <filename>stdin</filename> or from a pipe, but it can also
	      be given the output of a file.</para>

	    <para>The default command for <command>xargs</command> is
	      <link linkend="echoref">echo</link>. This means that input
	      piped to <command>xargs</command> may have linefeeds and
	      other whitespace characters stripped out.</para>
	      
	    <para>
	      <screen>
<prompt>bash$ </prompt><userinput>ls -l</userinput>
<computeroutput>total 0
 -rw-rw-r--    1 bozo  bozo         0 Jan 29 23:58 file1
 -rw-rw-r--    1 bozo  bozo         0 Jan 29 23:58 file2</computeroutput>



<prompt>bash$ </prompt><userinput>ls -l | xargs</userinput>
<computeroutput>total 0 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file1 -rw-rw-r-- 1 bozo bozo 0 Jan...</computeroutput>



<prompt>bash$ </prompt><userinput>find ~/mail -type f | xargs grep "Linux"</userinput>
<computeroutput>./misc:User-Agent: slrn/0.9.8.1 (Linux)
 ./sent-mail-jul-2005: hosted by the Linux Documentation Project.
 ./sent-mail-jul-2005: (Linux Documentation Project Site, rtf version)
 ./sent-mail-jul-2005: Subject: Criticism of Bozo's Windows/Linux article
 ./sent-mail-jul-2005: while mentioning that the Linux ext2/ext3 filesystem
 . . .</computeroutput>
	      </screen>
	      </para>

	    <para><userinput>ls | xargs -p -l gzip</userinput> <link
	      linkend="gzipref">gzips</link> every file in current
	      directory, one at a time, prompting before each
	      operation.</para>

	    <para><anchor id="xargsoneatatime"></para>
	    <note>
	    <para>Note that <firstterm>xargs</firstterm> processes the
	      arguments passed to it sequentially, <emphasis>one at
	      a time</emphasis>.</para>

            <para><screen>
<prompt>bash$ </prompt><userinput>find /usr/bin | xargs file</userinput>
<computeroutput>/usr/bin:          directory
 /usr/bin/foomatic-ppd-options:          perl script text executable
 . . .</computeroutput>
	      </screen>
	      </para>
	    </note>

	    <para><anchor id="xargslimargs"></para>
	    <tip>
	    <para>An interesting <firstterm>xargs</firstterm>
	      option is <option>-n <replaceable>NN</replaceable></option>,
	      which limits to <replaceable>NN</replaceable> the number
	      of arguments passed.</para>
	    <para><userinput>ls | xargs -n 8 echo</userinput> lists the files in the
	      current directory in <literal>8</literal> columns.</para>
	    </tip>  
	      
	      
	    <para><anchor id="xargsws"></para>
	    <tip>
	    <para>Another useful option is
	      <option>-0</option>, in combination with <userinput>find
	      -print0</userinput> or <userinput>grep -lZ</userinput>. This
	      allows handling arguments containing whitespace or
	      quotes.</para>
	      
	    <para>
	    <userinput>find / -type f -print0 | xargs -0 grep -liwZ GUI | xargs -0 rm -f</userinput>
	    </para>
	    
	    <para>
	    <userinput>grep -rliwZ GUI / | xargs -0 rm -f</userinput>
	    </para>

	    <para>Either of the above will remove any file containing <quote>GUI</quote>.
	      <emphasis>(Thanks, S.C.)</emphasis></para>

            <para>Or:
	      <programlisting>cat /proc/"$pid"/"$OPTION" | xargs -0 echo
#  Formats output:         ^^^^^^^^^^^^^^^
#  From Han Holl's fixup of "get-commandline.sh"
#+ script in "/dev and /proc" chapter.</programlisting></para>
	    </tip>



	    <example id="ex41">
	      <title>Logfile: Using <firstterm>xargs</firstterm> to monitor system log</title>
	      <programlisting>&ex41;</programlisting>
	    </example>	    

	    <para><anchor id="xargscurlyref"></para>
	    <para><link linkend="curlybracketsref">As in
	      <command>find</command></link>, a curly bracket
	      pair serves as a placeholder for replacement text.</para>

	    <example id="ex42">
	      <title>Copying files in current directory to another</title>
	      <programlisting>&ex42;</programlisting>
	    </example>	    

	    <example id="killbyname">
	      <title>Killing processes by name</title>
	      <programlisting>&killbyname;</programlisting>
	    </example>

	    <example id="wf2">
	      <title>Word frequency analysis using
	      <firstterm>xargs</firstterm></title>
	      <programlisting>&wf2;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="exprref"><userinput>expr</userinput></term>
	  <indexterm>
	    <primary>expr</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>expr</secondary>
	  </indexterm>
	  <listitem>
	    <para>All-purpose expression evaluator:
	      Concatenates and evaluates the arguments according
	      to the operation given (arguments must be separated
	      by spaces). Operations may be arithmetic, comparison,
	      string, or logical.</para>

	    <variablelist>
	      <varlistentry>
		<term><userinput>expr 3 + 5</userinput></term>
		<listitem>
		  <para>returns <literal>8</literal></para>
		</listitem>
	      </varlistentry>

	      <varlistentry>
		<term><userinput>expr 5 % 3</userinput></term>
		<listitem>
		  <para>returns 2</para>
		</listitem>
	      </varlistentry>

	      <varlistentry>
		<term><userinput>expr 1 / 0</userinput></term>
		<listitem>
		  <para>returns the error message, <errorcode>expr: division by
		    zero</errorcode></para>
                  <para>Illegal arithmetic operations not allowed.</para>
		</listitem>
	      </varlistentry>

	      <varlistentry>
		<term><userinput>expr 5 \* 3</userinput></term>
		<listitem>
		<para>returns 15</para>
		<para>The multiplication operator
		  must be escaped when used in an arithmetic expression
		  with <command>expr</command>.</para>
		</listitem>
	      </varlistentry>

	      <varlistentry>
		<term><userinput>y=`expr $y + 1`</userinput></term>
		<listitem>
		  <para>Increment a variable, with the same effect
		    as <userinput>let y=y+1</userinput> and
		    <userinput>y=$(($y+1))</userinput>. This is an
		    example of <link linkend="arithexpref">arithmetic
		    expansion</link>.</para>
		</listitem>
	      </varlistentry>

	      <varlistentry>
		<term><anchor id="expextrsub"><userinput>z=`expr substr
		$string $position $length`</userinput></term>
		<listitem>
		  <para>Extract substring of $length characters, starting
		    at $position.</para>
		</listitem>
	      </varlistentry>
	    </variablelist>

	    <example id="ex45">
	      <title>Using <firstterm>expr</firstterm></title>
	      <programlisting>&ex45;</programlisting>
	    </example>	    
	    
	    <important>
	    <para>The <link linkend="nullref">:
	      (<firstterm>null</firstterm>)</link> operator
	      can substitute for <command>match</command>. For example,
	      <userinput>b=`expr $a : [0-9]*`</userinput> is the
	      exact equivalent of <userinput>b=`expr match $a
	      [0-9]*`</userinput> in the above listing.</para>

	    <para><programlisting>&ex45a;</programlisting></para>
	      </important>

	  </listitem>
	</varlistentry>

       </variablelist>

	    <para>The above script illustrates how
	      <command>expr</command> uses the <firstterm>escaped
	      parentheses -- \( ... \) --</firstterm> grouping operator
	      in tandem with <link linkend="regexref">regular
	      expression</link> parsing to match a substring.
	      Here is a another example, this time from <quote>real
	      life.</quote>

	        <programlisting># Strip the whitespace from the beginning and end.
LRFDATE=`expr "$LRFDATE" : '[[:space:]]*\(.*\)[[:space:]]*$'`

#  From Peter Knowles' "booklistgen.sh" script
#+ for converting files to Sony Librie/PRS-50X format.
#  (http://booklistgensh.peterknowles.com)</programlisting>

	      </para>


            <para><link linkend="perlref">Perl</link>,
	      <link linkend="sedref">sed</link>, and <link
	      linkend="awkref">awk</link> have far superior string
	      parsing facilities. A short <command>sed</command> or
	      <command>awk</command> <quote>subroutine</quote> within
	      a script (see <xref linkend="wrapper">) is an attractive
	      alternative to <command>expr</command>.</para>


            <para>See <xref linkend="String-Manipulation"> for more on
              using <command>expr</command> in string operations.</para>


	</sect1> <!-- End Complex Commands -->



      <sect1 id="timedate">
        <title>Time / Date Commands</title>

       <variablelist id="tdlisting">
         <title><anchor id="tdlisting1">Time/date and timing</title>

	<varlistentry>
	  <term><anchor id="dateref"><command>date</command></term>
	  <indexterm>
	    <primary>date</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>date</secondary>
	  </indexterm>
	  <listitem>
	    <para>Simply invoked, <command>date</command> prints the date and
	      time to <filename>stdout</filename>. Where this command gets
	      interesting is in its formatting and parsing options.</para>

	    <example id="ex51">
	      <title>Using <firstterm>date</firstterm></title>
	      <programlisting>&ex51;</programlisting>
	    </example>	    	   


	    <para>The <option>-u</option> option gives the UTC (Universal
	      Coordinated Time).</para>

	      <para>
	      <screen>
<prompt>bash$ </prompt><userinput>date</userinput>
<computeroutput>Fri Mar 29 21:07:39 MST 2002</computeroutput>



<prompt>bash$ </prompt><userinput>date -u</userinput>
<computeroutput>Sat Mar 30 04:07:42 UTC 2002</computeroutput>
	      </screen>
	      </para>

	    <para>This option facilitates calculating the time between
	      different dates.</para>

	    <example id="datecalc">
	      <title><firstterm>Date</firstterm> calculations</title>
	      <programlisting>&datecalc;</programlisting>
	    </example>	    	   


	      <para><anchor id="daterandref"></para>
	      <para>The <firstterm>date</firstterm> command has quite a
		number of <firstterm>output</firstterm> options. For
		example <option>%N</option> gives the nanosecond portion
		of the current time. One interesting use for this is to
		generate random integers.

	       <programlisting>date +%N | sed -e 's/000$//' -e 's/^0//'
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#  Strip off leading and trailing zeroes, if present.
#  Length of generated integer depends on
#+ how many zeroes stripped off.

# 115281032
# 63408725
# 394504284</programlisting>
	      </para>

	      <para>There are many more options (try <command>man
	        date</command>).</para>

	      <para><programlisting>date +%j
# Echoes day of the year (days elapsed since January 1).

date +%k%M
# Echoes hour and minute in 24-hour format, as a single digit string.



# The 'TZ' parameter permits overriding the default time zone.
date                 # Mon Mar 28 21:42:16 MST 2005
TZ=EST date          # Mon Mar 28 23:42:16 EST 2005
# Thanks, Frank Kannemann and Pete Sjoberg, for the tip.


SixDaysAgo=$(date --date='6 days ago')
OneMonthAgo=$(date --date='1 month ago')  # Four weeks back (not a month!)
OneYearAgo=$(date --date='1 year ago')</programlisting></para>

              <para>See also <xref linkend="ex58"> and <xref
	       linkend="stopwatch">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="zdumpref"><command>zdump</command></term>
	  <indexterm>
	    <primary>zdump</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>time zone dump</secondary>
	  </indexterm>
	  <listitem>
	    <para>Time zone dump: echoes the time in a specified time zone.</para>
	      <para>
	      <screen><prompt>bash$ </prompt><userinput>zdump EST</userinput>
<computeroutput>EST  Tue Sep 18 22:09:22 2001 EST</computeroutput>
	      </screen>
	      </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="timref"><command>time</command></term>
	  <indexterm>
	    <primary>time</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>time</secondary>
	  </indexterm>
	  <listitem>

	    <para>Outputs verbose timing statistics for executing a command.</para>

	    <para><userinput>time ls -l /</userinput> gives something
	    like this:</para>

	    <para>
<screen><computeroutput>real    0m0.067s
 user    0m0.004s
 sys     0m0.005s</computeroutput></screen>
	  </para>

	  <para>See also the very similar <link
	    linkend="timesref">times</link> command in the previous
	    section.</para>

	  <note><para>As of <link linkend="bash2ref">version 2.0</link>
	    of Bash, <command>time</command> became a shell reserved word,
	    with slightly altered behavior in a pipeline.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="touchref"><command>touch</command></term>
	  <indexterm>
	    <primary>touch</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>touch</secondary>
	  </indexterm>
	  <listitem>

	    <para>Utility for updating access/modification times of a
	      file to current system time or other specified time,
	      but also useful for creating a new file. The command
	      <userinput>touch zzz</userinput> will create a new file
	      of zero length, named <filename>zzz</filename>, assuming
	      that <filename>zzz</filename> did not previously exist.
	      Time-stamping empty files in this way is useful for
	      storing date information, for example in keeping track of
	      modification times on a project.
	      </para>

	    <note><para>The <command>touch</command> command is
	      equivalent to <userinput>: &gt;&gt; newfile</userinput>
	      or <userinput>&gt;&gt; newfile</userinput> (for ordinary
	      files).</para></note>

	    <tip>
	    <para>Before doing a <link linkend="cpref">cp -u</link>
	      (<firstterm>copy/update</firstterm>), use
	      <command>touch</command> to update the time stamp of files
	      you don't wish overwritten.</para>
	    <para>As an example, if the directory <filename
	      class="directory">/home/bozo/tax_audit</filename> contains the
	      files <filename>spreadsheet-051606.data</filename>,
	      <filename>spreadsheet-051706.data</filename>, and
	      <filename>spreadsheet-051806.data</filename>, then
	      doing a <command>touch spreadsheet*.data</command>
	      will protect these files from being overwritten
	      by files with the same names during a
	      <command>cp -u /home/bozo/financial_info/spreadsheet*data
	      /home/bozo/tax_audit</command>.</para>
	      </tip>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="atref"><command>at</command></term>
	  <indexterm>
	    <primary>at</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>at</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>cron</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cron</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>at</command> job control command executes
	      a given set of commands at a specified time. Superficially,
	      it resembles <link linkend="cronref">cron</link>, however,
	      <command>at</command> is chiefly useful for one-time execution
	      of a command set.</para>
	  
	    <para><userinput>at 2pm January 15</userinput> prompts for a set of
	      commands to execute at that time. These commands should be
	      shell-script compatible, since, for all practical
	      purposes, the user is typing in an executable shell
	      script a line at a time.	Input terminates with a <link
	      linkend="ctldref">Ctl-D</link>.</para>

	    <para>Using either the <option>-f</option> option or input
	      redirection (<token><</token>), <command>at</command>
	      reads a command list from a file. This file is an
	      executable shell script, though it should, of course,
	      be non-interactive. Particularly clever is including the
	      <link linkend="runpartsref">run-parts</link> command in
	      the file to execute a different set of scripts.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>at 2:30 am Friday < at-jobs.list</userinput>
<computeroutput>job 2 at 2000-10-27 02:30</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="batchref"><command>batch</command></term>
	  <indexterm>
	    <primary>batch</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>batch</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>at</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>at</secondary>
	  </indexterm>
	  <listitem>

	    <para>The <command>batch</command> job control command is similar to
	      <command>at</command>, but it runs a command list when the system
	      load drops below <literal>.8</literal>. Like
	      <command>at</command>, it can read commands from a file with the
	      <option>-f</option> option.</para>

	    <para><anchor id="batchprocref"></para>

	    <sidebar>
            <para>The concept of <firstterm>batch processing</firstterm>
              dates back to the era of mainframe computers. It means
              running a set of commands without user intervention.</para>
	    </sidebar>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="calref"><command>cal</command></term>
	  <indexterm>
	    <primary>cal</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cal</secondary>
	  </indexterm>
	  <listitem>
	    <para>Prints a neatly formatted monthly calendar to
	      <filename>stdout</filename>. Will do current year or a large
	      range of past and future years.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="sleepref"><command>sleep</command></term>
	  <indexterm>
	    <primary>sleep</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sleep</secondary>
	  </indexterm>
	  <listitem>
	    <para>This is the shell equivalent of a <firstterm>wait
	      loop</firstterm>. It pauses for a specified number of
	      seconds, doing nothing. It can be useful for timing or
	      in processes running in the background, checking for
	      a specific event every so often (polling), as in <xref
	      linkend="online">.  <programlisting>sleep 3     # Pauses 3 seconds.</programlisting>
	    </para>

	    <note><para>The <command>sleep</command> command defaults to
	      seconds, but minute, hours, or days may also be specified.
	      <programlisting>sleep 3 h   # Pauses 3 hours!</programlisting>
            </para></note>

	    <note><para>The <link linkend="watchref">watch</link> command may
	      be a better choice than <command>sleep</command> for running
	      commands at timed intervals.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="usleepref"><command>usleep</command></term>
	  <indexterm>
	    <primary>usleep</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>usleep</secondary>
	  </indexterm>
	  <listitem>
	    <para><firstterm>Microsleep</firstterm> (the
	      <firstterm>u</firstterm> may be read as the Greek
	      <firstterm>mu</firstterm>, or <firstterm>micro-</firstterm>
	      prefix). This is the same as <command>sleep</command>,
	      above, but <quote>sleeps</quote> in microsecond
	      intervals. It can be used for fine-grained timing,
	      or for polling an ongoing process at very frequent
	      intervals.</para>

	    <para>  
	      <programlisting>usleep 30     # Pauses 30 microseconds.</programlisting>
	    </para>

	    <para>This command is part of the Red Hat
	    <firstterm>initscripts / rc-scripts</firstterm> package.</para>

	    <caution><para>The <command>usleep</command> command does not
	      provide particularly accurate timing, and is therefore
	      unsuitable for critical timing loops.</para></caution>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="hwclockref"><command>hwclock</command></term>
	  <term><anchor id="clockref"><command>clock</command></term>
	  <indexterm>
	    <primary>hwclock</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>hwclock</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>clock</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>clock</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>hwclock</command> command accesses or
	      adjusts the machine's hardware clock. Some options
	      require <firstterm>root</firstterm> privileges. The
	      <filename>/etc/rc.d/rc.sysinit</filename> startup file
	      uses <command>hwclock</command> to set the system time
	      from the hardware clock at bootup.</para>

	    <para>The <command>clock</command> command is a synonym for
	      <command>hwclock</command>.</para>
	  </listitem>
	</varlistentry>


       </variablelist>
       
        </sect1> <!-- End Time / Date Commands -->




      <sect1 id="textproc">
        <title>Text Processing Commands</title>

       <variablelist id="tpcommandlisting">
         <title><anchor id="tpcommandlisting1">Commands affecting text and
	   text files</title>

	<varlistentry>
	  <term><anchor id="sortref"><command>sort</command></term>
	  <indexterm>
	    <primary>sort</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sort</secondary>
	  </indexterm>
	  <listitem>
	    <para>File sort utility, often used as a filter in a pipe. This
	      command sorts a <firstterm>text stream</firstterm>
	      or file forwards or backwards, or according to various
	      keys or character positions. Using the <option>-m</option>
	      option, it merges presorted input files.	The <firstterm>info
	      page</firstterm> lists its many capabilities and options. See
	      <xref linkend="findstring">, <xref linkend="symlinks">,
	      and <xref linkend="makedict">.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="tsortref"><command>tsort</command></term>
	  <indexterm>
	    <primary>tsort</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>topological sort</secondary>
	  </indexterm>
	  <listitem>

	    <para><firstterm>Topological sort</firstterm>, reading in
	      pairs of whitespace-separated strings and sorting
	      according to input patterns. The original purpose of
	      <command>tsort</command> was to sort a list of dependencies
	      for an obsolete version of the <firstterm>ld</firstterm>
	      linker in an <quote>ancient</quote> version of UNIX.</para>

            <para>The results of a <firstterm>tsort</firstterm> will usually
	      differ markedly from those of the standard
	      <command>sort</command> command, above.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="uniqref"><command>uniq</command></term>
	  <indexterm>
	    <primary>uniq</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>uniq</secondary>
	  </indexterm>
	  <listitem>
	    <para>This filter removes duplicate lines from a sorted
	      file. It is often seen in a pipe coupled with
	      <link linkend="sortref">sort</link>.</para>

	    <para><programlisting>cat list-1 list-2 list-3 | sort | uniq > final.list
# Concatenates the list files,
# sorts them,
# removes duplicate lines,
# and finally writes the result to an output file.</programlisting></para>
 
             <para>The useful <option>-c</option> option prefixes each line of
	       the input file with its number of occurrences.</para>
	     <para>
	      <screen>
<prompt>bash$ </prompt><userinput>cat testfile</userinput>
<computeroutput>This line occurs only once.
 This line occurs twice.
 This line occurs twice.
 This line occurs three times.
 This line occurs three times.
 This line occurs three times.</computeroutput>


<prompt>bash$ </prompt><userinput>uniq -c testfile</userinput>
<computeroutput>      1 This line occurs only once.
       2 This line occurs twice.
       3 This line occurs three times.</computeroutput>


<prompt>bash$ </prompt><userinput>sort testfile | uniq -c | sort -nr</userinput>
<computeroutput>      3 This line occurs three times.
       2 This line occurs twice.
       1 This line occurs only once.</computeroutput>
	      </screen>
	     </para>

	     <para>The <userinput>sort INPUTFILE | uniq -c | sort -nr</userinput>
	       command string produces a <firstterm>frequency
	       of occurrence</firstterm> listing on the
	       <filename>INPUTFILE</filename> file (the
	       <option>-nr</option> options to <command>sort</command>
	       cause a reverse numerical sort). This template finds
	       use in analysis of log files and dictionary lists, and
	       wherever the lexical structure of a document needs to
	       be examined.</para>

	    <example id="wf">
	      <title>Word Frequency Analysis</title>
	      <programlisting>&wf;</programlisting>
	    </example>	    

	     <para>
	       <screen>
<prompt>bash$ </prompt><userinput>cat testfile</userinput>
<computeroutput>This line occurs only once.
 This line occurs twice.
 This line occurs twice.
 This line occurs three times.
 This line occurs three times.
 This line occurs three times.</computeroutput>


<prompt>bash$ </prompt><userinput>./wf.sh testfile</userinput>
<computeroutput>      6 this
       6 occurs
       6 line
       3 times
       3 three
       2 twice
       1 only
       1 once</computeroutput>
	       </screen>
	     </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="expandref"><command>expand</command></term>
	  <term><command>unexpand</command></term>
	  <indexterm>
	    <primary>expand</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>expand</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>unexpand</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>unexpand</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>expand</command> filter converts tabs to
	      spaces. It is often used in a <link
	      linkend="piperef">pipe</link>.</para>
	    <para>The <command>unexpand</command> filter
	      converts spaces to tabs. This reverses the effect of
	      <command>expand</command>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="cutref"><command>cut</command></term>
	  <indexterm>
	    <primary>cut</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cut</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>awk</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>awk</secondary>
	  </indexterm>
	  <listitem>
	    <para>A tool for extracting fields from files. It is similar to the 
	      <userinput>print $N</userinput> command set in <link
	      linkend="awkref">awk</link>, but more limited. It may be
	      simpler to use <firstterm>cut</firstterm> in a script than
	      <firstterm>awk</firstterm>. Particularly important are the
	      <option>-d</option> (delimiter) and <option>-f</option>
	      (field specifier) options.</para>

	    <para>Using <command>cut</command> to obtain a listing of the
	      mounted filesystems: 
	      <programlisting>cut -d ' ' -f1,2 /etc/mtab</programlisting></para>

	    <para>Using <command>cut</command> to list the OS and kernel version:
	      <programlisting>uname -a | cut -d" " -f1,3,11,12</programlisting></para>

	    <para>Using <command>cut</command> to extract message headers from
	      an e-mail folder:

	      <screen><prompt>bash$ </prompt><userinput>grep '^Subject:' read-messages | cut -c10-80</userinput>
<computeroutput>Re: Linux suitable for mission-critical apps?
 MAKE MILLIONS WORKING AT HOME!!!
 Spam complaint
 Re: Spam complaint</computeroutput></screen>
	    </para>

	    <para>Using <command>cut</command> to parse a file:
	      <programlisting># List all the users in /etc/passwd.

FILENAME=/etc/passwd

for user in $(cut -d: -f1 $FILENAME)
do
  echo $user
done

# Thanks, Oleg Philon for suggesting this.</programlisting></para>

	    <para><userinput>cut -d ' ' -f2,3 filename</userinput> is equivalent to
	      <userinput>awk -F'[ ]' '{ print $2, $3 }' filename</userinput></para>

            <note>
	    <para>It is even possible to specify a linefeed as a
	      delimiter. The trick is to actually embed a linefeed
	      (<keycap>RETURN</keycap>) in the command sequence.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>cut -d'
 ' -f3,7,19 testfile</userinput>
<computeroutput>This is line 3 of testfile.
 This is line 7 of testfile.
 This is line 19 of testfile.</computeroutput>
	      </screen>
	  </para>

	  <para>Thank you, Jaka Kranjc, for pointing this out.</para>
            </note>

	    <para>See also <xref linkend="base">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="pasteref"><command>paste</command></term>
	  <indexterm>
	    <primary>paste</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>paste</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>cut</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cut</secondary>
	  </indexterm>
	  <listitem>
	    <para>Tool for merging together different files into a single,
	      multi-column file.  In combination with
	      <link linkend="cutref">cut</link>, useful for creating system log
	      files.
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="joinref"><command>join</command></term>
	  <indexterm>
	    <primary>join</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>join</secondary>
	  </indexterm>
	  <listitem>
	    <para>Consider this a special-purpose cousin of
	      <command>paste</command>. This powerful utility allows
	      merging two files in a meaningful fashion, which essentially
	      creates a simple version of a relational database.</para>

	    <para>The <command>join</command> command operates on
	      exactly two files, but pastes together only those lines
	      with a common tagged field (usually a numerical label),
	      and writes the result to <filename>stdout</filename>.
	      The files to be joined should be sorted according to the
	      tagged field for the matchups to work properly.</para>

	      <para><programlisting>File: 1.data

100 Shoes
200 Laces
300 Socks</programlisting></para>
      
              <para><programlisting>File: 2.data

100 $40.00
200 $1.00
300 $2.00</programlisting></para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>join 1.data 2.data</userinput>
<computeroutput>File: 1.data 2.data

 100 Shoes $40.00
 200 Laces $1.00
 300 Socks $2.00</computeroutput>
	      </screen>
	    </para>

	    <note><para>The tagged field appears only once in the
	      output.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="headref"><command>head</command></term>
	  <indexterm>
	    <primary>head</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>head</secondary>
	  </indexterm>
	  <listitem>
	    <para>lists the beginning of a file to <filename>stdout</filename>.
	      The default is <literal>10</literal> lines, but a different
	      number can be specified. The command has a number of
	      interesting options.

	    <example id="scriptdetector">
	      <title>Which files are scripts?</title>
	      <programlisting>&scriptdetector;</programlisting>
	    </example>	    

	    <example id="rnd">
	      <title>Generating 10-digit random numbers</title>
	      <programlisting>&rnd;</programlisting>
	    </example>	    

	      See also <xref linkend="ex52">.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="tailref"><command>tail</command></term>
	  <indexterm>
	    <primary>tail</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tail</secondary>
	  </indexterm>
	  <listitem>
	    <para>lists the (tail) end of a file to <filename>stdout</filename>.
	      The default is <literal>10</literal> lines, but this can
	      be changed with the <option>-n</option> option.
	      Commonly used to keep track of
	      changes to a system logfile, using the <option>-f</option>
	      option, which outputs lines appended to the file.</para>

	   <example id="ex12">
	     <title>Using <firstterm>tail</firstterm> to monitor the system log</title>
	     <programlisting>&ex12;</programlisting>
	   </example>

	      <tip>
	      <para>To list a specific line of a text file,
	        <link linkend="piperef">pipe</link> the output of
	        <command>head</command> to <command>tail -n 1</command>.
		For example <userinput>head -n 8 database.txt | tail
		-n 1</userinput> lists the 8th line of the file
		<filename>database.txt</filename>.</para>
	      <para>To set a variable to a given block of a text file:
	        <programlisting>var=$(head -n $m $filename | tail -n $n)

# filename = name of file
# m = from beginning of file, number of lines to end of block
# n = number of lines to set variable to (trim from end of block)</programlisting></para>
	      </tip>

	      <note>
	      <para>Newer implementations of <command>tail</command>
	        deprecate the older <command>tail -$LINES
	        filename</command> usage. The standard <command>tail -n $LINES
	        filename</command> is correct.</para>
	      </note>

	      <para>See also <xref linkend="ex41">, <xref linkend="ex52"> and
		<xref linkend="online">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="grepref"><command>grep</command></term>
	  <indexterm>
	    <primary>grep</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>grep</secondary>
	  </indexterm>
	  <listitem>
	    <para>A multi-purpose file search tool that uses
	      <link linkend="regexref">Regular Expressions</link>.
	      It was originally a command/filter in the
	      venerable <command>ed</command> line editor:
	      <userinput>g/re/p</userinput> -- <firstterm>global -
	      regular expression - print</firstterm>.</para>

	    <para><cmdsynopsis>
		<command>grep</command> <arg
		choice="plain"><replaceable>pattern</replaceable></arg>
		<arg choice="opt"
		rep="repeat"><replaceable>file</replaceable></arg>
	      </cmdsynopsis>Search the target file(s) for
	      occurrences of <replaceable>pattern</replaceable>, where
	      <replaceable>pattern</replaceable> may be literal text
	      or a Regular Expression.</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>grep '[rst]ystem.$' osinfo.txt</userinput>
<computeroutput>The GPL governs the distribution of the Linux operating system.</computeroutput>
	      </screen>
	      </para>

	    <para>If no target file(s) specified, <command>grep</command>
	      works as a filter on <filename>stdout</filename>, as in
	      a <link linkend="piperef">pipe</link>.</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>ps ax | grep clock</userinput>
<computeroutput>765 tty1     S      0:00 xclock
 901 pts/1    S      0:00 grep clock</computeroutput>
	      </screen>
	      </para>

	    <para>The <option>-i</option> option causes a case-insensitive
	      search.</para>

	    <para>The <option>-w</option> option matches only whole
	      words.</para>

	    <para>The <option>-l</option> option lists only the files in which
	      matches were found, but not the matching lines.</para>

	    <para>The <option>-r</option> (recursive) option searches files in
	      the current working directory and all subdirectories below
	      it.</para>

	    <para>The <option>-n</option> option lists the matching lines,
	      together with line numbers.</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>grep -n Linux osinfo.txt</userinput>
<computeroutput>2:This is a file containing information about Linux.
 6:The GPL governs the distribution of the Linux operating system.</computeroutput>
	      </screen>
	      </para>

	    <para>The <option>-v</option> (or <option>--invert-match</option>)
	      option <firstterm>filters out</firstterm> matches.
	      <programlisting>grep pattern1 *.txt | grep -v pattern2

# Matches all lines in "*.txt" files containing "pattern1",
# but ***not*** "pattern2".	      
</programlisting></para>

	    <para>The <option>-c</option> (<option>--count</option>)
	      option gives a numerical count of matches, rather than
	      actually listing the matches.

	        <programlisting>grep -c txt *.sgml   # (number of occurrences of "txt" in "*.sgml" files)


#   grep -cz .
#            ^ dot
# means count (-c) zero-separated (-z) items matching "."
# that is, non-empty ones (containing at least 1 character).
# 
printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz .     # 3
printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '$'   # 5
printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '^'   # 5
#
printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -c '$'    # 9
# By default, newline chars (\n) separate items to match. 

# Note that the -z option is GNU "grep" specific.


# Thanks, S.C.</programlisting>
            </para>

	    <para>The <option>--color</option> (or <option>--colour</option>)
	      option marks the matching string in color (on the console
	      or in an <firstterm>xterm</firstterm> window). Since
	      <firstterm>grep</firstterm> prints out each entire line
	      containing the matching pattern, this lets you see exactly
	      <emphasis>what</emphasis> is being matched. See also
	      the <option>-o</option> option, which shows only the
	      matching portion of the line(s).</para>


	    <example id="fromsh">
	      <title>Printing out the <firstterm>From</firstterm> lines in
	        stored e-mail messages</title>
	      <programlisting>&fromsh;</programlisting>
	    </example>	    

	    <para>When invoked with more than one target file given,
	      <command>grep</command> specifies which file contains
	      matches.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>grep Linux osinfo.txt misc.txt</userinput>
<computeroutput>osinfo.txt:This is a file containing information about Linux.
 osinfo.txt:The GPL governs the distribution of the Linux operating system.
 misc.txt:The Linux operating system is steadily gaining in popularity.</computeroutput>
	      </screen>
	    </para>


	    <tip>
	    <para>To force <command>grep</command> to show the filename
	      when searching only one target file, simply give
	      <filename>/dev/null</filename> as the second file.</para>
	    <para>
	      <screen><prompt>bash$ </prompt><userinput>grep Linux osinfo.txt /dev/null</userinput>
<computeroutput>osinfo.txt:This is a file containing information about Linux.
 osinfo.txt:The GPL governs the distribution of the Linux operating system.</computeroutput>
	      </screen>
	    </para>
	    </tip>


	    <para>If there is a successful match, <command>grep</command>
	      returns an <link linkend="exitstatusref">exit status</link>
	      of 0, which makes it useful in a condition test in a
	      script, especially in combination with the <option>-q</option>
	      option to suppress output.
	        <programlisting>SUCCESS=0                      # if grep lookup succeeds
word=Linux
filename=data.file

grep -q "$word" "$filename"    #  The "-q" option
                               #+ causes nothing to echo to stdout.
if [ $? -eq $SUCCESS ]
# if grep -q "$word" "$filename"   can replace lines 5 - 7.
then
  echo "$word found in $filename"
else
  echo "$word not found in $filename"
fi</programlisting>
            </para>


	    <para><xref linkend="online"> demonstrates how to use
	      <command>grep</command> to search for a word pattern in
	      a system logfile.</para>


	    <example id="grp">
	      <title>Emulating <firstterm>grep</firstterm> in a script</title>
	      <programlisting>&grp;</programlisting>
	    </example>	    	   

	    <para>How can <command>grep</command> search for two (or
	      more) separate patterns? What if you want
	      <command>grep</command> to display all lines in a file
	      or files that contain both <quote>pattern1</quote>
	      <emphasis>and</emphasis> <quote>pattern2</quote>?</para>

	    <para>One method is to <link
	      linkend="piperef">pipe</link> the result of <command>grep
	      pattern1</command> to <command>grep pattern2</command>.</para>

            <para>For example, given the following file:</para>

            <para>
	    <programlisting># Filename: tstfile

This is a sample file.
This is an ordinary text file.
This file does not contain any unusual text.
This file is not unusual.
Here is some text.</programlisting>
            </para>

            <para>Now, let's search this file for lines containing
	      <emphasis>both</emphasis> <quote>file</quote> and
	      <quote>text</quote> . . . </para>

	      <screen><prompt>bash$ </prompt><userinput>grep file tstfile</userinput>
<computeroutput># Filename: tstfile
 This is a sample file.
 This is an ordinary text file.
 This file does not contain any unusual text.
 This file is not unusual.</computeroutput>

<prompt>bash$ </prompt><userinput>grep file tstfile | grep text</userinput>
<computeroutput>This is an ordinary text file.
 This file does not contain any unusual text.</computeroutput></screen>

            <para>Now, for an interesting recreational use
	      of <firstterm>grep</firstterm> . . .</para>


	    <example id="cwsolver">
	      <title>Crossword puzzle solver</title>
	      <programlisting>&cwsolver;</programlisting>
	    </example>	    



	    <para><anchor id="egrepref"><command>egrep</command>
	      -- <firstterm>extended grep</firstterm> -- is the same
	      as <command>grep -E</command>. This uses a somewhat
	      different, extended set of <link linkend="regexref">Regular
	      Expressions</link>, which can make the search a bit more
	      flexible. It also allows the boolean |
	      (<firstterm>or</firstterm>) operator.
	      <screen><prompt>bash $ </prompt><userinput>egrep 'matches|Matches' file.txt</userinput>
<computeroutput>Line 1 matches.
 Line 3 Matches.
 Line 4 contains matches, but also Matches</computeroutput>
              </screen>
	      </para>

	    <para><anchor id="fgrepref"><command>fgrep</command> --
	      <firstterm>fast grep</firstterm> -- is the same as
	      <command>grep -F</command>. It does a literal string search
	      (no <link linkend="regexref">Regular Expressions</link>),
	      which generally speeds things up a bit.</para>

            <note><para>On some Linux distros, <command>egrep</command> and
	      <command>fgrep</command> are symbolic links to, or aliases for
	      <command>grep</command>, but invoked with the
	      <option>-E</option> and <option>-F</option> options,
	      respectively.</para></note>

	    <example id="dictlookup">
	      <title>Looking up definitions in <citetitle
	      pubwork="book">Webster's 1913 Dictionary</citetitle></title>
	      <programlisting>&dictlookup;</programlisting>
	    </example>

	    <note><para>See also <xref linkend="qky"> for an example
	      of speedy <firstterm>fgrep</firstterm> lookup on a large
	      text file.</para></note>

	    <para><anchor id="agrepref"></para>
	    <para><command>agrep</command> (<firstterm>approximate
	      grep</firstterm>) extends the capabilities of
	      <command>grep</command> to approximate matching. The search
	      string may differ by a specified number of characters
	      from the resulting matches. This utility is not part of
	      the core Linux distribution.</para>


	    <para><anchor id="zegrepref"></para>
	    <tip> <para>To search compressed files, use
	      <command>zgrep</command>, <command>zegrep</command>, or
	      <command>zfgrep</command>. These also work on non-compressed
	      files, though slower than plain <command>grep</command>,
	      <command>egrep</command>, <command>fgrep</command>.
	      They are handy for searching through a mixed set of files,
	      some compressed, some not.</para>
	    <para><anchor id="bzgrepref"></para>
	    <para>To search <link linkend="bzipref">bzipped</link>
	      files, use <command>bzgrep</command>.</para> </tip>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="lookref"><command>look</command></term>
	  <indexterm>
	    <primary>look</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>look</secondary>
	  </indexterm>
	  <listitem>
	    <para>The command <command>look</command> works like
	      <command>grep</command>, but does a lookup on
	      a <quote>dictionary,</quote> a sorted word list.
	      By default, <command>look</command> searches for a match
	      in <filename>/usr/dict/words</filename>, but a different
	      dictionary file may be specified.</para>

	    <example id="lookup">
	      <title>Checking words in a list for validity</title>
	      <programlisting>&lookup;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><command>sed</command></term>
	  <term><command>awk</command></term>
	  <indexterm>
	    <primary>sed</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sed</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>awk</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>awk</secondary>
	  </indexterm>
	  <listitem>
	    <para>Scripting languages especially suited for parsing text
	      files and command output. May be embedded singly or in
	      combination in pipes and shell scripts.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><command><link linkend="sedref">sed</link></command></term>
	  <listitem>
	    <para>Non-interactive <quote>stream editor</quote>, permits using
	      many <command>ex</command> commands in <link
	      linkend="batchprocref">batch</link> mode. It finds many
	      uses in shell scripts.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><command><link linkend="awkref">awk</link></command></term>
	  <listitem>
	    <para>Programmable file extractor and formatter, good for
	      manipulating and/or extracting fields (columns) in
	      structured text files. Its syntax is similar to C.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="wcref"><command>wc</command></term>
	  <indexterm>
	    <primary>wc</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>wc</secondary>
	  </indexterm>
	  <listitem>

	    <para><firstterm>wc</firstterm> gives a <quote>word
	      count</quote> on a file or I/O stream:

	      <screen><prompt>bash $ </prompt><userinput>wc /usr/share/doc/sed-4.1.2/README</userinput>
<computeroutput>13  70  447 README</computeroutput>
[13 lines  70 words  447 characters]</screen></para>

	    <para><userinput>wc -w</userinput> gives only the word count.</para>
	    <para><userinput>wc -l</userinput> gives only the line count.</para>
	    <para><userinput>wc -c</userinput> gives only the byte count.</para>
	    <para><userinput>wc -m</userinput> gives only the character count.</para>
	    <para><userinput>wc -L</userinput> gives only the length of the longest line.</para>

            <para>Using <command>wc</command> to count how many
	    <filename>.txt</filename> files are in current working directory:
	      <programlisting>$ ls *.txt | wc -l
#  Will work as long as none of the "*.txt" files
#+ have a linefeed embedded in their name.

#  Alternative ways of doing this are:
#      find . -maxdepth 1 -name \*.txt -print0 | grep -cz .
#      (shopt -s nullglob; set -- *.txt; echo $#)

#  Thanks, S.C.</programlisting>
	    </para>

	    <para>Using <command>wc</command> to total up the size of all the
	      files whose names begin with letters in the range d - h
	      <screen><prompt>bash$ </prompt><userinput>wc [d-h]* | grep total | awk '{print $3}'</userinput>
<computeroutput>71832</computeroutput>
	      </screen>
	    </para>

	    <para>Using <command>wc</command> to count the instances of the
	      word <quote>Linux</quote> in the main source file for
	      this book.
	      <screen><prompt>bash$ </prompt><userinput>grep Linux abs-book.sgml | wc -l</userinput>
<computeroutput>50</computeroutput>
	      </screen>
	    </para>

	    <para>See also <xref linkend="ex52"> and <xref
	    linkend="redir4">.</para>

	    <para>Certain commands include some of the
	      functionality of <command>wc</command> as options.
	      
	    <programlisting>... | grep foo | wc -l
# This frequently used construct can be more concisely rendered.

... | grep -c foo
# Just use the "-c" (or "--count") option of grep.

# Thanks, S.C.</programlisting></para>

	  </listitem>
	</varlistentry>

	
	<varlistentry>
	  <term><anchor id="trref"><command>tr</command></term>
	  <indexterm>
	    <primary>tr</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tr</secondary>
	  </indexterm>
	  <listitem>
	    <para>character translation filter.</para>
	    
	    <caution><para><link linkend="ucref">Must use quoting and/or
	      brackets</link>, as appropriate. Quotes prevent the
	      shell from reinterpreting the special characters in
	      <command>tr</command> command sequences. Brackets should be
	      quoted to prevent expansion by the shell.  </para></caution>

	    <para>Either <userinput>tr "A-Z" "*" &lt;filename</userinput>
	      or <userinput>tr A-Z \* &lt;filename</userinput> changes
	      all the uppercase letters in <filename>filename</filename>
	      to asterisks (writes to <filename>stdout</filename>).
	      On some systems this may not work, but <userinput>tr A-Z
	      '[**]'</userinput> will.</para>

	    <para><anchor id="troptions"></para>
	    <para>The <option>-d</option> option deletes a range of
	      characters.
	    <programlisting>echo "abcdef"                 # abcdef
echo "abcdef" | tr -d b-d     # aef


tr -d 0-9 &lt;filename
# Deletes all digits from the file "filename".</programlisting></para>

            <para>The <option>--squeeze-repeats</option> (or
              <option>-s</option>) option deletes all but the
              first instance of a string of consecutive characters.
              This option is useful for removing excess <link
              linkend="whitespaceref">whitespace</link>.



	      <screen><prompt>bash$ </prompt><userinput>echo "XXXXX" | tr --squeeze-repeats 'X'</userinput>
<computeroutput>X</computeroutput></screen></para>

	    <para>The <option>-c</option> <quote>complement</quote>
	      option <firstterm>inverts</firstterm> the character set to
	      match. With this option, <command>tr</command> acts only
	      upon those characters <emphasis>not</emphasis> matching
	      the specified set.</para>

            <para>
	      <screen><prompt>bash$ </prompt><userinput>echo "acfdeb123" | tr -c b-d +</userinput>
<computeroutput>+c+d+b++++</computeroutput></screen>
            </para>



            <para>Note that <command>tr</command> recognizes <link
	      linkend="posixref">POSIX character classes</link>.
	         <footnote><para>This is only true of the GNU version of
		 <command>tr</command>, not the generic version often found on
		 commercial UNIX systems.</para></footnote>
	      </para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>echo "abcd2ef1" | tr '[:alpha:]' -</userinput>
<computeroutput>----2--1</computeroutput>
	      </screen>
	    </para>

	    <example id="ex49">
	      <title><firstterm>toupper</firstterm>: Transforms a file
	      to all uppercase.</title>
	      <programlisting>&ex49;</programlisting>
	    </example>	    


	    <example id="lowercase">
	      <title><firstterm>lowercase</firstterm>: Changes all
	      filenames in working directory to lowercase.</title>
	      <programlisting>&lowercase;</programlisting>
	    </example>	    

	    <para><anchor id="trd2u"></para>
	    <example id="du">
	      <title><firstterm>du</firstterm>: DOS to UNIX text file conversion.</title>
	      <programlisting>&du;</programlisting>
	    </example>	    

	    <example id="rot13">
	      <title><firstterm>rot13</firstterm>: ultra-weak encryption.</title>
	      <programlisting>&rot13;</programlisting>
	    </example>	    

	    <example id="cryptoquote">
	      <title>Generating <quote>Crypto-Quote</quote> Puzzles</title>
	      <programlisting>&cryptoquote;</programlisting>
	    </example>


	    <para><anchor id="trvariants"></para>
	    <sidebar><title><firstterm>tr</firstterm> variants</title>
	    <para>
	    The <command>tr</command> utility has two historic
	    variants. The BSD version does not use brackets
	    (<userinput>tr a-z A-Z</userinput>), but the SysV one does
	    (<userinput>tr '[a-z]' '[A-Z]'</userinput>). The GNU version
	    of <command>tr</command> resembles the BSD one.
	    </para>
	    </sidebar>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="foldref"><command>fold</command></term>
	  <indexterm>
	    <primary>fold</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>fold</secondary>
	  </indexterm>
	  <listitem>
	    <para>A filter that wraps lines of input to a specified width.
	      This is especially useful with the <option>-s</option>
	      option, which breaks lines at word spaces (see <xref
	      linkend="ex50"> and <xref linkend="mailformat">).</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="fmtref"><command>fmt</command></term>
	  <indexterm>
	    <primary>fmt</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>fmt</secondary>
	  </indexterm>
	  <listitem>
	    <para>Simple-minded file formatter, used as a filter in a
	      pipe to <quote>wrap</quote> long lines of text
	      output.</para>

	    <example id="ex50">
	      <title>Formatted file listing.</title>
	      <programlisting>&ex50;</programlisting>
	    </example>	    

	    <para>See also <xref linkend="ex41">.</para>

	    <tip><para>A powerful alternative to <command>fmt</command> is
	      Kamil Toman's <command>par</command>
	      utility, available from <ulink
	      url="http://www.cs.berkeley.edu/~amc/Par/">http://www.cs.berkeley.edu/~amc/Par/</ulink>.
	      </para></tip>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="colref"><command>col</command></term>
	  <indexterm>
	    <primary>col</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>reverse line feed</secondary>
	  </indexterm>
	  <listitem>
	    <para>This deceptively named filter removes reverse line feeds
	      from an input stream. It also attempts to replace
	      whitespace with equivalent tabs. The chief use of
	      <command>col</command> is in filtering the output
	      from certain text processing utilities, such as
	      <command>groff</command> and <command>tbl</command>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="columnref"><command>column</command></term>
	  <indexterm>
	    <primary>column</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>column</secondary>
	  </indexterm>
	  <listitem>
	    <para>Column formatter. This filter transforms list-type
	      text output into a <quote>pretty-printed</quote> table
	      by inserting tabs at appropriate places.</para>

	    <example id="col">
	      <title>Using <firstterm>column</firstterm> to format a directory
	        listing</title>
	      <programlisting>&colm;</programlisting>
	    </example>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="colrmref"><command>colrm</command></term>
	  <indexterm>
	    <primary>colrm</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>colrm</secondary>
	  </indexterm>
	  <listitem>
	    <para>Column removal filter. This removes columns (characters)
	      from a file and writes the file, lacking the range of
	      specified columns, back to <filename>stdout</filename>.
	      <userinput>colrm 2 4 &lt;filename</userinput> removes the
	      second through fourth characters from each line of the
	      text file <filename>filename</filename>.</para>
	    <caution><para>If the file contains tabs or nonprintable
	      characters, this may cause unpredictable
	      behavior. In such cases, consider using
	      <link linkend="expandref">expand</link> and
	      <command>unexpand</command> in a pipe preceding
	      <command>colrm</command>.</para></caution>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="nlref"><command>nl</command></term>
	  <indexterm>
	    <primary>nl</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>fmt</secondary>
	  </indexterm>
	  <listitem>
	    <para>Line numbering filter: <userinput>nl filename</userinput>
	    lists <filename>filename</filename> to
	    <filename>stdout</filename>, but inserts consecutive
	    numbers at the beginning of each non-blank line. If
	    <filename>filename</filename> omitted, operates on
	    <filename>stdin.</filename></para>

	    <para>The output of <command>nl</command> is very similar to
	      <userinput>cat -b</userinput>, since, by default
	      <command>nl</command> does not list blank lines.</para>

	    <example id="lnum">
	      <title><firstterm>nl</firstterm>: A self-numbering script.</title>
	      <programlisting>&lnum;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="prref"><command>pr</command></term>
	  <indexterm>
	    <primary>pr</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>pr</secondary>
	  </indexterm>
	  <listitem>
	    <para>Print formatting filter. This will paginate files
	      (or <filename>stdout</filename>) into sections suitable for
	      hard copy printing or viewing on screen.	Various options
	      permit row and column manipulation, joining lines, setting
	      margins, numbering lines, adding page headers, and merging
	      files, among other things. The <command>pr</command>
	      command combines much of the functionality of
	      <command>nl</command>, <command>paste</command>,
	      <command>fold</command>, <command>column</command>, and
	      <command>expand</command>.</para>

	   <para><userinput>pr -o 5 --width=65 fileZZZ | more</userinput>
	     gives a nice paginated listing to screen of
	     <filename>fileZZZ</filename> with margins set at 5 and
	     65.</para>

	    <para>A particularly useful option is <option>-d</option>,
	      forcing double-spacing (same effect as <command>sed
	      -G</command>).</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="gettextref"><command>gettext</command></term>
	  <indexterm>
	    <primary>gettext</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>localization</secondary>
	  </indexterm>
	  <listitem>

	    <para>The GNU <command>gettext</command> package is a set of
	      utilities for <link linkend="localization">localizing</link>
	      and translating the text output of programs into foreign
	      languages. While originally intended for C programs, it
	      now supports quite a number of programming and scripting
	      languages.</para>

	    <para>The  <command>gettext</command>
	      <emphasis>program</emphasis> works on shell scripts. See
	      the <replaceable>info page</replaceable>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="msgfmtref"><command>msgfmt</command></term>
	  <indexterm>
	    <primary>msgfmt</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>localization</secondary>
	  </indexterm>
	  <listitem>
	    <para>A program for generating binary
	      message catalogs. It is used for <link
	      linkend="localization">localization</link>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="iconvref"><command>iconv</command></term>
	  <indexterm>
	    <primary>iconv</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>encoding</secondary>
	  </indexterm>
	  <listitem>

	    <para>A utility for converting file(s) to a different encoding
	      (character set). Its chief use is for <link
	      linkend="localization">localization</link>.</para>

	    <para>
	    <programlisting># Convert a string from UTF-8 to UTF-16 and print to the BookList
function write_utf8_string {
    STRING=$1
    BOOKLIST=$2
    echo -n "$STRING" | iconv -f UTF8 -t UTF16 | \
    cut -b 3- | tr -d \\n >> "$BOOKLIST"
}

#  From Peter Knowles' "booklistgen.sh" script
#+ for converting files to Sony Librie/PRS-50X format.
#  (http://booklistgensh.peterknowles.com)</programlisting>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="recoderef"><command>recode</command></term>
	  <indexterm>
	    <primary>recode</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>encoding</secondary>
	  </indexterm>
	  <listitem>
	    <para>Consider this a fancier version of
	      <command>iconv</command>, above. This very versatile utility
	      for converting a file to a different encoding scheme.
	      Note that <firstterm>recode</firstterm> is not part of the
	      standard Linux installation.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="texref"><command>TeX</command></term>
	  <term><anchor id="gsref"><command>gs</command></term>
	  <indexterm>
	    <primary>TeX</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>TeX</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>gs</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>Postscript</secondary>
	  </indexterm>
	  <listitem>

	    <para><command>TeX</command> and <command>Postscript</command>
	      are text markup languages used for preparing copy for
	      printing or formatted video display.</para>
		
	      <para><command>TeX</command> is Donald Knuth's elaborate
		typsetting system. It is often convenient to write a
		shell script encapsulating all the options and arguments
		passed to one of these markup languages.</para>

	      <para><firstterm>Ghostscript</firstterm>
		(<command>gs</command>) is a GPL-ed Postscript
		interpreter.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="texexecref"><command>texexec</command></term>
	  <indexterm>
	    <primary>texexec</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>pdf</secondary>
	  </indexterm>
	  <listitem>

	    <para>Utility for processing <firstterm>TeX</firstterm> and
	      <firstterm>pdf</firstterm> files. Found in
	      <filename class="directory">/usr/bin</filename>
	      on many Linux distros, it is actually a <link
	      linkend="shwrapper">shell wrapper</link> that
	      calls <link linkend="perlref">Perl</link> to invoke
	      <firstterm>Tex</firstterm>.</para>

            <para>
	    <programlisting>texexec --pdfarrange --result=Concatenated.pdf *pdf

#  Concatenates all the pdf files in the current working directory
#+ into the merged file, Concatenated.pdf . . .
#  (The --pdfarrange option repaginates a pdf file. See also --pdfcombine.)
#  The above command line could be parameterized and put into a shell script.</programlisting> 
            </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="enscriptref"><command>enscript</command></term>
	  <indexterm>
	    <primary>enscript</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>PostScript</secondary>
	  </indexterm>
	  <listitem>
	    <para>Utility for converting plain text file to PostScript</para>
	    <para>For example, <command>enscript filename.txt -p filename.ps</command>
	      produces the PostScript output file
	      <filename>filename.ps</filename>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="groffref"><command>groff</command></term>
	  <term><anchor id="tblref"><command>tbl</command></term>
	  <term><anchor id="eqnref"><command>eqn</command></term>
	  <indexterm>
	    <primary>groff</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>groff</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>tbl</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>table</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>eqn</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>equation</secondary>
	  </indexterm>
	  <listitem>

            <para>Yet another text markup and display formatting language
	      is <command>groff</command>. This is the enhanced GNU version
	      of the venerable UNIX <command>roff/troff</command> display
	      and typesetting package. <link linkend="manref">Manpages</link>
	      use <command>groff</command>.</para>

	    <para>The <command>tbl</command> table processing utility
	      is considered part of <command>groff</command>, as its
	      function is to convert table markup into
	      <command>groff</command> commands.</para>

	    <para>The <command>eqn</command> equation processing utility
	      is likewise part of <command>groff</command>, and
	      its function is to convert equation markup into
	      <command>groff</command> commands.</para>

    <example id="manview">
      <title><firstterm>manview</firstterm>: Viewing formatted manpages</title>
      <programlisting>&manview;</programlisting>
    </example>

	    <para>See also <xref linkend="maned">.</para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="lexref"><command>lex</command></term>
	  <term><anchor id="yaccref"><command>yacc</command></term>
	  <indexterm>
	    <primary>lex</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>flex</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>yacc</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>bison</secondary>
	  </indexterm>
	  <listitem>
	    <para><anchor id="flexref"></para>
	    <para>The <command>lex</command> lexical analyzer produces
	      programs for pattern matching. This has been replaced
	      by the nonproprietary <command>flex</command> on Linux
	      systems.</para>
	    <para><anchor id="bisonref"></para>
	    <para>The <command>yacc</command> utility creates a
	      parser based on a set of specifications. This has been
	      replaced by the nonproprietary <command>bison</command>
	      on Linux systems.</para>
	  </listitem>
	</varlistentry>

       </variablelist>

        </sect1> <!-- End Text Processing Commands -->


      <sect1 id="filearchiv">
        <title>File and Archiving Commands</title>

       <variablelist id="faarchiving">
         <title><anchor id="faarchiving1">Archiving</title>

	<varlistentry>
	  <term><anchor id="tarref"><command>tar</command></term>
	  <indexterm>
	    <primary>tar</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tar</secondary>
	  </indexterm>
	  <listitem>

	    <para>The standard UNIX archiving utility.

	        <footnote><para>An <firstterm>archive</firstterm>,
	        in the sense discussed here, is simply a set of related
	        files stored in a single location.</para></footnote>

	      Originally a
	      <wordasword>Tape ARchiving</wordasword> program, it has
	      developed into a general purpose package that can handle
	      all manner of archiving with all types of destination
	      devices, ranging from tape drives to regular files to even
	      <filename>stdout</filename> (see <xref linkend="ex58">). GNU
	      <firstterm>tar</firstterm> has been patched to accept
	      various compression filters, for example: <command>tar
	      czvf archive_name.tar.gz *</command>, which recursively
	      archives and <link linkend="gzipref">gzips</link>
	      all files in a directory tree except <link
	      linkend="dotfilesref">dotfiles</link> in the current
	      working directory (<link linkend="pwdref">$PWD</link>).

		<footnote>
		  <para>
		    A <replaceable>tar czvf ArchiveName.tar.gz *</replaceable>
		    <emphasis>will</emphasis> include dotfiles in
		    subdirectories <emphasis>below</emphasis> the current
		    working directory. This is an undocumented GNU
		    <command>tar</command> <quote>feature.</quote>
		  </para>
		</footnote>
            </para>		
		

	    <para>Some useful <command>tar</command> options:  
	      <orderedlist>

		<listitem><para><option>-c</option> create (a new
		  archive)</para></listitem>

		<listitem><para><option>-x</option> extract (files from
		  existing archive)</para></listitem>

		<listitem>
		<para><option>--delete</option> delete (files
		  from existing archive)</para>
		<caution><para>This option will not work on magnetic tape
		  devices.</para></caution>  
		  </listitem>

		<listitem><para><option>-r</option> append (files to
		  existing archive)</para></listitem>

		<listitem><para><option>-A</option> append
		  (<firstterm>tar</firstterm> files to
		  existing archive)</para></listitem>

		<listitem><para><option>-t</option> list (contents of
                  existing archive)</para></listitem>

	        <listitem><para><option>-u</option> update archive</para></listitem>

	        <listitem><para><option>-d</option> compare archive with
		  specified filesystem</para></listitem>

	        <listitem><para><option>--after-date</option> only process
		  files with a date stamp <emphasis>after</emphasis>
		  specified date</para></listitem>

		<listitem>
		<para><option>-z</option> <link
		  linkend="gzipref">gzip</link> the archive</para>
		<para>(compress or uncompress, depending on whether
		combined with the <option>-c</option> or
		<option>-x</option>) option</para>
		</listitem>

		<listitem><para><option>-j</option>
		  <link linkend="bzipref">bzip2</link> the
		  archive</para></listitem>

	      </orderedlist>
	      </para>

	    <caution><para>It may be difficult to recover data from a
	      corrupted <firstterm>gzipped</firstterm> tar
	      archive. When archiving important files, make multiple
	      backups.</para></caution>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="sharref"><command>shar</command></term>
	  <indexterm>
	    <primary>shar</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>archive</secondary>
	  </indexterm>
	  <listitem>

	    <para><firstterm>Shell archiving</firstterm> utility.
	      The text files in a shell archive are concatenated
	      without compression, and the resultant archive
	      is essentially a shell script, complete with
	      <token>#!/bin/sh</token> header, containing all the
	      necessary unarchiving commands, as well as the files
	      themselves. <firstterm>Shar archives</firstterm>
	      still show up in Usenet newsgroups, but otherwise
	      <command>shar</command> has been replaced by
	      <command>tar</command>/<command>gzip</command>. The
	      <command>unshar</command> command unpacks
	      <firstterm>shar</firstterm> archives.</para>
	    <para>The <command>mailshar</command> command
	      is a Bash script that uses <command>shar</command> to
	      concatenate multiple files into a single one for e-mailing.
	      This script supports compression and <link
	      linkend="uuencoderef">uuencoding</link>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="arref"><command>ar</command></term>
	  <indexterm>
	    <primary>ar</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>archive</secondary>
	  </indexterm>
	  <listitem>
	    <para>Creation and manipulation utility for archives, mainly
	      used for binary object file libraries.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rpmref"><command>rpm</command></term>
	  <indexterm>
	    <primary>rpm</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>package manager</secondary>
	  </indexterm>
	  <listitem>

	    <para>The <firstterm>Red Hat Package Manager</firstterm>, or
	      <command>rpm</command> utility provides a wrapper for
	      source or binary archives. It includes commands for
	      installing and checking the integrity of packages, among
	      other things.</para>

	    <para>A simple <command>rpm -i package_name.rpm</command>
	      usually suffices to install a package, though there are many
	      more options available.</para>


	    <tip>
	    <para><userinput>rpm -qf</userinput> identifies which package a
	      file originates from.</para>

	  <para>
	      <screen>
<prompt>bash$ </prompt><userinput>rpm -qf /bin/ls</userinput>
<computeroutput>coreutils-5.2.1-31</computeroutput>
	      </screen>
	    </para>
	    </tip>

	    <tip>
	    <para><userinput>rpm -qa</userinput> gives a
	      complete list of all installed <firstterm>rpm</firstterm> packages
	      on a given system. An <userinput>rpm -qa package_name</userinput>
	      lists only the package(s) corresponding to
	      <filename>package_name</filename>.</para>

	  <para>
	      <screen>
<prompt>bash$ </prompt><userinput>rpm -qa</userinput>
<computeroutput>redhat-logos-1.1.3-1
 glibc-2.2.4-13
 cracklib-2.7-12
 dosfstools-2.7-1
 gdbm-1.8.0-10
 ksymoops-2.4.1-1
 mktemp-1.5-11
 perl-5.6.0-17
 reiserfs-utils-3.x.0j-2
 ...</computeroutput>


<prompt>bash$ </prompt><userinput>rpm -qa docbook-utils</userinput>
<computeroutput>docbook-utils-0.6.9-2</computeroutput>


<prompt>bash$ </prompt><userinput>rpm -qa docbook | grep docbook</userinput>
<computeroutput>docbook-dtd31-sgml-1.0-10
 docbook-style-dsssl-1.64-3
 docbook-dtd30-sgml-1.0-10
 docbook-dtd40-sgml-1.0-11
 docbook-utils-pdf-0.6.9-2
 docbook-dtd41-sgml-1.0-10
 docbook-utils-0.6.9-2</computeroutput>
	      </screen>
	    </para>
	    </tip>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="cpioref"><command>cpio</command></term>
	  <indexterm>
	    <primary>cpio</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cpio</secondary>
	  </indexterm>
	  <listitem>
	    <para>This specialized archiving copy command
	      (<command>c</command>o<command>p</command>y
	      <command>i</command>nput and <command>o</command>utput)
	      is rarely seen any more, having been supplanted by
	      <command>tar</command>/<command>gzip</command>. It still
	      has its uses, such as moving a directory tree. With an
	      appropriate block size (for copying) specified, it
	      can be appreciably faster than <command>tar</command>.</para>

	    <example id="ex48">
	      <title>Using <firstterm>cpio</firstterm> to move a directory tree</title>
	      <programlisting>&ex48;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rpm2cpioref"><command>rpm2cpio</command></term>
	  <indexterm>
	    <primary>rpm</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cpio</secondary>
	  </indexterm>
	  <listitem>
	    <para>This command extracts a
	      <command>cpio</command> archive from an <link
	      linkend="rpmref">rpm</link> one.</para>

	    <example id="derpm">
	      <title>Unpacking an <firstterm>rpm</firstterm> archive</title>
	      <programlisting>&derpm;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="facompression">
        <title><anchor id="facompression1">Compression</title>

	<varlistentry>
	  <term><anchor id="gzipref"><command>gzip</command></term>
	  <indexterm>
	    <primary>gzip</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>gzip</secondary>
	  </indexterm>
	  <listitem>

	    <para>The standard GNU/UNIX compression utility, replacing
	      the inferior and proprietary
	      <command>compress</command>. The corresponding decompression
	      command is <command>gunzip</command>, which is the equivalent of
	      <command>gzip -d</command>.</para>

            <note><para>The <option>-c</option> option sends the output of
	      <command>gzip</command> to <filename>stdout</filename>. This
	      is useful when <link linkend="piperef">piping</link> to other
	      commands.</para></note>

	    <para><anchor id="zcatref"></para>
	    <para>The <command>zcat</command> filter decompresses a
	      <firstterm>gzipped</firstterm> file to
	      <filename>stdout</filename>, as possible input to a pipe or
	      redirection. This is, in effect, a <command>cat</command>
	      command that works on compressed files (including files
	      processed with the older <link
	      linkend="compressref">compress</link>
	      utility). The <command>zcat</command> command is equivalent to
	      <command>gzip -dc</command>.</para>


	    <caution><para>On some commercial UNIX systems, <command>zcat</command>
	      is a synonym for <command>uncompress -c</command>,
	      and will not work on <firstterm>gzipped</firstterm>
	      files.</para></caution>

	      <para>See also <xref linkend="ex14">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="bzipref"><command>bzip2</command></term>
	  <indexterm>
	    <primary>bzip2</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>bzip2</secondary>
	  </indexterm>
	  <listitem>

	    <para>An alternate compression utility, usually more efficient
	      (but slower) than <command>gzip</command>, especially on
	      large files. The corresponding decompression command is
	      <command>bunzip2</command>.</para>

	    <note><para>Newer versions of <link
	      linkend="tarref">tar</link> have been patched with
	      <command>bzip2</command> support.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="compressref"><command>compress</command></term>
	  <term><anchor id="uncompressref"><command>uncompress</command></term>
	  <indexterm>
	    <primary>compress</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>compress</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>uncompress</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>uncompress</secondary>
	  </indexterm>
	  <listitem>
	    <para>This is an older, proprietary compression
	      utility found in commercial UNIX distributions. The
	      more efficient <command>gzip</command> has largely
	      replaced it. Linux distributions generally include a
	      <command>compress</command> workalike for compatibility,
	      although <command>gunzip</command> can unarchive files
	      treated with <command>compress</command>.</para>

	    <tip><para>The <command>znew</command> command transforms
	      <firstterm>compressed</firstterm> files into
	      <firstterm>gzipped</firstterm> ones.</para></tip>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="sqref"><command>sq</command></term>
	  <indexterm>
	    <primary>sq</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sq</secondary>
	  </indexterm>
	  <listitem>

	    <para>Yet another compression (<command>sq</command>ueeze)
	      utility, a filter that works only on sorted
	      ASCII word lists. It uses the standard invocation
	      syntax for a filter, <command>sq < input-file >
	      output-file</command>.  Fast, but not nearly as efficient
	      as <link linkend="gzipref">gzip</link>.  The corresponding
	      uncompression filter is <command>unsq</command>, invoked
	      like <command>sq</command>.</para>

	      <tip><para>The output of <command>sq</command> may be
	        piped to <command>gzip</command> for further
		compression.</para></tip>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="zipref"><command>zip</command></term>
	  <term><command>unzip</command></term>
	  <indexterm>
	    <primary>zip</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>pkzip.exe</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>unzip</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>unzip</secondary>
	  </indexterm>
	  <listitem>
	    <para>Cross-platform file archiving and compression utility
	      compatible with DOS <firstterm>pkzip.exe</firstterm>.
	      <quote>Zipped</quote> archives seem to be a more
	      common medium of file exchange on the Internet than
	      <quote>tarballs.</quote></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="unarcref"><command>unarc</command></term>
	  <term><command>unarj</command></term>
	  <term><command>unrar</command></term>
	  <indexterm>
	    <primary>unarc</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>arc.exe</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>unarj</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>arj.exe</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>unrar</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>rar.exe</secondary>
	  </indexterm>
	  <listitem>
	    <para>These Linux utilities permit unpacking archives
	      compressed with the DOS <firstterm>arc.exe</firstterm>,
	      <firstterm>arj.exe</firstterm>, and
	      <firstterm>rar.exe</firstterm> programs.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lzmaref"><command>lzma</command></term>
	  <term><command>unlzma</command></term>
	  <term><command>lzcat</command></term>
	  <indexterm>
	    <primary>lzma</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>lzma</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>unlzma</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>unlzma</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>lzcat</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>lzcat</secondary>
	  </indexterm>
	  <listitem>
	    <para>Highly efficient Lempel-Ziv-Markov compression.
	      The syntax of <firstterm>lzma</firstterm> is similar to
              that of <firstterm>gzip</firstterm>. The <ulink
              url="http://www.7-zip.org/sdk.html">7-zip Website</ulink>
              has more information.</para>

	  </listitem>
	</varlistentry>


      </variablelist>


      <variablelist id="fainformation">
        <title><anchor id="fainformation1">File Information</title>

	<varlistentry>
	  <term><anchor id="fileref"><command>file</command></term>
	  <indexterm>
	    <primary>file</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>file</secondary>
	  </indexterm>
	  <listitem>

	    <para>A utility for identifying file types. The command
	      <userinput>file file-name</userinput> will return a
	      file specification for <filename>file-name</filename>,
	      such as <computeroutput>ascii text</computeroutput> or
	      <computeroutput>data</computeroutput>. It references
	      the <link linkend="magnumref">magic numbers</link>
	      found in <filename>/usr/share/magic</filename>,
	      <filename>/etc/magic</filename>, or
	      <filename>/usr/lib/magic</filename>, depending on the
	      Linux/UNIX distribution.</para>

	    <para>The <option>-f</option> option causes
	      <command>file</command> to run in <link
	      linkend="batchprocref">batch</link> mode, to read from
	      a designated file a list of filenames to analyze. The
	      <option>-z</option> option, when used on a compressed
	      target file, forces an attempt to analyze the uncompressed
	      file type.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>file test.tar.gz</userinput>
<computeroutput>test.tar.gz: gzip compressed data, deflated,
 last modified: Sun Sep 16 13:34:51 2001, os: Unix</computeroutput>

<prompt>bash </prompt><userinput>file -z test.tar.gz</userinput>
<computeroutput>test.tar.gz: GNU tar archive (gzip compressed data, deflated,
 last modified: Sun Sep 16 13:34:51 2001, os: Unix)</computeroutput>
	      </screen>
	    </para>

	    <para>
	      <programlisting># Find sh and Bash scripts in a given directory:

DIRECTORY=/usr/local/bin
KEYWORD=Bourne
# Bourne and Bourne-Again shell scripts

file $DIRECTORY/* | fgrep $KEYWORD

# Output:

# /usr/local/bin/burn-cd:          Bourne-Again shell script text executable
# /usr/local/bin/burnit:           Bourne-Again shell script text executable
# /usr/local/bin/cassette.sh:      Bourne shell script text executable
# /usr/local/bin/copy-cd:          Bourne-Again shell script text executable
# . . .</programlisting>
	    </para>

	    <example id="stripc">
	      <title>Stripping comments from C program files</title>
	      <programlisting>&stripc;</programlisting>
	    </example>	    	   

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="whichref"><command>which</command></term>
	  <indexterm>
	    <primary>which</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>which</secondary>
	  </indexterm>
	  <listitem>
	    <para><command>which command</command> gives the full path
	      to <quote>command.</quote> This is useful for finding
	      out whether a particular command or utility is installed
	      on the system.</para>
	    <para><userinput>$bash which rm</userinput>
<screen><computeroutput>/usr/bin/rm</computeroutput></screen>
	  </para>
            <para>For an interesting use of this command, see <xref
            linkend="horserace">.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="whereisref"><command>whereis</command></term>
	  <indexterm>
	    <primary>whereis</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>whereis</secondary>
	  </indexterm>
	  <listitem>
	    <para>Similar to <command>which</command>, above,
	      <command>whereis command</command> gives the
	      full path to <quote>command,</quote> but also to its
	      <link linkend="manref">manpage</link>.</para>
	    <para><userinput>$bash whereis rm</userinput>
<screen><computeroutput>rm: /bin/rm /usr/share/man/man1/rm.1.bz2</computeroutput></screen>
	  </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="whatisref"><command>whatis</command></term>
	  <indexterm>
	    <primary>whatis</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>whatis</secondary>
	  </indexterm>
	  <listitem>
	    <para><command>whatis command</command> looks up
	      <quote>command</quote> in the
	      <replaceable>whatis</replaceable> database. This is useful
	      for identifying system commands and important configuration
	      files. Consider it a simplified <command>man</command>
	      command.</para>
	    <para><userinput>$bash whatis whatis</userinput>
<screen><computeroutput>whatis               (1)  - search the whatis database for complete words</computeroutput></screen>
	  </para>
	  
      <example id="what">
	<title>Exploring <filename
	class="directory">/usr/X11R6/bin</filename></title>
	<programlisting>&what;</programlisting>
      </example>

            <para>See also <xref linkend="fileinfo">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="vdirref"><command>vdir</command></term>
	  <indexterm>
	    <primary>vdir</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ls</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show a detailed directory listing. The effect is similar to
	      <link linkend="lsref">ls -lb</link>.</para>
	    <para>This is one of the GNU
	    <firstterm>fileutils</firstterm>.</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>vdir</userinput>
<computeroutput>total 10
 -rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 data1.xrolo
 -rw-r--r--    1 bozo  bozo      4602 May 25 13:58 data1.xrolo.bak
 -rw-r--r--    1 bozo  bozo       877 Dec 17  2000 employment.xrolo</computeroutput>

<prompt>bash </prompt><userinput>ls -l</userinput>
<computeroutput>total 10
 -rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 data1.xrolo
 -rw-r--r--    1 bozo  bozo      4602 May 25 13:58 data1.xrolo.bak
 -rw-r--r--    1 bozo  bozo       877 Dec 17  2000 employment.xrolo</computeroutput>
	      </screen>
	      </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="locateref"><command>locate</command></term>
	  <term><anchor id="slocateref"><command>slocate</command></term>
	  <indexterm>
	    <primary>locate</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>locate</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>slocate</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>slocate</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>locate</command> command searches for
	      files using a database stored for just that purpose. The
	      <command>slocate</command> command is the secure version of
	      <command>locate</command> (which may be aliased to
	      <command>slocate</command>).</para>
	    <para><userinput>$bash locate hickson</userinput>
<screen><computeroutput>/usr/lib/xephem/catalogs/hickson.edb</computeroutput></screen></para>
	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="readlinkref"><command>readlink</command></term>
	  <indexterm>
	    <primary>readlink</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>link</secondary>
	  </indexterm>
	  <listitem>
	    <para>Disclose the file that a symbolic link points to.</para>
	    <para>
	      <screen><prompt>bash$ </prompt><userinput>readlink /usr/bin/awk</userinput>
<computeroutput>../../bin/gawk</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="stringsref"><command>strings</command></term>
	  <indexterm>
	    <primary>strings</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>strings</secondary>
	  </indexterm>
	  <listitem>
	    <para>Use the <command>strings</command> command to find
	      printable strings in a binary or data file. It will list
	      sequences of printable characters found in the target
	      file. This might be handy for a quick 'n dirty examination
	      of a core dump or for looking at an unknown graphic image
	      file (<userinput>strings image-file | more</userinput> might
	      show something like <firstterm>JFIF</firstterm>,
	      which would identify the file as a <firstterm>jpeg</firstterm>
	      graphic). In a script, you would probably
	      parse the output of <command>strings</command>
	      with <link linkend="grepref">grep</link> or <link
	      linkend="sedref">sed</link>. See <xref linkend="bingrep">
	      and <xref linkend="findstring">.</para>

	    <example id="wstrings">
	      <title>An <quote>improved</quote>
	      <firstterm>strings</firstterm> command</title>
	      <programlisting>&wstrings;</programlisting>
	    </example>
	  </listitem>

	</varlistentry>

      </variablelist>

      <variablelist id="comparisonn">
        <title><anchor id="comparisonn1">Comparison</title>

	<varlistentry>
	  <term><anchor id="diffref"><command>diff</command></term>
	  <term><command>patch</command></term>
	  <indexterm>
	    <primary>diff</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>diff</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>patch</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>patch</secondary>
	  </indexterm>
	  <listitem>
	    <para><command>diff</command>: flexible file comparison
	      utility. It compares the target files line-by-line
	      sequentially.  In some applications, such as comparing
	      word dictionaries, it may be helpful to filter the
	      files through <link linkend="sortref">sort</link>
	      and <command>uniq</command> before piping them
	      to <command>diff</command>. <userinput>diff file-1
	      file-2</userinput> outputs the lines in the files that
	      differ, with carets showing which file each particular
	      line belongs to.</para>

	  <para>The <option>--side-by-side</option> option to
	    <command>diff</command> outputs each compared file, line by
	    line, in separate columns, with non-matching lines marked. The
	    <option>-c</option> and <option>-u</option> options likewise
	    make the output of the command easier to interpret.</para>

          <para>There are available various fancy frontends for
	    <command>diff</command>, such as <command>sdiff</command>,
	    <command>wdiff</command>, <command>xdiff</command>, and
	    <command>mgdiff</command>. </para>

	  <tip><para>The <command>diff</command> command returns an exit
	    status of 0 if the compared files are identical, and 1 if
	    they differ. This permits use of <command>diff</command>
	    in a test construct within a shell script (see
	    below).</para></tip>


	    <para>A common use for <command>diff</command> is generating
	      difference files to be used with <command>patch</command>
	      The <option>-e</option> option outputs files suitable
	      for <command>ed</command> or <command>ex</command>
	      scripts.</para>


	    <para><anchor id="patchref"></para>
	    <para><command>patch</command>: flexible versioning
	      utility. Given a difference file generated by
	      <command>diff</command>, <command>patch</command> can
	      upgrade a previous version of a package to a newer version.
	      It is much more convenient to distribute a relatively
	      small <quote>diff</quote> file than the entire body of a
	      newly revised package. Kernel <quote>patches</quote> have
	      become the preferred method of distributing the frequent
	      releases of the Linux kernel.</para>

	    <para><programlisting>patch -p1 &lt;patch-file
# Takes all the changes listed in 'patch-file'
# and applies them to the files referenced therein.
# This upgrades to a newer version of the package.</programlisting></para>

	    <para>Patching the kernel:</para>
            <para><programlisting>cd /usr/src
gzip -cd patchXX.gz | patch -p0
# Upgrading kernel source using 'patch'.
# From the Linux kernel docs "README",
# by anonymous author (Alan Cox?).</programlisting></para>



            <note>
	    <para>The <command>diff</command> command can also
	      recursively compare directories (for the filenames
	      present).</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>diff -r ~/notes1 ~/notes2</userinput>
<computeroutput>Only in /home/bozo/notes1: file02
 Only in /home/bozo/notes1: file03
 Only in /home/bozo/notes2: file04</computeroutput>
	      </screen>
	    </para>
            </note>

	    <tip>
	    <para><anchor id="zdiffref"></para>
	    <para>Use <command>zdiff</command> to compare
	       <firstterm>gzipped</firstterm> files.</para>
	     </tip>

	    <tip>
	    <para><anchor id="diffstatref"></para>
	    <para>Use <command>diffstat</command> to create
	       a histogram (point-distribution graph) of output from
	       <command>diff</command>.</para>
	     </tip>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="diff3ref"><command>diff3</command></term>
	  <term><command>merge</command></term>
	  <indexterm>
	    <primary>diff3</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>diff3</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>merge</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>merge</secondary>
	  </indexterm>

	  <listitem>
	    <para>An extended version of <command>diff</command> that compares
	      three files at a time. This command returns an exit value
	      of 0 upon successful execution, but unfortunately this gives
	      no information about the results of the comparison.</para>
	      <para>
	      <screen><prompt>bash$ </prompt><userinput>diff3 file-1 file-2 file-3</userinput>
<computeroutput>====
 1:1c
   This is line 1 of "file-1".
 2:1c
   This is line 1 of "file-2".
 3:1c
   This is line 1 of "file-3"</computeroutput>
	      </screen>
	      </para>

	    <para><anchor id="mergeref">The <command>merge</command>
	      (3-way file merge) command is an interesting adjunct to
	      <firstterm>diff3</firstterm>. Its syntax is
	      <userinput>merge Mergefile file1 file2</userinput>.
	      The result is to output to <filename>Mergefile</filename>
	      the changes that lead from <filename>file1</filename>
	      to <filename>file2</filename>. Consider this command
	      a stripped-down version of <firstterm>patch</firstterm>.</para>
	      
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="sdiffref"><command>sdiff</command></term>
	  <indexterm>
	    <primary>sdiff</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sdiff</secondary>
	  </indexterm>
	  <listitem>
	    <para>Compare and/or edit two files in order to merge
	      them into an output file. Because of its interactive nature,
	      this command would find little use in a script.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="cmpref"><command>cmp</command></term>
	  <indexterm>
	    <primary>cmp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cmp</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>cmp</command> command is a simpler version of
	      <command>diff</command>, above. Whereas <command>diff</command>
	      reports the differences between two files,
	      <command>cmp</command> merely shows at what point they
	      differ.</para>

	  <note><para>Like <command>diff</command>, <command>cmp</command>
	    returns an exit status of 0 if the compared files are
	    identical, and 1 if they differ. This permits use in a test
	    construct within a shell script.</para></note>

	    <example id="filecomp">
	      <title>Using <firstterm>cmp</firstterm> to compare two files
	        within a script.</title>
	      <programlisting>&filecomp;</programlisting>
	    </example>	    	   

	    <tip><para>Use <command>zcmp</command> on
	      <firstterm>gzipped</firstterm> files.</para></tip>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="commref"><command>comm</command></term>
	  <indexterm>
	    <primary>comm</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>comm</secondary>
	  </indexterm>
	  <listitem>
	    <para>Versatile file comparison utility. The files must be
	      sorted for this to be useful.</para>

	    <para><command>comm
		<replaceable>-options</replaceable>
		<replaceable>first-file</replaceable>
		<replaceable>second-file</replaceable></command></para>

	    <para><userinput>comm file-1 file-2</userinput> outputs three columns:
	      <itemizedlist>
		<listitem><para>column 1 = lines unique to <filename>file-1</filename></para>
		</listitem>
		
		<listitem><para>column 2 = lines unique to <filename>file-2</filename></para>
		</listitem>
		
		<listitem><para>column 3 = lines common to both.</para>
		</listitem>
	      </itemizedlist></para>
	      
	    <para>The options allow suppressing output of one or more columns.
	      <itemizedlist>
		<listitem><para><option>-1</option> suppresses column
		    <literal>1</literal></para>
		</listitem>
		<listitem><para><option>-2</option> suppresses column
		    <literal>2</literal></para>
		</listitem>
		<listitem><para><option>-3</option> suppresses column
		    <literal>3</literal></para>
		</listitem>
		<listitem><para><option>-12</option> suppresses both columns
		    <literal>1</literal> and <literal>2</literal>, etc.</para>
		</listitem>
		</itemizedlist>
	    </para>

	    <para>This command is useful for comparing
	      <quote>dictionaries</quote> or <firstterm>word
	      lists</firstterm> -- sorted text files with one word per
	      line.</para>

	  </listitem>
	</varlistentry>


      </variablelist>

      <variablelist id="fautils">
        <title><anchor id="fautils1">Utilities</title>

	<varlistentry>
	  <term><anchor id="basenameref"><command>basename</command></term>
	  <indexterm>
	    <primary>basename</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>basename</secondary>
	  </indexterm>
	  <listitem><para>Strips the path information from a file name, printing
	      only the file name. The construction  <userinput>basename
		$0</userinput> lets the script know its name, that is, the name it
	      was invoked by. This can be used for <quote>usage</quote> messages if, 
	      for example a script is called with missing arguments:
              <programlisting>echo "Usage: `basename $0` arg1 arg2 ... argn"</programlisting>
	    </para>

	  </listitem>
	</varlistentry>
	
	<varlistentry>
	  <term><anchor id="dirnameref"><command>dirname</command></term>
	  <indexterm>
	    <primary>dirname</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>dirname</secondary>
	  </indexterm>
	  <listitem><para>Strips the <command>basename</command> from
	    a filename, printing only the path information.</para>
	    <note>
	      <para><command>basename</command> and <command>dirname</command>
		can operate on any arbitrary string. The argument
		does not need to refer to an existing file, or
		even be a filename for that matter (see <xref
		linkend="daysbetween">).</para>
	    </note>
	    
	    <example id="ex35">
	      <title><firstterm>basename</firstterm> and
	      <firstterm>dirname</firstterm></title>
	      <programlisting>&ex35;</programlisting>
	    </example>	    
	    
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="splitref"><command>split</command></term>
	  <term><anchor id="csplitref"><command>csplit</command></term>
	  <indexterm>
	    <primary>split</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>split</secondary>
	  </indexterm>
	  <indexterm>
	  <primary>csplit</primary>
	  </indexterm>
	  <indexterm>
	  <primary>command</primary>
	  <secondary>csplit</secondary>
	  </indexterm>

	  <listitem>
	    <para>These are utilities for splitting a file into smaller
	      chunks. Their usual use is for splitting up large files
	      in order to back them up on floppies or preparatory to
	      e-mailing or uploading them.</para>

            <para>The <command>csplit</command> command splits a file
	      according to <firstterm>context</firstterm>, the split occuring
	      where patterns are matched.</para>

	    <example id="splitcopy">
	      <title>A script that copies itself in sections</title>
	      <programlisting>&splitcopy;</programlisting>
	    </example>
	      
	  </listitem>
	</varlistentry>

      </variablelist>



      <variablelist id="faencencr">
        <title><anchor id="faencencr1">Encoding and Encryption</title>

	<varlistentry>
	  <term><anchor id="sumref"><command>sum</command></term>
	  <term><anchor id="cksumref"><command>cksum</command></term>
	  <term><anchor id="md5sumref"><command>md5sum</command></term>
	  <term><anchor id="sha1sumref"><command>sha1sum</command></term>
	  <indexterm>
	    <primary>sum</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sum</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>cksum</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cksum</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>md5sum</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>md5sum</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sha1sum</secondary>
	  </indexterm>
	  <listitem>
	    <para>These are utilities for generating checksums. A
	      <firstterm>checksum</firstterm> is a number mathematically
	      calculated from the contents of a file, for the purpose
	      of checking its integrity. A script might refer to a list
	      of checksums for security purposes, such as ensuring
	      that the contents of key system files have not been
	      altered or corrupted. For security applications, use the
	      <command>md5sum</command> (<command>m</command>essage
	      <command>d</command>igest <command>5</command>
	      check<command>sum</command>) command, or better yet,
	      the newer <command>sha1sum</command> (Secure Hash
	      Algorithm).</para>


	  <para>
	      <screen>
<prompt>bash$ </prompt><userinput>cksum /boot/vmlinuz</userinput>
<computeroutput>1670054224 804083 /boot/vmlinuz</computeroutput>

<prompt>bash$ </prompt><userinput>echo -n "Top Secret" | cksum</userinput>
<computeroutput>3391003827 10</computeroutput>



<prompt>bash$ </prompt><userinput>md5sum /boot/vmlinuz</userinput>
<computeroutput>0f43eccea8f09e0a0b2b5cf1dcf333ba  /boot/vmlinuz</computeroutput>

<prompt>bash$ </prompt><userinput>echo -n "Top Secret" | md5sum</userinput>
<computeroutput>8babc97a6f62a4649716f4df8d61728f  -</computeroutput>
	      </screen>
	  </para>


	  <note>
	  <para>The <command>cksum</command> command shows the size,
	    in bytes, of its target, whether file or
	    <filename>stdout</filename>.</para>
	  <para>The <command>md5sum</command> and
	    <command>sha1sum</command> commands display a
	    <link linkend="dashref2">dash</link> when they receive their input from
	    <filename>stdout</filename>.</para>
	    </note>

	    <example id="fileintegrity">
	      <title>Checking file integrity</title>
	      <programlisting>&fileintegrity;</programlisting>
	    </example>

	  <para>Also see <xref linkend="directoryinfo">, <xref
	    linkend="horserace">, and <xref linkend="randstring"> for
	    creative uses of the <command>md5sum</command> command.</para>

          <note>

	  <para>
	    There have been reports that the 128-bit
	    <command>md5sum</command> can be cracked, so the more secure
	    160-bit <command>sha1sum</command> is a welcome new addition
	    to the checksum toolkit.
          </para>

	      <screen><prompt>bash$ </prompt><userinput>md5sum testfile</userinput>
<computeroutput>e181e2c8720c60522c4c4c981108e367  testfile</computeroutput>


<prompt>bash$ </prompt><userinput>sha1sum testfile</userinput>
<computeroutput>5d7425a9c08a66c3177f1e31286fa40986ffc996  testfile</computeroutput>
	      </screen></note>

	  <para>Security consultants have demonstrated that even
	      <command>sha1sum</command> can be compromised. Fortunately,
	      newer Linux distros include longer bit-length
	      <command>sha224sum</command>,
	      <command>sha256sum</command>,
	      <command>sha384sum</command>, and
	      <command>sha512sum</command> commands.</para>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="shredref"><command>shred</command></term>
	  <indexterm>
	    <primary>shred</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>secure delete</secondary>
	  </indexterm>
	  <listitem>

	    <para>Securely erase a file by overwriting it multiple times with
	      random bit patterns before deleting it. This command has
	      the same effect as <xref linkend="blotout">, but does it
	      in a more thorough and elegant manner.</para>

	    <para>This is one of the GNU
	    <firstterm>fileutils</firstterm>.</para>

	    <caution><para>Advanced forensic technology may still be able to
	      recover the contents of a file, even after application of
	      <command>shred</command>.</para></caution>
	    
	  </listitem>
	</varlistentry>



	<varlistentry>
	  <term><anchor id="uuencoderef"><command>uuencode</command></term>
	  <indexterm>
	    <primary>uuencode</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>uuencode</secondary>
	  </indexterm>
	  <listitem>
	    <para>This utility encodes binary files (images, sound files,
	      compressed files, etc.) into ASCII characters, making them
	      suitable for transmission in the body of an e-mail message or in a
	      newsgroup posting. This is especially useful where MIME
	      (multimedia) encoding is not available.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="uudecoderef"><command>uudecode</command></term>
	  <indexterm>
	    <primary>uudecode</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>uudecode</secondary>
	  </indexterm>
	  <listitem>
	    <para>This reverses the encoding, decoding
	      <firstterm>uuencoded</firstterm> files back into the
	      original binaries.</para>

	    <example id="ex52">
	      <title>Uudecoding encoded files</title>
	      <programlisting>&ex52;</programlisting>
	    </example>	    	   

	  <tip><para>The <link linkend="foldref">fold -s</link> command
	    may be useful (possibly in a pipe) to process long uudecoded
	    text messages downloaded from Usenet newsgroups.</para></tip>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mimencoderef"><command>mimencode</command></term>
	  <term><anchor id="mmencoderef"><command>mmencode</command></term>
	  <indexterm>
	    <primary>mimencode</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mime</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>mmencode</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>encode</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>mimencode</command> and
	      <command>mmencode</command> commands process
	      multimedia-encoded e-mail attachments. Although
	      <firstterm>mail user agents</firstterm> (such as
	      <firstterm>pine</firstterm> or <firstterm>kmail</firstterm>)
	      normally handle this automatically, these particular
	      utilities permit manipulating such attachments manually from
	      the command line or in <link linkend="batchprocref">batch
	      processing mode</link> by means of a shell script.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="cryptref"><command>crypt</command></term>
	  <indexterm>
	    <primary>crypt</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>crypt</secondary>
	  </indexterm>
	  <listitem>
	    <para>At one time, this was the standard UNIX file encryption
	      utility.

              <footnote><para>This is a symmetric block cipher, used to
		encrypt files on a single system or local network,
		as opposed to the <firstterm>public key</firstterm>
		cipher class, of which <firstterm>pgp</firstterm> is a
		well-known example.</para></footnote>

	      Politically-motivated government regulations
	      prohibiting the export of encryption software resulted
	      in the disappearance of <command>crypt</command>
	      from much of the UNIX world, and it is still
	      missing from most Linux distributions. Fortunately,
	      programmers have come up with a number of decent
	      alternatives to it, among them the author's very own <ulink
	      url="ftp://metalab.unc.edu/pub/Linux/utils/file/cruft-0.2.tar.gz">cruft</ulink>
	      (see <xref linkend="encryptedpw">).  </para>

	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="famisc">
        <title><anchor id="famisc1">Miscellaneous</title>

	<varlistentry>
	  <term><anchor id="mktempref"><command>mktemp</command></term>
	  <indexterm>
	    <primary>temporary</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>filename</secondary>
	  </indexterm>
	  <listitem>
	    <para>Create a <firstterm>temporary file</firstterm>

	       <footnote><para>Creates a temporary
	       <firstterm>directory</firstterm> when invoked with the
	       <option>-d</option> option.</para></footnote>

	      with a <quote>unique</quote> filename. When invoked
	      from the command line without additional arguments,
	      it creates a zero-length file in the <filename
	      class="directory">/tmp</filename> directory.</para>


	  <para>
	      <screen><prompt>bash$ </prompt><userinput>mktemp</userinput>
<computeroutput>/tmp/tmp.zzsvql3154</computeroutput>
	      </screen>
	    </para>

	    <para><programlisting>PREFIX=filename
tempfile=`mktemp $PREFIX.XXXXXX`
#                        ^^^^^^ Need at least 6 placeholders
#+                              in the filename template.
#   If no filename template supplied,
#+ "tmp.XXXXXXXXXX" is the default.

echo "tempfile name = $tempfile"
# tempfile name = filename.QA2ZpY
#                 or something similar...

#  Creates a file of that name in the current working directory
#+ with 600 file permissions.
#  A "umask 177" is therefore unnecessary,
#+ but it's good programming practice anyhow.</programlisting></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="makeref"><command>make</command></term>
	  <indexterm>
	    <primary>make</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>Makefile</secondary>
	  </indexterm>
	  <listitem>
	    <para><anchor id="makefileref"></para>
	    <para>Utility for building and compiling binary packages. 
	      This can also be used for any set of operations triggered
	      by incremental changes in source files.</para>
	    <para>The <firstterm>make</firstterm> command checks a
	    <filename>Makefile</filename>, a list of file dependencies and
	      operations to be carried out.</para>
            <para>The <firstterm>make</firstterm> utility is, in effect,
	      a powerful scripting language similar in many ways to
	      <firstterm>Bash</firstterm>, but with the capability of
	      recognizing <firstterm>dependencies</firstterm>. For in-depth
	      coverage of this useful tool set, see the <ulink
	      url="http://www.gnu.org/manual/manual.html">GNU software
	      documentation site</ulink>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="installref"><command>install</command></term>
	  <indexterm>
	    <primary>install</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>install</secondary>
	  </indexterm>
	  <listitem>
	    <para>Special purpose file copying command, similar to
	      <link linkend="cpref">cp</link>, but capable of
	      setting permissions and attributes of the copied
	      files. This command seems tailormade for installing
	      software packages, and as such it shows up frequently in
	      <filename>Makefiles</filename> (in the <replaceable>make
	      install :</replaceable> section). It could likewise prove
	      useful in installation scripts.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="dos2unixref"><command>dos2unix</command></term>
	  <indexterm>
	    <primary>dos2unix</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>file converter</secondary>
	  </indexterm>
	  <listitem>
	    <para>This utility, written by Benjamin Lin and collaborators,
	      converts DOS-formatted text files (lines terminated by
	      CR-LF) to UNIX format (lines terminated by LF only),
	      and <link linkend="dosnewlines">vice-versa</link>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="ptxref"><command>ptx</command></term>
	  <indexterm>
	    <primary>ptx</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>index</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>ptx [targetfile]</command> command
	      outputs a permuted index (cross-reference list) of the
	      targetfile. This may be further filtered and formatted in a
	      pipe, if necessary.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="moreref"><command>more</command></term>
	  <term><anchor id="lessref"><command>less</command></term>
	  <indexterm>
	    <primary>more</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>more</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>less</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>less</secondary>
	  </indexterm>
	  <listitem>

	    <para>Pagers that display a text file or stream to
	      <filename>stdout</filename>, one screenful at a time.
	      These may be used to filter the output of
	      <filename>stdout</filename> . . . or of a script.</para>

            <para>
	       An interesting application of <firstterm>more</firstterm>
	       is to <quote>test drive</quote> a command sequence,
	       to forestall potentially unpleasant consequences.
                 <programlisting>ls /home/bozo | awk '{print "rm -rf " $1}' | more
#                                            ^^^^
		 
# Testing the effect of the following (disastrous) command line:
#      ls /home/bozo | awk '{print "rm -rf " $1}' | sh
#      Hand off to the shell to execute . . .       ^^</programlisting>
            </para>

            <para>The <firstterm>less</firstterm> pager has the
	      interesting property of doing a formatted display of
	      <firstterm>man page</firstterm> source. See <xref
	      linkend="maned">.</para>

	  </listitem>
	</varlistentry>
       
       </variablelist>	

	</sect1> <!-- End File and Archiving Commands -->



      <sect1 id="communications">
        <title>Communications Commands</title>

	<para>Certain of the following commands find use in
	  network data transfer and analysis, as well as in
	  <link linkend="cspammers">chasing spammers</link>.</para>

       <variablelist id="communinfo">
         <title><anchor id="communinfo1">Information and Statistics</title>

	<varlistentry>
	  <term><anchor id="hostref"><command>host</command></term>
	  <indexterm>
	    <primary>host</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>host</secondary>
	  </indexterm>
	  <listitem>
	    <para>Searches for information about an Internet host by name or
	      IP address, using DNS.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>host surfacemail.com</userinput>
<computeroutput>surfacemail.com. has address 202.92.42.236</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="ipcalcref"><command>ipcalc</command></term>
	  <indexterm>
	    <primary>ipcalc</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ipcalc</secondary>
	  </indexterm>
	  <listitem>
	    <para>Displays IP information for a host.
	      With the <option>-h</option> option,
	      <command>ipcalc</command> does a reverse DNS lookup, finding
	      the name of the host (server) from the IP address.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>ipcalc -h 202.92.42.236</userinput>
<computeroutput>HOSTNAME=surfacemail.com</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="nslookupref"><command>nslookup</command></term>
	  <indexterm>
	    <primary>nslookup</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>name server lookup</secondary>
	  </indexterm>
	  <listitem>

	    <para>Do an Internet <quote>name server lookup</quote>
	      on a host by IP address. This is essentially equivalent
	      to <command>ipcalc -h</command> or <command>dig -x
	      </command>. The command may be run either interactively
	      or noninteractively, i.e., from within a script.</para>

	    <para>The <command>nslookup</command> command has allegedly
	      been <quote>deprecated,</quote> but it is still useful.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>nslookup -sil 66.97.104.180</userinput>
<computeroutput>nslookup kuhleersparnis.ch
 Server:         135.116.137.2
 Address:        135.116.137.2#53

 Non-authoritative answer:
 Name:   kuhleersparnis.ch</computeroutput>
	      </screen>
	  </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="digref"><command>dig</command></term>
	  <indexterm>
	    <primary>dig</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>domain information groper</secondary>
	  </indexterm>
	  <listitem>

	    <para><command>D</command>omain <command>I</command>nformation
	      <command>G</command>roper. Similar to
	      <command>nslookup</command>, <firstterm>dig</firstterm> does
	      an Internet <firstterm>name server lookup</firstterm> on a host.
	      May be run from the command line or from within a script.</para>

            <para>Some interesting options to <firstterm>dig</firstterm> are
	      <option>+time=N</option> for setting a query timeout to
	      <parameter>N</parameter> seconds, <option>+nofail</option> for
	      continuing to query servers until a reply is received, and
	      <option>-x</option> for doing a reverse address lookup.</para>

	    <para>Compare the output of <command>dig -x</command> with
	      <command>ipcalc -h</command> and
	      <command>nslookup</command>.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>dig -x 81.9.6.2</userinput>
<computeroutput>;; Got answer:
 ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 11649
 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

 ;; QUESTION SECTION:
 ;2.6.9.81.in-addr.arpa.         IN      PTR

 ;; AUTHORITY SECTION:
 6.9.81.in-addr.arpa.    3600    IN      SOA     ns.eltel.net. noc.eltel.net.
 2002031705 900 600 86400 3600

 ;; Query time: 537 msec
 ;; SERVER: 135.116.137.2#53(135.116.137.2)
 ;; WHEN: Wed Jun 26 08:35:24 2002
 ;; MSG SIZE  rcvd: 91</computeroutput>
	      </screen>
	  </para>

	    <para><anchor id="spamlookup_0"></para>
	    <example id="spamlookup">
	      <title>Finding out where to report a spammer</title>
	      <programlisting>&spamlookup;</programlisting>
	    </example>

	    <para><anchor id="isspammer_0"></para>
	    <example id="isspammer">
	      <title>Analyzing a spam domain</title>
	      <programlisting>&isspammer;</programlisting>
	    </example>

	  <para>For a much more elaborate version of the above script, see 
	    <xref linkend="isspammer2">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="tracerouteref"><command>traceroute</command></term>
	  <indexterm>
	    <primary>traceroute</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>traceroute</secondary>
	  </indexterm>
	  <listitem>

	    <para>Trace the route taken by packets sent to a remote host. This
	      command works within a LAN, WAN, or over the
	      Internet. The remote host may be specified by an IP
	      address. The output of this command may be filtered
	      by <link linkend="grepref">grep</link> or <link
	      linkend="sedref">sed</link> in a pipe.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>traceroute 81.9.6.2</userinput>
<computeroutput>traceroute to 81.9.6.2 (81.9.6.2), 30 hops max, 38 byte packets
 1  tc43.xjbnnbrb.com (136.30.178.8)  191.303 ms  179.400 ms  179.767 ms
 2  or0.xjbnnbrb.com (136.30.178.1)  179.536 ms  179.534 ms  169.685 ms
 3  192.168.11.101 (192.168.11.101)  189.471 ms  189.556 ms *
 ...</computeroutput>
	      </screen>
	  </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="pingref"><command>ping</command></term>
	  <indexterm>
	    <primary>ping</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ping</secondary>
	  </indexterm>
	  <listitem>

	    <para>Broadcast an <replaceable>ICMP
	      ECHO_REQUEST</replaceable> packet to another machine,
              either on a local or remote network. This is a
              diagnostic tool for testing network connections,
              and it should be used with caution.</para>


	  <para>
	      <screen><prompt>bash$ </prompt><userinput>ping localhost</userinput>
<computeroutput>PING localhost.localdomain (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data.
 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=255 time=709 usec
 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=255 time=286 usec

 --- localhost.localdomain ping statistics ---
 2 packets transmitted, 2 packets received, 0% packet loss
 round-trip min/avg/max/mdev = 0.286/0.497/0.709/0.212 ms</computeroutput>
	      </screen>
	    </para>

	    <para>A successful <firstterm>ping</firstterm> returns
	      an <link linkend="exitstatusref">exit status</link> of
	      <errorcode>0</errorcode>. This can be tested for in a
	      script.</para>

            <para><programlisting>  HNAME=nastyspammer.com
# HNAME=$HOST     # Debug: test for localhost.
  count=2  # Send only two pings.

if [[ `ping -c $count "$HNAME"` ]]
then
  echo ""$HNAME" still up and broadcasting spam your way."
else
  echo ""$HNAME" seems to be down. Pity."
fi</programlisting></para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="whoisref"><command>whois</command></term>
	  <indexterm>
	    <primary>whois</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>domain name server</secondary>
	  </indexterm>
	  <listitem>
	    <para>Perform a DNS (Domain Name System) lookup.
	      The <option>-h</option> option permits specifying which
	      particular <firstterm>whois</firstterm> server to query. See
	      <xref linkend="ex18"> and <xref linkend="spamlookup">.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="fingerref"><command>finger</command></term>
	  <indexterm>
	    <primary>finger</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>finger</secondary>
	  </indexterm>
	  <listitem>

	    <para>Retrieve information about users on a
	      network. Optionally, this command can display
	      a user's <filename>~/.plan</filename>,
	      <filename>~/.project</filename>, and
	      <filename>~/.forward</filename> files, if present.</para>

	  <para>
	      <screen>
<prompt>bash$ </prompt><userinput>finger</userinput>
<computeroutput>Login  Name           Tty      Idle  Login Time   Office     Office Phone
 bozo   Bozo Bozeman   tty1        8  Jun 25 16:59                (:0)
 bozo   Bozo Bozeman   ttyp0          Jun 25 16:59                (:0.0)
 bozo   Bozo Bozeman   ttyp1          Jun 25 17:07                (:0.0)</computeroutput>



<prompt>bash$ </prompt><userinput>finger bozo</userinput>
<computeroutput>Login: bozo                             Name: Bozo Bozeman
 Directory: /home/bozo                   Shell: /bin/bash
 Office: 2355 Clown St., 543-1234
 On since Fri Aug 31 20:13 (MST) on tty1    1 hour 38 minutes idle
 On since Fri Aug 31 20:13 (MST) on pts/0   12 seconds idle
 On since Fri Aug 31 20:13 (MST) on pts/1
 On since Fri Aug 31 20:31 (MST) on pts/2   1 hour 16 minutes idle
 Mail last read Tue Jul  3 10:08 2007 (MST) 
 No Plan.</computeroutput>
	      </screen>
	    </para>
	      
	    <para>Out of security considerations, many networks disable
	      <command>finger</command> and its associated daemon.
	          <footnote>
		  <para><anchor id="daemonref"></para>
		  <para>A <firstterm>daemon</firstterm> is a background
		    process not attached to a terminal session. Daemons
		    perform designated services either at specified times
		    or explicitly triggered by certain events.</para>
		  <para>The word <quote>daemon</quote> means ghost in
		    Greek, and there is certainly something mysterious,
		    almost supernatural, about the way UNIX daemons
		    wander about behind the scenes, silently carrying
		    out their appointed tasks.</para>
	          </footnote>
	      </para>
	  
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="chfnref"><command>chfn</command></term>
	  <indexterm>
	    <primary>chfn</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>finger</secondary>
	  </indexterm>
	  <listitem>
	    <para>Change information disclosed by the
	      <command>finger</command> command.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="vrfyref"><command>vrfy</command></term>
	  <indexterm>
	    <primary>vrfy</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>vrfy</secondary>
	  </indexterm>
	  <listitem>
	    <para>Verify an Internet e-mail address.</para>
	    
	    <para>This command seems to be missing from newer Linux
	      distros.</para>
	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="commremote">
        <title><anchor id="commremote1">Remote Host Access</title>

	<varlistentry>
	  <term><anchor id="rxref"><command>sx</command></term>
	  <term><command>rx</command></term>
	  <indexterm>
	    <primary>sx</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sx</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>rx</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>rx</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>sx</command> and <command>rx</command>
	      command set serves to transfer files to and from a remote
	      host using the <firstterm>xmodem</firstterm> protocol. These
	      are generally part of a communications package, such as
	      <command>minicom</command>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rzref"><command>sz</command></term>
	  <term><command>rz</command></term>
	  <indexterm>
	    <primary>sz</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sz</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>rz</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>rz</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>sz</command> and <command>rz</command>
	      command set serves to transfer files to and from a remote
	      host using the <firstterm>zmodem</firstterm> protocol.
	      <firstterm>Zmodem</firstterm> has certain advantages over
	      <firstterm>xmodem</firstterm>, such as faster transmission
	      rate and resumption of interrupted file transfers.
	      Like <command>sx</command> and <command>rx</command>,
	      these are generally part of a communications package.</para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="ftpref"><command>ftp</command></term>
	  <indexterm>
	    <primary>ftp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>file transfer</secondary>
	  </indexterm>
	  <listitem>
	    <para>Utility and protocol for uploading / downloading
	      files to or from a remote host. An ftp session can be automated
	      in a script (see <xref linkend="ex72">, <xref
	      linkend="encryptedpw">, and <xref linkend="ftpget">).</para>
	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="uucpref"><command>uucp</command></term>
	  <term><anchor id="uuxref"><command>uux</command></term>
	  <term><anchor id="curef"><command>cu</command></term>
	  <indexterm>
	    <primary>uucp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>uucp</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>uux</primary>
	    <secondary>unix to unix execute</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>cu</primary>
	    <secondary>call up</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>uucp</secondary>
	  </indexterm>
	  <listitem>

	    <para><command>uucp</command>: <firstterm>UNIX to UNIX
	      copy</firstterm>. This is a communications package for
	      transferring files between UNIX servers. A shell script
	      is an effective way to handle a <command>uucp</command>
	      command sequence.</para>

	    <para>Since the advent of the Internet and e-mail,
	      <command>uucp</command> seems to have faded into obscurity,
	      but it still exists and remains perfectly workable in
	      situations where an Internet connection is not available
	      or appropriate. The advantage of <command>uucp</command>
	      is that it is fault-tolerant, so even if there is a service
	      interruption the copy operation will resume where it left
	      off when the connection is restored.</para>

            <para>---</para>

	    <para><command>uux</command>: <firstterm>UNIX to UNIX
	      execute</firstterm>. Execute a command on a remote system.
	      This command is part of the <command>uucp</command>
	      package.</para>

            <para>---</para>

	    <para><command>cu</command>: <command>C</command>all
	      <command>U</command>p a remote system and connect as a
	      simple terminal. It is a sort of dumbed-down version of
	      <link linkend="telnetref">telnet</link>. This command is
	      part of the <command>uucp</command> package.</para>
	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="telnetref"><command>telnet</command></term>
	  <indexterm>
	    <primary>telnet</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>telnet</secondary>
	  </indexterm>
	  <listitem>
	    <para>Utility and protocol for connecting to a remote host.</para>
	    <caution><para>The <firstterm>telnet</firstterm> protocol
	    contains security holes and should therefore probably be
	    avoided. Its use within a shell script is
	    <emphasis>not</emphasis> recommended.</para></caution>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="wgetref"><command>wget</command></term>
	  <indexterm>
	    <primary>wget</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>download</secondary>
	  </indexterm>
	  <listitem>

	    <para>The <command>wget</command> utility
	      <firstterm>noninteractively</firstterm> retrieves or
	      downloads files from a Web or ftp site. It works well in a
	      script.</para>

	    <para><programlisting>wget -p http://www.xyz23.com/file01.html
#  The -p or --page-requisite option causes wget to fetch all files
#+ required to display the specified page.

wget -r ftp://ftp.xyz24.net/~bozo/project_files/ -O $SAVEFILE
#  The -r option recursively follows and retrieves all links
#+ on the specified site.

wget -c ftp://ftp.xyz25.net/bozofiles/filename.tar.bz2
#  The -c option lets wget resume an interrupted download.
#  This works with ftp servers and many HTTP sites.</programlisting></para>

	    <example id="quotefetch">
	      <title>Getting a stock quote</title>
	      <programlisting>&quotefetch;</programlisting>
	    </example>


            <para>See also <xref linkend="wgetter2"> and <xref
	      linkend="bashpodder">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lynxref"><command>lynx</command></term>
	  <indexterm>
	    <primary>lynx</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>browser</secondary>
	  </indexterm>
	  <listitem>

	    <para>The <command>lynx</command> Web and file browser
	      can be used inside a script (with the
	      <option>-dump</option> option) to retrieve a file from a Web or 
	      ftp site noninteractively.</para>

	   <para>
	   <programlisting>lynx -dump http://www.xyz23.com/file01.html &gt;$SAVEFILE</programlisting>
            </para>		

            <para>With the <option>-traversal</option> option,
	      <command>lynx</command> starts at the HTTP URL specified
	      as an argument, then <quote>crawls</quote> through all
	      links located on that particular server. Used together
	      with the <option>-crawl</option> option, outputs page text
	      to a log file.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rloginref"><command>rlogin</command></term>
	  <indexterm>
	    <primary>rlogin</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>remote login</secondary>
	  </indexterm>
	  <listitem>
	    <para><replaceable>Remote login</replaceable>, initates a
	      session on a remote host. This command has security issues,
	      so use <link linkend="sshref">ssh</link> instead.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rshref"><command>rsh</command></term>
	  <indexterm>
	    <primary>rsh</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>remote shell</secondary>
	  </indexterm>
	  <listitem>
	    <para><replaceable>Remote shell</replaceable>, executes
	      command(s) on a remote host. This has security issues,
	      so use <command>ssh</command> instead.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rcpref"><command>rcp</command></term>
	  <indexterm>
	    <primary>rcp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>remote copy</secondary>
	  </indexterm>
	  <listitem>
	    <para><replaceable>Remote copy</replaceable>, copies files
	      between two different networked machines.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rsyncref"><command>rsync</command></term>
	  <indexterm>
	    <primary>rsync</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>remote update</secondary>
	  </indexterm>
	  <listitem>

	    <para><replaceable>Remote synchronize</replaceable>, updates
	    (synchronizes) files
	      between two different networked machines.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>rsync -a ~/sourcedir/*txt /node1/subdirectory/</userinput>
	      </screen>
	    </para>

	    <example id="fc4upd">
	      <title>Updating FC4</title>
	      <programlisting>&fc4upd;</programlisting>
	    </example>

	    <para>See also <xref linkend="nightlybackup">.</para>
	      
	    <note><para>Using <link linkend="rcpref">rcp</link>, <link
	      linkend="rsyncref">rsync</link>, and similar
	      utilities with security implications in a shell
	      script may not be advisable. Consider, instead, using
	      <command>ssh</command>, <link linkend="scpref">scp</link>,
	      or an <command>expect</command> script.</para></note>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="sshref"><command>ssh</command></term>
	  <indexterm>
	    <primary>ssh</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>secure shell</secondary>
	  </indexterm>
	  <listitem>
	    <para><replaceable>Secure shell</replaceable>, logs onto
	      a remote host and executes commands there. This
	      secure replacement for <command>telnet</command>,
	      <command>rlogin</command>, <command>rcp</command>, and
	      <command>rsh</command> uses identity authentication
	      and encryption. See its <link linkend="manref">manpage</link>
	      for details.</para>

	    <example id="remote">
	      <title>Using <firstterm>ssh</firstterm></title>
	      <programlisting>&remote;</programlisting>
	    </example>

	      <caution>
	      <para>Within a loop, <command>ssh</command> may cause
		unexpected behavior. According to a <ulink
		url="http://groups-beta.google.com/group/comp.unix.shell/msg/dcb446b5fff7d230">
		Usenet post</ulink> in the comp.unix shell archives,
		<command>ssh</command> inherits the loop's
		<filename>stdin</filename>. To remedy this, pass
		<command>ssh</command> either the <option>-n</option>
		or <option>-f</option> option.</para>
		<para>Thanks, Jason Bechtel, for pointing this out.</para>
	      </caution>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="scpref"><command>scp</command></term>
	  <indexterm>
	    <primary>scp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>secure copy</secondary>
	  </indexterm>
	  <listitem>
	    <para><replaceable>Secure copy</replaceable>, similar in
	      function to <command>rcp</command>, copies files between
	      two different networked machines, but does so using
	      authentication, and with a security level similar to
	      <command>ssh</command>.</para>
	  </listitem>
	</varlistentry>
       
       </variablelist>	


      <variablelist id="commlocal">
        <title><anchor id="commlocal1">Local Network</title>

	<varlistentry>
	  <term><anchor id="writeref"><command>write</command></term>
	  <indexterm>
	    <primary>write</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>write</secondary>
	  </indexterm>
	  <listitem>
	    <para>This is a utility for terminal-to-terminal communication.
	      It allows sending lines from your terminal (console or
	      <firstterm>xterm</firstterm>) to that of another user. The
	      <link linkend="mesgref">mesg</link> command may, of course,
	      be used to disable write access to a terminal</para>

	    <para>Since <command>write</command> is interactive, it
	      would not normally find use in a script.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="netconfigref"><command>netconfig</command></term>
	  <indexterm>
	    <primary>netconfig</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>network</secondary>
	  </indexterm>
	  <listitem>
	    <para>A command-line utility for configuring a network adapter
	      (using <firstterm>DHCP</firstterm>). This command is native
	      to Red Hat centric Linux distros.</para>
	  </listitem>
	</varlistentry>

       </variablelist>	


      <variablelist id="commmail">
        <title><anchor id="commmail1">Mail</title>

	<varlistentry>
	  <term><command>mail</command></term>
	  <indexterm>
	    <primary>mail</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mail</secondary>
	  </indexterm>
	  <listitem>

	    <para>Send or read e-mail messages.</para>

            <para>This stripped-down command-line mail client
	      works fine as a command embedded in a script.</para>

	    <example id="selfmailer">
	      <title>A script that mails itself</title>
	      <programlisting>&selfmailer;</programlisting>
	    </example>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mailtoref"><command>mailto</command></term>
	  <indexterm>
	    <primary>mailto</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>MIME mail</secondary>
	  </indexterm>
	  <listitem>
	    <para>Similar to the <command>mail</command> command,
	      <command>mailto</command> sends e-mail messages
	      from the command line or in a script. However,
	      <command>mailto</command> also permits sending MIME
	      (multimedia) messages.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mailstatsref"><command>mailstats</command></term>
	  <indexterm>
	    <primary>mailstats</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>statistics</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show <firstterm>mail statistics</firstterm>. This command
	      may be invoked only by <firstterm>root</firstterm>.</para>

	  <para>
	      <screen><prompt>root# </prompt><userinput>mailstats</userinput>
<computeroutput>Statistics from Tue Jan  1 20:32:08 2008
  M   msgsfr  bytes_from   msgsto    bytes_to  msgsrej msgsdis msgsqur  Mailer
  4     1682      24118K        0          0K        0       0       0  esmtp
  9      212        640K     1894      25131K        0       0       0  local
 =====================================================================
  T     1894      24758K     1894      25131K        0       0       0
  C      414                    0</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="vacationref"><command>vacation</command></term>
	  <indexterm>
	    <primary>vacation</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mail</secondary>
	  </indexterm>
	  <listitem>
	    <para>This utility automatically replies to e-mails that
	      the intended recipient is on vacation and temporarily
	      unavailable. It runs on a network, in conjunction with
	      <command>sendmail</command>, and is not applicable to a
	      dial-up POPmail account.</para>
	  </listitem>
	</varlistentry>


       </variablelist>	

	</sect1> <!-- End Communications Commands -->



      <sect1 id="terminalccmds">
        <title>Terminal Control Commands</title>

       <variablelist id="termcommandlisting">	
         <title><anchor id="termcommandlisting1">Command affecting the console
	   or terminal</title>


	<varlistentry>
	  <term><anchor id="tputref"><command>tput</command></term>
	  <indexterm>
	    <primary>tput</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>terminal</secondary>
	  </indexterm>
	  <listitem>

	    <para>Initialize terminal and/or fetch information about it from
	      <database>terminfo</database> data. Various options permit
	      certain terminal operations:  <command>tput clear</command>
	      is the equivalent of <link linkend="clearref">clear</link>;
	      <command>tput reset</command> is the equivalent
	      of <link linkend="resetref">reset</link>.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>tput longname</userinput>
<computeroutput>xterm terminal emulator (X Window System)</computeroutput>
	      </screen>
	    </para>

	    <para>Issuing a <command>tput cup X Y</command> moves
	      the cursor to the (X,Y) coordinates in the current
	      terminal. A <command>clear</command> to erase the terminal
	      screen would normally precede this.</para>


	    <para>

	      Some interesting options to <firstterm>tput</firstterm> are:

	  <itemizedlist>
	    <listitem><para><option>bold</option>, for high-intensity
	      text</para></listitem>
	    <listitem><para><option>smul</option>, to underline text
	      in the terminal</para></listitem>
	    <listitem><para><option>smso</option>, to render text in
	      reverse</para></listitem>
	    <listitem><para><option>sgr0</option>, to reset the terminal
	      parameters (to normal), without clearing the
	      screen</para></listitem>
	  </itemizedlist>

	    </para>


	    <para>Example scripts using <firstterm>tput</firstterm>:
            <orderedlist id="tputexamples">
               <listitem><para><xref linkend="colorecho"></para></listitem>
               <listitem><para><xref linkend="ex30a"></para></listitem>
               <listitem><para><xref linkend="homework"></para></listitem>
               <listitem><para><xref linkend="nim"></para></listitem>
               <listitem><para><xref linkend="poem"></para></listitem>
            </orderedlist>
	    </para>

	    <para>Note that <link linkend="sttyref">stty</link> offers
	      a more powerful command set for controlling a terminal.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="infocmpref"><command>infocmp</command></term>
	  <indexterm>
	    <primary>infocmp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>terminal</secondary>
	  </indexterm>
	  <listitem>

	    <para>This command prints out extensive information about the
	      current terminal. It references the
	      <firstterm>terminfo</firstterm> database.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>infocmp</userinput>
<computeroutput>#       Reconstructed via infocmp from file:
 /usr/share/terminfo/r/rxvt
 rxvt|rxvt terminal emulator (X Window System), 
         am, bce, eo, km, mir, msgr, xenl, xon, 
         colors#8, cols#80, it#8, lines#24, pairs#64, 
         acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, 
         bel=^G, blink=\E[5m, bold=\E[1m,
         civis=\E[?25l, 
         clear=\E[H\E[2J, cnorm=\E[?25h, cr=^M, 
         ...</computeroutput>
	      </screen>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="resetref"><command>reset</command></term>
	  <indexterm>
	    <primary>reset</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>reset</secondary>
	  </indexterm>
	  <listitem>
	    <para>Reset terminal parameters and clear text screen. As with
	    <command>clear</command>, the cursor and prompt reappear in the
	    upper lefthand corner of the terminal.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="clearref"><command>clear</command></term>
	  <indexterm>
	    <primary>clear</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>clear</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>clear</command> command simply clears
	      the text screen at the console or in an
	      <firstterm>xterm</firstterm>. The prompt and cursor
	      reappear at the upper lefthand corner of the screen or
	      xterm window. This command may be used either at the command
	      line or in a script. See <xref linkend="ex30">.</para>
	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="resizeref"><command>resize</command></term>
	  <indexterm>
	    <primary>resize</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>resize</secondary>
	  </indexterm>
	  <listitem>
	    <para>Echoes commands necessary to set <varname>$TERM</varname>
	      and <varname>$TERMCAP</varname> to duplicate the
	      <firstterm>size</firstterm> (dimensions) of the current
	      terminal.</para>
	    <para>
	        <screen><prompt>bash$ </prompt><userinput>resize</userinput>
<computeroutput>set noglob;
 setenv COLUMNS '80';
 setenv LINES '24';
 unset noglob;</computeroutput>
	        </screen>
	      </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="scriptref"><command>script</command></term>
	  <indexterm>
	    <primary>script</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>script</secondary>
	  </indexterm>
	  <listitem>
	    <para>This utility records (saves to a file) all the user keystrokes at
	      the command line in a console or an xterm window. This, in effect,
	      creates a record of a session.</para>
	  </listitem>
	</varlistentry>

       </variablelist>	

	</sect1> <!-- End Terminal Control Commands -->

	
      <sect1 id="mathc">
        <title>Math Commands</title>

       <variablelist id="mathcommandlisting">	
         <title><anchor id="mathcommandlisting1"><quote>Doing the
	   numbers</quote></title>

      <varlistentry>
	<term><anchor id="factorref"><command>factor</command></term>
	  <indexterm>
	    <primary>factor</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>factor</secondary>
	  </indexterm>
	  <listitem><para>Decompose an integer into prime factors.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>factor 27417</userinput>
<computeroutput>27417: 3 13 19 37</computeroutput>
	      </screen>
	    </para>

            <example id="primes2">
              <title>Generating prime numbers</title>
              <programlisting>&primes2;</programlisting>
            </example>

	    </listitem>
	  </varlistentry>

	<varlistentry>
	  <term><anchor id="bcref"><command>bc</command></term>
	  <indexterm>
	    <primary>bc</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>bc</secondary>
	  </indexterm>
	  <listitem>

	    <para>Bash can't handle floating point calculations, and
	      it lacks operators for certain important mathematical
	      functions. Fortunately, <command>bc</command> comes to
	      the rescue.</para>

	    <para>Not just a versatile, arbitrary precision calculation
	      utility, <command>bc</command> offers many of the facilities of
	      a programming language.</para>

	    <para><command>bc</command> has a syntax vaguely resembling C.</para>

	    <para>Since it is a fairly well-behaved UNIX utility, and may
	       therefore be used in a <link linkend="piperef">pipe</link>,
	       <command>bc</command> comes in handy in scripts.</para>

	    <para><anchor id="bctemplate"></para>
	    <para>Here is a simple template for using
	      <command>bc</command> to calculate a script
	      variable. This uses <link linkend="commandsubref">command
	      substitution</link>.</para>

	      <para>
              <screen>
	      <userinput>variable=$(echo "OPTIONS; OPERATIONS" | bc)</userinput>
	      </screen>
	      </para>

	    <para><anchor id="monthlypmt0"></para>
            <example id="monthlypmt">
              <title>Monthly Payment on a Mortgage</title>
              <programlisting>&monthlypmt;</programlisting>
            </example>

	    <para><anchor id="base0"></para>
            <example id="base">
              <title>Base Conversion</title>
              <programlisting>&base;</programlisting>
            </example>

	      <para><anchor id="bcheredoc"></para>
	      <para>An alternate method of invoking <command>bc</command>
		involves using a <link linkend="heredocref">here
		document</link> embedded within a <link
		linkend="commandsubref">command substitution</link>
		block. This is especially appropriate when a script
		needs to pass a list of options and commands to
		<command>bc</command>.</para>

              <para>
	      <programlisting>variable=`bc << LIMIT_STRING
options
statements
operations
LIMIT_STRING
`

...or...


variable=$(bc << LIMIT_STRING
options
statements
operations
LIMIT_STRING
)</programlisting>
              </para>


            <example id="altbc">
              <title>Invoking <firstterm>bc</firstterm> using a <firstterm>here
	        document</firstterm></title>
              <programlisting>&altbc;</programlisting>
            </example>

	<para><anchor id="cannonref"></para>
            <example id="cannon">
              <title>Calculating PI</title>
              <programlisting>&cannon;</programlisting>
            </example>

	<para>See also <xref linkend="stddev">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="dcref"><command>dc</command></term>
	  <indexterm>
	    <primary>dc</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>dc</secondary>
	  </indexterm>
	  <listitem>

	    <para>The <command>dc</command> (<command>d</command>esk
	    <command>c</command>alculator) utility is stack-oriented
	      and uses RPN (<quote>Reverse Polish Notation</quote>). Like
	      <command>bc</command>, it has much of the power of a
	      programming language.</para>

              <para>Most persons avoid <command>dc</command>, since it
	        requires non-intuitive input. Yet, it has its uses.</para>

            <example id="hexconvert">
              <title>Converting a decimal number to hexadecimal</title>
              <programlisting>&hexconvert;</programlisting>
            </example>

	      <para>Studying the <firstterm>info</firstterm> page for
		<command>dc</command> is a painful path to understanding its
		intricacies. There seems to be a small, select group of
		<emphasis>dc wizards</emphasis> who delight in showing off
		their mastery of this powerful, but arcane utility.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>echo "16i[q]sa[ln0=aln100%Pln100/snlbx]sbA0D68736142snlbxq" | dc"</userinput>
<computeroutput>Bash</computeroutput>
	      </screen>
	  </para>

            <example id="factr">
              <title>Factoring</title>
              <programlisting>&factr;</programlisting>
            </example>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="awkmath"><command>awk</command></term>
	  <indexterm>
	    <primary>awk</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>math</secondary>
	  </indexterm>
	  <listitem>
	    <para>Yet another way of doing floating point math in
	      a script is using <link linkend="awkref">awk's</link>
	      built-in math functions in a <link linkend="shwrapper">shell
	      wrapper</link>.</para>

            <example id="hypot">
              <title>Calculating the hypotenuse of a triangle</title>
              <programlisting>&hypot;</programlisting>
            </example>

	  </listitem>
	</varlistentry>

       </variablelist>	

	</sect1> <!-- End Math Commands -->


      <sect1 id="extmisc">
        <title>Miscellaneous Commands</title>

       <variablelist id="misccommandlisting">	
         <title><anchor id="misccommandlisting1">Command that fit in no
	   special category</title>

	<varlistentry>
	  <term><anchor id="jotref"><command>jot</command></term>
	  <term><anchor id="seqref"><command>seq</command></term>
	  <indexterm>
	    <primary>jot</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>jot</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>seq</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>seq</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>loop</primary>
	    <secondary>arguments</secondary>
	  </indexterm>
	  <listitem>
	    <para>These utilities emit a sequence of integers, with a
	      user-selectable increment.</para>

	    <para>The default separator character between each integer is a
	      newline, but this can be changed with the <option>-s</option>
	      option.</para>
	    <para>
	      <screen>
<prompt>bash$ </prompt><userinput>seq 5</userinput>
<computeroutput>1
 2
 3
 4
 5</computeroutput>



<prompt>bash$ </prompt><userinput>seq -s : 5</userinput>
<computeroutput>1:2:3:4:5</computeroutput>
	      </screen>
	    </para>
	      
	      
	    <para>Both <command>jot</command> and <command>seq</command>
	      come in handy in a <link linkend="forloopref1">for
	      loop</link>.</para>

	    <example id="ex53">
	      <title>Using <firstterm>seq</firstterm> to generate loop
	      arguments</title>
	      <programlisting>&ex53;</programlisting>
	    </example>	    	   

	    <para>A simpler example:</para>

	<para><programlisting>#  Create a set of 10 files,
#+ named file.1, file.2 . . . file.10.
COUNT=10
PREFIX=file

for filename in `seq $COUNT`
do
  touch $PREFIX.$filename
  #  Or, can do other operations,
  #+ such as rm, grep, etc.
done</programlisting></para>

	    <example id="lettercount">
	      <title>Letter Count"</title>
	      <programlisting>&lettercount;</programlisting>
	    </example>	    	   

      <note>
      <para>Somewhat more capable than <firstterm>seq</firstterm>,
	<command>jot</command> is a classic UNIX
	utility that is not normally included in a standard Linux
	distro. However, the source <firstterm>rpm</firstterm>
	is available for download from the <ulink
	url="http://www.mit.edu/afs/athena/system/rhlinux/athena-9.0/free/SRPMS/athena-jot-9.0-3.src.rpm">
	MIT repository</ulink>.</para>

      <para><anchor id="jotrandom"></para>
      <para>Unlike <firstterm>seq</firstterm>, <command>jot</command> can
        generate a sequence of random numbers, using the <option>-r</option>
	option.</para>
	  <para><screen><prompt>bash$ </prompt><userinput>jot -r 3 999</userinput>
<computeroutput>1069
 1272
 1428</computeroutput></screen></para>
      </note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="getopty"><command>getopt</command></term>
	  <indexterm>
	    <primary>getopt</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>option</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>getopt</command> command
	      parses command-line options preceded by a <link
	      linkend="dashref">dash</link>. This external command
	      corresponds to the <link linkend="getoptsx">getopts</link>
	      Bash builtin. Using <command>getopt</command> permits
	      handling long options by means of the <option>-l</option>
	      flag, and this also allows parameter reshuffling.</para>

	    <example id="ex33a">
	      <title>Using <firstterm>getopt</firstterm> to parse command-line
	        options</title>
	      <programlisting>&ex33a;</programlisting>
	    </example>

	    <note>
	    <para>As <emphasis>Peggy Russell</emphasis> points out:</para>
	    <para>It is often necessary to include an <link
	      linkend="evalref">eval</link> to correctly process
              <link linkend="whitespaceref">whitespace</link> and
	      <firstterm>quotes</firstterm>.
	        <programlisting>args=$(getopt -o a:bc:d -- "$@")
eval set -- "$args"</programlisting></para>
	    </note>

	    <para>See <xref linkend="getoptsimple"> for a simplified emulation
	      of <command>getopt</command>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="runpartsref"><command>run-parts</command></term>
	  <indexterm>
	    <primary>run-parts</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>run-parts</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>run-parts</command> command

		<footnote><para>This is actually a script adapted from
		the Debian Linux distribution.</para></footnote>
	      
	      executes all the scripts in a target directory, sequentially
	      in ASCII-sorted filename order. Of course, the scripts
	      need to have execute permission.</para>
	      
	    <para>The <link linkend="cronref">cron</link> <link
	      linkend="daemonref">daemon</link> invokes
	      <command>run-parts</command> to run the scripts in
	      the <filename class="directory">/etc/cron.*</filename>
	      directories.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="yesref"><command>yes</command></term>
	  <indexterm>
	    <primary>yes</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>yes</secondary>
	  </indexterm>
	  <listitem>

	    <para>In its default behavior the <command>yes</command>
	      command feeds a continuous string of the character
	      <computeroutput>y</computeroutput> followed
	      by a line feed to <filename>stdout</filename>. A
	      <keycombo><keycap>control</keycap><keycap>C</keycap></keycombo>
	      terminates the run. A different output string
	      may be specified, as in <userinput>yes different
	      string</userinput>, which would continually output
	      <computeroutput>different string</computeroutput> to
	      <filename>stdout</filename>.</para>
	      
	    <para>One might well ask the purpose of this. From the
	      command line or in a script, the output of
	      <command>yes</command> can be redirected or piped into a
	      program expecting user input. In effect, this becomes a sort
	      of poor man's version of <firstterm>expect</firstterm>.</para>

	    <para><userinput>yes | fsck /dev/hda1</userinput> runs
	      <command>fsck</command> non-interactively (careful!).</para>

	   <para><userinput>yes | rm -r dirname</userinput> has same effect as
	     <userinput>rm -rf dirname</userinput> (careful!).</para>

	   <warning><para>Caution advised when piping
	     <firstterm>yes</firstterm> to a potentially dangerous
	     system command, such as <link linkend="fsckref">fsck</link>
	     or <link linkend="fdiskref">fdisk</link>. It might have
	     unintended consequences.</para></warning>

           <note>
	     <para>The <firstterm>yes</firstterm> command parses variables,
	       or more accurately, it echoes parsed variables.
	       For example:</para>
	        <para>
	        <screen><prompt>bash$ </prompt><userinput>yes $BASH_VERSION</userinput>
<computeroutput>3.1.17(1)-release
 3.1.17(1)-release
 3.1.17(1)-release
 3.1.17(1)-release
 3.1.17(1)-release
 . . .</computeroutput>
	      </screen>
	        </para>

	     <para>
	       This particular <quote>feature</quote> may be used
	       to create a <emphasis>very large</emphasis> ASCII file on the fly:
	      <screen><prompt>bash$ </prompt><userinput>yes $PATH > huge_file.txt</userinput>
<userinput>Ctl-C</userinput>	      
	      </screen>
	      Hit <userinput>Ctl-C</userinput> <emphasis>very
	      quickly</emphasis>, or you just might get more than you
	      bargained for. . . .
	      </para>
           </note>

	   <para><anchor id="yesemu">The <firstterm>yes</firstterm>
	     command may be emulated in a very simple script <link
	     linkend="functionref">function</link>.</para>

	   <para><programlisting>yes ()
{ # Trivial emulation of "yes" ...
  local DEFAULT_TEXT="y"
  while [ true ]   # Endless loop.
  do
    if [ -z "$1" ]
    then
      echo "$DEFAULT_TEXT"
    else           # If argument ...
      echo "$1"    # ... expand and echo it.
    fi
  done             #  The only things missing are the
}                  #+ --help and --version options.</programlisting></para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="bannerref"><command>banner</command></term>
	  <indexterm>
	    <primary>banner</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>banner</secondary>
	  </indexterm>
	  <listitem>
	    <para>Prints arguments as a large vertical banner to
	      <filename>stdout</filename>, using an ASCII character
	      (default '#'). This may be redirected to a printer for
	      hardcopy.</para>
	      
	    <para>Note that <firstterm>banner</firstterm> has been
              dropped from many Linux distros.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="printenvref"><command>printenv</command></term>
	  <indexterm>
	    <primary>printenv</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>environment</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show all the <link linkend="envref">environmental
	      variables</link> set for a particular user.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>printenv | grep HOME</userinput>
<computeroutput>HOME=/home/bozo</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lpref"><command>lp</command></term>
	  <indexterm>
	    <primary>lp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>lpr</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>lp</command> and <command>lpr</command>
	      commands send file(s) to the print queue, to be printed as
	      hard copy.

	      <footnote><para>The <firstterm>print queue</firstterm> is
	      the group of jobs <quote>waiting in line</quote> to be
	      printed.</para></footnote>

	      These commands trace the origin of their names to the
	      line printers of another era.</para>

	      <para><prompt>bash$ </prompt><userinput>lp file1.txt</userinput>
	        or <prompt>bash </prompt><userinput>lp
		&lt;file1.txt</userinput></para>

	      <para>It is often useful to pipe the formatted output from
	        <command>pr</command> to <command>lp</command>.</para>

	      <para><prompt>bash$ </prompt><userinput>pr -options file1.txt | lp</userinput>
	        </para>

	      <para>Formatting packages, such as <link
	      linkend="groffref">groff</link> and
		<firstterm>Ghostscript</firstterm> may send their output
		directly to <command>lp</command>.</para>

	      <para><prompt>bash$ </prompt><userinput>groff -Tascii file.tr | lp</userinput>
	        </para>

	      <para><prompt>bash$ </prompt><userinput>gs -options | lp file.ps</userinput>
	        </para>

	      <para>Related commands are <command>lpq</command>, for viewing
	        the print queue, and <command>lprm</command>, for removing
		jobs from the print queue.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="teeref"><command>tee</command></term>
	  <indexterm>
	    <primary>tee</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tee</secondary>
	  </indexterm>
	  <listitem>
	    <para>[UNIX borrows an idea from the plumbing trade.]</para>
	    <para>This is a redirection operator, but with a difference. Like the
	      plumber's <firstterm>tee,</firstterm> it permits <quote>siphoning
              off</quote> <emphasis>to a file </emphasis>the output of a command 
	      or commands within a pipe, but without affecting the result. This is
	      useful for printing an ongoing process to a file or paper, perhaps to
	      keep track of it for debugging purposes.</para>
	    
	    <screen>
                             (redirection)
                            |----> to file
                            |
  ==========================|====================
  command ---> command ---> |tee ---> command ---> ---> output of pipe
  ===============================================
	      </screen>


	    <para><programlisting>cat listfile* | sort | tee check.file | uniq > result.file
#                      ^^^^^^^^^^^^^^   ^^^^    

#  The file "check.file" contains the concatenated sorted "listfiles,"
#+ before the duplicate lines are removed by 'uniq.'</programlisting></para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mkfiforef"><command>mkfifo</command></term>
	  <indexterm>
	    <primary>mkfifo</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mkfifo</secondary>
	  </indexterm>
	  <listitem>
	    <para><anchor id="namedpiperef">This obscure command
	      creates a <firstterm>named pipe</firstterm>, a temporary
	      <firstterm>first-in-first-out buffer</firstterm> for
	      transferring data between processes.

		<footnote><para>For an excellent overview of this
		  topic, see Andy Vaught's article, <ulink
		  url="http://www2.linuxjournal.com/lj-issues/issue41/2156.html">Introduction
		  to Named Pipes</ulink>, in the September, 1997 issue of
		  <ulink url="http://www.linuxjournal.com"><citetitle
		  pubwork="journal">Linux
		  Journal</citetitle></ulink>.</para></footnote>

	      Typically, one process writes to the FIFO, and the other
	      reads from it. See <xref linkend="fifo">.</para>

            <para>
	      <programlisting>#!/bin/bash
# This short script by Omair Eshkenazi.
# Used in ABS Guide with permission (thanks!).

mkfifo pipe1   # Yes, pipes can be given names.
mkfifo pipe2   # Hence the designation "named pipe."

(cut -d' ' -f1 | tr "a-z" "A-Z") >pipe2 &lt;pipe1 &amp;
ls -l | tr -s ' ' | cut -d' ' -f3,9- | tee pipe1 |
cut -d' ' -f2 | paste - pipe2

rm -f pipe1
rm -f pipe2

# No need to kill background processes when script terminates (why not?).

exit $?

Now, invoke the script and explain the output:
sh mkfifo-example.sh

4830.tar.gz          BOZO
pipe1   BOZO
pipe2   BOZO
mkfifo-example.sh    BOZO
Mixed.msg BOZO</programlisting>
            </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="pathchkref"><command>pathchk</command></term>
	  <indexterm>
	    <primary>pathchk</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>pathchk</secondary>
	  </indexterm>
	  <listitem>
	    <para>This command checks the validity of a filename. If the
	      filename exceeds the maximum allowable length (255
	      characters) or one or more of the directories in
	      its path is not searchable, then an error message
	      results.</para>
	      
	    <para>Unfortunately, <command>pathchk</command> does
	      not return a recognizable error code, and it is therefore
	      pretty much useless in a script. Consider instead the
	      <link linkend="rtif">file test operators</link>.</para>
	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="ddref"><command>dd</command></term>
	  <indexterm>
	    <primary>dd</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>dd</secondary>
	  </indexterm>
	  <listitem>
	    <para>This is the somewhat obscure and much feared <firstterm>data
	      duplicator</firstterm> command. Originally a utility
	      for exchanging data on magnetic tapes between UNIX
	      minicomputers and IBM mainframes, this command still
	      has its uses.  The <command>dd</command> command simply
	      copies a file (or <filename>stdin/stdout</filename>), but
	      with conversions. <anchor id="ddconversions">Possible
	      conversions are ASCII/EBCDIC,
	        
		<footnote><para><acronym>EBCDIC</acronym> (pronounced
		  <quote>ebb-sid-ick</quote>) is an acronym for Extended
		  Binary Coded Decimal Interchange Code. This is an IBM
		  data format no longer in much use. A bizarre
		  application of the <option>conv=ebcdic</option> option
		  of <command>dd</command> is as a quick 'n easy, but
		  not very secure text file encoder.
		    <programlisting>cat $file | dd conv=swab,ebcdic > $file_encrypted
# Encode (looks like gibberish).		    
# Might as well switch bytes (swab), too, for a little extra obscurity.

cat $file_encrypted | dd conv=swab,ascii > $file_plaintext
# Decode.</programlisting>
                </para></footnote>

	      upper/lower case, swapping of byte pairs between input
	      and output, and skipping and/or truncating the head or
	      tail of the input file.</para>
	      
            <para>
	      <programlisting># Converting a file to all uppercase:

dd if=$filename conv=ucase > $filename.uppercase
#                    lcase   # For lower case conversion</programlisting>
            </para>

	    <para><anchor id="ddoptions"></para>
            <para>Some basic options to <command>dd</command> are:
                <itemizedlist>
                   <listitem>
                      <para>if=INFILE</para>
		      <para>INFILE is the <firstterm>source</firstterm>
		        file.</para>
                   </listitem>
                   <listitem>
                      <para>of=OUTFILE</para>
		      <para>OUTFILE is the <firstterm>target</firstterm>
		        file, the file that will have the data written to it.</para>
                   </listitem>
                   <listitem>
                      <para>bs=BLOCKSIZE</para>
		      <para>This is the size of each block of data being read
		        and written, usually a power of 2.</para>
                   </listitem>
                   <listitem>
                      <para>skip=BLOCKS</para>
		      <para>How many blocks of data to skip in INFILE before
		        starting to copy. This is useful when the INFILE has
			<quote>garbage</quote> or garbled data in its
			header or when it is desirable to copy only a portion
			of the INFILE.</para>
                   </listitem>
                   <listitem>
                      <para>seek=BLOCKS</para>
		      <para>How many blocks of data to skip in OUTFILE before
		        starting to copy, leaving blank data at beginning
			of OUTFILE.</para>
                   </listitem>
                   <listitem>
                      <para>count=BLOCKS</para>
		      <para>Copy only this many blocks of data, rather than the
		        entire INFILE.</para>
                   </listitem>
                   <listitem>
                      <para>conv=CONVERSION</para>
		      <para>Type of conversion to be applied to INFILE data
                        before copying operation.</para>
                   </listitem>
                </itemizedlist>
            </para>

	    <para>A <userinput>dd --help</userinput> lists all the
	      options this powerful utility takes.</para>


	    <example id="selfcopy">
	      <title>A script that copies itself</title>
	      <programlisting>&selfcopy;</programlisting>
	    </example>

	    <example id="exercisingdd">
	      <title>Exercising <firstterm>dd</firstterm></title>
	      <programlisting>&exercisingdd;</programlisting>
	    </example>


	    <para><anchor id="ddkeystrokes"></para>
	    <para>To demonstrate just how versatile <command>dd</command> is,
	     let's use it to capture keystrokes.</para>

	    <example id="ddkeypress">
	      <title>Capturing Keystrokes</title>
	      <programlisting>&ddkeypress;</programlisting>
	    </example>	    

	    <para><anchor id="ddrandom"></para>
	    <para>The <command>dd</command> command can do random access on a
	      data stream.

	        <programlisting>echo -n . | dd bs=1 seek=4 of=file conv=notrunc
#  The "conv=notrunc" option means that the output file
#+ will not be truncated.

# Thanks, S.C.</programlisting>
            </para>


	    <para><anchor id="ddcopy"></para>
	    <para>The <command>dd</command> command can copy raw data
	      and disk images to and from devices, such as floppies and
	      tape drives (<xref linkend="copycd">). A common use is
	      creating boot floppies.</para>
             <para>
		<userinput>dd if=kernel-image of=/dev/fd0H1440</userinput>
             </para>

             <para>Similarly, <command>dd</command> can copy the entire
	       contents of a floppy, even one formatted with a
	       <quote>foreign</quote> OS, to the hard drive as an
	       image file.</para>
             <para>
		<userinput>dd if=/dev/fd0 of=/home/bozo/projects/floppy.img</userinput>
             </para>

	     <para><anchor id="ddswap"></para>
             <para>
	      Other applications of <command>dd</command> include
	      initializing temporary swap files (<xref linkend="ex73">)
	      and ramdisks (<xref linkend="ramdisk">). It can even do a
	      low-level copy of an entire hard drive partition, although
	      this is not necessarily recommended.</para>

	    <para>People (with presumably nothing better to do with
	      their time) are constantly thinking of interesting
	      applications of <command>dd</command>.</para>

	    <para><anchor id="ddfdel"></para>
	    <example id="blotout">
	      <title>Securely deleting a file</title>
	      <programlisting>&blotout;</programlisting>
	    </example>	    

	    <para>See also the <link linkend="ddlink">dd
	      thread</link> entry in the <link
	      linkend="biblioref">bibliography</link>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="odref"><command>od</command></term>
	  <indexterm>
	    <primary>od</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>od</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>od</command>, or <firstterm>octal
	      dump</firstterm> filter converts input (or files) to octal
	      (base-8) or other bases. This is useful for viewing or
	      processing binary data files or otherwise unreadable system
	      device files, such as <filename>/dev/urandom</filename>,
	      and as a filter for binary data.</para>

	  <para>
	      <programlisting>head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p'
# Sample output: 1324725719, 3918166450, 2989231420, etc.

# From rnd.sh example script, by St&eacute;phane Chazelas</programlisting>
	  </para>
	      
	  <para>See also <xref linkend="seedingrandom"> and <xref
	     linkend="insertionsort">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="hexdumpref"><command>hexdump</command></term>
	  <indexterm>
	    <primary>hexdump</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>hexadecimal</secondary>
	  </indexterm>
	  <listitem>
	    <para>Performs a hexadecimal, octal, decimal, or ASCII
	      dump of a binary file. This command is the rough equivalent
	      of <command>od</command>, above, but not nearly as
	      useful. May be used to view the contents of a binary file,
	      in combination with <link linkend="ddref">dd</link> and <link
	      linkend="lessref">less</link>.</para>

	  <para>
	  <programlisting>dd if=/bin/ls | hexdump -C | less
# The -C option nicely formats the output in tabular form.</programlisting>
	    </para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="objdumpref"><command>objdump</command></term>
	  <indexterm>
	    <primary>objdump</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>object binary dump</secondary>
	  </indexterm>
	  <listitem>
	    <para>Displays information about an object file or binary
	      executable in either hexadecimal form or as a disassembled
	      listing (with the <option>-d</option> option).</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>objdump -d /bin/ls</userinput>
<computeroutput>/bin/ls:     file format elf32-i386

 Disassembly of section .init:

 080490bc &lt;.init&gt;:
  80490bc:       55                      push   %ebp
  80490bd:       89 e5                   mov    %esp,%ebp
  . . .</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mcookieref"><command>mcookie</command></term>
	  <indexterm>
	    <primary>magic</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>cookie</secondary>
	  </indexterm>
	  <listitem>

	    <para>This command generates a <quote>magic cookie,</quote> a
	      128-bit (32-character) pseudorandom hexadecimal number,
	      normally used as an authorization <quote>signature</quote>
	      by the X server. This also available for use in a script
	      as a <quote>quick 'n dirty</quote> random number.</para>

	    <para><programlisting>random000=$(mcookie)</programlisting></para>

	    <para>Of course, a script could use <link
	    linkend="md5sumref">md5sum</link> for the same purpose.</para>

            <para><programlisting># Generate md5 checksum on the script itself.
random001=`md5sum $0 | awk '{print $1}'`
# Uses 'awk' to strip off the filename.</programlisting></para>

	    <para>The <command>mcookie</command> command gives yet another way
	      to generate a <quote>unique</quote> filename.</para>

	    <example id="tempfilename">
	      <title>Filename generator</title>
	      <programlisting>&tempfilename;</programlisting>
	    </example>
	      
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="unitsref"><command>units</command></term>
	  <indexterm>
	    <primary>units</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>conversion</secondary>
	  </indexterm>
	  <listitem>
	    <para>This utility converts between different <firstterm>units
	      of measure</firstterm>. While normally invoked in interactive
	      mode, <command>units</command> may find use in a
	      script.</para>
	    <example id="unitconversion">
	      <title>Converting meters to miles</title>
	      <programlisting>&unitconversion;</programlisting>
	    </example>
	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="m4ref"><command>m4</command></term>
	  <indexterm>
	    <primary>m4</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>macro</secondary>
	  </indexterm>
	  <listitem>
	    <para>A hidden treasure, <command>m4</command> is a
	      powerful macro
		 <footnote><para>A <firstterm>macro</firstterm> is a
		 symbolic constant that expands into a command string
		 or a set of operations on parameters. Simply put,
		 it's a shortcut or abbreviation.</para></footnote>
	      processing filter, virtually a complete language.
	      Although originally written as a pre-processor
	      for <firstterm>RatFor</firstterm>, <command>m4</command>
	      turned out to be useful as a stand-alone utility. In
	      fact, <command>m4</command> combines some of the
	      functionality of <link linkend="evalref">eval</link>,
	      <link linkend="trref">tr</link>, and <link
	      linkend="awkref">awk</link>, in addition to its extensive
	      macro expansion facilities.</para>

	    <para>The April, 2002 issue of <ulink
	      url="http://www.linuxjournal.com"><citetitle
	      pubwork="journal">Linux Journal</citetitle></ulink>
	      has a very nice article on <command>m4</command> and
	      its uses.</para>

	    <example id="m4">
	      <title>Using <firstterm>m4</firstterm></title>
	      <programlisting>&m4;</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="xmessageref"><command>xmessage</command></term>
	  <indexterm>
	    <primary>xmessage</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>macro</secondary>
	  </indexterm>
	  <listitem>
	    <para>This X-based variant of
              <link linkend="echoref">echo</link> pops up a message/query
	      window on the desktop.</para>
	    <para>
	      <programlisting>xmessage Left click to continue -button okay</programlisting>
	      </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="zenityref"><command>zenity</command></term>
	  <indexterm>
	    <primary>zenity</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>macro</secondary>
	  </indexterm>
	  <listitem>
	    <para>The
	      <ulink url="http://freshmeat.net/projects/zenity">zenity</ulink>
	      utility is adept at displaying
	      <firstterm>GTK+</firstterm> dialog <link
	      linkend="widgetref">widgets</link> and <link
	      linkend="zenityref2">very suitable for scripting
	      purposes</link>.</para>
	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="doexecref"><command>doexec</command></term>
	  <indexterm>
	    <primary>doexec</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>executable arg list</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>doexec</command> command enables passing
	      an arbitrary list of arguments to a <firstterm>binary
	      executable</firstterm>. In particular, passing
	      <parameter>argv[0]</parameter> (which corresponds to <link
	      linkend="posparamref1">$0</link> in a script) lets the
	      executable be invoked by various names, and it can then
	      carry out different sets of actions, according to the name
	      by which it was called. What this amounts to is roundabout
	      way of passing options to an executable.</para>

	    <para>For example, the <filename
	      class="directory">/usr/local/bin</filename> directory might
	      contain a binary called <quote>aaa</quote>.  Invoking
	      <command>doexec /usr/local/bin/aaa list</command>
	      would <emphasis>list</emphasis> all those files
	      in the current working directory beginning with an
	      <quote>a</quote>, while invoking (the same executable
	      with) <command>doexec /usr/local/bin/aaa delete </command>
	      would <emphasis>delete</emphasis> those files.</para>

            <note><para>The various behaviors of the executable
              must be defined within the code of the executable itself,
              analogous to something like the following in a shell script:
                <programlisting>case `basename $0` in
"name1" ) do_something;;
"name2" ) do_something_else;;
"name3" ) do_yet_another_thing;;
*       ) bail_out;;
esac</programlisting></para></note>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><command>dialog</command></term>
	  <indexterm>
	    <primary>dialog</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>dialog</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <link linkend="dialogref">dialog</link> family of tools
	      provide a method of calling interactive
	      <quote>dialog</quote> boxes from a script. The more
	      elaborate variations of <command>dialog</command> --
	      <command>gdialog</command>, <command>Xdialog</command>,
	      and <command>kdialog</command> -- actually invoke X-Windows
	      <link linkend="widgetref">widgets</link>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="soxref"><command>sox</command></term>
	  <indexterm>
	    <primary>sox</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sound</secondary>
	  </indexterm>
	  <listitem>

	    <para>The <command>sox</command>, or
	      <quote><command>so</command>und
	      e<command>x</command>change</quote> command plays and
	      performs transformations on sound files. In fact,
	      the <filename>/usr/bin/play</filename> executable
	      (now deprecated) is nothing but a shell wrapper for
	      <firstterm>sox</firstterm>.</para>

            <para>For example, <command>sox soundfile.wav
	      soundfile.au</command> changes a WAV sound file into a
	      (Sun audio format) AU sound file.</para>

            <para>Shell scripts are ideally suited for batch-processing
	      <command>sox</command> operations on
	      sound files. For examples, see the <ulink
	      url="http://osl.iu.edu/~tveldhui/radio/"> Linux Radio
	      Timeshift HOWTO</ulink> and the <ulink
	      url="http://savannah.nongnu.org/projects/audiodo">MP3do
	      Project</ulink>.</para>

	  </listitem>
	</varlistentry>


      </variablelist>

        </sect1> <!-- End Miscellaneous Commands -->

  </chapter> <!-- External Filters, Programs and Commands -->



  <chapter id="system">
    <title>System and Administrative Commands</title>


      <para>The startup and shutdown scripts in 
	<filename class="directory">/etc/rc.d</filename> illustrate the uses
	(and usefulness) of many of these comands. These are usually
	invoked by <firstterm>root</firstterm> and used for system
	maintenance or emergency filesystem repairs. Use with caution, as
	some of these commands may damage your system if misused.</para>

      <variablelist id="usersgroups">
        <title><anchor id="usersgroups1">Users and Groups</title>

	<varlistentry>
	  <term><anchor id="usersref"><command>users</command></term>
	  <indexterm>
	    <primary>users</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>users</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show all logged on users. This is the approximate
	      equivalent of <command>who -q</command>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="groupscmdref"><command>groups</command></term>
	  <indexterm>
	    <primary>groups</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>groups</secondary>
	  </indexterm>
	  <listitem>
	    <para>Lists the current user and the groups she belongs to.
	       This corresponds to the <link
	       linkend="groupsref">$GROUPS</link> internal variable,
	       but gives the group names, rather than the numbers.</para>
	    <screen><prompt>bash$ </prompt><userinput>groups</userinput>
<computeroutput>bozita cdrom cdwriter audio xgrp</computeroutput>

<prompt>bash$ </prompt><userinput>echo $GROUPS</userinput>
<computeroutput>501</computeroutput></screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="chownref"><command>chown</command></term>
	  <term><anchor id="chgrpref"><command>chgrp</command></term>
	  <indexterm>
	    <primary>chown</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>chown</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>chgrp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>chgrp</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>chown</command> command changes the
	      ownership of a file or files. This command is a useful
	      method that <firstterm>root</firstterm> can use to
	      shift file ownership from one user to another. An ordinary
	      user may not change the ownership of files, not even her
	      own files.
	         <footnote><para>This is the case on a Linux machine or a UNIX
		   system with disk quotas.</para></footnote>
	      </para>

	  <para>
	      <screen><prompt>root# </prompt><userinput>chown bozo *.txt</userinput>
<computeroutput></computeroutput>
	      </screen>
	    </para>

	    <para>The <command>chgrp</command> command changes the
	      <replaceable>group</replaceable> ownership of a file or
	      files. You must be owner of the file(s) as well as a member
	      of the destination group (or <firstterm>root</firstterm>)
	      to use this operation.
	      <programlisting>chgrp --recursive dunderheads *.data
#  The "dunderheads" group will now own all the "*.data" files
#+ all the way down the $PWD directory tree (that's what "recursive" means).
</programlisting></para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="useraddref"><command>useradd</command></term>
	  <term><command>userdel</command></term>
	  <indexterm>
	    <primary>useradd</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>useradd</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>userdel</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>userdel</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>useradd</command> administrative command
	      adds a user account to the system and creates a home
	      directory for that particular user, if so specified. The
	      corresponding <command>userdel</command> command removes
	      a user account from the system
		 <footnote><para>The <command>userdel</command> command
		   will fail if the particular user being deleted is
		   still logged on.</para></footnote>
	      and deletes associated files.</para>

	    <note><para>The <command>adduser</command> command is a synonym
	      for <command>useradd</command> and is usually a symbolic link to
	      it.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="usermodref"><command>usermod</command></term>
	  <indexterm>
	    <primary>usermod</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>usermod</secondary>
	  </indexterm>
	  <listitem>
	    <para>Modify a user account. Changes may be made to the password,
	      group membership, expiration date, and other attributes of
	      a given user's account. With this command, a user's password
	      may be locked, which has the effect of disabling the
	      account.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="groupmodref"><command>groupmod</command></term>
	  <indexterm>
	    <primary>groupmod</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>group</secondary>
	  </indexterm>
	  <listitem>
	    <para>Modify a given group. The group name and/or ID number may be
	      changed using this command.</para>
	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="idref"><command>id</command></term>
	  <indexterm>
	    <primary>id</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>id</secondary>
	  </indexterm>
	  <listitem>

	    <para>The <command>id</command> command lists the real and
	      effective user IDs and the group IDs of the user
	      associated with the current process. This is the
	      counterpart to the <link linkend="uidref">$UID</link>,
	      <link linkend="euidref">$EUID</link>, and <link
	      linkend="groupsref">$GROUPS</link> internal Bash
	      variables.</para>

	    <screen><prompt>bash$ </prompt><userinput>id</userinput>
<computeroutput>uid=501(bozo) gid=501(bozo) groups=501(bozo),22(cdrom),80(cdwriter),81(audio)</computeroutput>

<prompt>bash$ </prompt><userinput>echo $UID</userinput>
<computeroutput>501</computeroutput></screen>

	    <note><para>The <command>id</command> command shows the
	      <emphasis>effective</emphasis> IDs only when they differ
	      from the <emphasis>real</emphasis> ones.</para></note>

            <para>Also see <xref linkend="amiroot">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lidref"><command>lid</command></term>
	  <indexterm>
	    <primary>lid</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>group</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <firstterm>lid</firstterm> (list ID) command
	      shows the group(s) that a given user belongs to, or alternately,
	      the users belonging to a given group. May be invoked only by
	      root.</para>
	  <para>
	      <screen><prompt>root# </prompt><userinput>lid bozo</userinput>
<computeroutput> bozo(gid=500)</computeroutput>


<prompt>root# </prompt><userinput>lid daemon</userinput>
<computeroutput> bin(gid=1)
  daemon(gid=2)
  adm(gid=4)
  lp(gid=7)</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="whoref"><command>who</command></term>
	  <indexterm>
	    <primary>who</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>whoami</secondary>
	  </indexterm>
	  <listitem>

	    <para>Show all users logged on to the system.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>who</userinput>
<computeroutput>bozo  tty1     Apr 27 17:45
 bozo  pts/0    Apr 27 17:46
 bozo  pts/1    Apr 27 17:47
 bozo  pts/2    Apr 27 17:49
</computeroutput>
	      </screen>
	    </para>

	    <para>The <option>-m</option> gives detailed information about
	      only the current user. Passing any two arguments to
	      <command>who</command> is the equivalent of <command>who
	      -m</command>, as in <command>who am i</command> or <command>who
	      The Man</command>.</para> 
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>who -m</userinput>
<computeroutput>localhost.localdomain!bozo  pts/2    Apr 27 17:49</computeroutput>
	      </screen>
	    </para>


	    <para><anchor id="whoamiref"><command>whoami</command> is similar to <command>who
	      -m</command>, but only lists the user name.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>whoami</userinput>
<computeroutput>bozo</computeroutput>
	      </screen>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="wref"><command>w</command></term>
	  <indexterm>
	    <primary>w</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>w</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show all logged on users and the processes belonging to them. This is
	      an extended version of <command>who</command>. The output of <command>w</command>
	      may be piped to <link linkend="grepref">grep</link> to find
	      a specific user and/or process.</para>

	    <screen><prompt>bash$ </prompt><userinput>w | grep startx</userinput>
<computeroutput>bozo  tty1     -                 4:22pm  6:41   4.47s  0.45s  startx</computeroutput></screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lognameref"><command>logname</command></term>
	  <indexterm>
	    <primary>logname</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>logname</secondary>
	  </indexterm>
	  <listitem>

	    <para>Show current user's login name (as found in
	      <filename>/var/run/utmp</filename>). This is a
	      near-equivalent to <link linkend="whoamiref">whoami</link>,
	      above.</para>

	    <screen><prompt>bash$ </prompt><userinput>logname</userinput>
<computeroutput>bozo</computeroutput>

<prompt>bash$ </prompt><userinput>whoami</userinput>
<computeroutput>bozo</computeroutput></screen>	    

            <para>However . . .</para>

	    <para>
	    <screen><prompt>bash$ </prompt><userinput>su</userinput>
<computeroutput>Password: ......</computeroutput>

<prompt>bash# </prompt><userinput>whoami</userinput>
<computeroutput>root</computeroutput>
<prompt>bash# </prompt><userinput>logname</userinput>
<computeroutput>bozo</computeroutput></screen>	    
	    </para>

	      
	    <note><para>While <command>logname</command> prints the name
	      of the logged in user, <command>whoami</command> gives the
	      name of the user attached to the current process. As we have
	      just seen, sometimes these are not the same.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="suref"><command>su</command></term>
	  <indexterm>
	    <primary>su</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>su</secondary>
	  </indexterm>
	  <listitem>
	    <para>Runs a program or script as a
	      <command>s</command>ubstitute <command>u</command>ser.
	      <command>su rjones</command> starts a shell as user
	      <emphasis>rjones</emphasis>. A naked <command>su</command>
	      defaults to <firstterm>root</firstterm>.  See <xref
	      linkend="fifo">.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="sudoref"><command>sudo</command></term>
	  <indexterm>
	    <primary>sudo</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sudo</secondary>
	  </indexterm>
	  <listitem>
	    <para>Runs a command as <firstterm>root</firstterm> (or
	      another user). This may be used in a script, thus permitting
	      a <firstterm>regular user</firstterm> to run the script.</para>

	      <para><programlisting>#!/bin/bash

# Some commands.
sudo cp /root/secretfile /home/bozo/secret
# Some more commands.</programlisting></para>
	    
	    <para>The file <filename>/etc/sudoers</filename> holds
	      the names of users permitted to invoke
	      <command>sudo</command>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="passwdref"><command>passwd</command></term>
	  <indexterm>
	    <primary>passwd</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>password</secondary>
	  </indexterm>
	  <listitem>

	    <para>Sets, changes, or manages a user's password.</para>

	    <para>The <command>passwd</command> command can be used in
	      a script, but probably <emphasis>should not</emphasis> be.</para>

	    <example id="setnewpw">
	      <title>Setting a new password</title>
	      <programlisting>&setnewpw;</programlisting>
	    </example>

            <para>The <command>passwd</command> command's <option>-l</option>,
	      <option>-u</option>, and <option>-d</option> options permit
	      locking, unlocking, and deleting a user's password. Only
	      <firstterm>root</firstterm> may use these options.</para>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="acref"><command>ac</command></term>
	  <indexterm>
	    <primary>ac</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>accounting</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show users' logged in time, as read from
	      <filename>/var/log/wtmp</filename>. This is one of the GNU
	      accounting utilities.</para>
	    <screen><prompt>bash$ </prompt><userinput>ac</userinput>
<computeroutput>        total       68.08</computeroutput></screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lastref"><command>last</command></term>
	  <indexterm>
	    <primary>last</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>logged in</secondary>
	  </indexterm>
	  <listitem>

	    <para>List <emphasis>last</emphasis> logged in users, as read from
	      <filename>/var/log/wtmp</filename>. This command can also
	      show remote logins.</para>

            <para>For example, to show the last few times the system
	      rebooted:</para>

	    <screen><prompt>bash$ </prompt><userinput>last reboot</userinput>
<computeroutput>reboot   system boot  2.6.9-1.667      Fri Feb  4 18:18          (00:02)    
 reboot   system boot  2.6.9-1.667      Fri Feb  4 15:20          (01:27)    
 reboot   system boot  2.6.9-1.667      Fri Feb  4 12:56          (00:49)    
 reboot   system boot  2.6.9-1.667      Thu Feb  3 21:08          (02:17)    
 . . .

 wtmp begins Tue Feb  1 12:50:09 2005</computeroutput></screen>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="newgrpref"><command>newgrp</command></term>
	  <indexterm>
	    <primary>newgrp</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>group</secondary>
	  </indexterm>
	  <listitem>
	    <para>Change user's <firstterm>group ID</firstterm> without
	      logging out. This permits access to the new group's
	      files. Since users may be members of multiple groups
	      simultaneously, this command finds only limited use.</para>

            <note><para>Kurt Glaesemann points out that the
	      <firstterm>newgrp</firstterm> command could prove helpful
	      in setting the default group permissions for files a user
	      writes. However, the <link linkend="chgrpref">chgrp</link>
	      command might be more convenient for this purpose.</para></note>

	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="terminalssys">
        <title><anchor id="terminalssys1">Terminals</title>

	<varlistentry>
	  <term><anchor id="ttyref"><command>tty</command></term>
	  <indexterm>
	    <primary>tty</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tty</secondary>
	  </indexterm>
	  <listitem>
	    <para>Echoes the name (filename) of the current user's terminal.
	      Note that each separate <firstterm>xterm</firstterm>
	      window counts as a different terminal.</para>
	    <screen><prompt>bash$ </prompt><userinput>tty</userinput>
<computeroutput>/dev/pts/1</computeroutput></screen>
	      
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="sttyref"><command>stty</command></term>
	  <indexterm>
	    <primary>stty</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>stty</secondary>
	  </indexterm>
	  <listitem>
	    <para>Shows and/or changes terminal settings. This complex
	      command, used in a script, can control terminal behavior
	      and the way output displays. See the info page, and study
	      it carefully.</para>

	    <example id="erase">
	      <title>Setting an <firstterm>erase</firstterm> character</title>
	      <programlisting>&erase;</programlisting>
	    </example>

	    <example id="secretpw">
	      <title><firstterm>secret password</firstterm>:
	      Turning off terminal echoing </title>
	      <programlisting>&secretpw;</programlisting>
	    </example>

	    <para>A creative use of <command>stty</command> is detecting a
	      user keypress (without hitting
	      <keycap>ENTER</keycap>).</para>

	    <example id="keypress">
	      <title>Keypress detection</title>
	      <programlisting>&keypress;</programlisting>
	    </example>

	    <para>Also see <xref linkend="timeout"> and <xref
	      linkend="stopwatch">.</para>


	    <para><anchor id="terminalsref"></para>
	    <sidebar><title>terminals and modes</title>

	    <para>Normally, a terminal works in the
	      <firstterm>canonical</firstterm> mode.  When a user hits a
	      key, the resulting character does not immediately go to
	      the program actually running in this terminal.  A buffer
	      local to the terminal stores keystrokes. When the user
	      hits the <keycap>ENTER</keycap> key, this sends all the
	      stored keystrokes to the program running.  There is even
	      a basic line editor inside the terminal.</para>

	    <para>
	        <screen><prompt>bash$ </prompt><userinput>stty -a</userinput>
<computeroutput>speed 9600 baud; rows 36; columns 96; line = 0;
 intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = &lt;undef&gt;; eol2 = &lt;undef&gt;;
 start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O;
 ...
 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt</computeroutput>
                </screen>
	    </para>

            <para>Using canonical mode, it is possible to redefine the
              special keys for the local terminal line editor.

	        <screen>
<prompt>bash$ </prompt><userinput>cat > filexxx</userinput>
<userinput>wha&lt;ctl-W&gt;I&lt;ctl-H&gt;foo bar&lt;ctl-U&gt;hello world&lt;ENTER&gt;</userinput>
<userinput>&lt;ctl-D&gt;</userinput>
<prompt>bash$ </prompt><userinput>cat filexxx</userinput>
<computeroutput>hello world</computeroutput>		
<prompt>bash$ </prompt><userinput>wc -c < filexxx</userinput>
<computeroutput>12</computeroutput>		
                </screen>

              The process controlling the terminal receives only 12
              characters (11 alphabetic ones, plus a newline), although
              the user hit 26 keys.
            </para>

            <para>In non-canonical (<quote>raw</quote>) mode, every
              key hit (including special editing keys such as
              <keycap>ctl-H</keycap>) sends a character immediately to
              the controlling process.</para>


            <para>The Bash prompt disables both <option>icanon</option>
              and <option>echo</option>, since it replaces the basic
              terminal line editor with its own more elaborate one. For
              example, when you hit <keycap>ctl-A</keycap> at the Bash
              prompt, there's no <keycap>^A</keycap> echoed by the
              terminal, but Bash gets a <keycap>\1</keycap> character,
              interprets it, and moves the cursor to the begining of
              the line.</para>

	    <para><emphasis>St&eacute;phane Chazelas</emphasis></para>  

	    </sidebar>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="settermref"><command>setterm</command></term>
	  <indexterm>
	    <primary>setterm</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>terminal</secondary>
	  </indexterm>
	  <listitem>

	    <para>Set certain terminal attributes. This command writes
	      to its terminal's <filename>stdout</filename> a string that
	      changes the behavior of that terminal.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>setterm -cursor off</userinput>
<computeroutput>bash$</computeroutput>
	      </screen>
	    </para>

	    <para>The <command>setterm</command> command can be used within a
	      script to change the appearance of text written to
	      <filename>stdout</filename>, although there are certainly
	      <link linkend="colorizingref">better tools</link> available
	      for this purpose.</para>

	    <para><programlisting>setterm -bold on
echo bold hello

setterm -bold off
echo normal hello</programlisting></para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="tsetref"><command>tset</command></term>
	  <indexterm>
	    <primary>tset</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tset</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show or initialize terminal settings. 
	      This is a less capable version of
	      <command>stty</command>.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>tset -r</userinput>
<computeroutput>Terminal type is xterm-xfree86.
 Kill is control-U (^U).
 Interrupt is control-C (^C).</computeroutput>
	      </screen>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="setserialref"><command>setserial</command></term>
	  <indexterm>
	    <primary>setserial</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>serial</secondary>
	  </indexterm>
	  <listitem>

	    <para>Set or display serial port parameters. This command must be
	      run by <firstterm>root</firstterm> and is usually found in a
	      system setup script.</para>

	    <para><programlisting># From /etc/pcmcia/serial script:

IRQ=`setserial /dev/$DEVICE | sed -e 's/.*IRQ: //'`
setserial /dev/$DEVICE irq 0 ; setserial /dev/$DEVICE irq $IRQ</programlisting></para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="gettyref"><command>getty</command></term>
	  <term><anchor id="agettyref"><command>agetty</command></term>
	  <indexterm>
	    <primary>getty</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>getty</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>agetty</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>agetty</secondary>
	  </indexterm>
	  <listitem>
	    <para>The initialization process for a terminal uses
	      <command>getty</command> or <command>agetty</command>
	      to set it up for login by a user. These commands are not
	      used within user shell scripts. Their scripting counterpart
	      is <command>stty</command>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mesgref"><command>mesg</command></term>
	  <indexterm>
	    <primary>mesg</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mesg</secondary>
	  </indexterm>
	  <listitem>
	    <para>Enables or disables write access to the current user's
	      terminal.  Disabling access would prevent another user
	      on the network to <link linkend="writeref">write</link>
	      to the terminal.</para>

	    <tip><para>It can be quite annoying to have a message
	      about ordering pizza suddenly appear in the middle of
	      the text file you are editing. On a multi-user network,
	      you might therefore wish to disable write access to your
	      terminal when you need to avoid interruptions.</para></tip>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="wallref"><command>wall</command></term>
	  <indexterm>
	    <primary>wall</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>wall</secondary>
	  </indexterm>
	  <listitem>
	    <para>This is an acronym for <quote><link
	      linkend="writeref">write</link> all,</quote> i.e., sending
	      a message to all users at every terminal logged into the
	      network. It is primarily a system administrator's tool,
	      useful, for example, when warning everyone that the
	      system will shortly go down due to a problem (see <xref
	      linkend="ex70">).</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>wall System going down for maintenance in 5 minutes!</userinput>
<computeroutput>Broadcast message from bozo (pts/1) Sun Jul  8 13:53:27 2001...

 System going down for maintenance in 5 minutes!</computeroutput>
	      </screen>
	    </para>

	    <note><para>If write access to a particular terminal has been
	      disabled with <command>mesg</command>, then
	      <command>wall</command> cannot send a message to
	      that terminal.</para></note>

	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="statisticssys">
        <title><anchor id="statisticssys1">Information and Statistics</title>

	<varlistentry>
	  <term><anchor id="unameref"><command>uname</command></term>
	  <indexterm>
	    <primary>uname</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>uname</secondary>
	  </indexterm>
	  <listitem>
	    <para>Output system specifications (OS, kernel version,
	      etc.) to <filename>stdout</filename>.  Invoked with the
	      <option>-a</option> option, gives verbose system info
	      (see <xref linkend="ex41">). The <option>-s</option>
	      option shows only the OS type.</para>

	    <screen><prompt>bash$ </prompt><userinput>uname</userinput>
<computeroutput>Linux</computeroutput>

<prompt>bash$ </prompt><userinput>uname -s</userinput>
<computeroutput>Linux</computeroutput>


<prompt>bash$ </prompt><userinput>uname -a</userinput>
<computeroutput>Linux iron.bozo 2.6.15-1.2054_FC5 #1 Tue Mar 14 15:48:33 EST 2006
 i686 i686 i386 GNU/Linux</computeroutput></screen>	    

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="archref"><command>arch</command></term>
	  <indexterm>
	    <primary>arch</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>arch</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show system architecture.
	      Equivalent to <command>uname -m</command>. See <xref
	      linkend="casecmd">.</para>
	    <screen><prompt>bash$ </prompt><userinput>arch</userinput>
<computeroutput>i686</computeroutput>

<prompt>bash$ </prompt><userinput>uname -m</userinput>
<computeroutput>i686</computeroutput></screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lastcommref"><command>lastcomm</command></term>
	  <indexterm>
	    <primary>lastcomm</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>last</secondary>
	  </indexterm>
	  <listitem>
	    <para>Gives information about previous commands, as stored
	      in the <filename>/var/account/pacct</filename> file. Command
	      name and user name can be specified by options. This is
	      one of the GNU accounting utilities.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lastlogref"><command>lastlog</command></term>
	  <indexterm>
	    <primary>lastlog</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>last</secondary>
	  </indexterm>
	  <listitem>
	    <para>List the last login time of all system users. This
	      references the <filename>/var/log/lastlog</filename>
	      file.</para>
	    <para>
	      <screen><prompt>bash$ </prompt><userinput>lastlog</userinput>
<computeroutput>root          tty1                      Fri Dec  7 18:43:21 -0700 2001
 bin                                     **Never logged in**
 daemon                                  **Never logged in**
 ...
 bozo          tty1                      Sat Dec  8 21:14:29 -0700 2001</computeroutput>



<prompt>bash$ </prompt><userinput>lastlog | grep root</userinput>
<computeroutput>root          tty1                      Fri Dec  7 18:43:21 -0700 2001</computeroutput>
	      </screen>
	      </para>

	      <caution><para>This command will fail if the user invoking
		it does not have read permission for the
		<filename>/var/log/lastlog</filename> file.</para></caution>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lsofref"><command>lsof</command></term>
	  <indexterm>
	    <primary>lsof</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>lsof</secondary>
	  </indexterm>
	  <listitem>
	    <para>List open files. This command outputs a detailed
	      table of all currently open files and gives information
	      about their owner, size, the processes associated with
	      them, and more. Of course, <command>lsof</command> may
	      be piped to <link linkend="grepref">grep</link> and/or
	      <link linkend="awkref">awk</link> to parse and analyze
	      its results.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>lsof</userinput>
<computeroutput>COMMAND    PID    USER   FD   TYPE     DEVICE    SIZE     NODE NAME
 init         1    root  mem    REG        3,5   30748    30303 /sbin/init
 init         1    root  mem    REG        3,5   73120     8069 /lib/ld-2.1.3.so
 init         1    root  mem    REG        3,5  931668     8075 /lib/libc-2.1.3.so
 cardmgr    213    root  mem    REG        3,5   36956    30357 /sbin/cardmgr
 ...</computeroutput>
	      </screen>
	    </para>

	    <para>The <command>lsof</command> command is a useful,
	      if complex administrative tool. If you are unable to
	      dismount a filesystem and get an error message that it is
	      still in use, then running <firstterm>lsof</firstterm> helps
	      determine which files are still open on that filesystem. The
	      <option>-i</option> option lists open network socket files,
	      and this can help trace intrusion or hack attempts.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>lsof -an -i tcp</userinput>
<computeroutput>COMMAND  PID USER  FD  TYPE DEVICE SIZE NODE NAME
 firefox 2330 bozo  32u IPv4   9956       TCP 66.0.118.137:57596->67.112.7.104:http ...
 firefox 2330 bozo  38u IPv4  10535       TCP 66.0.118.137:57708->216.79.48.24:http ...</computeroutput>
	      </screen>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="straceref"><command>strace</command></term>
	  <indexterm>
	    <primary>strace</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>trace</secondary>
	  </indexterm>
	  <listitem>
	    <para><command>S</command>ystem <command>trace</command>:
	      diagnostic and debugging tool for tracing <firstterm>system
	      calls</firstterm> and signals. This command and
	      <command>ltrace</command>, following, are useful for
	      diagnosing why a given program or package fails to
	      run . . . perhaps due to missing libraries or related
	      causes.</para>

	    <para>
	    <screen><prompt>bash$ </prompt><userinput>strace df</userinput>
<computeroutput>execve("/bin/df", ["df"], [/* 45 vars */]) = 0
 uname({sys="Linux", node="bozo.localdomain", ...}) = 0
 brk(0)                                  = 0x804f5e4

 ...</computeroutput>
	    </screen>
	    </para>

	    <para>This is the Linux equivalent of
	      the Solaris <command>truss</command> command.</para> 

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="ltraceref"><command>ltrace</command></term>
	  <indexterm>
	    <primary>ltrace</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>trace</secondary>
	  </indexterm>
	  <listitem>
	    <para><command>L</command>ibrary <command>trace</command>:
	      diagnostic and debugging tool that traces <firstterm>library calls</firstterm>
	      invoked by a given command.</para>

	    <para>
	    <screen><prompt>bash$ </prompt><userinput>ltrace df</userinput>
<computeroutput>__libc_start_main(0x804a910, 1, 0xbfb589a4, 0x804fb70, 0x804fb68 &lt;unfinished ...&gt:
 setlocale(6, "")                                 = "en_US.UTF-8"
bindtextdomain("coreutils", "/usr/share/locale") = "/usr/share/locale"
textdomain("coreutils")                          = "coreutils"
__cxa_atexit(0x804b650, 0, 0, 0x8052bf0, 0xbfb58908) = 0
getenv("DF_BLOCK_SIZE")                          = NULL

 ...</computeroutput>
	    </screen>
	    </para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="nmapref"><command>nmap</command></term>
	  <indexterm>
	    <primary>nmap</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>port scan</secondary>
	  </indexterm>
	  <listitem>
	    <para><command>N</command>etwork <command>map</command>per
	      and port scanner. This command scans a server to
	      locate open ports and the services associated with those
	      ports. It can also report information about packet filters and
	      firewalls. This is an important security tool for locking down
	      a network against hacking attempts.</para>
	    <para><programlisting>#!/bin/bash

SERVER=$HOST                           # localhost.localdomain (127.0.0.1).
PORT_NUMBER=25                         # SMTP port.

nmap $SERVER | grep -w "$PORT_NUMBER"  # Is that particular port open?
#              grep -w matches whole words only,
#+             so this wouldn't match port 1025, for example.

exit 0

# 25/tcp     open        smtp</programlisting></para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="ncref"><command>nc</command></term>
	  <indexterm>
	    <primary>nc</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>nc</secondary>
	  </indexterm>
	  <listitem>

	    <para>The <command>nc</command> (<firstterm>netcat</firstterm>)
	      utility is a complete toolkit for connecting to and
	      listening to TCP and UDP ports. It is useful as a diagnostic
	      and testing tool and as a component in simple script-based HTTP
	      clients and servers.</para>

	    <para>
	    <screen><prompt>bash$ </prompt><userinput>nc localhost.localdomain 25</userinput>
<computeroutput>220 localhost.localdomain ESMTP Sendmail 8.13.1/8.13.1;
 Thu, 31 Mar 2005 15:41:35 -0700</computeroutput></screen>
	    </para>

            <example id="iscan">
              <title>Checking a remote server for
              <firstterm>identd</firstterm></title>
              <programlisting>&iscan;</programlisting>
            </example>

	    <para>
	      And, of course, there's Dr. Andrew Tridgell's notorious
	      one-line script in the BitKeeper Affair:
	        <programlisting>echo clone | nc thunk.org 5000 > e2fsprogs.dat</programlisting>
	    </para>
	      
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="freeref"><command>free</command></term>
	  <indexterm>
	    <primary>free</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>free</secondary>
	  </indexterm>
	  <listitem>
	    <para>Shows memory and cache usage in tabular form. The
	      output of this command lends itself to parsing, using
	      <link linkend="grepref">grep</link>, <link
	      linkend="awkref">awk</link> or <command>Perl</command>. The
	      <command>procinfo</command> command shows all the
	      information that <command>free</command> does, and much
	      more.</para>

	    <screen><prompt>bash$ </prompt><command>free</command>
<computeroutput>                total       used       free     shared    buffers     cached
   Mem:         30504      28624       1880      15820       1608       16376
   -/+ buffers/cache:      10640      19864
   Swap:        68540       3128      65412</computeroutput></screen>

            <para>To show unused RAM memory:</para>
	    <screen><prompt>bash$ </prompt><command>free | grep Mem | awk '{ print $4 }'</command>
<computeroutput>1880</computeroutput></screen>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="procinforef"><command>procinfo</command></term>
	  <indexterm>
	    <primary>procinfo</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>procinfo</secondary>
	  </indexterm>
	  <listitem>
	    <para>Extract and list information and statistics from the
	      <link linkend="devprocref"><filename
	      class="directory">/proc</filename>
	      pseudo-filesystem</link>. This gives a very extensive and
	      detailed listing.</para>

	    <screen><prompt>bash$ </prompt><userinput>procinfo | grep Bootup</userinput>
<computeroutput>Bootup: Wed Mar 21 15:15:50 2001    Load average: 0.04 0.21 0.34 3/47 6829</computeroutput>
</screen>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lsdevref"><command>lsdev</command></term>
	  <indexterm>
	    <primary>lsdev</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>device</secondary>
	  </indexterm>
	  <listitem>
	    <para>List devices, that is, show installed hardware.</para>
	      <para>
	      <screen><prompt>bash$ </prompt><userinput>lsdev</userinput>
<computeroutput>Device            DMA   IRQ  I/O Ports
 ------------------------------------------------
 cascade             4     2 
 dma                          0080-008f
 dma1                         0000-001f
 dma2                         00c0-00df
 fpu                          00f0-00ff
 ide0                     14  01f0-01f7 03f6-03f6
 ...</computeroutput>
	      </screen>
	      </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="duref"><command>du</command></term>
	  <indexterm>
	    <primary>du</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>du</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show (disk) file usage, recursively. Defaults to current
	      working directory, unless otherwise specified.</para>

	    <screen><prompt>bash$ </prompt><command>du -ach</command>
<computeroutput>1.0k    ./wi.sh
 1.0k    ./tst.sh
 1.0k    ./random.file
 6.0k    .
 6.0k    total</computeroutput></screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="dfref"><command>df</command></term>
	  <indexterm>
	    <primary>df</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>df</secondary>
	  </indexterm>
	  <listitem>
	    <para>Shows filesystem usage in tabular form.</para>

	    <screen><prompt>bash$ </prompt><command>df</command>
<computeroutput>Filesystem           1k-blocks      Used Available Use% Mounted on
 /dev/hda5               273262     92607    166547  36% /
 /dev/hda8               222525    123951     87085  59% /home
 /dev/hda7              1408796   1075744    261488  80% /usr</computeroutput></screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="dmesgref"><command>dmesg</command></term>
	  <indexterm>
	    <primary>dmesg</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>dmesg</secondary>
	  </indexterm>
	  <listitem>
	    <para>Lists all system bootup messages to
	      <filename>stdout</filename>. Handy for debugging and
	      ascertaining which device drivers were installed
	      and which system interrupts in use. The output
	      of <command>dmesg</command> may, of course, be
	      parsed with <link linkend="grepref">grep</link>,
	      <link linkend="sedref">sed</link>, or <link
	      linkend="awkref">awk</link> from within a script.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>dmesg | grep hda</userinput>
<computeroutput>Kernel command line: ro root=/dev/hda2
 hda: IBM-DLGA-23080, ATA DISK drive
 hda: 6015744 sectors (3080 MB) w/96KiB Cache, CHS=746/128/63
 hda: hda1 hda2 hda3 < hda5 hda6 hda7 > hda4</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="statref"><command>stat</command></term>
	  <indexterm>
	    <primary>stat</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>stat</secondary>
	  </indexterm>
	  <listitem>
	    <para>Gives detailed and verbose <emphasis>stat</emphasis>istics 
	      on a given file (even a directory or device file) or set
	      of files.</para>
	    <para>
	      <screen><prompt>bash$ </prompt><userinput>stat test.cru</userinput>
<computeroutput>  File: "test.cru"
   Size: 49970        Allocated Blocks: 100          Filetype: Regular File
   Mode: (0664/-rw-rw-r--)         Uid: (  501/ bozo)  Gid: (  501/ bozo)
 Device:  3,8   Inode: 18185     Links: 1    
 Access: Sat Jun  2 16:40:24 2001
 Modify: Sat Jun  2 16:40:24 2001
 Change: Sat Jun  2 16:40:24 2001</computeroutput>
	      </screen>
	    </para>

	    <para>If the target file does not exist, <command>stat</command>
	      returns an error message.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>stat nonexistent-file</userinput>
<computeroutput>nonexistent-file: No such file or directory</computeroutput>
	      </screen>
	    </para>

	    <para>In a script, you can use <command>stat</command> to extract
	      information about files (and filesystems) and set variables
	      accordingly.</para>

	    <para>
	      <programlisting>#!/bin/bash
# fileinfo2.sh

# Per suggestion of Jo&euml;l Bourquard and . . .
# http://www.linuxquestions.org/questions/showthread.php?t=410766


FILENAME=testfile.txt
file_name=$(stat -c%n "$FILENAME")   # Same as "$FILENAME" of course.
file_owner=$(stat -c%U "$FILENAME")
file_size=$(stat -c%s "$FILENAME")
#  Certainly easier than using "ls -l $FILENAME"
#+ and then parsing with sed.
file_inode=$(stat -c%i "$FILENAME")
file_type=$(stat -c%F "$FILENAME")
file_access_rights=$(stat -c%A "$FILENAME")

echo "File name:          $file_name"
echo "File owner:         $file_owner"
echo "File size:          $file_size"
echo "File inode:         $file_inode"
echo "File type:          $file_type"
echo "File access rights: $file_access_rights"

exit 0

sh fileinfo2.sh

File name:          testfile.txt
File owner:         bozo
File size:          418
File inode:         1730378
File type:          regular file
File access rights: -rw-rw-r--</programlisting>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="vmstatref"><command>vmstat</command></term>
	  <indexterm>
	    <primary>vmstat</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>virtual memory</secondary>
	  </indexterm>
	  <listitem>
	    <para>Display virtual memory statistics.</para>
	    <para>
	    <screen><prompt>bash$ </prompt><userinput>vmstat</userinput>
<computeroutput>   procs                      memory    swap          io system         cpu
 r  b  w   swpd   free   buff  cache  si  so    bi    bo   in    cs  us  sy id
 0  0  0      0  11040   2636  38952   0   0    33     7  271    88   8   3 89</computeroutput>
	    </screen>
	    </para>
  
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="netstatref"><command>netstat</command></term>
	  <indexterm>
	    <primary>netstat</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>netstat</secondary>
	  </indexterm>
	  <listitem>

	    <para>Show current network statistics and information, 
	      such as routing tables and active connections. This utility
	      accesses information in <filename>/proc/net</filename>
	      (<xref linkend="devproc">). See <xref
	      linkend="constat">.</para>
	    <para><command>netstat -r</command> is equivalent to <link
	      linkend="routeref">route</link>.</para>

	      <screen><prompt>bash$ </prompt><userinput>netstat</userinput>
<computeroutput>Active Internet connections (w/o servers)
 Proto Recv-Q Send-Q Local Address           Foreign Address         State      
 Active UNIX domain sockets (w/o servers)
 Proto RefCnt Flags       Type       State         I-Node Path
 unix  11     [ ]         DGRAM                    906    /dev/log
 unix  3      [ ]         STREAM     CONNECTED     4514   /tmp/.X11-unix/X0
 unix  3      [ ]         STREAM     CONNECTED     4513
 . . .</computeroutput></screen>

            <note><para>A <command>netstat -lptu</command> shows <link
	    linkend="socketref">sockets</link> that are listening
	    to ports, and the associated processes. This can be useful
	    for determining whether a computer has been hacked or
	    compromised.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="uptimeref"><command>uptime</command></term>
	  <indexterm>
	    <primary>uptime</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>uptime</secondary>
	  </indexterm>
	  <listitem>

	    <para>Shows how long the system has been running, along with
	      associated statistics.</para>

	    <para>
	    <screen><prompt>bash$ </prompt><userinput>uptime</userinput>
<computeroutput>10:28pm  up  1:57,  3 users,  load average: 0.17, 0.34, 0.27</computeroutput></screen>
	    </para>

            <note><para>A <firstterm>load average</firstterm> of 1 or less
	      indicates that the system handles processes immediately. A load
	      average greater than 1 means that processes are being queued. When
	      the load average gets above 3, then system performance is
	      significantly degraded.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="hnameref"><command>hostname</command></term>
	  <indexterm>
	    <primary>hostname</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>hostname</secondary>
	  </indexterm>
	  <listitem>

	    <para>Lists the system's host name. This command sets the host
	      name in an <filename class="directory">/etc/rc.d</filename>
	      setup script (<filename>/etc/rc.d/rc.sysinit</filename>
	      or similar).  It is equivalent to <command>uname
	      -n</command>,  and a counterpart to the <link
	      linkend="hostnameref">$HOSTNAME</link> internal
	      variable.</para>

	    <screen><prompt>bash$ </prompt><userinput>hostname</userinput>
<computeroutput>localhost.localdomain</computeroutput>

<prompt>bash$ </prompt><userinput>echo $HOSTNAME</userinput>
<computeroutput>localhost.localdomain</computeroutput></screen>

	    <para>Similar to the <command>hostname</command> command are the
	      <command>domainname</command>,
	      <command>dnsdomainname</command>,
	      <command>nisdomainname</command>, and
	      <command>ypdomainname</command> commands. Use these to
	      display or set the system DNS or NIS/YP domain name. Various
	      options to <command>hostname</command> also perform these
	      functions.</para>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="hostidref"><command>hostid</command></term>
	  <indexterm>
	    <primary>hostid</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>host id</secondary>
	  </indexterm>
	  <listitem>

	    <para>Echo a 32-bit hexadecimal numerical identifier for the
	      host machine.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>hostid</userinput>
<computeroutput>7f0100</computeroutput></screen>
	    </para>

	    <note>
	    <para>This command allegedly fetches a <quote>unique</quote>
	      serial number for a particular system. Certain
	      product registration procedures use this number
	      to brand a particular user license. Unfortunately,
	      <command>hostid</command> only returns the machine
	      network address in hexadecimal, with pairs of bytes
	      transposed.</para>

	    <para>The network address of a typical non-networked Linux
	      machine, is found in <filename>/etc/hosts</filename>.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>cat /etc/hosts</userinput>
<computeroutput>127.0.0.1               localhost.localdomain localhost</computeroutput>
</screen>
	    </para>

	    <para>As it happens, transposing the bytes of
	      <userinput>127.0.0.1</userinput>, we get
	      <userinput>0.127.1.0</userinput>, which translates in
	      hex to <userinput>007f0100</userinput>, the exact equivalent
	      of what <command>hostid</command> returns, above. There
	      exist only a few million other Linux machines with this
	      identical <firstterm>hostid</firstterm>.</para>
	    </note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="sarref"><command>sar</command></term>
	  <indexterm>
	    <primary>sar</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>system activity report</secondary>
	  </indexterm>
	  <listitem>
	    <para>Invoking <command>sar</command> (System Activity Reporter)
	      gives a very detailed rundown on system statistics. The
	      Santa Cruz Operation (<quote>Old</quote> SCO) released
	      <command>sar</command> as Open Source in June, 1999.</para>

	    <para>This command is not part of the base Linux distribution,
	      but may be obtained as part of the<ulink
	      url="http://perso.wanadoo.fr/sebastien.godard/">
	      sysstat utilities</ulink> package, written by <ulink
	      url="mailto:sebastien.godard@wanadoo.fr">Sebastien
	      Godard</ulink>.</para>

	    <screen>
<prompt>bash$ </prompt><userinput>sar</userinput>
<computeroutput>Linux 2.4.9 (brooks.seringas.fr) 	09/26/03

10:30:00          CPU     %user     %nice   %system   %iowait     %idle
10:40:00          all      2.21     10.90     65.48      0.00     21.41
10:50:00          all      3.36      0.00     72.36      0.00     24.28
11:00:00          all      1.12      0.00     80.77      0.00     18.11
Average:          all      2.23      3.63     72.87      0.00     21.27

14:32:30          LINUX RESTART

15:00:00          CPU     %user     %nice   %system   %iowait     %idle
15:10:00          all      8.59      2.40     17.47      0.00     71.54
15:20:00          all      4.07      1.00     11.95      0.00     82.98
15:30:00          all      0.79      2.94      7.56      0.00     88.71
Average:          all      6.33      1.70     14.71      0.00     77.26</computeroutput>
           </screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="readelfref"><command>readelf</command></term>
	  <indexterm>
	    <primary>elf</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>statistics</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show information and statistics about a designated
	      <firstterm>elf</firstterm> binary. This is part of the
	      <firstterm>binutils</firstterm> package.</para>
	    <screen><prompt>bash$ </prompt><userinput>readelf -h /bin/bash</userinput>
<computeroutput>ELF Header:
   Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
   Class:                             ELF32
   Data:                              2's complement, little endian
   Version:                           1 (current)
   OS/ABI:                            UNIX - System V
   ABI Version:                       0
   Type:                              EXEC (Executable file)
   . . .</computeroutput></screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="sizeref"><command>size</command></term>
	  <indexterm>
	    <primary>size</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>segment</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>size [/path/to/binary]</command> command
	      gives the segment sizes of a binary executable or archive file.
	      This is mainly of use to programmers.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>size /bin/bash</userinput>
<computeroutput>   text    data     bss     dec     hex filename
  495971   22496   17392  535859   82d33 /bin/bash</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

      </variablelist>

      <variablelist id="syslog">
        <title><anchor id="syslog1">System Logs</title>

	<varlistentry>
	  <term><anchor id="loggerref"><command>logger</command></term>
	  <indexterm>
	    <primary>logger</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>logger</secondary>
	  </indexterm>
	  <listitem>

	    <para>Appends a user-generated message to the system log
	      (<filename>/var/log/messages</filename>). You do not have
	      to be <firstterm>root</firstterm> to invoke
	      <command>logger</command>.</para>

            <para>
	      <programlisting>logger Experiencing instability in network connection at 23:10, 05/21.
# Now, do a 'tail /var/log/messages'.</programlisting></para>

            <para>By embedding a <command>logger</command> command in a script,
	      it is possible to write debugging information to
	      <filename>/var/log/messages</filename>.</para>

            <para><programlisting>logger -t $0 -i Logging at line "$LINENO".
# The "-t" option specifies the tag for the logger entry.
# The "-i" option records the process ID.

# tail /var/log/message
# ...
# Jul  7 20:48:58 localhost ./test.sh[1712]: Logging at line 3.</programlisting>
            </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="logrotateref"><command>logrotate</command></term>
	  <indexterm>
	    <primary>logrotate</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>logrotate</secondary>
	  </indexterm>
	  <listitem>

	    <para>This utility manages the system log files, rotating,
	      compressing, deleting, and/or e-mailing them, as appropriate.
	      This keeps the <filename class="directory">/var/log</filename>
	      from getting cluttered with old log files.
	      Usually <link linkend="cronref">cron</link> runs
	      <command>logrotate</command> on a daily basis.</para>

	     <para>Adding an appropriate entry to
	       <filename>/etc/logrotate.conf</filename> makes it possible
	       to manage personal log files, as well as system-wide
	       ones.</para>

	     <note><para>Stefano Falsetto has created <ulink
	     url="http://www.gnu.org/software/rottlog/">rottlog</ulink>,
	     which he considers to be an improved version of
	     <command>logrotate</command>.</para></note>

	  </listitem>
	</varlistentry>
	
      </variablelist>


      <variablelist id="jobcontrolsys">
        <title><anchor id="jobcontrolsys1">Job Control</title>

	<varlistentry>
	  <term><anchor id="ppssref"><command>ps</command></term>
	  <indexterm>
	    <primary>ps</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ps</secondary>
	  </indexterm>
	  <listitem>

	    <para><replaceable>P</replaceable>rocess
	      <replaceable>S</replaceable>tatistics: lists currently
	      executing processes by owner and PID (process ID). This
	      is usually invoked with <option>ax</option> or
	      <option>aux</option> options,
	      and may be piped to <link linkend="grepref">grep</link>
	      or <link linkend="sedref">sed</link> to search for a
	      specific process (see <xref linkend="ex44"> and <xref
	      linkend="pidid">).</para>

	    <screen><prompt>bash$ </prompt><userinput> ps ax | grep sendmail</userinput>
<computeroutput>295 ?	   S	  0:00 sendmail: accepting connections on port 25</computeroutput></screen>

	    <para>To display system processes in graphical <quote>tree</quote>
	      format: <command>ps afjx</command> or
	      <command>ps ax --forest</command>.</para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="pgrepref"><command>pgrep</command></term>
	  <term><anchor id="pkillref"><command>pkill</command></term>
	  <indexterm>
	    <primary>pgrep</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>process grep</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>pkill</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>process kill</secondary>
	  </indexterm>

	  <listitem>
	    <para>Combining the <command>ps</command> command
	      with <link linkend="grepref">grep</link> or
	      <link linkend="killref">kill</link>.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>ps a | grep mingetty</userinput>
<computeroutput>2212 tty2     Ss+    0:00 /sbin/mingetty tty2
 2213 tty3     Ss+    0:00 /sbin/mingetty tty3
 2214 tty4     Ss+    0:00 /sbin/mingetty tty4
 2215 tty5     Ss+    0:00 /sbin/mingetty tty5
 2216 tty6     Ss+    0:00 /sbin/mingetty tty6
 4849 pts/2    S+     0:00 grep mingetty</computeroutput>


<prompt>bash$ </prompt><userinput>pgrep mingetty</userinput>
<computeroutput>2212 mingetty
 2213 mingetty
 2214 mingetty
 2215 mingetty
 2216 mingetty</computeroutput>
	      </screen>
	    </para>

	    <para>Compare the action of <command>pkill</command> with <link
	      linkend="killallref">killall</link>.</para>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="pstreeref"><command>pstree</command></term>
	  <indexterm>
	    <primary>pstree</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>pstree</secondary>
	  </indexterm>
	  <listitem>
	    <para>Lists currently executing processes in
	      <quote>tree</quote> format. The <option>-p</option> option
	      shows the PIDs, as well as the process names.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="topref"><command>top</command></term>
	  <indexterm>
	    <primary>top</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>processes</secondary>
	  </indexterm>
	  <listitem>

	    <para>Continuously updated display of most cpu-intensive
	      processes. The <option>-b</option> option displays in text
	      mode, so that the output may be parsed or accessed from
	      a script.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>top -b</userinput>
<computeroutput>  8:30pm  up 3 min,  3 users,  load average: 0.49, 0.32, 0.13
 45 processes: 44 sleeping, 1 running, 0 zombie, 0 stopped
 CPU states: 13.6% user,  7.3% system,  0.0% nice, 78.9% idle
 Mem:    78396K av,   65468K used,   12928K free,       0K shrd,    2352K buff
 Swap:  157208K av,       0K used,  157208K free                   37244K cached

   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND
   848 bozo      17   0   996  996   800 R     5.6  1.2   0:00 top
     1 root       8   0   512  512   444 S     0.0  0.6   0:04 init
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd
   ...</computeroutput>  
	      </screen>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="niceref"><command>nice</command></term>
	  <indexterm>
	    <primary>nice</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>nice</secondary>
	  </indexterm>
	  <listitem>
	    <para><anchor id="nice2ref"></para>
	    <para>Run a background job with an altered
	      priority. Priorities run from 19 (lowest) to -20
	      (highest). Only <firstterm>root</firstterm> may set the
	      negative (higher) priorities. Related commands are
	      <command>renice</command> and <command>snice</command>,
	      which change the priority of a running process or
	      processes, and <command>skill</command>, which sends a
	      <link linkend="killref">kill</link> signal to a process
	      or processes.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="nohupref"><command>nohup</command></term>
	  <indexterm>
	    <primary>nohup</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>nohup</secondary>
	  </indexterm>
	  <listitem>
	    <para>Keeps a command running even after user logs off.
	      The command will run as a foreground process unless followed
	      by <token>&</token>.  If you use <command>nohup</command>
	      within a script, consider coupling it with a <link
	      linkend="waitref">wait</link> to avoid creating an
	      <firstterm>orphan</firstterm> or
	      <link linkend="zombieref">zombie</link> process.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="pidofref"><command>pidof</command></term>
	  <indexterm>
	    <primary>pidof</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>process ID</secondary>
	  </indexterm>
	  <listitem>
	    <para>Identifies <firstterm>process ID (PID)</firstterm> of a
	    running job. Since job control commands, such as <link
	    linkend="killref">kill</link> and <link
	    linkend="nice2ref">renice</link> act on the
	    <firstterm>PID</firstterm> of a process (not its
	    name), it is sometimes necessary to identify that
	    <firstterm>PID</firstterm>. The <command>pidof</command>
	    command is the approximate counterpart to the <link
	    linkend="ppidref">$PPID</link> internal variable.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>pidof xclock</userinput>
<computeroutput>880</computeroutput>
	      </screen>
	    </para>

            <example id="killprocess">
              <title><firstterm>pidof</firstterm> helps kill a process</title>
              <programlisting>&killprocess;</programlisting>
            </example>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="fuserref"><command>fuser</command></term>
	  <indexterm>
	    <primary>fuser</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>fuser</secondary>
	  </indexterm>
	  <listitem>
	    <para>Identifies the processes (by PID) that are accessing
	      a given file, set of files, or directory. May also be
	      invoked with the <option>-k</option> option, which kills
	      those processes. This has interesting implications for
	      system security, especially in scripts preventing
	      unauthorized users from accessing system services.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>fuser -u /usr/bin/vim</userinput>
<computeroutput>/usr/bin/vim:         3207e(bozo)</computeroutput>



<prompt>bash$ </prompt><userinput>fuser -u /dev/null</userinput>
<computeroutput>/dev/null:            3009(bozo)  3010(bozo)  3197(bozo)  3199(bozo)</computeroutput>
	      </screen>
	    </para>

           <para>One important application for <command>fuser</command> is
	     when physically inserting or removing storage media, such
	     as CD ROM disks or USB flash drives. Sometimes trying
	     a <link linkend="umountref">umount</link> fails with a
	     <errorname>device is busy</errorname> error message. This
	     means that some user(s) and/or process(es) are accessing
	     the device. An <command>fuser -um /dev/device_name</command>
	     will clear up the mystery, so you can kill any relevant
	     processes.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>umount /mnt/usbdrive</userinput>
<computeroutput>umount: /mnt/usbdrive: device is busy</computeroutput>



<prompt>bash$ </prompt><userinput>fuser -um /dev/usbdrive</userinput>
<computeroutput>/mnt/usbdrive:        1772c(bozo)</computeroutput>

<prompt>bash$ </prompt><userinput>kill -9 1772</userinput>
<prompt>bash$ </prompt><userinput>umount /mnt/usbdrive</userinput>
	      </screen>
	    </para>

            <para> The <command>fuser</command> command, invoked with the
	      <option>-n</option> option identifies the processes
	      accessing a <firstterm>port</firstterm>. This
	      is especially useful in combination with <link
	      linkend="nmapref">nmap</link>.</para>

	  <para>
	      <screen><prompt>root# </prompt><userinput>nmap localhost.localdomain</userinput>
<computeroutput>PORT     STATE SERVICE
 25/tcp   open  smtp</computeroutput>



<prompt>root# </prompt><userinput>fuser -un tcp 25</userinput>
<computeroutput>25/tcp:               2095(root)</computeroutput>

<prompt>root# </prompt><userinput>ps ax | grep 2095 | grep -v grep</userinput>
<computeroutput>2095 ?        Ss     0:00 sendmail: accepting connections</computeroutput>
	      </screen>
            </para>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="cronref"><command>cron</command></term>
	  <indexterm>
	    <primary>cron</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>crond</secondary>
	  </indexterm>
	  <listitem>

	    <para>Administrative program scheduler, performing such
	      duties as cleaning up and deleting system log files and
	      updating the <database>slocate</database> database. This
	      is the <firstterm>superuser</firstterm> version of <link
	      linkend="atref">at</link> (although each user may have
	      their own <filename>crontab</filename> file which can be
	      changed with the <command>crontab</command> command).
	      It runs as a <link linkend="daemonref">daemon</link>
	      and executes scheduled entries from
	      <filename>/etc/crontab</filename>.</para>

	    <note><para>Some flavors of Linux run
	      <command>crond</command>, Matthew Dillon's version of
	      <command>cron</command>.</para></note>

	  </listitem>
	</varlistentry>

      </variablelist>

      <variablelist id="runcontrolsys">
        <title><anchor id="runcontrolsys1">Process Control and Booting</title>

	<varlistentry>
	  <term><anchor id="initref"><command>init</command></term>
	  <indexterm>
	    <primary>init</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>init</secondary>
	  </indexterm>
	  <listitem>
	    <para><anchor id="inittabref"></para>
	    <para>The <command>init</command> command is the <link
	      linkend="forkref">parent</link> of all processes. Called
	      in the final step of a bootup, <command>init</command>
	      determines the runlevel of the system from
	      <filename>/etc/inittab</filename>. Invoked by its alias
	      <command>telinit</command>, and by
	      <firstterm>root</firstterm> only.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="telinitref"><command>telinit</command></term>
	  <indexterm>
	    <primary>telinit</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>telinit</secondary>
	  </indexterm>
	  <listitem>
	    <para>Symlinked to <command>init</command>, this is a means of changing the system runlevel,
	      usually done for system maintenance or emergency filesystem
	      repairs. Invoked only by <firstterm>root</firstterm>. This
	      command can be dangerous -- be certain you understand it
	      well before using!</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="runlevelref"><command>runlevel</command></term>
	  <indexterm>
	    <primary>runlevel</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>runlevel</secondary>
	  </indexterm>
	  <listitem>
	    <para>Shows the current and last runlevel, that is, whether the system
	      is halted (runlevel <literal>0</literal>), in single-user mode
	      (<literal>1</literal>), in multi-user mode (<literal>2</literal>
	      or <literal>3</literal>), in X Windows (<literal>5</literal>), or
	      rebooting (<literal>6</literal>). This command accesses the
	      <filename>/var/run/utmp</filename> file.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="haltref"><command>halt</command></term>
	  <term><anchor id="shutdownref"><command>shutdown</command></term>
	  <term><anchor id="rebootref"><command>reboot</command></term>
	  <indexterm>
	    <primary>halt</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>halt</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>shutdown</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>shutdown</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>reboot</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>reboot</secondary>
	  </indexterm>
	  <listitem>
	    <para>Command set to shut the system down, usually just prior to a power down.</para>
	    <warning><para>On some Linux distros, the <command>halt</command> command
	      has 755 permissions, so it can be invoked by a non-root user.
	      A careless <firstterm>halt</firstterm> in a terminal or a script
	      may shut down the system!</para></warning>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="serviceref"><command>service</command></term>
	  <indexterm>
	    <primary>service</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>service</secondary>
	  </indexterm>
	  <listitem>
	    <para>Starts or stops a system <firstterm>service</firstterm>.
	    The startup scripts in <filename class="directory">/etc/init.d</filename>
	    and <filename class="directory">/etc/rc.d</filename> use this
	    command to start services at bootup.</para>
	  <para>
	      <screen><prompt>root# </prompt><userinput>/sbin/service iptables stop</userinput>
<computeroutput>Flushing firewall rules:                                   [  OK  ]
 Setting chains to policy ACCEPT: filter                    [  OK  ]
 Unloading iptables modules:                                [  OK  ]</computeroutput>
	      </screen>
	    </para>
	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="networksys">
        <title><anchor id="networksys1">Network</title>

	<varlistentry>
	  <term><anchor id="ifconfigref"><command>ifconfig</command></term>
	  <indexterm>
	    <primary>ifconfig</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ifconfig</secondary>
	  </indexterm>
	  <listitem>
	    <para>Network <firstterm>interface configuration</firstterm>
	      and tuning utility.</para>

	      <screen><prompt>bash$ </prompt><userinput>ifconfig -a</userinput>
<computeroutput>lo        Link encap:Local Loopback
           inet addr:127.0.0.1  Mask:255.0.0.0
           UP LOOPBACK RUNNING  MTU:16436  Metric:1
           RX packets:10 errors:0 dropped:0 overruns:0 frame:0
           TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 txqueuelen:0 
           RX bytes:700 (700.0 b)  TX bytes:700 (700.0 b)</computeroutput></screen>

	    <para>The <command>ifconfig</command> command is most often used
	      at bootup to set up the interfaces, or to shut them down
	      when rebooting.</para>

	    <para><programlisting># Code snippets from /etc/rc.d/init.d/network

# ...

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

[ -x /sbin/ifconfig ] || exit 0

# ...

for i in $interfaces ; do
  if ifconfig $i 2>/dev/null | grep -q "UP" >/dev/null 2>&1 ; then
    action "Shutting down interface $i: " ./ifdown $i boot
  fi
#  The GNU-specific "-q" option to "grep" means "quiet", i.e.,
#+ producing no output.
#  Redirecting output to /dev/null is therefore not strictly necessary.
       
# ...

echo "Currently active devices:"
echo `/sbin/ifconfig | grep ^[a-z] | awk '{print $1}'`
#                            ^^^^^  should be quoted to prevent globbing.
#  The following also work.
#    echo $(/sbin/ifconfig | awk '/^[a-z]/ { print $1 })'
#    echo $(/sbin/ifconfig | sed -e 's/ .*//')
#  Thanks, S.C., for additional comments.</programlisting></para>

	    <para>See also <xref linkend="online">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="iwconfigref"><command>iwconfig</command></term>
	  <indexterm>
	    <primary>iwconfig</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>wireless</secondary>
	  </indexterm>
	  <listitem>
	    <para>This is the command set for configuring a wireless network.
	      It is the wireless equivalent of <command>ifconfig</command>,
	      above.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="ipref"><command>ip</command></term>
	  <indexterm>
	    <primary>ip</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>routing</secondary>
	  </indexterm>
	  <listitem>

	    <para>General purpose utility for setting up, changing, and
	      analyzing <firstterm>IP</firstterm> (Internet Protocol)
	      networks and attached devices. This command is part of
	      the <firstterm>iproute2</firstterm> package.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>ip link show</userinput>
<computeroutput>1: lo: &lt;LOOPBACK,UP&gt; mtu 16436 qdisc noqueue 
     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 2: eth0: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc pfifo_fast qlen 1000
     link/ether 00:d0:59:ce:af:da brd ff:ff:ff:ff:ff:ff
 3: sit0: &lt;NOARP&gt; mtu 1480 qdisc noop 
     link/sit 0.0.0.0 brd 0.0.0.0</computeroutput>


<prompt>bash$ </prompt><userinput>ip route list</userinput>
<computeroutput>169.254.0.0/16 dev lo  scope link</computeroutput>
	      </screen>
	    </para>

            <para>Or, in a script:</para>

	    <para>
              <programlisting>&ipscript;</programlisting>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="routeref"><command>route</command></term>
	  <indexterm>
	    <primary>route</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>route</secondary>
	  </indexterm>
	  <listitem>

	    <para>Show info about or make changes to the kernel routing table.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>route</userinput>
<computeroutput>Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
 pm3-67.bozosisp *               255.255.255.255 UH       40 0          0 ppp0
 127.0.0.0       *               255.0.0.0       U        40 0          0 lo
 default         pm3-67.bozosisp 0.0.0.0         UG       40 0          0 ppp0</computeroutput>
	      </screen>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="chkconfigref"><command>chkconfig</command></term>
	  <indexterm>
	    <primary>chkconfig</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>network configuration</secondary>
	  </indexterm>
	  <listitem>

	    <para>Check network and system configuration. This command
	      lists and
	      manages the network and system services started at bootup in
	      the <filename class="directory">/etc/rc?.d</filename>
	      directory.</para>

	    <para>Originally a port from IRIX to Red Hat Linux,
	      <command>chkconfig</command> may not be part of the core
	      installation of some Linux flavors.</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>chkconfig --list</userinput>
<computeroutput>atd             0:off   1:off   2:off   3:on    4:on    5:on    6:off
 rwhod           0:off   1:off   2:off   3:off   4:off   5:off   6:off
 ...</computeroutput>
	      </screen>
	    </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="tcpdumpref"><command>tcpdump</command></term>
	  <indexterm>
	    <primary>tcpdump</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tcp</secondary>
	  </indexterm>
	  <listitem>
	    <para>Network packet <quote>sniffer.</quote> This is a tool for
	      analyzing and troubleshooting traffic on a network by dumping
	      packet headers that match specified criteria.</para>

	      <para>Dump ip packet traffic between hosts
	        <emphasis>bozoville</emphasis> and
	        <emphasis>caduceus</emphasis>:</para>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>tcpdump ip host bozoville and caduceus</userinput>
	      </screen>
	      </para>

	      <para>Of course, the output of <command>tcpdump</command> can be
	        parsed with certain of the previously discussed <link
		linkend="tpcommandlisting1">text processing
		utilities</link>.</para>
	  </listitem>
	</varlistentry>

      </variablelist>



      <variablelist id="filesystemsys">
        <title><anchor id="filesystemsys1">Filesystem</title>

	<varlistentry>
	  <term><anchor id="mountref"><command>mount</command></term>
	  <indexterm>
	    <primary>mount</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mount</secondary>
	  </indexterm>
	  <listitem>
	    <para>Mount a filesystem, usually on an external device,
	      such as a floppy or CDROM. The file
	      <filename>/etc/fstab</filename> provides a handy listing
	      of available filesystems, partitions, and devices,
	      including options, that may be automatically or manually
	      mounted. The file <filename>/etc/mtab</filename> shows
	      the currently mounted filesystems and partitions
	      (including the virtual ones, such as <filename
	      class="directory">/proc</filename>).</para>

	    <para><command>mount -a</command> mounts all filesystems and
	      partitions listed in <filename>/etc/fstab</filename>,
	      except those with a <option>noauto</option>
	      option. At bootup, a startup script in
	      <filename class="directory">/etc/rc.d</filename>
	      (<filename>rc.sysinit</filename> or something similar)
	      invokes this to get everything mounted.</para>


	    <para><programlisting>mount -t iso9660 /dev/cdrom /mnt/cdrom
# Mounts CD ROM. ISO 9660 is a standard CD ROM filesystem.
mount /mnt/cdrom
# Shortcut, if /mnt/cdrom listed in /etc/fstab</programlisting>
     </para>

     <para><anchor id="isomountref0"></para>
     <para>The versatile <firstterm>mount</firstterm> command can even
       mount an ordinary file on a block device, and the file will
       act as if it were a filesystem. <firstterm>Mount</firstterm>
       accomplishes that by associating the file with a <link
       linkend="loopbackref">loopback device</link>. One application of
       this is to mount and examine an ISO9660 filesystem image before
       burning it onto a CDR.

	  <footnote><para>For more detail on burning CDRs, see Alex
	    Withers' article, <ulink
	    url="http://www2.linuxjournal.com/lj-issues/issue66/3335.html">Creating
	    CDs</ulink>, in the October, 1999 issue of <ulink
	    url="http://www.linuxjournal.com"><citetitle
	    pubwork="journal">Linux
	     Journal</citetitle></ulink>.</para></footnote>

       </para>

	     <example id="isomountref">
	      <title>Checking a CD image</title>
	       <programlisting># As root...

mkdir /mnt/cdtest  # Prepare a mount point, if not already there.

mount -r -t iso9660 -o loop cd-image.iso /mnt/cdtest   # Mount the image.
#                  "-o loop" option equivalent to "losetup /dev/loop0"
cd /mnt/cdtest     # Now, check the image.
ls -alR            # List the files in the directory tree there.
                   # And so forth.</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="umountref"><command>umount</command></term>
	  <indexterm>
	    <primary>umount</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>umount</secondary>
	  </indexterm>
	  <listitem>
	    <para>Unmount a currently mounted filesystem. Before physically removing a
	      previously mounted floppy or CDROM disk, the device must be
	      <command>umount</command>ed, else filesystem corruption may result.
	      <programlisting>umount /mnt/cdrom
# You may now press the eject button and safely remove the disk.</programlisting></para>

	      <note><para>The <command>automount</command> utility, if
		properly installed, can mount and unmount floppies or
		CDROM disks as they are accessed or removed. On
		<quote>multispindle</quote> laptops with swappable
		floppy and optical drives, this can cause problems,
		however.</para></note>

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="gnomemountref"><command>gnome-mount</command></term>
	  <indexterm>
	    <primary>gnome-mount</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mount</secondary>
	  </indexterm>
	  <listitem>
	    <para>The newer Linux distros have deprecated
	    <command>mount</command> and <command>umount</command>.
	    The successor, for command-line mounting of removable storage
	    devices, is <command>gnome-mount</command>. It can take the
	    <option>-d</option> option to mount a device file by its listing
	    in <filename class="directory">/dev</filename>.</para>

	    <para>For example, to mount a USB flash drive:</para>

	    <para>
	    <screen><prompt>bash$ </prompt><userinput>gnome-mount -d /dev/sda1</userinput>
<computeroutput>gnome-mount 0.4</computeroutput>


<prompt>bash$ </prompt><userinput>df</userinput>
<computeroutput>. . .
 /dev/sda1                63584     12034     51550  19% /media/disk</computeroutput>
 </screen>
	    </para>


	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="syncref"><command>sync</command></term>
	  <indexterm>
	    <primary>sync</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>sync</secondary>
	  </indexterm>
	  <listitem>
	    <para>Forces an immediate write of all updated data from
	      buffers to hard drive (synchronize drive
	      with buffers). While not strictly necessary, a
	      <command>sync</command> assures the sys admin or
	      user that the data just changed will survive a sudden
	      power failure. In the olden days, a <userinput>sync;
	      sync</userinput> (twice, just to make absolutely sure) was a
	      useful precautionary measure before a system reboot.</para>
	    <para>At times, you may wish to force an immediate buffer
	      flush, as when securely deleting a file (see <xref
	      linkend="blotout">) or when the lights begin to
	      flicker.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="losetupref"><command>losetup</command></term>
	  <indexterm>
	    <primary>losetup</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>losetup</secondary>
	  </indexterm>
	  <listitem>
	    <para>Sets up and configures <link linkend="loopbackref">
	      loopback devices</link>.</para>

	    <example id="createfs">
	      <title>Creating a filesystem in a file</title>
	      <programlisting>SIZE=1000000  # 1 meg

head -c $SIZE < /dev/zero > file  # Set up file of designated size.
losetup /dev/loop0 file           # Set it up as loopback device.
mke2fs /dev/loop0                 # Create filesystem.
mount -o loop /dev/loop0 /mnt     # Mount it.

# Thanks, S.C.</programlisting>
	    </example>	    

	  </listitem>
	</varlistentry>


	<varlistentry>
	  <term><anchor id="mkswapref"><command>mkswap</command></term>
	  <indexterm>
	    <primary>mkswap</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mkswap</secondary>
	  </indexterm>
	  <listitem>
	    <para>Creates a swap partition or file. The swap area must
	      subsequently be enabled with
	      <command>swapon</command>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="swaponref"><command>swapon</command></term>
	  <term><anchor id="swapoffref"><command>swapoff</command></term>
	  <indexterm>
	    <primary>swapon</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>swapon</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>swapoff</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>swapoff</secondary>
	  </indexterm>
	  <listitem>
	    <para>Enable / disable swap partitition or file.
	      These commands usually take effect at bootup and
	      shutdown.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mke2fsref"><command>mke2fs</command></term>
	  <indexterm>
	    <primary>mke2fs</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mke2fs</secondary>
	  </indexterm>
	  <listitem>
	    <para>Create a Linux <firstterm>ext2</firstterm>
	      filesystem. This command must be invoked as
	      <firstterm>root</firstterm>.</para>


	    <example id="adddrv">
	      <title>Adding a new hard drive</title>
	      <programlisting>&adddrv;</programlisting>
	    </example>

	    <para>See also <xref linkend="createfs"> and <xref
	      linkend="ramdisk">.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="tune2fsref"><command>tune2fs</command></term>
	  <indexterm>
	    <primary>tune2fs</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tune2fs</secondary>
	  </indexterm>
	  <listitem>
	    <para>Tune <firstterm>ext2</firstterm> filesystem. May be
	      used to change filesystem parameters, such as maximum
	      mount count. This must be invoked as
	      <firstterm>root</firstterm>.</para>

	    <warning><para>This is an extremely dangerous command. Use it at
	      your own risk, as you may inadvertently destroy your filesystem.
	      </para></warning>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="dumpe2fsref"><command>dumpe2fs</command></term>
	  <indexterm>
	    <primary>dumpe2fs</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>dumpe2fs</secondary>
	  </indexterm>
	  <listitem>
	    <para>Dump (list to <filename>stdout</filename>) very verbose
	      filesystem info. This must be invoked as
	      <firstterm>root</firstterm>.</para>

	    <screen><prompt>root# </prompt><command>dumpe2fs /dev/hda7 | grep 'ount count'</command>
<computeroutput>dumpe2fs 1.19, 13-Jul-2000 for EXT2 FS 0.5b, 95/08/09
 Mount count:              6
 Maximum mount count:      20</computeroutput></screen>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="hdparmref"><command>hdparm</command></term>
	  <indexterm>
	    <primary>hdparm</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>hard disk parameters</secondary>
	  </indexterm>
	  <listitem>
	    <para>List or change hard disk parameters. This command must be
	      invoked as <firstterm>root</firstterm>, and it may be
	      dangerous if misused.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="fdiskref"><command>fdisk</command></term>
	  <indexterm>
	    <primary>fdisk</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>fdisk</secondary>
	  </indexterm>
	  <listitem>
	    <para>Create or change a partition table on a storage device,
	      usually a hard drive. This command must be invoked as
	      <firstterm>root</firstterm>.</para>
	    <warning><para>Use this command with extreme caution. If something
	      goes wrong, you may destroy an existing
	      filesystem.</para></warning>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="fsckref"><command>fsck</command></term>
	  <term><anchor id="e2fsckref"><command>e2fsck</command></term>
	  <term><anchor id="debugfsref"><command>debugfs</command></term>
	  <indexterm>
	    <primary>fsck</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>fsck</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>e2fsck</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>e2fsck</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>debugfs</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>debugfs</secondary>
	  </indexterm>
	  <listitem>

	    <para>Filesystem check, repair, and debug command set.</para>

	    <para><command>fsck</command>: a front end for checking a UNIX
	      filesystem (may invoke other utilities). The actual
	      filesystem type generally defaults to
	      <firstterm>ext2</firstterm>.</para>

	    <para><command>e2fsck</command>: ext2 filesystem checker.</para>

	    <para><command>debugfs</command>: ext2 filesystem debugger.
	      One of the uses of this versatile, but dangerous command
	      is to (attempt to) recover deleted files. For advanced users
	      only!</para>

	    <caution><para>All of these should be invoked as
	      <firstterm>root</firstterm>, and they can damage or destroy
	      a filesystem if misused.</para></caution>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="badblocksref"><command>badblocks</command></term>
	  <indexterm>
	    <primary>badblocks</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>badblocks</secondary>
	  </indexterm>
	  <listitem>
	    <para>Checks for bad blocks (physical media flaws) on a
	      storage device.  This command finds use when formatting
	      a newly installed hard drive or testing the integrity
	      of backup media.
	        <footnote><para>The <option>-c</option> option to <link
		linkend="mke2fsref">mke2fs</link> also invokes a check for bad
		blocks.</para></footnote>
	      As an example, <command>badblocks /dev/fd0</command>
	      tests a floppy disk.</para>

	    <para>The <command>badblocks</command> command
	      may be invoked destructively (overwrite all data) or
	      in non-destructive read-only mode. If <firstterm>root
	      user</firstterm> owns the device to be tested, as is
	      generally the case, then <firstterm>root</firstterm>
	      must invoke this command.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lsusbref"><command>lsusb</command></term>
	  <term><command>usbmodules</command></term>
	  <indexterm>
	    <primary>lsusb</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>usb</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>usbmodules</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>usb</secondary>
	  </indexterm>
	  <listitem>

	    <para>The <command>lsusb</command> command lists all USB
	      (Universal Serial Bus) buses and the devices hooked up to
	      them.</para>

            <para>The <command>usbmodules</command> command outputs
	      information about the driver modules for connected USB
	      devices.</para>

            <para>
	      <screen><prompt>bash$ </prompt><userinput>lsusb</userinput>
<computeroutput>Bus 001 Device 001: ID 0000:0000  
 Device Descriptor:
   bLength                18
   bDescriptorType         1
   bcdUSB               1.00
   bDeviceClass            9 Hub
   bDeviceSubClass         0 
   bDeviceProtocol         0 
   bMaxPacketSize0         8
   idVendor           0x0000 
   idProduct          0x0000

   . . .</computeroutput>
	      </screen>
            </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lspciref"><command>lspci</command></term>
	  <indexterm>
	    <primary>lspci</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>pci</secondary>
	  </indexterm>
	  <listitem>
	    <para>Lists <firstterm>pci</firstterm> busses present.</para>

            <para>
	      <screen><prompt>bash$ </prompt><userinput>lspci</userinput>
<computeroutput>00:00.0 Host bridge: Intel Corporation 82845 845
 (Brookdale) Chipset Host Bridge (rev 04)
 00:01.0 PCI bridge: Intel Corporation 82845 845
 (Brookdale) Chipset AGP Bridge (rev 04)
 00:1d.0 USB Controller: Intel Corporation 82801CA/CAM USB (Hub #1) (rev 02)
 00:1d.1 USB Controller: Intel Corporation 82801CA/CAM USB (Hub #2) (rev 02)
 00:1d.2 USB Controller: Intel Corporation 82801CA/CAM USB (Hub #3) (rev 02)
 00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 42)

   . . .</computeroutput>
	      </screen>
            </para>

	  </listitem>
	</varlistentry>



	<varlistentry>
	  <term><anchor id="mkbootdiskref"><command>mkbootdisk</command></term>
	  <indexterm>
	    <primary>mkbootdisk</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>bootdisk</secondary>
	  </indexterm>
	  <listitem>
	    <para>Creates a boot floppy which can be used to bring up the
	      system if, for example, the MBR (master boot record) becomes
	      corrupted. Of special interest is the <option>--iso</option>
	      option, which uses <command>mkisofs</command> to create a
	      bootable <firstterm>ISO9660</firstterm> filesystem image
	      suitable for burning a bootable CDR.</para>
	    <para>The <command>mkbootdisk</command> command is actually
	      a Bash script, written by Erik Troan, in the <filename
	      class="directory">/sbin</filename> directory.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mkisofsref"><command>mkisofs</command></term>
	  <indexterm>
	    <primary>mkisofs</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ISO9660</secondary>
	  </indexterm>
	  <listitem>
	    <para>Creates an <firstterm>ISO9660</firstterm> filesystem
	      suitable for a CDR image.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="chrootref"><command>chroot</command></term>
	  <indexterm>
	    <primary>chroot</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>chroot</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>directory</primary>
	    <secondary>root</secondary>
	    <tertiary>change</tertiary>
	  </indexterm>
	  <listitem>
	    <para>CHange ROOT directory. Normally commands are fetched
	      from <link linkend="pathref">$PATH</link>, relative to
	      <filename class="directory">/</filename>, the default
	      <firstterm>root
	      directory</firstterm>. This changes the
	      <firstterm>root</firstterm> directory to a different one
	      (and also changes the working directory to there).  This is
	      useful for security purposes, for instance when the system
	      administrator wishes to restrict certain users, such as
	      those <link linkend="telnetref">telnetting</link> in,
	      to a secured portion of the filesystem (this is sometimes
	      referred to as confining a guest user to a <quote>chroot
	      jail</quote>). Note that after a <command>chroot</command>,
	      the execution path for system binaries is no longer
	      valid.</para>

	      <para>A <userinput>chroot /opt</userinput> would cause
		references to <filename
		class="directory">/usr/bin</filename>
		to be translated to <filename
		class="directory">/opt/usr/bin</filename>. Likewise,
		<userinput>chroot /aaa/bbb /bin/ls</userinput> would
		redirect future instances of <command>ls</command>
		to <filename>/aaa/bbb</filename> as the base directory,
		rather than <filename class="directory">/</filename> as is
		normally the case. An <command>alias XX 'chroot /aaa/bbb
		ls'</command> in a user's <filename>~/.bashrc</filename>
		effectively restricts which portion of the filesystem
		she may run command <quote>XX</quote> on.</para>


	    <para>The <command>chroot</command> command is also handy
	      when running from an emergency boot floppy 
	      (<command>chroot</command> to <filename>/dev/fd0</filename>),
	      or as an option to <command>lilo</command> when recovering
	      from a system crash. Other uses include installation from a
	      different filesystem (an <link linkend="rpmref">rpm</link>
	      option) or running a readonly filesystem from a CD ROM.
	      Invoke only as <firstterm>root</firstterm>, and use with
	      care.</para>

	    <caution><para>It might be necessary to copy certain system
	      files to a <firstterm>chrooted</firstterm> directory,
	      since the normal <varname>$PATH</varname> can no longer
	      be relied upon.</para></caution>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lockfileref"><command>lockfile</command></term>
	  <indexterm>
	    <primary>lockfile</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>lockfile</secondary>
	  </indexterm>
	  <listitem>
	    <para>This utility is part of the <command>procmail</command>
	      package (<ulink url="http://www.procmail.org">www.procmail.org</ulink>).
	      It creates a <firstterm>lock file</firstterm>, a
	      <firstterm>semaphore</firstterm> 

		<footnote><para><anchor id="semaphoreref">Definition:
		  A <firstterm>semaphore</firstterm> is a flag or
		  signal. (The usage originated in railroading, where a
		  colored flag, lantern, or striped movable arm
		  <firstterm>semaphore</firstterm> indicated whether a
		  particular track was in use and therefore unavailable
		  for another train.) A UNIX process can check the
		  appropriate semaphore to determine whether a particular
		  resource is available/accessible.</para></footnote>

	      file that controls access to a file, device, or resource.
	      The lock file serves as a flag that this particular
	      file, device, or resource is in use by a process (it is
	      <quote>busy</quote>), and this permits only restricted
	      access (or no access) to other processes.</para>

            <para><programlisting>lockfile /home/bozo/lockfiles/$0.lock
# Creates a write-protected lockfile prefixed with the name of the script.

lockfile /home/bozo/lockfiles/${0##*/}.lock
# A safer version of the above, as pointed out by E. Choroba.</programlisting></para>
	      
	    <para>Lock files are used in such applications as protecting 
	      system mail folders from simultaneously being changed
	      by multiple users, indicating that a modem port
	      is being accessed, and showing that an instance of
	      <application>Netscape</application> is using its cache.
	      Scripts may check for the existence of a lock file created
	      by a certain process to check if that process is running.
	      Note that if a script attempts to create a lock file that
	      already exists, the script will likely hang.</para>

	    <para>Normally, applications create and check for lock files
	      in the <filename class="directory">/var/lock</filename>
	      directory.
	         <footnote><para>Since only <firstterm>root</firstterm>
		 has write permission in the <filename
		 class="directory">/var/lock</filename> directory,
		 a user script cannot set a lock file there.</para></footnote>
	      A script can test for the presence of a lock file by
	      something like the following.
	        <programlisting>appname=xyzip
# Application "xyzip" created lock file "/var/lock/xyzip.lock".

if [ -e "/var/lock/$appname.lock" ]
then   #+ Prevent other programs & scripts
       #  from accessing files/resources used by xyzip.
  ...</programlisting></para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="flockref"><command>flock</command></term>
	  <indexterm>
	    <primary>flock</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>lock file</secondary>
	  </indexterm>
	  <listitem>

	    <para>Much less useful than the <command>lockfile</command>
	      command is <command>flock</command>. It sets an
	      <quote>advisory</quote> lock on a file and then executes
	      a command while the lock is on. This is to prevent
	      any other process from setting a lock on that file until
	      completion of the specified command.</para>

	    <para><programlisting>flock $0 cat $0 > lockfile__$0
#  Set a lock on the script the above line appears in,
#+ while listing the script to stdout.</programlisting></para>

            <note><para>Unlike <command>lockfile</command>,
	      <command>flock</command> does <emphasis>not</emphasis>
	      automatically create a lock file.</para></note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="mknodref"><command>mknod</command></term>
	  <indexterm>
	    <primary>mknod</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>mknod</secondary>
	  </indexterm>
	  <listitem>
	    <para>Creates block or character device files (may be
	      necessary when installing new hardware on the system). The
	      <command>MAKEDEV</command> utility has virtually
	      all of the functionality of <command>mknod</command>,
	      and is easier to use.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="MAKEDEVref"><command>MAKEDEV</command></term>
	  <indexterm>
	    <primary>MAKEDEV</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>make device file</secondary>
	  </indexterm>
	  <listitem>

	    <para>Utility for creating device files. It must be run as
	      <firstterm>root</firstterm>, and in the <filename
	      class="directory">/dev</filename> directory. It is a sort
	      of advanced version of <command>mknod</command>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="tmpwatchref"><command>tmpwatch</command></term>
	  <indexterm>
	    <primary>tmpwatch</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>tmpwatch</secondary>
	  </indexterm>
	  <listitem>
	    <para>Automatically deletes files which have not been accessed
	      within a specified period of time. Usually invoked by
	      <link linkend="cronref">cron</link> to remove stale log
	      files.</para>
	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="periphsys">
        <title><anchor id="periphsys1">Backup</title>

	<varlistentry>
	  <term><anchor id="dumpref"><command>dump</command></term>
	  <term><anchor id="restoreref"><command>restore</command></term>
	  <indexterm>
	    <primary>dump</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>dump</secondary>
	  </indexterm>
	  <indexterm>
	    <primary>restore</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>restore</secondary>
	  </indexterm>
	  <listitem>
	    <para>The <command>dump</command> command is an elaborate
	      filesystem backup utility, generally used on larger
	      installations and networks.
		<footnote><para>Operators of single-user Linux systems
		  generally prefer something simpler for backups, such
		  as <command>tar</command>.</para></footnote>
	      It reads raw disk partitions and writes a backup file
	      in a binary format.  Files to be backed up may be saved
	      to a variety of storage media, including disks and tape
	      drives. The <command>restore</command> command restores
	      backups made with <command>dump</command>.</para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="fdformatref"><command>fdformat</command></term>
	  <indexterm>
	    <primary>fdformat</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>floppy</secondary>
	  </indexterm>
	  <listitem>
	    <para>Perform a low-level format on a floppy disk
	    (<filename>/dev/fd0*</filename>).</para>
	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="sysresources">
        <title><anchor id="sysresources1">System Resources</title>

	<varlistentry>
	  <term><anchor id="ulimitref"><command>ulimit</command></term>
	  <indexterm>
	    <primary>ulimit</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ulimit</secondary>
	  </indexterm>
	  <listitem>

	    <para>Sets an <firstterm>upper limit</firstterm> on use
	     of system resources. Usually invoked with the
	     <option>-f</option> option, which sets a limit on file size
	     (<command>ulimit -f 1000</command> limits files to 1 meg
	     maximum). The <option>-t</option> option limits the coredump
	     size (<command>ulimit -c 0</command> eliminates coredumps).
	      Normally, the value of <command>ulimit</command>
	      would be set in <filename>/etc/profile</filename>
	      and/or <filename>~/.bash_profile</filename> (see <xref
	      linkend="files">).</para>

            <important>

	    <para>Judicious use of <command>ulimit</command> can
	      protect a system against the dreaded <firstterm>fork
	      bomb</firstterm>.</para>

	    <para>
	    <programlisting>#!/bin/bash
# This script is for illustrative purposes only.
# Run it at your own peril -- it WILL freeze your system.

while true  #  Endless loop.
do
  $0 &      #  This script invokes itself . . .
            #+ forks an infinite number of times . . .
            #+ until the system freezes up because all resources exhausted.
done        #  This is the notorious <quote>sorcerer's appentice</quote> scenario.

exit 0      #  Will not exit here, because this script will never terminate.</programlisting>
	    </para>

	    <para>A <command>ulimit -Hu XX</command> (where
	      <emphasis>XX</emphasis> is the user process limit) in
	      <filename>/etc/profile</filename> would abort
	      this script when it exceeded the preset limit.
	    </para>

            </important>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="quotaref"><command>quota</command></term>
	  <indexterm>
	    <primary>quota</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>quota</secondary>
	  </indexterm>
	  <listitem>
	    <para>Display user or group disk quotas.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="setquotaref"><command>setquota</command></term>
	  <indexterm>
	    <primary>setquota</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>quota</secondary>
	  </indexterm>
	  <listitem>
	    <para>Set user or group disk quotas from the command line.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <indexterm>
	    <primary>umask</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>umask</secondary>
	  </indexterm>
	  <term><anchor id="umaskref"><command>umask</command></term>
	  <listitem>
	    <para>User file creation permissions
	      <firstterm>mask</firstterm>. Limit the default file
	      attributes for a particular user.  All files created
	      by that user take on the attributes specified by
	      <command>umask</command>. The (octal) value passed to
	      <command>umask</command> defines the file permissions
	      <firstterm>disabled</firstterm>. For example, <command>umask
	      022</command> ensures that new files will have at most
	      755 permissions (777 NAND 022).

                <footnote><para>NAND is the logical
		  <firstterm>not-and</firstterm> operator. Its effect
		  is somewhat similar to subtraction.</para></footnote>

	      Of course, the user may later change the
	      attributes of particular files with <link
	      linkend="chmodref">chmod</link>. The usual practice
	      is to set the value of <command>umask</command>
	      in <filename>/etc/profile</filename> and/or
	      <filename>~/.bash_profile</filename> (see <xref
	      linkend="files">).</para>

	    <example id="rot13a">
	      <title>Using <firstterm>umask</firstterm> to hide an output file
	        from prying eyes</title>
	      <programlisting>&rot13a;</programlisting>
	    </example>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rdevref"><command>rdev</command></term>
	  <indexterm>
	    <primary>rdev</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>rdev</secondary>
	  </indexterm>
	  <listitem>
	    <para>Get info about or make changes to root device, swap space, or video
	       mode.  The functionality of <command>rdev</command> has generally been taken over by
	       <command>lilo</command>, but <command>rdev</command> remains
	       useful for setting up a ram disk. This is a dangerous command, if misused.
	     </para>
	   </listitem>
	 </varlistentry>
	 
      </variablelist>


      <variablelist id="modulessys">
        <title><anchor id="modulessys1">Modules</title>

	<varlistentry>
	  <term><anchor id="lsmodref"><command>lsmod</command></term>
	  <indexterm>
	    <primary>lsmod</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>loadable modules</secondary>
	  </indexterm>
	  <listitem>
	    <para>List installed kernel modules.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>lsmod</userinput>
<computeroutput>Module                  Size  Used by
 autofs                  9456   2 (autoclean)
 opl3                   11376   0
 serial_cs               5456   0 (unused)
 sb                     34752   0
 uart401                 6384   0 [sb]
 sound                  58368   0 [opl3 sb uart401]
 soundlow                 464   0 [sound]
 soundcore               2800   6 [sb sound]
 ds                      6448   2 [serial_cs]
 i82365                 22928   2
 pcmcia_core            45984   0 [serial_cs ds i82365]</computeroutput>
	      </screen>
	    </para>
	    <note><para>Doing a <command>cat /proc/modules</command> gives the
	      same information.</para></note>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="insmodref"><command>insmod</command></term>
	  <indexterm>
	    <primary>insmod</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>loadable modules</secondary>
	  </indexterm>
	  <listitem>
	    <para>Force installation of a kernel module (use
	      <command>modprobe</command> instead, when possible). Must
	      be invoked as <firstterm>root</firstterm>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rmmodref"><command>rmmod</command></term>
	  <indexterm>
	    <primary>rmmod</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>loadable modules</secondary>
	  </indexterm>
	  <listitem>
	    <para>Force unloading of a kernel module. Must be invoked
	      as <firstterm>root</firstterm>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="modproberef"><command>modprobe</command></term>
	  <indexterm>
	    <primary>modprobe</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>loadable modules</secondary>
	  </indexterm>
	  <listitem>
	    <para>Module loader that is normally invoked automatically
	      in a startup script. Must be invoked as
	      <firstterm>root</firstterm>.</para>
	  </listitem>
	</varlistentry>
	
	<varlistentry>
	  <term><anchor id="depmodref"><command>depmod</command></term>
	  <indexterm>
	    <primary>depmod</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>loadable modules</secondary>
	  </indexterm>
	  <listitem>
	    <para>Creates module dependency file. Usually invoked from a
	      startup script.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="modinforef"><command>modinfo</command></term>
	  <indexterm>
	    <primary>modinfo</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>loadable modules</secondary>
	  </indexterm>
	  <listitem>

	    <para>Output information about a loadable module.</para>

	      <screen><prompt>bash$ </prompt><userinput>modinfo hid</userinput>
<computeroutput>filename:    /lib/modules/2.4.20-6/kernel/drivers/usb/hid.o
 description: "USB HID support drivers"
 author:      "Andreas Gal, Vojtech Pavlik &lt;vojtech@suse.cz&gt;"
 license:     "GPL"</computeroutput>
	      </screen>
	  </listitem>
	</varlistentry>

      </variablelist>


      <variablelist id="miscsys">
        <title><anchor id="miscsys1">Miscellaneous</title>

	<varlistentry>
	  <term><anchor id="envvref"><command>env</command></term>
	  <indexterm>
	    <primary>env</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>env</secondary>
	  </indexterm>
	  <listitem>
	    <para>
	      Runs a program or script with certain <link
	      linkend="envref">environmental variables</link>
	      set or changed (without changing the overall system
	      environment). The <option>[varname=xxx]</option>
	      permits changing the environmental variable
	      <varname>varname</varname> for the duration of the
	      script. With no options specified, this command lists all
	      the environmental variable settings.

	    <footnote><para>In Bash and other Bourne shell derivatives, it is
	      possible to set variables in a single command's environment.
	      <programlisting>var1=value1 var2=value2 commandXXX
# $var1 and $var2 set in the environment of 'commandXXX' only.</programlisting>	      
            </para></footnote>
	    </para>

            <note>
	    <para><anchor id="envv2ref">The first line of a script (the
	      <quote>sha-bang</quote> line) may use <command>env</command>
	      when the path to the shell or interpreter is unknown.</para>

	      <para><programlisting>#! /usr/bin/env perl

print "This Perl script will run,\n";
print "even when I don't know where to find Perl.\n";

# Good for portable cross-platform scripts,
# where the Perl binaries may not be in the expected place.
# Thanks, S.C.</programlisting></para>

            <para>Or even ... </para>
            <para><programlisting>#!/bin/env bash
# Queries the $PATH enviromental variable for the location of bash.
# Therefore ...
# This script will run where Bash is not in its usual place, in /bin.
...</programlisting></para>

	    </note>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="lddref"><command>ldd</command></term>
	  <indexterm>
	    <primary>ldd</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>ldd</secondary>
	  </indexterm>
	  <listitem>
	    <para>Show shared lib dependencies for an executable file.</para>
	    <screen><prompt>bash$ </prompt><userinput>ldd /bin/ls</userinput>
<computeroutput>libc.so.6 => /lib/libc.so.6 (0x4000c000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)</computeroutput></screen>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="watchref"><command>watch</command></term>
	  <indexterm>
	    <primary>watch</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>periodic</secondary>
	  </indexterm>
	  <listitem>
	    <para>Run a command repeatedly, at specified time intervals.</para>
	    <para>The default is two-second intervals, but this may be changed
	      with the <option>-n</option> option.</para>
	    <para><programlisting>watch -n 5 tail /var/log/messages
# Shows tail end of system log, /var/log/messages, every five seconds.</programlisting></para>	    

            <note><para>Unfortunately, <link linkend="piperef">piping</link>
	      the output of <command>watch command</command> to <link
	      linkend="grepref">grep</link> does not work.</para></note>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="stripref"><command>strip</command></term>
	  <indexterm>
	    <primary>strip</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>symbol</secondary>
	  </indexterm>
	  <listitem>
	    <para>Remove the debugging symbolic references from an executable
	      binary. This decreases its size, but makes debugging it
	      impossible.</para>
	    <para>This command often occurs in a <link
	      linkend="makefileref">Makefile</link>,
	      but rarely in a shell script.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="nmref"><command>nm</command></term>
	  <indexterm>
	    <primary>nm</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>symbol</secondary>
	  </indexterm>
	  <listitem>
	    <para>List symbols in an unstripped compiled binary.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="rdistref"><command>rdist</command></term>
	  <indexterm>
	    <primary>rdist</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>rdist</secondary>
	  </indexterm>
	  <listitem>
	    <para>Remote distribution client: synchronizes, clones,
	      or backs up a file system on a remote server.</para>
	  </listitem>
	</varlistentry>

      </variablelist>



      <sect1 id="sysscripts">
        <title>Analyzing a System Script</title>

      <para><anchor id="killall2ref"></para>

      <para>Using our knowledge of administrative commands, let us examine a system
	script. One of the shortest and simplest to understand scripts is
	<quote>killall,</quote>
	   <footnote><para>The <firstterm>killall</firstterm> system
	   script should not be confused with the <link
	   linkend="killallref">killall</link> command in <filename
	   class="directory">/usr/bin</filename>.</para></footnote>
	used to suspend running processes at system shutdown.</para>

	    <example id="ex55">
	      <title><firstterm>killall</firstterm>, from <filename
	      class="directory">/etc/rc.d/init.d</filename></title>
	      <programlisting>&ex55;</programlisting>
	    </example>
      
      <para>That wasn't so bad. Aside from a little fancy footwork with variable
	matching, there is no new material there.</para>

      <formalpara><title>Exercise 1</title>
        <para>In <filename class="directory">/etc/rc.d/init.d</filename>,
	  analyze the <command>halt</command> script. It is a bit longer
	  than <command>killall</command>, but similar in concept. Make
	  a copy of this script somewhere in your home directory and
	  experiment with it (do <emphasis>not</emphasis> run it as
	  <firstterm>root</firstterm>). Do a simulated run
	  with the <option>-vn</option> flags (<userinput>sh
	  -vn scriptname</userinput>). Add extensive
	  comments. Change the <quote>action</quote> commands to
	  <quote>echos</quote>.</para></formalpara>

      <formalpara><title>Exercise 2</title>
      <para>Look at some of the more complex scripts in
	<filename class="directory">/etc/rc.d/init.d</filename>. See if
	you can understand parts of them. Follow the above procedure
	to analyze them. For some additional insight, you might also
	examine the file <filename>sysvinitfiles</filename> in <filename
	class="directory">/usr/share/doc/initscripts-?.??</filename>,
	which is part of the <quote>initscripts</quote>
	documentation.</para></formalpara>

	</sect1> <!-- Analyzing a System Script -->

  </chapter> <!-- System and Administrative Commands -->

  </part> <!-- Part 4 (Beyond the Basics) -->


  

  <part label="Part 5" id="part5">
    <title>Advanced Topics</title>

    <partintro>
      <para>At this point, we are ready to delve into certain of the
	difficult and unusual aspects of scripting. Along the way, we
	will attempt to <quote>push the envelope</quote> in various
	ways and examine <firstterm>boundary conditions</firstterm>
	(what happens when we move into uncharted territory?).</para>
     </partintro>

  <chapter id="regexp">
      <title>Regular Expressions</title>

    <epigraph>
      <para>. . . the intellectual activity associated with software
        development is largely one of gaining insight.</para>
      <para>--Stowe Boyd</para>
    </epigraph>

      <para><anchor id="regexref"></para>

      <para>To fully utilize the power of shell scripting, you need to
	master Regular Expressions. Certain commands
	and utilities commonly used in scripts, such
	as <link linkend="grepref">grep</link>, <link
	linkend="exprref">expr</link>, <link linkend="sedref">sed</link>
	and <link linkend="awkref">awk</link>, interpret and use REs. As of
	<link linkend="bash3ref">version 3</link>, Bash has acquired its
	own <link linkend="regexmatchref">RE-match operator</link>:
	<command>=~</command>.</para>



      <sect1><title>A Brief Introduction to Regular Expressions</title>

	<para>An expression is a string of characters. Those characters
	  having an interpretation above and beyond their literal
	  meaning are called <firstterm>metacharacters</firstterm>.
	  A quote symbol, for example, may denote speech by a person,
	  <firstterm>ditto</firstterm>, or a meta-meaning

	    <footnote><para><anchor id="metameaningref">A
	    <firstterm>meta-meaning</firstterm> is the meaning of a
	    term or expression on a higher level of abstraction. For
	    example, the <firstterm>literal</firstterm> meaning
	    of <firstterm>regular expression</firstterm> is an
	    ordinary expression that conforms to accepted usage. The
	    <firstterm>meta-meaning</firstterm> is drastically different,
	    as discussed at length in this chapter.</para></footnote>

	  for the symbols that follow. Regular Expressions are sets
	  of characters and/or metacharacters that match (or specify)
	  patterns.</para>

	<para>A Regular Expression contains one or more of the
	following:</para>

        <itemizedlist>

	  <listitem>
	    <para><firstterm>A character set</firstterm>. These are the
	      characters retaining their literal meaning. The
	      simplest type of Regular Expression consists
	      <emphasis>only</emphasis> of a character set, with no
	      metacharacters.</para>
	  </listitem>

	  <listitem>
	    <para><anchor id="anchorref"></para>
	    <para><firstterm>An anchor</firstterm>. These designate
	      (<firstterm>anchor</firstterm>) the position in the line of
	      text that the RE is to match. For example, <token>^</token>,
	      and <token>$</token> are anchors.</para>
	  </listitem>

	  <listitem>
	    <para><firstterm>Modifiers</firstterm>. These expand or narrow
	      (<firstterm>modify</firstterm>) the range of text the RE is
	      to match. Modifiers include the asterisk, brackets, and
	      the backslash.</para>
	  </listitem>

        </itemizedlist>


	<para>The main uses for Regular Expressions
	  (<firstterm>RE</firstterm>s) are text searches and string
	  manipulation. An RE <firstterm>matches</firstterm> a single
	  character or a set of characters -- a string or a part of
	  a string.</para>

	<itemizedlist>
	  <listitem>
	    <indexterm>
	      <primary>*</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>*</secondary>
	    </indexterm>

	    <para><anchor id="asteriskreg">The asterisk --
	    <token>*</token> -- matches any number of
	      repeats of the character string or RE preceding it,
	      including <emphasis>zero</emphasis> instances.</para>

	    <para><quote>1133*</quote> matches <replaceable>11 +
	      one or more 3's</replaceable>:
	      <replaceable>113</replaceable>, <replaceable>1133</replaceable>,
	      <replaceable>1133333</replaceable>, and so forth.</para>

	  </listitem>
	  <listitem>
	    <indexterm>
	      <primary>.</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>.</secondary>
	    </indexterm>

	    <para><anchor id="regexdot">The <firstterm>dot</firstterm>
	    -- <token>.</token> -- matches
	      any one character, except a newline.
	        <footnote><para>Since <link linkend="sedref">sed</link>, <link
		  linkend="awkref">awk</link>, and <link
		  linkend="grepref">grep</link> process single lines, there
		  will usually not be a newline to match. In those cases where
		  there is a newline in a multiple line expression, the dot
		  will match the newline.
	            <programlisting>#!/bin/bash

sed -e 'N;s/.*/[&]/' &lt;&lt; EOF   # Here Document
line1
line2
EOF
# OUTPUT:
# [line1
# line2]



echo

awk '{ $0=$1 "\n" $2; if (/line.1/) {print}}' &lt;&lt; EOF
line 1
line 2
EOF
# OUTPUT:
# line
# 1


# Thanks, S.C.

exit 0</programlisting></para></footnote>  
	    </para>

	   <para><quote>13.</quote> matches <replaceable>13 + at
	     least one of any character (including a
	     space)</replaceable>: <replaceable>1133</replaceable>,
	     <replaceable>11333</replaceable>, but not
	     <replaceable>13</replaceable> (additional character
	     missing).</para>

	     <para>See <xref linkend="cwsolver"> for a demonstration
	       of <firstterm>dot single-character</firstterm>
	       matching.</para>
	  </listitem>


	  <listitem>
	    <indexterm>
	      <primary>^</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>^</secondary>
	    </indexterm>
	    <para><anchor id="caretref">The caret -- <token>^</token>
	      -- matches the beginning of a line, but sometimes, depending
	      on context, negates the meaning of a set of characters in
	      an RE.</para>
	  </listitem>

	  <listitem>
	    <indexterm>
	      <primary>$</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>$</secondary>
	    </indexterm>
	    <para><anchor id="dollarsignref"></para>
	    <para>The dollar sign -- <token>$</token> -- at the end of an
	      RE matches the end of a line.</para>
	    <para><quote>XXX$</quote> matches <token>XXX</token> at the
	      end of a line.</para>
	    <para><quote>^$</quote> matches blank lines.</para>
	  </listitem>

	  <listitem>
	    <indexterm>
	      <primary>[...]</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>[...]</secondary>
	    </indexterm>

	    <para><anchor id="bracketsref"></para>
	    <para>Brackets -- <token>[...]</token> -- enclose a set of characters
	      to match in a single RE.</para>

	    <para><quote>[xyz]</quote> matches any one of the characters
	      <replaceable>x</replaceable>, <replaceable>y</replaceable>,
	      or <replaceable>z</replaceable>.</para>

	    <para><quote>[c-n]</quote> matches any one of the
	      characters in the range <replaceable>c</replaceable>
	      to <replaceable>n</replaceable>.</para>

	    <para><quote>[B-Pk-y]</quote> matches any one of the
	      characters in the ranges <replaceable>B</replaceable>
	      to <replaceable>P</replaceable>
	      and <replaceable>k</replaceable> to
	      <replaceable>y</replaceable>.</para>

	    <para><quote>[a-z0-9]</quote> matches any single lowercase
	      letter or any digit.</para>

	    <para><quote>[^b-d]</quote> matches any character
	      <emphasis>except</emphasis> those in
	      the range <replaceable>b</replaceable> to
	      <replaceable>d</replaceable>. This is an instance of
	      <token>^</token> negating or inverting the meaning
	      of the following RE (taking on a role similar to
	      <token>!</token> in a different context).</para>

	    <para>Combined sequences of bracketed characters match  
	      common word patterns. <quote>[Yy][Ee][Ss]</quote> matches
	      <replaceable>yes</replaceable>, <replaceable>Yes</replaceable>,
	      <replaceable>YES</replaceable>, <replaceable>yEs</replaceable>,
	      and so forth.
	      <quote>[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]</quote>
	      matches any Social Security number.</para>

	  </listitem>


	  <listitem>
	    <indexterm>
	      <primary>\</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>\</secondary>
	    </indexterm>

	    <para><anchor id="regexbs"></para>
	    <para>The backslash -- <token>\</token> -- <link
	      linkend="escp">escapes</link> a special character, which
              means that character gets interpreted literally (and is
              therefore no longer <firstterm>special</firstterm>).</para>

	     <para>A <quote>\$</quote> reverts back to its
	       literal meaning of <quote>$</quote>, rather than its
	       RE meaning of end-of-line. Likewise a <quote>\\</quote>
	       has the literal meaning of <quote>\</quote>.</para>
	  </listitem>


	  <listitem>
	    <indexterm>
	      <primary>\&lt; \&gt;</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>\&lt; \&gt;</secondary>
	    </indexterm>

	    <para><anchor id="anglebrac"></para>
	    <para><link linkend="escp">Escaped</link> <quote>angle
	      brackets</quote> -- <token>\&lt;...\&gt;</token> -- mark word
	      boundaries.</para>

	    <para>The angle brackets must be escaped, since otherwise
	      they have only their literal character meaning.</para>

	    <para><quote>\&lt;the\&gt;</quote> matches the word
	      <quote>the,</quote> but not the words <quote>them,</quote>
	      <quote>there,</quote> <quote>other,</quote> etc.</para>

	    <para>
	      <screen>
<prompt>bash$ </prompt><userinput>cat textfile</userinput>
<computeroutput>This is line 1, of which there is only one instance.
 This is the only instance of line 2.
 This is line 3, another line.
 This is line 4.</computeroutput>


<prompt>bash$ </prompt><userinput>grep 'the' textfile</userinput>
<computeroutput>This is line 1, of which there is only one instance.
 This is the only instance of line 2.
 This is line 3, another line.</computeroutput>


<prompt>bash$ </prompt><userinput>grep '\&lt;the\&gt;' textfile</userinput>
<computeroutput>This is the only instance of line 2.</computeroutput>
	      </screen>
	    </para>

	  </listitem>

	</itemizedlist>

	<sidebar>
	  <para>The only way to be certain that a particular RE works is to
	    test it.</para>

          <para><programlisting>TEST FILE: tstfile                          # No match.
                                            # No match.
Run   grep "1133*"  on this file.           # Match.
                                            # No match.
                                            # No match.
This line contains the number 113.          # Match.
This line contains the number 13.           # No match.
This line contains the number 133.          # No match.
This line contains the number 1133.         # Match.
This line contains the number 113312.       # Match.
This line contains the number 1112.         # No match.
This line contains the number 113312312.    # Match.
This line contains no numbers at all.       # No match.</programlisting></para>

	      <screen><prompt>bash$ </prompt><userinput>grep "1133*" tstfile</userinput>
<computeroutput>Run   grep "1133*"  on this file.           # Match.
 This line contains the number 113.          # Match.
 This line contains the number 1133.         # Match.
 This line contains the number 113312.       # Match.
 This line contains the number 113312312.    # Match.</computeroutput>
	      </screen>

	</sidebar>

	<itemizedlist>

	  <listitem override="square">
	    <formalpara>
	      <title><anchor id="extregex">Extended REs</title>

	      <para>Additional metacharacters added to the basic set. Used
		in <link linkend="egrepref">egrep</link>,
		<link linkend="awkref">awk</link>, and <link
		linkend="perlref">Perl</link>.</para>

	      </formalpara>
	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>?</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>?</secondary>
	    </indexterm>

	    <para><anchor id="quexregex"></para>
	    <para>The question mark -- <token>?</token> -- matches zero or
	      one of the previous RE. It is generally used for matching
	      single characters.</para>

	  </listitem>

	  <listitem>
	    <indexterm>
	      <primary>+</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>+</secondary>
	    </indexterm>

	    <para><anchor id="plusref"></para>
	    <para>The plus -- <token>+</token> -- matches one or more of the
	    previous RE. It serves a role similar to the <token>*</token>, but
	    does <emphasis>not</emphasis> match zero occurrences.</para>

	    <para><programlisting># GNU versions of sed and awk can use "+",
# but it needs to be escaped.

echo a111b | sed -ne '/a1\+b/p'
echo a111b | grep 'a1\+b'
echo a111b | gawk '/a1+b/'
# All of above are equivalent.

# Thanks, S.C.</programlisting></para>

          <para><anchor id="escpcb"></para>
	  </listitem>

	  <listitem>
	    <indexterm>
	      <primary>\{ \}</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>\{ \}</secondary>
	    </indexterm>

	    <para><link linkend="escp">Escaped</link> <quote>curly
	      brackets</quote> -- <token>\{ \}</token> -- indicate the number
	      of occurrences of a preceding RE to match.</para>


	    <para>It is necessary to escape the curly brackets since
	      they have only their literal character meaning
	      otherwise. This usage is technically not part of the basic
	      RE set.</para>

	    <para><quote>[0-9]\{5\}</quote> matches exactly five digits
	      (characters in the range of 0 to 9).</para>

	    <note>
	    <para>Curly brackets are not available as an RE in the
	      <quote>classic</quote> (non-POSIX compliant) version
	      of <link linkend="awkref">awk</link>. However,
	      <command>gawk</command> has the
	      <option>--re-interval</option> option that permits them
	      (without being escaped).</para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>echo 2222 | gawk --re-interval '/2{3}/'</userinput>
<computeroutput>2222</computeroutput>
	      </screen>
	    </para>

	    <para><command>Perl</command> and some
	      <command>egrep</command> versions do not require escaping
	      the curly brackets.</para>

	      </note>

	  </listitem>

	  <listitem>
	    <indexterm>
	      <primary>()</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>()</secondary>
	    </indexterm>

	    <para><anchor id="parengrps"></para>
	    <para>Parentheses -- <command>( )</command> -- enclose a group of
	      REs. They are useful with the following
	      <quote><token>|</token></quote> operator and in <link
	      linkend="exprparen">substring extraction</link> using <link
	      linkend="exprref">expr</link>.</para>
	  </listitem>

	  <listitem>
	    <indexterm>
	      <primary>|</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>|</secondary>
	    </indexterm>

	    <para>The -- <command>|</command> -- <quote>or</quote> RE operator
	      matches any of a set of alternate characters.</para>
	      <para>
	      <screen><prompt>bash$ </prompt><userinput>egrep 're(a|e)d' misc.txt</userinput>
<computeroutput>People who read seem to be better informed than those who do not.
 The clarinet produces sound by the vibration of its reed.</computeroutput>
	      </screen>
	      </para>
	  </listitem>

	</itemizedlist>

	    <note><para>Some versions of <command>sed</command>,
	      <command>ed</command>, and <command>ex</command> support
	      escaped versions of the extended Regular Expressions
	      described above, as do the GNU utilities.</para></note>


	<itemizedlist>

	  <listitem override="square">

	    <formalpara><title><anchor id="posixref">POSIX Character Classes</title>
	      <para><userinput>[:class:]</userinput></para></formalpara>

	    <indexterm>
	      <primary>[:</primary>
	    </indexterm>
	    <indexterm>
	      <primary>special character</primary>
	      <secondary>:]</secondary>
	    </indexterm>

	    <para>This is an alternate method of specifying a range of
	      characters to match.</para>

	  </listitem>


	  <listitem>

	    <indexterm>
	      <primary>alnum</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>alphabetic numeric</secondary>
	    </indexterm>

	    <para><userinput>[:alnum:]</userinput> matches alphabetic or
	      numeric characters. This is equivalent to
	      <userinput>A-Za-z0-9</userinput>.</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>alpha</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>alphabetic</secondary>
	    </indexterm>

	    <para><userinput>[:alpha:]</userinput> matches alphabetic
	      characters. This is equivalent to
	      <userinput>A-Za-z</userinput>.</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>blank</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>space tab</secondary>
	    </indexterm>

	    <para><userinput>[:blank:]</userinput> matches a space or a
	      tab.</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>cntrl</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>control</secondary>
	    </indexterm>

	    <para><userinput>[:cntrl:]</userinput> matches control
	      characters.</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>digit</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>decimal digit</secondary>
	    </indexterm>

	    <para><userinput>[:digit:]</userinput> matches (decimal)
	      digits. This is equivalent to
	      <userinput>0-9</userinput>.</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>graph</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>graph</secondary>
	    </indexterm>

	    <para><userinput>[:graph:]</userinput> (graphic printable
	      characters). Matches characters in the range of ASCII 33 -
	      126. This is the same as <userinput>[:print:]</userinput>,
	      below, but excluding the space character.</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>lower</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>lowercase</secondary>
	    </indexterm>

	    <para><userinput>[:lower:]</userinput> matches lowercase
	      alphabetic characters. This is equivalent to
	      <userinput>a-z</userinput>.</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>print</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>printable</secondary>
	    </indexterm>

	    <para><userinput>[:print:]</userinput> (printable
	      characters). Matches characters in the range of ASCII 32 -
	      126. This is the same as <userinput>[:graph:]</userinput>,
	      above, but adding the space character.</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>space</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>whitespace</secondary>
	    </indexterm>

	    <para><anchor id="wsposix"><userinput>[:space:]</userinput>
	      matches whitespace characters (space and horizontal
	      tab).</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>upper</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>uppercase</secondary>
	    </indexterm>

	    <para><userinput>[:upper:]</userinput> matches uppercase
	      alphabetic characters. This is equivalent to
	      <userinput>A-Z</userinput>.</para>

	  </listitem>

	  <listitem>

	    <indexterm>
	      <primary>xdigit</primary>
	    </indexterm>
	    <indexterm>
	      <primary>character range</primary>
	      <secondary>hexadecimal</secondary>
	    </indexterm>

	    <para><userinput>[:xdigit:]</userinput> matches hexadecimal
	      digits. This is equivalent to
	      <userinput>0-9A-Fa-f</userinput>.</para>

            <important>

	    <para>POSIX character classes generally require quoting
	      or <link linkend="dblbrackets">double brackets</link>
	      ([[ ]]).</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>grep [[:digit:]] test.file</userinput>
<computeroutput>abc=723</computeroutput>
	      </screen>
	    </para>

	    <para>These character classes may even be used with <link
	      linkend="globbingref">globbing</link>, to a limited
	      extent.</para>

	    <para>
	      <screen><prompt>bash$ </prompt><userinput>ls -l ?[[:digit:]][[:digit:]]?</userinput>
<computeroutput>-rw-rw-r--    1 bozo  bozo         0 Aug 21 14:47 a33b</computeroutput>
	      </screen>
	    </para>

	    <para>To see POSIX character classes used in scripts, refer to
	      <xref linkend="ex49"> and <xref linkend="lowercase">.</para>

	    </important>  

	  </listitem>

	</itemizedlist>


	<para><link linkend="sedref">Sed</link>, <link
	  linkend="awkref">awk</link>, and <link
	  linkend="perlref">Perl</link>, used as filters in scripts, take
	  REs as arguments when "sifting" or transforming files or I/O
	  streams. See <xref linkend="behead"> and <xref linkend="tree">
	  for illustrations of this.</para>

	<para>The standard reference on this complex topic is Friedl's
	  <citetitle pubwork="book">Mastering Regular
	  Expressions</citetitle>. <citetitle pubwork="book">Sed &
	  Awk</citetitle>, by Dougherty and Robbins, also gives a very
	  lucid treatment of REs. See the <xref linkend="biblio"> for
	  more information on these books.</para>

      </sect1> <!-- A Brief Introduction to Regular Expressions -->




      <sect1 id="globbingref">
	<title>Globbing</title>

	<para><anchor id="globbingref2"></para>
	<para>Bash itself cannot recognize Regular Expressions. Inside
	  scripts, it is commands and utilities -- such as
	  <link linkend="sedref">sed</link> and <link
	  linkend="awkref">awk</link> -- that interpret RE's.</para>


	<para>Bash <emphasis>does</emphasis> carry out <firstterm>filename
	  expansion</firstterm>

	    <footnote><para><firstterm>Filename expansion</firstterm> means
	    expanding filename patterns or templates containing special
	    characters. For example, <filename>example.???</filename> might
	    expand to <filename>example.001</filename> and/or
	    <filename>example.txt</filename>.</para></footnote>
	  
	  -- a process known as <firstterm>globbing</firstterm> -- but
	  this does <emphasis>not</emphasis> use the standard RE set.
	  Instead, globbing recognizes and expands <firstterm>wild
	  cards</firstterm>. Globbing interprets the standard wild
	  card characters
	      <footnote><para><anchor id="wildcarddef">A <firstterm>wild
	      card</firstterm> character, analogous to a wild card in poker,
	      can represent (almost) any other character.</para></footnote>
	  -- <link linkend="asteriskref">*</link> and
	  <link linkend="wildcardqu">?</link>, character lists in
	  square brackets, and certain other special characters (such
	  as <token>^</token> for negating the sense of a match).
          <anchor id="wdotfilewc">There are important limitations on wild
	  card characters in globbing, however. Strings containing
	  <replaceable>*</replaceable> will not match filenames that
	  start with a dot, as, for example, <filename>.bashrc</filename>.

	    <footnote>
	    <para>
	    Filename expansion <emphasis>can</emphasis>
	    match dotfiles, but only if the pattern explicitly includes the dot
	    as a literal character.
	        <programlisting>~/[.]bashrc    #  Will not expand to ~/.bashrc
~/?bashrc      #  Neither will this.
               #  Wild cards and metacharacters will NOT
               #+ expand to a dot in globbing.

~/.[b]ashrc    #  Will expand to ~/.bashrc
~/.ba?hrc      #  Likewise.
~/.bashr*      #  Likewise.

# Setting the "dotglob" option turns this off.

# Thanks, S.C.</programlisting>
	    </para>
	    </footnote>
	  
	  Likewise, the <replaceable>?</replaceable> has a different
	  meaning in globbing than as part of an RE.</para>

	      <para>
	      <screen>
<prompt>bash$ </prompt><userinput>ls -l</userinput>
<computeroutput>total 2
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 a.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 b.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 c.1
 -rw-rw-r--    1 bozo  bozo       466 Aug  6 17:48 t2.sh
 -rw-rw-r--    1 bozo  bozo       758 Jul 30 09:02 test1.txt</computeroutput>

<prompt>bash$ </prompt><userinput>ls -l t?.sh</userinput>
<computeroutput>-rw-rw-r--    1 bozo  bozo       466 Aug  6 17:48 t2.sh</computeroutput>

<prompt>bash$ </prompt><userinput>ls -l [ab]*</userinput>
<computeroutput>-rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 a.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 b.1</computeroutput>

<prompt>bash$ </prompt><userinput>ls -l [a-c]*</userinput>
<computeroutput>-rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 a.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 b.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 c.1</computeroutput>

<prompt>bash$ </prompt><userinput>ls -l [^ab]*</userinput>
<computeroutput>-rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 c.1
 -rw-rw-r--    1 bozo  bozo       466 Aug  6 17:48 t2.sh
 -rw-rw-r--    1 bozo  bozo       758 Jul 30 09:02 test1.txt</computeroutput>

<prompt>bash$ </prompt><userinput>ls -l {b*,c*,*est*}</userinput>
<computeroutput>-rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 b.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 c.1
 -rw-rw-r--    1 bozo  bozo       758 Jul 30 09:02 test1.txt</computeroutput>
	      </screen>
	      </para>



	  <para>Bash performs filename expansion on unquoted command-line
	    arguments. The <link linkend="echoref">echo</link> command
	    demonstrates this.</para>

	   <para>
	      <screen>
<prompt>bash$ </prompt><userinput>echo *</userinput>
<computeroutput>a.1 b.1 c.1 t2.sh test1.txt</computeroutput>

<prompt>bash$ </prompt><userinput>echo t*</userinput>
<computeroutput>t2.sh test1.txt</computeroutput>

<prompt>bash$ </prompt><userinput>echo t?.sh</userinput>
<computeroutput>t2.sh</computeroutput>
	      </screen>
	   </para>

	  <note><para>It is possible to modify the way Bash interprets
	    special characters in globbing. A <command>set -f</command>
	    command disables globbing, and the
	    <option>nocaseglob</option> and <option>nullglob</option>
	    options to <link linkend="shoptref">shopt</link> change
	    globbing behavior.</para></note>

	  <para>See also <xref linkend="listglob">.</para>

      </sect1> <!-- Globbing -->


  </chapter> <!-- Regular Expressions -->



  <chapter id="here-docs">
    <title>Here Documents</title>

    <epigraph>
      <para>Here and now, boys.</para>
      <para>--Aldous Huxley, <firstterm>Island</firstterm></para>
    </epigraph>
    
      <para><anchor id="heredocref"></para>

      <indexterm>
	<primary><<</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary><<</secondary>
      </indexterm>
      
      <para>A <firstterm>here document</firstterm> is a special-purpose
	code block. It uses a form of <link linkend="ioredirref">I/O
	redirection</link> to feed a command list to
	an interactive program or a command, such as <link
	linkend="ftpref">ftp</link>, <link linkend="catref">cat</link>,
	or the <firstterm>ex</firstterm> text editor.</para>

      <para><programlisting>COMMAND &lt;&lt;InputComesFromHERE
...
InputComesFromHERE</programlisting></para>


      <para><anchor id="limitstringref"></para>
      <para>A <firstterm>limit string</firstterm> delineates (frames)
	the command list.  The special symbol <token><<</token> designates
	the limit string.  This has the effect of redirecting the output
	of a file into the <filename>stdin</filename> of the program
	or command. It is similar to <userinput>interactive-program <
	command-file</userinput>, where <filename>command-file</filename>
	contains

	  <programlisting>command #1
command #2
...</programlisting></para>

      <para>The <firstterm>here document</firstterm> alternative looks
        like this:</para>

      <para><programlisting>#!/bin/bash
interactive-program &lt;&lt;LimitString
command #1
command #2
...
LimitString</programlisting></para>

      <para>Choose a <firstterm>limit string</firstterm> sufficiently
	unusual that it will not occur anywhere in the command list and
	confuse matters.</para>

      <para>Note that <firstterm>here documents</firstterm> may sometimes
	be used to good effect with non-interactive utilities and commands,
	such as, for example, <link linkend="wallref">wall</link>.</para>


      <example id="ex70">
	<title><firstterm>broadcast</firstterm>: Sends message to everyone
	logged in</title>
	<programlisting>&ex70;</programlisting>
      </example>


      <para><anchor id="vihere"></para>
      <para>Even such unlikely candidates as the <firstterm>vi</firstterm>
        text editor lend themselves to <firstterm>here
        documents</firstterm>.</para>

      <example id="ex69">
	<title><firstterm>dummyfile</firstterm>: Creates a 2-line dummy
	file</title>
	<programlisting>&ex69;</programlisting>
      </example>

      <para>
        The above script could just as effectively have been implemented with
	<command>ex</command>, rather than
	<command>vi</command>. <anchor id="exscriptref"><firstterm>Here
	documents</firstterm> containing a list of <command>ex</command>
	commands are common enough to form their own category, known as
	<firstterm>ex scripts</firstterm>.

	  <programlisting>#!/bin/bash
#  Replace all instances of "Smith" with "Jones"
#+ in files with a ".txt" filename suffix. 

ORIGINAL=Smith
REPLACEMENT=Jones

for word in $(fgrep -l $ORIGINAL *.txt)
do
  # -------------------------------------
  ex $word &lt;&lt;EOF
  :%s/$ORIGINAL/$REPLACEMENT/g
  :wq
EOF
  # :%s is the "ex" substitution command.
  # :wq is write-and-quit.
  # -------------------------------------
done</programlisting>
	</para>

      <para><anchor id="catscriptref"></para>
      <para>Analogous to <quote>ex scripts</quote> are <firstterm>cat
        scripts</firstterm>.</para>

      <example id="ex71">
	<title>Multi-line message using <firstterm>cat</firstterm></title>
	<programlisting>&ex71;</programlisting>
      </example>


      <para><anchor id="limitstrdash"></para>
      <para>The <option>-</option> option to mark a here document limit string
	(<userinput>&lt;&lt;-LimitString</userinput>) suppresses leading
	tabs (but not spaces) in the output. This may be useful in making
	a script more readable.</para>

      <example id="ex71a">
	<title>Multi-line message, with tabs suppressed</title>
	<programlisting>&ex71a;</programlisting>
      </example>


      <para><anchor id="herepassp"></para>
      <para>A <firstterm>here document</firstterm> supports parameter and
	command substitution.  It is therefore possible to pass different
	parameters to the body of the here document, changing its output
	accordingly.</para>

      <example id="ex71b">
	<title>Here document with replaceable parameters</title>
	<programlisting>&ex71b;</programlisting>
      </example>

      <para><anchor id="hereparamsub"></para>
      <para>This is a useful script containing a <firstterm>here
        document</firstterm> with parameter substitution.</para>

      <example id="ex72">
	<title>Upload a file pair to <firstterm>Sunsite</firstterm> incoming
	  directory</title>
	<programlisting>&ex72;</programlisting>
      </example>

      
      <para><anchor id="hereesc"></para>
      <para>Quoting or escaping the <quote>limit string</quote> at the
        head of a here document disables parameter substitution within its
	body.</para>

      <example id="ex71c">
	<title>Parameter substitution turned off</title>
	<programlisting>&ex71c;</programlisting>
      </example>

      <para><anchor id="herelit"></para>
      <para>Disabling parameter substitution permits outputting literal text.
        Generating scripts or even program code is one use for this.</para>
      
      <example id="generatescript">
	<title>A script that generates another script</title>
	<programlisting>&generatescript;</programlisting>
      </example>



      <para><anchor id="herecs"></para>
      <para>
        It is possible to set a variable from the output of a here document.
	This is actually a devious form of <link
	linkend="commandsubref">command substitution</link>.
	<programlisting>variable=$(cat &lt;&lt;SETVAR
This variable
runs over multiple lines.
SETVAR)

echo "$variable"</programlisting>
      </para>


      <para><anchor id="herefunc"></para>
      <para>A here document can supply input to a function in the same
        script.</para>

	    <example id="hf">
	      <title>Here documents and functions</title>
	      <programlisting>&hf;</programlisting>
	    </example>

      <para><anchor id="anonheredoc0"></para>
      <para>It is possible to use <token>:</token> as a dummy command
        accepting output from a here document. This, in effect, creates an
	<quote>anonymous</quote> here document.</para>

	<example id="anonheredoc">
	  <title><quote>Anonymous</quote> Here Document</title>
	<programlisting>#!/bin/bash

: &lt;&lt;TESTVARIABLES
${HOSTNAME?}${USER?}${MAIL?}  # Print error message if one of the variables not set.
TESTVARIABLES

exit $?</programlisting>
       </example>


      <para><anchor id="cblock1"></para>
      <tip><para>A variation of the above technique permits <quote>commenting
        out</quote> blocks of code.</para></tip>

      <example id="commentblock">
	<title>Commenting out a block of code</title>
	<programlisting>&commentblock;</programlisting>
      </example>


      <para><anchor id="hselfdoc"></para>
      <tip><para>Yet another twist of this nifty trick makes
        <quote>self-documenting</quote> scripts possible.</para></tip>

      <example id="selfdocument">
	<title>A self-documenting script</title>
	<programlisting>&selfdocument;</programlisting>
      </example>

      <para>Using a <link linkend="catscriptref">cat script</link> is an
        alternate way of accomplishing this.</para>

      <para>
      <programlisting>DOC_REQUEST=70

if [ "$1" = "-h"  -o "$1" = "--help" ]     # Request help.
then                                       # Use a "cat script" . . .
  cat &lt;&lt;DOCUMENTATIONXX
List the statistics of a specified directory in tabular format.
---------------------------------------------------------------
The command line parameter gives the directory to be listed.
If no directory specified or directory specified cannot be read,
then list the current working directory.

DOCUMENTATIONXX
exit $DOC_REQUEST
fi</programlisting>
      </para>


      <para>See also <xref linkend="isspammer2">, <xref linkend="petals">,
        <xref linkend="qky">, and <xref linkend="nim"> for more examples
        of self-documenting scripts.</para>

	  <para><anchor id="heretemp"></para>
	  <note>
	  <para>Here documents create temporary files, but these
	    files are deleted after opening and are not accessible to
	    any other process.</para>
	  <para>
	      <screen><prompt>bash$ </prompt><userinput>bash -c 'lsof -a -p $$ -d0' << EOF</userinput>
<prompt>&gt; </prompt><userinput>EOF</userinput>
<computeroutput>lsof    1213 bozo    0r   REG    3,5    0 30386 /tmp/t1213-0-sh (deleted)</computeroutput>
	      </screen>
	  </para>
	  </note>

	<caution><para>Some utilities will not work inside a
	  <firstterm>here document</firstterm>.</para></caution>

         <para><anchor id="indentedls"></para>

	<warning>

	<para>The closing <firstterm>limit string</firstterm>,
	  on the final line of a here document, must start in the
	  <emphasis>first</emphasis> character position. There can
	  be <emphasis>no leading whitespace</emphasis>. Trailing
	  whitespace after the limit string likewise causes unexpected
	  behavior. The whitespace prevents the limit string from being
	  recognized.</para>

	  
	  
	 <para>
	 <programlisting>#!/bin/bash

echo "----------------------------------------------------------------------"

cat &lt;&lt;LimitString
echo "This is line 1 of the message inside the here document."
echo "This is line 2 of the message inside the here document."
echo "This is the final line of the message inside the here document."
     LimitString
#^^^^Indented limit string. Error! This script will not behave as expected.

echo "----------------------------------------------------------------------"

#  These comments are outside the 'here document',
#+ and should not echo.

echo "Outside the here document."

exit 0

echo "This line had better not echo."  # Follows an 'exit' command.</programlisting>
	 </para>
	  </warning>


	<para>For those tasks too complex for a <quote>here
	  document</quote>, consider using the
	  <firstterm>expect</firstterm> scripting language, which was
	  specifically designed for feeding input into interactive
	  programs.</para>



      <sect1><title>Here Strings</title>

	 <para><anchor id="herestringsref"></para>

         <para>A <firstterm>here string</firstterm> can be considered as
	   a stripped-down form of a <firstterm>here document</firstterm>.
	   It consists of nothing more than <command>COMMAND
	   &lt;&lt;&lt;$WORD</command>, where <varname>$WORD</varname>
	   is expanded and fed to the <filename>stdin</filename> of
	   <parameter>COMMAND</parameter>.</para>

        <para>As a simple example, consider this alternative to the <link
	  linkend="echogrepref">echo-grep</link> construction.</para>

        <para>
	  <programlisting># Instead of:
if echo "$VAR" | grep -q txt   # if [[ $VAR = *txt* ]]
# etc.

# Try:
if grep -q "txt" <<< "$VAR"
then   #         ^^^
   echo "$VAR contains the substring sequence \"txt\""
fi
# Thank you, Sebastian Kaminski, for the suggestion.</programlisting>
        </para>

	<para><anchor id="hsread"></para>
        <para>Or, in combination with <link linkend="readref">read</link>:</para>

        <para>
	<programlisting>String="This is a string of words."

read -r -a Words <<< "$String"
#  The -a option to "read"
#+ assigns the resulting values to successive members of an array.

echo "First word in String is:    ${Words[0]}"   # This
echo "Second word in String is:   ${Words[1]}"   # is
echo "Third word in String is:    ${Words[2]}"   # a
echo "Fourth word in String is:   ${Words[3]}"   # string
echo "Fifth word in String is:    ${Words[4]}"   # of
echo "Sixth word in String is:    ${Words[5]}"   # words.
echo "Seventh word in String is:  ${Words[6]}"   # (null)
                                                 # Past end of $String.

# Thank you, Francisco Lobo, for the suggestion.</programlisting>
        </para>

	<para><anchor id="hspre"></para>
      <example id="prependex">
	<title>Prepending a line to a file</title>
	<programlisting>&prependex;</programlisting>
      </example>

      <example id="mailboxgrep">
	<title>Parsing a mailbox</title>
	<programlisting>&mailboxgrep;</programlisting>
      </example>

         <para>Exercise: Find other uses for <firstterm>here
            strings</firstterm>.</para>

      </sect1><!--   Here Strings    -->


  </chapter> <!-- Here Documents -->



  <chapter id="io-redirection">
    <title>I/O Redirection</title>

      <para><anchor id="ioredirref"></para>

      <para>There are always three default <firstterm>files</firstterm>
         <footnote><para>By convention in UNIX and Linux, data streams
	 and peripherals (<firstterm>device files</firstterm>)
	 are treated as files, in a fashion analogous to ordinary
	 files.</para></footnote>
	open, <filename>stdin</filename> (the keyboard),
	<filename>stdout</filename> (the screen), and
	<filename>stderr</filename> (error messages output to the
	screen).  These, and any other open files, can be redirected.
	Redirection simply means capturing output from a file, command,
	program, script, or even code block within a script (see <xref
	linkend="ex8"> and <xref linkend="rpmcheck">) and sending it as
	input to another file, command, program, or script.</para>

      <para><anchor id="fdref">Each open file gets assigned a file descriptor.	

               <footnote><para><anchor id="fdref1">A <firstterm>file
		 descriptor</firstterm> is simply a number that
		 the operating system assigns to an open file
		 to keep track of it.  Consider it a simplified
		 type of file pointer. It is analogous
		 to a <firstterm>file handle</firstterm> in
		 <firstterm>C</firstterm>.</para></footnote>

	The file descriptors for <filename>stdin</filename>,
	<filename>stdout</filename>, and <filename>stderr</filename> are
	0, 1, and 2, respectively.  For opening additional files, there
	remain descriptors 3 to 9. It is sometimes useful to assign one of
	these additional file descriptors to <filename>stdin</filename>,
	<filename>stdout</filename>, or <filename>stderr</filename>
	as a temporary duplicate link.
	       <footnote><para>Using <replaceable>file
	       descriptor 5</replaceable> might cause problems.
	       When Bash creates a child process, as with <link
	       linkend="execref">exec</link>, the child inherits
	       fd 5 (see Chet Ramey's archived e-mail, <ulink
	       url="http://www.geocrawler.com/archives/3/342/1996/1/0/1939805/">
	       SUBJECT: RE:  File descriptor 5 is held open</ulink>).
	       Best leave this particular fd alone.</para></footnote>
	This simplifies restoration to normal after complex redirection
	and reshuffling (see <xref linkend="redir1">).</para>

      <para><anchor id="ioredirectionref"></para>

      <programlisting>   COMMAND_OUTPUT >
      # Redirect stdout to a file.
      # Creates the file if not present, otherwise overwrites it.

      ls -lR > dir-tree.list
      # Creates a file containing a listing of the directory tree.

   : > filename
      # The > truncates file "filename" to zero length.
      # If file not present, creates zero-length file (same effect as 'touch').
      # The : serves as a dummy placeholder, producing no output.

   > filename    
      # The > truncates file "filename" to zero length.
      # If file not present, creates zero-length file (same effect as 'touch').
      # (Same result as ": >", above, but this does not work with some shells.)

   COMMAND_OUTPUT >>
      # Redirect stdout to a file.
      # Creates the file if not present, otherwise appends to it.


      # Single-line redirection commands (affect only the line they are on):
      # --------------------------------------------------------------------

   1>filename
      # Redirect stdout to file "filename."
   1>>filename
      # Redirect and append stdout to file "filename."
   2>filename
      # Redirect stderr to file "filename."
   2>>filename
      # Redirect and append stderr to file "filename."
   &>filename
      # Redirect both stdout and stderr to file "filename."
      #
      #  Note that   &>>filename
      #+ -- attempting to redirect and *append*
      #+ stdout and stderr to file "filename" --
      #+ fails with the error message,
      #+ syntax error near unexpected token `>'.

   M>N
     # "M" is a file descriptor, which defaults to 1, if not explicitly set.
     # "N" is a filename.
     # File descriptor "M" is redirect to file "N."
   M&gt;&amp;N
     # "M" is a file descriptor, which defaults to 1, if not set.
     # "N" is another file descriptor.

      #==============================================================================

      # Redirecting stdout, one line at a time.
      LOGFILE=script.log

      echo "This statement is sent to the log file, \"$LOGFILE\"." 1>$LOGFILE
      echo "This statement is appended to \"$LOGFILE\"." 1>>$LOGFILE
      echo "This statement is also appended to \"$LOGFILE\"." 1>>$LOGFILE
      echo "This statement is echoed to stdout, and will not appear in \"$LOGFILE\"."
      # These redirection commands automatically "reset" after each line.



      # Redirecting stderr, one line at a time.
      ERRORFILE=script.errors

      bad_command1 2>$ERRORFILE       #  Error message sent to $ERRORFILE.
      bad_command2 2>>$ERRORFILE      #  Error message appended to $ERRORFILE.
      bad_command3                    #  Error message echoed to stderr,
                                      #+ and does not appear in $ERRORFILE.
      # These redirection commands also automatically "reset" after each line.
      #=======================================================================</programlisting>


      <para><anchor id="ioredirectionref1"></para>

      <programlisting>
   2>&amp;1
      # Redirects stderr to stdout.
      # Error messages get sent to same place as standard output.

   i>&amp;j
      # Redirects file descriptor <emphasis>i</emphasis> to <emphasis>j</emphasis>.
      # All output of file pointed to by <emphasis>i</emphasis> gets sent to file pointed to by <emphasis>j</emphasis>.

   >&amp;j
      # Redirects, by default, file descriptor <emphasis>1</emphasis> (stdout) to <emphasis>j</emphasis>.
      # All stdout gets sent to file pointed to by <emphasis>j</emphasis>.</programlisting>

      <para><anchor id="ioredirectionref2"></para>

      <programlisting>
   0< FILENAME
    < FILENAME
      # Accept input from a file.
      # Companion command to <quote>></quote>, and often used in combination with it.
      #
      # grep search-word &lt;filename


   [j]&lt;&gt;filename
      #  Open file "filename" for reading and writing,
      #+ and assign file descriptor "j" to it.
      #  If "filename" does not exist, create it.
      #  If file descriptor "j" is not specified, default to fd 0, stdin.
      #
      #  An application of this is writing at a specified place in a file. 
      echo 1234567890 > File    # Write string to "File".
      exec 3&lt;&gt; File             # Open "File" and assign fd 3 to it.
      read -n 4 <&3             # Read only 4 characters.
      echo -n . >&3             # Write a decimal point there.
      exec 3>&-                 # Close fd 3.
      cat File                  # ==> 1234.67890
      #  Random access, by golly.



   |
      # Pipe.
      # General purpose process and command chaining tool.
      # Similar to <quote>></quote>, but more general in effect.
      # Useful for chaining commands, scripts, files, and programs together.
      cat *.txt | sort | uniq > result-file
      # Sorts the output of all the .txt files and deletes duplicate lines,
      # finally saves results to <quote>result-file</quote>.</programlisting>

      <para>Multiple instances of input and output redirection
        and/or pipes can be combined in a single command
        line.

       <programlisting>command &lt; input-file &gt; output-file

command1 | command2 | command3 > output-file</programlisting>
        See <xref linkend="derpm"> and <xref linkend="fifo">.</para>

       
       <para>Multiple output streams may be redirected to one file.

         <programlisting>ls -yz >> command.log 2>&1
#  Capture result of illegal options "yz" in file "command.log."
#  Because stderr is redirected to the file,
#+ any error messages will also be there.

#  Note, however, that the following does *not* give the same result.
ls -yz 2>&1 >> command.log
#  Outputs an error message and does not write to file.

#  If redirecting both stdout and stderr,
#+ the order of the commands makes a difference.
</programlisting></para>


      <variablelist id="closingfiledescriptors">
        <title><anchor id="cfd">Closing File Descriptors</title>

	<varlistentry>
	  <term><token>n<&-</token></term>
	  <listitem>
	    <para>Close input file descriptor
	    <replaceable>n</replaceable>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>0<&-</token></term>
	  <term><token><&-</token></term>
	  <listitem>
	    <para>Close <filename>stdin</filename>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>n>&-</token></term>
	  <listitem>
	    <para>Close output file descriptor <replaceable>n</replaceable>.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><token>1>&-</token></term>
	  <term><token>>&-</token></term>
	  <listitem>
	    <para>Close <filename>stdout</filename>.</para>
	  </listitem>
	</varlistentry>

      </variablelist>


        <para>Child processes inherit open file descriptors. This is why pipes
	  work. To prevent an fd from being inherited, close it.
	    <programlisting># Redirecting only stderr to a pipe.

exec 3>&1                              # Save current "value" of stdout.
ls -l 2>&1 >&3 3>&- | grep bad 3>&-    # Close fd 3 for 'grep' (but not 'ls').
#              ^^^^   ^^^^
exec 3>&-                              # Now close it for the remainder of the script.

# Thanks, S.C.</programlisting>
        </para>

	<para>For a more detailed introduction to I/O redirection see
	  <xref linkend="ioredirintro">.</para>




      <sect1><title>Using <firstterm>exec</firstterm></title>


	<para><anchor id="usingexecref"></para>

        <para>An <command>exec &lt;filename</command> command redirects
	  <filename>stdin</filename> to a file. From that point on, all
	  <filename>stdin</filename> comes from that file, rather than
	  its normal source (usually keyboard input). This provides a
	  method of reading a file line by line and possibly parsing
	  each line of input using <link linkend="sedref">sed</link>
	  and/or <link linkend="awkref">awk</link>.</para>

      <example id="redir1">
	<title>Redirecting <filename>stdin</filename> using
	  <firstterm>exec</firstterm></title>
	<programlisting>&redir1;</programlisting>
      </example>

        <para>Similarly, an <command>exec &gt;filename</command>
	  command redirects <filename>stdout</filename> to a designated
	  file.  This sends all command output that would normally go
	  to <filename>stdout</filename> to that file.</para>

      <important>
        <para>
	  <command>exec N > filename</command> affects the entire
	  script or <firstterm>current shell</firstterm>. Redirection in
	  the <link linkend="processidref">PID</link> of the script or shell
	  from that point on has changed. However . . .
        </para>
        <para>
	  <command>N > filename</command> affects only the newly-forked process,
	  not the entire script or shell.
        </para>
	<para>Thank you, Ahmed Darwish, for pointing this out.</para>
      </important>



      <example id="reassignstdout">
	<title>Redirecting <filename>stdout</filename> using
	  <firstterm>exec</firstterm></title>
	<programlisting>&reassignstdout;</programlisting>
      </example>

      <example id="upperconv">
	<title>Redirecting both <filename>stdin</filename> and
	  <filename>stdout</filename> in the same script with
	  <firstterm>exec</firstterm></title>
	<programlisting>&upperconv;</programlisting>
      </example>

      <para>I/O redirection is a clever way of avoiding the dreaded <link
      linkend="parvis">inaccessible variables within a subshell</link>
      problem.</para>

      <example id="avoidsubshell">
	<title>Avoiding a subshell</title>
	<programlisting>&avoidsubshell;</programlisting>
      </example>

       

       </sect1><!-- Using exec For Redirection -->	



      <sect1 id="redircb"><title>Redirecting Code Blocks</title>

        <para><anchor id="redirref">Blocks of code, such as <link
	  linkend="whileloopref">while</link>, <link
	  linkend="untilloopref">until</link>, and <link
	  linkend="forloopref1">for</link> loops, even <link
	  linkend="ifthen">if/then</link> test blocks can also incorporate
	  redirection of <filename>stdin</filename>.  Even a function may
	  use this form of redirection (see <xref linkend="realname">).
	  The <token>&lt;</token> operator at the end of the code block
	  accomplishes this.</para>

      <example id="redir2">
	<title>Redirected <firstterm>while</firstterm> loop</title>
	<programlisting>&redir2;</programlisting>
      </example>

      <example id="redir2a">
	<title>Alternate form of redirected <firstterm>while</firstterm> loop</title>
	<programlisting>&redir2a;</programlisting>
      </example>

      <example id="redir3">
	<title>Redirected <firstterm>until</firstterm> loop</title>
	<programlisting>&redir3;</programlisting>
      </example>

      <example id="redir4">
	<title>Redirected <firstterm>for</firstterm> loop</title>
	<programlisting>&redir4;</programlisting>
      </example>

      <para>We can modify the previous example to also redirect the output of
        the loop.</para>

      <example id="redir4a">
	<title>Redirected <firstterm>for</firstterm> loop (both
	  <filename>stdin</filename> and <filename>stdout</filename>
	  redirected)</title>
	<programlisting>&redir4a;</programlisting>
      </example>

      <example id="redir5">
	<title>Redirected <firstterm>if/then</firstterm> test</title>
	<programlisting>&redir5;</programlisting>
      </example>

      <example id="namesdata">
	<title>Data file <firstterm>names.data</firstterm> for above
	examples</title>
	<programlisting>&namesdata;</programlisting>
      </example>

      <para>Redirecting the <filename>stdout</filename> of a code
	block has the effect of saving its output to a file. See <xref
	linkend="rpmcheck">.</para>

      <para><link linkend="heredocref">Here documents</link>
        are a special case of redirected code blocks. That being the case,
	it should be possible to feed the output of a <firstterm>here
	document</firstterm> into the <filename>stdin</filename> for a
	<firstterm>while loop</firstterm>.</para>

            <para>
	    <programlisting># This example by Albert Siersema
# Used with permission (thanks!).

function doesOutput()
 # Could be an external command too, of course.
 # Here we show you can use a function as well.
{
  ls -al *.jpg | awk '{print $5,$9}'
}


nr=0          #  We want the while loop to be able to manipulate these and
totalSize=0   #+ to be able to see the changes after the while finished.

while read fileSize fileName ; do
  echo "$fileName is $fileSize bytes"
  let nr++
  totalSize=$((totalSize+fileSize))   # Or: "let totalSize+=fileSize"
done&lt;&lt;EOF
$(doesOutput)
EOF

echo "$nr files totaling $totalSize bytes"</programlisting>
            </para>

      </sect1><!--  Redirecting Code Blocks -->



      <sect1 id="redirapps"><title>Applications</title>

      <para>Clever use of I/O redirection permits parsing and stitching
	together snippets of command output (see <xref
	linkend="readredir">). This permits
	 generating report and log files.</para>

      <example id="logevents">
	<title>Logging events</title>
	<programlisting>&logevents;</programlisting>
      </example>


       </sect1><!-- Applications -->	


  </chapter> <!-- I/O Redirection -->




  <chapter id="subshells">
    <title>Subshells</title>

      <para><anchor id="subshellsref"></para>

      <para>Running a shell script launches a new process, a
        <firstterm>subshell</firstterm>.</para>

      <sidebar>
        <para>Definition: A <firstterm>subshell</firstterm> is a
          <link linkend="childref2">child process</link> launched by a
          shell (or <firstterm>shell script</firstterm>).</para>
      </sidebar>
      
      <para>A subshell is a separate instance of the command processor
        -- the <firstterm>shell</firstterm> that gives you the prompt at
        the console or in an <firstterm>xterm</firstterm> window. Just
        as your commands are interpreted at the command line prompt,
        similarly does a script <link
        linkend="batchprocref">batch-process</link> a list of
        commands. Each shell script running is, in effect, a subprocess
        (<firstterm>child process</firstterm>) of the <link
        linkend="forkref">parent</link> shell.</para>


      <para>A shell script can itself launch subprocesses. These
	<firstterm>subshells</firstterm> let the script do
	parallel processing, in effect executing multiple subtasks
	simultaneously.</para>


      <para>
      <programlisting>#!/bin/bash
# subshell-test.sh

(
# Inside parentheses, and therefore a subshell . . .
while [ 1 ]   # Endless loop.
do
  echo "Subshell running . . ."
done
)

#  Script will run forever,
#+ or at least until terminated by a Ctl-C.

exit $?  # End of script (but will never get here).



Now, run the script:
sh subshell-test.sh

And, while the script is running, from a different xterm:
ps -ef | grep subshell-test.sh

UID       PID   PPID  C STIME TTY      TIME     CMD
500       2698  2502  0 14:26 pts/4    00:00:00 sh subshell-test.sh
500       2699  2698 21 14:26 pts/4    00:00:24 sh subshell-test.sh

          ^^^^

Analysis:
PID 2698, the script, launched PID 2699, the subshell.

Note: The "UID ..." line would be filtered out by the "grep" command,
but is shown here for illustrative purposes.</programlisting>
      </para>


      <para>In general, an <link linkend="externalref">external
	command</link> in a script <link linkend="forkref">forks
	off</link> a subprocess,
           <footnote><para>An external command invoked with an <link
             linkend="execref">exec</link> does <emphasis>not</emphasis>
             (usually) fork off a subprocess / subshell.</para></footnote>
	whereas a Bash <link
	linkend="builtinref">builtin</link> does not. For this reason,
	builtins execute more quickly than their external command
	equivalents.</para>



      <variablelist id="subshellparens">
	<title><anchor id="subshellparens1">Command List within
	Parentheses</title>

	<varlistentry>
	  <term>( command1; command2; command3; ... )</term>
	<listitem>
	  <para>A command list embedded between
	  <replaceable>parentheses</replaceable> runs as a
	  subshell.</para>
	</listitem>
	</varlistentry>
      </variablelist>

      <para><anchor id="parvis">Variables in a subshell are
        <emphasis>not</emphasis> visible outside the block of code
        in the subshell. They are not accessible to the <link
        linkend="forkref">parent process</link>, to the shell
        that launched the subshell. These are, in effect,
        variables <link linkend="localref">local</link> to the
	<firstterm>child process</firstterm>.</para>

      <example id="subshell">
	<title>Variable scope in a subshell</title>
	<programlisting>&subshell;</programlisting>
      </example>
      <para>See also <xref linkend="subpit">.</para>

      <sidebar>
          <para><anchor id="scoperef"></para>
	  <para><emphasis>Definition:</emphasis> The
	    <firstterm>scope</firstterm> of a variable is the
	    context in which it has meaning, in which it has a
	    <firstterm>value</firstterm> that can be referenced. For
	    example, the scope of a <link linkend="localref1">local
	    variable</link> lies only within the function,
	    block of code, or subshell within which it is defined,
	    while the scope of a <firstterm>global</firstterm> variable
	    is the entire script in which it appears.</para>
      </sidebar>




	  <para><anchor id="subshnlevref"></para>
	  <note>
	    <para>While the <link linkend="bashsubshellref">$BASH_SUBSHELL</link>
	      internal variable indicates the nesting level of a
	      subshell, the <link linkend="shlvlref">$SHLVL</link>
	      variable <emphasis>shows no change</emphasis> within
	      a subshell.</para>

            <para>
<programlisting>echo " \$BASH_SUBSHELL outside subshell       = $BASH_SUBSHELL"           # 0
  ( echo " \$BASH_SUBSHELL inside subshell        = $BASH_SUBSHELL" )     # 1
  ( ( echo " \$BASH_SUBSHELL inside nested subshell = $BASH_SUBSHELL" ) ) # 2
# ^ ^                           *** nested ***                        ^ ^

echo

echo " \$SHLVL outside subshell = $SHLVL"       # 3
( echo " \$SHLVL inside subshell  = $SHLVL" )   # 3 (No change!)</programlisting>
            </para>
	  </note>



      <para>Directory changes made in a subshell do not carry over to the
        parent shell.</para>

      <example id="allprofs">
	<title>List User Profiles</title>
	<programlisting>&allprofs;</programlisting>
      </example>


      <para>A subshell may be used to set up a <quote>dedicated
	      environment</quote> for a command group.
	      <programlisting>COMMAND1
COMMAND2
COMMAND3
(
  IFS=:
  PATH=/bin
  unset TERMINFO
  set -C
  shift 5
  COMMAND4
  COMMAND5
  exit 3 # Only exits the subshell!
)
# The parent shell has not been affected, and the environment is preserved.
COMMAND6
COMMAND7</programlisting>

    As seen here, the <link linkend="exitref">exit</link>
    command only terminates the subshell in which it is running,
    <emphasis>not</emphasis> the parent shell or script.</para>

      <para>One application of such a <quote>dedicated environment</quote>
        is testing whether a variable is defined.
              <programlisting>if (set -u; : $variable) 2&gt; /dev/null
then
  echo "Variable is set."
fi     #  Variable has been set in current script,
       #+ or is an an internal Bash variable,
       #+ or is present in environment (has been exported).

# Could also be written [[ ${variable-x} != x || ${variable-y} != y ]]
# or                    [[ ${variable-x} != x$variable ]]
# or                    [[ ${variable+x} = x ]]
# or                    [[ ${variable-x} != x ]]</programlisting></para>

      <para>Another application is checking for a lock file:
	      <programlisting>if (set -C; : &gt; lock_file) 2&gt; /dev/null
then
  :   # lock_file didn't exist: no user running the script
else
  echo "Another user is already running that script."
exit 65
fi

#  Code snippet by St&eacute;phane Chazelas,
#+ with modifications by Paulo Marcel Coelho Aragao.</programlisting>
      </para>   

      <para>+</para>

      <para>Processes may execute in parallel within different
        subshells. This permits breaking a complex task into subcomponents
        processed concurrently.</para>

      <example id="parallel-processes">
	<title>Running parallel processes in subshells</title>
	<programlisting>
	(cat list1 list2 list3 | sort | uniq > list123) &
	(cat list4 list5 list6 | sort | uniq > list456) &
	# Merges and sorts both sets of lists simultaneously.
	# Running in background ensures parallel execution.
	#
	# Same effect as
	#   cat list1 list2 list3 | sort | uniq > list123 &
	#   cat list4 list5 list6 | sort | uniq > list456 &
	
	wait   # Don't execute the next command until subshells finish.
	
	diff list123 list456</programlisting>
	</example>

	<para>Redirecting I/O to a subshell uses the <quote>|</quote> pipe
	  operator, as in <userinput>ls -al | (command)</userinput>.</para>


	  <note><para>A command block between <replaceable>curly
	  braces</replaceable> does <emphasis>not</emphasis> launch
	  a subshell.</para>
	  <para>{ command1; command2; command3; . . . commandN; }</para></note>



  </chapter> <!-- Subshells -->


    
  <chapter id="restricted-sh">
    <title>Restricted Shells</title>

      <para><anchor id="restrictedshref"></para>

      <variablelist id="disabledcommref0">
        <title><anchor id="disabledcommref">Disabled commands in restricted
	  shells</title>
	<varlistentry>
	  <term></term>
	  <listitem>
	  <formalpara><title> </title>
      <para>Running a script or portion of a script in
        <firstterm>restricted mode</firstterm> disables certain commands
        that would otherwise be available. This is a security measure
        intended to limit the privileges of the script user and to
        minimize possible damage from running the script.</para>
	  </formalpara>  
	  </listitem>
      </varlistentry>

      </variablelist>	

      <para>The following commands and actions are disabled:</para>
        
      <itemizedlist>
        <listitem>
	  <para>Using <replaceable>cd</replaceable> to change the working
	  directory.</para>
	</listitem>

	<listitem>
	  <para>Changing the values of the
	  <replaceable>$PATH</replaceable>,
	  <replaceable>$SHELL</replaceable>,
	  <replaceable>$BASH_ENV</replaceable>,
	  or <replaceable>$ENV</replaceable> <link
	  linkend="envref">environmental variables</link>.</para>
	</listitem>
	
	<listitem>
	  <para>Reading or changing the <replaceable>$SHELLOPTS</replaceable>,
	  shell environmental options.</para>
	</listitem>
	
	<listitem>
	  <para>Output redirection.</para>
	</listitem>
	
	<listitem>
	  <para>Invoking commands containing one or more
	  <token>/</token>'s.</para>
	</listitem>
	
	
	<listitem>
	  <para>Invoking <link linkend="execref">exec</link> to substitute
	  a different process for the shell.</para>
	</listitem>
	
	<listitem>
	  <para>Various other commands that would enable monkeying
	  with or attempting to subvert the script for an unintended
	  purpose.</para>
	</listitem>
	
	
	<listitem>
	  <para>Getting out of restricted mode within the script.</para>
	</listitem>  

      </itemizedlist>


      <example id="restricted">
	<title>Running a script in restricted mode</title>
	<programlisting>&restricted;</programlisting>
      </example>

  </chapter> <!-- Restricted Shells -->




  <chapter id="process-sub">
    <title>Process Substitution</title>

      <para><anchor id="processsubref"><link
	linkend="piperef">Piping</link> the <filename>stdout</filename>
	of a command into the <filename>stdin</filename> of another
	is a powerful technique.  But, what if you need to pipe the
	<filename>stdout</filename> of <emphasis>multiple</emphasis>
	commands? This is where <replaceable>process
	substitution</replaceable> comes in.</para>

      <para><firstterm>Process substitution</firstterm> feeds the
        output of a process (or processes) into the
        <filename>stdin</filename> of another process.</para>

      <variablelist id="commandsparens">
        <title><anchor id="commandsparens1">Template</title>

	<varlistentry>
	  <term>Command list enclosed within parentheses</term>

	<listitem>
	  <para><command>&gt;(command_list)</command></para>
	  <para><command>&lt;(command_list)</command></para>
	  <para>Process substitution uses
	    <filename>/dev/fd/&lt;n&gt;</filename> files to send the
	    results of the process(es) within parentheses to another process.
	      <footnote><para>This has the same effect as a
		<link linkend="namedpiperef">named pipe</link> (temp
		file), and, in fact, named pipes were at one time used
		in process substitution.</para></footnote>
	  </para>

          <caution><para>There is <emphasis>no</emphasis> space between the
            the <quote><</quote> or <quote>></quote> and the parentheses.
            Space there would give an error message.</para></caution>

	</listitem>
	
	</varlistentry>
      </variablelist>


              <para>
	      <screen><prompt>bash$ </prompt><userinput>echo >(true)</userinput>
<computeroutput>/dev/fd/63</computeroutput>

<prompt>bash$ </prompt><userinput>echo <(true)</userinput>
<computeroutput>/dev/fd/63</computeroutput>
	      </screen>

	  Bash creates a pipe with two <link linkend="fdref">file
	  descriptors</link>, <filename>--fIn</filename> and
	  <filename>fOut--</filename>.	The <filename>stdin</filename>
	  of <link linkend="trueref">true</link> connects
	  to <filename>fOut</filename> (dup2(fOut, 0)),
	  then Bash passes a <filename>/dev/fd/fIn</filename>
	  argument to <command>echo</command>. On systems lacking
	  <filename>/dev/fd/&lt;n&gt;</filename> files, Bash may use
	  temporary files. (Thanks, S.C.)</para>


              <para>Process substitution can compare the output of two
	       different commands, or even the output of different options
	       to the same command.</para>

	 <screen><prompt>bash$ </prompt><userinput>comm <(ls -l) <(ls -al)</userinput>
<computeroutput>total 12
-rw-rw-r--    1 bozo bozo       78 Mar 10 12:58 File0
-rw-rw-r--    1 bozo bozo       42 Mar 10 12:58 File2
-rw-rw-r--    1 bozo bozo      103 Mar 10 12:58 t2.sh
        total 20
        drwxrwxrwx    2 bozo bozo     4096 Mar 10 18:10 .
        drwx------   72 bozo bozo     4096 Mar 10 17:58 ..
        -rw-rw-r--    1 bozo bozo       78 Mar 10 12:58 File0
        -rw-rw-r--    1 bozo bozo       42 Mar 10 12:58 File2
        -rw-rw-r--    1 bozo bozo      103 Mar 10 12:58 t2.sh</computeroutput></screen>

	      <para><anchor id="pcc2dir"></para>
	      <para>
	        Using process substitution to compare the contents
		of two directories (to see which filenames are in one,
		but not the other):
		<programlisting>diff <(ls $first_directory) <(ls $second_directory)</programlisting>
              </para>

              <para>Some other usages and uses of process substitution:</para>
	      <para><anchor id="psfdstdin"></para>
      <para><programlisting>read -a list < <( od -Ad -w24 -t u2 /dev/urandom )
#  Read a list of random numbers from /dev/urandom,
#+ process with "od"
#+ and feed into stdin of "read" . . .

#  From "insertion-sort.bash" example script.
#  Courtesy of JuanJo Ciarlante.</programlisting></para>

      <para><programlisting>cat <(ls -l)
# Same as     ls -l | cat

sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) <(ls -l /usr/X11R6/bin)
# Lists all the files in the 3 main 'bin' directories, and sorts by filename.
# Note that three (count 'em) distinct commands are fed to 'sort'.

 
diff <(command1) <(command2)    # Gives difference in command output.

tar cf >(bzip2 -c > file.tar.bz2) $directory_name
# Calls "tar cf /dev/fd/?? $directory_name", and "bzip2 -c > file.tar.bz2".
#
# Because of the /dev/fd/&lt;n&gt; system feature,
# the pipe between both commands does not need to be named.
#
# This can be emulated.
#
bzip2 -c < pipe > file.tar.bz2&
tar cf pipe $directory_name
rm pipe
#        or
exec 3>&1
tar cf /dev/fd/4 $directory_name 4>&1 >&3 3>&- | bzip2 -c > file.tar.bz2 3>&-
exec 3>&-


# Thanks, St&eacute;phane Chazelas</programlisting></para>


      <para>A reader sent in the following interesting example of process
        substitution.</para>

      <para><programlisting># Script fragment taken from SuSE distribution:

# --------------------------------------------------------------#
while read  des what mask iface; do
# Some commands ...
done < <(route -n)  
#    ^ ^  First &lt; is redirection, second is process substitution.

# To test it, let's make it do something.
while read  des what mask iface; do
  echo $des $what $mask $iface
done < <(route -n)  

# Output:
# Kernel IP routing table
# Destination Gateway Genmask Flags Metric Ref Use Iface
# 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
# --------------------------------------------------------------#

#  As St&eacute;phane Chazelas points out,
#+ an easier-to-understand equivalent is:
route -n |
  while read des what mask iface; do   # Variables set from output of pipe.
    echo $des $what $mask $iface
  done  #  This yields the same output as above.
        #  However, as Ulrich Gayer points out . . .
        #+ this simplified equivalent uses a subshell for the while loop,
        #+ and therefore the variables disappear when the pipe terminates.
	
# --------------------------------------------------------------#
	
#  However, Filip Moritz comments that there is a subtle difference
#+ between the above two examples, as the following shows.

(
route -n | while read x; do ((y++)); done
echo $y # $y is still unset

while read x; do ((y++)); done < <(route -n)
echo $y # $y has the number of lines of output of route -n
)

More generally spoken
(
: | x=x
# seems to start a subshell like
: | ( x=x )
# while
x=x < <(:)
# does not
)

# This is useful, when parsing csv and the like.
# That is, in effect, what the original SuSE code fragment does.</programlisting></para>

  </chapter> <!-- Process Substitution -->




  <chapter id="functions">
    <title>Functions</title>

      <para><anchor id="functionref"></para>
      
      <para>Like <quote>real</quote> programming languages,
	Bash has functions, though in a somewhat limited implementation.
	A function is a subroutine, a <link linkend="codeblockref">code
	block</link> that implements a set of operations, a <quote>black
	box</quote> that performs a specified task.  Wherever there is
	repetitive code, when a task repeats with only slight variations in
	procedure, then consider using a function.</para>

      <para><cmdsynopsis>
	  <command>function</command>
	  <arg choice="plain"><replaceable>function_name</replaceable></arg> 
	  <arg choice="plain">{</arg><sbr>
	  <arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr>
	  <arg choice="plain">}</arg><sbr>
	</cmdsynopsis>
	or 
	<cmdsynopsis>
	  <arg choice="plain"><replaceable>function_name</replaceable></arg> 
	  <arg choice="plain">()</arg>
	  <arg choice="plain">{</arg><sbr>
	  <arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr>
	  <arg choice="plain">}</arg><sbr>
	</cmdsynopsis>
      </para>

      <para>This second form will cheer the hearts of C programmers
        (and is more portable).</para>

      <para>As in C, the function's opening bracket may optionally appear
        on the second line.</para>

      <para><cmdsynopsis>
	  <arg choice="plain"><replaceable>function_name</replaceable></arg> 
	  <arg choice="plain">()</arg><sbr>
	  <arg choice="plain">{</arg><sbr>
	  <arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr>
	  <arg choice="plain">}</arg><sbr>
	</cmdsynopsis>
      </para>

      <note>
        <para>A function may be <quote>compacted</quote> into a single
          line.</para>
	  
	<para><programlisting>fun () { echo "This is a function"; echo; }
#                                 ^     ^</programlisting></para>

        <para>In this case, however, a <firstterm>semicolon</firstterm>
          must follow the final command in the function.</para>

	<para><programlisting>fun () { echo "This is a function"; echo } # Error!
#                                       ^</programlisting></para>
      </note>

      <para>Functions are called, <firstterm>triggered</firstterm>, simply by
	invoking their names. <emphasis>A function call is equivalent to
	a command.</emphasis></para>

      <example id="ex59">
	<title>Simple functions</title>
	<programlisting>&ex59;</programlisting>
      </example>

      <para><anchor id="functdefmust"></para>
      <para>The function definition must precede the first call to
	it. There is no method of <quote>declaring</quote> the function,
	as, for example, in C.
	  <programlisting>f1
# Will give an error message, since function "f1" not yet defined.

declare -f f1      # This doesn't help either.
f1                 # Still an error message.

# However...

	  
f1 ()
{
  echo "Calling function \"f2\" from within function \"f1\"."
  f2
}

f2 ()
{
  echo "Function \"f2\"."
}

f1  #  Function "f2" is not actually called until this point,
    #+ although it is referenced before its definition.
    #  This is permissible.
    
    # Thanks, S.C.</programlisting>
      </para>

      <note><para><anchor id="emptyfunc">Functions may not be empty!
        <programlisting>#!/bin/bash
# empty-function.sh

empty ()
{
}

exit 0  # Will not exit here!

# $ sh empty-function.sh
# empty-function.sh: line 6: syntax error near unexpected token `}'
# empty-function.sh: line 6: `}'

# $ echo $?
# 2



# However ...

not_quite_empty ()
{
  illegal_command
} #  A script containing this function will *not* bomb
  #+ as long as the function is not called.


# Thank you, Thiemo Kellner, for pointing this out.</programlisting>
</para></note>




      <para>It is even possible to nest a function within another function,
        although this is not very useful.
	  <programlisting>f1 ()
{

  f2 () # nested
  {
    echo "Function \"f2\", inside \"f1\"."
  }

}  

f2  #  Gives an error message.
    #  Even a preceding "declare -f f2" wouldn't help.

echo    

f1  #  Does nothing, since calling "f1" does not automatically call "f2".
f2  #  Now, it's all right to call "f2",
    #+ since its definition has been made visible by calling "f1".

    # Thanks, S.C.</programlisting>
      </para>
      
      <para>Function declarations can appear in unlikely places, even where a
        command would otherwise go.
          <programlisting>ls -l | foo() { echo "foo"; }  # Permissible, but useless.



if [ "$USER" = bozo ]
then
  bozo_greet ()   # Function definition embedded in an if/then construct.
  {
    echo "Hello, Bozo."
  }
fi  

bozo_greet        # Works only for Bozo, and other users get an error.



# Something like this might be useful in some contexts.
NO_EXIT=1   # Will enable function definition below.

[[ $NO_EXIT -eq 1 ]] && exit() { true; }     # Function definition in an "and-list".
# If $NO_EXIT is 1, declares "exit ()".
# This disables the "exit" builtin by aliasing it to "true".

exit  # Invokes "exit ()" function, not "exit" builtin.



# Or, similarly:
filename=file1

[ -f "$filename" ] &&
foo () { rm -f "$filename"; echo "File "$filename" deleted."; } ||
foo () { echo "File "$filename" not found."; touch bar; }

foo

# Thanks, S.C. and Christopher Head</programlisting>
      </para>

      <note><para>What happens when different versions of the same function
        appear in a script?
	<programlisting>#  As Yan Chen points out,
#  when a function is defined multiple times,
#  the final version is what is invoked.
#  This is not, however, particularly useful.

func ()
{
  echo "First version of func ()."
}

func ()
{
  echo "Second version of func ()."
}

func   # Second version of func ().

exit $?

#  It is even possible to use functions to override
#+ or preempt system commands.
#  Of course, this is *not* advisable.</programlisting></para></note>

      <!-- End of intro section -->

      <sect1 id="complexfunct">
        <title>Complex Functions and Function Complexities</title>

      <para>Functions may process arguments passed to them and return
	an <link linkend="exitstatusref">exit status</link> to the script
	for further processing.</para>

      <programlisting>function_name $arg1 $arg2</programlisting>

      <para><anchor id="passedargs"></para>
      <para>The function refers to the passed arguments by position (as if they were
	<link linkend="posparamref">positional parameters</link>),
	that is, <varname>$1</varname>, <varname>$2</varname>, and
	so forth.</para>

      <example id="ex60">
	<title>Function Taking Parameters</title>
	<programlisting>&ex60;</programlisting>
      </example>

      <para><anchor id="fshiftref"></para>
      <important><para>The <link linkend="shiftref">shift</link>
        command works on arguments passed to functions (see <xref
	linkend="multiplication">).</para></important>

      <para>But, what about command-line arguments passed to the script? 
        Does a function see them? Well, let's clear up the confusion.</para>

      <example id="funccmdlinearg">
	<title>Functions and command-line args passed to the script</title>
	<programlisting>&funccmdlinearg;</programlisting>
      </example>


      <para>In contrast to certain other programming languages,
	shell scripts normally pass only value parameters to
	functions. Variable names (which are actually
	<firstterm>pointers</firstterm>), if
	passed as parameters to functions, will be treated as string
	literals.  <emphasis>Functions interpret their arguments
	literally.</emphasis></para>

	<para><anchor id="funcpointers"></para>
	<para><link linkend="ivrref">Indirect variable
	    references</link> (see <xref linkend="ex78">) provide a clumsy
	    sort of mechanism for passing variable pointers to
	    functions.</para>

	    <example id="indfunc">
	      <title>Passing an indirect reference to a function</title>
	      <programlisting>&indfunc;</programlisting>
	    </example>

	<para>The next logical question is whether parameters can be
	  dereferenced <emphasis>after</emphasis> being passed to a
	  function.</para>

	    <example id="dereferencecl">
	      <title>Dereferencing a parameter passed to a function</title>
	      <programlisting>&dereferencecl;</programlisting>
	    </example>

	    <example id="refparams">
	      <title>Again, dereferencing a parameter passed to a function</title>
	      <programlisting>&refparams;</programlisting>
	    </example>


      <variablelist id="exitreturn">
        <title><anchor id="exitreturn1">Exit and Return</title>

	<varlistentry>
	  <term><command>exit status</command></term>
	  <listitem>
	    <para>Functions return a value, called an <firstterm>exit
	      status</firstterm>. The exit status may be explicitly
	      specified by a <command>return</command> statement,
	      otherwise it is the exit status of the last command
	      in the function (<returnvalue>0</returnvalue> if
	      successful, and a non-zero error code if not). This
	      <link linkend="exitstatusref">exit status</link>
	      may be used in the script by referencing it as
	      <link linkend="xstatvarref">$?</link>.  This mechanism
	      effectively permits script functions to have a <quote>return
	      value</quote> similar to C functions.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><command>return</command></term>
	  <indexterm>
	    <primary>return</primary>
	  </indexterm>
	  <indexterm>
	    <primary>command</primary>
	    <secondary>return</secondary>
	  </indexterm>
	  <listitem>
            <para><anchor id="returnref"></para>
	    <para>Terminates a function. A <command>return</command> command
	       <footnote><para>The <command>return</command> command is a
		 Bash <link linkend="builtinref">builtin</link>.</para></footnote>
	      optionally takes an <firstterm>integer</firstterm>
	      argument, which is returned to the calling script as
	      the <quote>exit status</quote> of the function, and
	      this exit status is assigned to the variable <link
	      linkend="xstatvarref">$?</link>.</para>

	    <example id="max">
	      <title>Maximum of two numbers</title>
	      <programlisting>&max;</programlisting>
	    </example>

	    <tip>
	    <para>For a function to return a string or array, use a
	      dedicated variable.
	        <programlisting>count_lines_in_etc_passwd()
{
  [[ -r /etc/passwd ]] && REPLY=$(echo $(wc -l < /etc/passwd))
  #  If /etc/passwd is readable, set REPLY to line count.
  #  Returns both a parameter value and status information.
  #  The 'echo' seems unnecessary, but . . .
  #+ it removes excess whitespace from the output.
}

if count_lines_in_etc_passwd
then
  echo "There are $REPLY lines in /etc/passwd."
else
  echo "Cannot count lines in /etc/passwd."
fi  

# Thanks, S.C.</programlisting>
	    </para>
	    </tip>




	    <example id="ex61">
	      <title>Converting numbers to Roman numerals</title>
	      <programlisting>&ex61;</programlisting>
	    </example>

	    <para>See also <xref linkend="isalpha">.</para>

	    <important>

	    <para>The largest positive integer a function can return is
	      255. The <command>return</command> command is closely tied
	      to the concept of <link linkend="exitstatusref">exit
	      status</link>, which accounts for this particular
	      limitation.  Fortunately, there are various <link
	      linkend="rvt">workarounds</link> for those situations
	      requiring a large integer return value from a
	      function.</para>


	    <example id="returntest">
	      <title>Testing large return values in a function</title>
	      <programlisting>&returntest;</programlisting>
	    </example>


	    <para>A workaround for obtaining large integer <quote>return
	      values</quote> is to simply assign the <quote>return
	      value</quote> to a global variable.

	        <programlisting>Return_Val=   # Global variable to hold oversize return value of function.

alt_return_test ()
{
  fvar=$1
  Return_Val=$fvar
  return   # Returns 0 (success).
}

alt_return_test 1
echo $?                              # 0
echo "return value = $Return_Val"    # 1

alt_return_test 256
echo "return value = $Return_Val"    # 256

alt_return_test 257
echo "return value = $Return_Val"    # 257

alt_return_test 25701
echo "return value = $Return_Val"    #25701</programlisting>
            </para>


	    <para><anchor id="captureretval"></para>
	    <para>A more elegant method is to have the function
              <command>echo</command> its <quote>return
              value to <filename>stdout</filename>,</quote> and
              then capture it by <link linkend="commandsubref">command
	      substitution</link>. See the <link linkend="rvt">discussion
	      of this</link> in <xref linkend="assortedtips">.</para>

	    <example id="max2">
	      <title>Comparing two large integers</title>
	      <programlisting>&max2;</programlisting>
	    </example>

            <para>Here is another example of capturing a function
	      <quote>return value.</quote> Understanding it requires some
	      knowledge of <link linkend="awkref">awk</link>.

	    <programlisting>month_length ()  # Takes month number as an argument.
{                # Returns number of days in month.
monthD="31 28 31 30 31 30 31 31 30 31 30 31"  # Declare as local?
echo "$monthD" | awk '{ print $'"${1}"' }'    # Tricky.
#                             ^^^^^^^^^
# Parameter passed to function  ($1 -- month number), then to awk.
# Awk sees this as "print $1 . . . print $12" (depending on month number)
# Template for passing a parameter to embedded awk script:
#                                 $'"${script_parameter}"'

#  Needs error checking for correct parameter range (1-12)
#+ and for February in leap year.
}

# ----------------------------------------------
# Usage example:
month=4        # April, for example (4th month).
days_in=$(month_length $month)
echo $days_in  # 30
# ----------------------------------------------</programlisting></para>


	    <para>See also <xref linkend="daysbetween">
	      and <xref linkend="stddev">.</para>

	    <para><userinput>Exercise:</userinput> Using what we have
	      just learned, extend the previous <link
	      linkend="ex61">Roman numerals example</link> to accept
	      arbitrarily large input.</para>

	    </important>

	  </listitem>
	</varlistentry>
      </variablelist>


      <variablelist id="redstdinfunc">
        <title><anchor id="redstdinfunc1">Redirection</title>

	<varlistentry>
	  <term><replaceable>Redirecting the stdin
	    of a function</replaceable></term>
	  <indexterm>
	    <primary>redirection</primary>
	    <secondary>stdin</secondary>
	  </indexterm>
	  <listitem>

	    <para>A function is essentially a <link
	      linkend="codeblockref">code block</link>, which means its
	      <filename>stdin</filename> can be redirected (as in <xref
	      linkend="ex8">).</para>

	    <example id="realname">
	      <title>Real name from username</title>
	      <programlisting>&realname;</programlisting>
	    </example>

	   <para>There is an alternate, and perhaps less confusing
	     method of redirecting a function's
	     <filename>stdin</filename>.  This involves redirecting the
	     <filename>stdin</filename> to an embedded bracketed code
	     block within the function.

	       <programlisting># Instead of:
Function ()
{
 ...
 } < file

# Try this:
Function ()
{
  {
    ...
   } < file
}

# Similarly,

Function ()  # This works.
{
  {
   echo $*
  } | tr a b
}

Function ()  # This doesn't work.
{
  echo $*
} | tr a b   # A nested code block is mandatory here.


# Thanks, S.C.</programlisting>
           </para>

	  </listitem>
	</varlistentry>

      </variablelist>

      </sect1> <!-- Complex Functions and Function Complexities -->



      <sect1 id="localvar">
        <title>Local Variables</title>

      <variablelist id="localref">
        <title><anchor id="localref1">What makes a variable
        <firstterm>local</firstterm>?</title>

	<varlistentry>
	  <term>local variables</term>
	  <indexterm>
	    <primary>variable</primary>
	    <secondary>local</secondary>
	  </indexterm>
	  <listitem>
	    <para>A variable declared as <firstterm>local</firstterm>
	      is one that is visible only within the <link
	      linkend="codeblockref">block of code</link> in which it
	      appears. It has local <link linkend="scoperef">scope</link>.
	      In a function, a <firstterm>local variable</firstterm> has
	      meaning only within that function block.</para>

	    <example id="ex62">
	      <title>Local variable visibility</title>
	      <programlisting>&ex62;</programlisting>
	    </example>

	    <caution>
	    <para>Before a function is called, <emphasis>all</emphasis>
	      variables declared within the function are invisible outside
	      the body of the function, not just those explicitly declared
	      as <firstterm>local</firstterm>.
	        <programlisting>#!/bin/bash

func ()
{
global_var=37    #  Visible only within the function block
                 #+ before the function has been called. 
}                #  END OF FUNCTION

echo "global_var = $global_var"  # global_var =
                                 #  Function "func" has not yet been called,
                                 #+ so $global_var is not visible here.

func
echo "global_var = $global_var"  # global_var = 37
                                 # Has been set by function call.</programlisting>
            </para>
	    </caution>

	  </listitem>
	</varlistentry>

      </variablelist>

      <sect2 id="locvarrecur">
        <title>Local variables and recursion.</title>

	      <para><anchor id="recursionref0"></para>

	      <sidebar>

	      <para><anchor id="recursionref"></para>
	      <para><firstterm>Recursion</firstterm> is an interesting
		and sometimes useful form of
		<firstterm>self-reference</firstterm>.	<link
		linkend="mayerref">Herbert Mayer</link> defines it
		as <quote>. . . expressing an algorithm by using a
		simpler version of that same algorithm . . .</quote></para>

             <para>Consider a definition defined in terms of itself,
		  <footnote><para>Otherwise known as
		  <firstterm>redundancy</firstterm>.</para></footnote>
		an expression implicit in its own expression,
		  <footnote><para>Otherwise known as
		  <firstterm>tautology</firstterm>.</para></footnote>
		<emphasis>a snake swallowing its own
		tail</emphasis>,
		  <footnote><para>Otherwise known as a
		  <firstterm>metaphor</firstterm>.</para></footnote>
		or . . . a function that calls itself.
		  <footnote><para>Otherwise known as a
		  <firstterm>recursive function</firstterm>.</para></footnote>
		</para>


	      <para><anchor id="recursiondemo0"></para>
	      <example id="recursiondemo">
	      <title>Demonstration of a simple recursive function</title>
	      <programlisting>&recursiondemo;</programlisting>
	    </example>

	      <para><anchor id="recursiondemo02"></para>
	      <example id="recursiondemo2">
	      <title>Another simple demonstration</title>
	      <programlisting>&recursiondemo2;</programlisting>
	    </example>

		</sidebar>

	    <para>Local variables are a useful tool for writing recursive
	      code, but this practice generally involves a great deal of
	      computational overhead and is definitely
	      <emphasis>not</emphasis> recommended in a shell script.

	         <footnote><para>Too many levels of recursion may crash a
		   script with a segfault.
		   <programlisting>#!/bin/bash

#  Warning: Running this script could possibly lock up your system!
#  If you're lucky, it will segfault before using up all available memory.

recursive_function ()		   
{
echo "$1"     # Makes the function do something, and hastens the segfault.
(( $1 < $2 )) && recursive_function $(( $1 + 1 )) $2;
#  As long as 1st parameter is less than 2nd,
#+ increment 1st and recurse.
}

recursive_function 1 50000  # Recurse 50,000 levels!
#  Most likely segfaults (depending on stack size, set by ulimit -m).

#  Recursion this deep might cause even a C program to segfault,
#+ by using up all the memory allotted to the stack.


echo "This will probably not print."
exit 0  # This script will not exit normally.

#  Thanks, St&eacute;phane Chazelas.</programlisting>
</para></footnote>
	      
	      </para>

	    <para><anchor id="factorialref"></para>
	    <example id="ex63">
	      <title>Recursion, using a local variable</title>
	      <programlisting>&ex63;</programlisting>
	    </example>

	    <para>Also see <xref linkend="primes"> for an example of
	      recursion in a script. Be aware that recursion is
	      resource-intensive and executes slowly, and is therefore
	      generally not appropriate in a script.</para>

      </sect2>
      </sect1> <!-- Local Variables -->



      <sect1 id="recurnolocvar">
        <title>Recursion Without Local Variables</title>

            <para>A function may recursively call itself even without use of
	      local variables.</para>

            <para><anchor id="fiboref"></para>
	    <example id="fibo">
	      <title><firstterm>The Fibonacci Sequence</firstterm></title>
	      <programlisting>&fibo;</programlisting>
	    </example>

            <para><anchor id="hanoiref"></para>
	    <example id="hanoi">
	      <title><firstterm>The Towers of Hanoi</firstterm></title>
	      <programlisting>&hanoi;</programlisting>
	    </example>

      </sect1> <!-- Recursion Without Local Variables -->



  </chapter> <!-- Functions -->



  <chapter id="aliases">
    <title>Aliases</title>

      <para><anchor id="aliasref"></para>

      <indexterm>
        <primary>alias</primary>
      </indexterm>

      <para>A Bash <firstterm>alias</firstterm> is essentially nothing
	more than a keyboard shortcut, an abbreviation, a means of
	avoiding typing a long command sequence. If, for example,
	we include <command>alias lm="ls -l | more"</command> in
	the <link linkend="filesref1"><filename>~/.bashrc</filename>
	file</link>, then each <userinput>lm</userinput> typed at the
	command line will automatically be replaced by a <command>ls -l
	| more</command>. This can save a great deal of typing at the
	command line and avoid having to remember complex combinations of
	commands and options. Setting <command>alias rm="rm -i"</command>
	(interactive mode delete) may save a good deal of grief, since
	it can prevent inadvertently losing important files.</para>

      <para>In a script, aliases have very limited usefulness. It would be
	quite nice if aliases could assume some of the functionality of
	the C preprocessor, such as macro expansion, but unfortunately
	Bash does not expand arguments within the alias body.
	  <footnote><para>However, aliases do seem to expand positional
	  parameters.</para></footnote>
	Moreover, a script fails to expand an alias itself
	within <quote>compound constructs,</quote> such as <link
	linkend="ifthen">if/then</link> statements, loops, and
	functions. An added limitation is that an alias will not expand
	recursively. Almost invariably, whatever we would like an alias
	to do could be accomplished much more effectively with a <link
	linkend="functionref">function</link>.</para>

    <example id="al">
      <title>Aliases within a script</title>
      <programlisting>&al;</programlisting>
    </example>

    <para><anchor id="unaliasref"></para>
    <para>The <command>unalias</command> command removes a previously
      set <firstterm>alias</firstterm>.</para>

    <example id="unal">
      <title><firstterm>unalias</firstterm>: Setting and unsetting
      an alias</title>
      <programlisting>&unal;</programlisting>
    </example>

	    <screen><prompt>bash$ </prompt><userinput>./unalias.sh</userinput>
<computeroutput>
total 6
drwxrwxr-x    2 bozo     bozo         3072 Feb  6 14:04 .
drwxr-xr-x   40 bozo     bozo         2048 Feb  6 14:04 ..
-rwxr-xr-x    1 bozo     bozo          199 Feb  6 14:04 unalias.sh

./unalias.sh: llm: command not found
</computeroutput></screen>


  </chapter> <!-- Aliases -->




  <chapter id="list-cons">
    <title>List Constructs</title>

    <para><anchor id="listconsref"></para>


      <indexterm>
	<primary>&&</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>&&</secondary>
      </indexterm>
      <indexterm>
	<primary>AND</primary>
	<secondary>list</secondary>
      </indexterm>
      <indexterm>
	<primary>||</primary>
      </indexterm>
      <indexterm>
	<primary>special character</primary>
	<secondary>||</secondary>
      </indexterm>
      <indexterm>
	<primary>OR</primary>
	<secondary>list</secondary>
      </indexterm>

      <para>The <firstterm>and list</firstterm> and <firstterm>or
	list</firstterm> constructs provide a means of processing a
	number of commands consecutively. These can effectively replace
	complex nested <link linkend="testconstructs1">if/then</link>
	or even <link linkend="caseesac1">case</link> statements.</para>


      <variablelist id="lcons">
        <title><anchor id="lcons1">Chaining together commands</title>

	<varlistentry>
	  <term>and list</term>
	  <listitem>
	    <para><programlisting>command-1 && command-2 && command-3 && ... command-n</programlisting>
	      Each command executes in turn, provided that
	      the previous command has given a return value of
	      <replaceable>true</replaceable> (zero). At the first
	      <replaceable>false</replaceable> (non-zero) return, the
	      command chain terminates (the first command returning
	      <replaceable>false</replaceable> is the last one to
	      execute).</para>



	    <example id="ex64">
	      <title>Using an <firstterm>and list</firstterm> to test
	      for command-line arguments</title>
	      <programlisting>&ex64;</programlisting>
	    </example>

	    <example id="andlist2">
	      <title>Another command-line arg test using an <firstterm>and
	      list</firstterm></title>
	      <programlisting>&andlist2;</programlisting>
	    </example>

            <para><anchor id="anddefault"></para>
            <para>
	      Of course, an <firstterm>and list</firstterm> can also
	      <firstterm>set</firstterm> variables to a default value.
	        <programlisting>arg1=$@ && [ -z "$arg1" ] && arg1=DEFAULT
		
              # Set $arg1 to command line arguments, if any.
              # But . . . set to DEFAULT if not specified on command line.</programlisting>
            </para>

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="orlistref">or list</term>
	  <listitem>
	    <para><programlisting>command-1 || command-2 || command-3 || ... command-n</programlisting>
	      Each command executes in turn for as long as the previous
	      command returns <returnvalue>false</returnvalue>. At
	      the first <returnvalue>true</returnvalue> return, the
	      command chain terminates (the first command returning
	      <returnvalue>true</returnvalue> is the last one to
	      execute). This is obviously the inverse of the <quote>and
	      list</quote>.</para>

	    <example id="ex65">
	      <title>Using <firstterm>or lists</firstterm> in combination
	      with an <firstterm>and list</firstterm></title>
	      <programlisting>&ex65;</programlisting>
	    </example>

	    <caution><para>If the first command in an <firstterm>or
	      list</firstterm> returns <returnvalue>true</returnvalue>,
	      it <replaceable>will</replaceable> execute.</para></caution>

	  </listitem>
	</varlistentry>

	</variablelist>


	    <para><programlisting># ==> The following snippets from the /etc/rc.d/init.d/single
#+==> script by Miquel van Smoorenburg
#+==> illustrate use of "and" and "or" lists.
# ==> "Arrowed" comments added by document author.

[ -x /usr/bin/clear ] && /usr/bin/clear
  # ==> If /usr/bin/clear exists, then invoke it.
  # ==> Checking for the existence of a command before calling it
  #+==> avoids error messages and other awkward consequences.

  # ==> . . .

# If they want to run something in single user mode, might as well run it...
for i in /etc/rc1.d/S[0-9][0-9]* ; do
        # Check if the script is there.
        [ -x "$i" ] || continue
  # ==> If corresponding file in $PWD *not* found,
  #+==> then "continue" by jumping to the top of the loop.

        # Reject backup files and files generated by rpm.
        case "$1" in
                *.rpmsave|*.rpmorig|*.rpmnew|*~|*.orig)
                        continue;;
        esac
        [ "$i" = "/etc/rc1.d/S00single" ] && continue
  # ==> Set script name, but don't execute it yet.
        $i start
done

  # ==> . . .</programlisting></para>


	<important><para>The <link linkend="exitstatusref">exit
	  status</link> of an <userinput>and list</userinput> or an
	  <userinput>or list</userinput> is the exit status of the last
	  command executed.</para></important>

	<para>Clever combinations of <firstterm>and</firstterm> and
	<firstterm>or</firstterm> lists are possible, but the logic may
	easily become convoluted and require close attention to <link
	linkend="opprecedence1">operator precedence rules</link>, and
	possibly extensive debugging.</para>

	<para><programlisting>false && true || echo false         # false

# Same result as
( false && true ) || echo false     # false
# But NOT
false && ( true || echo false )     # (nothing echoed)

#  Note left-to-right grouping and evaluation of statements,
#+ since the logic operators "&&" and "||" have equal precedence.

#  It's usually best to avoid such complexities.

#  Thanks, S.C.</programlisting>
	</para>

	<para>See <xref linkend="daysbetween"> and <xref
	linkend="brokenlink"> for illustrations of using <userinput>and
	/ or list</userinput> constructs to test variables.</para>


  </chapter> <!-- List Constructs -->




  <chapter id="arrays">
    <title>Arrays</title>

      <para><anchor id="arrayref"></para>

      <para>Newer versions of Bash support one-dimensional arrays.
        <anchor id="brackarray">
	Array elements may be initialized with the
	<userinput>variable[xx]</userinput> notation. Alternatively,
	a script may introduce the entire array by an explicit
	<userinput>declare -a variable</userinput> statement. To
	dereference (retrieve the contents of) an array element, use
	<firstterm>curly bracket</firstterm> notation, that is,
	<userinput>${element[xx]}</userinput>.</para>

      <para><anchor id="arraynotation"></para>

      <example id="ex66">
	<title>Simple array usage</title>
	<programlisting>&ex66;</programlisting>
      </example>

      <para><anchor id="arrayinit0"></para>
      <para>As we have seen, a convenient way of initializing an entire array
        is the <varname>array=( element1 element2 ... elementN )</varname>
	notation.</para>

      <para><anchor id="arrayopsvars"></para>

      <sidebar><para>Bash permits array operations on variables, even if
        the variables are not explicitly declared as arrays.</para>
	  <para><programlisting>string=abcABC123ABCabc
echo ${string[@]}               # abcABC123ABCabc
echo ${string[*]}               # abcABC123ABCabc 
echo ${string[0]}               # abcABC123ABCabc
echo ${string[1]}               # No output!
                                # Why?
echo ${#string[@]}              # 1
                                # One element in the array.
                                # The string itself.

# Thank you, Michael Zick, for pointing this out.</programlisting>
      Once again this demonstrates that <link linkend="bvuntyped">Bash
      variables are untyped</link>.
      </para></sidebar>


      <example id="poem">
	<title>Formatting a poem</title>
	<programlisting>&poem;</programlisting>
      </example>

      <para><anchor id="arraysyntax"></para>
      <para>Array variables have a syntax all their own, and even
	standard Bash commands and operators have special options adapted
	for array use.</para>

      <example id="arrayops">
	<title>Various array operations</title>
	<programlisting>&arrayops;</programlisting>
      </example>

      <para><anchor id="arraystringops"></para>
      <para>Many of the standard <link linkend="stringmanip">string
       operations</link> work on arrays.</para>

      <example id="arraystrops">
	<title>String operations on arrays</title>
	<programlisting>&arraystrops;</programlisting>
      </example>


      <para><link linkend="commandsubref">Command substitution</link> can
        construct the individual elements of an array.</para>
      
      <example id="scriptarray">
	<title>Loading the contents of a script into an array</title>
	<programlisting>&scriptarray;</programlisting>
      </example>

      <para>In an array context, some Bash <link
	linkend="builtinref">builtins</link> have a slightly
	altered meaning. <anchor id="arrayunset">For example, <link
	linkend="unsetref">unset</link> deletes array elements, or even
	an entire array.</para>

      <para><anchor id="arrayspecialprops"></para>
      <example id="ex67">
	<title>Some special properties of arrays</title>
	<programlisting>&ex67;</programlisting>
      </example>

      <para><anchor id="arraynumelements"></para>
      <para>As seen in the previous example, either
	<command>${array_name[@]}</command> or
	<command>${array_name[*]}</command> refers to
	<emphasis>all</emphasis> the elements of the array.
	Similarly, to get a count of the number of elements in an
	array, use either <command>${#array_name[@]}</command>
	or <command>${#array_name[*]}</command>.
	<command>${#array_name}</command> is the length (number of
	characters) of <command>${array_name[0]}</command>, the first
	element of the array.</para>

      <para><anchor id="emptyarray0"></para>
      <example id="emptyarray">
	<title>Of empty arrays and empty elements</title>
	<programlisting>&emptyarray;</programlisting>
      </example>

      <para>The relationship of <command>${array_name[@]}</command>
	and <command>${array_name[*]}</command> is analogous to that
	between <link linkend="appref">$@ and $*</link>. This powerful
	array notation has a number of uses.</para>

      <para><anchor id="copyarray0"></para>
      <para>
      <programlisting># Copying an array.
array2=( "${array1[@]}" )
# or
array2="${array1[@]}"
#
#  However, this fails with "sparse" arrays,
#+ arrays with holes (missing elements) in them,
#+ as Jochen DeSmet points out.
# ------------------------------------------
  array1[0]=0
# array1[1] not assigned
  array1[2]=2
  array2=( "${array1[@]}" )       # Copy it?

echo ${array2[0]}      # 0
echo ${array2[2]}      # (null), should be 2
# ------------------------------------------



# Adding an element to an array.
array=( "${array[@]}" "new element" )
# or
array[${#array[*]}]="new element"

# Thanks, S.C.</programlisting>
      </para>


      <para><anchor id="arrayinitcs"></para>
      <tip>
      <para>The <command>array=( element1 element2 ... elementN )</command>
	initialization operation, with the help of <link
	linkend="commandsubref">command substitution</link>, makes it
	possible to load the contents of a text file into an array.</para>

      <para>  	
      <programlisting>#!/bin/bash

filename=sample_file

#            cat sample_file
#
#            1 a b c
#            2 d e fg


declare -a array1

array1=( `cat "$filename"`)                #  Loads contents
#         List file to stdout              #+ of $filename into array1.
#
#  array1=( `cat "$filename" | tr '\n' ' '`)
#                            change linefeeds in file to spaces. 
#  Not necessary because Bash does word splitting,
#+ changing linefeeds to spaces.

echo ${array1[@]}            # List the array.
#                              1 a b c 2 d e fg
#
#  Each whitespace-separated "word" in the file
#+ has been assigned to an element of the array.

element_count=${#array1[*]}
echo $element_count          # 8</programlisting>
      </para>  	
      </tip>
      
      <para>Clever scripting makes it possible to add array operations.</para>

      <para><anchor id="arrayassign0"></para>
      <example id="arrayassign">
        <title>Initializing arrays</title>
	<programlisting>&arrayassign;</programlisting>
      </example>

      <note><para>Adding a superfluous <command>declare -a</command>
	statement to an array declaration may speed up execution of
	subsequent operations on the array.</para></note>

      <para><anchor id="arrayappend0"></para>
      <example id="copyarray">
        <title>Copying and concatenating arrays</title>
	<programlisting>&copyarray;</programlisting>
      </example>

      <example id="arrayappend">
        <title>More on concatenating arrays</title>
	<programlisting>&arrayappend;</programlisting>
      </example>


      <para>--</para>

      <para>Arrays permit deploying old familiar algorithms as shell scripts.
        Whether this is necessarily a good idea is left to the reader to
	decide.</para>

      <para><anchor id="bubblesort"></para>

      <example id="bubble">
	<title>The Bubble Sort</title>
	<programlisting>&bubble;</programlisting>
      </example>
      
      <para>--</para>

      <para><anchor id="arraynest"></para>
      <para>Is it possible to nest arrays within arrays?</para>
      <para><programlisting>#!/bin/bash
# "Nested" array.

#  Michael Zick provided this example,
#+ with corrections and clarifications by William Park.

AnArray=( $(ls --inode --ignore-backups --almost-all \
	--directory --full-time --color=none --time=status \
	--sort=time -l ${PWD} ) )  # Commands and options.

# Spaces are significant . . . and don't quote anything in the above.

SubArray=( ${AnArray[@]:11:1}  ${AnArray[@]:6:5} )
#  This array has six elements:
#+     SubArray=( [0]=${AnArray[11]} [1]=${AnArray[6]} [2]=${AnArray[7]}
#      [3]=${AnArray[8]} [4]=${AnArray[9]} [5]=${AnArray[10]} )
#
#  Arrays in Bash are (circularly) linked lists
#+ of type string (char *).
#  So, this isn't actually a nested array,
#+ but it's functionally similar.

echo "Current directory and date of last status change:"
echo "${SubArray[@]}"

exit 0</programlisting></para>

      <para>--</para>

      <para>Embedded arrays in combination with <link
        linkend="varrefnew">indirect references</link> create some fascinating
	possibilities</para>

      <para><anchor id="arrayindir"></para>
      <example id="embarr">
	<title>Embedded arrays and indirect references</title>
	<programlisting>&embarr;</programlisting>
      </example>
      
      <para>--</para>

      <para><anchor id="primes0"></para>
      <para>Arrays enable implementing a shell script version of the
	<firstterm>Sieve of Eratosthenes</firstterm>. Of course, a
	resource-intensive application of this nature should really be
	written in a compiled language, such as C. It runs excruciatingly
	slowly as a script.</para>

      <example id="ex68">
	<title>The Sieve of Eratosthenes</title>
	<programlisting>&ex68;</programlisting>
      </example>

      <example id="ex68a">
	<title>The Sieve of Eratosthenes, Optimized</title>
	<programlisting>&ex68a;</programlisting>
      </example>

      <para>Compare these array-based prime number generators with
        alternatives that do not use arrays, <xref linkend="primes">,
        and <xref linkend="primes2">.</para>

      <para>--</para>

      <para>Arrays lend themselves, to some extent, to emulating data
        structures for which Bash has no native support.</para>

	    <para><anchor id="stackex0"></para>
	    <example id="stackex">
	      <title>Emulating a push-down stack</title>
	      <programlisting>&stackex;</programlisting>
	    </example>

      <para>--</para>

      <para>Fancy manipulation of array <quote>subscripts</quote> may require
        intermediate variables. For projects involving this, again consider
	using a more powerful programming language, such as Perl or C.</para>

      <example id="qfunction">
	<title>Complex array application:
             <emphasis>Exploring a weird mathematical series</emphasis></title>
	<programlisting>&qfunction;</programlisting>
      </example>

      <para>--</para>

      <para><anchor id="arraymultidim"></para>
      <para>Bash supports only one-dimensional arrays, though a little
        trickery permits simulating multi-dimensional ones.</para>

      <example id="twodim">
	<title>Simulating a two-dimensional array, then tilting it</title>
	<programlisting>&twodim;</programlisting>
      </example>

      <para>A two-dimensional array is essentially equivalent to a
	one-dimensional one, but with additional addressing modes
	for referencing and manipulating the individual elements by
	<firstterm>row</firstterm> and <firstterm>column</firstterm>
	position.</para>

      <para>For an even more elaborate example of simulating a
        two-dimensional array, see <xref linkend="lifeslow">.</para>

     <para>--</para>

     <para>For more interesting scripts using arrays, see:
       <itemizedlist>
	 <listitem><para><xref linkend="agram2"></para></listitem>
	 <listitem><para><xref linkend="primes2"></para></listitem>
	 <listitem><para><xref linkend="hashex2"></para></listitem>
         <listitem><para><xref linkend="homework"></para></listitem>
         <listitem><para><xref linkend="qky"></para></listitem>
         <listitem><para><xref linkend="nim"></para></listitem>
       </itemizedlist>
     </para>

  </chapter> <!-- Arrays -->


  <chapter id="devproc">
    <title><filename class="directory">/dev</filename> and <filename
    class="directory">/proc</filename></title>

      <para><anchor id="devprocref"></para>

      <para>A Linux or UNIX filesystem typically has the
      <filename class="directory">/dev</filename> and
	<filename class="directory">/proc</filename> special-purpose
	directories.</para>



      <sect1 id="devref1">
	<title><filename class="directory">/dev</filename></title>

      <para>The <filename class="directory">/dev</filename> directory
	contains entries for the <firstterm>physical devices</firstterm>
	that may or may not be present in the hardware.
	   <footnote>
	   <para>The entries in <filename class="directory">/dev</filename>
	     provide mount points for physical and virtual devices. These
	     entries use very little drive space.</para>
	 <para>Some devices, such as <filename>/dev/null</filename>,
	   <filename>/dev/zero</filename>,
	   and <filename>/dev/urandom</filename> are virtual. They
	   are not actual physical devices and exist only in
	   software.</para>
	   </footnote>
	For example, the hard drive partitions containing
	the mounted filesystem(s) have entries in <filename
	class="directory">/dev</filename>, as <link
	linkend="dfref">df</link> shows.</para>

	 <para><screen><prompt>bash$ </prompt><userinput>df</userinput>
<computeroutput>Filesystem           1k-blocks      Used Available Use%
 Mounted on
 /dev/hda6               495876    222748    247527  48% /
 /dev/hda1                50755      3887     44248   9% /boot
 /dev/hda8               367013     13262    334803   4% /home
 /dev/hda5              1714416   1123624    503704  70% /usr</computeroutput>
	      </screen>
        </para>	     

      <para><anchor id="loopbackref">Among other things, the <filename
        class="directory">/dev</filename> directory
	contains <firstterm>loopback</firstterm> devices, such as
	<filename>/dev/loop0</filename>. A loopback device is a gimmick
	that allows an ordinary file to be accessed as if it were a
	block device.

	  <footnote><para><anchor id="blockdevref">A <firstterm>block
	    device</firstterm> reads and/or writes data in chunks,
	    or <firstterm>blocks</firstterm>, in contrast to a <anchor
	    id="chardevref"><firstterm>character device</firstterm>,
	    which acesses data in <firstterm>character</firstterm>
	    units. Examples of block devices are hard drives, CDROM
	    drives, and flash drives. Examples of character devices are
	    keyboards, modems, sound cards.</para></footnote>

	This permits mounting an entire filesystem within a
	single large file. See <xref linkend="createfs"> and <xref
	linkend="isomountref">.</para>

       <para>A few of the pseudo-devices in <filename
	 class="directory">/dev</filename>
	 have other specialized uses, such as <link
	 linkend="zerosref"><filename>/dev/null</filename></link>, <link
	 linkend="zerosref1"><filename>/dev/zero</filename></link>, <link
	 linkend="urandomref"><filename>/dev/urandom</filename></link>,
	 <filename>/dev/sda1</filename> (hard drive partition),
	 <filename>/dev/udp</filename> (<firstterm>User
	 Datagram Packet</firstterm> port), and <link
	 linkend="devtcp"><filename>/dev/tcp</filename></link>.</para>

       <para>For instance:</para>

       <para>To manually <link linkend="mountref">mount</link>
         a USB flash drive, append the following line to
         <filename>/etc/fstab</filename>.

	      <footnote>
	      <para>Of course, the mount point
	        <filename>/mnt/flashdrive</filename> must exist. If not,
		then, as <firstterm>root</firstterm>, <command>mkdir
		/mnt/flashdrive</command>.</para>
	     <para>To actually mount the drive, use the following command:
	       <command>mount /mnt/flashdrive</command></para>
	     <para>Newer Linux distros automount flash drives in the
	       <filename class="directory">/media</filename>
	       directory without user intervention.</para>
	      </footnote>

	   <programlisting>/dev/sda1    /mnt/flashdrive    auto    noauto,user,noatime    0 0</programlisting>

         (See also <xref linkend="usbinst">.)</para>

       <para>Checking whether a disk is in the CD-burner
         (soft-linked to <filename>/dev/hdc</filename>):

	 <programlisting>head -1 /dev/hdc


#  head: cannot open '/dev/hdc' for reading: No medium found
#  (No disc in the drive.)

#  head: error reading '/dev/hdc': Input/output error
#  (There is a disk in the drive, but it can't be read;
#+  possibly it's an unrecorded CDR blank.)   

#  Stream of characters and assorted gibberish
#  (There is a pre-recorded disk in the drive,
#+ and this is raw output -- a stream of ASCII and binary data.)
#  Here we see the wisdom of using 'head' to limit the output
#+ to manageable proportions, rather than 'cat' or something similar.


#  Now, it's just a matter of checking/parsing the output and taking
#+ appropriate action.</programlisting></para>


       <para><anchor id="socketref"></para>

       <para>When executing a command on a
         <filename>/dev/tcp/$host/$port</filename> pseudo-device file, Bash
	 opens a TCP connection to the associated
	 <firstterm>socket</firstterm>.</para>


	    <sidebar><para>A <firstterm>socket</firstterm> is a
	      communications node associated with a specific I/O
	      port. (This is analogous to a <firstterm>hardware
	      socket</firstterm>, or <firstterm>receptacle</firstterm>,
	      for a connecting cable.) It permits data transfer between
	      hardware devices on the same machine, between machines
	      on the same network, between machines across different
	      networks, and, of course, between machines at different
	      locations on the Internet.</para></sidebar>


       <para>The following examples assume an active Internet
         connection.</para>

       <para>Getting the time from <filename>nist.gov</filename>:</para>
	      <screen><prompt>bash$ </prompt><userinput>cat &lt;/dev/tcp/time.nist.gov/13</userinput>
<computeroutput>53082 04-03-18 04:26:54 68 0 0 502.3 UTC(NIST) *</computeroutput>
	      </screen>

       <para>[Mark contributed the above example.]</para>

       <para>Downloading a URL:</para>
	      <screen><prompt>bash$ </prompt><userinput>exec 5&lt;&gt;/dev/tcp/www.net.cn/80</userinput>
<prompt>bash$ </prompt><userinput>echo -e "GET / HTTP/1.0\n" >&5</userinput>
<prompt>bash$ </prompt><userinput>cat &lt;&5</userinput>
	      </screen>

       <para>[Thanks, Mark and Mihai Maties.]</para>




	    <example id="devtcp">
	      <title>Using <filename>/dev/tcp</filename> for
	      troubleshooting</title>
	      <programlisting>&devtcp;</programlisting>
	    </example>

	    <example id="musicscr">
	      <title>Playing music</title>
	      <programlisting>&musicscr;</programlisting>
	    </example>


      </sect1> <!-- /dev -->



      <sect1 id="procref1">
        <title><filename class="directory">/proc</filename></title>


      <para><anchor id="procref2"></para>
      <para>The <filename class="directory">/proc</filename> directory
	is actually a pseudo-filesystem.  The files in <filename
	class="directory">/proc</filename> mirror currently running
	system and kernel <link linkend="processref">processes</link>
	and contain information and statistics about them.</para>

       <para>
         <screen><prompt>bash$ </prompt><userinput>cat /proc/devices</userinput>
<computeroutput>Character devices:
   1 mem
   2 pty
   3 ttyp
   4 ttyS
   5 cua
   7 vcs
  10 misc
  14 sound
  29 fb
  36 netlink
 128 ptm
 136 pts
 162 raw
 254 pcmcia

 Block devices:
   1 ramdisk
   2 fd
   3 ide0
   9 md</computeroutput>



<prompt>bash$ </prompt><userinput>cat /proc/interrupts</userinput>
<computeroutput>           CPU0       
   0:      84505          XT-PIC  timer
   1:       3375          XT-PIC  keyboard
   2:          0          XT-PIC  cascade
   5:          1          XT-PIC  soundblaster
   8:          1          XT-PIC  rtc
  12:       4231          XT-PIC  PS/2 Mouse
  14:     109373          XT-PIC  ide0
 NMI:          0 
 ERR:          0</computeroutput>


<prompt>bash$ </prompt><userinput>cat /proc/partitions</userinput>
<computeroutput>major minor  #blocks  name     rio rmerge rsect ruse wio wmerge wsect wuse running use aveq

    3     0    3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030
    3     1      52416 hda1 27 395 844 960 4 2 14 180 0 800 1140
    3     2          1 hda2 0 0 0 0 0 0 0 0 0 0 0
    3     4     165280 hda4 10 0 20 210 0 0 0 0 0 210 210
    ...</computeroutput>



<prompt>bash$ </prompt><userinput>cat /proc/loadavg</userinput>
<computeroutput>0.13 0.42 0.27 2/44 1119</computeroutput>



<prompt>bash$ </prompt><userinput>cat /proc/apm</userinput>
<computeroutput>1.16 1.2 0x03 0x01 0xff 0x80 -1% -1 ?</computeroutput>



<prompt>bash$ </prompt><userinput>cat /proc/acpi/battery/BAT0/info</userinput>
<computeroutput>present:                 yes
 design capacity:         43200 mWh
 last full capacity:      36640 mWh
 battery technology:      rechargeable
 design voltage:          10800 mV
 design capacity warning: 1832 mWh
 design capacity low:     200 mWh
 capacity granularity 1:  1 mWh
 capacity granularity 2:  1 mWh
 model number:            IBM-02K6897
 serial number:            1133
 battery type:            LION
 OEM info:                Panasonic</computeroutput>
 
 
 
<prompt>bash$ </prompt><userinput>fgrep Mem /proc/meminfo</userinput>
<computeroutput>MemTotal:       515216 kB
 MemFree:        266248 kB</computeroutput>
         </screen>
      </para>

       <para>Shell scripts may extract data from certain of the files in
         <filename class="directory">/proc</filename>.

	   <footnote><para>Certain system commands, such as
	     <link linkend="procinforef">procinfo</link>,
	     <link linkend="freeref">free</link>,
	     <link linkend="vmstatref">vmstat</link>,
	     <link linkend="lsdevref">lsdev</link>,
	     and <link linkend="uptimeref">uptime</link>
	     do this as well.</para></footnote></para>

	  <para><programlisting>FS=iso                       # ISO filesystem support in kernel?

grep $FS /proc/filesystems   # iso9660</programlisting></para>


       <para><programlisting>kernel_version=$( awk '{ print $3 }' /proc/version )</programlisting></para>

       <para><programlisting>CPU=$( awk '/model name/ {print $5}' < /proc/cpuinfo )

if [ "$CPU" = "Pentium(R)" ]
then
  run_some_commands
  ...
else
  run_other_commands
  ...
fi



cpu_speed=$( fgrep "cpu MHz" /proc/cpuinfo | awk '{print $4}' )
#  Current operating speed (in MHz) of the cpu on your machine.
#  On a laptop this may vary, depending on use of battery
#+ or AC power.</programlisting></para>


       <para><programlisting>#!/bin/bash
# get-commandline.sh
# Get the command-line parameters of a process.

OPTION=cmdline

# Identify PID.
pid=$( echo $(pidof "$1") | awk '{ print $1 }' )
# Get only first            ^^^^^^^^^^^^^^^^^^ of multiple instances.

echo
echo "Process ID of (first instance of) "$1" = $pid"
echo -n "Command-line arguments: "
cat /proc/"$pid"/"$OPTION" | xargs -0 echo
#   Formats output:        ^^^^^^^^^^^^^^^
#   (Thanks, Han Holl, for the fixup!)

echo; echo


# For example:
# sh get-commandline.sh xterm</programlisting></para>

       <para>+</para>

       <para><programlisting>devfile="/proc/bus/usb/devices"
text="Spd"
USB1="Spd=12"
USB2="Spd=480"


bus_speed=$(fgrep -m 1 "$text" $devfile | awk '{print $9}')
#                 ^^^^ Stop after first match.

if [ "$bus_speed" = "$USB1" ]
then
  echo "USB 1.1 port found."
  # Do something appropriate for USB 1.1.
fi</programlisting></para>


	<note>
	<para>It is even possible to control certain peripherals with commands
	  sent to the <filename class="directory">/proc</filename> directory.

          <screen>
	  <prompt>root# </prompt><command>echo on > /proc/acpi/ibm/light</command>
          </screen>

	  This turns on the <emphasis>Thinklight</emphasis> in certain models
	  of IBM/Lenovo Thinkpads. (May not work on all Linux distros.)</para>

        <para>Of course, caution is advised when writing to <filename
	  class="directory">/proc</filename>.</para>

	</note>


	<para><anchor id="procrunning"></para>
	<para>The <filename class="directory">/proc</filename> directory
	   contains subdirectories with unusual numerical
	   names.  Every one of these names maps to the <link
	   linkend="ppidref">process ID</link> of a currently running
	   process.  Within each of these subdirectories, there are
	   a number of files that hold useful information about the
	   corresponding process.  The <filename>stat</filename> and
	   <filename>status</filename> files keep running statistics
	   on the process, the <filename>cmdline</filename> file holds
	   the command-line arguments the process was invoked with, and
	   the <filename>exe</filename> file is a symbolic link to the
	   complete path name of the invoking process. There are a few
	   more such files, but these seem to be the most interesting
	   from a scripting standpoint.</para>

	    <example id="pidid">
	      <title>Finding the process associated with a PID</title>
	      <programlisting>&pidid;</programlisting>
	    </example>

	    <example id="constat">
	      <title>On-line connect status</title>
	      <programlisting>&constat;</programlisting>
	    </example>


       <para><anchor id="procwarning"></para>
       <warning><para>In general, it is dangerous to
	 <emphasis>write</emphasis> to the files in <filename
	 class="directory">/proc</filename>, as this can corrupt the
	 filesystem or crash the machine.</para></warning>

      </sect1> <!-- /proc -->

  </chapter> <!-- /dev and /proc -->

    

  <chapter id="zeros">
    <title>Of Zeros and Nulls</title>

    <epigraph>
      <para>Faultily faultless, icily regular, splendidly null</para>
      <para>Dead perfection; no more.</para>
      <para>--Alfred Lord Tennyson</para>
    </epigraph>

      <para><anchor id="zerosref"></para>

      <variablelist id="zeronull">
        <title><anchor id="zeronull1"><filename>/dev/zero</filename>
          ... <filename>/dev/null</filename></title>
	<varlistentry>
	  <term><anchor id="devnullref">Uses of
	    <filename>/dev/null</filename></term>
	  <listitem>
	    <para>Think of <filename>/dev/null</filename> as a <firstterm>black
		hole</firstterm>. It is essentially the equivalent of
		a write-only file. Everything written to it disappears.
		Attempts to read or output from it result in nothing. All
		the same, <filename>/dev/null</filename> can be quite
		useful from both the command line and in scripts.</para>

	    <para>Suppressing <filename>stdout</filename>.
	      <programlisting>cat $filename >/dev/null
# Contents of the file will not list to stdout.</programlisting>
            </para>

	    <para>Suppressing <filename>stderr</filename>
	      (from <xref linkend="ex57">).
	      <programlisting>rm $badname 2>/dev/null
#           So error messages [stderr] deep-sixed.</programlisting>
	    </para>

	    <para>Suppressing output from <emphasis>both</emphasis>
	      <filename>stdout</filename> and <filename>stderr</filename>.
	      <programlisting>cat $filename 2>/dev/null >/dev/null
# If "$filename" does not exist, there will be no error message output.
# If "$filename" does exist, the contents of the file will not list to stdout.
# Therefore, no output at all will result from the above line of code.
#
#  This can be useful in situations where the return code from a command
#+ needs to be tested, but no output is desired.
#
# cat $filename &>/dev/null
#     also works, as Baris Cicek points out.</programlisting>
	    </para>

	    <para>Deleting contents of a file, but preserving the file itself, with
	      all attendant permissions (from <xref linkend="ex1"> and <xref linkend="ex2">):
	      <programlisting>cat /dev/null > /var/log/messages
#  : > /var/log/messages   has same effect, but does not spawn a new process.

cat /dev/null > /var/log/wtmp</programlisting>
	      </para>

	    <para>Automatically emptying the contents of a logfile
	      (especially good for dealing with those nasty
	      <quote>cookies</quote> sent by commercial Web sites):</para>

	    <example id="cookies">  
	      <title>Hiding the cookie jar</title>
	      <programlisting># Obsolete Netscape browser.
# Same principle applies to newer browsers.

if [ -f ~/.netscape/cookies ]  # Remove, if exists.
then
  rm -f ~/.netscape/cookies
fi

ln -s /dev/null ~/.netscape/cookies
# All cookies now get sent to a black hole, rather than saved to disk.</programlisting>
            </example> 

	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><anchor id="zerosref1">Uses of <filename>/dev/zero</filename></term>
	  <listitem>
	    <para>Like <filename>/dev/null</filename>,
	      <filename>/dev/zero</filename> is a pseudo-device file, but
	      it actually produces a stream of nulls
	      (<emphasis>binary</emphasis> zeros, not the ASCII
	      kind). Output written to <filename>/dev/zero</filename>
	      disappears, and it is fairly difficult to actually read
	      the nulls emitted there, though it can be done with <link
	      linkend="odref">od</link> or a hex editor. <anchor
	      id="swapfileref">The chief use of
	      <filename>/dev/zero</filename> is creating an initialized
	      dummy file of predetermined length intended as a temporary
	      swap file.</para>

	    <example id="ex73">
	      <title>Setting up a swapfile using <filename>/dev/zero</filename></title>
	      <programlisting>&ex73;</programlisting>
	    </example>

	    <para>Another application of <filename>/dev/zero</filename>
	      is to <quote>zero out</quote> a file of a designated
	      size for a special purpose, such as mounting a filesystem
	      on a <link linkend="loopbackref">loopback device</link>
	      (see <xref linkend="createfs">) or <quote>securely</quote>
	      deleting a file (see <xref linkend="blotout">).</para>

	    <example id="ramdisk">
	      <title>Creating a ramdisk</title>
	      <programlisting>&ramdisk;</programlisting>
	    </example>

	    <para>In addition to all the above,
	      <filename>/dev/zero</filename> is needed by ELF
	      (<firstterm>Executable and Linking Format</firstterm>)
	      UNIX/Linux binaries.</para>

	  </listitem>
	</varlistentry>

      </variablelist>

  </chapter> <!-- Zeros and Nulls -->



  <chapter id="debugging">
    <title>Debugging</title>

    <epigraph>
      <para>Debugging is twice as hard as writing the code in the first
        place. Therefore, if you write the code as cleverly as possible,
        you are, by definition, not smart enough to debug it.</para>
      <para>--Brian Kernighan</para>
    </epigraph>

      <para>The Bash shell contains no built-in debugger, and only bare-bones
	debugging-specific commands and constructs. Syntax errors or
	outright typos in the script generate cryptic error messages that
	are often of no help in debugging a non-functional script.</para>

      <example id="ex74">
	<title>A buggy script</title>
	<programlisting>&ex74;</programlisting>
      </example>

      <para>Output from script:
	<screen><computeroutput>./ex74.sh: [37: command not found</computeroutput></screen>
        What's wrong with the above script? Hint: after the
        <firstterm>if</firstterm>.</para>

      <example id="missingkeyword">
	<title>Missing <link linkend="keywordref">keyword</link></title>
	<programlisting>&missingkeyword;</programlisting>
      </example>

      <para>Output from script:
	<screen>
<computeroutput>missing-keyword.sh: line 10: syntax error: unexpected end of file</computeroutput>
	</screen>
	Note that the error message does <emphasis>not</emphasis> necessarily
	reference the line in which the error occurs, but the line where the
	Bash interpreter finally becomes aware of the error.
	</para>

      <para>Error messages may disregard comment lines in a script when
        reporting the line number of a syntax error.</para>

      <para>What if the script executes, but does not work as expected? This is the
	all too familiar logic error.</para>

      <example id="ex75">
	<title><firstterm>test24</firstterm>: another buggy script</title>
	<programlisting>&ex75;</programlisting>
      </example>

      <para>Try to find out what's wrong with <xref linkend="ex75">
	by uncommenting the <userinput>echo "$badname"</userinput> line. Echo
	statements are useful for seeing whether what you expect is
	actually what you get.</para>

      <para>In this particular case, <userinput>rm "$badname"</userinput>
	will not give the desired results because
	<varname>$badname</varname> should not be quoted. Placing it
	in quotes ensures that <command>rm</command> has only one
	argument (it will match only one filename). A partial fix
	is to remove to quotes from <varname>$badname</varname> and
	to reset <varname>$IFS</varname> to contain only a newline,
	<userinput>IFS=$'\n'</userinput>. However, there are simpler
	ways of going about it.
	<programlisting># Correct methods of deleting filenames containing spaces.
rm *\ *
rm *" "*
rm *' '*
# Thank you. S.C.</programlisting>
	
	</para>

      <para>Summarizing the symptoms of a buggy script,
	<orderedlist>
	  <listitem>
	    <para>It bombs with a <quote><errorname>syntax error</errorname></quote> message, or</para>
	  </listitem>
	  <listitem>
	    <para>It runs, but does not work as expected 
	      (<errorname>logic error</errorname>).</para> 
	  </listitem>
	  <listitem>
	    <para>It runs, works as expected, but has nasty side effects
	      (<errorname>logic bomb</errorname>).</para> 
	  </listitem>
	</orderedlist>
      </para>
	
      <para><anchor id="debugtools"></para>
      <para>Tools for debugging non-working scripts include
	<orderedlist>
	  <listitem>

	    <para>Inserting <link linkend="echoref">echo</link>
	      statements at critical points in the script to trace the
	      variables, and otherwise give a snapshot of what is going
	      on.</para>

            <tip>
	    <para>Even better is an <command>echo</command> that echoes
	      only when <firstterm>debug</firstterm> is on.</para>

	    <para><programlisting>### debecho (debug-echo), by Stefano Falsetto ###
### Will echo passed parameters only if DEBUG is set to a value. ###
debecho () {
  if [ ! -z "$DEBUG" ]; then
     echo "$1" >&2
     #         ^^^ to stderr
  fi
}

DEBUG=on
Whatever=whatnot
debecho $Whatever   # whatnot

DEBUG=
Whatever=notwhat
debecho $Whatever   # (Will not echo.)</programlisting></para>

	    </tip>

	  </listitem>
	  <listitem>
	    <para>Using the <link linkend="teeref">tee</link> filter
	      to check processes or data flows at critical points.</para>
	  </listitem>
	  <listitem>
	    <para>Setting option flags <option>-n -v -x</option></para>

	    <para><userinput>sh -n scriptname</userinput> checks for
	      syntax errors without actually running the script. This is
	      the equivalent of inserting <userinput>set -n</userinput> or
	      <userinput>set -o noexec</userinput> into the script. Note
	      that certain types of syntax errors can slip past this
	      check.</para>

	    <para><userinput>sh -v scriptname</userinput> echoes each
	      command before executing it. This is the equivalent of
	      inserting <userinput>set -v</userinput> or <userinput>set
	      -o verbose</userinput> in the script.</para>
	    
	    <para>The <option>-n</option> and <option>-v</option>
	      flags work well together. <userinput>sh -nv
	      scriptname</userinput> gives a verbose syntax check.</para>

	    <para><userinput>sh -x scriptname</userinput> echoes the result each
	      command, but in an abbreviated manner. This is the equivalent of
	      inserting <userinput>set -x</userinput> or 
	      <userinput>set -o xtrace</userinput> in the script.</para>

	    <para><anchor id="undvarerr"></para>
	    <para>Inserting <userinput>set -u</userinput> or 
		<userinput>set -o nounset</userinput> in the script runs it, but
		gives an <errorname>unbound variable</errorname> error message
		at each attempt to use an undeclared variable.</para>
	  </listitem>

	  <listitem>
	    
	    <para>Using an <quote>assert</quote> function to test a
	      variable or condition at critical points in a script. (This is
	      an idea borrowed from C.)</para>

	    <example id="assert">
	      <title>Testing a condition with an
	      <firstterm>assert</firstterm></title>
	      <programlisting>&assert;</programlisting>
	    </example>	    

	  </listitem>

	  <listitem>

	    <para>Using the <link linkend="linenoref">$LINENO</link>
	      variable and the <link linkend="callerref">caller</link>
	      builtin.</para>

	  </listitem>


	  <listitem>

	    <para><anchor id="debugtrap">Trapping at exit.</para>

	<para>The <link linkend="exitref">exit</link> command in a script
	      triggers a signal <returnvalue>0</returnvalue>, terminating
	      the process, that is, the script itself.

	      <footnote><para>By convention, <replaceable>signal
		0</replaceable> is assigned to <link
		linkend="exitcommandref">exit</link>.  </para></footnote>

	      It is often useful to trap the
	      <firstterm>exit</firstterm>, forcing a <quote>printout</quote>
	      of variables, for example. The <firstterm>trap</firstterm>
	      must be the first command in the script.</para>

	  </listitem>
	</orderedlist>
      </para>

	<variablelist id="trapref">
	  <title><anchor id="trapref1">Trapping signals</title>

	  <varlistentry>
	    <term><command>trap</command></term>
	    <listitem>
	      <para>Specifies an action on receipt of a
	        signal; also useful for debugging.</para>

	      <para><anchor id="signald"></para>
	      <sidebar>
		<para>A <firstterm>signal</firstterm> is a message
		sent to a process, either by the kernel or another
		process, telling it to take some specified action
		(usually to terminate).  For example, hitting a
		<link linkend="ctlcref">Control-C</link>
		sends a user interrupt, an INT signal, to a running
		program.</para></sidebar>

		<para><emphasis>A simple instance:</emphasis>
		  <programlisting>trap '' 2
# Ignore interrupt 2 (Control-C), with no action specified. 

trap 'echo "Control-C disabled."' 2
# Message when Control-C pressed.</programlisting>
	      </para>

	    </listitem>
	  </varlistentry>
	</variablelist>

      <example id="ex76">
	<title>Trapping at exit</title>
	<programlisting>&ex76;</programlisting>
      </example>
	
      <example id="online">
	<title>Cleaning up after <keycap>Control-C</keycap></title>
	<programlisting>&online;</programlisting>
      </example>

      <note>
      <para>The <option>DEBUG</option> argument to
	<command>trap</command> causes a specified action to execute
	after every command in a script. This permits tracing variables,
	for example.

      <example id="vartrace">
	<title>Tracing a variable</title>
	<programlisting>&vartrace;</programlisting>
      </example>

      </para>
      </note>


      <para>Of course, the <command>trap</command> command has other uses
        aside from debugging, such as disabling certain keystrokes within a
	script (see <xref linkend="stopwatch">).</para>

      <example id="multipleproc">
	<title>Running multiple processes (on an SMP box)</title>
	<programlisting>&multipleproc;</programlisting>
      </example>


      <note><para><userinput>trap '' SIGNAL</userinput> (two adjacent
	apostrophes) disables SIGNAL for the remainder of the
	script. <userinput>trap SIGNAL</userinput> restores
	the functioning of SIGNAL once more. This is useful to
	protect a critical portion of a script from an undesirable
	interrupt.</para></note>

	<para><programlisting>
	trap '' 2  # Signal 2 is Control-C, now disabled.
	command
	command
	command
	trap 2     # Reenables Control-C
	</programlisting></para>

      <sidebar>
        <para><link linkend="bash3ref">Version 3</link> of Bash adds the
	  following <link linkend="internalvariables1">internal
	  variables</link> for use by the debugger.

       <orderedlist>

         <listitem>
	   <para><varname>$BASH_ARGC</varname></para>
	   <para>Number of command-line arguments passed to script,
	     similar to <link
	     linkend="clacountref"><varname>$#</varname></link>.</para>
	 </listitem>

         <listitem>
	   <para><varname>$BASH_ARGV</varname></para>
	   <para>Final command-line parameter passed to script, equivalent
	     <link
	     linkend="lastargref"><varname>${!#}</varname></link>.</para>
	 </listitem>

         <listitem>
	   <para><varname>$BASH_COMMAND</varname></para>
	   <para>Command currently executing.</para>
	 </listitem>

         <listitem>
	   <para><varname>$BASH_EXECUTION_STRING</varname></para>
	   <para>The <firstterm>option string</firstterm> following the
	     <option>-c</option> <link linkend="clopts">option</link>
	     to Bash.</para>
	 </listitem>

         <listitem>
	   <para><varname>$BASH_LINENO</varname></para>
	   <para>In a <link linkend="functionref">function</link>,
	     indicates the line number of the function call.</para>
	</listitem>

         <listitem>
	   <para><varname>$BASH_REMATCH</varname></para>
	   <para>Array variable associated with <command>=~</command>
	   <link linkend="regexmatchref">conditional regex
	   matching</link>.</para>
	 </listitem>

         <listitem>
	   <para><varname>$BASH_SOURCE</varname></para>
	   <para>Same as <link linkend="arg0">$0</link>.</para>
	 </listitem>

	 <listitem>
	   <para>
	 <link
	 linkend="bashsubshellref"><varname>$BASH_SUBSHELL</varname></link></para>
	 </listitem>

       </orderedlist></para>
      </sidebar>

  </chapter> <!-- Debugging -->



  <chapter id="options">
    <title>Options</title>

      <para><anchor id="optionsref"></para>

      <para>Options are settings that change shell and/or script
        behavior.</para> 
	
      <para>The <link linkend="setref">set</link> command
	enables options within a script. At the point in the script
	where you want the options to take effect, use <command>set
	-o option-name</command> or, in short form, <command>set
	-option-abbrev</command>. These two forms are equivalent.</para>

      <para><programlisting>
      #!/bin/bash

      set -o verbose
      # Echoes all commands before executing.
      </programlisting></para>

      <para><programlisting>
      #!/bin/bash

      set -v
      # Exact same effect as above.
      </programlisting></para>

      <note><para>To <firstterm>disable</firstterm> an option within a script,
	use <command>set +o option-name</command> or <command>set
	+option-abbrev</command>.</para></note>

      <para><programlisting>
      #!/bin/bash

      set -o verbose
      # Command echoing on.
      command
      ...
      command

      set +o verbose
      # Command echoing off.
      command
      # Not echoed.


      set -v
      # Command echoing on.
      command
      ...
      command

      set +v
      # Command echoing off.
      command

      exit 0
      </programlisting></para>


      <para>An alternate method of enabling options in a script is
	to specify them immediately following the
	<replaceable>#!</replaceable> script header.</para>

      <para><programlisting>
      #!/bin/bash -x
      #
      # Body of script follows.
      </programlisting></para>


      <para><anchor id="invocationoptionsref"></para>
      <para>It is also possible to enable script options from the command
	line. Some options that will not work with
	<command>set</command> are available this way. Among these
	are <replaceable>-i</replaceable>, force script to run
	interactive.</para>

      <para><userinput>bash -v script-name</userinput></para>
      
      <para><userinput>bash -o verbose script-name</userinput></para>


      <para>The following is a listing of some useful options. They may be
	specified in either abbreviated form (preceded by a single dash)
	or by complete name (preceded by a <emphasis>double</emphasis>
	dash or by <option>-o</option>).</para>

      <para><anchor id="optionstable"></para>

      <table>
	<title>Bash options</title>
	<tgroup cols="3">
	  <thead>
	    <row>
	      <entry>Abbreviation</entry>
	      <entry>Name</entry>
	      <entry>Effect</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><anchor id="noclobberref"><option>-C</option></entry>
	      <entry>noclobber</entry>
	      <entry>Prevent overwriting of files by redirection (may be
		overridden by <token>>|</token>)</entry> 
	    </row>
	    <row>
	      <entry><option>-D</option></entry>
	      <entry>(none)</entry>
	      <entry>List double-quoted strings prefixed by <token>$</token>,
	      but do not execute commands in script</entry>
	    </row>
	    <row>
	      <entry><option>-a</option></entry>
	      <entry>allexport</entry>
	      <entry>Export all defined variables</entry>
	    </row>
	    <row>
	      <entry><option>-b</option></entry>
	      <entry>notify</entry>
	      <entry>Notify when jobs running in background terminate (not of
	        much use in a script)</entry>
	    </row>
	    <row>
	      <entry><option>-c ...</option></entry>
	      <entry>(none)</entry>
	      <entry>Read commands from <command>...</command></entry>
	    </row>
	    <row>
	      <entry><option>-e</option></entry>
	      <entry>errexit</entry>
	      <entry>Abort script at first error, when a command
		exits with non-zero status (except in <link
		linkend="untilloopref">until</link> or <link
		linkend="whileloopref">while loops</link>, <link
		linkend="testconstructs1">if-tests</link>, <link
		linkend="lcons1">list constructs</link>)</entry>
	    </row>
	    <row>
	      <entry><option>-f</option></entry>
	      <entry>noglob</entry>
	      <entry>Filename expansion (globbing) disabled</entry>
	    </row>
	    <row>
	      <entry><option>-i</option></entry>
	      <entry>interactive</entry>
	      <entry>Script runs in <firstterm>interactive</firstterm> mode</entry>
	    </row>
	    <row>
	      <entry><option>-n</option></entry>
	      <entry>noexec</entry>
	      <entry>Read commands in script, but do not execute them (syntax check)</entry>
	    </row>
	    <row>
	      <entry><option>-o Option-Name</option></entry>
	      <entry>(none)</entry>
	      <entry>Invoke the <firstterm>Option-Name</firstterm>
	        option</entry>
	    </row>
	    <row>
	      <entry><option>-o posix</option></entry>
	      <entry>POSIX</entry>
	      <entry>Change the behavior of Bash, or invoked script, to
		conform to <link linkend="posix2ref">POSIX</link>
		standard.</entry>
	    </row>
	    <row>
	      <entry><option>-o pipefail</option></entry>
	      <entry>pipe failure</entry>
	      <entry>Causes a pipeline to return the <link
	      linkend="exitstatusref">exit status</link> of
	      the last command in the pipe that returned a non-zero
	      return value.</entry>
	    </row>
	    <row>
	      <entry><option>-p</option></entry>
	      <entry>privileged</entry>
	      <entry>Script runs as <quote>suid</quote> (caution!)</entry>
	    </row>
	    <row>
	      <entry><option>-r</option></entry>
	      <entry>restricted</entry>
	      <entry>Script runs in <firstterm>restricted</firstterm>
	      mode (see <xref linkend="restricted-sh">).</entry>
	    </row>
	    <row>
	      <entry><option>-s</option></entry>
	      <entry>stdin</entry>
	      <entry>Read commands from <filename>stdin</filename></entry>
	    </row>
	    <row>
	      <entry><option>-t</option></entry>
	      <entry>(none)</entry>
	      <entry>Exit after first command</entry>
	    </row>
	    <row>
	      <entry><option>-u</option></entry>
	      <entry>nounset</entry>
	      <entry>Attempt to use undefined variable
		outputs error message, and forces an exit</entry>
	    </row>
	    <row>
	      <entry><option>-v</option></entry>
	      <entry>verbose</entry>
	      <entry>Print each command to <filename>stdout</filename> before executing it</entry>
	    </row>
	    <row>
	      <entry><option>-x</option></entry>
	      <entry>xtrace</entry>
	      <entry>Similar to <option>-v</option>, but expands commands</entry>
	    </row>
	    <row>
	      <entry><option>-</option></entry>
	      <entry>(none)</entry>
	      <entry>End of options flag. All other arguments
		are <link linkend="posparamref">positional
		parameters</link>.</entry>
	    </row>
	    <row>
	      <entry><option>--</option></entry>
	      <entry>(none)</entry>
	      <entry>Unset positional parameters.
		If arguments given (<parameter>-- arg1 arg2</parameter>),
		positional parameters set to arguments.</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>
  </chapter> <!-- Options -->


  
  <chapter id="gotchas">
    <title>Gotchas</title>

    <epigraph>
      <para>Turandot: <foreignphrase>Gli enigmi sono tre, la morte
        una!</foreignphrase></para>
      <para>Caleph: <foreignphrase>No, no! Gli enigmi sono tre, una la
        vita!</foreignphrase></para>
      <para>--Puccini</para>
    </epigraph>

      <para><anchor id="bash3gotcha"></para>

      <para>Here are some (non-recommended!) scripting practices that
        will bring excitement to an otherwise dull life.</para>


      <itemizedlist>

	<listitem>
      <para><anchor id="inappvn"></para>

      <para>Assigning reserved words or characters to variable names.</para>

	<para>
	<programlisting>case=value0       # Causes problems.
23skidoo=value1   # Also problems.
# Variable names starting with a digit are reserved by the shell.
# Try _23skidoo=value1. Starting variables with an underscore is o.k.

# However . . .   using just the underscore will not work.
_=25
echo $_           # $_ is a special variable set to last arg of last command.

xyz((!*=value2    # Causes severe problems.
# As of version 3 of Bash, periods are not allowed within variable names.</programlisting>
	</para>
	</listitem>

	<listitem>
      <para>Using a hyphen or other reserved characters in a variable name (or
        function name).</para>
	<para>
	<programlisting>var-1=23
# Use 'var_1' instead.

function-whatever ()   # Error
# Use 'function_whatever ()' instead.

 
# As of version 3 of Bash, periods are not allowed within function names.
function.whatever ()   # Error
# Use 'functionWhatever ()' instead.</programlisting>
      </para>
	</listitem>

	<listitem>
      <para>Using the same name for a variable and a function. This can make a
        script difficult to understand.</para>
      <para>
        <programlisting>do_something ()
{
  echo "This function does something with \"$1\"."
}

do_something=do_something

do_something do_something

# All this is legal, but highly confusing.</programlisting>
	</para>
	</listitem>



	<listitem>
      <para><anchor id="wsbad">Using <link
	linkend="whitespaceref">whitespace</link> inappropriately.
	In contrast to other programming languages, Bash can be quite
	finicky about whitespace.</para>

	<para>
	<programlisting>var1 = 23   # 'var1=23' is correct.
# On line above, Bash attempts to execute command "var1"
# with the arguments "=" and "23".
	
let c = $a - $b   # 'let c=$a-$b' or 'let "c = $a - $b"' are correct.

if [ $a -le 5]    # if [ $a -le 5 ]   is correct.
# if [ "$a" -le 5 ]   is even better.
# [[ $a -le 5 ]] also works.</programlisting>
	</para>
	</listitem>


	<listitem>
      <para><anchor id="omitsemicolon"></para>
      <para>Not terminating with a <link
        linkend="semicolonref">semicolon</link> the final command
        in a <link linkend="codeblockref">code block within curly
        brackets</link>.</para>
      <para>
        <programlisting>{ ls -l; df; echo "Done." }
# bash: syntax error: unexpected end of file

{ ls -l; df; echo "Done."; }
#                        ^     ### Final command needs semicolon.</programlisting>
      </para>
	</listitem>


	<listitem>
      <para><anchor id="uninitvar"></para>
      <para>
        Assuming uninitialized variables (variables before a value is
	assigned to them) are <quote>zeroed out</quote>. An
	uninitialized variable has a value of <firstterm>null</firstterm>,
	<emphasis>not</emphasis> zero.</para>

      <para>
	   <programlisting>#!/bin/bash

echo "uninitialized_var = $uninitialized_var"
# uninitialized_var =</programlisting>

      </para>
	</listitem>


	<listitem>
	<para><anchor id="eqdif"></para>
	<para>Mixing up <firstterm>=</firstterm> and
	  <firstterm>-eq</firstterm> in a test. Remember,
	  <firstterm>=</firstterm> is for comparing literal variables
	  and <firstterm>-eq</firstterm> for integers.</para>

      <para>
	<programlisting>if [ "$a" = 273 ]      # Is $a an integer or string?
if [ "$a" -eq 273 ]    # If $a is an integer.

# Sometimes you can interchange -eq and = without adverse consequences.
# However . . .


a=273.0   # Not an integer.
	   
if [ "$a" = 273 ]
then
  echo "Comparison works."
else  
  echo "Comparison does not work."
fi    # Comparison does not work.

# Same with   a=" 273"  and a="0273".


# Likewise, problems trying to use "-eq" with non-integer values.
	   
if [ "$a" -eq 273.0 ]
then
  echo "a = $a"
fi  # Aborts with an error message.  
# test.sh: [: 273.0: integer expression expected</programlisting>
        </para>
	</listitem>
	  

	<listitem>
      <para><anchor id="numstrcompne"></para>
      <para>Misusing <link linkend="scomparison1">string comparison</link>
        operators.</para>

	    <example id="badop">
	      <title>Numerical and string comparison are not equivalent</title>
	      <programlisting>&badop;</programlisting>
	    </example>
	</listitem>

      
	<listitem>
      <para><anchor id="failquote"></para>
      <para>Sometimes variables within <quote>test</quote> brackets
	([ ]) need to be quoted (double quotes).  Failure to do so may
	cause unexpected behavior. See <xref linkend="strtest">, <xref
	linkend="redir2">, and <xref linkend="arglist">.</para>
	</listitem>

	<listitem>
      <para><anchor id="failnotquote"></para>
      <para>Quoting a variable containing whitespace <link
        linkend="wsquo">prevents splitting</link>. Sometimes
	this produces <link linkend="varsplitting">unintended
	consequences</link>.</para>
	</listitem>


	<listitem>
      <para><anchor id="execperm"></para>
      <para>Commands issued from a script may fail to execute because
	the script owner lacks execute permission for them. If a user
	cannot invoke a command from the command line, then putting it
	into a script will likewise fail. Try changing the attributes of
	the command in question, perhaps even setting the suid bit
	(as <firstterm>root</firstterm>, of course).</para>
	</listitem>



	<listitem>
      <para><anchor id="dashnredr"></para>
      <para>Attempting to use <command>-</command> as a redirection
        operator (which it is not) will usually result in an unpleasant
	surprise.</para>
        <para>
	<programlisting>command1 2&gt; - | command2
# Trying to redirect error output of command1 into a pipe . . .
# . . . will not work.	

command1 2&gt;&amp; - | command2  # Also futile.

Thanks, S.C.</programlisting></para>
	</listitem>




	<listitem>
      <para><anchor id="lateverf"></para>
      <para>Using Bash <link linkend="bash2ref">version 2+</link>
	functionality may cause a bailout with error messages. Older
	Linux machines may have version 1.XX of Bash as the default
	installation.</para>
        <para>
	<programlisting>#!/bin/bash

minimum_version=2
# Since Chet Ramey is constantly adding features to Bash,
# you may set $minimum_version to 2.XX, 3.XX, or whatever is appropriate.
E_BAD_VERSION=80

if [ "$BASH_VERSION" \< "$minimum_version" ]
then
  echo "This script works only with Bash, version $minimum or greater."
  echo "Upgrade strongly recommended."
  exit $E_BAD_VERSION
fi

...</programlisting></para>
	</listitem>

	

	<listitem>
      <para>Using Bash-specific functionality in a Bourne shell script
	(<userinput>#!/bin/sh</userinput>) on a non-Linux machine
	<link linkend="binsh">may cause unexpected behavior</link>. A
	Linux system usually aliases <command>sh</command> to
	<command>bash</command>, but this does not necessarily hold true
	for a generic UNIX machine.</para> </listitem>

	<listitem>
      <para><anchor id="undocf"></para>
      <para>Using undocumented features in Bash turns out to be a
	dangerous practice. In previous releases of this
	book there were several scripts that depended on the
	<quote>feature</quote> that, although the maximum value
	of an <link linkend="exitstatusref">exit</link> or <link
	linkend="returnref">return</link> value was 255, that limit
	did not apply to <emphasis>negative</emphasis> integers.
	Unfortunately, in version 2.05b and later, that loophole
	disappeared.  See <xref linkend="returntest">.</para>
	</listitem>



	<listitem>
      <para><anchor id="dosnewlines"></para>
      <para>
        A script with DOS-type newlines (<replaceable>\r\n</replaceable>)
	will fail to execute, since <userinput>#!/bin/bash\r\n</userinput>
	is <emphasis>not</emphasis> recognized, <emphasis>not</emphasis>
	the same as the expected <userinput>#!/bin/bash\n</userinput>. The
	fix is to convert the script to UNIX-style newlines.</para>
      <para>
	  <programlisting>#!/bin/bash

echo "Here"

unix2dos $0    # Script changes itself to DOS format.
chmod 755 $0   # Change back to execute permission.
               # The 'unix2dos' command removes execute permission.

./$0           # Script tries to run itself again.
               # But it won't work as a DOS file.

echo "There"

exit 0</programlisting>
      </para>

	</listitem>



	<listitem>
      <para><anchor id="binsh"></para>
      <para>A shell script headed by <userinput>#!/bin/sh</userinput>
	will not run in full Bash-compatibility mode. Some Bash-specific
	functions might be disabled. Scripts that need complete
	access to all the Bash-specific extensions should start with
	<userinput>#!/bin/bash</userinput>.</para>
	</listitem>

	<listitem>
      <para><link linkend="indentedls">Putting whitespace in front of
	the terminating limit string</link> of a <link
	linkend="heredocref">here document</link> will cause unexpected
	behavior in a script.</para>
	</listitem>

	<listitem>
      <para><anchor id="rvtcaution2">Putting more than one
	<firstterm>echo</firstterm> statement in a function <link
	linkend="rvt">whose output is captured</link>.
	<programlisting>add2 ()
{
  echo "Whatever ... "   # Delete this line!
  let "retval = $1 + $2"
    echo $retval
    }

    num1=12
    num2=43
    echo "Sum of $num1 and $num2 = $(add2 $num1 $num2)"

#   Sum of 12 and 43 = Whatever ... 
#   55

#        The "echoes" concatenate.</programlisting>
	This <link
	linkend="rvtcaution">will not work</link>.</para>
	</listitem>


	<listitem>
      <para><anchor id="parchildprobref"></para>
      
      <para>A script may not <command>export</command> variables back
	to its <link linkend="forkref">parent process</link>, the shell,
	or to the environment. Just as we learned in biology, a child
	process can inherit from a parent, but not vice versa.</para>
      <para>
	  <programlisting>WHATEVER=/home/bozo
export WHATEVER
exit 0</programlisting>
          <screen><prompt>bash$ </prompt><command>echo $WHATEVER</command>
<computeroutput>

</computeroutput>
<prompt>bash$ </prompt></screen>
      </para>
      <para>
        Sure enough, back at the command prompt, $WHATEVER remains unset.
       </para>
	
	</listitem>


      
	<listitem>
      <para><anchor id="varsubsh"></para>
      <para>Setting and manipulating variables in a <link
        linkend="subshellsref">subshell</link>, then attempting
        to use those same variables outside the scope of the subshell will
	result an unpleasant surprise.</para>

      <example id="subpit">
	<title>Subshell Pitfalls</title>
	<programlisting>&subpit;</programlisting>
      </example>
	</listitem>


	<listitem>
      <para><anchor id="badread0"></para>
      <para><link linkend="piperef">Piping</link>
	<command>echo</command> output to a <link
	linkend="readref">read</link> may produce unexpected
	results.  In this scenario, the <command>read</command>
	acts as if it were running in a subshell. Instead, use
	the <link linkend="setref">set</link> command (as in <xref
	linkend="setpos">).</para>

      <example id="badread">
	<title>Piping the output of <firstterm>echo</firstterm> to a
	<firstterm>read</firstterm></title>
	<programlisting>&badread;</programlisting>
      </example>

      <para><anchor id="pipeloop"></para>
      <para>In fact, as Anthony Richardson points out, piping to
        <emphasis>any</emphasis> loop can cause a similar problem.</para>

      <para>	
<programlisting># Loop piping troubles.
#  This example by Anthony Richardson,
#+ with addendum by Wilbert Berendsen.


foundone=false
find $HOME -type f -atime +30 -size 100k |
while true
do
   read f
   echo "$f is over 100KB and has not been accessed in over 30 days"
   echo "Consider moving the file to archives."
   foundone=true
   # ------------------------------------
   echo "Subshell level = $BASH_SUBSHELL"
   # Subshell level = 1
   # Yes, we're inside a subshell.
   # ------------------------------------
done
   
#  foundone will always be false here since it is
#+ set to true inside a subshell
if [ $foundone = false ]
then
   echo "No files need archiving."
fi

# =====================Now, here is the correct way:=================

foundone=false
for f in $(find $HOME -type f -atime +30 -size 100k)  # No pipe here.
do
   echo "$f is over 100KB and has not been accessed in over 30 days"
   echo "Consider moving the file to archives."
   foundone=true
done
   
if [ $foundone = false ]
then
   echo "No files need archiving."
fi

# ==================And here is another alternative==================

#  Places the part of the script that reads the variables
#+ within a code block, so they share the same subshell.
#  Thank you, W.B.

find $HOME -type f -atime +30 -size 100k | {
     foundone=false
     while read f
     do
       echo "$f is over 100KB and has not been accessed in over 30 days"
       echo "Consider moving the file to archives."
       foundone=true
     done

     if ! $foundone
     then
       echo "No files need archiving."
     fi
}</programlisting>
      </para>

      <para><anchor id="ptailgrep"></para>
      <para>
        A related problem occurs when trying to write the
	<filename>stdout</filename> of a <command>tail -f</command>
	piped to <link linkend="grepref">grep</link>.
	  <programlisting>tail -f /var/log/messages | grep "$ERROR_MSG" >> error.log
# The "error.log" file will not have anything written to it.</programlisting>
      </para>
	</listitem>



	<listitem>
      <para><anchor id="suidscr"></para>
      <para>Using <quote>suid</quote> commands within scripts is risky,
	as it may compromise system security.
	  <footnote><para>Setting the <link linkend="suidref">suid</link>
	  permission on the script itself has no effect in Linux
	  and most other UNIX flavors.</para></footnote>
      </para>
	</listitem>


	<listitem>
      <para><anchor id="cgiref"></para>
      <para>Using shell scripts for CGI programming may be problematic. Shell
        script variables are not <quote>typesafe,</quote> and this can cause
	undesirable behavior as far as CGI is concerned. Moreover, it is
	difficult to <quote>cracker-proof</quote> shell scripts.</para>
	</listitem>


	<listitem>
      <para>Bash does not handle the <link linkend="doubleslashref">double slash
        (<token>//</token>) string</link> correctly.</para>
	</listitem>


	<listitem>
      <para><anchor id="gnuref"></para>
      <para>Bash scripts written for Linux or BSD systems may need
	fixups to run on a commercial UNIX (or Apple OSX) machine. Such
	scripts often employ the GNU set of commands and filters,
	which have greater functionality than their generic UNIX
	counterparts. This is particularly true of such text processing
	utilites as <link linkend="trref">tr</link>.</para>
	</listitem>


      </itemizedlist>

    <epigraph>
      <para>Danger is near thee --</para>
      <para>Beware, beware, beware, beware.</para>
      <para>Many brave hearts are asleep in the deep.</para>
      <para>So beware --</para>
      <para>Beware.</para>
      <para>--A.J. Lamb and H.W. Petrie</para>
    </epigraph>

  </chapter> <!-- Gotchas -->



  <chapter id="scrstyle">
    <title>Scripting With Style</title>

      <para>Get into the habit of writing shell scripts in a structured and
	systematic manner. Even on-the-fly and <quote>written on the
	back of an envelope</quote> scripts will benefit if you take a
	few minutes to plan and organize your thoughts before sitting
	down and coding.</para>

      <para>Herewith are a few stylistic guidelines. This is not
	(necessarily) intended as an <emphasis>Official Shell Scripting
	Stylesheet</emphasis>.</para>



      <sect1 id="unofficialst">
        <title>Unofficial Shell Scripting Stylesheet</title>

      <itemizedlist>

        <listitem>

	  <para>Comment your code. This makes it easier for others to
	    understand (and appreciate), and easier for you to maintain.
	    <programlisting>PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}"
#  It made perfect sense when you wrote it last year,
#+ but now it's a complete mystery.
#  (From Antek Sawicki's "pw.sh" script.)</programlisting>
	  </para>

	  <para>Add descriptive headers to your scripts and functions.
	    <programlisting>#!/bin/bash

#************************************************#
#                   xyz.sh                       #
#           written by Bozo Bozeman              #
#                July 05, 2001                   #
#                                                #
#           Clean up project files.              #
#************************************************#

E_BADDIR=85                       # No such directory.
projectdir=/home/bozo/projects    # Directory to clean up.

# --------------------------------------------------------- #
# cleanup_pfiles ()                                         #
# Removes all files in designated directory.                #
# Parameter: $target_directory                              #
# Returns: 0 on success, $E_BADDIR if something went wrong. #
# --------------------------------------------------------- #
cleanup_pfiles ()
{
  if [ ! -d "$1" ]  # Test if target directory exists.
  then
    echo "$1 is not a directory."
    return $E_BADDIR
  fi

  rm -f "$1"/*
  return 0   # Success.
}  

cleanup_pfiles $projectdir

exit $?</programlisting></para>

        </listitem>


        <listitem>
	  <para>Avoid using <quote>magic numbers,</quote>

	     <footnote><para>In this context, <quote>magic
	       numbers</quote> have an entirely different meaning than
	       the <link linkend="magnumref">magic numbers</link> used
	       to designate file types.</para></footnote>

	    that is, <quote>hard-wired</quote> literal constants. Use
	    meaningful variable names instead. This makes the script
	    easier to understand and permits making changes and updates
	    without breaking the application.

	    <programlisting>if [ -f /var/log/messages ]
then
  ...
fi
#  A year later, you decide to change the script to check /var/log/syslog.
#  It is now necessary to manually change the script, instance by instance,
#+ and hope nothing breaks.

# A better way:
LOGFILE=/var/log/messages  # Only line that needs to be changed.
if [ -f "$LOGFILE" ]
then
  ...
fi</programlisting>
          </para>
        </listitem>


        <listitem>

	  <para>Choose descriptive names for variables and functions.
	    <programlisting>fl=`ls -al $dirname`                 # Cryptic.
file_listing=`ls -al $dirname`       # Better.


MAXVAL=10   # All caps used for a script constant.
while [ "$index" -le "$MAXVAL" ]
...


E_NOTFOUND=95                        #  Uppercase for an errorcode,
                                     #+ and name prefixed with E_.
if [ ! -e "$filename" ]
then
  echo "File $filename not found."
  exit $E_NOTFOUND
fi  


MAIL_DIRECTORY=/var/spool/mail/bozo  #  Uppercase for an environmental
export MAIL_DIRECTORY                #+ variable.


GetAnswer ()                         #  Mixed case works well for a
{                                    #+ function name, especially
  prompt=$1                          #+ when it improves legibility.
  echo -n $prompt
  read answer
  return $answer
}  

GetAnswer "What is your favorite number? "
favorite_number=$?
echo $favorite_number


_uservariable=23                     # Permissible, but not recommended.
# It's better for user-defined variables not to start with an underscore.
# Leave that for system variables.</programlisting>
          </para>
        </listitem>


        <listitem>

	  <para>Use <link linkend="exitcommandref">exit codes</link>
	    in a systematic and meaningful way.

	    <programlisting>E_WRONG_ARGS=95
...
...
exit $E_WRONG_ARGS</programlisting>
            See also <xref linkend="exitcodes">.</para>


          <para><emphasis>Ender</emphasis> suggests using the <link
	    linkend="sysexitsref">exit codes
	    in <filename>/usr/include/sysexits.h</filename></link> in shell
	    scripts, though these are primarily intended for C and C++
	    programming.</para>

        </listitem>



        <listitem>


	   <para>Use standardized parameter flags for script invocation.
	     <emphasis>Ender</emphasis> proposes the following set
	     of flags.</para>

           <para>
             <programlisting>-a      All: Return all information (including hidden file info).
-b      Brief: Short version, usually for other scripts.
-c      Copy, concatenate, etc.
-d      Daily: Use information from the whole day, and not merely
        information for a specific instance/user.
-e      Extended/Elaborate: (often does not include hidden file info).
-h      Help: Verbose usage w/descs, aux info, discussion, help.
        See also -V.
-l      Log output of script.
-m      Manual: Launch man-page for base command.
-n      Numbers: Numerical data only.
-r      Recursive: All files in a directory (and/or all sub-dirs).
-s      Setup & File Maintenance: Config files for this script.
-u      Usage: List of invocation flags for the script.
-v      Verbose: Human readable output, more or less formatted.
-V      Version / License / Copy(right|left) / Contribs (email too).</programlisting>
           </para>

           <para>See also <xref linkend="standard-options">.</para>

        </listitem>


        <listitem>
	  <para>Break complex scripts into simpler modules. Use functions
	    where appropriate. See <xref linkend="cards">.</para>
        </listitem>

        <listitem>
	  <para>Don't use a complex construct where a simpler one will do.

	    <programlisting>COMMAND
if [ $? -eq 0 ]
...
# Redundant and non-intuitive.

if COMMAND
...
# More concise (if perhaps not quite as legible).</programlisting>
          </para>
        </listitem>

	    
      </itemizedlist>


    <epigraph>
      <para>... reading the UNIX source code to the Bourne shell (/bin/sh). I
        was shocked at how much simple algorithms could be made cryptic, and
	therefore useless, by a poor choice of code style. I asked myself,
	<quote>Could someone be proud of this code?</quote></para>
      <para>--Landon Noll</para>
    </epigraph>

    </sect1> <!-- Unofficial Shell Scripting Stylesheet -->  



  </chapter> <!-- Scripting With Style -->



  <chapter id="miscellany">
    <title>Miscellany</title>

    <epigraph>
      <para>Nobody really knows what the Bourne shell's grammar is. Even
        examination of the source code is little help.</para>
      <para>--Tom Duff</para>
    </epigraph>


      <sect1 id="intandnonint">
        <title>Interactive and non-interactive shells and scripts</title>
         
	 <para>An <firstterm>interactive</firstterm> shell reads
	   commands from user input on a <filename>tty</filename>. Among
	   other things, such a shell reads startup files on activation,
	   displays a prompt, and enables job control by default. The
	   user can <firstterm>interact</firstterm> with the shell.</para>

	 <para>A shell running a script is always a non-interactive
	   shell. All the same, the script can still access its
	   <filename>tty</filename>. It is even possible to emulate an
	   interactive shell in a script.

	   <programlisting>#!/bin/bash
MY_PROMPT='$ '
while :
do
  echo -n "$MY_PROMPT"
  read line
  eval "$line"
  done

exit 0

# This example script, and much of the above explanation supplied by
# St&eacute;phane Chazelas (thanks again).</programlisting></para>

	 <para>Let us consider an <firstterm>interactive</firstterm>
	   script to be one that requires input from the user, usually
	   with <link linkend="readref">read</link> statements (see <xref
	   linkend="ex36">). <quote>Real life</quote> is actually a
	   bit messier than that. For now, assume an interactive script
	   is bound to a tty, a script that a user has invoked from the
	   console or an <firstterm>xterm</firstterm>.</para>

	 <para>Init and startup scripts are necessarily non-interactive,
	   since they must run without human intervention. Many
	   administrative and system maintenance scripts are likewise
	   non-interactive.  Unvarying repetitive tasks cry out for
	   automation by non-interactive scripts.</para>

	 <para>Non-interactive scripts can run in the background, but
	   interactive ones hang, waiting for input that never comes.
	   Handle that difficulty by having an <command>expect</command>
	   script or embedded <link linkend="heredocref">here
	   document</link> feed input to an interactive script running
	   as a background job.  In the simplest case, redirect a
	   file to supply input to a <command>read</command> statement
	   (<command>read variable &lt;file</command>).  These particular
	   workarounds make possible general purpose scripts that run
	   in either interactive or non-interactive modes.</para>

	 <para>If a script needs to test whether it is running in an
	   interactive shell, it is simply a matter of finding
	   whether the <firstterm>prompt</firstterm> variable, <link
	   linkend="ps1ref">$PS1</link> is set. (If the user is being
	   prompted for input, then the script needs to display a prompt.)

	   <programlisting>if [ -z $PS1 ] # no prompt?
then
  # non-interactive
  ...
else
  # interactive
  ...
fi</programlisting>

	   <anchor id="iitest">Alternatively, the script can test
	   for the presence of option <quote>i</quote> in the <link
	   linkend="flpref">$-</link> flag.

           <programlisting>case $- in
*i*)    # interactive shell
;;
*)      # non-interactive shell
;;
# (Courtesy of "UNIX F.A.Q.," 1993)</programlisting></para>


	 <note><para>Scripts may be forced to run in interactive
	   mode with the <token>-i</token> option or with a
	   <userinput>#!/bin/bash -i</userinput> header. Be aware that
	   this can cause erratic script behavior or show error messages
	   even when no error is present.</para></note>


      </sect1> <!-- Interactive and non-interactive scripts -->

    <sect1 id="opprecedence">
      <title>Operator Precedence</title>

      <para><anchor id="opprecedence1"></para>

      <para>
        In a script, operations execute in order of
        <firstterm>precedence</firstterm>: the higher precedence operations
	execute <emphasis>before</emphasis> the lower precedence ones.
	  <footnote><para><firstterm>Precedence</firstterm>, in this context,
	    has approximately the same meaning as
	    <firstterm>priority</firstterm></para></footnote>
      </para>

       &opprectable;

      <para>In practice, all you really need to remember is the
      following:</para>

      <itemizedlist>
	<listitem>
	<para>The <quote>My Dear Aunt Sally</quote> mantra (<emphasis>multiply,
	  divide, add, subtract</emphasis>) for the familiar <link
	  linkend="arops1">arithmetic operations</link>.</para>
	</listitem>
	<listitem>
	<para>The <firstterm>compound</firstterm> logical operators,
	  <command>&&</command>, <command>||</command>, <command>-a</command>,
	  and <command>-o</command> have low precedence.</para>
	</listitem>
	<listitem>
	<para>The order of evaluation of equal-precedence operators is
	  usually <firstterm>left-to-right</firstterm>.</para>
	</listitem>
      </itemizedlist>

	<para>Now, let's utilize our knowledge of operator precedence to
	  analyze a couple of lines from the
	  <filename>/etc/init.d/functions file</filename>, as found in
	  the <firstterm>Fedora Core</firstterm> Linux distro.</para>

	<para><programlisting>while [ -n "$remaining" -a "$retry" -gt 0 ]; do

# This looks rather daunting at first glance.


# Separate the conditions:
while [ -n "$remaining" -a "$retry" -gt 0 ]; do
#       --condition 1-- ^^ --condition 2-

#  If variable "$remaining" is not zero length
#+      AND (-a)
#+ variable "$retry" is greater-than zero
#+ then
#+ the [ expresion-within-condition-brackets ] returns success (0)
#+ and the while-loop executes an iteration.
#  ==============================================================
#  Evaluate "condition 1" and "condition 2" ***before***
#+ ANDing them. Why? Because the AND (-a) has a lower precedence
#+ than the -n and -gt operators,
#+ and therefore gets evaluated *last*.

#################################################################

if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then


# Again, separate the conditions:
if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
#    --condition 1--------- ^^ --condition 2-----

#  If file "/etc/sysconfig/i18n" exists
#+      AND (-a)
#+ variable $NOLOCALE is zero length
#+ then
#+ the [ test-expresion-within-condition-brackets ] returns success (0)
#+ and the commands following execute.
#
#  As before, the AND (-a) gets evaluated *last*
#+ because it has the lowest precedence of the operators within
#+ the test brackets.
#  ==============================================================
#  Note:
#  ${NOLOCALE:-} is a parameter expansion that seems redundant.
#  But, if $NOLOCALE has not been declared, it gets set to *null*,
#+ in effect declaring it.
#  This makes a difference in some contexts.</programlisting></para>

      <tip>
      <para>To avoid confusion or error in a complex sequence of test
        operators, break up the sequence into bracketed sections.
      <programlisting>if [ "$v1" -gt "$v2"  -o  "$v1" -lt "$v2"  -a  -e "$filename" ]
# Unclear what's going on here...

if [[ "$v1" -gt "$v2" ]] || [[ "$v1" -lt "$v2" ]] && [[ -e "$filename" ]]
# Much better -- the condition tests are grouped in logical sections.</programlisting>
      </para>
      </tip>

      </sect1> <!-- Operator Precedence -->


    <sect1 id="wrapper">
      <title>Shell Wrappers</title>

      <para><anchor id="shwrapper"></para>

      <para>A <firstterm>wrapper</firstterm> is a shell script that embeds
	a system command or utility, that accepts and passes a set of
	parameters to that command.

      <footnote><para>Quite a number of Linux utilities are, in fact,
	shell wrappers. Some examples are
	<filename>/usr/bin/pdf2ps</filename>,
	<filename>/usr/bin/batch</filename>, and
	<filename>/usr/bin/xmkmf</filename>.</para></footnote>
	
	Wrapping a script around a complex command line
	simplifies invoking it.  This is expecially useful
	with <link linkend="sedref">sed</link> and <link
	linkend="awkref">awk</link>.</para>

      <para>A
	<command>
	  <indexterm>
	    <primary>sed</primary>
	  </indexterm> <indexterm>
	    <primary>script</primary> <secondary>sed</secondary>
	  </indexterm> sed</command> or
	<command>
	  <indexterm>
	    <primary>awk</primary>
	  </indexterm> <indexterm>
	    <primary>script</primary> <secondary>awk</secondary>
	  </indexterm>
	    awk</command> script would normally be invoked
	    from the command line by a <userinput>sed -e
	    <replaceable>'commands'</replaceable></userinput>
	    or <userinput>awk
	    <replaceable>'commands'</replaceable></userinput>.	Embedding
	    such a script in a Bash script permits calling it more simply,
	    and makes it <firstterm>reusable</firstterm>. This also
	    enables combining the functionality of <firstterm>sed</firstterm>
	    and <firstterm>awk</firstterm>, for example <link
	    linkend="piperef">piping</link> the output of a set of
	    <firstterm>sed</firstterm> commands to
	    <firstterm>awk</firstterm>. As a saved executable file,
	    you can then repeatedly invoke it in its original form or
	    modified, without the inconvenience of retyping it on the
	    command line.</para>

      <example id="ex3">
	<title><firstterm>shell wrapper</firstterm></title>
	<programlisting>&ex3;</programlisting>
      </example>
      
      <example id="ex4">
	<title> A slightly more complex <firstterm>shell
	wrapper</firstterm></title>
	<programlisting>&ex4;</programlisting>
      </example>

      <example id="loggingwrapper">
	<title> A generic <firstterm>shell wrapper</firstterm> that
	writes to a logfile</title>
	<programlisting>&loggingwrapper;</programlisting>
      </example>

      <example id="prasc">
	<title> A <firstterm>shell wrapper</firstterm> around an awk
	script</title>
	<programlisting>&prasc;</programlisting>
      </example>

      <example id="coltotaler">
	<title> A <firstterm>shell wrapper</firstterm> around another
	awk script</title>
	<programlisting>&coltotaler;</programlisting>
      </example>


      <para><anchor id="perlref">For those scripts needing a single
	do-it-all tool, a Swiss army knife, there is
	<firstterm>Perl</firstterm>. Perl combines the
	capabilities of <link linkend="sedref">sed</link> and <link
	linkend="awkref">awk</link>, and throws in a large subset of
	<command>C</command>, to boot. It is modular and contains support
	for everything ranging from object-oriented programming up to and
	including the kitchen sink. Short Perl scripts lend themselves to
	embedding within shell scripts, and there may be some substance
	to the claim that Perl can totally replace shell scripting
	(though the author of the <emphasis>ABS Guide</emphasis> remains
	skeptical).</para>

      <para><anchor id="perlemb"></para>
      <example id="ex56">
	<title>Perl embedded in a <firstterm>Bash</firstterm> script</title>
	<programlisting>&ex56;</programlisting>
      </example>
     
      <para>It is even possible to combine a Bash script and Perl script
        within the same file. Depending on how the script is invoked, either
	the Bash part or the Perl part will execute.</para>

      <para><anchor id="bashandperl0"></para>
      <example id="bashandperl">
	<title>Bash and Perl scripts combined</title>
	<programlisting>&bashandperl;</programlisting>
      </example>

	      <para>
	      <screen><prompt>bash$ </prompt><userinput>bash bashandperl.sh</userinput>
<computeroutput>Greetings from the Bash part of the script.</computeroutput>


<prompt>bash$ </prompt><userinput>perl -x bashandperl.sh</userinput>
<computeroutput>Greetings from the Perl part of the script.</computeroutput>
	      </screen>
	      </para>

      <para>One interesting example of a complex shell wrapper is Martin
         Matusiak's <ulink
         url="http://www.matusiak.eu/numerodix/blog/index.php/"><firstterm>undvd</firstterm>
         script</ulink>, which provides an easy-to-use
         command-line interface to the complex <ulink
         url="http://www.mplayerhq.hu/DOCS/HTML/en/mencoder.html">mencoder</ulink>
         utility. Another example is Itzchak Rehberg's <ulink
         url="http://projects.izzysoft.de/trac/ext3undel">Ext3Undel</ulink>,
         a set of scripts to recover deleted file on an
         <firstterm>ext3</firstterm> filesystem.</para>


    </sect1> <!-- Shell wrappers -->



      <sect1 id="testsandcomparisons">
        <title>Tests and Comparisons: Alternatives</title>

	<para>For tests, the <link linkend="dblbrackets">[[    ]]</link>
	  construct may be more appropriate than <userinput>[
	  ]</userinput>. Likewise, <link linkend="icomparison1">arithmetic
	  comparisons</link> might benefit from the <link
	  linkend="dblparens">((    ))</link> construct.

	  <programlisting>a=8

# All of the comparisons below are equivalent.
test "$a" -lt 16 && echo "yes, $a < 16"         # "and list"
/bin/test "$a" -lt 16 && echo "yes, $a < 16" 
[ "$a" -lt 16 ] && echo "yes, $a < 16" 
[[ $a -lt 16 ]] && echo "yes, $a < 16"          # Quoting variables within
(( a < 16 )) && echo "yes, $a < 16"             # [[ ]] and (( )) not necessary.

city="New York"
# Again, all of the comparisons below are equivalent.
test "$city" \< Paris && echo "Yes, Paris is greater than $city"
                                  # Greater ASCII order.
/bin/test "$city" \< Paris && echo "Yes, Paris is greater than $city" 
[ "$city" \< Paris ] && echo "Yes, Paris is greater than $city" 
[[ $city < Paris ]] && echo "Yes, Paris is greater than $city"
                                  # Need not quote $city.

# Thank you, S.C.</programlisting></para>

      </sect1> <!-- Tests and Comparisons: Alternatives -->



      <sect1 id="recursionsct">
        <title>A script calling itself (recursion)</title>


	<para><anchor id="scriptrecursion"></para>
	<para>Can a script <link linkend="recursionref">recursively</link>
	  call itself? Indeed.</para>

	    <example id="recurse">
	      <title>A (useless) script that recursively calls itself</title>
	      <programlisting>&recurse;</programlisting>
	    </example>

	    <example id="pbook">
	      <title>A (useful) script that recursively calls itself</title>
	      <programlisting>&pbook;</programlisting>
	    </example>

	    <example id="usrmnt">
	      <title>Another (useful) script that recursively calls itself</title>
	      <programlisting>&usrmnt;</programlisting>
	    </example>

	<caution><para>Too many levels of recursion can exhaust the
	  script's stack space, causing a segfault.</para></caution>

      </sect1> <!-- Recursion -->



      <sect1 id="colorizing">
        <title><quote>Colorizing</quote> Scripts</title>

	<para><anchor id="colorizingref"></para>

	<para>The ANSI
	   <footnote><para><acronym>ANSI</acronym> is, of course, the
	     acronym for the American National Standards
	     Institute. This august body establishes and maintains
	     various technical and industrial standards.</para></footnote>
	   escape sequences set screen attributes, such as bold
	   text, and color of foreground and background. <link
	   linkend="dosbatch1">DOS batch files</link> commonly used
	   ANSI escape codes for <emphasis>color</emphasis> output,
	   and so can Bash scripts.</para>

	    <example id="ex30a">
	      <title>A <quote>colorized</quote> address database</title>
	      <programlisting>&ex30a;</programlisting>
	    </example>

	    <example id="draw-box">
	      <title>Drawing a box</title>
	      <programlisting>&drawbox;</programlisting>
	    </example>


	<para>The simplest, and perhaps most useful ANSI escape sequence is
	  bold text, <command>\033[1m ... \033[0m</command>. The
	  <token>\033</token> represents an <link
	  linkend="escp">escape</link>, the <quote>[1</quote> turns on the
	  bold attribute, while the <quote>[0</quote> switches it off. The
	  <quote>m</quote> terminates each term of the escape sequence.
	      <screen>
<prompt>bash$ </prompt><userinput>echo -e "\033[1mThis is bold text.\033[0m"</userinput>
	      </screen>
	</para>

	<para>A similar escape sequence switches on the underline
	  attribute (on an <firstterm>rxvt</firstterm> and an
	  <firstterm>aterm</firstterm>).
	      <screen>
<prompt>bash$ </prompt><userinput>echo -e "\033[4mThis is underlined text.\033[0m"</userinput>
	      </screen>
	</para>

	<note><para>With an <command>echo</command>, the
	  <option>-e</option> option enables the escape
	  sequences.</para></note>

	<para>Other escape sequences change the text and/or background
	  color.</para>

	      <para>
	      <screen>
<prompt>bash$ </prompt><userinput>echo -e '\E[34;47mThis prints in blue.'; tput sgr0</userinput>


<prompt>bash$ </prompt><userinput>echo -e '\E[33;44m'"yellow text on blue background"; tput sgr0</userinput>


<prompt>bash$ </prompt><userinput>echo -e '\E[1;33;44m'"BOLD yellow text on blue background"; tput sgr0</userinput>
	      </screen>
	      </para>

	<note><para>It's usually advisable to set the
	  <firstterm>bold</firstterm> attribute for light-colored foreground
	  text.</para></note>

	      <para>The <command>tput sgr0</command> restores the
		terminal settings to normal. Omitting this lets all
	        subsequent output from that particular terminal remain
	        blue.</para>

              <note><para>Since <command>tput sgr0</command> fails to restore
	        terminal settings under certain circumstances,
		<command>echo -ne \E[0m</command> may be a better choice.</para></note>

	<para><anchor id="coloriztempl"></para>
	<sidebar>
	<para>Use the following template for writing colored text on a colored
	background.</para>

        <para>
	  <userinput>echo -e '\E[COLOR1;COLOR2mSome text goes here.'</userinput>
        </para>

	<para>The <quote>\E[</quote> begins the escape sequence.
	  The semicolon-separated numbers <quote>COLOR1</quote> and
	  <quote>COLOR2</quote> specify a foreground and a background
	  color, according to the table below. (The order of the
	  numbers does not matter, since the foreground and background
	  numbers fall in non-overlapping ranges.) The <quote>m</quote>
	  terminates the escape sequence, and the text begins immediately
	  after that.</para>

	<para>Note also that <link linkend="snglquo">single quotes</link>
	  enclose the remainder of the command sequence following the
	  <command>echo -e</command>.</para>
	</sidebar>


	<para>The numbers in the following table work for an
	  <firstterm>rxvt</firstterm> terminal. Results may vary for other
	  terminal emulators.</para>

      <para><anchor id="coloriztable"></para>
      <table>
	<title>Numbers representing colors in Escape Sequences</title>
	<tgroup cols="3">
	  <thead>
	    <row>
	      <entry>Color</entry>
	      <entry>Foreground</entry>
	      <entry>Background</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>black</option></entry>
	      <entry>30</entry>
	      <entry>40</entry>
	    </row>
	    <row>
	      <entry><option>red</option></entry>
	      <entry>31</entry>
	      <entry>41</entry>
	    </row>
	    <row>
	      <entry><option>green</option></entry>
	      <entry>32</entry>
	      <entry>42</entry>
	    </row>
	    <row>
	      <entry><option>yellow</option></entry>
	      <entry>33</entry>
	      <entry>43</entry>
	    </row>
	    <row>
	      <entry><option>blue</option></entry>
	      <entry>34</entry>
	      <entry>44</entry>
	    </row>
	    <row>
	      <entry><option>magenta</option></entry>
	      <entry>35</entry>
	      <entry>45</entry>
	    </row>
	    <row>
	      <entry><option>cyan</option></entry>
	      <entry>36</entry>
	      <entry>46</entry>
	    </row>
	    <row>
	      <entry><option>white</option></entry>
	      <entry>37</entry>
	      <entry>47</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>

	    <example id="colorecho">
	      <title>Echoing colored text</title>
	      <programlisting>&colorecho;</programlisting>
	    </example>

	<para><anchor id="horseraceref"></para>
	    <example id="horserace">
	      <title>A <quote>horserace</quote> game</title>
	      <programlisting>&horserace;</programlisting>
	    </example>

	<para>See also <xref linkend="hashexample">, <xref
	  linkend="homework">, and <xref linkend="petals">.</para>


	<caution><para>There is, however, a major problem with all
	  this. <emphasis>ANSI escape sequences are emphatically
	  non-portable.</emphasis> What works fine on some terminal
	  emulators (or the console) may work differently, or not
	  at all, on others. A <quote>colorized</quote> script that
	  looks stunning on the script author's machine may produce
	  unreadable output on someone else's. This somewhat compromises
	  the usefulness of colorizing scripts, and possibly relegates
	  this technique to the status of a gimmick. Colorized scripts
	  are probably inappropriate in a commercial setting, i.e., your
	  supervisor might disapprove.</para></caution>

	<para>Moshe Jacobson's <command>color</command> utility  
	  (<ulink
	  url="http://runslinux.net/projects.html#color">http://runslinux.net/projects.html#color</ulink>)
	  considerably simplifies using ANSI escape sequences. It
	  substitutes a clean and logical syntax for the clumsy constructs
	  just discussed.</para>

        <para>Henry/teikedvl has likewise created a utility (<ulink
          url="http://scriptechocolor.sourceforge.net/">http://scriptechocolor.sourceforge.net/</ulink>) to simplify creation of colorized scripts.</para>


      </sect1> <!-- "Colorizing" scripts -->



      <sect1 id="optimizations">
        <title>Optimizations</title>

	<para>Most shell scripts are quick 'n dirty solutions to non-complex
	  problems. As such, optimizing them for speed is not much of an
	  issue.  Consider the case, though, where a script carries out
	  an important task, does it well, but runs too slowly. Rewriting
	  it in a compiled language may not be a palatable option. The
	  simplest fix would be to rewrite the parts of the script
	  that slow it down. Is it possible to apply principles of code
	  optimization even to a lowly shell script?</para>

	<para>Check the loops in the script. Time consumed by repetitive
	  operations adds up quickly. If at all possible, remove
	  time-consuming operations from within loops.</para>

	<para>Use <link linkend="builtinref">builtin</link> commands in
	  preference to system commands. Builtins execute faster and
	  usually do not launch a subshell when invoked.</para>
	
	<para><anchor id="catabuse"></para>
	<para>Avoid unnecessary commands, particularly in a <link
	  linkend="piperef">pipe</link>.
	    <programlisting>cat "$file" | grep "$word"

grep "$word" "$file"

#  The above command lines have an identical effect,
#+ but the second runs faster since it launches one fewer subprocess.</programlisting>
	  The <link linkend="catref">cat</link> command seems especially
	  prone to overuse in scripts.</para>

	<para>Use the <link linkend="timref">time</link> and <link
	  linkend="timesref">times</link> tools to profile
	  computation-intensive commands. Consider rewriting time-critical
	  code sections in C, or even in assembler.</para>

	 <para>Try to minimize file I/O. Bash is not particularly
	   efficient at handling files, so consider using
	   more appropriate tools for this within the script,
	   such as <link linkend="awkref">awk</link> or <link
	   linkend="perlref">Perl</link>.</para>

	 <para>Write your scripts in a modular and coherent form,
	   <footnote><para>This usually means liberal use of
	   <link linkend="functionref">functions</link>.</para></footnote>
	   so they can be reorganized and tightened up as necessary. Some
	   of the optimization techniques applicable to high-level
	   languages may work for scripts, but others, such as
	   <firstterm>loop unrolling</firstterm>, are mostly
	   irrelevant. Above all, use common sense.</para>

	 <para>For an excellent demonstration of how optimization can
	   dramatically reduce the  execution time of a script, see <xref
	   linkend="monthlypmt">.</para>

      </sect1> <!-- Optimizations -->



      <sect1 id="assortedtips">
        <title>Assorted Tips</title>


      <sect2>
      <title>Ideas for more powerful scripts</title>

       <itemizedlist>

	<listitem>

	   <para><anchor id="pseudocoderef"></para>
	   <para>You have a problem that you want to solve by writing a Bash
	     script. Unfortunately, you don't know quite where to start.
	     One method is to plunge right in and code those parts
	     of the script that come easily, and write the hard parts as
	     <firstterm>pseudo-code</firstterm>.</para>

           <para><programlisting>#!/bin/bash

ARGCOUNT=1                     # Need name as argument.
E_WRONGARGS=65

if [ number-of-arguments is-not-equal-to "$ARGCOUNT" ]
#    ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
#  Can't figure out how to code this . . .
#+ . . . so write it in pseudo-code.

then
  echo "Usage: name-of-script name"
  #            ^^^^^^^^^^^^^^     More pseudo-code.
  exit $E_WRONGARGS
fi 

. . .

exit 0


# Later on, substitute working code for the pseudo-code.

# Line 6 becomes:
if [ $# -ne "$ARGCOUNT" ]

# Line 12 becomes:
  echo "Usage: `basename $0` name"</programlisting></para>

	   <para>For an example of using pseudo-code, see the <link
	     linkend="newtonsqrt">Square Root</link> exercise.</para>

	</listitem>


	<listitem>

	  <para><anchor id="trackingscr"></para>
	  <para>To keep a record of which user scripts have run
	    during a particular session or over a number of sessions,
	    add the following lines to each script you want to keep track
	    of. This will keep a continuing file record of the script
	    names and invocation times. </para>

	  <para>
	  <programlisting># Append (>>) following to end of each script tracked.

whoami>> $SAVE_FILE    # User invoking the script.
echo $0>> $SAVE_FILE   # Script name.
date>> $SAVE_FILE      # Date and time.
echo>> $SAVE_FILE      # Blank line as separator.

#  Of course, SAVE_FILE defined and exported as environmental variable in ~/.bashrc
#+ (something like ~/.scripts-run)</programlisting>
          </para>
	</listitem>

	<listitem>
	  <para><anchor id="prependref"></para>
	  <para>The <token>&gt;&gt;</token> operator
	    <firstterm>appends</firstterm> lines to a file.
	    What if you wish to <firstterm>prepend</firstterm> a
	    line to an existing file, that is, to paste it in at the
	    beginning?</para>

	  <para>
	  <programlisting>file=data.txt
title="***This is the title line of data text file***"

echo $title | cat - $file >$file.new
# "cat -" concatenates stdout to $file.
#  End result is
#+ to write a new file with $title appended at *beginning*.</programlisting>
	  </para>

	  <para>This is a simplified variant of the <xref
	    linkend="prependex"> script given earlier.	And, of course,
	    <link linkend="sedref">sed</link> can also do this.</para>


	</listitem>

	<listitem>
	  <para><anchor id="scriptasemb"></para>
	  <para>A shell script may act as an embedded command inside
	    another shell script, a <firstterm>Tcl</firstterm> or
	    <firstterm>wish</firstterm> script, or even a <link
	    linkend="makefileref">Makefile</link>. It can be invoked
	    as an external shell command in a C program using the
	    <replaceable>system()</replaceable> call, i.e.,
	   <replaceable>system("script_name");</replaceable>.</para>
	</listitem>

	<listitem>
	  <para><anchor id="setvaremb"></para>
          <para>Setting a variable to the contents of an embedded
	    <firstterm>sed</firstterm> or <firstterm>awk</firstterm>
	    script increases the readability of the surrounding <link
	    linkend="shwrapper">shell wrapper</link>. See <xref
	    linkend="mailformat"> and <xref linkend="coltotaler3">.</para>
	</listitem>

	<listitem>
          <para><anchor id="libroutines"></para>
	  <para>Put together files containing your favorite and most useful
	    definitions and functions.	As necessary,
	    <quote>include</quote> one or more of these
	    <quote>library files</quote> in scripts with either the
	    <link linkend="dotref">dot</link> (<command>.</command>)
	    or <link linkend="sourceref">source</link> command.</para>

	  <para>  
            <programlisting># SCRIPT LIBRARY
# ------ -------

# Note:
# No "#!" here.
# No "live code" either.


# Useful variable definitions

ROOT_UID=0             # Root has $UID 0.
E_NOTROOT=101          # Not root user error. 
MAXRETVAL=255          # Maximum (positive) return value of a function.
SUCCESS=0
FAILURE=-1



# Functions

Usage ()               # "Usage:" message.
{
  if [ -z "$1" ]       # No arg passed.
  then
    msg=filename
  else
    msg=$@
  fi

  echo "Usage: `basename $0` "$msg""
}  


Check_if_root ()       # Check if root running script.
{                      # From "ex39.sh" example.
  if [ "$UID" -ne "$ROOT_UID" ]
  then
    echo "Must be root to run this script."
    exit $E_NOTROOT
  fi
}  


CreateTempfileName ()  # Creates a "unique" temp filename.
{                      # From "ex51.sh" example.
  prefix=temp
  suffix=`eval date +%s`
  Tempfilename=$prefix.$suffix
}


isalpha2 ()            # Tests whether *entire string* is alphabetic.
{                      # From "isalpha.sh" example.
  [ $# -eq 1 ] || return $FAILURE

  case $1 in
  *[!a-zA-Z]*|"") return $FAILURE;;
  *) return $SUCCESS;;
  esac                 # Thanks, S.C.
}


abs ()                           # Absolute value.
{                                # Caution: Max return value = 255.
  E_ARGERR=-999999

  if [ -z "$1" ]                 # Need arg passed.
  then
    return $E_ARGERR             # Obvious error value returned.
  fi

  if [ "$1" -ge 0 ]              # If non-negative,
  then                           #
    absval=$1                    # stays as-is.
  else                           # Otherwise,
    let "absval = (( 0 - $1 ))"  # change sign.
  fi  

  return $absval
}


tolower ()             #  Converts string(s) passed as argument(s)
{                      #+ to lowercase.

  if [ -z "$1" ]       #  If no argument(s) passed,
  then                 #+ send error message
    echo "(null)"      #+ (C-style void-pointer error message)
    return             #+ and return from function.
  fi  

  echo "$@" | tr A-Z a-z
  # Translate all passed arguments ($@).

  return

# Use command substitution to set a variable to function output.
# For example:
#    oldvar="A seT of miXed-caSe LEtTerS"
#    newvar=`tolower "$oldvar"`
#    echo "$newvar"    # a set of mixed-case letters
#
# Exercise: Rewrite this function to change lowercase passed argument(s)
#           to uppercase ... toupper()  [easy].
}</programlisting>
          </para>

	</listitem>

	<listitem>
	  <para><anchor id="commenth"></para>
	  <para>Use special-purpose comment headers to increase clarity
	    and legibility in scripts.</para>
	  <para><programlisting>## Caution.
rm -rf *.zzy   ##  The "-rf" options to "rm" are very dangerous,
               ##+ especially with wild cards.

#+ Line continuation.
#  This is line 1
#+ of a multi-line comment,
#+ and this is the final line.

#* Note.

#o List item.

#> Another point of view.
while [ "$var1" != "end" ]    #> while test "$var1" != "end"</programlisting></para>
	
	</listitem>

	<listitem>
	  <para><anchor id="progbar"></para>
	  <para>Dotan Barak contributes template code for a
	  <firstterm>progress bar</firstterm> in a script.</para>

	    <example id="progressbar">
	      <title>A Progress Bar</title>
	      <programlisting>&progressbar;</programlisting>
	    </example>
	</listitem>
	
	<listitem>
	  <para><anchor id="comoutbl"></para>
	  <para>A particularly clever use of <link
	    linkend="testconstructs1">if-test</link> constructs
	    is for comment blocks.</para>
	      
	  <para>    
	      <programlisting>#!/bin/bash

COMMENT_BLOCK=
#  Try setting the above variable to some value
#+ for an unpleasant surprise.

if [ $COMMENT_BLOCK ]; then

Comment block --
=================================
This is a comment line.
This is another comment line.
This is yet another comment line.
=================================

echo "This will not echo."

Comment blocks are error-free! Whee!

fi

echo "No more comments, please."

exit 0</programlisting>
	  </para>    

	  <para>Compare this with <link linkend="cblock1">using  
	    here documents to comment out code blocks</link>.</para>    

	</listitem>

	<listitem>
	  <para><anchor id="intparam"></para>
	  <para>Using the <link linkend="xstatvarref">$? exit status
	    variable</link>, a script may test if a parameter contains
	    only digits, so it can be treated as an integer.</para>

	  <para>  
	    <programlisting>#!/bin/bash

SUCCESS=0
E_BADINPUT=65

test "$1" -ne 0 -o "$1" -eq 0 2>/dev/null
# An integer is either equal to 0 or not equal to 0.
# 2>/dev/null suppresses error message.

if [ $? -ne "$SUCCESS" ]
then
  echo "Usage: `basename $0` integer-input"
  exit $E_BADINPUT
fi

let "sum = $1 + 25"             # Would give error if $1 not integer.
echo "Sum = $sum"

# Any variable, not just a command line parameter, can be tested this way.

exit 0</programlisting>
          </para>
	</listitem>


        <listitem>

	  <para><anchor id="rvt">The 0 - 255 range for function return
	    values is a severe limitation. Global variables and
	    other workarounds are often problematic. An alternative
	    method for a function to communicate a value back to
	    the main body of the script is to have the function
	    write to <filename>stdout</filename> (usually with
	    <link linkend="echoref">echo</link>) the <quote>return
	    value,</quote> and assign this to a variable. This is
	    actually a variant of <link linkend="commandsubref">command
	    substitution.</link></para>

	    <example id="multiplication">
	      <title>Return value trickery</title>
	      <programlisting>&multiplication;</programlisting>
	    </example>

	  <para>The same technique also works for alphanumeric
	    strings. This means that a function can <quote>return</quote>
	    a non-numeric value.</para>
	    
	  <para>
	  <programlisting>capitalize_ichar ()          #  Capitalizes initial character
{                            #+ of argument string(s) passed.

  string0="$@"               # Accepts multiple arguments.

  firstchar=${string0:0:1}   # First character.
  string1=${string0:1}       # Rest of string(s).

  FirstChar=`echo "$firstchar" | tr a-z A-Z`
                             # Capitalize first character.

  echo "$FirstChar$string1"  # Output to stdout.

}  

newstring=`capitalize_ichar "every sentence should start with a capital letter."`
echo "$newstring"          # Every sentence should start with a capital letter.</programlisting> 
	  </para>

	  <para>It is even possible for a function to <quote>return</quote>
	    multiple values with this method.</para>

	    <example id="sumproduct">
	      <title>Even more return value trickery</title>
	      <programlisting>&sumproduct;</programlisting>
	    </example>

          <caution><para><anchor id="rvtcaution">There can be only
	    <command>one</command> <firstterm>echo</firstterm> statement
	    in the function for this to work. If you alter the previous
	    example:</para>

	      <para><programlisting>sum_and_product ()
{
  echo "This is the sum_and_product function." # This messes things up!
  echo $(( $1 + $2 )) $(( $1 * $2 ))
}
...
retval=`sum_and_product $first $second`      # Assigns output of function.
# Now, this will not work correctly.</programlisting></para></caution>


	</listitem>

        <listitem>
	  <para><anchor id="passarray"></para>
	  <para>Next in our bag of tricks are techniques for passing
	    an <link linkend="arrayref">array</link> to a
	    <link linkend="functionref">function</link>, then
	    <quote>returning</quote> an array back to the main body of
	    the script.</para>

	  <para>Passing an array involves loading the space-separated
	    elements of the array into a variable with <link
	    linkend="commandsubref">command substitution</link>. <anchor
	    id="retarray">Getting an array back as the <quote>return
	    value</quote> from a function uses the previously mentioned
	    strategem of <link linkend="echoref">echoing</link> the
	    array in the function, then invoking command substitution
	    and the <command>( ... )</command> operator to assign it to
	    an array.</para>

	    <example id="arrfunc">
	      <title>Passing and returning arrays</title>
	      <programlisting>&arrfunc;</programlisting>
	    </example>

	  <para>For a more elaborate example of passing arrays to
	    functions, see <xref linkend="lifeslow">.</para>

        </listitem>

        <listitem>
	  <para><anchor id="cstyle"></para>
	  <para>Using the <link linkend="dblparens">double-parentheses
	    construct</link>, it is possible to use C-style syntax
	    for setting and incrementing/decrementing variables
	    and in <link linkend="forloopref1">for</link> and <link
	    linkend="whileloopref">while</link> loops.	See <xref
	    linkend="forloopc"> and <xref linkend="whloopc">.</para>
	</listitem>

	<listitem>
	  <para><anchor id="setpum"></para>
	  <para>Setting the <link linkend="pathref">path</link> and <link
	    linkend="umaskref">umask</link> at the beginning of a script makes
	    it more <quote>portable</quote> -- more likely to run on a
	    <quote>foreign</quote> machine whose user may have bollixed up the
	    <varname>$PATH</varname> and <command>umask</command>.
	      <programlisting>#!/bin/bash
PATH=/bin:/usr/bin:/usr/local/bin ; export PATH
umask 022   # Files that the script creates will have 755 permission.

# Thanks to Ian D. Allen, for this tip.</programlisting></para>
	</listitem>

        <listitem>
	  <para><anchor id="filteroutp"></para>
	  <para>A useful scripting technique is to
	    <emphasis>repeatedly</emphasis> feed the output of a filter
	    (by piping) back to the <emphasis>same filter</emphasis>, but
	    with a different set of arguments and/or options. Especially
	    suitable for this are <link linkend="trref">tr</link> and
	    <link linkend="grepref">grep</link>.</para>

	  <para>
	  <programlisting># From "wstrings.sh" example.

wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \
tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '`</programlisting>
	  </para>

	    <example id="agram">
	      <title>Fun with anagrams</title>
	      <programlisting>&agram;</programlisting>
	    </example>

	  <para>See also <xref linkend="constat">, <xref
	    linkend="cryptoquote">, and <xref linkend="soundex">.</para>

	</listitem>

	<listitem>
	  <para><anchor id="commblahd"></para>
	  <para>Use <quote><link linkend="anonheredoc0">anonymous here
	    documents</link></quote> to comment out blocks of code,
	    to save having to individually comment out each line with
	    a <token>#</token>.  See <xref linkend="commentblock">.</para>
	</listitem>

	<listitem>
	  <para><anchor id="whatisref3"></para>
	  <para>Running a script on a machine that relies on a command
	    that might not be installed is dangerous. Use <link
	    linkend="whatisref">whatis</link> to avoid potential problems
	    with this.</para>

	  <para>
	    <programlisting>CMD=command1                 # First choice.
PlanB=command2               # Fallback option.

command_test=$(whatis "$CMD" | grep 'nothing appropriate')
#  If 'command1' not found on system , 'whatis' will return
#+ "command1: nothing appropriate."
#
#  A safer alternative is:
#     command_test=$(whereis "$CMD" | grep \/)
#  But then the sense of the following test would have to be reversed,
#+ since the $command_test variable holds content only if
#+ the $CMD exists on the system.
#     (Thanks, bojster.)


if [[ -z "$command_test" ]]  # Check whether command present.
then
  $CMD option1 option2       #  Run command1 with options.
else                         #  Otherwise,
  $PlanB                     #+ run command2. 
fi</programlisting>
          </para>
	</listitem>

	<listitem>

	  <para><anchor id="ifgrepfix"></para>
	  <para>An <link linkend="ifgrepref">if-grep test</link> may not
	    return expected results in an error case, when text is output to
	    <filename>stderr</filename>, rather that
	    <filename>stdout</filename>.
	      <programlisting>if ls -l nonexistent_filename | grep -q 'No such file or directory'
  then echo "File \"nonexistent_filename\" does not exist."
fi</programlisting></para>

          <para><link linkend="ioredirref">Redirecting</link>
	    <filename>stderr</filename> to <filename>stdout</filename> fixes
	    this.
	      <programlisting>if ls -l nonexistent_filename 2&gt;&1 | grep -q 'No such file or directory'
#                             ^^^^
  then echo "File \"nonexistent_filename\" does not exist."
fi

# Thanks, Chris Martin, for pointing this out.</programlisting></para>

	</listitem>


	<listitem>

      <para><anchor id="subshtmp">
        If you absolutely must access a subshell variable outside the
	subshell, here's a way to do it.
	  <programlisting>TMPFILE=tmpfile                  # Create a temp file to store the variable.

(   # Inside the subshell ...
inner_variable=Inner
echo $inner_variable
echo $inner_variable >>$TMPFILE  # Append to temp file.
)

    # Outside the subshell ...

echo; echo "-----"; echo
echo $inner_variable             # Null, as expected.
echo "-----"; echo

# Now ...
read inner_variable <$TMPFILE    # Read back shell variable.
rm -f "$TMPFILE"                 # Get rid of temp file.
echo "$inner_variable"           # It's an ugly kludge, but it works.</programlisting>
	</para>

	</listitem>


	<listitem>
	  <para><anchor id="runpartsref2"></para>
	  <para>The <link linkend="runpartsref">run-parts</link>
	    command is handy for running a set of command
	    scripts in a particular sequence, especially in
	    combination with <link linkend="cronref">cron</link> or
	    <link linkend="atref">at</link>.</para>
	</listitem>


	<listitem>
	  <para><anchor id="rcsref"></para>
	  <para>For doing multiple revisions on a complex script, use the
	    <firstterm>rcs</firstterm> Revision Control System package.</para>

	  <para> Among other benefits of this is automatically updated ID
	    header tags. The <command>co</command> command in
	    <firstterm>rcs</firstterm> does a parameter replacement of
	    certain reserved key words, for example, replacing
	    <parameter># $Id$</parameter> in a script with something like:
	      <programlisting># $Id: hello-world.sh,v 1.1 2004/10/16 02:43:05 bozo Exp $</programlisting></para>

	</listitem>

      </itemizedlist>

	</sect2>


	<sect2>
      <title>Widgets</title>

	  <para><anchor id="widgetref"></para>
	  <para>It would be nice to be able to invoke X-Windows widgets
	    from a shell script. There happen to exist several packages
	    that purport to do so, namely <firstterm>Xscript</firstterm>,
	    <firstterm>Xmenu</firstterm>, and <firstterm>widtools</firstterm>.
	    The first two of these no longer seem
	    to be maintained.  Fortunately, it is still
	    possible to obtain <firstterm>widtools</firstterm> <ulink
	    url="http://www.batse.msfc.nasa.gov/~mallozzi/home/software/xforms/src/widtools-2.0.tgz">here</ulink>.
	    </para>

	  <caution><para>The <firstterm>widtools</firstterm> (widget tools)
	    package requires the <firstterm>XForms</firstterm> library to
	    be installed. Additionally, the <link
	    linkend="makefileref">Makefile</link> needs some judicious
	    editing before the package will build on a typical Linux
	    system. Finally, three of the six widgets offered do not work
	    (and, in fact, segfault).</para></caution>


          <para><anchor id="dialogref"></para>

	  <para>The <firstterm>dialog</firstterm> family of tools offers a method
	    of calling <quote>dialog</quote> widgets from a shell script. The
	    original <firstterm>dialog</firstterm> utility works in a text
	    console, but its successors, <firstterm>gdialog</firstterm>,
	    <firstterm>Xdialog</firstterm>, and <firstterm>kdialog</firstterm>
	    use X-Windows-based widget sets.</para>

    <example id="dialog">
      <title>Widgets invoked from a shell script</title>
      <programlisting>&dialog;</programlisting>
    </example>

	  <para><anchor id="xmessageref2">
	    The <link linkend="xmessageref">xmessage</link> command is
	    a simple method of popping up a message/query window. For
	    example:
	      <programlisting>xmessage Fatal error in script! -button exit</programlisting>
	  </para>

	  <para><anchor id="zenityref2">
	    The latest entry in the widget sweepstakes is
	    <link linkend="zenityref">zenity</link>.
	    This utility pops up
	    <firstterm>GTK+</firstterm> dialog widgets-and-windows,
	    and it works very nicely within a script.
	      <programlisting>get_info ()
{
  zenity --entry       #  Pops up query window . . .
                       #+ and prints user entry to stdout.

                       #  Also try the --calendar and --scale options.
}

answer=$( get_info )   #  Capture stdout in $answer variable.

echo "User entered: "$answer""</programlisting>
	  </para>

	  <para>For other methods of scripting with widgets, try
	    <firstterm>Tk</firstterm> or <firstterm>wish</firstterm>
	    (<firstterm>Tcl</firstterm> derivatives),
	    <firstterm>PerlTk</firstterm> (<firstterm>Perl</firstterm>
	    with <firstterm>Tk</firstterm> extensions),
	    <firstterm>tksh</firstterm> (<firstterm>ksh</firstterm>
	    with <firstterm>Tk</firstterm> extensions),
	    <firstterm>XForms4Perl</firstterm>
	    (<firstterm>Perl</firstterm> with
	    <firstterm>XForms</firstterm> extensions),
	    <firstterm>Gtk-Perl</firstterm> (<firstterm>Perl</firstterm>
	    with <firstterm>Gtk</firstterm> extensions), or
	    <firstterm>PyQt</firstterm> (<firstterm>Python</firstterm>
	    with <firstterm>Qt</firstterm> extensions).</para>

	</sect2>



      </sect1> <!-- Assorted Tips -->



      <sect1 id="securityissues">
        <title>Security Issues</title>

      <sect2 id="infectedscripts">
        <title>Infected Shell Scripts</title>

	<para><anchor id="infectedscripts1"></para>
	<para>A brief warning about script security is indicated.
	  A shell script may contain a <firstterm>worm</firstterm>,
	  <firstterm>trojan</firstterm>, or even a
	  <firstterm>virus</firstterm>. For that reason, never run
	  as <firstterm>root</firstterm> a script (or permit it to
	  be inserted into the system startup scripts in <filename
	  class="directory">/etc/rc.d</filename>) unless you have obtained
	  said script from a trusted source or you have carefully analyzed
	  it to make certain it does nothing harmful.</para>

	<para>Various researchers at Bell Labs and other sites, including M.
	  Douglas McIlroy, Tom Duff, and Fred Cohen have investigated the
	  implications of shell script viruses. They conclude that it is
	  all too easy for even a novice, a <quote>script kiddie,</quote>
	  to write one.
	    <footnote><para>See Marius van Oers' article, <ulink
	      url="http://www.virusbtn.com/magazine/archives/200204/malshell.xml">Unix
	      Shell Scripting Malware</ulink>, and also the
	      <link linkend="denningref"><emphasis>Denning</emphasis>
	      reference</link> in the
	      <firstterm>bibliography</firstterm>.</para></footnote>
	  </para>

	<para>Here is yet another reason to learn scripting. Being able to
	  look at and understand scripts may protect your system from
	  being compromised by a rogue script.</para>

     </sect2> <!-- Infected Shell Scripts -->

      <sect2 id="hidingsource">
        <title>Hiding Shell Script Source</title>

	<para>For security purposes, it may be necessary to render a script
	  unreadable. If only there were a utility to create a stripped
	  binary executable from a script. Francisco Rosales' <ulink
	  url="http://www.datsi.fi.upm.es/~frosal/sources/">shc --
	  generic shell script compiler</ulink> does exactly that.</para>

	<para>Unfortunately, according to <ulink
	 url="http://www.linuxjournal.com/article/8256">an article</ulink> in
	 the October, 2005 <emphasis>Linux Journal</emphasis>,
	 the binary can, in at least some cases, be decrypted to recover
	 the original script source. Still, this could be a useful
	 method of keeping scripts secure from all but the most skilled
	 hackers.</para>

     </sect2> <!-- Hiding Shell Script Source -->


      <sect2 id="securitytips">
        <title>Writing Secure Shell Scripts</title>

	<para><anchor id="securitytips1"></para>
	<para><emphasis>Dan Stromberg</emphasis> suggests the following
	  guidelines for writing (relatively) secure shell scripts.</para>

        <para>
         <itemizedlist>

	  <listitem>
	    <para>Don't put secret data in <link
	      linkend="envref">environment variables</link>.</para>
	  </listitem>

	  <listitem>
	    <para>Don't pass secret data in an external
	      command's arguments (pass them in via a <link
	      linkend="piperef">pipe</link> or <link
	      linkend="ioredirref">redirection</link> instead).</para>
	  </listitem>

	  <listitem>
	    <para>Set your <link linkend="pathref">$PATH</link>
	      carefully. Don't just trust whatever path you
	      inherit from the caller if your script is running as
	      <firstterm>root</firstterm>. In fact, whenever you use
	      an environment variable inherited from the caller, think
	      about what could happen if the caller put something
	      misleading in the variable, e.g., if the caller set
	      <link linkend="homedirref">$HOME</link> to <filename
	      class="directory">/etc</filename>.</para>
	  </listitem>

         </itemizedlist>
        </para>

     </sect2> <!-- Security Tips -->

      </sect1> <!-- Security -->



      <sect1 id="portabilityissues">
        <title>Portability Issues</title>

	<para>This book deals specifically with Bash scripting on
	  a GNU/Linux system. All the same, users of <command>sh</command>
	  and <command>ksh</command> will find much of value here.</para>

	<para><anchor id="posix3ref">As it happens, many of the various
	  shells and scripting languages seem to be converging toward the
	  <link linkend="posix2ref">POSIX</link> 1003.2 standard. Invoking
	  Bash with the <option>--posix</option> option or inserting
	  a <command>set -o posix</command> at the head of a script
	  causes Bash to conform very closely to this standard. Another
	  alternative is to use a <firstterm>#!/bin/sh</firstterm> <link
	  linkend="shabangref">sha-bang header</link> in the script,
	  rather than <firstterm>#!/bin/bash</firstterm>.

	    <footnote><para>Or, better yet, <link
	    linkend="envv2ref">#!/bin/env sh</link>.</para></footnote>

	  Note that <filename>/bin/sh</filename> is a <link
	  linkend="linkref">link</link> to <filename>/bin/bash</filename>
	  in Linux and certain other flavors of UNIX, and a script invoked
	  this way disables extended Bash functionality.</para>

	<para>Most Bash scripts will run as-is under
	  <command>ksh</command>, and vice-versa, since Chet Ramey has
	  been busily porting <command>ksh</command> features to the
	  latest versions of Bash.</para>

	<para>On a commercial UNIX machine, scripts using GNU-specific
	  features of standard commands may not work. This has become less
	  of a problem in the last few years, as the GNU utilities have
	  pretty much displaced their proprietary
	  counterparts even on <quote>big-iron</quote> UNIX.
	  <ulink url="http://linux.oreillynet.com/pub/a/linux/2002/02/28/caldera.html">Caldera's
	  release of the source</ulink> to many of the original UNIX
	  utilities has accelerated the trend.</para>

	<para><anchor id="bashcompat"></para>
	<para>Bash has certain features that the traditional Bourne shell
	  lacks. Among these are:

	<itemizedlist>

	<listitem>
	<para>Certain extended <link
	linkend="invocationoptionsref">invocation options</link></para>
	</listitem>

        <listitem>
	<para><link linkend="commandsubref">Command substitution</link> using
	  <command>$(    )</command> notation</para>
	</listitem>

	<listitem>
	<para>The <link linkend="dblbrackets">double brackets</link>
	  extended test construct</para>
	</listitem>

	<listitem>
	<para>The <link linkend="dblparensref">double-parentheses</link>
	  arithmetic-evaluation construct</para>
	</listitem>

	<listitem>
	<para>Certain <link linkend="stringmanip">string manipulation</link>
	  operations</para>
	</listitem>

	<listitem>
	<para><link linkend="processsubref">Process substitution</link></para>
	</listitem>

	<listitem>
	<para>A Regular Expression <link linkend="regexmatchref">matching
	  operator</link></para>
	</listitem>

	<listitem>
	<para>Bash-specific <link linkend="builtinref">builtins</link></para>
	</listitem>

	</itemizedlist>
	</para>

	<para>See the <ulink url="ftp://ftp.cwru.edu/pub/bash/FAQ">Bash
	   F.A.Q.</ulink> for a complete listing.</para>

      </sect1> <!-- Portability Issues -->



      <sect1 id="winscript">
        <title>Shell Scripting Under Windows</title>

	<para>Even users running <emphasis>that other</emphasis> OS can
	  run UNIX-like shell scripts, and therefore benefit
	  from many of the lessons of this book. The <ulink
	  url="http://sourceware.cygnus.com/cygwin/">
	  Cygwin</ulink> package from Cygnus and the <ulink
	  url="http://www.mkssoftware.com/">MKS utilities</ulink> from
	  Mortice Kern Associates add shell scripting capabilities to
	  Windows.</para>

        <para>There have been intimations that a future release of Windows
	  will contain Bash-like command line scripting capabilities,
	  but that remains to be seen.</para>

      </sect1> <!-- Shell Scripting Under Windows -->



  </chapter> <!-- Miscellany -->



  <chapter id="bash2">
    <title>Bash, versions 2 and 3</title>

    <sect1 id="bashver2">
      <title>Bash, version 2</title>

      <para><anchor id="bash2ref"></para>

      <para>
        The current version of <firstterm>Bash</firstterm>, the one
	you have running on your machine, is most likely version 2.xx.yy
	or 3.xx.yy.
	      <screen><prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
<computeroutput>3.2.25(1)-release</computeroutput>
	      </screen>
      </para>

      <para>The  version 2 update of the classic Bash scripting language
        added array variables,

	  <footnote><para>Chet Ramey has promised associative arrays
	  (a nifty Perl feature) in a future Bash release. As of version
	  3.2, this has not yet happened.</para></footnote>

	string and parameter expansion, and a better method
	of indirect variable references, among other features.</para>

      <example id="ex77">
	<title>String expansion</title>
	<programlisting>&ex77;</programlisting>
      </example>

      <para><anchor id="varrefnew"></para>
      <example id="ex78">
	<title>Indirect variable references - the new way</title>
	<programlisting>&ex78;</programlisting>
      </example>
	
      <example id="resistor">
	<title>Simple database application, using indirect variable
	  referencing</title>
	<programlisting>&resistor;</programlisting>
      </example>

      <example id="cards">
	<title>Using arrays and other miscellaneous trickery
	  to deal four random hands from a deck of cards</title>
	<programlisting>&cards;</programlisting>
      </example>

    </sect1> <!-- Bash, Version 2 -->



    <sect1 id="bashver3">
      <title>Bash, version 3</title>

      <para><anchor id="bash3ref"></para>

      <para>On July 27, 2004, Chet Ramey released version 3 of Bash.
        This update fixed quite a number of bugs and added new
        features.</para>

      <para>Some of the more important added features:

      <itemizedlist>
	<listitem>
	  <para><anchor id="braceexpref3"></para>
	  <para>A new, more generalized <command>{a..z}</command> <link
	  linkend="braceexpref">brace expansion</link> operator.</para>

          <para><programlisting>#!/bin/bash

for i in {1..10}
#  Simpler and more straightforward than
#+ for i in $(seq 10)
do
  echo -n "$i "
done

echo

# 1 2 3 4 5 6 7 8 9 10



# Or just . . .

echo {a..z}    #  a b c d e f g h i j k l m n o p q r s t u v w x y z
echo {z..a}    #  z y x w v u t s r q p o n m l k j i h g f e d c b a
               #  Works backwards, too.
echo {3..-2}   #  3 2 1 0 -1 -2
echo {X..d}    #  X Y Z [  ] ^ _ ` a b c d
               #  Shows (some of) the ASCII characters between Z and a,
               #+ but don't rely on this type of behavior because . . .
echo {]..a}    #  {]..a}
               #  Why?</programlisting></para>

	</listitem>


	<listitem>
	  <para>The <command>${!array[@]}</command> operator, which
	    expands to all the indices of a given <link
	    linkend="arrayref">array</link>.</para>

	   <para><programlisting>#!/bin/bash

Array=(element-zero element-one element-two element-three)

echo ${Array[0]}   # element-zero
                   # First element of array.

echo ${!Array[@]}  # 0 1 2 3
                   # All the indices of Array.

for i in ${!Array[@]}
do
  echo ${Array[i]} # element-zero
                   # element-one
                   # element-two
                   # element-three
                   #
                   # All the elements in Array.
done</programlisting></para>

	</listitem>


	<listitem>
	  <para><anchor id="regexmatchref"></para>
	  <para>The <command>=~</command> <link linkend="regexref">Regular
	    Expression</link> matching operator within a <link
	    linkend="dblbrackets">double brackets</link> test expression.
	    (Perl has a similar operator.)</para>

	      <para><programlisting>#!/bin/bash

variable="This is a fine mess."

echo "$variable"

# Regex matching with =~ operator within [[ double brackets ]].
if [[ "$variable" =~ "T.........fin*es*" ]]
#                    ^                 ^
# NOTE: Quoting not necessary, as of version 3.2 of Bash.
then
  echo "match found"
      # match found
fi</programlisting></para>

              <para>Or, more usefully:</para>

	      <para><programlisting>#!/bin/bash

input=$1


if [[ "$input" =~ "[1-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]" ]]
#                 ^ NOTE: Quoting not necessary, as of version 3.2 of Bash.
# NNN-NN-NNNN (where each N is a digit). Initial digit must not be 0.
then
  echo "Social Security number."
  # Process SSN.
else
  echo "Not a Social Security number!"
  # Or, ask for corrected input.
fi</programlisting></para>

              <para>For additional examples of using the
                <command>=~</command> operator, see <xref linkend="whx">,
                <xref linkend="mailboxgrep">, <xref
                linkend="findsplit">, and <xref linkend="tohtml">.</para>


	</listitem>

	<listitem>
	  <para><anchor id="pipefailref"></para>
	  <para>The new <option>set -o pipefail</option> option is
	    useful for debugging <link linkend="piperef">pipes</link>. If
	    this option is set, then the <link
	    linkend="exitstatusref">exit status</link> of a pipe
	    is the exit status of the last command in the pipe to
	    <emphasis>fail</emphasis> (return a non-zero value), rather
	    than the actual final command in the pipe.</para>
	  <para>See <xref linkend="fc4upd">.</para>
	</listitem>


      </itemizedlist>
      </para>

      <caution>
      <para>The update to version 3 of Bash breaks a few scripts
        that worked under earlier versions. <emphasis>Test critical legacy
	scripts to make sure they still work!</emphasis></para>
      <para>As it happens, a couple of the scripts in the
        <emphasis>Advanced Bash Scripting Guide</emphasis> had to be
        fixed up (see <xref linkend="objoriented">
        and <xref linkend="tout">, for instance).</para>
      </caution>


       <sect2> <!-- Bash, Version 3.1 -->
         <title>Bash, version 3.1</title>

	 <para>The version 3.1 update of Bash introduces a number of bugfixes
	   and a few minor changes.</para>

          <itemizedlist>

	    <listitem>
	      <para>The <token>+=</token> operator is now permitted in
	        in places where previously only the <token>=</token>
		assignment operator was recognized.</para>

              <para><anchor id="pluseqstr"></para>

	      <para><programlisting>a=1
echo $a        # 1

a+=5           # Won't work under versions of Bash earlier than 3.1.
echo $a        # 15

a+=Hello
echo $a        # 15Hello</programlisting>
	      </para>

	      <para>Here, <token>+=</token> functions as a <firstterm>string
		concatenation</firstterm> operator. Note that its behavior
		in this particular context is different than within a
		<link linkend="letref">let</link> construct.</para>

	      <para><programlisting>a=1
echo $a        # 1

let a+=5       # Integer arithmetic, rather than string concatenation.
echo $a        # 6

let a+=Hello   # Doesn't "add" anything to a.
echo $a        # 6</programlisting>
	      </para>

	    </listitem>

          </itemizedlist>


       </sect2> <!-- Bash, Version 3.1 -->



       <sect2> <!-- Bash, Version 3.2 -->
         <title>Bash, version 3.2</title>

	 <para>This is pretty much a bugfix update.</para>

          <itemizedlist>

	    <listitem>
	      <para>In <link linkend="psglob"><firstterm>global</firstterm>
	        parameter substitutions</link>, the pattern no longer anchors
		at the start of the string.</para>
	    </listitem>

	    <listitem>
	      <para>The <option>--wordexp</option> option disables
	        <link linkend="processsubref">process substitution</link>.</para>
	    </listitem>

	    <listitem>
              <para>The <command>=~</command> <link
                linkend="regexmatchref">Regular Expression
                match operator</link> no longer requires
                <link linkend="quotingref">quoting</link> of the
                <firstterm>pattern</firstterm> within <link
                linkend="dblbrackets">[[ ... ]]</link>.</para>
		
              <caution>
	        <para>In fact, quoting in this context is
		<emphasis>not</emphasis> advisable as it may
		cause <firstterm>regex</firstterm> evaluation to fail.
	        See the <ulink
		url="https://bugs.launchpad.net/ubuntu-website/+bug/109931">
		Ubuntu Bug List</ulink>
		and <ulink
		url="http://en.wikinerds.org/index.php/Bash_syntax_and_semantics">
		Wikinerds on Bash syntax</ulink>.</para>
		<para>With Bash version 3.2.25(1), running on Fedora Core,
		quoting works, but do not assume this will be the case on
		<emphasis>your</emphasis> machine.</para>
              </caution>

	    </listitem>

          </itemizedlist>

       </sect2> <!-- Bash, Version 3.2 -->




    </sect1> <!-- Bash, Version 3 -->

  </chapter> <!-- Bash, versions 2 and 3 -->

  </part> <!-- Part 5 (Advanced Topics) -->



  <chapter id="endnotes">
    <title>Endnotes</title>


    <sect1 id="authorsnote">
      <title>Author's Note</title>

    <epigraph>
      <para><foreignphrase>doce ut discas</foreignphrase></para>
      <para>(Teach, that you yourself may learn.)</para>
    </epigraph>


      <para>How did I come to write a Bash scripting book? It's a strange
	tale. It seems that a few years back I needed to learn
	shell scripting -- and what better way to do that than to read a
	good book on the subject? I was looking to buy a tutorial and
	reference covering all aspects of the subject. I was looking for a
	book that would take difficult concepts, turn them inside out, and
	explain them in excruciating detail, with well-commented examples.
	    <footnote><para>This is the notorious <emphasis>flog it to
	      death</emphasis> technique.</para></footnote>
	In fact, I was looking for <emphasis>this very book</emphasis>,
	or something very much like it. Unfortunately, <link
	linkend="kochanref">it didn't exist</link>, and if I wanted it,
	I'd have to write it.  And so, here we are, folks.</para>

      <para>That reminds me of the apocryphal story about a mad
        professor. Crazy as a loon, the fellow was. At the sight of a
        book, any book -- at the library, at a bookstore, anywhere --
        he would become totally obsessed with the idea that he could have
        written it, should have written it -- and done a better job of it
        to boot. He would thereupon rush home and proceed to do just that,
        write a book with the very same title. When he died some years
        later, he allegedly had several thousand books to his credit,
        probably putting even Asimov to shame. The books might not have
        been any good, who knows, but does that really matter? Here's
        a fellow who lived his dream, even if he was obsessed by it,
        driven by it . . . and somehow I can't help admiring the old
        coot.</para>

    </sect1> <!-- Author's Note -->


    
    <sect1 id="aboutauthor">
      <title>About the Author</title>
      <subtitle>Who is this guy anyhow?</subtitle>

      <para>The author claims no credentials or special qualifications,
          <footnote><para>In fact, he is a school dropout
          and has no formal credentials or qualifications
          whatsoever.</para></footnote>
	other than a compulsion to write.
          <footnote><para>Those who can, do. Those who can't . . . get an
	  MCSE.</para></footnote>
	This book is somewhat of a departure from his other major work,
	<ulink url="http://personal.riverusers.com/~thegrendel/hmw60.zip">
	HOW-2 Meet Women: The Shy Man's Guide to
	Relationships</ulink>. He has also written the <ulink
	url="http://tldp.org/HOWTO/Software-Building-HOWTO.html">Software-Building
	HOWTO</ulink>. Of late, he has been trying his (heavy) hand at
	short fiction.</para>

      <para>A Linux user since 1995 (Slackware 2.2, kernel 1.2.1),
	the author has emitted a few
	software truffles, including the <ulink
	url="http://ibiblio.org/pub/Linux/utils/file/cruft-0.2.tar.gz">cruft</ulink>
	one-time pad encryption utility, the <ulink
	url="http://ibiblio.org/pub/Linux/apps/financial/mcalc-1.6.tar.gz">mcalc</ulink>
	mortgage calculator, the <ulink
	url="http://ibiblio.org/pub/Linux/games/amusements/judge-1.0.tar.gz">judge</ulink>
	Scrabble&reg; adjudicator, the <ulink
	url="http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz">yawl</ulink>
	word gaming list package, and the <ulink
	url="http://personal.riverusers.com/~thegrendel/qky.README.html">Quacky</ulink>
	anagramming gaming package. He got off to a rather shaky start in the
	computer game -- programming FORTRAN IV on a CDC 3800 --
	and is not the least bit nostalgic for those days.</para>

       <para>Living in a secluded desert community with wife and orange
         tabby, he cherishes human frailty, especially his own.
	   <footnote><para>Sometimes it seems as if he has spent
	   his entire life flouting conventional wisdom and defying the
	   sonorous Voice of Authority: <quote><emphasis>Hey, you
	   can't do that!</emphasis></quote></para></footnote>
	 </para>

    </sect1> <!-- About the Author -->



    <sect1 id="wherehelp">
      <title>Where to Go For Help</title>

       <para><ulink url="mailto:thegrendel@theriver.com">The author</ulink>
	 will sometimes, if not too busy (and in a good mood),
	 answer general scripting questions.
	   <footnote><para>E-mails from certain spam-infested TLDs
	   (61, 202, 211, 218, 220, etc.) will be trapped by spam
	   filters and deleted unread. If your ISP is located on
	   one of these, please use a Webmail account to contact the
	   author.</para></footnote>
	 However, if you have a problem getting a specific script
	 to work, you would be well advised to post to the <ulink
	 url="news:comp.unix.shell">comp.os.unix.shell</ulink> Usenet
	 newsgroup.</para>

       <para>
         If you need assistance with a schoolwork assignment, read
	 the pertinent sections of this and other reference works.
	 Do your best to solve the problem using your own wits and
	 resources. Kindly do not waste the author's time. You will get
	 neither help nor sympathy.
	   <footnote><para>Well, if you <emphasis>absolutely</emphasis>
	   insist, you can try modifying <xref linkend="homework"> to suit
	   your purposes.</para></footnote>
       </para>

    </sect1> <!-- Where to Go For Help -->



    <sect1 id="toolsused">
      <title>Tools Used to Produce This Book</title>


     <sect2 id="software-hardware">
       <title>Hardware</title>

       <para>A used IBM Thinkpad, model 760XL laptop (P166, 104 meg RAM)
	 running Red Hat 7.1/7.3. Sure, it's slow and has a funky
	 keyboard, but it beats the heck out of a No. 2 pencil and a
	 Big Chief tablet.</para>
	 
	 <para>
	   <emphasis>Update:</emphasis> upgraded to a
	   770Z Thinkpad (P2-366, 192 meg RAM) running FC3. Anyone
	   feel like donating a later-model laptop to a starving writer
	   &lt;g&gt;?
	 </para>

	 <para>
	   <emphasis>Update:</emphasis> upgraded to a A31 Thinkpad (P4-1.6,
	   512 meg RAM) running FC8. No longer starving, and no longer
	   soliciting donations &lt;g&gt;.
	 </para>

     </sect2> <!-- Hardware -->


     <sect2 id="software-printware">
       <title>Software and Printware</title>

      <orderedlist id="software-printware2" numeration="lowerroman">

        <listitem>
	<para>Bram Moolenaar's powerful SGML-aware <ulink
	url="http://www.vim.org">vim</ulink> text editor.</para>
	</listitem>

	<listitem>
	<para><ulink
	url="http://www.netfolder.com/DSSSL/">OpenJade</ulink>,
	a DSSSL rendering engine for converting SGML documents into other
	formats.</para>
	</listitem>

	<listitem>
	<para><ulink url="http://nwalsh.com/docbook/dsssl/"> Norman
	Walsh's DSSSL stylesheets</ulink>.</para>
	</listitem>

	<listitem>
	<para><citetitle pubwork="book">DocBook, The Definitive
	  Guide</citetitle>, by Norman Walsh and Leonard Muellner
	  (O'Reilly, ISBN 1-56592-580-7). This is still the standard
	  reference for anyone attempting to write a document in Docbook
	  SGML format.</para>
	</listitem>

      </orderedlist>

     </sect2> <!-- Software and Printware -->

    </sect1> <!-- Tools Used -->



    <sect1 id="credits">
      <title>Credits</title>

      <para><emphasis>Community participation made this project
        possible.</emphasis> The author gratefully acknowledges that
	writing this book would have been unthinkable without
	help and feedback from all you people out there.</para>

      <para><ulink url="mailto:feloy@free.fr">Philippe Martin</ulink>
	translated the first version (0.1) of this document into
	DocBook/SGML. While not on the job at a small French company as a
	software developer, he enjoys working on GNU/Linux documentation
	and software, reading literature, playing music, and, for his
	peace of mind, making merry with friends. You may run across him
	somewhere in France or in the Basque Country, or you can email him
	at <ulink url="mailto:feloy@free.fr">feloy@free.fr</ulink>.</para>

      <para>Philippe Martin also pointed out that positional parameters
	past $9 are possible using {bracket} notation. (See <xref
	linkend="ex17">).</para>

      <para><ulink url="mailto:stephane_chazelas@yahoo.fr">St&eacute;phane
	Chazelas</ulink> sent a long list of corrections, additions,
	and example scripts. More than a contributor, he had, in effect,
	for a while taken on the role of <emphasis>co-editor</emphasis>
	for this document. <foreignphrase>Merci
	beaucoup!</foreignphrase></para>

      <para>Paulo Marcel Coelho Aragao offered many corrections, both major
        and minor, and contributed quite a number of helpful
        suggestions.</para>

      <para>I would like to especially thank <emphasis>Patrick
        Callahan</emphasis>, <emphasis>Mike Novak</emphasis>, and
        <emphasis>Pal Domokos</emphasis> for catching bugs, pointing out
        ambiguities, and for suggesting clarifications and changes in the
	preliminary version (0.1) of this document. Their lively
	discussion of shell scripting and general documentation issues
	inspired me to try to make this document more readable.</para>

      <para>I'm grateful to Jim Van Zandt for pointing out errors and
        omissions in version 0.2 of this document. He also contributed
        an instructive <link linkend="zfifo">example script</link>.</para>

      <para>Many thanks to <ulink
        url="mailto:mikaku@fiwix.org">Jordi Sanfeliu</ulink>
        for giving permission to use his fine tree script (<xref
        linkend="tree">), and to Rick Boivie for revising it.</para>

      <para>Likewise, thanks to <ulink
        url="mailto:charpov@cs.unh.edu">Michel Charpentier</ulink> for
	permission to use his <link linkend="dcref">dc</link> factoring script
	(<xref linkend="factr">).</para>

      <para>Kudos to <ulink
        url="mailto:friedman@prep.ai.mit.edu">Noah Friedman</ulink>
        for permission to use his string function script (<xref
        linkend="string">).</para>

      <para><ulink url="mailto:emmanuel.rouat@wanadoo.fr">Emmanuel
        Rouat</ulink> suggested corrections and additions on
	<link linkend="commandsubref">command substitution</link> and
	<link linkend="aliasref">aliases</link>.  He also contributed
	a very nice sample <filename>.bashrc</filename> file (<xref
	linkend="sample-bashrc">).</para>

      <para><ulink url="mailto:heiner.steven@odn.de">Heiner Steven</ulink>
	kindly gave permission to use his base conversion script, <xref
	linkend="base">. He also made a number of corrections and many
	helpful suggestions. Special thanks.</para>

      <para>Rick Boivie contributed the delightfully recursive
	<emphasis>pb.sh</emphasis> script (<xref linkend="pbook">),
	revised the <emphasis>tree.sh</emphasis> script (<xref
	linkend="tree">), and suggested performance improvements
	for the <emphasis>monthlypmt.sh</emphasis> script (<xref
	linkend="monthlypmt">).</para>

      <para>Florian Wisser enlightened me on some of the fine points of
	testing strings (see <xref linkend="strtest">), and on other
	matters.</para>

      <para>Oleg Philon sent suggestions concerning <link
        linkend="cutref">cut</link> and <link
        linkend="pidofref">pidof</link>.</para>

      <para>Michael Zick extended the <link linkend="emptyarray">empty
	array</link> example to demonstrate some surprising array
	properties. He also contributed the <emphasis>isspammer</emphasis>
	scripts (<xref linkend="isspammer"> and <xref
	linkend="isspammer2">).</para>

      <para>Marc-Jano Knopp sent corrections and clarifications on DOS
        batch files.</para>

      <para>Hyun Jin Cha found several typos in the document in the
        process of doing a Korean translation. Thanks for pointing
        these out.</para>

      <para>Andreas Abraham sent in a long list of typographical
	errors and other corrections. Special thanks!</para>

      <para>Others contributing scripts, making helpful suggestions, and
	pointing out errors were Gabor Kiss, Leopold Toetsch,
	Peter Tillier, Marcus Berglof, Tony Richardson, Nick Drage
	(script ideas!), Rich Bartell, Jess Thrysoee, Adam Lazur, Bram
	Moolenaar, Baris Cicek, Greg Keraunen, Keith Matthews, Sandro
	Magi, Albert Reiner, Dim Segebart, Rory Winston, Lee Bigelow,
	Wayne Pollock, <quote>jipe,</quote> <quote>bojster,</quote>
	<quote>nyal,</quote> <quote>Hobbit,</quote> <quote>Ender,</quote>
	<quote>Little Monster</quote> (Alexis), <quote>Mark,</quote>
	<quote>Patsie,</quote> Peggy Russell, Emilio Conti, Ian. D. Allen,
	Hans-Joerg Diers, Arun Giridhar, Dennis Leeuw, Dan Jacobson,
	Aurelio Marinho Jargas, Edward Scholtz, Jean Helou, Chris Martin,
	Lee Maschmeyer, Bruno Haible, Wilbert Berendsen, Sebastien Godard,
	Bj&ouml;n Eriksson, John MacDonald, Joshua Tschida, Troy Engel,
	Manfred Schwarb, Amit Singh, Bill Gradwohl, E. Choroba, David
	Lombard, Jason Parker, Steve Parker, Bruce W. Clare, William Park,
	Vernia Damiano, Mihai Maties, Mark Alexander, Jeremy Impson,
	Ken Fuchs, Jared Martin, Frank Wang, Sylvain Fourmanoit, Matthew
	Sage, Matthew Walker, Kenny Stauffer, Filip Moritz, Andrzej
	Stefanski, Daniel Albers, Stefano Palmeri, Nils Radtke, Serghey
	Rodin, Jeroen Domburg, Alfredo Pironti, Phil Braham, Bruno de
	Oliveira Schneider, Stefano Falsetto, Chris Morgan, Walter Dnes,
	Linc Fessenden, Michael Iatrou, Pharis Monalo, Jesse Gough,
	Fabian Kreutz, Mark Norman, Harald Koenig, Dan Stromberg, Peter
	Knowles, Francisco Lobo, Mariusz Gniazdowski, Sebastian Arming,
	Benno Schulenberg, Tedman Eng, Jochen DeSmet, Juan Nicolas Ruiz,
	Oliver Beckstein, Achmed Darwish, Dotan Barak, Richard Neill,
	Albert Siersema, Omair Eshkenazi, Geoff Lee, JuanJo Ciarlante,
	Cliff Bamford, Nathan Coulter, Antonio Macchi, Andreas K&uuml;hne,
	P&aacute;draig Brady, and David Lawyer (himself an author of
	four HOWTOs).</para>

      <para>My gratitude to <ulink url="mailto:chet@po.cwru.edu">Chet
	Ramey</ulink> and Brian Fox for writing <firstterm>Bash</firstterm>,
	and building into it elegant and powerful scripting
	capabilities rivaling those of <firstterm>ksh</firstterm>.</para>

      <para>Very special thanks to the hard-working volunteers at
	the <ulink url="http://www.tldp.org">Linux Documentation
	Project</ulink>. The LDP hosts a repository of Linux knowledge
	and lore, and has, to a great extent, enabled the publication
	of this book.</para>

      <para>Thanks and appreciation to IBM, Red Hat, the <ulink
        url="http://www.fsf.org">Free Software Foundation</ulink>, and
        all the good people fighting the good fight to keep Open Source
        software free and open.</para>

      <para>Thanks most of all to my wife, Anita, for her encouragement,
        inspiration,  and emotional support.</para>	

    </sect1> <!-- Credits --> 

    <sect1 id="disclaimer">
      <title>Disclaimer</title>


      <para>(This is a variant of the standard <ulink
        url="http://www.tldp.org">LDP</ulink> disclaimer.)</para>

      <para>No liability for the contents of this document can be
        accepted. Use the concepts, examples and information at your
        own risk. There may be errors, omissions, and inaccuracies
        that could cause you to lose data or harm your system, so
        <emphasis>proceed with appropriate caution</emphasis>. The
        author takes no responsibility for any damages, incidental or
        otherwise.</para>

      <para>As it happens, it is highly unlikely that either you or
        your system will suffer ill effects. In fact, the
        <foreignphrase>raison d'etre</foreignphrase> of this book is to
        enable its readers to analyze shell scripts and determine whether
        they have <link linkend="gotchas">unanticipated
        consequences</link>.</para>

    </sect1> <!-- Disclaimer --> 

  </chapter> <!-- End Notes --> 



  <bibliography id="biblio">
  <anchor id="biblioref">

    <epigraph>
      <para>Those who do not understand UNIX are condemned to reinvent it,
	poorly.</para>
      <para>--Henry Spencer</para>
             <para><anchor id="denningref"></para>
    </epigraph>
    

    <biblioentry>
      <authorgroup>
	<editor><firstname>Peter</firstname><surname>Denning</surname></editor>
      </authorgroup>
      <title>Computers Under Attack: Intruders, Worms, and Viruses</title>
      <publisher>
	<publishername>ACM Press</publishername>
      </publisher>
      <copyright>
	<year>1990</year>
      </copyright>
      <isbn>0-201-53067-8</isbn>
      <abstract><para>This compendium contains a couple of articles on 
        shell script viruses.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Ken</firstname><surname>Burtch</surname></author>
      </authorgroup>
      <title><ulink url="http://www.samspublishing.com/title/0672326426">Linux Shell Scripting with Bash</ulink></title>
      <edition>1st edition</edition>
      <publisher>
	<publishername>Sams Publishing (Pearson)</publishername>
      </publisher>
      <copyright>
	<year>2004</year>
      </copyright>
      <isbn>0672326426</isbn>
      <abstract><para>
	  Covers much of the same material as the <emphasis>ABS
	    Guide</emphasis>, though in a different style.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Dale</firstname><surname>Dougherty</surname></author>
	<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
      </authorgroup>
      <title>Sed and Awk</title>
      <edition>2nd edition</edition>
      <publisher>
	<publishername>O'Reilly and Associates</publishername>
      </publisher>
      <copyright>
	<year>1997</year>
      </copyright>
      <isbn>1-156592-225-5</isbn>
      <abstract><para>
	  Unfolding the full power of shell scripting requires at least a passing
	  familiarity with <link linkend="sedref"><firstterm>sed</firstterm>
	  and <firstterm>awk</firstterm></link>. This is the standard
	  tutorial. It includes an excellent introduction to
	  <quote>regular expressions</quote>. Recommended.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Jeffrey</firstname><surname>Friedl</surname></author>
      </authorgroup>
      <title>Mastering Regular Expressions</title>
      <publisher>
	<publishername>O'Reilly and Associates</publishername>
      </publisher>
      <copyright>
	<year>2002</year>
      </copyright>
      <isbn>0-596-00289-0</isbn>
      <abstract><para>Still the best all-around reference on <link
      linkend="regexref">Regular Expressions</link>.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Aeleen</firstname><surname>Frisch</surname></author>
      </authorgroup>
      <title>Essential System Administration</title>
      <edition>3rd edition</edition>
      <publisher>
	<publishername>O'Reilly and Associates</publishername>
      </publisher>
      <copyright>
	<year>2002</year>
      </copyright>
      <isbn>0-596-00343-9</isbn>
      <abstract><para>This excellent sys admin manual has a decent introduction to shell
	  scripting for sys administrators and does a thorough job of explaining the
	  startup and initialization scripts.</para>
	  <para>*</para>
             <para><anchor id="kochanref"></para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Stephen</firstname><surname>Kochan</surname></author>
	<author><firstname>Patrick</firstname><surname>Wood</surname></author>
      </authorgroup>
      <title>Unix Shell Programming</title>
      <publisher>
	<publishername>Hayden</publishername>
      </publisher>
      <copyright>
	<year>1990</year>
      </copyright>
      <isbn>067248448X</isbn>
      <abstract>
      <para>Still considered a standard reference, though somewhat dated, and
      a bit <quote>wooden</quote> stylistically speaking.
          <footnote><para>It was hard to resist the obvious pun. No slight
	  intended, since the book is a pretty decent introduction to
	  the basic concepts of shell scripting.</para></footnote>
	In fact, this book was the <firstterm>ABS Guide</firstterm> author's
	first exposure to UNIX shell scripting, lo these many years ago.</para>
	  <para>For more information, see <ulink
	  url="http://www.kochan-wood.com/">the Kochan-Wood
	  website</ulink>.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Neil</firstname><surname>Matthew</surname></author>
	<author><firstname>Richard</firstname><surname>Stones</surname></author>
      </authorgroup>
      <title>Beginning Linux Programming</title>
      <publisher>
	<publishername>Wrox Press</publishername>
      </publisher>
      <copyright>
	<year>1996</year>
      </copyright>
      <isbn>1874416680</isbn>
      <abstract><para>Surprisingly good in-depth coverage of various
        programming languages available for Linux, including a fairly
        strong chapter on shell scripting.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry id="mayerref">
      <authorgroup>
	<author><firstname>Herbert</firstname><surname>Mayer</surname></author>
      </authorgroup>
      <title>Advanced C Programming on the IBM PC</title>
      <publisher>
	<publishername>Windcrest Books</publishername>
      </publisher>
      <copyright>
	<year>1989</year>
      </copyright>
      <isbn>0830693637</isbn>
      <abstract><para>Excellent coverage of algorithms and general
        programming practices. Highly recommended, but unfortunately
        out of print.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>David</firstname><surname>Medinets</surname></author>
      </authorgroup>
      <title>Unix Shell Programming Tools</title>
      <publisher>
	<publishername>McGraw-Hill</publishername>
      </publisher>
      <copyright>
	<year>1999</year>
      </copyright>
      <isbn>0070397333</isbn>
      <abstract><para>Pretty good treatment of shell scripting, with
        examples, and a short intro to Tcl and Perl.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Cameron</firstname><surname>Newham</surname></author>
	<author><firstname>Bill</firstname><surname>Rosenblatt</surname></author>
      </authorgroup>
      <title>Learning the Bash Shell</title>
      <edition>2nd edition</edition>
      <publisher>
	<publishername>O'Reilly and Associates</publishername>
      </publisher>
      <copyright>
	<year>1998</year>
      </copyright>
      <isbn>1-56592-347-2</isbn>
      <abstract><para>This is a valiant effort at a decent shell primer,
          but sadly deficient in coverage on writing scripts and
          lacking sufficient examples.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Anatole</firstname><surname>Olczak</surname></author>
      </authorgroup>
      <title>Bourne Shell Quick Reference Guide</title>
      <publisher>
	<publishername>ASP, Inc.</publishername>
      </publisher>
      <copyright>
	<year>1991</year>
      </copyright>
      <isbn>093573922X</isbn>
      <abstract><para>A very handy pocket reference, despite lacking
        coverage of Bash-specific features.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Jerry</firstname><surname>Peek</surname></author>
	<author><firstname>Tim</firstname><surname>O'Reilly</surname></author>
	<author><firstname>Mike</firstname><surname>Loukides</surname></author>
      </authorgroup>
      <title>Unix Power Tools</title>
      <edition>3nd edition</edition>
      <publisher>
	<publishername>O'Reilly and Associates</publishername>
      </publisher>
      <publisher>
	<publishername>Random House</publishername>
      </publisher>
      <copyright>
	<year>2002</year>
      </copyright>
      <isbn>0-596-00330-7</isbn>
      <abstract><para>Contains a couple of sections of very informative
       in-depth articles on shell programming, but falls short of being
       a self-teaching manual. It reproduces much of the <firstterm>Regular
       Expressions</firstterm> tutorial from the Dougherty and Robbins book,
       above. The coverage of UNIX commands makes this book worthy of
       a place on your bookshelf.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Clifford</firstname><surname>Pickover</surname></author>
      </authorgroup>
      <title>Computers, Pattern, Chaos, and Beauty</title>
      <publisher>
	<publishername>St. Martin's Press</publishername>
      </publisher>
      <copyright>
	<year>1990</year>
      </copyright>
      <isbn>0-312-04123-3</isbn>
      <abstract><para>A treasure trove of ideas and recipes for
        computer-based exploration of mathematical oddities.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>George</firstname><surname>Polya</surname></author>
      </authorgroup>
      <title>How To Solve It</title>
      <publisher>
	<publishername>Princeton University Press</publishername>
      </publisher>
      <copyright>
	<year>1973</year>
      </copyright>
      <isbn>0-691-02356-5</isbn>
      <abstract><para>The classic tutorial on problem solving methods
        (i.e., algorithms), with special emphasis on how to teach them.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

     <biblioentry>
       <authorgroup>
 	<author><firstname>Chet</firstname><surname>Ramey</surname></author>
 	<author><firstname>Brian</firstname><surname>Fox</surname></author>
       </authorgroup>
       <title><ulink
           url="http://www.network-theory.co.uk/bash/manual/">The GNU Bash Reference Manual</ulink></title>
       <publisher>
 	<publishername>Network Theory Ltd</publishername>
       </publisher>
       <copyright>
 	<year>2003</year>
       </copyright>
       <isbn>0-9541617-7-7</isbn>
       <abstract><para>This manual is the definitive reference for
         GNU Bash. The authors of this manual, Chet Ramey and Brian Fox,
         are the original developers of GNU Bash. For each copy sold,
         the publisher donates $1 to the Free Software Foundation.</para>
	  <para>*</para>
       </abstract>
     </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
      </authorgroup>
      <title>Bash Reference Card</title>
      <publisher>
	<publishername>SSC</publishername>
      </publisher>
      <copyright>
	<year>1998</year>
      </copyright>
      <isbn>1-58731-010-5</isbn>
      <abstract>
          <para>Excellent Bash pocket reference (don't leave home without it,
	    especially if you're a sysadmin). A bargain at $4.95, but
	    unfortunately no longer available for free download.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
      </authorgroup>
      <title>Effective Awk Programming</title>
      <publisher>
	<publishername>Free Software Foundation / O'Reilly and Associates</publishername>
      </publisher>
      <copyright>
	<year>2000</year>
      </copyright>
      <isbn>1-882114-26-4</isbn>
      <abstract>
          <para>The absolute best <firstterm>awk</firstterm> tutorial and
	    reference. The free electronic version of this book is part of the
	    <firstterm>awk</firstterm> documentation, and printed copies of the
	    latest version are available from O'Reilly and Associates.</para>
	  <para>This book has served as an inspiration for the author of the
	    <firstterm>ABS Guide</firstterm>.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Bill</firstname><surname>Rosenblatt</surname></author>
      </authorgroup>
      <title>Learning the Korn Shell</title>
      <publisher>
	<publishername>O'Reilly and Associates</publishername>
      </publisher>
      <copyright>
	<year>1993</year>
      </copyright>
      <isbn>1-56592-054-6</isbn>
      <abstract>
      <para>This well-written book contains some excellent pointers on shell
        scripting in general.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Paul</firstname><surname>Sheer</surname></author>
      </authorgroup>
      <title>LINUX: Rute User's Tutorial and Exposition</title>
      <edition>1st edition</edition>
      <publisher>
	<publishername></publishername>
      </publisher>
      <copyright>
	<year>2002</year>
      </copyright>
      <isbn>0-13-033351-4</isbn>
      <abstract>
      <para>Very detailed and readable introduction to Linux system
        administration.</para>
      <para>The book is available in print, or
        <ulink
        url="http://burks.brighton.ac.uk/burks/linux/rute/rute.htm">on-line</ulink>.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Ellen</firstname><surname>Siever</surname></author>
	<author><surname>the staff of O'Reilly and Associates</surname></author>
      </authorgroup>
      <title>Linux in a Nutshell</title>
      <edition>2nd edition</edition>
      <publisher>
	<publishername>O'Reilly and Associates</publishername>
      </publisher>
      <copyright>
	<year>1999</year>
      </copyright>
      <isbn>1-56592-585-8</isbn>
      <abstract><para>The all-around best Linux command reference.
        It even has a Bash section.</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <authorgroup>
	<author><firstname>Dave</firstname><surname>Taylor</surname></author>
      </authorgroup>
      <title>Wicked Cool Shell Scripts: 101 Scripts for Linux, Mac OS X, and Unix Systems</title>
      <edition>1st edition</edition>
      <publisher>
	<publishername>No Starch Press</publishername>
      </publisher>
      <copyright>
	<year>2004</year>
      </copyright>
      <isbn>1-59327-012-7</isbn>
      <abstract><para>Just what the title promises . . .</para>
	  <para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <title>The UNIX CD Bookshelf</title>
      <edition>3rd edition</edition>
      <publisher>
	<publishername>O'Reilly and Associates</publishername>
      </publisher>
      <copyright>
	<year>2003</year>
      </copyright>
      <isbn>0-596-00392-7</isbn>
      <abstract><para>An array of seven UNIX books on CD ROM, including
	<citetitle pubwork="book">UNIX Power Tools</citetitle>,
	<citetitle pubwork="book">Sed and Awk</citetitle>, and <citetitle
	pubwork="book">Learning the Korn Shell</citetitle>. A complete
	set of all the UNIX references and tutorials you would ever need
	at about $130. Buy this one, even if it means going into debt
	and not paying the rent.</para>
	<para>Update: Seems to have somehow fallen out of print.
	Oh, well. You can still buy the books individually.</para>
	<para>*</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>The O'Reilly books on Perl. (Actually, any O'Reilly books.)</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>* * *</para>
      <para><command>Other Resources</command></para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract><para>Fioretti, Marco, <quote>Scripting for X
	Productivity,</quote> <ulink url="linuxjournal.com"><citetitle
	pubwork="journal">Linux Journal</citetitle></ulink>, Issue 113,
	September, 2003, pp.  86-9.</para></abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Ben Okopnik's well-written <citetitle
	  pubwork="article">introductory Bash scripting</citetitle>
	  articles in issues 53, 54, 55, 57, and 59 of the
	  <ulink url="http://www.linuxgazette.com"><citetitle
	  pubwork="journal">Linux Gazette</citetitle></ulink>, and his
	  explanation of <quote>The Deep, Dark Secrets of Bash</quote>
	  in issue 56.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract><para>Chet Ramey's <citetitle pubwork="article">bash -
        The GNU Shell</citetitle>, a two-part series published in issues 3
        and 4 of the <ulink url="http://www.linuxjournal.com"><citetitle
        pubwork="journal">Linux Journal</citetitle></ulink>, July-August
        1994.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Mike G's <ulink
	  url="http://www.tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html">Bash-Programming-Intro
	  HOWTO</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Richard's <ulink url="http://www.injunea.demon.co.uk/index.htm">Unix
	  Scripting Universe</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Chet Ramey's <ulink
	url="ftp://ftp.cwru.edu/pub/bash/FAQ">Bash FAQ.</ulink>.
	This site carries the latest version of the FAQ.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Ed Schaefer's <ulink
	url="http://www.unixreview.com/columns/schaefer/">Shell
	Corner</ulink>
	 in <ulink url="http://www.unixreview.com"><citetitle
	 pubwork="journal">Unix Review</citetitle></ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Example shell scripts at <ulink
	  url="http://alge.anart.no/linux/scripts/">Lucc's Shell Scripts
	  </ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Example shell scripts at <ulink
	  url="http://www.shelldorado.com">SHELLdorado </ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Example shell scripts at <ulink
	  url="http://www.splode.com/~friedman/software/scripts/src/">Noah
	  Friedman's script site</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Example shell scripts at <ulink
	  url="http://www.zazzybob.com">zazzybob</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Steve Parker's <ulink
	url="http://steve-parker.org/sh/sh.shtml">Shell Programming
	Stuff</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Giles Orr's <ulink
	url="http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/">Bash-Prompt
	HOWTO</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>The <ulink
	url="http://www.pixelbeat.org/cmdline.html"><emphasis>Pixelbeat</emphasis>
	command-line reference</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Very nice <command>sed</command>,
	<command>awk</command>, and regular expression tutorials at
	<ulink url="http://www.grymoire.com/Unix/index.html">The UNIX
	Grymoire</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>The GNU <ulink
          url="http://www.gnu.org/software/sed/manual/">sed</ulink>
          and
	  <ulink url="http://www.gnu.org/software/gawk/manual/">
          gawk</ulink> manuals.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Eric Pement's
	<ulink url="http://www.student.northpark.edu/pemente/sed/">sed resources page</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Many interesting sed scripts at the <ulink
	url="http://sed.sourceforge.net/grabbag/"> seder's grab bag</ulink>.</para>
      </abstract>
    </biblioentry>



    <biblioentry>
      <abstract>
	<para>The GNU <command>gawk</command> <ulink
	url="http://sunsite.ualberta.ca/Documentation/Gnu/gawk-3.0.6/gawk.html">
	reference manual</ulink> (<command>gawk</command> is the extended
	GNU version of <command>awk</command> available on Linux and
	BSD systems).</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Tips and tricks at <ulink
	url="http://linuxreviews.org"> Linux Reviews</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Trent Fisher's <ulink
	url="http://www.cs.pdx.edu/~trent/gnu/groff/groff.html">groff
	tutorial</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Mark Komarinski's <ulink
	url="http://www.tldp.org/HOWTO/Printing-Usage-HOWTO.html">Printing-Usage
	HOWTO</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
        <para><ulink url="http://www.linux-usb.org/USB-guide/book1.html">The
	  Linux USB subsystem</ulink> (helpful in writing scripts affecting
	  USB peripherals).</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>There is some nice material on <link
	linkend="ioredirref">I/O redirection</link> in <ulink
	url="http://sunsite.ualberta.ca/Documentation/Gnu/textutils-2.0/html_chapter/textutils_10.html">
	chapter 10 of the textutils documentation</ulink> at the <ulink
	url="http://sunsite.ualberta.ca/Documentation"> University of
	Alberta site</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para><ulink url="mailto:humbubba@smarty.smart.net">Rick
	  Hohensee</ulink> has written the <ulink
	  url="ftp://ftp.gwdg.de/pub/linux/install/clienux/interim/osimpa.tgz">
	  osimpa</ulink> i386 assembler entirely as Bash scripts.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Aurelio Marinho Jargas has written a <ulink
	  url="http://txt2regex.sf.net">Regular expression
	  wizard</ulink>. He has also written an informative <ulink
	  url="http://guia-er.sf.net">book</ulink> on Regular Expressions,
	  in Portuguese.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para><ulink url="mailto:brtompkins@comcast.net">Ben
	  Tomkins</ulink> has created the <ulink
	  url="http://bashnavigator.sourceforge.net">
	  Bash Navigator</ulink> directory management tool.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para><ulink url="mailto:opengeometry@yahoo.ca">William Park</ulink>
	  has been working on a <ulink
	  url="http://home.eol.ca/~parkw/index.html">project</ulink>
	  to incorporate certain <firstterm>Awk</firstterm> and
	  <firstterm>Python</firstterm> features into Bash. Among these is
	  a <firstterm>gdbm</firstterm> interface. He has released <ulink
	  url="http://freshmeat.net/projects/bashdiff/">bashdiff</ulink>
	  on <ulink url="http://freshmeat.net">Freshmeat.net</ulink>. He
	  has an <ulink
	  url="http://linuxgazette.net/108/park.html">article</ulink>
	  in the November, 2004 issue of the <ulink
	  url="http://www.linuxgazette.net"><citetitle
	  pubwork="journal">Linux Gazette</citetitle></ulink>
	  on adding string functions to Bash, with a <ulink
	  url="http://linuxgazette.net/109/park.html">followup
	  article</ulink> in the December issue, and <ulink
	  url="http://linuxgazette.net/110/park.htm">yet another</ulink>
	  in the January, 2005 issue.</para>
      </abstract>

    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Peter Knowles has written an
	  <ulink url="http://booklistgensh.peterknowles.com/">elaborate
	  Bash script</ulink> that generates a book list on the <ulink
	  url="http://www.dottocomu.com/b/archives/002571.html">Sony
	  Librie</ulink> e-book reader. This useful tool facilitates
	  loading non-DRM user content on the <emphasis>Librie</emphasis>
	  (and the newer <emphasis>PRS-50X-series</emphasis> devices).</para>
	  
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Tim Waugh's <ulink
          url="http://cyberelk.net/tim/xmlto/">xmlto</ulink> is an
          elaborate Bash script for converting Docbook XML documents to
          other formats.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Of historical interest are Colin Needham's
	<firstterm>original International Movie Database (IMDB)
	reader polling scripts</firstterm>, which nicely illustrate
	the use of <link linkend="awkref">awk</link> for string
	parsing. Unfortunately, the URL link is broken.</para>
	<para>---</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>Fritz Mehner has written a <ulink
	  url="http://vim.sourceforge.net/scripts/script.php?script_id=365">bash-support
	  plugin</ulink> for the <firstterm>vim</firstterm> text editor.
	  He has also also come up with his own <ulink
	  url="http://lug.fh-swf.de/vim/vim-bash/StyleGuideShell.en.pdf">stylesheet
	  for Bash</ulink>. Compare it with the <link linkend="unofficialst">ABS Guide
	  Unofficial Stylesheet</link>.</para>
	<para>---</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para><emphasis>Penguin Pete</emphasis> has quite a number of
	  shell scripting tips and hints on <ulink
	  url="http://www.penguinpetes.com">his superb
	  site</ulink>. Highly recommended.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>The excellent <citetitle pubwork="book"> Bash Reference
	  Manual</citetitle>, by Chet Ramey and Brian Fox, distributed as
	  part of the <firstterm>bash-2-doc</firstterm> package (available
	  as an <link linkend="rpmref">rpm</link>). See especially the
	  instructive example scripts in this package.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>John Lion's classic, <ulink
	url="http://www.lemis.com/grog/Documentation/Lions/index.html">
	<emphasis>A Commentary on the Sixth Edition UNIX Operating
	System</emphasis></ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
        <para>The <ulink
          url="news:comp.unix.shell">comp.os.unix.shell</ulink>
          newsgroup.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
        <para><anchor id="ddlink"></para>
        <para>The <ulink
          url="http://www.linuxquestions.org/questions/showthread.php?t=362506"><firstterm>dd</firstterm>
          thread</ulink> on <ulink
          url="http://www.linuxquestions.org">Linux Questions</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
        <para>The 
	  <ulink
	  url="http://www.newsville.com/cgi-bin/getfaq?file=comp.unix.shell/comp.unix.shell_FAQ_-_Answers_to_Frequently_Asked_Questions">comp.os.unix.shell
	  FAQ</ulink>.</para>

      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
        <para>Assorted comp.os.unix <ulink
          url="http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.shell.html">
          FAQs</ulink>.</para>
      </abstract>
    </biblioentry>

    <biblioentry>
      <abstract>
	<para>The <link linkend="manref">manpages</link> for
	  <command>bash</command> and <command>bash2</command>,
	  <command>date</command>, <command>expect</command>,
	  <command>expr</command>, <command>find</command>,
	  <command>grep</command>, <command>gzip</command>,
	  <command>ln</command>, <command>patch</command>,
	  <command>tar</command>, <command>tr</command>,
	  <command>bc</command>, <command>xargs</command>.
	  The <firstterm>texinfo</firstterm> documentation on
	  <command>bash</command>, <command>dd</command>,
	  <command>m4</command>, <command>gawk</command>, and
	  <command>sed</command>.</para>
      </abstract>
    </biblioentry>


  </bibliography>



  <appendix id="contributed-scripts">
      <title>Contributed Scripts</title>

    <para>These scripts, while not fitting into the text of this document, do
    illustrate some interesting shell programming techniques. They are useful,
    too. Have fun analyzing and running them.</para>

    <example id="mailformat">
      <title><firstterm>mailformat</firstterm>: Formatting an e-mail
      message</title>
      <programlisting>&mailformat;</programlisting>
    </example>

    <example id="rn">
      <title><firstterm>rn</firstterm>: A simple-minded file renaming
      utility</title>
      <para>This script is a modification of <xref
      linkend="lowercase">.</para>
      <programlisting>&rn;</programlisting>
    </example>

    <example id="blankrename">
      <title><firstterm>blank-rename</firstterm>: Renames filenames containing
        blanks</title>
      <para>This is an even simpler-minded version of previous script.</para>
      <programlisting>&blankrename;</programlisting>
    </example>

    <example id="encryptedpw">
      <title><firstterm>encryptedpw</firstterm>: Uploading to an ftp site,
      using a locally encrypted password</title>
      <programlisting>&encryptedpw;</programlisting>
    </example>

    <example id="copycd">
      <title><firstterm>copy-cd</firstterm>: Copying a data CD</title>
      <programlisting>&copycd;</programlisting>
    </example>

    <example id="collatz">
      <title>Collatz series</title>
    <programlisting>&collatz;</programlisting>
    </example>

    <para><anchor id="daysbetween0"></para>
    <example id="daysbetween">
      <title><firstterm>days-between</firstterm>: Days between two
        dates</title>
      <programlisting>&daysbetween;</programlisting>
    </example>

    <example id="makedict">
      <title>Making a <firstterm>dictionary</firstterm></title>
    <programlisting>&makedict;</programlisting>
    </example>

    <para><anchor id="soundex0"></para>
    <example id="soundex">
      <title>Soundex conversion</title>
    <programlisting>&soundex;</programlisting>
    </example>

    <para><anchor id="liferef"></para>
    <example id="lifeslow">
      <title><firstterm>Game of Life</firstterm></title>
    <programlisting>&lifeslow;</programlisting>
    </example>

    <example id="gen0data">
      <title>Data file for <firstterm>Game of Life</firstterm></title>
    <programlisting>&gen0data;</programlisting>
    </example>



    <para>+++</para>
    
    <para>The following two scripts are by Mark Moraes of the University
    of Toronto. See the file <filename>Moraes-COPYRIGHT</filename>
    for permissions and restrictions. This file is included in the
    combined <link linkend="where_tarball">HTML/source tarball</link>
    of the <emphasis>ABS Guide</emphasis>.</para>

    <example id="behead">
      <title><firstterm>behead</firstterm>: Removing mail and news
      message headers</title>
      <programlisting>&behead;</programlisting>
    </example>

    <example id="ftpget">
      <title><firstterm>ftpget</firstterm>: Downloading files via ftp</title>
      <programlisting>&ftpget;</programlisting>
    </example>

    <para>+</para>

    <para>Antek Sawicki contributed the following script, which makes very
      clever use of the parameter substitution operators discussed in
      <xref linkend="Parameter-Substitution">.</para>

    <para><anchor id="pw0"></para>
    <example id="pw">
      <title><firstterm>password</firstterm>: Generating random
      8-character passwords</title>
      <programlisting>&pw;</programlisting>
    </example>

    <para>+</para>

    <para><anchor id="zfifo">James R. Van Zandt contributed this script
      which uses named pipes and, in his words, <quote>really exercises
      quoting and escaping.</quote></para>

    <example id="fifo">
      <title><firstterm>fifo</firstterm>: Making daily backups, using
      named pipes</title>
      <programlisting>&fifo;</programlisting>
    </example>

    <para>+</para>

    <para><anchor id="primes1"></para>
    <para>St&eacute;phane Chazelas used the following script to
      demonstrate generating prime numbers without arrays.</para>

    <para><anchor id="primes00"></para>
    <example id="primes">
      <title>Generating prime numbers using the modulo operator</title>
      <programlisting>&primes;</programlisting>
    </example>
    
    <para>+</para>

    <para>Rick Boivie's revision of Jordi Sanfeliu's
      <emphasis>tree</emphasis> script.</para>

    <example id="tree">
      <title><firstterm>tree</firstterm>: Displaying a directory tree</title>
      <programlisting>&tree;</programlisting>
    </example>

    <para>Patsie's version of a directory <firstterm>tree</firstterm>
      script.</para>

    <example id="tree2">
      <title><firstterm>tree2</firstterm>: Alternate directory tree script</title>
      <programlisting>&tree2;</programlisting>
    </example>

    <para>Noah Friedman permitted use of his <emphasis>string
      function</emphasis> script. It essentially reproduces some
      of the <firstterm>C</firstterm>-library string manipulation
      functions.</para>

    <example id="string">
      <title><firstterm>string functions</firstterm>: C-style string
      functions</title>
      <programlisting>&string;</programlisting>
    </example>

    <para>Michael Zick's complex array example uses the <link
      linkend="md5sumref">md5sum</link> check sum command to encode directory
      information.</para>

    <example id="directoryinfo">
      <title>Directory information</title>
      <programlisting>&directoryinfo;</programlisting>
    </example>


    <para>St&eacute;phane Chazelas demonstrates object-oriented programming in a
      Bash script.</para>

    <example id="objoriented">
      <title>Object-oriented database</title>
      <programlisting>&objoriented;</programlisting>
    </example>

    <para>Mariusz Gniazdowski contributed a <link linkend="hashref">hash</link>
      library for use in scripts.</para>

    <example id="hashlib">
      <title>Library of hash functions</title>
      <programlisting>&hashlib;</programlisting>
    </example>

    <para>Here is an example script using the foregoing hash library.</para>

    <example id="hashexample">
      <title>Colorizing text using hash functions</title>
      <programlisting>&hashexample;</programlisting>
    </example>

    <para><anchor id="hashex2_0">An example illustrating the mechanics
      of hashing, but from a different point of view.</para>

    <example id="hashex2">
      <title>More on hash functions</title>
      <programlisting>&hashex2;</programlisting>
    </example>

    <para>Now for a script that installs and mounts
      those cute USB keychain solid-state <quote>hard drives.</quote></para>

    <example id="usbinst">
      <title>Mounting USB keychain storage devices</title>
      <programlisting>&usbinst;</programlisting>
    </example>

    <para>Converting a text file to HTML format.</para>

    <example id="tohtml">
      <title>Converting to HTML</title>
      <programlisting>&tohtml;</programlisting>
    </example>

    <para>Here is something to warm the hearts of webmasters and mistresses:
      a script that saves weblogs.</para>

    <example id="archivweblogs">
      <title>Preserving weblogs</title>
      <programlisting>&archiveweblogs;</programlisting>
    </example>

    <para><anchor id="protectliteral0">How to keep the shell from
      expanding and reinterpreting text strings.</para>

    <example id="protectliteral">
      <title>Protecting literal strings</title>
      <programlisting>&protectliteral;</programlisting>
    </example>

    <para><anchor id="unprotectliteral0">But, what if you
      <emphasis>want</emphasis> the shell to expand
      and reinterpret strings?</para>

    <example id="unprotectliteral">
      <title>Unprotecting literal strings</title>
      <programlisting>&unprotectliteral;</programlisting>
    </example>


    <para>This interesting script helps hunt down spammers.</para>

    <para><anchor id="isspammer2_0"></para>
    <example id="isspammer2">
      <title>Spammer Identification</title>
      <programlisting>&isspammer2;</programlisting>
    </example>


    <para>Another anti-spam script.</para>

    <para><anchor id="whx0"></para>
    <example id="whx">
      <title>Spammer Hunt</title>
      <programlisting>&whx;</programlisting>
    </example>


    <para><quote>Little Monster's</quote> front end to <link
      linkend="wgetref">wget</link>.</para>

    <example id="wgetter2">
      <title>Making <firstterm>wget</firstterm> easier to use</title>
      <programlisting>&wgetter2;</programlisting>
    </example>

    <example id="bashpodder">
      <title>A <firstterm>podcasting</firstterm> script</title>
      <programlisting>&bashpodder;</programlisting>
    </example>

    <example id="nightlybackup">
      <title>Nightly backup to a firewire HD</title>
      <programlisting>&nightlybackup;</programlisting>
    </example>

    <example id="cdll">
      <title>An expanded <firstterm>cd</firstterm> command</title>
      <programlisting>&cdll;</programlisting>
    </example>

    <example id="soundcardon">
      <title>A soundcard setup script</title>
      <programlisting>&soundcardon;</programlisting>
    </example>

    <para><anchor id="findsplit0"></para>
    <example id="findsplit">
      <title>Locating split paragraphs in a text file</title>
      <programlisting>&findsplit;</programlisting>
    </example>

    <para><anchor id="insertionsort0"></para>
    <example id="insertionsort">
      <title>Insertion sort</title>
      <programlisting>&insertionsort;</programlisting>
    </example>

    <example id="stddev">
      <title>Standard Deviation</title>
      <programlisting>&stddev;</programlisting>
    </example>

    <example id="padsw">
      <title>A <firstterm>pad</firstterm> file generator for shareware
        authors</title>
      <programlisting>&padsw;</programlisting>
    </example>

    <example id="maned">
      <title>A <firstterm>man page</firstterm> editor</title>
      <programlisting>&maned;</programlisting>
    </example>

    <example id="petals">
      <title>Petals Around the Rose</title>
      <programlisting>&petals;</programlisting>
    </example>

    <example id="qky">
      <title>Quacky: a Perquackey-type word game</title>
      <programlisting>&qky;</programlisting>
    </example>

    <example id="nim">
      <title>Nim</title>
      <programlisting>&nim;</programlisting>
    </example>

    <example id="stopwatch">
      <title>A command-line stopwatch</title>
      <programlisting>&stopwatch;</programlisting>
    </example>

    <example id="homework">
      <title>An all-purpose shell scripting homework assignment solution</title>
      <programlisting>&homework;</programlisting>
    </example>

    <example id="usegetopt">
      <title>An alternate version of the
      <link linkend="getoptsimple">getopt-simple.sh</link> script</title>
      <programlisting>&usegetopt;</programlisting>
    </example>

    <para><anchor id="basicsrev0">To end this section, a review of the
      basics . . . and more.</para>

    <example id="basicsreviewed">
      <title>Basics Reviewed</title>
      <programlisting>&basicsreviewed;</programlisting>
    </example>


  </appendix>
    <!-- End Contributed Scripts appendix -->




  <appendix id="refcards">
      <title>Reference Cards</title>

      <para>The following reference cards provide a useful
	<emphasis>summary</emphasis> of certain scripting concepts.
	The foregoing text treats these matters in more depth, as well as
	giving usage examples.</para>

      <para><anchor id="specshvartab"></para>
      <table pgwide=0>
	<title>Special Shell Variables</title>
	<tgroup cols="2">
	  <thead>
	    <row>
	      <entry>Variable</entry>
	      <entry>Meaning</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>$0</option></entry>
	      <entry>Filename of script</entry>
	    </row>
	    <row>
	      <entry><option>$1</option></entry>
	      <entry>Positional parameter #1</entry>
	    </row>
	    <row>
	      <entry><option>$2 - $9</option></entry>
	      <entry>Positional parameters #2 - #9</entry>
	    </row>
	    <row>
	      <entry><option>${10}</option></entry>
	      <entry>Positional parameter #10</entry>
	    </row>
	    <row>
	      <entry><option>$#</option></entry>
	      <entry>Number of positional parameters</entry>
	    </row>
	    <row>
	      <entry><option>"$*"</option></entry>
	      <entry>All the positional parameters (as a single word) *</entry>
	    </row>
	    <row>
	      <entry><option>"$@"</option></entry>
	      <entry>All the positional parameters (as separate strings)</entry>
	    </row>
	    <row>
	      <entry><option>${#*}</option></entry>
	      <entry>Number of command line parameters passed to
	      script</entry>
	    </row>
	    <row>
	      <entry><option>${#@}</option></entry>
	      <entry>Number of command line parameters passed to
	      script</entry>
	    </row>
	    <row>
	      <entry><option>$?</option></entry>
	      <entry>Return value</entry>
	    </row>
	    <row>
	      <entry><option>$$</option></entry>
	      <entry>Process ID (PID) of script</entry>
	    </row>
	    <row>
	      <entry><option>$-</option></entry>
	      <entry>Flags passed to script (using
	        <firstterm>set</firstterm>)</entry>
	    </row>
	    <row>
	      <entry><option>$_</option></entry>
	      <entry>Last argument of previous command</entry>
	    </row>
	    <row>
	      <entry><option>$!</option></entry>
	      <entry>Process ID (PID) of last job run in background</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>

      <para><command>*</command> <emphasis>Must be quoted</emphasis>,
        otherwise it defaults to
        <quote><varname>$@</varname></quote>.</para>


      <para><anchor id="bincomptab"></para>
      <table>
	<title>TEST Operators: Binary Comparison</title>
	<tgroup cols="5">
	  <thead>
	    <row>
	      <entry>Operator</entry>
	      <entry>Meaning</entry>
	      <entry>-----</entry>
	      <entry>Operator</entry>
	      <entry>Meaning</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry></entry>
	      <entry></entry>
	    </row>
	    <row>
	      <entry><link linkend="icomparison1">Arithmetic
	        Comparison</link></entry>
	      <entry></entry>
	      <entry></entry>
	      <entry><link linkend="scomparison1">String
	        Comparison</link></entry>
	      <entry></entry>
	    </row>
	    <row>
	      <entry><option>-eq</option></entry>
	      <entry>Equal to</entry>
	      <entry></entry>
	      <entry><option>=</option></entry>
	      <entry>Equal to</entry>
	    </row>
	    <row>
	      <entry></entry>
	      <entry></entry>
	      <entry></entry>
	      <entry><option>==</option></entry>
	      <entry>Equal to</entry>
	    </row>
	    <row>
	      <entry><option>-ne</option></entry>
	      <entry>Not equal to</entry>
	      <entry></entry>
	      <entry><option>!=</option></entry>
	      <entry>Not equal to</entry>
	    </row>
	    <row>
	      <entry><option>-lt</option></entry>
	      <entry>Less than</entry>
	      <entry></entry>
	      <entry><option>\&lt;</option></entry>
	      <entry>Less than (ASCII) *</entry>
	    </row>
	    <row>
	      <entry><option>-le</option></entry>
	      <entry>Less than or equal to</entry>
	      <entry></entry>
	      <entry></entry>
	    </row>
	    <row>
	      <entry><option>-gt</option></entry>
	      <entry>Greater than</entry>
	      <entry></entry>
	      <entry><option>\&gt;</option></entry>
	      <entry>Greater than (ASCII) *</entry>
	    </row>
	    <row>
	      <entry><option>-ge</option></entry>
	      <entry>Greater than or equal to</entry>
	      <entry></entry>
	      <entry></entry>
	    </row>
	    <row>
	      <entry></entry>
	      <entry></entry>
	      <entry></entry>
	      <entry><option>-z</option></entry>
	      <entry>String is empty</entry>
	    </row>
	    <row>
	      <entry></entry>
	      <entry></entry>
	      <entry></entry>
	      <entry><option>-n</option></entry>
	      <entry>String is not empty</entry>
	    </row>
	    <row>
	      <entry></entry>
	      <entry></entry>
	    </row>
	    <row>
	      <entry>Arithmetic Comparison</entry>
	      <entry><link linkend="dblprx">within double
	        parentheses</link> (( ... ))</entry>
	    </row>
	    <row>  
	      <entry><option>&gt;</option></entry>
	      <entry>Greater than</entry>
	    </row>
	    <row>
	      <entry><option>&gt;=</option></entry>
	      <entry>Greater than or equal to</entry>
	    </row>
	    <row>  
	      <entry><option>&lt;</option></entry>
	      <entry>Less than</entry>
	    </row>
	    <row>  
	      <entry><option>&lt;=</option></entry>
	      <entry>Less than or equal to</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>


      <para><command>*</command> <emphasis>If within a
        double-bracket</emphasis> <token>[[ ... ]]</token> <emphasis>test construct,
        then no escape</emphasis> <token>\</token> <emphasis>is
        needed.</emphasis></para>

      <para><anchor id="filestab"></para>
      <table>
	<title>TEST Operators: Files</title>
	<tgroup cols="5">
	  <thead>
	    <row>
	      <entry>Operator</entry>
	      <entry>Tests Whether</entry>
	      <entry>-----</entry>
	      <entry>Operator</entry>
	      <entry>Tests Whether</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>-e</option></entry>
	      <entry>File exists</entry>
	      <entry></entry>
	      <entry><option>-s</option></entry>
	      <entry>File is not zero size</entry>
	    </row>
	    <row>
	      <entry><option>-f</option></entry>
	      <entry>File is a <firstterm>regular</firstterm> file</entry>
	    </row>
	    <row>
	      <entry><option>-d</option></entry>
	      <entry>File is a <firstterm>directory</firstterm></entry>
	      <entry></entry>
	      <entry><option>-r</option></entry>
	      <entry>File has <firstterm>read</firstterm>
	         permission</entry>
	    </row>
	    <row>
	      <entry><option>-h</option></entry>
	      <entry>File is a <link linkend="symlinkref">symbolic link</link></entry>
	      <entry></entry>
	      <entry><option>-w</option></entry>
	      <entry>File has <firstterm>write</firstterm>
	         permission</entry>
	    </row>
	    <row>
	      <entry><option>-L</option></entry>
	      <entry>File is a <firstterm>symbolic link</firstterm></entry>
	      <entry></entry>
	      <entry><option>-x</option></entry>
	      <entry>File has <firstterm>execute</firstterm>
	        permission</entry>
	    </row>
	    <row>
	      <entry><option>-b</option></entry>
	      <entry>File is a <link linkend="blockdevref">block
	      device</link></entry>
	    </row>
	    <row>
	      <entry><option>-c</option></entry>
	      <entry>File is a <link linkend="chardevref">character
	      device</link></entry>
	      <entry></entry>
	      <entry><option>-g</option></entry>
	      <entry><firstterm>sgid</firstterm> flag set</entry>
	    </row>
	    <row>
	      <entry><option>-p</option></entry>
	      <entry>File is a <link linkend="piperef">pipe</link></entry>
	      <entry></entry>
	      <entry><option>-u</option></entry>
	      <entry><firstterm>suid</firstterm> flag set</entry>
	    </row>
	    <row>
	      <entry><option>-S</option></entry>
	      <entry>File is a <link linkend="socketref">socket</link></entry>
	      <entry></entry>
	      <entry><option>-k</option></entry>
	      <entry><quote>sticky bit</quote> set</entry>
	    </row>
	    <row>
	      <entry><option>-t</option></entry>
	      <entry>File is associated with a
	        <firstterm>terminal</firstterm></entry>
	    </row>
	    <row><entry></entry></row>
	    <row>
	      <entry><option>-N</option></entry>
	      <entry>File modified since it was last read</entry>
	      <entry></entry>
	      <entry><option>F1 -nt F2</option></entry>
	      <entry>File F1 is <emphasis>newer</emphasis> than F2 *</entry>
	    </row>
	    <row>
	      <entry><option>-O</option></entry>
	      <entry>You own the file</entry>
	      <entry></entry>
	      <entry><option>F1 -ot F2</option></entry>
	      <entry>File F1 is <emphasis>older</emphasis> than F2 *</entry>
	    </row>
	    <row>
	      <entry><option>-G</option></entry>
	      <entry><firstterm>Group id</firstterm> of file same as
	        yours</entry>
	      <entry></entry>
	      <entry><option>F1 -ef F2</option></entry>
	      <entry>Files F1 and F2 are <firstterm>hard links</firstterm>
	        to the same file *</entry>
	    </row>
	    <row><entry></entry></row>
	    <row>
	      <entry><option>!</option></entry>
	      <entry>NOT (inverts sense of above tests)</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>


      <para><command>*</command> <firstterm>Binary</firstterm> operator
        (requires two operands).</para>




      <para><anchor id="parsubtab"></para>
      <table pgwide=0>
	<title>Parameter Substitution and Expansion</title>
	<tgroup cols="2">
	  <thead>
	    <row>
	      <entry>Expression</entry>
	      <entry>Meaning</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>${var}</option></entry>
	      <entry>Value of <parameter>var</parameter>, same as
	        <parameter>$var</parameter></entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><option>${var-DEFAULT}</option></entry>
	      <entry>If <parameter>var</parameter> not set, evaluate expression
	        as <parameter>$DEFAULT</parameter> *</entry>
	    </row>
	    <row>
	      <entry><option>${var:-DEFAULT}</option></entry>
	      <entry>If <parameter>var</parameter> not set or is empty,
		evaluate expression as <parameter>$DEFAULT</parameter>
		*</entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><option>${var=DEFAULT}</option></entry>
	      <entry>If <parameter>var</parameter> not set, evaluate expression
	        as <parameter>$DEFAULT</parameter> *</entry>
	    </row>
	    <row>
	      <entry><option>${var:=DEFAULT}</option></entry>
	      <entry>If <parameter>var</parameter> not set, evaluate expression
	        as <parameter>$DEFAULT</parameter> *</entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><option>${var+OTHER}</option></entry>
	      <entry>If <parameter>var</parameter> set, evaluate expression as
	        <parameter>$OTHER</parameter>, otherwise as null string</entry>
	    </row>
	    <row>
	      <entry><option>${var:+OTHER}</option></entry>
	      <entry>If <parameter>var</parameter> set, evaluate expression as
	        <parameter>$OTHER</parameter>, otherwise as null string</entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><option>${var?ERR_MSG}</option></entry>
	      <entry>If <parameter>var</parameter> not set, print
	        <parameter>$ERR_MSG</parameter> *</entry>
	    </row>
	    <row>
	      <entry><option>${var:?ERR_MSG}</option></entry>
	      <entry>If <parameter>var</parameter> not set, print
	        <parameter>$ERR_MSG</parameter> *</entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><option>${!varprefix*}</option></entry>
	      <entry>Matches all previously declared variables beginning with
	        <parameter>varprefix</parameter></entry>
	    </row>
	    <row>
	      <entry><option>${!varprefix@}</option></entry>
	      <entry>Matches all previously declared variables beginning with
	        <parameter>varprefix</parameter></entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>

      <para><command>*</command> Of course if <parameter>var</parameter>
        <emphasis>is</emphasis> set, evaluate the expression as
	<parameter>$var</parameter>.</para>


      <para><anchor id="stringopstab"></para>
      <table pgwide=0>
	<title>String Operations</title>
	<tgroup cols="2">
	  <thead>
	    <row>
	      <entry>Expression</entry>
	      <entry>Meaning</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>${#string}</option></entry>
	      <entry>Length of <parameter>$string</parameter></entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><option>${string:position}</option></entry>
	      <entry>Extract substring from <parameter>$string</parameter>
		at <parameter>$position</parameter></entry>
	    </row>
	    <row>
	      <entry><option>${string:position:length}</option></entry>
	      <entry>Extract <parameter>$length</parameter>
		characters substring from <parameter>$string</parameter>
		at <parameter>$position</parameter></entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><option>${string#substring}</option></entry>
	      <entry>Strip shortest match of
	      <parameter>$substring</parameter> from front of
	      <parameter>$string</parameter></entry>
	    </row>
	    <row>
	      <entry><option>${string##substring}</option></entry>
	      <entry>Strip longest match of
	      <parameter>$substring</parameter> from front of
	      <parameter>$string</parameter></entry>
	    </row>
	    <row>
	      <entry><option>${string%substring}</option></entry>
	      <entry>Strip shortest match of
	      <parameter>$substring</parameter> from back of
	      <parameter>$string</parameter></entry>
	    </row>
	    <row>
	      <entry><option>${string%%substring}</option></entry>
	      <entry>Strip longest match of
	      <parameter>$substring</parameter> from back of
	      <parameter>$string</parameter></entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><option>${string/substring/replacement}</option></entry>
	      <entry>Replace first match of
	      <parameter>$substring</parameter> with
	      <parameter>$replacement</parameter></entry>
	    </row>
	    <row>
	      <entry><option>${string//substring/replacement}</option></entry>
	      <entry>Replace <emphasis>all</emphasis> matches of
	      <parameter>$substring</parameter> with
	      <parameter>$replacement</parameter></entry>
	    </row>
	    <row>
	      <entry><option>${string/#substring/replacement}</option></entry>
	      <entry>If <parameter>$substring</parameter>
	      matches <emphasis>front</emphasis> end of
	      <parameter>$string</parameter>, substitute
	      <parameter>$replacement</parameter> for
	      <parameter>$substring</parameter></entry>
	    </row>
	    <row>
	      <entry><option>${string/%substring/replacement}</option></entry>
	      <entry>If <parameter>$substring</parameter>
	      matches <emphasis>back</emphasis> end of
	      <parameter>$string</parameter>, substitute
	      <parameter>$replacement</parameter> for
	      <parameter>$substring</parameter></entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><option>expr match "$string" '$substring'</option></entry>
	      <entry>Length of matching <parameter>$substring</parameter>*
	        at beginning of <parameter>$string</parameter></entry>
	    </row>
	    <row>
	      <entry><option>expr "$string" : '$substring'</option></entry>
	      <entry>Length of matching <parameter>$substring</parameter>*
	        at beginning of <parameter>$string</parameter></entry>
	    </row>
	    <row>
	      <entry><option>expr index "$string" $substring</option></entry>
	      <entry>Numerical position in <parameter>$string</parameter>
		of first character in <parameter>$substring</parameter>
		that matches</entry>
	    </row>
	    <row>
	      <entry><option>expr substr $string $position
	        $length</option></entry>
	      <entry>Extract <parameter>$length</parameter> characters
	        from <parameter>$string</parameter> starting at
	        <parameter>$position</parameter></entry>
            </row>
	    <row>
	      <entry><option>expr match "$string"
	        '\($substring\)'</option></entry>
	      <entry>Extract <parameter>$substring</parameter>* at
	        beginning of <parameter>$string</parameter></entry>
            </row>
	    <row>
	      <entry><option>expr "$string" :
	        '\($substring\)'</option></entry>
	      <entry>Extract <parameter>$substring</parameter>* at
	        beginning of <parameter>$string</parameter></entry>
            </row>
	    <row>
	      <entry><option>expr match "$string"
	        '.*\($substring\)'</option></entry>
	      <entry>Extract <parameter>$substring</parameter>* at
	        end of <parameter>$string</parameter></entry>
            </row>
	    <row>
	      <entry><option>expr "$string" :
	        '.*\($substring\)'</option></entry>
	      <entry>Extract <parameter>$substring</parameter>* at
	        end of <parameter>$string</parameter></entry>
            </row>
	  </tbody>
	</tgroup>
      </table>
      
      <para><command>*</command> Where <parameter>$substring</parameter> is a
        <link linkend="regexref">Regular Expression</link>.</para>



      <para><anchor id="misctab"></para>
      <table pgwide=0>
	<title>Miscellaneous Constructs</title>
	<tgroup cols="2">
	  <thead>

	    <row>
	      <entry>Expression</entry>
	      <entry>Interpretation</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><link linkend="bracketsref">Brackets</link></entry><entry></entry>
	    </row>  
	    <row>
	      <entry><option>if [ CONDITION ]</option></entry>
	      <entry><link linkend="leftbracket">Test construct</link></entry>
	    </row>
	    <row>
	      <entry><option>if [[ CONDITION ]]</option></entry>
	      <entry><link linkend="dblbrackets">Extended test construct</link></entry>
	    </row>
	    <row>
	      <entry><option>Array[1]=element1</option></entry>
	      <entry><link linkend="arrayref">Array initialization</link></entry>
	    </row>
	    <row>
	      <entry><option> [a-z]</option></entry>
	      <entry><link linkend="bracketsref">Range of
	      characters</link> within a <link linkend="regexref">Regular
	      Expression</link></entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry>Curly Brackets</entry><entry></entry>
	    </row>  
	    <row>
	      <entry><option>${variable}</option></entry>
	      <entry><link linkend="paramsubref">Parameter substitution</link></entry>
	    </row>
	    <row>
	      <entry><option>${!variable}</option></entry>
	      <entry><link linkend="ivrref">Indirect variable reference</link></entry>
	    </row>
	    <row>
	      <entry><option>{ command1; command2; . . . commandN; }</option></entry>
	      <entry><link linkend="codeblockref">Block of code</link></entry>
	    </row>
	    <row>
	      <entry><option>{string1,string2,string3,...}</option></entry>
	      <entry><link linkend="braceexpref">Brace expansion</link></entry>
	    </row>
	    <row>
	      <entry><option>{a..z}</option></entry>
	      <entry><link linkend="braceexpref3">Extended brace expansion</link></entry>
	    </row>
	    <row>
	      <entry><option>{}</option></entry>
	      <entry>Text replacement, after <link
	      linkend="curlybracketsref">find</link> and <link
	      linkend="xargscurlyref">xargs</link></entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><link linkend="parensref">Parentheses</link></entry><entry></entry>
	    </row>  
	    <row>
	      <entry><option>( command1; command2 )</option></entry>
	      <entry>Command group executed within a <link
	      linkend="subshellsref">subshell</link></entry>
	    </row>
	    <row>
	      <entry><option>Array=(element1 element2 element3)</option></entry>
	      <entry><link linkend="arrayinit0">Array initialization</link></entry>
	    </row>
	    <row>
	      <entry><option>result=$(COMMAND)</option></entry>
	      <entry><link linkend="csparens">Command substitution</link>,
	      new style</entry>
	    </row>
	    <row>
	      <entry><option>&gt;(COMMAND)</option></entry>
	      <entry><link linkend="processsubref">Process substitution</link></entry>
	    </row>
	    <row>
	      <entry><option>&lt;(COMMAND)</option></entry>
	      <entry>Process substitution</entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><link linkend="dblparens">Double Parentheses</link></entry><entry></entry>
	    </row>  
	    <row>
	      <entry><option>(( var = 78 ))</option></entry>
	      <entry><link linkend="dblparensref">Integer arithmetic</link></entry>
	    </row>
	    <row>
	      <entry><option>var=$(( 20 + 5 ))</option></entry>
	      <entry>Integer arithmetic, with variable assignment</entry>
	    </row>
	    <row>
	      <entry><option>(( var++ ))</option></entry>
	      <entry><firstterm>C-style</firstterm> <link
	        linkend="plusplusref"> variable increment</link></entry>
	    </row>
	    <row>
	      <entry><option>(( var-- ))</option></entry>
	      <entry><firstterm>C-style</firstterm> <link
	        linkend="plusplusref"> variable decrement</link></entry>
	    </row>
	    <row>
	      <entry><option>(( var0 = var1&lt;98?9:21 ))</option></entry>
	      <entry><firstterm>C-style</firstterm> <link
	        linkend="cstrinary"> trinary</link> operation</entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><link linkend="quotingref">Quoting</link></entry><entry></entry>
	    </row>  
	    <row>
	      <entry><option>"$variable"</option></entry>
	      <entry><link linkend="dblquo">"Weak" quoting</link></entry>
	    </row>  
	    <row>  
	      <entry><option>'string'</option></entry>
	      <entry><link linkend="snglquo">'Strong' quoting</link></entry>
	    </row>
	    <row><entry></entry><entry></entry></row>
	    <row>
	      <entry><link linkend="backquotesref">Back Quotes</link></entry><entry></entry>
	    </row>  
	    <row>
	      <entry><option>result=`COMMAND`</option></entry>
	      <entry><link linkend="commandsubref">Command
	        substitution</link>, classic style</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>

  </appendix>
    <!-- Reference Cards appendix -->





  <appendix id="sedawk">
      <title>A Sed and Awk Micro-Primer</title>
      
      <para><anchor id="sedref"></para>

      <para>This is a very brief introduction to the <command>sed</command>
	and <command>awk</command> text processing utilities. We will
	deal with only a few basic commands here, but that will suffice
	for understanding simple sed and awk constructs within shell
	scripts.</para>


       <para><command>sed</command>: a non-interactive
         text file editor</para>

       <para><command>awk</command>: a field-oriented pattern processing
         language with a C-style syntax</para>

       <para>For all their differences, the two utilities share a similar
	 invocation syntax, both use <link linkend="regexref">regular
	 expressions </link>, both read input by default
	 from <filename>stdin</filename>, and both output to
	 <filename>stdout</filename>. These are well-behaved UNIX tools,
	 and they work together well. The output from one can be piped
	 to the other, and their combined capabilities give shell scripts
	 some of the power of <link linkend="perlref">Perl</link>.</para>

       <note><para>One important difference between the utilities is
	 that while shell scripts can easily pass arguments to sed, it
	 is more complicated for awk (see <xref linkend="coltotaler">
	 and <xref linkend="coltotaler2">).
	 </para></note>


    <sect1>
      <title>Sed</title>

      <para>Sed is a non-interactive
          <footnote><para>Sed executes without user
          intervention.</para></footnote>
	<command>s</command>tream <command>ed</command>itor. It
	receives text input, whether from <filename>stdin</filename>
	or from a file, performs certain operations on specified lines
	of the input, one line at a time, then outputs the result to
	<filename>stdout</filename> or to a file.  Within a shell script,
	sed is usually one of several tool components in a pipe.</para>

      <para>Sed determines which lines of its input that it will
	operate on from the <firstterm>address range</firstterm> passed
	to it.
	  <footnote><para>If no address range is specified, the default
	  is <emphasis>all</emphasis> lines.</para></footnote>
	Specify this address range either by line number or by a
	pattern to match. For example, <replaceable>3d</replaceable>
	signals sed to delete line 3 of the input, and
	<replaceable>/windows/d</replaceable> tells sed that
	you want every line of the input containing a match to
	<quote>windows</quote> deleted.</para>

      <para>Of all the operations in the sed toolkit, we will focus
	primarily on the three most commonly used
	ones. These are <command>p</command>rinting (to
	<filename>stdout</filename>), <command>d</command>eletion,
	and <command>s</command>ubstitution.</para>


      <para><anchor id="sedbasictable"></para>
      <table>
	<title>Basic sed operators</title>
	<tgroup cols="3">
	  <thead>
	    <row>
	      <entry>Operator</entry>
	      <entry>Name</entry>
	      <entry>Effect</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>[address-range]/p</option></entry>
	      <entry>print</entry>
	      <entry>Print [specified address range]</entry>
	    </row>
	    <row>
	      <entry><option>[address-range]/d</option></entry>
	      <entry>delete</entry>
	      <entry>Delete [specified address range]</entry>
	    </row>
	    <row>
	      <entry><option>s/pattern1/pattern2/</option></entry>
	      <entry>substitute</entry>
	      <entry>Substitute pattern2 for first instance of pattern1 in a line</entry>
	    </row>
	    <row>
	      <entry><option>[address-range]/s/pattern1/pattern2/</option></entry>
	      <entry>substitute</entry>
	      <entry>Substitute pattern2 for first instance of pattern1 in a
	      line, over <replaceable>address-range</replaceable></entry>
	    </row>
	    <row>
	      <entry><option>[address-range]/y/pattern1/pattern2/</option></entry>
	      <entry>transform</entry>
	      <entry>replace any character in pattern1 with the
	        corresponding character in pattern2, over
	      <replaceable>address-range</replaceable> (equivalent of
	        <command>tr</command>)</entry>
	    </row>
	    <row>
	      <entry><option>g</option></entry>
	      <entry>global</entry>
	      <entry>Operate on <emphasis>every</emphasis> pattern match
	        within each matched line of input</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>

      <note><para>Unless the <option>g</option>
	(<firstterm>global</firstterm>) operator is appended to a
	<firstterm>substitute</firstterm> command, the substitution
	operates only on the first instance of a pattern match within
	each line.</para></note>

      <para>From the command line and in a shell script, a sed operation may
       require quoting and certain options.</para>

       <para><programlisting>sed -e '/^$/d' $filename
# The -e option causes the next string to be interpreted as an editing instruction.
#  (If passing only a single instruction to sed, the "-e" is optional.)
#  The "strong" quotes ('') protect the RE characters in the instruction
#+ from reinterpretation as special characters by the body of the script.
# (This reserves RE expansion of the instruction for sed.)
#
# Operates on the text contained in file $filename.
</programlisting></para>

       <para>In certain cases, a <firstterm>sed</firstterm> editing command will
         not work with single quotes.</para>

       <para><programlisting>
filename=file1.txt
pattern=BEGIN

  sed "/^$pattern/d" "$filename"  # Works as specified.
# sed '/^$pattern/d' "$filename"    has unexpected results.
#        In this instance, with strong quoting (' ... '),
#+      "$pattern" will not expand to "BEGIN".</programlisting></para>


       <note><para><firstterm>Sed</firstterm> uses the <option>-e</option>
	 option to specify that the following string is an instruction
	 or set of instructions. If there is only a single instruction
	 contained in the string, then this may be omitted.</para></note>

       <para><programlisting>sed -n '/xzy/p' $filename
# The -n option tells sed to print only those lines matching the pattern.
# Otherwise all input lines would print.
# The -e option not necessary here since there is only a single editing instruction.
</programlisting></para>

      <para><anchor id="sedoptable"></para>
      <table>
	<title>Examples of sed operators</title>
	<tgroup cols="2">
	  <thead>
	    <row>
	      <entry>Notation</entry>
	      <entry>Effect</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>8d</option></entry>
	      <entry>Delete 8th line of input.</entry>
	    </row>
	    <row>
	      <entry><option>/^$/d</option></entry>
	      <entry>Delete all blank lines.</entry>
	    </row>
	    <row>
	      <entry><option>1,/^$/d</option></entry>
	      <entry>Delete from beginning of input up to, and including
	        first blank line.</entry>
	    </row>
	    <row>
	      <entry><option>/Jones/p</option></entry>
	      <entry>Print only lines containing <quote>Jones</quote> (with
	        <token>-n</token> option).</entry>
	    </row>
	    <row>
	      <entry><option>s/Windows/Linux/</option></entry>
	      <entry>Substitute <quote>Linux</quote> for first instance
	        of <quote>Windows</quote> found in each input line.</entry>
	    </row>
	    <row>
	      <entry><option>s/BSOD/stability/g</option></entry>
	      <entry>Substitute <quote>stability</quote> for every instance
	        of <quote>BSOD</quote> found in each input line.</entry>
	    </row>
	    <row>
	      <entry><option>s/ *$//</option></entry>
	      <entry>Delete all spaces at the end of every line.</entry>
	    </row>
	    <row>
	      <entry><option>s/00*/0/g</option></entry>
	      <entry>Compress all consecutive sequences of zeroes into
	        a single zero.</entry>
	    </row>
	    <row>
	      <entry><option>/GUI/d</option></entry>
	      <entry>Delete all lines containing <quote>GUI</quote>.</entry>
	    </row>
	    <row>
	      <entry><option>s/GUI//g</option></entry>
	      <entry>Delete all instances of <quote>GUI</quote>, leaving the 
	        remainder of each line intact.</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>


     <para>Substituting a zero-length string for another is equivalent
       to deleting that string within a line of input. This leaves the
       remainder of the line intact. Applying <userinput>s/GUI//</userinput>   
       to the line
       <screen><userinput>The most important parts of any application are its GUI and sound effects</userinput></screen>
       results in
       <screen><computeroutput>The most important parts of any application are its  and sound effects</computeroutput></screen></para>

     <para>A backslash forces the <command>sed</command> replacement
       command to continue on to the next line. This has the effect of
       using the <firstterm>newline</firstterm> at the end of the first
       line as the <firstterm>replacement string</firstterm>.

       <programlisting>s/^  */\
/g</programlisting>

       This substitution replaces line-beginning spaces with a
       newline. The net result is to replace paragraph indents with a
       blank line between paragraphs.</para>

     <para>An address range followed by one or more operations may require
       open and closed curly brackets, with appropriate newlines. 
       <programlisting>/[0-9A-Za-z]/,/^$/{
/^$/d
}</programlisting>
       This deletes only the first of each set of consecutive blank
       lines. That might be useful for single-spacing a text file,
       but retaining the blank line(s) between paragraphs.</para>


     <note><para>The usual delimiter that <firstterm>sed</firstterm> uses is
      <token>/</token>. However, <emphasis>sed</emphasis> allows other
      delimiters, such as <token>%</token>. This is useful when
      <token>/</token> is part of a replacement string, as in a file pathname.
      See <xref linkend="findstring"> and <xref
      linkend="stripc">.</para></note>

     <para><anchor id="doublespace"></para>
     <tip><para>A quick way to double-space a text file is <userinput>sed G
       filename</userinput>.</para></tip>  

     <para>For illustrative examples of sed within shell scripts, see:
       <orderedlist>
         <listitem><para><xref linkend="ex3"></para></listitem>
	 <listitem><para><xref linkend="ex4"></para></listitem>
	 <listitem><para><xref linkend="ex57"></para></listitem>
         <listitem><para><xref linkend="rn"></para></listitem>
	 <listitem><para><xref linkend="grp"></para></listitem>
	 <listitem><para><xref linkend="col"></para></listitem>
         <listitem><para><xref linkend="behead"></para></listitem>
	 <listitem><para><xref linkend="tree"></para></listitem>
	 <listitem><para><xref linkend="tree2"></para></listitem>
	 <listitem><para><xref linkend="stripc"></para></listitem>
	 <listitem><para><xref linkend="findstring"></para></listitem>
	 <listitem><para><xref linkend="base"></para></listitem>
	 <listitem><para><xref linkend="mailformat"></para></listitem>
	 <listitem><para><xref linkend="rnd"></para></listitem>
	 <listitem><para><xref linkend="wf"></para></listitem>
	 <listitem><para><xref linkend="lifeslow"></para></listitem>
         <listitem><para><xref linkend="selfdocument"></para></listitem>
         <listitem><para><xref linkend="dictlookup"></para></listitem>
         <listitem><para><xref linkend="whx"></para></listitem>
         <listitem><para><xref linkend="bashpodder"></para></listitem>
         <listitem><para><xref linkend="tohtml"></para></listitem>
         <listitem><para><xref linkend="stopwatch"></para></listitem>
       </orderedlist>
     </para>  

      <para>For a more extensive treatment of <firstterm>sed</firstterm>,
        check the appropriate references in the <xref
        linkend="biblio">.</para>

    </sect1>
    <!-- End sed primer -->



    <sect1 id="awk">
      <title>Awk</title>

      <para><anchor id="awkref"></para>

     <para><firstterm>Awk</firstterm>
       <footnote><para>Its name derives from the initials of its authors,
       <command>A</command>ho, <command>W</command>einberg, and
       <command>K</command>ernighan.</para></footnote>
       is a full-featured text processing language with a syntax
       reminiscent of <firstterm>C</firstterm>.  While it possesses an
       extensive set of operators and capabilities, we will cover only
       a few of these here - the ones most useful in shell scripts.</para>

     <para>Awk breaks each line of input passed to it into
       <firstterm>fields</firstterm>. By default, a field
       is a string of consecutive characters delimited by <link
       linkend="whitespaceref">whitespace</link>, though there are options
       for changing this. Awk parses and operates on each separate
       field. This makes it ideal for handling structured text files
       -- especially tables -- data organized into consistent chunks,
       such as rows and columns.</para>

     <para><link linkend="snglquo">Strong quoting</link> and <link
       linkend="codeblockref">curly brackets</link> enclose blocks of
       awk code within a shell script.</para>

     <para><programlisting># $1 is field #1, $2 is field #2, etc.

echo one two | awk '{print $1}'
# one

echo one two | awk '{print $2}'
# two

# But what is field #0 ($0)?
echo one two | awk '{print $0}'
# one two
# All the fields!


awk '{print $3}' $filename
# Prints field #3 of file $filename to stdout.

awk '{print $1 $5 $6}' $filename
# Prints fields #1, #5, and #6 of file $filename.

awk '{print $0}' $filename
# Prints the entire file!
# Same effect as:   cat $filename . . . or . . . sed '' $filename</programlisting></para> 

     <para>We have just seen the awk <firstterm>print</firstterm> command
       in action. The only other feature of awk we need to deal with
       here is variables. Awk handles variables similarly to shell
       scripts, though a bit more flexibly.</para>

     <para><programlisting>{ total += ${column_number} }</programlisting>
       This adds the value of <parameter>column_number</parameter> to
       the running total of <parameter>total</parameter>>. Finally, to print
       <quote>total</quote>, there is an <command>END</command> command
       block, executed after the script has processed all its input.
       <programlisting>END { print total }</programlisting></para>

     <para>Corresponding to the <command>END</command>, there is a
       <command>BEGIN</command>, for a code block to be performed before awk
       starts processing its input.</para>

     <para>The following example illustrates how <command>awk</command> can
       add text-parsing tools to a shell script.</para>

    <example id="lettercount2">
      <title>Counting Letter Occurrences</title>
      <programlisting>&lettercount2;</programlisting>
    </example>

     <para>For simpler examples of awk within shell scripts, see:
       <orderedlist>
         <listitem><para><xref linkend="ex44"></para></listitem>
	 <listitem><para><xref linkend="redir4"></para></listitem>
	 <listitem><para><xref linkend="stripc"></para></listitem>
         <listitem><para><xref linkend="coltotaler"></para></listitem>
         <listitem><para><xref linkend="coltotaler2"></para></listitem>
         <listitem><para><xref linkend="coltotaler3"></para></listitem>
         <listitem><para><xref linkend="pidid"></para></listitem>
         <listitem><para><xref linkend="constat"></para></listitem>
         <listitem><para><xref linkend="fileinfo"></para></listitem>
         <listitem><para><xref linkend="blotout"></para></listitem>
         <listitem><para><xref linkend="seedingrandom"></para></listitem>
         <listitem><para><xref linkend="idelete"></para></listitem>
         <listitem><para><xref linkend="substringex"></para></listitem>
         <listitem><para><xref linkend="sumproduct"></para></listitem>
         <listitem><para><xref linkend="userlist"></para></listitem>
         <listitem><para><xref linkend="prasc"></para></listitem>
         <listitem><para><xref linkend="hypot"></para></listitem>
       </orderedlist>
      </para>	 

     <para>That's all the awk we'll cover here, folks, but there's lots
       more to learn. See the appropriate references in the <xref
       linkend="biblio">.</para>


     </sect1> 
    <!-- End awk primer -->

  </appendix>
    <!-- End sed/awk appendix -->



  <appendix id="exitcodes">
      <title>Exit Codes With Special Meanings</title>

      <para><anchor id="exitcodesref"></para>

      <table>
	<title><firstterm>Reserved</firstterm> Exit Codes</title>
	<tgroup cols="4">
	  <thead>
	    <row>
	      <entry>Exit Code Number</entry>
	      <entry>Meaning</entry>
	      <entry>Example</entry>
	      <entry>Comments</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>1</option></entry>
	      <entry>Catchall for general errors</entry>
	      <entry>let "var1 = 1/0"</entry>
	      <entry>Miscellaneous errors, such as <quote>divide by
	        zero</quote> and other impermissible operations</entry>
	    </row>
	    <row>
	      <entry><option>2</option></entry>
	      <entry>Misuse of shell builtins (according to Bash documentation)</entry>
	      <entry>empty_function() {}</entry>
	      <entry>Seldom seen, usually defaults to exit
	        code <errorcode>1</errorcode></entry>
	    </row>
	    <row>
	      <entry><option>126</option></entry>
	      <entry>Command invoked cannot execute</entry>
	      <entry></entry>
	      <entry>Permission problem or command is not an executable</entry>
	    </row>
	    <row>
	      <entry><option>127</option></entry>
	      <entry><quote>command not found</quote></entry>
	      <entry>illegal_command</entry>
	      <entry>Possible problem with <varname>$PATH</varname> or a typo</entry>
	    </row>
	    <row>
	      <entry><option>128</option></entry>
	      <entry>Invalid argument to <link linkend="exitcommandref">exit</link></entry>
	      <entry>exit 3.14159</entry>
	      <entry><command>exit</command> takes only integer args in the
		range <returnvalue>0 - 255</returnvalue> (see
		first footnote)</entry>
	    </row>
	    <row>
	      <entry><option>128+n</option></entry>
	      <entry>Fatal error signal <quote>n</quote></entry>
	      <entry><firstterm>kill -9</firstterm> <varname>$PPID</varname> of script</entry>
	      <entry><userinput>$?</userinput> returns
	      <errorcode>137</errorcode> (128 + 9)</entry>
	    </row>
	    <row>
	      <entry><option>130</option></entry>
	      <entry>Script terminated by Control-C</entry>
	      <entry></entry>
	      <entry>Control-C is fatal error signal
	      <errorcode>2</errorcode>, (130 = 128 + 2, see above)</entry>
	    </row>
	    <row>
	      <entry><option>255*</option></entry>
	      <entry>Exit status out of range</entry>
	      <entry>exit <returnvalue>-1</returnvalue></entry>
	      <entry><command>exit</command> takes only integer args in the
	        range <errorcode>0 - 255</errorcode></entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>

      <para>According to the above table, exit codes <errorcode>1 - 2,
        126 - 165, and 255</errorcode>

	<footnote><para><anchor id="excoor">Out of range exit values
	  can result in unexpected exit codes. An exit value
	  greater than <errorcode>255</errorcode> returns an
	  exit code <link linkend="moduloref">modulo</link>
	  <errorcode>256</errorcode>. For example, <firstterm>exit
	  3809</firstterm> gives an exit code of <errorcode>225</errorcode>
	  (3809 % 256 = 225).</para></footnote>

	have special meanings, and should therefore be avoided for
	user-specified exit parameters. Ending a script with <firstterm>exit
	127</firstterm> would certainly cause confusion when troubleshooting
	(is the error code a <quote>command not found</quote> or a
	user-defined one?). However, many scripts use an <firstterm>exit
	1</firstterm> as a general bailout-upon-error. Since exit code
	<errorcode>1</errorcode> signifies so many possible errors,
	it is not particularly useful in debugging.</para>

      <para><anchor id="sysexitsref"></para>
      <para>There has been an attempt to systematize exit status numbers
	(see <filename
	class="headerfile">/usr/include/sysexits.h</filename>),
	but this is intended for C and C++ programmers. A similar
	standard for scripting might be appropriate. The author of
	this document proposes restricting user-defined exit codes to
	the range <returnvalue>64 - 113</returnvalue> (in addition to
	<returnvalue>0</returnvalue>, for success), to conform with
	the C/C++ standard. This would allot 50 valid codes, and make
	troubleshooting scripts more straightforward.
	  <footnote><para>An update of <filename
	  class="headerfile">/usr/include/sysexits.h</filename>
	  allocates previously unused exit codes from <returnvalue>64
	  - 78</returnvalue>.  It may be anticipated that the range of
	  unallotted exit codes will be further restricted in the future.
	  The author of this document will <emphasis>not</emphasis> do
	  fixups on the scripting examples to conform to the changing
	  standard. This should not cause any problems, since there
	  is no overlap or conflict in usage of exit codes between
	  compiled C/C++ binaries and shell scripts.</para></footnote>
	All user-defined exit codes in the accompanying examples to
	this document conform to this standard, except where overriding
	circumstances exist, as in <xref linkend="tmdin">.</para>

      <note><para>Issuing a <link linkend="xstatvarref">$?</link> from
	the command line after a shell script exits gives
	results consistent with the table above only from the
	Bash or <firstterm>sh</firstterm> prompt. Running the
	<firstterm>C-shell</firstterm> or <firstterm>tcsh</firstterm>
	may give different values in some cases.</para></note>


  </appendix>
    <!-- End Reserved Exit Code appendix -->


  <appendix id="ioredirintro">
      <title>A Detailed Introduction to I/O and I/O Redirection</title>

      <para><emphasis>written by St&eacute;phane Chazelas, and revised
        by the document author</emphasis></para>

      <para><anchor id="stdinoutdef"></para>
      <para>A command expects the first three <link linkend="fdref">file
        descriptors</link> to be available. The first, <firstterm>fd
        0</firstterm> (standard input, <filename>stdin</filename>),
        is for reading. The other two (<firstterm>fd 1</firstterm>,
        <filename>stdout</filename> and <firstterm>fd 2</firstterm>,
        <filename>stderr</filename>) are for writing.</para>

      <para>There is a <filename>stdin</filename>, <filename>stdout</filename>,
        and a <filename>stderr</filename> associated with each command.
        <userinput>ls 2&gt;&1</userinput> means temporarily connecting the
        <filename>stderr</filename> of the <command>ls</command> command to the
        same <quote>resource</quote> as the shell's
        <filename>stdout</filename>.</para>

      <para>By convention, a command reads its input from fd 0
        (<filename>stdin</filename>), prints normal output to fd
        1 (<filename>stdout</filename>), and error ouput to fd 2
        (<filename>stderr</filename>). If one of those three fd's is
        not open, you may encounter problems:</para>

      <screen>
<prompt>bash$ </prompt><userinput>cat /etc/passwd >&-</userinput>
<computeroutput>cat: standard output: Bad file descriptor</computeroutput>
      </screen>

      <para>For example, when <command>xterm</command> runs, it first
        initializes itself.  Before running the user's shell,
        <command>xterm</command> opens the terminal device
        (/dev/pts/&lt;n&gt; or something similar) three times.</para>

      <para>At this point, Bash inherits these three file descriptors,
        and each command (child process) run by Bash inherits
        them in turn, except when you redirect the command.  <link
        linkend="ioredirref">Redirection</link> means reassigning
        one of the file descriptors to another file (or a pipe, or
        anything permissible). File descriptors may be reassigned
        locally (for a command, a command group, a <link
	linkend="subshellsref">subshell</link>, a <link
        linkend="redirref">while or if or case or for loop</link>...),
        or globally, for the remainder of the shell (using <link
        linkend="execref">exec</link>).</para>

      <para><userinput>ls &gt; /dev/null</userinput> means
        running <command>ls</command> with its fd 1 connected to
        <filename>/dev/null</filename>.</para>

      <para>
      <screen>
<prompt>bash$ </prompt><userinput>lsof -a -p $$ -d0,1,2</userinput>
<computeroutput>COMMAND PID     USER   FD   TYPE DEVICE SIZE NODE NAME
 bash    363 bozo        0u   CHR  136,1         3 /dev/pts/1
 bash    363 bozo        1u   CHR  136,1         3 /dev/pts/1
 bash    363 bozo        2u   CHR  136,1         3 /dev/pts/1</computeroutput>


<prompt>bash$ </prompt><userinput>exec 2&gt; /dev/null</userinput>
<prompt>bash$ </prompt><userinput>lsof -a -p $$ -d0,1,2</userinput>
<computeroutput>COMMAND PID     USER   FD   TYPE DEVICE SIZE NODE NAME
 bash    371 bozo        0u   CHR  136,1         3 /dev/pts/1
 bash    371 bozo        1u   CHR  136,1         3 /dev/pts/1
 bash    371 bozo        2w   CHR    1,3       120 /dev/null</computeroutput>


<prompt>bash$ </prompt><userinput>bash -c 'lsof -a -p $$ -d0,1,2' | cat</userinput>
<computeroutput>COMMAND PID USER   FD   TYPE DEVICE SIZE NODE NAME
 lsof    379 root    0u   CHR  136,1         3 /dev/pts/1
 lsof    379 root    1w  FIFO    0,0      7118 pipe
 lsof    379 root    2u   CHR  136,1         3 /dev/pts/1</computeroutput>


<prompt>bash$ </prompt><userinput>echo "$(bash -c 'lsof -a -p $$ -d0,1,2' 2&gt;&1)"</userinput>
<computeroutput>COMMAND PID USER   FD   TYPE DEVICE SIZE NODE NAME
 lsof    426 root    0u   CHR  136,1         3 /dev/pts/1
 lsof    426 root    1w  FIFO    0,0      7520 pipe
 lsof    426 root    2w  FIFO    0,0      7520 pipe</computeroutput>
</screen>
</para>

<para>This works for different types of redirection.</para>

<para><userinput>Exercise:</userinput> Analyze the following script.

<programlisting>#! /usr/bin/env bash

mkfifo /tmp/fifo1 /tmp/fifo2
while read a; do echo "FIFO1: $a"; done < /tmp/fifo1 & exec 7> /tmp/fifo1
exec 8> >(while read a; do echo "FD8: $a, to fd7"; done >&7)

exec 3>&1
(
 (
  (
   while read a; do echo "FIFO2: $a"; done < /tmp/fifo2 | tee /dev/stderr \
   | tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 >&7 & exec 3> /tmp/fifo2

   echo 1st, to stdout
   sleep 1
   echo 2nd, to stderr >&2
   sleep 1
   echo 3rd, to fd 3 >&3
   sleep 1
   echo 4th, to fd 4 >&4
   sleep 1
   echo 5th, to fd 5 >&5
   sleep 1
   echo 6th, through a pipe | sed 's/.*/PIPE: &, to fd 5/' >&5
   sleep 1
   echo 7th, to fd 6 >&6
   sleep 1
   echo 8th, to fd 7 >&7
   sleep 1
   echo 9th, to fd 8 >&8

  ) 4>&1 >&3 3>&- | while read a; do echo "FD4: $a"; done 1>&3 5>&- 6>&-
 ) 5>&1 >&3 | while read a; do echo "FD5: $a"; done 1>&3 6>&-
) 6>&1 >&3 | while read a; do echo "FD6: $a"; done 3>&-

rm -f /tmp/fifo1 /tmp/fifo2


# For each command and subshell, figure out which fd points to what.
# Good luck!

exit 0</programlisting>
      </para>

  </appendix>
    <!-- A Detailed Introduction to I/O and I/O Redirection -->


   <appendix id="command-line-options">
     <title>Command-Line Options</title>

     <para>Many executables, whether binaries or script files, accept
       options to modify their run-time behavior. For example: from
       the command line, typing <command>command -o</command>
       would invoke <emphasis>command</emphasis>, with option
       <option>o</option>.</para>


   <sect1 id="standard-options">
     <title>Standard Command-Line Options</title>

      <para>Over time, there has evolved a loose standard for the
        meanings of command line option flags. The GNU utilities conform
        more closely to this <quote>standard</quote> than older UNIX
        utilities.</para>

      <para>Traditionally, UNIX command-line options consist of a dash,
        followed by one or more lowercase letters. The GNU utilities
        added a double-dash, followed by a complete word or compound
        word.</para>


      <para>The two most widely-accepted options are:</para>

      <itemizedlist id="widelyaccopt">

      <listitem>
      <para><option>-h</option></para>
      <para><option>--help</option></para>
      <para><firstterm>Help</firstterm>: Give usage message and exit.</para>
      </listitem>

      <listitem>
      <para><option>-v</option></para>
      <para><option>--version</option></para>
      <para><firstterm>Version</firstterm>: Show program version and exit.</para>
      </listitem>

      </itemizedlist>


      <para>Other common options are:</para>

      <itemizedlist id="otheroptns">

      <listitem>
      <para><option>-a</option></para>
      <para><option>--all</option></para>
      <para><firstterm>All</firstterm>: show <emphasis>all</emphasis>
        information or operate on <emphasis>all</emphasis> arguments.</para>
       
      </listitem>

      <listitem>
      <para><option>-l</option></para>
      <para><option>--list</option></para>
      <para><firstterm>List</firstterm>: list files or arguments without
        taking other action.</para>
      </listitem>

      <listitem>
      <para><option>-o</option></para>
      <para><firstterm>Output</firstterm> filename</para>
      </listitem>

      <listitem>
      <para><option>-q</option></para>
      <para><option>--quiet</option></para>
      <para><firstterm>Quiet</firstterm>: suppress
      <filename>stdout</filename>.</para>
      </listitem>

      <listitem>
      <para><option>-r</option></para>
      <para><option>-R</option></para>
      <para><option>--recursive</option></para>
      <para><firstterm>Recursive</firstterm>: Operate recursively (down
        directory tree).</para>
      </listitem>

      <listitem>
      <para><option>-v</option></para>
      <para><option>--verbose</option></para>
      <para><firstterm>Verbose</firstterm>: output additional information to
        <filename>stdout</filename> or <filename>stderr</filename>.</para>
      </listitem>

      <listitem>
      <para><option>-z</option></para>
      <para><option>--compress</option></para>
      <para><firstterm>Compress</firstterm>: apply compression (usually
        <link linkend="gzipref">gzip</link>).</para>
      </listitem>

      </itemizedlist>


      <para>However:</para>

      <itemizedlist id="exceptionsopts">

      <listitem>
      <para>In <command>tar</command> and <command>gawk</command>:</para>
      <para><option>-f</option></para>
      <para><option>--file</option></para>
      <para><firstterm>File</firstterm>: filename follows.</para>
      </listitem>

      <listitem>
      <para>In <command>cp</command>, <command>mv</command>,
        <command>rm</command>:</para>
      <para><option>-f</option></para>
      <para><option>--force</option></para>
      <para><firstterm>Force</firstterm>: force overwrite of target file(s).</para>
      </listitem>

      </itemizedlist>


      <caution><para>Many UNIX and Linux utilities deviate from this
      <quote>standard,</quote> so it is dangerous to
      <emphasis>assume</emphasis> that a given option will behave in a
      standard way. Always check the man page for the command in question
      when in doubt.</para></caution>

      <para>A complete table of recommended options for the GNU utilities
        is available at <ulink
        url="http://www.gnu.org/prep/standards/">the GNU standards page</ulink>.</para>

   </sect1>




   <sect1 id="bash-options">
     <title>Bash Command-Line Options</title>

     <para><anchor id="clopts"></para>
     <para><firstterm>Bash</firstterm> itself has a number of command-line
       options. Here are some of the more useful ones.</para>

      <itemizedlist id="bash-commline-opts">

      <listitem>
      <para><option>-c</option></para>
      <para><emphasis>Read commands from the following string and assign any
        arguments to the <link linkend="posparamref">positional
        parameters</link>.</emphasis></para>
       <para>
	      <screen>
<prompt>bash$ </prompt><userinput>bash -c 'set a b c d; IFS="+-;"; echo "$*"'</userinput>
<computeroutput>a+b+c+d</computeroutput>
	      </screen>
       </para>
      </listitem>

      <listitem>
      <para><option>-r</option></para>
      <para><option>--restricted</option></para>
      <para><emphasis>Runs the shell, or a script, in <link
        linkend="restrictedshref">restricted mode</link>.</emphasis></para>
      </listitem>

      <listitem>
      <para><option>--posix</option></para>
      <para><emphasis>Forces Bash to conform to <link
        linkend="posix2ref">POSIX</link> mode.</emphasis></para>
      </listitem>

      <listitem>
      <para><option>--version</option></para>
      <para><emphasis>Display Bash version information and
        exit.</emphasis></para>
      </listitem>

      <listitem>
      <para><option>--</option></para>
      <para><emphasis>End of options. Anything further on the command
      line is an argument, not an option.</emphasis></para>
      </listitem>

      </itemizedlist>

      </sect1>


   </appendix>
   <!-- End Command-Line Options appendix -->


   <appendix id="files">
    <title> Important Files</title>

      <variablelist id="filesref">
        <title><anchor id="filesref1">startup files</title>

	<varlistentry>
	  <term></term>
	<listitem>
	  <para>These files contain the aliases and <link
	    linkend="envref">environmental variables</link>
	    made available to Bash running as a user shell and to all
	    Bash scripts invoked after system initialization.</para>
	</listitem>
	</varlistentry>


	<varlistentry>
	  <term><filename>/etc/profile</filename></term>
	<listitem>
	  <para>Systemwide defaults, mostly setting the environment
	  (all Bourne-type shells, not just Bash
	     <footnote><para>This does not apply to <command>csh</command>,
	       <command>tcsh</command>, and other shells not related to or
	       descended from the classic Bourne shell
	       (<command>sh</command>).</para></footnote>)</para>
	</listitem>
      </varlistentry>

	<varlistentry>
	  <term><filename>/etc/bashrc</filename></term>
	<listitem>
	  <para>systemwide functions and <link
	  linkend="aliasref">aliases</link> for Bash</para>
	</listitem>
      </varlistentry>

	<varlistentry>
	  <term><filename><varname>$HOME</varname>/.bash_profile</filename></term>
	<listitem>
	  <para>user-specific Bash environmental default settings,
	    found in each user's home directory (the local counterpart
	    to <filename>/etc/profile</filename>)</para>
	</listitem>
      </varlistentry>

	<varlistentry>
	  <term><filename><varname>$HOME</varname>/.bashrc</filename></term>
	<listitem>
	  <para>user-specific Bash init file, found in each user's home
	    directory (the local counterpart to
	    <filename>/etc/bashrc</filename>).	Only interactive
	    shells and user scripts read this file. See
	    <xref linkend="sample-bashrc"> for a sample
	    <filename>.bashrc</filename> file.</para>
	</listitem>
      </varlistentry>

      </variablelist>


      <variablelist id="logoutfileref">
        <title><anchor id="logoutfileref1">logout file</title>
	<varlistentry>
	  <term><filename><varname>$HOME</varname>/.bash_logout</filename></term>

	<listitem>
	  <para>user-specific instruction file, found in
	    each user's home directory. Upon exit from a login (Bash)
	    shell, the commands in this file execute.</para>
	</listitem>

	</varlistentry>
      </variablelist>

      <variablelist id="sysconfref">
        <title><anchor id="sysconfref1">system configuration files</title>
	<varlistentry>

	  <term><filename>/etc/sysconfig/hwconf</filename></term>
	<listitem>
	  <para>Listing and description of attached hardware devices.
	     This information is in text form and can be extracted and
	     parsed.</para>
<para>
<screen>
<prompt>bash$ </prompt><userinput>grep -A 5 AUDIO /etc/sysconfig/hwconf</userinput>	      
<computeroutput>class: AUDIO
 bus: PCI
 detached: 0
 driver: snd-intel8x0
 desc: "Intel Corporation 82801CA/CAM AC'97 Audio Controller"
 vendorId: 8086</computeroutput>
 </screen>
</para>
	  <note><para>This file is present on Red Hat and Fedora Core
	     installations, but may be missing from other
	     distros.</para></note>
	</listitem>
      </varlistentry>

      </variablelist>

  </appendix>
  <!-- End Files appendix -->





  <appendix id="systemdirs">

      <title>Important System Directories</title>


      <para>Sysadmins and anyone else writing administrative scripts
        should be intimately familiar with the following system
        directories.</para>

        <itemizedlist>

          <listitem>
	    <para><filename class="directory">/bin</filename></para>
	    <para>Binaries (executables). Basic system programs
	      and utilities (such as <command>bash</command>).</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/usr/bin</filename>

            <footnote>
	    <para>Some early UNIX systems had a fast, small-capacity fixed
	      disk (containing <filename class="directory">/</filename>,
	      the root partition), and a second drive which
	      was larger, but slower (containing <filename
	      class="directory">/usr</filename> and other
	      partitions). The most frequently used programs and
	      utilities therefore resided on the small-but-fast
	      drive, in <filename class="directory">/bin</filename>,
	      and the others on the slower drive, in <filename
	      class="directory">/usr/bin</filename>.</para>

	    <para>This likewise accounts for the split between
	      <filename class="directory">/sbin</filename> and
	      <filename class="directory">/usr/sbin</filename>,
	      <filename class="directory">/lib</filename> and <filename
	      class="directory">/usr/lib</filename>, etc.</para>
	    </footnote>

	    </para>

	    <para>More system binaries.</para>

          </listitem>

          <listitem>
            <para><filename class="directory">/usr/local/bin</filename></para>
	    <para>Miscellaneous binaries local to the particular machine.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/sbin</filename></para>
	    <para>System binaries. Basic system administrative programs
	      and utilities (such as <command>fsck</command>).</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/usr/sbin</filename></para>
	    <para>More system administrative programs and utilities.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/etc</filename></para>

	    <para><firstterm>Et cetera</firstterm>. Systemwide configuration
	      scripts.</para>
	      
	    <para>Of particular interest are the
	      <filename>/etc/fstab</filename> (filesystem table),
	      <filename>/etc/mtab</filename>
	      (mounted filesystem table), and the <link
	      linkend="inittabref"><filename>/etc/inittab</filename></link>
	      files.</para>

	  </listitem>

          <listitem>
            <para><filename class="directory">/etc/rc.d</filename></para>
	    <para>Boot scripts, on Red Hat and derivative distributions
	      of Linux.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/usr/share/doc</filename></para>
	    <para>Documentation for installed packages.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/usr/man</filename></para>
	    <para>The systemwide <link linkend="manref">manpages</link>.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/dev</filename></para>
	    <para>Device directory. Entries (but <emphasis>not</emphasis>
	      mount points) for physical and virtual devices.
	      See <xref linkend="devproc">.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/proc</filename></para>
	    <para>Process directory. Contains information and statistics
	      about running processes and kernel parameters.
	      See <xref linkend="devproc">.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/sys</filename></para>
	    <para>Systemwide device directory. Contains information and
	      statistics about device and device names. This is newly
	      added to Linux with the 2.6.X kernels.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/mnt</filename></para>
	    <para><firstterm>Mount</firstterm>. Directory for mounting
	      hard drive partitions, such as <filename
	      class="directory">/mnt/dos</filename>, and physical
	      devices. In newer Linux distros, the <filename
	      class="directory">/media</filename> directory has taken
	      over as the preferred mount point for I/O devices.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/media</filename></para>
	    <para>In newer Linux distros, the preferred mount point for
	      I/O devices, such as CD/DVD drives or USB flash drives.</para>
          </listitem>

          <listitem>
	    <para><filename class="directory">/var</filename></para>
	    <para><firstterm>Variable</firstterm> (changeable) system
	      files. This is a catchall <quote>scratchpad</quote>
	      directory for data generated while a Linux/UNIX machine
	      is running.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/var/log</filename></para>
	    <para>Systemwide log files.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/var/spool/mail</filename></para>
	    <para>User mail spool.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/lib</filename></para>
	    <para>Systemwide library files.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/usr/lib</filename></para>
	    <para>More systemwide library files.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/tmp</filename></para>
	    <para>System temporary files.</para>
          </listitem>

          <listitem>
            <para><filename class="directory">/boot</filename></para>
	    <para>System <firstterm>boot</firstterm> directory. The kernel,
	      module links, system map, and boot manager reside here.</para>
            <warning><para>Altering files in this directory may result in an
	      unbootable system.</para></warning>
          </listitem>

        </itemizedlist>

  </appendix>



  <appendix id="localization">
      <title>Localization</title>


      <para>Localization is an undocumented Bash feature.</para>

      <para>A localized shell script echoes its text output in the
        language defined as the system's locale. A Linux user in Berlin,
        Germany, would get script output in German, whereas his cousin
        in Berlin, Maryland, would get output from the same script in
        English.</para>

      <para>To create a localized script, use the following template to
        write all messages to the user (error messages, prompts,
        etc.).</para>

      <para>
      <programlisting>#!/bin/bash
# localized.sh
#  Script by St&eacute;phane Chazelas,
#+ modified by Bruno Haible, bugfixed by Alfredo Pironti.

. gettext.sh

E_CDERROR=65

error()
{
  printf "$@" >&2
  exit $E_CDERROR
}

cd $var || error "`eval_gettext \"Can\'t cd to \\\$var.\"`"
#  The triple backslashes (escapes) in front of $var needed
#+ "because eval_gettext expects a string
#+ where the variable values have not yet been substituted."
#    -- per Bruno Haible
read -p "`gettext \"Enter the value: \"`" var
#  ...


#  ------------------------------------------------------------------
#  Alfredo Pironti comments:

#  This script has been modified to not use the $"..." syntax in
#+ favor of the "`gettext \"...\"`" syntax.
#  This is ok, but with the new localized.sh program, the commands
#+ "bash -D filename" and "bash --dump-po-string filename"
#+ will produce no output
#+ (because those command are only searching for the $"..." strings)!
#  The ONLY way to extract strings from the new file is to use the
# 'xgettext' program. However, the xgettext program is buggy.

# Note that 'xgettext' has another bug.
#
# The shell fragment:
#    gettext -s "I like Bash"
# will be correctly extracted, but . . .
#    xgettext -s "I like Bash"
# . . . fails!
#  'xgettext' will extract "-s" because
#+ the command only extracts the
#+ very first argument after the 'gettext' word.


#  Escape characters:
#
#  To localize a sentence like
#     echo -e "Hello\tworld!"
#+ you must use
#     echo -e "`gettext \"Hello\\tworld\"`"
#  The "double escape character" before the `t' is needed because
#+ 'gettext' will search for a string like: 'Hello\tworld'
#  This is because gettext will read one literal `\')
#+ and will output a string like "Bonjour\tmonde",
#+ so the 'echo' command will display the message correctly.
#
#  You may not use
#     echo "`gettext -e \"Hello\tworld\"`"
#+ due to the xgettext bug explained above.



# Let's localize the following shell fragment:
#     echo "-h display help and exit"
#
# First, one could do this:
#     echo "`gettext \"-h display help and exit\"`"
#  This way 'xgettext' will work ok,
#+ but the 'gettext' program will read "-h" as an option!
#
# One solution could be
#     echo "`gettext -- \"-h display help and exit\"`"
#  This way 'gettext' will work,
#+ but 'xgettext' will extract "--", as referred to above.
#
# The workaround you may use to get this string localized is
#     echo -e "`gettext \"\\0-h display help and exit\"`"
#  We have added a \0 (NULL) at the beginning of the sentence.
#  This way 'gettext' works correctly, as does 'xgettext.'
#  Moreover, the NULL character won't change the behavior
#+ of the 'echo' command.
#  ------------------------------------------------------------------</programlisting>
      </para>


      <para>
      <screen><prompt>bash$ </prompt><userinput>bash -D localized.sh</userinput>
<computeroutput>"Can't cd to %s."
 "Enter the value: "</computeroutput></screen>

      This lists all the localized text. (The <option>-D</option>
      option lists double-quoted strings prefixed by a <token>$</token>,
      without executing the script.)</para>

      <para>
      <screen><prompt>bash$ </prompt><userinput>bash --dump-po-strings localized.sh</userinput>
<computeroutput>#: a:6
 msgid "Can't cd to %s."
 msgstr ""
 #: a:7
 msgid "Enter the value: "
 msgstr ""</computeroutput></screen>
      
      The <option>--dump-po-strings</option> option to Bash
      resembles the <option>-D</option> option, but uses <link
      linkend="gettextref">gettext</link> <quote>po</quote> format.

      </para>

      <note>
      <para>Bruno Haible points out:</para>

      <para>Starting with gettext-0.12.2, <command>xgettext -o - localized.sh</command>
      is recommended instead of <command>bash --dump-po-strings
      localized.sh</command>, because <command>xgettext</command> . . .</para>
      
      <para>1. understands the gettext and eval_gettext commands
      (whereas bash --dump-po-strings understands only its deprecated
      $"..." syntax)</para>

      <para>2. can extract comments placed by the programmer, intended
      to be read by the translator.</para>

      <para>This shell code is then not specific to Bash any
      more; it works the same way with Bash 1.x and other /bin/sh
      implementations.</para>
      </note>


      <para>Now, build a <filename>language.po</filename>
	file for each language that the script will be translated
	into, specifying the <replaceable>msgstr</replaceable>. Alfredo
	Pironti gives the following example:</para>

      <para>fr.po:

      <programlisting>#: a:6
msgid "Can't cd to $var."
msgstr "Impossible de se positionner dans le repertoire $var."
#: a:7
msgid "Enter the value: "
msgstr "Entrez la valeur : "

#  The string are dumped with the variable names, not with the %s syntax,
#+ similar to C programs.
#+ This is a very cool feature if the programmer uses
#+ variable names that make sense!</programlisting>
      </para>

      <para>Then, run <link linkend="msgfmtref">msgfmt</link>.</para>
      <para><userinput>msgfmt -o localized.sh.mo fr.po</userinput></para>

      <para>Place the resulting <filename>localized.sh.mo</filename> file in the
        <filename class="directory">/usr/local/share/locale/fr/LC_MESSAGES</filename>
        directory, and at the beginning of the script, insert the lines:

	  <programlisting>TEXTDOMAINDIR=/usr/local/share/locale
TEXTDOMAIN=localized.sh</programlisting>
      </para>

      <para>If a user on a French system runs the script, she will get
        French messages.</para>

      <note>
      <para>With older versions of Bash or other shells, localization requires
        <link linkend="gettextref">gettext</link>, using the
	<option>-s</option> option. In this case, the script becomes:</para>

      <para><anchor id="gettextexample">
      <programlisting>#!/bin/bash
# localized.sh

E_CDERROR=65

error() {
  local format=$1
  shift
  printf "$(gettext -s "$format")" "$@" >&2
  exit $E_CDERROR
}
cd $var || error "Can't cd to %s." "$var"
read -p "$(gettext -s "Enter the value: ")" var
# ...</programlisting>
      </para>
      </note>

      <para>The <varname>TEXTDOMAIN</varname> and
	<varname>TEXTDOMAINDIR</varname> variables need to be set and
	exported to the environment. This should be done within the
	script itself.</para>

      <para>---</para>

      <para>This appendix written by St&eacute;phane Chazelas,
	with modifications suggested by Alfredo Pironti,
	and by Bruno Haible, maintainer of GNU <link
	linkend="gettextref">gettext</link>.</para>

  </appendix>
    <!-- Localization -->



  <appendix id="histcommands">
      <title>History Commands</title>

     <para>The Bash shell provides command-line tools for editing and
       manipulating a user's <firstterm>command history</firstterm>. This
       is primarily a convenience, a means of saving keystrokes.</para>

     <para>Bash history commands:
       <orderedlist>
         <listitem><para><command>history</command></para></listitem>
         <listitem><para><command>fc</command></para></listitem>
       </orderedlist>
     </para>  

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>history</userinput>
<computeroutput>   1  mount /mnt/cdrom
    2  cd /mnt/cdrom
    3  ls
     ...</computeroutput>
	      </screen>
	    </para>

     <para>Internal variables associated with Bash history commands:
       <orderedlist>
         <listitem><para>$HISTCMD</para></listitem>
         <listitem><para>$HISTCONTROL</para></listitem>
         <listitem><para>$HISTIGNORE</para></listitem>
         <listitem><para>$HISTFILE</para></listitem>
         <listitem><para>$HISTFILESIZE</para></listitem>
         <listitem><para>$HISTSIZE</para></listitem>
         <listitem><para>$HISTTIMEFORMAT (Bash, ver. 3.0 or later)</para></listitem>
         <listitem><para>!!</para></listitem>
         <listitem><para>!$</para></listitem>
         <listitem><para>!#</para></listitem>
         <listitem><para>!N</para></listitem>
         <listitem><para>!-N</para></listitem>
         <listitem><para>!STRING</para></listitem>
         <listitem><para>!?STRING?</para></listitem>
         <listitem><para>^STRING^string^</para></listitem>
       </orderedlist>
     </para>  

     <para>Unfortunately, the Bash history tools find no use in
       scripting.</para> 

     <para><programlisting>#!/bin/bash
# history.sh
# A (vain) attempt to use the 'history' command in a script.

history                      # No output.

var=$(history); echo "$var"  # $var is empty.

# History commands disabled within a script.</programlisting>
     </para>

	  <para>
	      <screen><prompt>bash$ </prompt><userinput>./history.sh</userinput>
<computeroutput>(no output)</computeroutput>	      
	      </screen>
	  </para>

     <para>The <ulink url="http://www.deadman.org/bash.html">Advancing in the
       Bash Shell</ulink> site gives a good introduction to the use of
       history commands in Bash.</para>



  </appendix>
    <!-- History Commands -->


  <appendix id="sample-bashrc">
      <title>A Sample <filename>.bashrc</filename> File</title>

     <para>The <filename>~/.bashrc</filename> file determines the
       behavior of interactive shells. A good look at this file can
       lead to a better understanding of Bash.</para>

      <para><ulink url="mailto:emmanuel.rouat@wanadoo.fr">Emmanuel
        Rouat</ulink> contributed the following very elaborate
        <filename>.bashrc</filename> file, written for a Linux system.
        He welcomes reader feedback on it.</para>
       
      <para>Study the file carefully, and feel free to reuse code
        snippets and functions from it in your own
        <filename>.bashrc</filename> file or even in your scripts.</para>


      <example id="bashrc">
	<title>Sample <filename>.bashrc</filename> file</title>
	<programlisting>&bashrc;</programlisting>
      </example>

  </appendix>
    <!-- End Sample .bashrc File appendix -->


  <appendix id="dosbatch">
      <title>Converting DOS Batch Files to Shell Scripts</title>

  <para><anchor id="dosbatch1"></para>
  <para>Quite a number of programmers learned scripting on a PC running
    DOS. Even the crippled DOS batch file language allowed writing some
    fairly powerful scripts and applications, though they often required
    extensive kludges and workarounds. Occasionally, the need still
    arises to convert an old DOS batch file to a UNIX shell script. This
    is generally not difficult, as DOS batch file operators are only a
    limited subset of the equivalent shell scripting ones.</para>

      <table>
	<title>Batch file keywords / variables / operators, and their shell equivalents</title>
	<tgroup cols="3">
	  <thead>
	    <row>
	      <entry>Batch File Operator</entry>
	      <entry>Shell Script Equivalent</entry>
	      <entry>Meaning</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>%</option></entry>
	      <entry>$</entry>
	      <entry>command-line parameter prefix</entry>
	    </row>
	    <row>
	      <entry><option>/</option></entry>
	      <entry>-</entry>
	      <entry>command option flag</entry>
	    </row>
	    <row>
	      <entry><option>\</option></entry>
	      <entry>/</entry>
	      <entry>directory path separator</entry>
	    </row>
	    <row>
	      <entry><option>==</option></entry>
	      <entry>=</entry>
	      <entry>(equal-to) string comparison test</entry>
	    </row>
	    <row>
	      <entry><option>!==!</option></entry>
	      <entry>!=</entry>
	      <entry>(not equal-to) string comparison test</entry>
	    </row>
	    <row>
	      <entry><option>|</option></entry>
	      <entry>|</entry>
	      <entry>pipe</entry>
	    </row>
	    <row>
	      <entry><option>@</option></entry>
	      <entry>set <option>+v</option></entry>
	      <entry>do not echo current command</entry>
	    </row>
	    <row>
	      <entry><option>*</option></entry>
	      <entry>*</entry>
	      <entry>filename <quote>wild card</quote></entry>
	    </row>
	    <row>
	      <entry><option>&gt;</option></entry>
	      <entry>&gt;</entry>
	      <entry>file redirection (overwrite)</entry>
	    </row>
	    <row>
	      <entry><option>&gt;&gt;</option></entry>
	      <entry>&gt;&gt;</entry>
	      <entry>file redirection (append)</entry>
	    </row>
	    <row>
	      <entry><option>&lt;</option></entry>
	      <entry>&lt;</entry>
	      <entry>redirect <filename>stdin</filename></entry>
	    </row>
	    <row>
	      <entry><option>%VAR%</option></entry>
	      <entry>$VAR</entry>
	      <entry>environmental variable</entry>
	    </row>
	    <row>
	      <entry><option>REM</option></entry>
	      <entry>#</entry>
	      <entry>comment</entry>
	    </row>
	    <row>
	      <entry><option>NOT</option></entry>
	      <entry>!</entry>
	      <entry>negate following test</entry>
	    </row>
	    <row>
	      <entry><option>NUL</option></entry>
	      <entry><filename>/dev/null</filename></entry>
	      <entry><quote>black hole</quote> for burying command output</entry>
	    </row>
	    <row>
	      <entry><option>ECHO</option></entry>
	      <entry>echo</entry>
	      <entry>echo (many more option in Bash)</entry>
	    </row>
	    <row>
	      <entry><option>ECHO.</option></entry>
	      <entry>echo</entry>
	      <entry>echo blank line</entry>
	    </row>
	    <row>
	      <entry><option>ECHO OFF</option></entry>
	      <entry>set <option>+v</option></entry>
	      <entry>do not echo command(s) following</entry>
	    </row>
	    <row>
	      <entry><option>FOR %%VAR IN (LIST) DO</option></entry>
	      <entry>for var in [list]; do</entry>
	      <entry><quote>for</quote> loop</entry>
	    </row>
	    <row>
	      <entry><option>:LABEL</option></entry>
	      <entry>none (unnecessary)</entry>
	      <entry>label</entry>
	    </row>
	    <row>
	      <entry><option>GOTO</option></entry>
	      <entry>none (use a function)</entry>
	      <entry>jump to another location in the script</entry>
	    </row>
	    <row>
	      <entry><option>PAUSE</option></entry>
	      <entry>sleep</entry>
	      <entry>pause or wait an interval</entry>
	    </row>
	    <row>
	      <entry><option>CHOICE</option></entry>
	      <entry>case or select</entry>
	      <entry>menu choice</entry>
	    </row>
	    <row>
	      <entry><option>IF</option></entry>
	      <entry>if</entry>
	      <entry>if-test</entry>
	    </row>
	    <row>
	      <entry><option>IF EXIST <replaceable>FILENAME</replaceable></option></entry>
	      <entry>if [ -e filename ]</entry>
	      <entry>test if file exists</entry>
	    </row>
	    <row>
	      <entry><option>IF !%N==!</option></entry>
	      <entry>if [ -z "$N" ]</entry>
	      <entry>if replaceable parameter <quote>N</quote> not present</entry>
	    </row>
	    <row>
	      <entry><option>CALL</option></entry>
	      <entry>source or . (dot operator)</entry>
	      <entry><quote>include</quote> another script</entry>
	    </row>
	    <row>
	      <entry><option>COMMAND /C</option></entry>
	      <entry>source or . (dot operator)</entry>
	      <entry><quote>include</quote> another script (same as
	        CALL)</entry>
	    </row>
	    <row>
	      <entry><option>SET</option></entry>
	      <entry>export</entry>
	      <entry>set an environmental variable</entry>
	    </row>
	    <row>
	      <entry><option>SHIFT</option></entry>
	      <entry>shift</entry>
	      <entry>left shift command-line argument list</entry>
	    </row>
	    <row>
	      <entry><option>SGN</option></entry>
	      <entry>-lt or -gt</entry>
	      <entry>sign (of integer)</entry>
	    </row>
	    <row>
	      <entry><option>ERRORLEVEL</option></entry>
	      <entry>$?</entry>
	      <entry>exit status</entry>
	    </row>
	    <row>
	      <entry><option>CON</option></entry>
	      <entry><filename>stdin</filename></entry>
	      <entry><quote>console</quote> (<filename>stdin</filename>)</entry>
	    </row>
	    <row>
	      <entry><option>PRN</option></entry>
	      <entry><filename>/dev/lp0</filename></entry>
	      <entry>(generic) printer device</entry>
	    </row>
	    <row>
	      <entry><option>LPT1</option></entry>
	      <entry><filename>/dev/lp0</filename></entry>
	      <entry>first printer device</entry>
	    </row>
	    <row>
	      <entry><option>COM1</option></entry>
	      <entry><filename>/dev/ttyS0</filename></entry>
	      <entry>first serial port</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>



      <para><anchor id="dosunixequiv"></para>
      <para>Batch files usually contain DOS commands. These must be
	translated into their UNIX equivalents in order to convert a
	batch file into a shell script.</para>

      <table>
	<title>DOS commands and their UNIX equivalents</title>
	<tgroup cols="3">
	  <thead>
	    <row>
	      <entry>DOS Command</entry>
	      <entry>UNIX Equivalent</entry>
	      <entry>Effect</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry><option>ASSIGN</option></entry>
	      <entry>ln</entry>
	      <entry>link file or directory</entry>
	    </row>
	    <row>
	      <entry><option>ATTRIB</option></entry>
	      <entry>chmod</entry>
	      <entry>change file permissions</entry>
	    </row>
	    <row>
	      <entry><option>CD</option></entry>
	      <entry>cd</entry>
	      <entry>change directory</entry>
	    </row>
	    <row>
	      <entry><option>CHDIR</option></entry>
	      <entry>cd</entry>
	      <entry>change directory</entry>
	    </row>
	    <row>
	      <entry><option>CLS</option></entry>
	      <entry>clear</entry>
	      <entry>clear screen</entry>
	    </row>
	    <row>
	      <entry><option>COMP</option></entry>
	      <entry>diff, comm, cmp</entry>
	      <entry>file compare</entry>
	    </row>
	    <row>
	      <entry><option>COPY</option></entry>
	      <entry>cp</entry>
	      <entry>file copy</entry>
	    </row>
	    <row>
	      <entry><option>Ctl-C</option></entry>
	      <entry>Ctl-C</entry>
	      <entry>break (signal)</entry>
	    </row>
	    <row>
	      <entry><option>Ctl-Z</option></entry>
	      <entry>Ctl-D</entry>
	      <entry>EOF (end-of-file)</entry>
	    </row>
	    <row>
	      <entry><option>DEL</option></entry>
	      <entry>rm</entry>
	      <entry>delete file(s)</entry>
	    </row>
	    <row>
	      <entry><option>DELTREE</option></entry>
	      <entry>rm -rf</entry>
	      <entry>delete directory recursively</entry>
	    </row>
	    <row>
	      <entry><option>DIR</option></entry>
	      <entry>ls -l</entry>
	      <entry>directory listing</entry>
	    </row>
	    <row>
	      <entry><option>ERASE</option></entry>
	      <entry>rm</entry>
	      <entry>delete file(s)</entry>
	    </row>
	    <row>
	      <entry><option>EXIT</option></entry>
	      <entry>exit</entry>
	      <entry>exit current process</entry>
	    </row>
	    <row>
	      <entry><option>FC</option></entry>
	      <entry>comm, cmp</entry>
	      <entry>file compare</entry>
	    </row>
	    <row>
	      <entry><option>FIND</option></entry>
	      <entry>grep</entry>
	      <entry>find strings in files</entry>
	    </row>
	    <row>
	      <entry><option>MD</option></entry>
	      <entry>mkdir</entry>
	      <entry>make directory</entry>
	    </row>
	    <row>
	      <entry><option>MKDIR</option></entry>
	      <entry>mkdir</entry>
	      <entry>make directory</entry>
	    </row>
	    <row>
	      <entry><option>MORE</option></entry>
	      <entry>more</entry>
	      <entry>text file paging filter</entry>
	    </row>
	    <row>
	      <entry><option>MOVE</option></entry>
	      <entry>mv</entry>
	      <entry>move</entry>
	    </row>
	    <row>
	      <entry><option>PATH</option></entry>
	      <entry>$PATH</entry>
	      <entry>path to executables</entry>
	    </row>
	    <row>
	      <entry><option>REN</option></entry>
	      <entry>mv</entry>
	      <entry>rename (move)</entry>
	    </row>
	    <row>
	      <entry><option>RENAME</option></entry>
	      <entry>mv</entry>
	      <entry>rename (move)</entry>
	    </row>
	    <row>
	      <entry><option>RD</option></entry>
	      <entry>rmdir</entry>
	      <entry>remove directory</entry>
	    </row>
	    <row>
	      <entry><option>RMDIR</option></entry>
	      <entry>rmdir</entry>
	      <entry>remove directory</entry>
	    </row>
	    <row>
	      <entry><option>SORT</option></entry>
	      <entry>sort</entry>
	      <entry>sort file</entry>
	    </row>
	    <row>
	      <entry><option>TIME</option></entry>
	      <entry>date</entry>
	      <entry>display system time</entry>
	    </row>
	    <row>
	      <entry><option>TYPE</option></entry>
	      <entry>cat</entry>
	      <entry>output file to <filename>stdout</filename></entry>
	    </row>
	    <row>
	      <entry><option>XCOPY</option></entry>
	      <entry>cp</entry>
	      <entry>(extended) file copy</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>	


      <note>
      <para>Virtually all UNIX and shell operators and commands have
	many more options and enhancements than their DOS and batch file
	counterparts. Many DOS batch files rely on auxiliary utilities,
	such as <command>ask.com</command>, a crippled counterpart to
	<link linkend="readref">read</link>.</para>

      <para>DOS supports only a very limited and incompatible subset of
	filename <link linkend="globbingref">wild-card expansion</link>,
	recognizing just the <token>*</token> and <token>?</token>
	characters.</para>
	</note>

      <para>Converting a DOS batch file into a shell script is generally
	straightforward, and the result ofttimes reads better than the
	original.</para>

      <example id="VIEWDAT">
	<title>VIEWDATA.BAT: DOS Batch File</title>
	<programlisting>&VIEWDAT;</programlisting>
      </example>

      <para>
      The script conversion is somewhat of an improvement.
	<footnote><para>Various readers have suggested modifications
	of the above batch file to prettify it and make it more
	compact and efficient. In the opinion of the <emphasis>ABS
	Guide</emphasis> author, this is wasted effort. A Bash script
	can access a DOS filesystem, or even an NTFS partition (with
	the help of <ulink url="http://www.ntfs-3g.org">ntfs-3g</ulink>)
	to do batch or scripted operations.</para></footnote>
      </para>

      <example id="viewdata">
	<title><firstterm>viewdata.sh</firstterm>: Shell Script Conversion
	of VIEWDATA.BAT</title>
	<programlisting>&viewdata;</programlisting>
      </example>



      <para>Ted Davis' <ulink url="http://www.maem.umr.edu/batch/">Shell
	Scripts on the PC</ulink> site has a set of comprehensive
	tutorials on the old-fashioned art of batch file
	programming. Certain of his ingenious techniques could conceivably
	have relevance for shell scripts.</para>

      
  </appendix>
    <!-- End DOS Batch File Conversion appendix -->


  <appendix id="exercises">
    <title>Exercises</title>

      <para>The exercises that follow test and extend your knowledge
	of scripting. Think of them as a challenge, as an entertaining way
	to take you further along the stony path toward UNIX wizardry.</para>

      <para>On a dingy side street in a run-down section of Hoboken, New
	Jersey, there sits a nondescript squat two-story brick building
	with a inscription incised on a marble plate in its wall:
	<emphasis>Bash Scripting Hall of Fame</emphasis>. Inside,
	among various dusty uninteresting exhibits is a corroding,
	cobweb-festooned brass plaque inscribed with a short,
	very short list of those few persons who have successfully
	mastered the material in the <firstterm>Advanced Bash Scripting
	Guide</firstterm>, as evidenced by their performance on the
	following Exercise sections. . . .</para>

    <sect1 id="scriptanalysis">
      <title>Analyzing Scripts</title>

      <para>Examine the following script. Run it, then explain what it
        does.  Annotate the script and rewrite it in a more compact and
        elegant manner.</para>
	
       <para>
       <programlisting>#!/bin/bash

MAX=10000


  for((nr=1; nr<$MAX; nr++))
  do

    let "t1 = nr % 5"
    if [ "$t1" -ne 3 ]
    then
      continue
    fi

    let "t2 = nr % 7"
    if [ "$t2" -ne 4 ]
    then
      continue
    fi

    let "t3 = nr % 9"
    if [ "$t3" -ne 5 ]
    then
      continue
    fi

  break   # What happens when you comment out this line? Why?

  done

  echo "Number = $nr"


exit 0</programlisting>
       </para>

      <para>---</para>

      <para>Explain what the following script does. It is really just
        a parameterized command-line pipe.</para>

      <para>
        <programlisting>#!/bin/bash

DIRNAME=/usr/bin
FILETYPE="shell script"
LOGFILE=logfile

file "$DIRNAME"/* | fgrep "$FILETYPE" | tee $LOGFILE | wc -l

exit 0</programlisting>
      </para>

      <para>---</para>

      <para>Examine and explain the following script. For hints, you
        might refer to the listings for <link
        linkend="findref">find</link> and <link
        linkend="statref">stat</link>.</para>

      <para>
        <programlisting>#!/bin/bash

# Author:  Nathan Coulter
# This code is released to the public domain.
# The author gave permission to use this code snippet in the ABS Guide.

find -maxdepth 1 -type f -printf '%f\000'  | {
   while read -d $'\000'; do
      mv "$REPLY" "$(date -d "$(stat -c '%y' "$REPLY") " '+%Y%m%d%H%M%S'
      )-$REPLY"
   done
}

# Warning: Test-drive this script in a "scratch" directory.
# It will somehow affect all the files there.</programlisting>
      </para>

      <para>---</para>

      <para>A reader sent in the following code snippet.</para>

	 <para>
         <programlisting>while read LINE
do
  echo $LINE
done < `tail -f /var/log/messages`</programlisting>
	 </para>

	<para>He wished to write a script tracking changes to the system log
	   file, <filename>/var/log/messages</filename>. Unfortunately,
	   the above code block hangs and does nothing
	   useful. Why? Fix this so it does work. (Hint:
	   rather than <link linkend="redirref">redirecting the
	   <filename>stdin</filename> of the loop</link>, try a <link
	   linkend="piperef">pipe</link>.)</para>


      <para>---</para>

      <para>Analyze the following <quote>one-liner</quote> (here
        split into two lines for clarity) contributed by Rory
        Winston:</para>

	 <para>
      <programlisting>export SUM=0; for f in $(find src -name "*.java");
do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUM</programlisting>
	 </para>

      <para>Hint: First, break the script up into bite-sized
	sections. Then, carefully examine its use of <link
	linkend="dblparens">double-parentheses</link> arithmetic,
	the <link linkend="exportref">export</link> command,
	the <link linkend="findref">find</link> command, the
	<link linkend="wcref">wc</link> command, and <link
	linkend="awkref">awk</link>.</para>

      <para>---</para>


      <para>Analyze <xref linkend="lifeslow">, and reorganize it in a
	simplified and more logical style. See how many of the variables
	can be eliminated, and try to optimize the script to speed up
	its execution time.</para>

      <para>Alter the script so that it accepts any ordinary ASCII
	text file as input for its initial <quote>generation</quote>. The
	script will read the first <parameter>$ROW*$COL</parameter>
	characters, and set the occurrences of vowels as
	<quote>living</quote> cells. Hint: be sure to translate the
	spaces in the input file to underscore characters.</para>

    </sect1>
    <!-- End Analyzing Scripts section -->



    <sect1 id="writingscripts">
      <title>Writing Scripts</title>

      <para><anchor id="writingscripts1"></para>

      <para>Write a script to carry out each of the following tasks.</para>


      <variablelist id="exeasy">
        <title><anchor id="exeasy1">EASY</title>

	  <varlistentry>
	    <term><command>Self-reproducing Script</command></term>
	    <listitem>
	    <para>Write a script that backs itself up, that is, copies
	      itself to a file named <filename>backup.sh</filename>.</para>
            <para>Hint: Use the <link linkend="catref">cat</link> command
	      and the <link linkend="scrnameparam">appropriate positional
	      parameter</link>.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Home Directory Listing</command></term>
	    <listitem>
	    <para>Perform a recursive directory listing on the user's home
	      directory and save the information to a file. Compress
	      the file, have the script prompt the user to insert
	      a USB flash drive, then press <keycap>ENTER</keycap>.
              Finally, save the file to the flash drive after making
              certain the flash drive has properly mounted by parsing
              the output of <link linkend="dfref">df</link>.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Converting  <link linkend="forloopref1">for</link>
	    loops to <link linkend="whileloopref">while</link> and <link
	    linkend="untilloopref">until</link> loops</command></term>
	    <listitem>
	    <para>Convert the <firstterm>for loops</firstterm> in <xref
	      linkend="ex22"> to <firstterm>while
	      loops</firstterm>. Hint: store the data in an <link
	      linkend="arrayref">array</link> and step through the array
	      elements.</para>
	    <para>Having already done the <quote>heavy lifting</quote>,
	      now convert the loops in the example to <firstterm> until
	      loops</firstterm>.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Changing the line spacing of a text file</command></term>
	    <listitem>

	    <para>Write a script that reads each line of a target file, then
	      writes the line back to <filename>stdout</filename>, but with
	      an extra blank line following. This has the effect of
	      <emphasis>double-spacing</emphasis> the file.</para>

	    <para>Include all necessary code to check whether the script
	      gets the necessary command line argument (a filename),
	      and whether the specified file exists.</para>

	    <para>When the script runs correctly, modify it to
	      <emphasis>triple-space</emphasis> the target file.</para>

	    <para>Finally, write a script to remove all blank lines from
	      the target file, <emphasis>single-spacing</emphasis> it.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Backwards Listing</command></term>
	    <listitem>
	    <para>Write a script that echoes itself to
	      <filename>stdout</filename>, but
	      <emphasis>backwards</emphasis>.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Automatically Decompressing Files</command></term>
	    <listitem>
	    <para>Given a list of filenames as input, this script
	      queries each target file (parsing the output of the
	      <link linkend="fileref">file</link> command) for
	      the type of compression used on it. Then the script
	      automatically invokes the appropriate decompression command
	      (<command>gunzip</command>, <command>bunzip2</command>,
	      <command>unzip</command>, <command>uncompress</command>,
	      or whatever). If a target file is not compressed, the
	      script emits a warning message, but takes no other action
	      on that particular file.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Unique System ID</command></term>
	    <listitem>
	    <para>Generate a <quote>unique</quote> 6-digit hexadecimal
	      identifier for your computer. Do <emphasis>not</emphasis>
	      use the flawed <link linkend="hostidref">hostid</link>
	      command. Hint: <command><link
	      linkend="md5sumref">md5sum</link>
	      <filename>/etc/passwd</filename></command>, then select
	      the first 6 digits of output.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Backup</command></term>
	    <listitem>
	    <para>Archive as a <quote>tarball</quote>
	      (<filename>*.tar.gz</filename> file) all the files
	      in your home directory tree
	      (<filename>/home/your-name</filename>) that have
	      been modified in the last 24 hours. Hint: use <link
	      linkend="findref">find</link>.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Checking whether a process is still running</command></term>
	    <listitem>
	    <para>Given a <link linkend="processidref">process ID</link>
	      (<firstterm>PID</firstterm>) as an argument, this script
	      will check, at user-specified intervals, whether
	      the given process is still running. You may use
	      the <link linkend="ppssref">ps</link> and <link
	      linkend="sleepref">sleep</link> commands.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Primes</command></term>
	    <listitem>
	    <para>Print (to stdout) all prime numbers between 60000 and
	      63000. The output should be nicely formatted in columns
	      (hint: use <link linkend="printfref">printf</link>).</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Lottery Numbers</command></term>
	    <listitem>
	    <para>One type of lottery involves picking five
	      different numbers, in the range of 1 - 50. Write a
	      script that generates five pseudorandom numbers in this
	      range, <emphasis>with no duplicates</emphasis>. The
	      script will give the option of echoing the numbers to
	      <filename>stdout</filename> or saving them to a file,
	      along with the date and time the particular number set
	      was generated. (If your script consistently generates
	    <emphasis>winning</emphasis> lottery numbers, then you can
	    retire on your earnings and leave shell scripting to those
	    of us who have to work for a living.)</para>
	    </listitem>
	  </varlistentry>

      </variablelist>


      <variablelist id="exmedium">
        <title><anchor id="exmedium1">INTERMEDIATE</title>

	  <varlistentry>
	    <term><command>Integer or String</command></term>
	    <listitem>
	    <para>Write a script <link linkend="functionref">function</link>
	      that determines if an argument passed to it is an integer
	      or a string. The function will return TRUE (0) if
	      passed an integer, and FALSE (1) if passed a string.</para>
            <para>Hint: What does the following expression return
	      when <varname>$1</varname> is <emphasis>not</emphasis>
	      an integer?</para>
            <para><varname>expr $1 + 0</varname></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Managing Disk Space</command></term>
	    <listitem>
	    <para>List, one at a time, all files larger than 100K in
	      the <filename class="directory">/home/username</filename>
	      directory tree. Give the user the option to delete or
	      compress the file, then proceed to show the next one. Write
	      to a logfile the names of all deleted files and the
	      deletion times.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Banner</command></term>
	    <listitem>
	    <para>Simulate the functionality of the deprecated <link
	      linkend="bannerref">banner</link> command in a script.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Removing Inactive Accounts</command></term>
	    <listitem>
	    <para>Inactive accounts on a network waste disk space and may
	      become a security risk. Write an administrative script
	      (to be invoked by <firstterm>root</firstterm> or the <link
	      linkend="cronref">cron daemon</link>) that checks
	      for and deletes user accounts that have not been accessed
	      within the last 90 days.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Enforcing Disk Quotas</command></term>
	    <listitem>
	    <para>Write a script for a multi-user system that checks users'
	      disk usage. If a user surpasses a preset limit
	      (100 MB, for example) in her <filename
	      class="directory">/home/username</filename> directory,
	      then the script automatically sends her a warning
	      e-mail.</para>
            <para>The script will use the <link linkend="duref">du</link> and
	      <link linkend="commmail1">mail</link> commands. As an option,
	      it will allow setting and enforcing quotas using the <link
	      linkend="quotaref">quota</link> and <link
	      linkend="setquotaref">setquota</link> commands.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Logged in User Information</command></term>
	    <listitem>

	    <para>For all logged in users, show their real names and the time
              and date of their last login.</para>
	      
	    <para>Hint: use <link linkend="whoref">who</link>,
	      <link linkend="lastlogref">lastlog</link>,
	      and parse <filename>/etc/passwd</filename>.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Safe Delete</command></term>
	    <listitem>
	    <para>Implement, as a script, a <quote>safe</quote> delete
	      command, <filename>sdel.sh</filename>. Filenames passed as
	      command-line arguments to this script are not deleted,
	      but instead <link linkend="gzipref">gzipped</link>
	      if not already compressed (use <link
	      linkend="fileref">file</link> to check), then moved
	      to a <filename class="directory">~/TRASH</filename>
	      directory. Upon invocation, the script checks the <filename
	      class="directory">~/TRASH</filename> directory for files
	      older than 48 hours and <link linkend="rmref">permanently
	      deletes</link> them. (An better alternative might be to
	      have a second script handle this, periodically invoked
	      by the <link linkend="cronref">cron daemon</link>.)</para>
            <para><emphasis>Extra credit:</emphasis> Write the script
	      so it can handle files and directories <link
	      linkend="rmrecurs">recursively</link>. This would give it
	      the capability of <quote>safely deleting</quote> entire
	      directory structures.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Making Change</command></term>
	    <listitem>
	    <para>What is the most efficient way to make change for $1.68,
	      using only coins in common circulations (up to 25c)? It's
	      6 quarters, 1 dime, a nickel, and three cents.</para>
            <para>Given any arbitrary command line input in dollars and
	      cents ($*.??), calculate the change, using the minimum
	      number of coins. If your home country is not the United
	      States, you may use your local currency units instead. The
	      script will need to parse the command line input, then
	      change it to multiples of the smallest monetary unit (cents
	      or whatever). Hint: look at <xref linkend="ex61">.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Quadratic Equations</command></term>
	    <listitem>
	    <para>Solve a <firstterm>quadratic</firstterm> equation of the form
	      <parameter>Ax^2 + Bx + C = 0</parameter>. Have a script take
	      as arguments the coefficients, <userinput>A</userinput>,
	      <userinput>B</userinput>, and <userinput>C</userinput>,
	      and return the solutions to four decimal places.</para>

	    <para>Hint: pipe the coefficients to <link
	      linkend="bcref">bc</link>, using the well-known formula,
	      <parameter>x = ( -B +/- sqrt( B^2 - 4AC ) ) / 2A</parameter>.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Table of Logarithms</command></term>
	    <listitem>
	    <para>Using the <link linkend="bcref">bc</link> and <link
	      linkend="printfref">printf</link> commands, print out a
	      nicely-formatted table of eight-place natural logarithms
	      in the interval between 0.00 and 100.00, in steps of
	      .01.</para>
	    <para>Hint: <firstterm>bc</firstterm> requires the
	      <option>-l</option> option to load the math library.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Sum of Matching Numbers</command></term>
	    <listitem>
	    <para>Find the sum of all five-digit numbers (in the range
	      10000 - 99999) containing <emphasis>exactly two</emphasis>
	      out of the following set of digits: { 4, 5, 6 }. These may
	      repeat within the same number, and if so, they count once
	      for each occurrence.</para>
	    <para>Some examples of <firstterm>matching numbers</firstterm> are
	      42057, 74638, and 89515.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Lucky Numbers</command></term>
	    <listitem>
	    <para>A <firstterm>lucky number</firstterm> is one whose
	      individual digits add up to 7, in successive additions. For
	      example, 62431 is a <firstterm>lucky number</firstterm>
	      (6 + 2 + 4 + 3 + 1 = 16, 1 + 6 = 7). Find all the
	      <firstterm>lucky numbers</firstterm> between 1000 and
	      10000.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Craps</command></term>
	    <listitem>
	    <para>Borrowing the ASCII graphics from <xref linkend="petals">,
	      write a script that plays the well-known gambling game of
	      <firstterm>craps</firstterm>. The script will accept bets
	      from one or more players, roll the dice, and keep track of
	      wins and losses, as well as of each player's bankroll.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Tic-tac-toe</command></term>
	    <listitem>
	    <para>Write a script that plays the child's game of
	      <firstterm>tic-tac-toe</firstterm> against a human
	      player. The script will let the human choose whether
	      to take the first move. The script will follow
	      an optimal strategy, and therefore never lose. To simplify
	      matters, you may use ASCII graphics:</para>

	    <para><programlisting>   o | x |
   ----------
     | x |
   ----------
     | o |
     
   Your move, human (row, column)?</programlisting></para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Alphabetizing a String</command></term>
	    <listitem>
	    <para>Alphabetize (in ASCII order) an arbitrary string
	      read from the command line.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Parsing</command></term>
	    <listitem>
	    <para>Parse <filename>/etc/passwd</filename>, and output
	      its contents in nice, easy-to-read tabular form.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Logging Logins</command></term>
	    <listitem>
	    <para>Parse <filename>/var/log/messages</filename> to
	      produce a nicely formatted file of user logins and login
	      times. The script may need to run as
	      <firstterm>root</firstterm>. (Hint: Search for the string
	      <quote>LOGIN.</quote>)</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Pretty-Printing a Data File</command></term>
	    <listitem>
	    <para>Certain database and spreadsheet packages use save-files
	      with <firstterm>comma-separated values</firstterm>
	      (CSVs). Other applications often need to parse these
	      files.</para>
	    <para>Given a data file with comma-separated fields,
	      of the form:
	        <programlisting>Jones,Bill,235 S. Williams St.,Denver,CO,80221,(303) 244-7989
Smith,Tom,404 Polk Ave.,Los Angeles,CA,90003,(213) 879-5612
...</programlisting>
	      Reformat the data and print it out to
	      <filename>stdout</filename> in labeled, evenly-spaced columns.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Justification</command></term>
	    <listitem>
	    <para>Given ASCII text input either from
	      <filename>stdin</filename> or a file, adjust
	      the word spacing to right-justify each line to a
	      user-specified line-width, then send the output to
	      <filename>stdout</filename>.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Mailing List</command></term>
	    <listitem>
	    <para>Using the <link linkend="commmail1">mail</link> command,
	      write a script that manages a simple mailing list. The
	      script automatically e-mails the monthly company newsletter,
	      read from a specified text file, and sends it to all the
	      addresses on the mailing list, which the script reads from
	      another specified file.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Generating Passwords</command></term>
	    <listitem>
	    <para>Generate pseudorandom 8-character passwords, using
	      characters in the ranges [0-9], [A-Z], [a-z]. Each password
	      must contain at least two digits.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Monitoring a User</command></term>
	    <listitem>

	    <para>You suspect that one particular user on the network
	      has been abusing his privileges and possibly attempting to
	      hack the system. Write a script to automatically monitor
	      and log his activities when he's signed on. The log file
	      will save entries for the previous week, and delete those
	      entries more than seven days old.</para>

           <para>You may use <link linkend="lastref">last</link>,
             <link linkend="lastlogref">lastlog</link>, and <link
             linkend="lastcommref">lastcomm</link> to aid your
             surveillance of the suspected malefactor.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Checking for Broken Links</command></term>
	    <listitem>
	    <para>Using <link linkend="lynxref">lynx</link> with the
	      <option>-traversal</option> option, write a script that
	      checks a Web site for broken links.</para>
	    </listitem>
	  </varlistentry>

      </variablelist>


      <variablelist id="exdifficult">
        <title><anchor id="exdifficult1">DIFFICULT</title>

	  <varlistentry>
	    <term><command>Testing Passwords</command></term>
	    <listitem>
	    <para>Write a script to check and validate passwords. The object
	      is to flag <quote>weak</quote> or easily guessed password
	      candidates.</para>

	    <para>A trial password will be input to the script as a
	       command line parameter. To be considered acceptable,
	       a password must meet the following minimum qualifications:

            <itemizedlist>
	      <listitem>
	        <para>Minimum length of 8 characters</para>
	      </listitem>

	      <listitem>
	        <para>Must contain at least one numeric character</para>
	      </listitem>

	      <listitem>
	        <para>Must contain at least one of the following
		  non-alphabetic characters: <token>@</token>,
		  <token>#</token>, <token>$</token>, <token>%</token>,
		  <token>&</token>, <token>*</token>, <token>+</token>,
		  <token>-</token>, <token>=</token></para>
	      </listitem>
            </itemizedlist></para>

	     <para>Optional:

            <itemizedlist>
	      <listitem>
	        <para>Do a dictionary check on every sequence of at least
		  four consecutive alphabetic characters in the password under
		  test. This will eliminate passwords containing embedded
		  <quote>words</quote> found in a standard dictionary.</para>
	      </listitem>

	      <listitem>
	        <para>Enable the script to check all the passwords on your
		  system. These may or may not reside in
		  <filename>/etc/passwd</filename>.</para>
	      </listitem>
            </itemizedlist></para>

	     <para>This exercise tests mastery of <link
	       linkend="regexref">Regular Expressions</link>.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Cross Reference</command></term>
	    <listitem>
	    <para>Write a script that generates a
	      <firstterm>cross-reference</firstterm>
	      (<firstterm>concordance</firstterm>) on a target file.
	      The output will be a listing of all word occurrences in
	      the target file, along with the line numbers in which
	      each word occurs. Traditionally, <firstterm>linked
	      list</firstterm> constructs would be used in such
	      applications. Therefore, you should investigate <link
	      linkend="arrayref">arrays</link> in the course of
	      this exercise. <xref linkend="wf"> is probably
	      <emphasis>not</emphasis> a good place to start.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="newtonsqrt"><command>Square Root</command></term>
	    <listitem>
            <para>Write a script to calculate square roots of numbers
              using <firstterm>Newton's Method</firstterm>.</para>

            <para>The algorithm for this, expressed as a snippet of Bash
              <link linkend="pseudocoderef">pseudo-code</link> is:</para>

            <para><programlisting>#  (Isaac) Newton's Method for speedy extraction
#+ of square roots.

guess = $argument
#  $argument is the number to find the square root of.
#  $guess is each successive calculated "guess" -- or trial solution --
#+ of the square root.
#  Our first "guess" at a square root is the argument itself.

oldguess = 0
# $oldguess is the previous $guess.

tolerance = .000001
# To how close a tolerance we wish to calculate.

loopcnt = 0
# Let's keep track of how many times through the loop.
# Some arguments will require more loop iterations than others.


while [ ABS( $guess $oldguess ) -gt $tolerance ]
#       ^^^^^^^^^^^^^^^^^^^^^^^ Fix up syntax, of course.

#      "ABS" is a (floating point) function to find the absolute value
#+      of the difference between the two terms.
#             So, as long as difference between current and previous
#+            trial solution (guess) exceeds the tolerance, keep looping.

do
   oldguess = $guess  # Update $oldguess to previous $guess.

#  =======================================================
   guess = ( $oldguess + ( $argument / $oldguess ) ) / 2.0
#        = 1/2 ( ($oldguess **2 + $argument) / $oldguess )
#  equivalent to:
#        = 1/2 ( $oldguess + $argument / $oldguess )
#  that is, "averaging out" the trial solution and
#+ the proportion of argument deviation
#+ (in effect, splitting the error in half).
#  This converges on an accurate solution
#+ with surprisingly few loop iterations . . .
#+ for arguments > $tolerance, of course.
#  =======================================================

   (( loopcnt++ ))     # Update loop counter.
done</programlisting></para>

            <para>It's a simple enough recipe, and
              <emphasis>seems</emphasis> at first glance easy enough to
              convert into a working Bash script. The problem, though,
              is that Bash has <link linkend="nofloatingpoint">no native
              support for floating point numbers</link>. So, the script
              writer needs to use <link linkend="bcref">bc</link> or
              possibly <link linkend="awkref">awk</link> to convert the
              numbers and do the calculations. It may get rather messy
              . . .</para>

	    </listitem>
	  </varlistentry>




	  <varlistentry>
	    <term><command>Logging File Accesses</command></term>
	    <listitem>
	    <para>Log all accesses to the files in <filename
	      class="directory">/etc</filename> during the course of
	      a single day. This information should include the filename,
	      user name, and access time. If any alterations to the
	      files take place, that should be flagged. Write this data
	      as neatly formatted records in a logfile.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Monitoring Processes</command></term>
	    <listitem>
	    <para>Write a script to continually monitor all running
	      processes and to keep track of how many child processes each
	      parent spawns. If a process spawns more than five children,
	      then the script sends an e-mail to the system administrator
	      (or <firstterm>root</firstterm>) with all relevant
	      information, including the time, PID of the parent, PIDs
	      of the children, etc. The script appends a report to a log
	      file every ten minutes.  </para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Strip Comments</command></term>
	    <listitem>
	    <para>Strip all comments from a shell script whose name
	      is specified on the command line. Note that the <link
	      linkend="shabangref">#! line</link> must not be stripped
	      out.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Strip HTML Tags</command></term>
	    <listitem>
	    <para>Strip all HTML tags from a specified HTML file, then
	      reformat it into lines between 60 and 75 characters
	      in length. Reset paragraph and block spacing, as
	      appropriate, and convert HTML tables to their approximate
	      text equivalent.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>XML Conversion</command></term>
	    <listitem>
	    <para>Convert an XML file to both HTML and text format.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><anchor id="cspammers"><command>Chasing Spammers</command></term>
	    <listitem>

	    <para> Write a script that analyzes a spam e-mail by doing
	      DNS lookups on the IP addresses in the headers to identify
	      the relay hosts as well as the originating ISP. The
	      script will forward the unaltered spam message to the
	      responsible ISPs. Of course, it will be necessary to
	      filter out <emphasis>your own ISP's IP address</emphasis>,
	      so you don't end up complaining about yourself.</para>

            <para>As necessary, use the appropriate <link
              linkend="communinfo1">network analysis commands</link>.</para>

            <para>For some ideas, see <xref linkend="isspammer"> and <xref
	      linkend="isspammer2">.</para>

            <para>Optional: Write a script that searches through a list of
	      e-mail messages and deletes the spam according to specified
	      filters.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Creating man pages</command></term>
	    <listitem>

	    <para>Write a script that automates the process of creating
	      <link linkend="manref">man pages</link>.</para>

            <para>Given a text file which contains information to be
	      formatted into a <firstterm>man page</firstterm>, the
	      script will read the file, then invoke the appropriate
	      <link linkend="groffref">groff</link> commands to
	      output the corresponding <firstterm>man page</firstterm>
	      to <filename>stdout</filename>. The text file contains
	      blocks of information under the standard <firstterm>man
	      page</firstterm> headings, i.e., NAME, SYNOPSIS,
	      DESCRIPTION, etc.</para>

            <para><xref linkend="maned"> is an instructive first step.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Morse Code</command></term>
	    <listitem>
	    <para>Convert a text file to Morse code. Each character of the
	      text file will be represented as a corresponding Morse
	      code group of dots and dashes (underscores), separated by
	      whitespace from the next. For example:
		<programlisting>Invoke the "morse.sh" script with "script"
as an argument to convert to Morse.


$ sh morse.sh script

... _._. ._. .. .__. _
s   c    r   i   p   t</programlisting></para>
	    </listitem>
	  </varlistentry>


	  <varlistentry>
	    <term><command>Hex Dump</command></term>
	    <listitem>
	    <para>Do a hex(adecimal) dump on a binary file
	      specified as an argument. The output should be in neat
	      tabular fields, with the first field showing the address,
	      each of the next 8 fields a 4-byte hex number, and the final
	      field the ASCII equivalent of the previous 8 fields.</para>
            <para>The obvious followup to this is to extend the hex dump
	      script into a disassembler. Using a lookup table, or some other
	      clever gimmick, convert the hex values into 80x86 op
	      codes.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Emulating a Shift Register</command></term>
	    <listitem>
	    <para>Using <xref linkend="stackex"> as an inspiration,
	      write a script that emulates a 64-bit shift register as
	      an <link linkend="arrayref">array</link>. Implement
	      functions to <firstterm>load</firstterm> the register,
	      <firstterm>shift left</firstterm>, <firstterm>shift
	      right</firstterm>, and <firstterm>rotate</firstterm>
	      it. Finally, write a function that interprets the register
	      contents as eight 8-bit ASCII characters.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Calculating Determinants</command></term>
	    <listitem>
	    <para>Write a script that calculates
	      determinants
	        <footnote>
		<para>For all you fine people who failed second-year algebra,
                a <firstterm>determinant</firstterm> is a numerical quantity
		associated with a multidimensional
		<firstterm>matrix</firstterm> (<link
		linkend="arrayref">array</link> of numbers).
		  <programlisting>For the simple case of a 2 x 2 determinant:

  |a  b|
  |b  a|

The solution is a*a - b*b, where "a" and "b" represent numbers.</programlisting>
                </para></footnote>
		
		by <link
	      linkend="recursionref0">recursively</link> expanding the
	      <firstterm>minors</firstterm>. Use a 4 x 4 determinant as
	      a test case.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Hidden Words</command></term>
	    <listitem>
	    <para>Write a <quote>word-find</quote> puzzle generator,
	      a script that hides 10 input words in a 10 x 10 array
	      of random letters. The words may be hidden across, down,
	      or diagonally.</para>
            <para>Optional: Write a script that <emphasis>solves</emphasis>
	      word-find puzzles. To keep this from becoming too difficult,
	      the solution script will find only horizontal and vertical
	      words. (Hint: Treat each row and column as a string, and
	      search for substrings.)</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Anagramming</command></term>
	    <listitem>
	    <para> Anagram 4-letter input. For example, the
	      anagrams of <emphasis>word</emphasis> are:
	      <emphasis>do or rod row word</emphasis>. You may use
	      <filename>/usr/share/dict/linux.words</filename> as the
	      reference list.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Word Ladders</command></term>
	    <listitem>
            <para>A <quote>word ladder</quote> is a sequence of words,
              with each successive word in the sequence differing from
              the previous one by a single letter.</para>

            <para>For example, to <quote>ladder</quote> from
              <emphasis>mark</emphasis> to
              <emphasis>vase</emphasis>:</para>

            <para>
	    <programlisting>
mark --> park --> part --> past --> vast --> vase
         ^           ^       ^      ^           ^</programlisting>
            </para>

            <para>Write a script that solves word ladder puzzles. Given
	      a starting and an ending word, the script will list all
	      intermediate steps in the <quote>ladder.</quote> Note
	      that <emphasis>all</emphasis> words in the sequence must
	      be legitimate dictionary words.</para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Fog Index</command></term>
	    <listitem>

	    <para>The <quote>fog index</quote> of a passage of text
	      estimates its reading difficulty, as a number corresponding
	      roughly to a school grade level. For example, a passage
	      with a fog index of 12 should be comprehensible to anyone
	      with 12 years of schooling.</para>

	    <para>The Gunning version of the fog index uses the following
	      algorithm.</para>

             <orderedlist>

               <listitem><para>Choose a section of the text at least
                 100 words in length.</para></listitem>

               <listitem><para>Count the number of sentences (a portion of
                 a sentence truncated by the boundary of the text section
                 counts as one).</para></listitem>

               <listitem>
	         <para>Find the average number of words per
                   sentence.</para>
		   
		 <para>AVE_WDS_SEN = TOTAL_WORDS / SENTENCES</para>
               </listitem>

               <listitem>
		 <para>Count the number of <quote>difficult</quote>
		   words in the segment -- those containing at least
		   3 syllables. Divide this quantity by total words to
		   get the proportion of difficult words.</para>

                 <para>PRO_DIFF_WORDS = LONG_WORDS / TOTAL_WORDS</para>
               </listitem>

               <listitem>
                 <para>The Gunning fog index is the sum of the above two
                   quantities, multiplied by 0.4, then rounded to the
                   nearest integer.</para>

                 <para>G_FOG_INDEX = int ( 0.4 * ( AVE_WDS_SEN  + PRO_DIFF_WORDS ) )</para>
               </listitem>

             </orderedlist>

            <para>Step 4 is by far the most difficult portion of the
	      exercise. There exist various algorithms for estimating
	      the syllable count of a word. A rule-of-thumb formula
	      might consider the number of letters in a word and the
	      vowel-consonant mix.</para>
	      
	    <para>A strict interpretation of the Gunning fog index does
	      not count compound words and proper nouns as
	      <quote>difficult</quote> words, but this would enormously
	      complicate the script.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Calculating PI using Buffon's Needle</command></term>
	    <listitem>

            <para>The Eighteenth Century French mathematician de Buffon
	      came up with a novel experiment. Repeatedly drop a needle
	      of length <replaceable>n</replaceable> onto a wooden floor
	      composed of long and narrow parallel boards. The cracks
	      separating the equal-width floorboards are a fixed distance
	      <replaceable>d</replaceable> apart. Keep track of the
	      total drops and the number of times the needle intersects
	      a crack on the floor. The ratio of these two quantities
	      turns out to be a fractional multiple of PI.</para>

            <para>In the spirit of <xref linkend="cannon">, write a
	      script that runs a Monte Carlo simulation of
	      <firstterm>Buffon's Needle</firstterm>. To simplify matters,
	      set the needle length equal to the distance between the
	      cracks, <parameter>n = d</parameter>.</para>

            <para>Hint: there are actually two critical variables:
              the distance from the center of the needle to the nearest
              crack, and the inclination angle of the needle to that crack.
	      You may use <link linkend="bcref">bc</link> to handle
	      the calculations.</para>

	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><command>Playfair Cipher</command></term>
	    <listitem>

	    <para>Implement the Playfair (Wheatstone) Cipher in a
	      script.</para>

	    <para>The Playfair Cipher encrypts text by substitution
	      of <firstterm>digrams</firstterm> (2-letter groupings).
	      It is traditional to use a 5 x 5 letter scrambled-alphabet
	      <firstterm>key square</firstterm> for the encryption and
	      decryption.</para>

             <para>
	     <programlisting>   C O D E S
   A B F G H
   I K L M N
   P Q R T U
   V W X Y Z

Each letter of the alphabet appears once, except "I" also represents
"J". The arbitrarily chosen key word, "CODES" comes first, then all
the rest of the alphabet, in order from left to right, skipping letters
already used.

To encrypt, separate the plaintext message into digrams (2-letter
groups). If a group has two identical letters, delete the second, and
form a new group. If there is a single letter left over at the end,
insert a "null" character, typically an "X."

THIS IS A TOP SECRET MESSAGE

TH IS IS AT OP SE CR ET ME SA GE



For each digram, there are three possibilities.
-----------------------------------------------

1) Both letters will be on the same row of the key square:
   For each letter, substitute the one immediately to the right, in that
   row. If necessary, wrap around left to the beginning of the row.

or

2) Both letters will be in the same column of the key square:
   For each letter, substitute the one immediately below it, in that
   row. If necessary, wrap around to the top of the column.

or

3) Both letters will form the corners of a rectangle within the key square:
   For each letter, substitute the one on the other corner the rectangle
   which lies on the same row.


The "TH" digram falls under case #3.
G H
M N
T U           (Rectangle with "T" and "H" at corners)

T --&gt; U
H --&gt; G


The "SE" digram falls under case #1.
C O D E S     (Row containing "S" and "E")

S --&gt; C  (wraps around left to beginning of row)
E --&gt; S

=========================================================================

To decrypt encrypted text, reverse the above procedure under cases #1
and #2 (move in opposite direction for substitution). Under case #3,
just take the remaining two corners of the rectangle.


Helen Fouche Gaines' classic work, ELEMENTARY CRYPTANALYSIS (1939), gives a
fairly detailed description of the Playfair Cipher and its solution methods.</programlisting>
             </para>

             <para>This script will have three main sections</para>

             <orderedlist id="playfairexref" numeration="upperroman">
	       <listitem><para>Generating the <firstterm>key square</firstterm>,
	         based on a user-input keyword.</para></listitem>
	       <listitem><para>Encrypting a <firstterm>plaintext</firstterm>
	         message.</para></listitem>
	       <listitem><para>Decrypting encrypted
	         text.</para></listitem>
             </orderedlist>

	     <para>The script will make extensive use of <link
	       linkend="arrayref">arrays</link> and <link
	       linkend="functionref">functions</link>.</para>

	    </listitem>
	  </varlistentry>

      </variablelist>


	  <para>--</para>
          <para>Please do not send the author your solutions to these
            exercises. There are more appropriate ways to impress him with
            your cleverness, such as submitting bugfixes and suggestions
            for improving this book.</para>


    </sect1>
    <!-- End Writing Scripts section -->

  </appendix>
    <!-- End Exercises appendix -->



  <appendix id="revisionhistory">
    <title>Revision History</title>

    <synopsis>
      This document first appeared as a 60-page HOWTO in the late spring
      of 2000. Since then, it has gone through quite a number of
      updates and revisions. This book could not have been written
      without the assistance of the Linux community, and especially
      of the volunteers of the <ulink url="http://www.tldp.org">Linux
      Documentation Project</ulink>.
    </synopsis>

    <para>Here is the e-mail to the LDP requesting permission to submit
     version 0.1.</para>

    <para><programlisting>From thegrendel@theriver.com Sat Jun 10 09:05:33 2000 -0700
Date: Sat, 10 Jun 2000 09:05:28 -0700 (MST)
From: "M. Leo Cooper" &lt;thegrendel@theriver.com&gt;
X-Sender: thegrendel@localhost
To: ldp-discuss@lists.linuxdoc.org
Subject: Permission to submit HOWTO

Dear HOWTO Coordinator,

I am working on and would like to submit to the LDP a HOWTO on the subject
of "Bash Scripting" (shell scripting, using 'bash'). As it happens,
I have been writing this document, off and on, for about the last eight
months or so, and I could produce a first draft in ASCII text format in
a matter of just a few more days.

I began writing this out of frustration at being unable to find a
decent book on shell scripting. I managed to locate some pretty good
articles on various aspects of scripting, but nothing like a complete,
beginning-to-end tutorial.  Well, in keeping with my philosophy, if all
else fails, do it yourself.

As it stands, this proposed "Bash-Scripting HOWTO" would serve as a
combination tutorial and reference, with the heavier emphasis on the
tutorial. It assumes Linux experience, but only a very basic level
of programming skills. Interspersed with the text are 79 illustrative
example scripts of varying complexity, all liberally commented. There
are even exercises for the reader.

At this stage, I'm up to 18,000+ words (124k), and that's over 50 pages of
text (whew!).


I haven't mentioned that I've previously authored an LDP HOWTO, the
"Software-Building HOWTO", which I wrote in Linuxdoc/SGML. I don't know
if I could handle Docbook/SGML, and I'm glad you have volunteers to do
the conversion. You people seem to have gotten on a more organized basis
these last few months. Working with Greg Hankins and Tim Bynum was nice,
but a professional team is even nicer.

Anyhow, please advise.


Mendel Cooper
thegrendel@theriver.com</programlisting></para>


      <table frame=none>
	<title>Revision History</title>
	<tgroup cols="3" colsep=0 rowsep=0>
	  <thead>
	    <row>
	      <entry>Release</entry>
	      <entry>Date</entry>
	      <entry>Comments</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry>0.1</entry>
	      <entry>14 Jun 2000</entry>
	      <entry>Initial release.</entry>
	    </row>
	    <row>
	      <entry><option>0.2</option></entry>
	      <entry>30 Oct 2000</entry>
	      <entry>Bugs fixed, plus much additional material and more
	      example scripts.</entry>
	    </row>
	    <row>
	      <entry><option>0.3</option></entry>
	      <entry>12 Feb 2001</entry>
	      <entry>Major update.</entry>
	    </row>
	    <row>
	      <entry><option>0.4</option></entry>
	      <entry>08 Jul 2001</entry>
	      <entry>Complete revision and expansion of the book.</entry>
	    </row>
	    <row>
	      <entry><option>0.5</option></entry>
	      <entry>03 Sep 2001</entry>
	      <entry>Major update: Bugfixes, material added,
	      sections reorganized.</entry>
	    </row>
	    <row>
	      <entry><option>1.0</option></entry>
	      <entry>14 Oct 2001</entry>
	      <entry>Stable release: Bugfixes, reorganization, material
	      added.</entry>
	    </row>
	    <row>
	      <entry><option>1.1</option></entry>
	      <entry>06 Jan 2002</entry>
	      <entry>Bugfixes, material and scripts added.</entry>
	    </row>
	    <row>
	      <entry><option>1.2</option></entry>
	      <entry>31 Mar 2002</entry>
	      <entry>Bugfixes, material and scripts added.</entry>
	    </row>
	    <row>
	      <entry><option>1.3</option></entry>
	      <entry>02 Jun 2002</entry>
	      <entry>TANGERINE release: A few bugfixes, much more material and
	      scripts added.</entry>
	    </row>
	    <row>
	      <entry><option>1.4</option></entry>
	      <entry>16 Jun 2002</entry>
	      <entry>MANGO release: A number of typos fixed, more
	      material and scripts.</entry>
	    </row>
	    <row>
	      <entry><option>1.5</option></entry>
	      <entry>13 Jul 2002</entry>
	      <entry>PAPAYA release: A few bugfixes, much more material and
	      scripts added.</entry>
	    </row>
	    <row>
	      <entry><option>1.6</option></entry>
	      <entry>29 Sep 2002</entry>
	      <entry>POMEGRANATE release: Bugfixes, more material,
	      one more script.</entry>
	    </row>
	    <row>
	      <entry><option>1.7</option></entry>
	      <entry>05 Jan 2003</entry>
	      <entry>COCONUT release: A couple of bugfixes, more material,
	      one more script.</entry>
	    </row>
	    <row>
	      <entry><option>1.8</option></entry>
	      <entry>10 May 2003</entry>
	      <entry>BREADFRUIT release: A number of bugfixes, more scripts and
	      material.</entry>
	    </row>
	    <row>
	      <entry><option>1.9</option></entry>
	      <entry>21 Jun 2003</entry>
	      <entry>PERSIMMON release: Bugfixes, and more material.</entry>
	    </row>
	    <row>
	      <entry><option>2.0</option></entry>
	      <entry>24 Aug 2003</entry>
	      <entry>GOOSEBERRY release: Major update.</entry>
	    </row>
	    <row>
	      <entry><option>2.1</option></entry>
	      <entry>14 Sep 2003</entry>
	      <entry>HUCKLEBERRY release: Bugfixes, and more material.</entry>
	    </row>
	    <row>
	      <entry><option>2.2</option></entry>
	      <entry>31 Oct 2003</entry>
	      <entry>CRANBERRY release: Major update.</entry>
	    </row>
	    <row>
	      <entry><option>2.3</option></entry>
	      <entry>03 Jan 2004</entry>
	      <entry>STRAWBERRY release: Bugfixes and more material.</entry>
	    </row>
	    <row>
	      <entry><option>2.4</option></entry>
	      <entry>25 Jan 2004</entry>
	      <entry>MUSKMELON release: Bugfixes.</entry>
	    </row>
	    <row>
	      <entry><option>2.5</option></entry>
	      <entry>15 Feb 2004</entry>
	      <entry>STARFRUIT release: Bugfixes and more material.</entry>
	    </row>
	    <row>
	      <entry><option>2.6</option></entry>
	      <entry>15 Mar 2004</entry>
	      <entry>SALAL release: Minor update.</entry>
	    </row>
	    <row>
	      <entry><option>2.7</option></entry>
	      <entry>18 Apr 2004</entry>
	      <entry>MULBERRY release: Minor update.</entry>
	    </row>
	    <row>
	      <entry><option>2.8</option></entry>
	      <entry>11 Jul 2004</entry>
	      <entry>ELDERBERRY release: Minor update.</entry>
	    </row>
	    <row>
	      <entry><option>3.0</option></entry>
	      <entry>03 Oct 2004</entry>
	      <entry>LOGANBERRY release: Major update.</entry>
	    </row>
	    <row>
	      <entry><option>3.1</option></entry>
	      <entry>14 Nov 2004</entry>
	      <entry>BAYBERRY release: Bugfix update.</entry>
	    </row>
	    <row>
	      <entry><option>3.2</option></entry>
	      <entry>06 Feb 2005</entry>
	      <entry>BLUEBERRY release: Minor update.</entry>
	    </row>
	    <row>
	      <entry><option>3.3</option></entry>
	      <entry>20 Mar 2005</entry>
	      <entry>RASPBERRY release: Bugfixes, much material added.</entry>
	    </row>
	    <row>
	      <entry><option>3.4</option></entry>
	      <entry>08 May 2005</entry>
	      <entry>TEABERRY release: Bugfixes, stylistic revisions.</entry>
	    </row>
	    <row>
	      <entry><option>3.5</option></entry>
	      <entry>05 Jun 2005</entry>
	      <entry>BOXBERRY release: Bugfixes, some material added.</entry>
	    </row>
	    <row>
	      <entry><option>3.6</option></entry>
	      <entry>28 Aug 2005</entry>
	      <entry>POKEBERRY release: Bugfixes, some material added.</entry>
	    </row>
	    <row>
	      <entry><option>3.7</option></entry>
	      <entry>23 Oct 2005</entry>
	      <entry>WHORTLEBERRY release: Bugfixes, some material added.</entry>
	    </row>
	    <row>
	      <entry><option>3.8</option></entry>
	      <entry>26 Feb 2006</entry>
	      <entry>BLAEBERRY release: Bugfixes, some material added.</entry>
	    </row>
	    <row>
	      <entry><option>3.9</option></entry>
	      <entry>15 May 2006</entry>
	      <entry>SPICEBERRY release: Bugfixes, some material added.</entry>
	    </row>
	    <row>
	      <entry><option>4.0</option></entry>
	      <entry>18 Jun 2006</entry>
	      <entry>WINTERBERRY release: Major reorganization.</entry>
	    </row>
	    <row>
	      <entry><option>4.1</option></entry>
	      <entry>08 Oct 2006</entry>
	      <entry>WAXBERRY release: Minor update.</entry>
	    </row>
	    <row>
	      <entry><option>4.2</option></entry>
	      <entry>10 Dec 2006</entry>
	      <entry>SPARKLEBERRY release: Important update.</entry>
	    </row>
	    <row>
	      <entry><option>4.3</option></entry>
	      <entry>29 Apr 2007</entry>
	      <entry>INKBERRY release: Bugfixes, material added.</entry>
	    </row>
	    <row>
	      <entry><option>5.0</option></entry>
	      <entry>24 Jun 2007</entry>
	      <entry>SERVICEBERRY release: Major update.</entry>
	    </row>
	    <row>
	      <entry><option>5.1</option></entry>
	      <entry>10 Nov 2007</entry>
	      <entry>LINGONBERRY release: Minor update.</entry>
	    </row>
	    <row>
	      <entry><option>5.2</option></entry>
	      <entry>16 Mar 2008</entry>
	      <entry>SILVERBERRY release: Important update.</entry>
	    </row>
	    <row>
	      <entry><option>5.3</option></entry>
	      <entry>11 May 2008</entry>
	      <entry>GOLDENBERRY release: Minor update.</entry>
	    </row>
	    <row>
	      <entry><option>5.4</option></entry>
	      <entry>21 Jul 2008</entry>
	      <entry>ANGLEBERRY release: Minor update.</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>


  </appendix> <!-- End Revision History appendix -->

  <appendix id="mirrorsites">
    <title>Mirror Sites</title>

      <para><ulink
        url="http://thegrendel.150m.com/abs-guide-5.4.tar.bz2">
        The latest update of this document</ulink>, as an archived
	<quote>tarball</quote>
	including both the SGML source and rendered HTML, may
	be downloaded from the <ulink
	url="http://personal.riverusers.com/~thegrendel/abs-guide-5.4.tar.bz2">author's
	home site</ulink>.</para>

      <para>The main mirror site for this document is the <ulink
        url="http://www.tldp.org/LDP/abs/">Linux Documentation Project</ulink>,
        which maintains many other Guides and HOWTOs as well.</para>


      <para>Yet another mirror site for this document is
        <ulink url="http://www.morethan.org">morethan.org</ulink>.</para>

      <para>You can download the <emphasis>pdf</emphasis> version
        <ulink
        url="http://personal.riverusers.com/~thegrendel/abs-guide.pdf">
	here</ulink>.</para>


  </appendix> <!-- Mirror Sites appendix -->


  <appendix id="todolist">
    <title>To Do List</title>

            <itemizedlist>
	      <listitem>
		<para>A comprehensive survey of <link
		  linkend="bashcompat">incompatibilities between Bash and
		  the classic Bourne shell</link>.</para>
	      </listitem>

	      <listitem>
		<para>Same as above, but for the Korn shell
		  (<firstterm>ksh</firstterm>).</para>
	      </listitem>

	      <listitem>

	        <para>A primer on CGI programming, using Bash.</para>

		<para>Here is a simple CGI script to get you started.</para>

                  <example id="testcgi">
                     <title>Print the server environment</title>
                     <programlisting>&testcgi;</programlisting>
                  </example>

	      </listitem>
            </itemizedlist>


  </appendix> <!-- End Todo List appendix -->


  <appendix id="copyright">
    <title>Copyright</title>

    <para>
        The <citetitle pubwork="book">Advanced Bash Scripting
        Guide</citetitle> is <trademark class=copyright>copyright
        </trademark> 2000, by Mendel Cooper.
           <footnote><para>The ISBN of the <ulink
	   url="http://www.lulu.com/content/176217">print
	   edition</ulink> of this book is
	   <productnumber>978-1-4357-5219-1</productnumber>.</para></footnote>
	The author also asserts copyright on all previous versions of
	this document.
           <footnote><para>The author intends that this book be released
           into the Public Domain after a period of 14 years from
           initial publication, that is, in 2014. In the early years
           of the American republic this was the duration statutorily
           granted to a copyrighted work.</para></footnote>
      </para>

    <para>This blanket copyright recognizes and protects the rights of all
      contributors to this document.</para>


    <para>This document may only be distributed subject to the terms
      and conditions set forth in the Open Publication
      License (version 1.0 or later), <ulink url="
      http://www.opencontent.org/openpub/">http://www.opencontent.org/openpub/</ulink>.
      The following license options also apply.
    </para>

    <para><programlisting>A.  Distribution of substantively modified versions of this document
    is permitted only under the following provisions.

A1. The modified document must clearly indicate that it is derivative
    of the original Advanced Bash Scripting Guide, and the original
    author, Mendel Cooper, must be listed as the primary author.

A2. The modified or derivative document must clearly indicate which portions
    of the text differ or deviate from the original document. A notice must
    be present, stating that the original author does not necessarily
    endorse the changes to the original.

A3. The modified or derivative document must be distributed under this
    same license, and the original author's copyright, as applicable,
    may not be modified.


B.  This document, or any modified or derivative version thereof, may
    NOT be distributed encrypted or with any form of DRM (Digital Rights
    Management) or content-control mechanism embedded in it. Nor may this
    document or any derivative thereof be bundled with other DRM-ed works.

C.  If this document (or any previous version or derivative thereof)
    is made available on a Web or ftp site, then the file(s) must be
    publicly accessible. No password or other access restrictions to
    its download may be imposed.

D.  Distribution of the original work in any standard (paper) book form
    requires permission from the copyright holder.

E.  In the event that the author or maintainer of this document cannot
    be contacted, the Linux Documentation Project is authorized to
    take over custodianship of the document and name a new maintainer,
    who would then have the right to update and modify the document.</programlisting></para>
    

    <para>Without <emphasis>explicit written permission</emphasis>
      from the author, distributors and publishers (including on-line
      publishers) are prohibited from imposing any additional conditions,
      strictures, or provisions on this document, any previous versions,
      or any derivative versions. As of this update, the author asserts
      that he has <emphasis>not</emphasis> entered into any contractual
      obligations that would alter the foregoing declarations.</para>

    <para>Essentially, you may freely distribute this book or any
      derivative thereof in electronic form.</para>

    <para>If you display or distribute this document, any previous
      versions thereof, or any derivatives thereof under any license
      except the one above, then you are required to obtain the author's
      written permission. Failure to do so may terminate your distribution
      rights.</para>


    <para><emphasis>Additionally, the following waiver
      applies:</emphasis></para>

<para><programlisting>By copying or distributing this book YOU WAIVE THE RIGHT
to use the materials within, or any portion thereof, in a patent or copyright
lawsuit against the Open Source community, its developers, its
distributors, or against any of its associated software or documentation
including, but not limited to, the Linux kernel, Open Office, Samba,
and Wine. You further waive the right to use any of the materials within
this book in testimony or depositions as a plaintiff's "expert witness" in
any lawsuit against the Open Source community, any of its developers, its
distributors, or any of its associated software or
documentation.</programlisting></para>


    <para>These are very liberal terms, and they should not hinder any
      legitimate distribution or use of this book. The author especially
      encourages its use for classroom and instructional purposes.</para>

    <note><para>Certain of the scripts contained in this document are,
      where noted, in the Public Domain. These scripts are exempt from
      the foregoing license and copyright restrictions.</para></note>

    <para>The commercial print and other rights to this book are
      available. Please contact <ulink
      url="mailto:thegrendel@theriver.com">the author</ulink> if
      interested.</para>

    <para>The author produced this book in a manner consistent with the
      spirit of the <ulink url="http://www.tldp.org/manifesto.html">LDP
      Manifesto</ulink>.</para>


    <sidebar>
    <para>Linux is a trademark registered to Linus Torvalds.</para>
    <para>Fedora is a trademark registered to Red Hat.</para>
    <para>Unix and UNIX are trademarks registered to the Open Group.</para>
    <para>MS Windows is a trademark registered to the Microsoft Corp.</para>
    <para>Solaris is a trademark registered to Sun, Inc.</para>
    <para>OSX is a trademark registered to Apple, Inc.</para>
    <para>Yahoo is a trademark registered to Yahoo, Inc.</para>
    <para>Pentium is a trademark registered to Intel, Inc.</para>
    <para>Thinkpad is a trademark registered to Lenovo, Inc.</para>
    <para>Scrabble is a trademark registered to Hasbro, Inc.</para>
    <para>Librie, PRS-500, and PRS-505 are trademarks registered to
      Sony, Inc.</para>
    <para>All other commercial trademarks mentioned in the body of this work
      are registered to their respective owners.</para>
      </sidebar>


    <para>Hyun Jin Cha has done a <ulink
      url="http://kldp.org/HOWTO/html/Adv-Bash-Scr-HOWTO/index.html">Korean
      translation</ulink> of version 1.0.11 of this book. Spanish,
      Portuguese, <ulink
      url="http://abs.traduc.org/">French</ulink>, German, <ulink
      url="http://it.tldp.org/guide/abs/index.html">Italian</ulink>,
      <ulink
      url="http://gazette.linux.ru.net/rus/articles/index-abs-guide.html">Russian</ulink>,
      <ulink url="http://premekvihan.net/bash">Czech</ulink>, <ulink
      url="http://www.linuxsir.org/bbs/showthread.php?t=256887">Chinese</ulink>,
      Indonesian, and Dutch translations are also available or in
      progress. If you wish to translate this document into another
      language, please feel free to do so, subject to the terms stated
      above. The author wishes to be notified of such efforts.</para>


  </appendix> <!-- End Copyright appendix -->

  <appendix id="asciitable">
    <title>ASCII Table</title>


    <para>In a book of this sort it is traditional to have an
      ASCII Table appendix. This book does not. Instead, here is a short
      shell script that generates a complete ASCII table and writes it
      to the file <filename>ASCII.txt</filename>.</para>

    <example id="asciish">
      <title>A script that generates an ASCII table</title>
      <programlisting>&asciish;</programlisting>
    </example>

  </appendix> <!-- End ASCII Table appendix -->



      <index id="xrefindex"> <!-- Begin Index -->

      &INDEX00;

      </index> <!-- End Index -->



</book>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-indent-step:2
sgml-indent-data:t
End:
-->

