<!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 fo