LDP/LDP/guide/docbook/abs-guide/abs-guide.sgml

24566 lines
778 KiB
Plaintext
Raw Normal View History

2001-07-10 14:25:50 +00:00
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
<!--
Uncomment line below to generate index.
-->
2001-09-04 13:27:31 +00:00
<!--
<!ENTITY indice SYSTEM "indice.sgml">
-->
2001-07-10 14:25:50 +00:00
<!ENTITY ex1 SYSTEM "ex1.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 ex31 SYSTEM "ex31.sh">
<!ENTITY ex32 SYSTEM "ex32.sh">
<!ENTITY ex33 SYSTEM "ex33.sh">
2002-06-03 14:35:48 +00:00
<!ENTITY ex33a SYSTEM "ex33a.sh">
2001-07-10 14:25:50 +00:00
<!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">
2001-09-04 13:27:31 +00:00
<!ENTITY ex45a SYSTEM "ex45a.sh">
2001-07-10 14:25:50 +00:00
<!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 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 ex79 SYSTEM "ex79.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 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">
2001-10-15 14:21:41 +00:00
<!ENTITY redir4a SYSTEM "redir4a.sh">
2001-07-10 14:25:50 +00:00
<!ENTITY redir5 SYSTEM "redir5.sh">
<!ENTITY wipedir SYSTEM "wipedir.sh">
<!ENTITY grp SYSTEM "grp.sh">
<!ENTITY killprocess SYSTEM "kill-process.sh">
<!ENTITY strtest SYSTEM "str-test.sh">
2002-04-01 16:04:17 +00:00
<!ENTITY colm SYSTEM "colm.sh">
2001-07-10 14:25:50 +00:00
<!ENTITY lookup SYSTEM "lookup.sh">
<!ENTITY arglist SYSTEM "arglist.sh">
<!ENTITY rot13 SYSTEM "rot13.sh">
2002-04-01 16:04:17 +00:00
<!ENTITY rot14 SYSTEM "rot14.sh">
2001-07-10 14:25:50 +00:00
<!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">
2001-10-15 14:21:41 +00:00
<!ENTITY symlinks2 SYSTEM "symlinks2.sh">
2001-07-10 14:25:50 +00:00
<!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">
2001-09-04 13:27:31 +00:00
<!ENTITY max2 SYSTEM "max2.sh">
2001-07-10 14:25:50 +00:00
<!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 primes SYSTEM "primes.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">
2001-09-04 13:27:31 +00:00
<!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">
2001-10-15 14:21:41 +00:00
<!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">
2002-01-07 15:24:19 +00:00
<!ENTITY cvt SYSTEM "cvt.sh">
<!ENTITY wf SYSTEM "wf.sh">
<!ENTITY hypot SYSTEM "hypotenuse.sh">
<!ENTITY random2 SYSTEM "random2.sh">
<!ENTITY altbc SYSTEM "alt-bc.sh">
<!ENTITY substringex SYSTEM "substring-extraction.sh">
2002-04-01 16:04:17 +00:00
<!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">
2002-06-03 14:35:48 +00:00
<!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 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">
2002-06-17 13:17:07 +00:00
<!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">
2002-04-01 16:04:17 +00:00
<!ENTITY namesdata SYSTEM "names.data">
<!ENTITY gen0data SYSTEM "gen0">
2001-07-10 14:25:50 +00:00
<!ENTITY bashrc SYSTEM "bashrc">
]>
<book>
<bookinfo>
<title>Advanced Bash-Scripting Guide</title>
2002-06-17 13:17:07 +00:00
<subtitle>An in-depth exploration of the gentle art of shell scripting</subtitle>
2001-07-10 14:25:50 +00:00
<author>
<firstname>Mendel</firstname>
<surname>Cooper</surname>
<affiliation>
2002-06-17 13:17:07 +00:00
<orgname>Brindle-Phlogiston Associates</orgname>
2001-07-10 14:25:50 +00:00
<address><email>thegrendel@theriver.com</email></address>
</affiliation>
</author>
2002-06-17 13:17:07 +00:00
<releaseinfo>1.4</releaseinfo>
<pubdate>16 June 2002</pubdate>
2001-07-10 14:25:50 +00:00
<revhistory>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<revision>
2001-09-04 13:27:31 +00:00
<revnumber>0.1</revnumber>
<date>14 June 2000</date>
2001-07-10 14:25:50 +00:00
<authorinitials>mc</authorinitials>
2001-09-04 13:27:31 +00:00
<revremark>Initial release.</revremark>
</revision>
<revision>
<revnumber>0.2</revnumber>
<date>30 October 2000</date>
<authorinitials>mc</authorinitials>
<revremark>Bugs fixed, plus much additional material and more example
scripts.</revremark>
2001-07-10 14:25:50 +00:00
</revision>
<revision>
<revnumber>0.3</revnumber>
<date>12 February 2001</date>
<authorinitials>mc</authorinitials>
<revremark>Another major update.</revremark>
</revision>
<revision>
2001-09-04 13:27:31 +00:00
<revnumber>0.4</revnumber>
<date>08 July 2001</date>
2001-07-10 14:25:50 +00:00
<authorinitials>mc</authorinitials>
2001-09-04 13:27:31 +00:00
<revremark>More bugfixes, much more material, more
scripts - a complete revision and expansion of the book.</revremark>
2001-07-10 14:25:50 +00:00
</revision>
<revision>
2001-09-04 13:27:31 +00:00
<revnumber>0.5</revnumber>
<date>03 September 2001</date>
2001-07-10 14:25:50 +00:00
<authorinitials>mc</authorinitials>
2001-09-04 13:27:31 +00:00
<revremark>Major update. Bugfixes, material added, chapters and
sections reorganized.</revremark>
2001-07-10 14:25:50 +00:00
</revision>
2001-10-15 14:21:41 +00:00
<revision>
<revnumber>1.0</revnumber>
<date>14 October 2001</date>
<authorinitials>mc</authorinitials>
2002-01-07 15:24:19 +00:00
<revremark>Bugfixes, reorganization, material added.
Stable release.</revremark>
</revision>
<revision>
<revnumber>1.1</revnumber>
<date>06 January 2002</date>
<authorinitials>mc</authorinitials>
<revremark>Bugfixes, material and scripts added.</revremark>
2001-10-15 14:21:41 +00:00
</revision>
2002-04-01 16:04:17 +00:00
<revision>
<revnumber>1.2</revnumber>
<date>31 March 2002</date>
<authorinitials>mc</authorinitials>
2002-06-03 14:35:48 +00:00
<revremark>Bugfixes, material and scripts added.</revremark>
</revision>
<revision>
<revnumber>1.3</revnumber>
<date>02 June 2002</date>
<authorinitials>mc</authorinitials>
<revremark>'TANGERINE' release: A few bugfixes, much more material
and scripts added.</revremark>
2002-04-01 16:04:17 +00:00
</revision>
2002-06-17 13:17:07 +00:00
<revision>
<revnumber>1.4</revnumber>
<date>16 June 2002</date>
<authorinitials>mc</authorinitials>
<revremark>'MANGO' release: Quite a number of typos fixed, more material
and scripts added.</revremark>
</revision>
2001-07-10 14:25:50 +00:00
</revhistory>
<abstract>
2001-10-15 14:21:41 +00:00
<para>This tutorial assumes no previous knowledge of
2001-07-10 14:25:50 +00:00
scripting or programming, but progresses rapidly toward an
2002-06-03 14:35:48 +00:00
intermediate/advanced level of instruction <emphasis>...all
2001-10-15 14:21:41 +00:00
the while sneaking in little snippets of UNIX wisdom and
2002-06-03 14:35:48 +00:00
lore</emphasis>. It serves as a textbook, a manual for
2001-10-15 14:21:41 +00:00
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
2002-06-03 14:35:48 +00:00
that <userinput>the only way to really learn scripting is to
write scripts</userinput>.</para>
<para>The latest update of this document, as an archived, <link
linkend="bzipref">bzip2-ed</link> <quote>tarball</quote>
including both the SGML source and
rendered HTML, may be downloaded from <ulink
2002-06-17 13:17:07 +00:00
url="http://personal.riverusers.com/~thegrendel/abs-guide-1.4.tar.bz2">
2001-10-15 14:21:41 +00:00
the author's home site</ulink>. See the <ulink
url="http://personal.riverusers.com/~thegrendel/Change.log">change
log</ulink> for a revision history.</para>
2001-07-10 14:25:50 +00:00
</abstract>
</bookinfo>
2001-09-04 13:27:31 +00:00
<dedication>
<para>For Anita, the source of all the magic</para>
</dedication>
<part label="Part 1" id="part1">
<title>Introduction</title>
<partintro>
<para>The shell is a command interpreter. More than just the
2002-06-17 13:17:07 +00:00
insulating layer between the operating system kernel and the user,
it's also a fairly powerful programming language. A shell program,
called a <emphasis>script</emphasis>, is an easy-to-use tool for
building applications by <quote>gluing</quote> together 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, give additional power and flexibility to scripts.
Shell scripts lend themselves exceptionally well to administrative
system tasks and other routine repetitive jobs not requiring the
bells and whistles of a full-blown tightly structured programming
language.</para>
2001-09-04 13:27:31 +00:00
</partintro>
2001-07-10 14:25:50 +00:00
<chapter id="why-shell">
<title>Why Shell Programming?</title>
2001-09-04 13:27:31 +00:00
<para>A working knowledge of shell scripting is essential to everyone
wishing to become reasonably adept 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>
2001-07-10 14:25:50 +00:00
<para>Writing shell scripts is not hard to learn, 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> to learn.
Most short scripts work right the first time, and debugging even
the longer ones is straightforward.</para>
<para>A shell script is a <quote>quick and dirty</quote> method of
prototyping a complex application. Getting even a limited subset
of the functionality to work in a shell script, even if slowly,
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 C, C++, Java, or Perl.</para>
<para>Shell scripting hearkens back to the classical 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 Perl, 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>When not to use shell scripts
<itemizedlist>
<listitem>
<para>resource-intensive tasks, especially where speed is
a factor (sorting, hashing, etc.)</para>
</listitem> <listitem>
<para>procedures involving heavy-duty math operations,
2001-09-04 13:27:31 +00:00
especially floating point arithmetic, arbitrary precision
calculations, or complex numbers (use C++ or FORTRAN
instead)</para>
2001-07-10 14:25:50 +00:00
</listitem> <listitem>
<para>cross-platform portability required (use C instead)</para>
</listitem> <listitem>
<para>complex applications, where structured programming is
a necessity (need typechecking of variables, function
prototypes, etc.)</para>
</listitem> <listitem>
<para>mission-critical applications upon which you are betting the
ranch, or the future of the company</para>
</listitem> <listitem>
<para>situations where security is important, where you need to
2001-10-15 14:21:41 +00:00
guarantee the integrity of your system and protect against
intrusion, cracking, and vandalism</para>
2001-07-10 14:25:50 +00:00
</listitem> <listitem>
<para>project consists of subcomponents with interlocking
dependencies</para>
</listitem> <listitem>
<para>extensive file operations required (Bash is limited to
serial file access, and that only in a particularly clumsy
and inefficient line-by-line fashion)</para>
</listitem> <listitem>
<para>need multi-dimensional arrays</para>
2001-09-04 13:27:31 +00:00
</listitem> <listitem>
<para>need data structures, such as linked lists or trees</para>
2001-07-10 14:25:50 +00:00
</listitem> <listitem>
<para>need to generate or manipulate graphics or GUIs</para>
</listitem> <listitem>
<para>need direct access to system hardware</para>
</listitem> <listitem>
<para>need port or socket 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 are
necessarily Open Source)</para>
</listitem>
</itemizedlist></para>
<para>If any of the above applies, consider a more powerful scripting
language, perhaps Perl, Tcl, Python, or possibly a high-level
compiled language such as C, C++, or Java. Even then, prototyping
the application as a shell script might still be a useful
development step.</para>
<para>We will be using Bash, an acronym for <quote>Bourne-Again
Shell</quote> and a pun on Stephen Bourne's now classic Bourne
Shell. Bash has become a <foreignphrase>de facto</foreignphrase>
standard for shell scripting on all flavors of UNIX. Most of
2001-10-15 14:21:41 +00:00
the principles dealt with in this book apply equally well to
2001-07-10 14:25:50 +00:00
scripting with other shells, such as the Korn Shell, from which
Bash derives some of its features,
<footnote><para>Many of the features of <emphasis>ksh88</emphasis>,
and even a few from the updated <emphasis>ksh93</emphasis>
have been merged into Bash.</para></footnote>
and the C Shell and its variants. (Note that C Shell programming
is not recommended due to certain inherent problems, as pointed
out in a <ulink
url="http://www.etext.org/Quartz/computer/unix/csh.harmful.gz">news
group posting</ulink> by Tom Christiansen in October of 1993).
</para>
<para>The following is a tutorial in shell scripting. It relies
heavily on examples to illustrate features of the shell.
2002-06-17 13:17:07 +00:00
As far as possible, the example scripts have been tested,
and some of them may actually be useful in real life. The
reader should use the actual examples in the source archive
2001-07-10 14:25:50 +00:00
(<filename>something-or-other.sh</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 follow this guideline.</para></footnote>
give them execute 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 HTML, pdf, or text rendered versions. Be aware that some of
the scripts below introduce features before they are explained,
and this may require the reader to temporarily skip ahead for
enlightenment.</para>
2001-10-15 14:21:41 +00:00
<para>Unless otherwise noted, the book author wrote the example
scripts that follow.</para>
2001-07-10 14:25:50 +00:00
</chapter> <!-- Why Shell Programming? -->
<chapter id="sha-bang">
<title>Starting Off With a Sha-Bang</title>
<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><command>cleanup</command>: A script to clean up the log
files in /var/log </title> <programlisting>&ex1;</programlisting>
</example>
<para>There is nothing unusual here, just a set of commands that
could just as easily be invoked one by one from the command line on
the console or in an xterm. The advantages of placing the commands
in a script go beyond not having to retype them time and again. The
script can easily be modified, customized, or generalized for a
particular application.</para>
<example id="ex2">
<title><command>cleanup</command>: An enhanced
and generalized version of above script.</title>
<programlisting>&ex2;</programlisting>
</example>
<para>Since you may not wish to wipe out the entire system log, this variant of
the first script keeps the last section of the message log intact. You
will constantly discover ways of refining previously written scripts
for increased effectiveness.</para>
<para>The
<firstterm><indexterm>
<primary>sha-bang</primary>
</indexterm>
sha-bang</firstterm>
(<token>
<indexterm>
<primary>#!</primary>
</indexterm>
#!</token>) 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.
<anchor id="magnumref">The <token>#!</token> is actually a two-byte
2002-01-07 15:24:19 +00:00
<footnote><para>Some flavors of UNIX (those based on 4.2BSD)
take a four-byte magic number, requiring
a blank after the <token>!</token>,
<userinput>#! /bin/sh</userinput>.</para></footnote>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>magic number</primary>
</indexterm>
<quote>magic number</quote>, a special marker that
designates a file type, or in this case an executable
shell script (see <userinput>man magic</userinput> for more
details on this fascinating topic). Immediately following
the <emphasis>sha-bang</emphasis> is a path name. 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 1 of the script), 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></footnote>
</para>
<para><programlisting>#!/bin/sh
#!/bin/bash
#!/usr/bin/perl
2001-10-15 14:21:41 +00:00
#!/usr/bin/tcl
2001-07-10 14:25:50 +00:00
#!/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.</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.</para>
</footnote>
Using <userinput>#!/bin/sh</userinput>, the default Bourne Shell
2001-09-04 13:27:31 +00:00
in most commercial variants of UNIX, makes the script <link
linkend="portabilityissues">portable</link> to non-Linux machines,
though you may have to sacrifice a few Bash-specific features
(the script will conform to the
<acronym>POSIX</acronym>
2002-04-01 16:04:17 +00:00
<footnote><para><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.</para></footnote>
2001-07-10 14:25:50 +00:00
<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.</para>
<para><token>#!</token> can be omitted if the script consists only
of a set of generic system commands, using no internal
shell directives. Example 2, above, requires the initial
<token>#!</token>, since the variable assignment line,
<userinput>lines=50</userinput>, uses a shell-specific construct.
Note that <userinput>#!/bin/sh</userinput> invokes the default
shell interpreter, which defaults to <filename>/bin/bash</filename>
on a Linux machine.</para>
<important><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 can build a quite 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.
<programlisting>if [ $# -ne Number_of_expected args ]
then
echo "Usage: `basename $0` whatever"
exit $WRONG_ARGS
fi</programlisting>
</para></important>
<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 Bash script by <userinput>sh
scriptname</userinput> turns off Bash-specific extensions, and the
script may therefore fail to execute.</para></footnote>
2002-06-17 13:17:07 +00:00
or alternatively <userinput>bash scriptname</userinput>. (Not
2001-07-10 14:25:50 +00:00
recommended is using <userinput>sh &lt;scriptname</userinput>,
since this effectively disables reading from
<filename>stdin</filename> 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 <emphasis>read</emphasis>, 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
<emphasis>scriptname</emphasis> is located, why doesn't this
work? This fails because, for security reasons, the current
directory, <quote>.</quote> is not 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 root, of
course), to make the script available to yourself and all
other users as a system-wide 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 -->
2001-10-15 14:21:41 +00:00
<sect1 id="prelimexer">
<title>Preliminary Exercises</title>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<orderedlist>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<listitem>
<para>System administrators often write scripts to automate common
2002-06-03 14:35:48 +00:00
tasks. Give several instances where such scripts would be
useful.</para>
2001-10-15 14:21:41 +00:00
</listitem>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
</orderedlist>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
</sect1> <!-- Preliminary Exercises -->
2001-07-10 14:25:50 +00:00
</chapter> <!-- Starting Off With a Sha-Bang -->
2001-09-04 13:27:31 +00:00
</part> <!-- Part 1 (Introduction) -->
<part label="Part 2" id="part2">
<title>Basics</title>
<chapter id="exit-status">
<title>Exit and Exit Status</title>
2001-07-10 14:25:50 +00:00
<epigraph>
<attribution>Chet Ramey</attribution>
<para>...there are dark corners in the Bourne shell, and people use all
of them.</para>
</epigraph>
<para><anchor id="exitcommandref">The
<command>
<indexterm>
<primary>exit</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>exit</secondary>
</indexterm>
exit
</command>
command may be used to terminate a script, just as in a C 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>). 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 error code. 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
2001-10-15 14:21:41 +00:00
<userinput>exit <replaceable>nnn</replaceable></userinput>
2001-07-10 14:25:50 +00:00
command may be used to deliver an
2001-10-15 14:21:41 +00:00
<returnvalue><replaceable>nnn</replaceable></returnvalue> exit status
to the shell (<returnvalue><replaceable>nnn</replaceable></returnvalue>
2001-07-10 14:25:50 +00:00
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 (<emphasis>not</emphasis>
counting the <command>exit</command>).</para></note>
2002-06-03 14:35:48 +00:00
<para><anchor id="exsref"></para>
2001-07-10 14:25:50 +00:00
<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 1 - 255 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 logical
<quote>not</quote> 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.
# !true leads to a "command not found" error
# Thanks, S.C.</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>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Exit and Exit status -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="special-chars">
<title>Special Characters</title>
<variablelist id="scharlist">
<title><anchor id="scharlist1">Special Characters Found In
Scripts and Elsewhere</title>
2001-07-10 14:25:50 +00:00
<varlistentry><term><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>
(<link linkend="magnumref">with the exception of
<token>#!</token></link>) are comments.</para>
</formalpara>
<para><programlisting># This line is a comment.</programlisting></para>
<para>Comments may also occur at the end of a command.</para>
<para><programlisting>echo "A comment will follow." # Comment here.</programlisting></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, an escaped <token>#</token> in an
<command>echo</command> 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>
2001-09-04 13:27:31 +00:00
<para>Certain <link linkend="psorex1">pattern matching
operations</link> also use the <token>#</token>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry><term><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</title>
2001-09-04 13:27:31 +00:00
<para>[Semicolon] Permits putting two or more commands on
the same line.</para>
2001-07-10 14:25:50 +00:00
</formalpara>
<para><programlisting>echo hello; echo there</programlisting></para>
<para>Note that the <quote><token>;</token></quote> sometimes
needs to be <link linkend="escp">escaped</link>.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<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</title>
<para>[Double semicolon]</para>
</formalpara>
<para><programlisting>case "$variable" in
abc) echo "$variable = abc" ;;
xyz) echo "$variable = xyz" ;;
esac</programlisting></para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry><term><token>.</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>.</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>.</secondary>
</indexterm>
<indexterm>
<primary>dot command</primary>
</indexterm>
<indexterm>
<primary>source</primary>
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para><anchor id="dotref"></para>
2001-07-10 14:25:50 +00:00
<formalpara><title><quote>dot</quote> command</title>
2001-09-04 13:27:31 +00:00
<para>[period] Equivalent to <link
linkend="sourceref">source</link> (see
<xref linkend="ex38">). This is a bash <link
linkend="builtinref">builtin</link>.</para>
2001-07-10 14:25:50 +00:00
</formalpara>
2001-09-04 13:27:31 +00:00
2002-06-03 14:35:48 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
2002-06-03 14:35:48 +00:00
<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 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>
2001-09-04 13:27:31 +00:00
<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>
2002-06-03 14:35:48 +00:00
2001-09-04 13:27:31 +00:00
<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>
2002-06-03 14:35:48 +00:00
</screen>
</para>
</formalpara>
<para>When considering directory names, <emphasis>a single
dot</emphasis> represents the current working directory,
and <emphasis>two dots</emphasis> 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 <emphasis>dot</emphasis> often appears as the
destination (directory) of a file movement command.</para>
2001-09-04 13:27:31 +00:00
2002-06-03 14:35:48 +00:00
<para>
<screen>
<prompt>bash$ </prompt><userinput>cp /home/bozo/current_work/junk/* .</userinput>
</screen>
</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2002-06-03 14:35:48 +00:00
<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> matches a single character.</para>
</formalpara>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><token>"</token></term>
<listitem><formalpara><title><link linkend="dblquo">partial
quoting</link></title>
2001-09-04 13:27:31 +00:00
<para>[double quote] <emphasis>"STRING"</emphasis>
preserves (from interpretation) most of the special
characters within <emphasis>STRING</emphasis>. See also
<xref linkend="quoting">.</para>
2001-07-10 14:25:50 +00:00
</formalpara> </listitem>
</varlistentry>
<varlistentry>
<term><token>'</token></term>
<listitem><formalpara><title><link linkend="snglquo">full
quoting</link></title>
2001-09-04 13:27:31 +00:00
<para>[single quote] <emphasis>'STRING'</emphasis>
preserves all special characters within
<emphasis>STRING</emphasis>. This is a stronger form
of quoting than using <token>"</token>. See also <xref
linkend="quoting">.</para>
</formalpara> </listitem>
</varlistentry>
<varlistentry>
<term><token>,</token></term>
<listitem><formalpara><title><link linkend="commaop">comma
operator</link></title>
<para>The <command>comma operator</command> 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" and calculate "t2".</programlisting>
</para>
2001-07-10 14:25:50 +00:00
</formalpara> </listitem>
</varlistentry>
<varlistentry>
<term><token>\</token></term>
<listitem><formalpara><title><link linkend="escp">escape</link></title>
2001-09-04 13:27:31 +00:00
<para>[backslash] <userinput>\X</userinput>
<quote>escapes</quote> the character
<emphasis>X</emphasis>. This has the effect of
2001-07-10 14:25:50 +00:00
<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>
</formalpara>
2001-09-04 13:27:31 +00:00
<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</title>
<para>[forward slash] 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>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><token>`</token></term>
<listitem><formalpara><title><link
linkend="commandsubref">command substitution</link></title>
2001-09-04 13:27:31 +00:00
<para>[backticks] <emphasis>`command`</emphasis> makes
available the output of <emphasis>command</emphasis>
for setting a variable. This is also known as
<link linkend="backquotesref">backticks</link> or
2001-07-10 14:25:50 +00:00
backquotes.</para></formalpara> </listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry><term><token>:</token></term>
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
<para><anchor id="nullref"></para>
2001-07-10 14:25:50 +00:00
<formalpara><title>null command</title>
2001-09-04 13:27:31 +00:00
<para>[colon] 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
2002-06-03 14:35:48 +00:00
<quote><token>:</token></quote> command is a itself a Bash
2001-09-04 13:27:31 +00:00
builtin, and its <link linkend="exitstatusref">exit
status</link> is <quote>true</quote>
(<returnvalue>0</returnvalue>).</para>
2001-07-10 14:25:50 +00:00
</formalpara>
2001-09-04 13:27:31 +00:00
<para><programlisting>:
echo $? # 0</programlisting></para>
2001-07-10 14:25:50 +00:00
<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
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`} without the leading : gives an error
# 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
2001-09-04 13:27:31 +00:00
<link linkend="paramsubref">parameter substitution</link>
(as in <xref linkend="ex6">).
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<programlisting>: ${HOSTNAME?} ${USER?} ${MAIL?}
2001-07-10 14:25:50 +00:00
#Prints error message if one or more of essential environmental variables not set.</programlisting>
</para>
2001-09-04 13:27:31 +00:00
<para><command><link linkend="exprepl1">Variable expansion / substring
replacement</link></command>.</para>
2001-07-10 14:25:50 +00:00
<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, updates a file access/modification
time (<userinput>: &gt;&gt; new_file</userinput>).
If the file did not previously exist, creates it. This is
equivalent to <link linkend="touchref">touch</link>.</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 be 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>
2001-10-15 14:21:41 +00:00
</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>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>!</token></term>
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
<listitem>
<para><anchor id="notref"></para>
<formalpara><title>reverse (or negate) the sense of
2001-07-10 14:25:50 +00:00
a test or exit status</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 <quote>equal</quote>
( <link linkend="equalsignref">=</link>
) to <quote>not-equal</quote> ( != ). The
<token>!</token> operator is a Bash <link
linkend="keywordref">keyword</link>.</para>
</formalpara>
2001-09-04 13:27:31 +00:00
<para>In a different context, the <token>!</token>
also appears in <link linkend="ivr2">indirect variable
references</link>.</para>
2002-06-17 13:17:07 +00:00
<para>In yet another context, from the <emphasis>command
line</emphasis>, the <token>!</token> invokes the
Bash <emphasis>history mechanism</emphasis> (see <xref
linkend="histcommands">). Note that within a script,
the history mechanism is disabled.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><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>
2001-09-04 13:27:31 +00:00
<para>[asterisk] The <token>*</token> character serves
as a <quote>wild card</quote> for filename expansion in
<link linkend="globbingref">globbing</link>, as well as
2001-07-10 14:25:50 +00:00
representing any number (or zero) characters in a <link
linkend="regexref">regular expression</link>.</para>
</formalpara>
2001-09-04 13:27:31 +00:00
2002-06-03 14:35:48 +00:00
</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>
2001-09-04 13:27:31 +00:00
<para>A double asterisk, <token>**</token>, is the <link
linkend="exponentiationref">exponentiation
operator</link>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2002-06-03 14:35:48 +00:00
<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>In a <link linkend="dblparens">double
parentheses construct</link>, the <token>?</token> serves
as a C-style trinary operator. See <xref
linkend="cvars">.</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>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><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>
2002-06-03 14:35:48 +00:00
<listitem><formalpara><title>wild card</title>
2001-10-15 14:21:41 +00:00
2002-06-03 14:35:48 +00:00
<para>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>
2001-10-15 14:21:41 +00:00
</formalpara>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<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></title>
<para>
<programlisting>var1=5
var2=23skidoo
echo $var1 # 5
echo $var2 # 23skidoo</programlisting>
</para>
</formalpara>
2002-06-03 14:35:48 +00:00
<para>A <token>$</token> prefixing a variable name
indicates the <emphasis>value</emphasis> the variable
holds.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
2002-06-03 14:35:48 +00:00
<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 end of a line of text.</para>
</formalpara>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
<listitem><formalpara><title><link linkend="appref">positional
parameters</link></title>
<para></para>
2001-07-10 14:25:50 +00:00
</formalpara>
</listitem>
</varlistentry>
2002-06-03 14:35:48 +00:00
<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><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 <emphasis>process id</emphasis> of the script in
which it appears.</para>
</formalpara>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><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><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><programlisting>grep Linux file*.{txt,htm*}
2002-06-17 13:17:07 +00:00
# Finds all instances of the word "Linux"
2001-07-10 14:25:50 +00:00
# in the files "fileA.txt", "file2.txt", "fileR.html", "file-87.htm", etc.</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 <emphasis>brace
expansion</emphasis>. 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>
2001-09-04 13:27:31 +00:00
<term><token>{}</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>{}</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>{}</secondary>
</indexterm>
<indexterm>
<primary>block of code</primary>
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem>
<para><anchor id="codeblockref"></para>
<formalpara><title>Block of code</title>
<para>[curly brackets] Also referred to as an
<quote>inline group</quote>, this construct, in effect,
creates an anonymous function. However, unlike a <link
2001-07-10 14:25:50 +00:00
linkend="functionref">function</link>, the variables
in 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>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>
<example id="rpmcheck">
<title>Saving the results 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> be run as a
<link linkend="subshellsref">subshell</link>.
<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" # Will not work.
# Thanks, S.C.</programlisting></para></footnote>
</para></note>
</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><token>[ ]</token></term>
<indexterm>
<primary>[]</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
2001-09-04 13:27:31 +00:00
<secondary>[ ]</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>test</primary>
</indexterm>
<listitem>
<formalpara><title>test</title>
<para></para></formalpara>
<para><anchor id="leftbracket"><link
linkend="ifthen">Test</link> expression between <command>[
]</command>. Note that <command>[</command> is part of
the shell builtin <command>test</command> (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>
2001-09-04 13:27:31 +00:00
<secondary>[[ ]]</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>test</primary>
</indexterm>
<listitem>
<formalpara><title>test</title>
<para></para></formalpara>
<para>Test expression between <token>[[ ]]</token> (shell
<link linkend="keywordref">keyword</link>).</para>
<para>See the discussion on the <link
2001-10-15 14:21:41 +00:00
linkend="dblbrackets">[[ ... ]] construct</link>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2002-06-03 14:35:48 +00:00
<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>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<varlistentry>
2002-06-17 13:17:07 +00:00
<term><token>></token> <token>&></token> <token>>&</token> <token>>></token> <token><</token></term>
2001-07-10 14:25:50 +00:00
<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>
2002-06-17 13:17:07 +00:00
<para><userinput>command &>filename</userinput> redirects
both the <filename>stdout</filename> and the
<filename>stderr</filename> of <filename>command</filename>
to <filename>filename</filename>.</para>
2001-07-10 14:25:50 +00:00
<para><userinput>command >&2</userinput> redirects
2002-06-17 13:17:07 +00:00
<filename>stdout</filename> of <filename>command</filename>
to <filename>stderr</filename>.</para>
2001-07-10 14:25:50 +00:00
<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 will be created.</para>
<formalpara><title><link linkend="processsubref">process substitution</link></title>
<para></para>
</formalpara>
<para><userinput>(command)></userinput></para>
<para><userinput><(command)</userinput></para>
2001-09-04 13:27:31 +00:00
<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>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><token><<</token></term>
<listitem><formalpara><title>redirection used in a <link
linkend="heredocref">here document</link></title>
<para></para>
</formalpara>
</listitem>
</varlistentry>
2002-06-17 13:17:07 +00:00
<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 "this implies nothing 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>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>|</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>|</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>|</secondary>
</indexterm>
<indexterm>
<primary>pipe</primary>
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem>
<para><anchor id="piperef"></para>
<formalpara><title>pipe</title>
2001-10-15 14:21:41 +00:00
<para>Passes the output of previous command to the input
of the next one, or to the shell. This is a method of
chaining commands together.</para>
2001-07-10 14:25:50 +00:00
</formalpara>
2001-09-04 13:27:31 +00:00
<para>
<programlisting>echo ls -l | sh
2001-10-15 14:21:41 +00:00
# Passes the output of "echo ls -l" to the shell,
#+ with the same result as a simple "ls -l".
2001-09-04 13:27:31 +00:00
cat *.lst | sort | uniq
2001-10-15 14:21:41 +00:00
# Merges and sorts all ".lst" files, then deletes duplicate lines.</programlisting>
2001-09-04 13:27:31 +00:00
</para>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<sidebar>
<para>A pipe, as a classic method of interprocess
communication, sends the <filename>stdout</filename>
of one process to the <filename>stdin</filename>
2002-06-03 14:35:48 +00:00
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
<quote>filter</quote> (a command that transforms its input)
for processing.</para>
2001-10-15 14:21:41 +00:00
<para>
<userinput>cat $filename | grep $search_word</userinput>
</para>
</sidebar>
2001-07-10 14:25:50 +00:00
<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.
2001-09-04 13:27:31 +00:00
tr 'a-z' 'A-Z'
2001-10-15 14:21:41 +00:00
# Letter ranges must be quoted
#+ to prevent filename generation from single-letter filenames.
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
exit 0</programlisting>
2001-07-10 14:25:50 +00:00
Now, let us pipe the output of <command>ls -l</command> to this
2001-09-04 13:27:31 +00:00
script.
2001-07-10 14:25:50 +00:00
<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>
2001-10-15 14:21:41 +00:00
<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 <emphasis>block</emphasis>, 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
2001-07-10 14:25:50 +00:00
aborts, this prematurely terminates execution of the
pipe. Called a <emphasis>broken pipe</emphasis>, this
condition sends a <emphasis>SIGPIPE</emphasis> <link
2001-10-15 14:21:41 +00:00
linkend="signald">signal</link>.</para>
</note>
2001-07-10 14:25:50 +00:00
2002-04-01 16:04:17 +00:00
2001-07-10 14:25:50 +00:00
</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>
2002-06-03 14:35:48 +00:00
<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>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><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>
2002-04-01 16:04:17 +00:00
2001-09-04 13:27:31 +00:00
<para>
<screen><prompt>bash$ </prompt><userinput>sleep 10 &</userinput>
<computeroutput>[1] 850</computeroutput>
<computeroutput>[1]+ Done sleep 10</computeroutput>
</screen>
</para>
2001-10-15 14:21:41 +00:00
2002-04-01 16:04:17 +00:00
<para>Within a script, commands and even <link
linkend="forloopref1">loops</link> may run in the
background.</para>
<example id="bgloop">
<title>Running a loop in the background</title>
<programlisting>&bgloop;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<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>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
2002-06-03 14:35:48 +00:00
<varlistentry><term><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.</para>
</formalpara>
<para><userinput>COMMAND -[Option1][Option2][...]</userinput></para>
<para><userinput>ls -al</userinput></para>
<para><userinput>sort -dfu $filename</userinput></para>
<para><userinput>set -- $variable</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</programlisting>
</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><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></title>
2001-09-04 13:27:31 +00:00
<para><anchor id="coxex">[dash]</para>
2001-07-10 14:25:50 +00:00
</formalpara>
2001-09-04 13:27:31 +00:00
<para><programlisting>(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)
2001-07-10 14:25:50 +00:00
# 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 ../target-directory; tar xzf -)
#
# cp -a /source/directory /dest also has same effect.
</programlisting></para>
<para><programlisting>bunzip2 linux-2.4.3.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>
2002-04-01 16:04:17 +00:00
<para>
<screen><prompt>bash$ </prompt><userinput>echo "whatever" | cat -</userinput>
<computeroutput>whatever</computeroutput> </screen>
</para>
2001-07-10 14:25:50 +00:00
<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. 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>
2001-10-15 14:21:41 +00:00
By itself on the command line, <link
2001-07-10 14:25:50 +00:00
linkend="fileref">file</link> fails with an error message.
</para>
<para>
2002-06-03 14:35:48 +00:00
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>
2001-07-10 14:25:50 +00:00
<userinput>#!/bin/bash</userinput>
<computeroutput>standard input: Bourne-Again shell script text executable</computeroutput>
</screen>
2002-06-03 14:35:48 +00:00
Now the command accepts input from <filename>stdin</filename>
and analyzes it.
2001-07-10 14:25:50 +00:00
</para>
2002-06-03 14:35:48 +00:00
<para>The <quote>-</quote> can be used to pipe
2001-10-15 14:21:41 +00:00
<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
2001-07-10 14:25:50 +00:00
compare a file with a <emphasis>section</emphasis>
2001-10-15 14:21:41 +00:00
of another:</para>
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
<para><userinput>grep Linux file1 | diff file2 -</userinput></para>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
2001-07-10 14:25:50 +00:00
<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>
2002-06-03 14:35:48 +00:00
2001-07-10 14:25:50 +00:00
<para>Filenames beginning with
2002-06-03 14:35:48 +00:00
<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>
2001-07-10 14:25:50 +00:00
<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>
2002-06-03 14:35:48 +00:00
<para>[dash] <command>cd -</command> changes to the
previous working directory. This uses the
<link linkend="oldpwd">$OLDPWD</link> <link
linkend="envref">environmental variable</link>.</para>
2001-07-10 14:25:50 +00:00
</formalpara>
2002-06-03 14:35:48 +00:00
<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>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<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>
2002-06-03 14:35:48 +00:00
<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
<token>+</token> to enable certain options and the
<token>-</token> to disable them.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><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>In a <link linkend="pctpatref">different context</link>,
the <token>%</token> is a <link linkend="psub2">pattern
matching</link> operator.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><token>~</token></term>
<listitem><formalpara><title>home directory</title>
2001-09-04 13:27:31 +00:00
<para>[tilde] This corresponds to the <link
2001-07-10 14:25:50 +00:00
linkend="homedirref">$HOME</link> internal variable.
<emphasis>~bozo</emphasis> 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>
2001-09-04 13:27:31 +00:00
<term><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><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>
2002-06-03 14:35:48 +00:00
<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>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 beginning of a line of text.</para>
</formalpara>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term>Control Characters</term>
<listitem>
<para><anchor id="controlcharref"></para>
<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.</para>
</formalpara>
<itemizedlist id="ctlchar">
<listitem>
<para><userinput>Ctl-C</userinput></para>
<para>Terminate a foreground job.</para>
</listitem>
<listitem>
2001-10-15 14:21:41 +00:00
<para><anchor id="ctldref"></para>
2001-09-04 13:27:31 +00:00
<para><userinput>Ctl-D</userinput></para>
<para>Log out from a shell (similar to
<link linkend="exitcommandref">exit</link>).</para>
2001-10-15 14:21:41 +00:00
<para><quote>EOF</quote> (end of file). This also
terminates input from <filename>stdin</filename>.</para>
2001-09-04 13:27:31 +00:00
</listitem>
<listitem>
<para><userinput>Ctl-G</userinput></para>
<para><quote>BEL</quote> (beep).</para>
</listitem>
<listitem>
<para><userinput>Ctl-H</userinput></para>
<para>Backspace.</para>
2002-04-01 16:04:17 +00:00
<para>
<programlisting>#!/bin/bash
# Embedding Ctl-H in a string.
a="^H^H" # Two Ctl-H's (backspaces).
echo "abcdef" # abcdef
echo -n "abcdef$a " # abcd f
# Space at end ^ ^ Backspaces twice.
echo -n "abcdef$a" # abcdef
# No space at end Doesn't backspace (why?).
# Results may not be quite as expected.
echo; echo</programlisting>
</para>
2001-09-04 13:27:31 +00:00
</listitem>
<listitem>
<para><userinput>Ctl-J</userinput></para>
<para>Carriage return.</para>
</listitem>
<listitem>
<para><userinput>Ctl-L</userinput></para>
<para>Formfeed (clear the terminal screen). This has
the same effect as the <link
linkend="clearref">clear</link> command.</para>
</listitem>
<listitem>
<para><userinput>Ctl-M</userinput></para>
<para>Newline.</para>
</listitem>
<listitem>
<para><userinput>Ctl-U</userinput></para>
<para>Erase a line of input.</para>
</listitem>
<listitem>
<para><userinput>Ctl-Z</userinput></para>
<para>Pause a foreground job.</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term>Whitespace</term>
<listitem>
<para><anchor id="whitespaceref"></para>
<formalpara><title>functions as a separator, separating commands or variables.</title>
<para>Whitespace consists of either spaces, tabs, blank
lines, or any combination thereof. 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>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
</variablelist>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Special characters used in shell scripts -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="variables">
2001-07-10 14:25:50 +00:00
<title>Introduction to Variables and Parameters</title>
<para>Variables are at the heart of every programming and scripting
language. They appear in arithmetic operations and manipulation
of quantities, string parsing, and are indispensable for working
in the abstract with symbols - tokens that represent something
else. A variable is nothing more than a location or set of
2002-01-07 15:24:19 +00:00
locations in computer memory holding an item of data.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="varsubn">
<title>Variable Substitution</title>
<para>The <emphasis>name</emphasis> of a variable is a placeholder for
its <emphasis>value</emphasis>, the data it holds. Referencing its
value is called <emphasis>variable substitution</emphasis>.</para>
<variablelist id="dollarsign">
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<para>Let us carefully distinguish between the
<emphasis>name</emphasis> of a variable
and its <emphasis>value</emphasis>. If
<userinput>variable1</userinput> is the name of a
variable, then <userinput>$variable1</userinput>
is a reference to its <emphasis>value</emphasis>,
the data item it contains. The only time a
2001-10-15 14:21:41 +00:00
variable appears <quote>naked</quote>, without
the <token>$</token> prefix, is when declared
or assigned, when <emphasis>unset</emphasis>,
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 <emphasis>var1=27</emphasis>),
in a <link linkend="readref">read</link> statement,
and at the head of a loop (<emphasis>for var2 in 1 2
3</emphasis>).</para>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<para><anchor id="dblquo">Enclosing a referenced value in
double quotes (<token>" "</token>) does not
interfere with variable substitution. This is called
partial quoting, 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
full quoting, sometimes referred to as <quote>strong
quoting</quote>. See <xref linkend="quoting"> for a
detailed discussion.</para>
<para>Note that <userinput>$variable</userinput> is actually a
simplified alternate 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>
<example id="ex9">
<title>Variable assignment and substitution</title>
<programlisting>&ex9;</programlisting>
</example>
<warning><para>An uninitialized variable has a
<quote>null</quote> value - no assigned value at all
(not zero!). Using a variable before assigning a value
to it will inevitably cause problems.</para></warning>
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Variable Substitution -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="varassignment">
<title>Variable Assignment</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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 &
after</emphasis>)</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<caution>
<para>Do not confuse this with <link
linkend="equalsignref">=</link> and <link
linkend="equalref">-eq</link>, which test, rather than
assign!</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>Note that <token>=</token> can be either an assignment
or a test operator, depending on context.</para>
</caution>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<example id="ex15">
<title>Plain Variable Assignment</title>
<programlisting>&ex15;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<example id="ex16">
<title>Variable Assignment, plain and fancy</title>
<programlisting>&ex16;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>Variable assignment using the <token>$(...)</token> mechanism
(a newer method than <link
linkend="backquotesref">backquotes</link>)</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para><programlisting># From /etc/rc.d/rc.local
R=$(cat /etc/redhat-release)
arch=$(uname -m)</programlisting></para>
</listitem>
</varlistentry>
</variablelist>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
</sect1> <!-- Variable Assignment -->
<sect1 id="untyped">
<title>Bash Variables Are Untyped</title>
<para>Unlike many other programming languages, Bash does not segregate
its variables by <quote>type</quote>. Essentially, Bash
variables are character strings, but, depending on context, Bash
permits integer 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 (enough rope to hang yourself) and make
it easier to grind out lines of code. However, they permit errors to
creep in and encourage sloppy programming habits.</para>
<para>The burden is on the programmer to keep track of what type the
script variables are. Bash will not do it for you.</para>
</sect1> <!-- Bash Variables Are Untyped-->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="othertypesv">
<title>Special Variable Types</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><replaceable>local variables</replaceable></term>
<indexterm>
<primary>variable</primary>
<secondary>local</secondary>
</indexterm>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<listitem><para>variables visible 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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
2002-06-03 14:35:48 +00:00
<term><anchor id="envref"><replaceable>environmental variables</replaceable></term>
2001-09-04 13:27:31 +00:00
<indexterm>
<primary>variable</primary>
<secondary>environmental</secondary>
</indexterm>
<listitem>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>variables that affect the behavior of the shell and
user interface</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<note>
<para>In a more general context, each process has an
<quote>environment</quote>, that is, a group of
variables that hold information 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 shell variables causes the shell to update its
environment, and all the shell's child processes (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>(Thank you, S. C. 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
environment local to the script. This is the function of
the <link linkend="exportref">export</link> command.</para>
2001-10-15 14:21:41 +00:00
<anchor id="childref">
2001-09-04 13:27:31 +00:00
<note><para>A script can <command>export</command> variables only
to child processes, 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. <link
linkend="forkref">Child processes</link> cannot export
variables back to the parent processes that spawned
them.</para></note>
<para>---</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>positional parameters</replaceable></term>
<indexterm>
<primary>parameter</primary>
<secondary>positional</secondary>
</indexterm>
<listitem>
<para>arguments passed to the script from the command
line - $0, $1, $2, $3... $0 is the name of the script
itself, $1 is the first argument, $2 the second, $3 the
third, and so forth.
<footnote><para>The process calling the script sets the
<replaceable>$0</replaceable> parameter. By convention, this
parameter is the name of the script. See the manpage for
<command>execv</command>.</para></footnote>
2002-04-01 16:04:17 +00:00
<anchor id="bracketnotation">
2001-09-04 13:27:31 +00:00
After $9, the arguments must be enclosed in brackets,
for example, ${10}, ${11}, ${12}.</para>
<example id="ex17">
<title>Positional Parameters</title>
<programlisting>&ex17;</programlisting>
</example>
<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.</para>
<tip><para>If a script expects a command line parameter
but is invoked without one, this may cause a null variable
assignment, 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>
2001-10-15 14:21:41 +00:00
<programlisting>variable1_=$1_
2001-09-04 13:27:31 +00:00
# This will prevent an error, even if positional parameter is absent.
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
critical_argument01=$variable1_
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
# The extra character can be stripped off later, if desired, like so.
2001-10-15 14:21:41 +00:00
variable1=${variable1_/_/} # Side effects only if $variable1_ begins with "_".
# This uses one of the parameter substitution templates discussed in Chapter 9.
2001-09-04 13:27:31 +00:00
# Leaving out the replacement pattern results in a deletion.
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
# A more straightforward way of dealing with this is
#+ to simply test whether expected positional parameters have been passed.
2001-09-04 13:27:31 +00:00
if [ -z $1 ]
then
exit $POS_PARAMS_MISSING
fi
</programlisting>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>---</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<example id="ex18">
<title><command>wh</command>, <link
linkend="whoisref">whois</link> domain name lookup</title>
<programlisting>&ex18;</programlisting>
2001-07-10 14:25:50 +00:00
</example>
2001-09-04 13:27:31 +00:00
<para>---</para>
2002-04-01 16:04:17 +00:00
<para><anchor id="shiftref"></para>
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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
2002-04-01 16:04:17 +00:00
<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>
2001-09-04 13:27:31 +00:00
<example id="ex19">
<title>Using <command>shift</command></title>
<programlisting>&ex19;</programlisting>
2001-07-10 14:25:50 +00:00
</example>
2002-04-01 16:04:17 +00:00
<note><para>The <command>shift</command> command also works on
parameters passed to a <link
linkend="functionref">function</link>. See <xref
linkend="multiplication">.</para></note>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
</variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1> <!-- Special Variable Types -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- Variables -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="quoting">
<title>Quoting</title>
2001-07-10 14:25:50 +00:00
<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 special characters 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, such as the <token>wild card</token> character,
<token>*</token>.)</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>
<note>
<para>Certain programs and utilities can still reinterpret or expand
special characters in a quoted string. This is an important use
of quoting, 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>Of course, <userinput>grep [Ff]irst *.txt</userinput>
would not work.</para>
</note>
<para>When referencing a variable, it is generally advisable in
enclose it in double quotes (<token>" "</token>). This
preserves all special characters within the variable name,
except <token>$</token>, <token>`</token> (backquote),
and <token>\</token> (escape). Keeping <token>$</token>
as a special character permits referencing a quoted variable
(<replaceable>"$variable"</replaceable>), that is, replacing the
variable with its value (see <xref linkend="ex9">, above).</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.
<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, S.C.
</programlisting></para>
<tip><para>Enclosing the arguments to an <command>echo</command>
statement in double quotes is necessary only when word splitting
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 Stephane Chazelas.</programlisting>
</para></note>
<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>
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
<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 <quote>alert</quote> (beep or flash)</para>
</listitem>
</varlistentry>
<varlistentry><term><token>\0xx</token></term>
<indexterm>
<primary>\0xx</primary>
</indexterm>
<indexterm>
<primary>escaped character</primary>
<secondary>\0xx</secondary>
</indexterm>
<indexterm>
<primary>octal ASCII</primary>
</indexterm>
<listitem><para>translates to the octal ASCII
equivalent of <replaceable>0xx</replaceable></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" # results in $variable01</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 \</programlisting></para>
</listitem>
</varlistentry>
</variablelist>
2002-04-01 16:04:17 +00:00
<note>
<para>The behavior of <token>\</token> depends on whether
it is itself escaped, quoted, or appearing within <link
linkend="commandsubref">command substitution</link> or a <link
2001-07-10 14:25:50 +00:00
linkend="heredocref">here document</link>.
2002-04-01 16:04:17 +00:00
<programlisting> # Simple escaping and quoting
echo \z # z
2001-07-10 14:25:50 +00:00
echo \\z # \z
echo '\z' # \z
echo '\\z' # \\z
echo "\z" # \z
echo "\\z" # \z
2002-04-01 16:04:17 +00:00
# Command substitution
2001-07-10 14:25:50 +00:00
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
2002-04-01 16:04:17 +00:00
# Here document
2001-07-10 14:25:50 +00:00
cat &lt;&lt;EOF
\z
EOF # \z
cat &lt;&lt;EOF
\\z
EOF # \z
# These examples supplied by Stephane Chazelas.</programlisting>
2002-04-01 16:04:17 +00:00
</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>
2001-07-10 14:25:50 +00:00
<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>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:
2002-06-03 14:35:48 +00:00
tar cf - -C /source/directory . |
2001-07-10 14:25:50 +00:00
tar xpvf - -C /dest/directory
# See note below.
# (Thanks, Stephane 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.
#foor\
#bar
# Examples suggested by Stephane Chazelas.</programlisting></para>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Quoting -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="tests">
<title>Tests</title>
2001-07-10 14:25:50 +00:00
<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 if</primary>
</indexterm>
<indexterm>
<primary>elif</primary>
</indexterm>
2001-09-04 13:27:31 +00:00
<para>Every reasonably complete programming language can test
for a condition, then act according to the result of
the test. Bash has the <command>test</command> command,
various bracket and parenthesis operators, and the
<command>if/then</command> construct.</para>
<sect1 id="testconstructs">
2002-06-03 14:35:48 +00:00
<title><anchor id="testconstructs1">Test Constructs</title>
2001-09-04 13:27:31 +00:00
<itemizedlist id="testingref">
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
<para>With version 2.02, Bash introduced the <link
linkend="dblbrackets">[[ ... ]]</link> <emphasis>extended
test command</emphasis>, which performs comparisons
in a manner more familiar to programmers from other
2001-07-10 14:25:50 +00:00
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>
<para>The <link linkend="dblparens">(( ... ))</link> and <link
linkend="letref">let ...</link> constructs also return an
exit status of <returnvalue>0</returnvalue> if 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 arithmetic
comparisons.
<programlisting>let "1&lt;2" returns 0 (as "1&lt;2" expands to "1")
(( 0 && 1 )) returns 1 (as "0 && 1" expands to "0")</programlisting>
</para>
</listitem>
<listitem>
<para>An <command>if</command> can test any command, not just
conditions enclosed within brackets.
2002-06-17 13:17:07 +00:00
<programlisting>if cmp a b &amp;&gt; /dev/null # Suppress output.
2001-07-10 14:25:50 +00:00
then echo "Files a and b are identical."
else echo "Files a and b differ."
fi
if grep -q Bash file
then echo "File contains at least one occurrence of Bash."
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>An <command>if/then</command> construct can contain nested
comparisons and tests.
<programlisting>if echo "Next *if* is part of the comparison for the first *if*."
if [[ $comparison = "integer" ]]
then (( a < b ))
else
[[ $a < $b ]]
fi
then
echo '$a is less than $b'
fi</programlisting>
</para>
<para><emphasis>This detailed <quote>if-test</quote> explanation
courtesy of Stephane 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><programlisting>if [ condition-true ]
then
command 1
command 2
...
else
# Optional (may be left out if not needed).
# Adds default code block executing if original condition tests false.
command 3
command 4
...
fi</programlisting>
</para>
2002-04-01 16:04:17 +00:00
<note>
<para>When <emphasis>if</emphasis> and <emphasis>then</emphasis>
are on same line in a condition test, a semicolon must
terminate the <emphasis>if</emphasis> statement. Both
<emphasis>if</emphasis> and <emphasis>then</emphasis> 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>
2001-07-10 14:25:50 +00:00
<para><programlisting>if [ -x "$filename" ]; then</programlisting></para>
2002-04-01 16:04:17 +00:00
</note>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="elifref">
<title><anchor id="elifref1">Else if and elif</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>elif</token></term>
<listitem>
<para><userinput>elif</userinput> is a contraction
for <token>else if</token>. The effect is to nest an
inner <token>if/then</token> construct within an outer
one.</para>
2001-07-10 14:25:50 +00:00
<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>
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>
<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 <emphasis>sh-utils</emphasis>
package. Likewise, <token>[</token> does not call
<filename>/usr/bin/[</filename>, which is linked to
2001-09-04 13:27:31 +00:00
<filename>/usr/bin/test</filename>.</para>
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
</para></note>
2001-07-10 14:25:50 +00:00
<example id="ex11">
2002-06-17 13:17:07 +00:00
<title>Equivalence of <token>test</token>,
<filename>/usr/bin/test</filename>, <token>[ ]</token>,
and <filename>/usr/bin/[</filename></title>
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
<para><anchor id="dblbrackets">The <token>[[ ]]</token> construct
is the shell equivalent of <token>[ ]</token>. This is the
<emphasis>extended test command</emphasis>, adopted from
<emphasis>ksh88</emphasis>.</para>
<note><para>No filename expansion or word splitting takes place
between <token>[[</token> and <token>]]</token>, but there is
parameter expansion and command substitution.</para></note>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>
2001-07-10 14:25:50 +00:00
<programlisting>file=/etc/passwd
if [[ -e $file ]]
then
echo "Password file exists."
fi</programlisting>
</para>
<tip>
2001-09-04 13:27:31 +00:00
<para>Using the <command>[[ ... ]]</command> test construct,
rather than <command>[ ... ]</command> can prevent many
2002-06-17 13:17:07 +00:00
logic errors in scripts. For example, the <token>&&</token>,
2001-09-04 13:27:31 +00:00
<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>
</tip>
2001-07-10 14:25:50 +00:00
<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>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>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Test Constructs -->
<sect1 id="fto">
2001-07-10 14:25:50 +00:00
<title>File test operators</title>
<variablelist>
2001-09-04 13:27:31 +00:00
<title><anchor id="rtif">Returns true if...</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><token>-e</token></term>
<listitem><para>file exists</para></listitem>
</varlistentry>
<varlistentry>
<term><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 block device (floppy, cdrom, etc.)
</para></listitem>
</varlistentry>
<varlistentry>
<term><token>-c</token></term>
<listitem><para>file is a character device (keyboard, modem, sound
card, etc.)</para></listitem>
</varlistentry>
<varlistentry>
<term><token>-p</token></term>
<listitem><para>file is a pipe</para></listitem>
</varlistentry>
<varlistentry>
<term><token>-h</token></term>
<listitem><para>file is a symbolic 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 socket</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>set-user-id (suid) flag set on file</para>
<para>A binary owned by <emphasis>root</emphasis>
with <replaceable>set-user-id</replaceable> flag set
runs with <emphasis>root</emphasis> privileges, even
when an ordinary user invokes it.
<footnote><para>Be aware that <emphasis>suid</emphasis>
binaries may open security holes and that the
2001-09-04 13:27:31 +00:00
<emphasis>suid</emphasis> flag has no effect on
2001-07-10 14:25:50 +00:00
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
<emphasis>suid</emphasis> flag, these binaries could not
be invoked by a non-root user.
<screen>
<computeroutput>-rwsr-xr-t 1 root 178236 Oct 2 2000 /usr/sbin/pppd</computeroutput>
</screen>
A file with the <replaceable>suid</replaceable> flag set shows
an <emphasis>s</emphasis> 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 <quote>sticky bit</quote>, the
<emphasis>save-text-mode</emphasis> 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 <emphasis>t</emphasis>
to the permissions on the file or directory listing.
<screen>
<computeroutput>drwxrwxrwt 7 root 1024 May 19 21:26 tmp/</computeroutput>
</screen>
If a user does not own a directory that has the sticky
bit set, but has write permission in that directory,
he can only delete files in it that he owns. This keeps
users from inadvertently overwriting or deleting each
other's files in a publicly accessible directory, such
as <filename class="directory">/tmp</filename>.</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>
<para><xref linkend="cookies">, <xref linkend="bingrep">,
2001-10-15 14:21:41 +00:00
<xref linkend="fileinfo">, <xref linkend="ramdisk">, and <xref
linkend="mailformat"> illustrate uses of the file test
operators.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1> <!-- File test operators -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="comparison-ops">
2001-07-10 14:25:50 +00:00
<title>Comparison operators (binary)</title>
2001-09-04 13:27:31 +00:00
<variablelist id="icomparison">
<title><anchor id="icomparison1">integer comparison</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><token>-eq</token></term>
<listitem>
2001-09-04 13:27:31 +00:00
<para><anchor id="equalref"></para>
2001-07-10 14:25:50 +00:00
<para>is equal to</para>
<para><userinput>if [ "$a" -eq "$b" ]</userinput></para>
</listitem>
</varlistentry>
<varlistentry>
<term><token>-ne</token></term>
<listitem>
<para>is not equal to</para>
<para><userinput>if [ "$a" -ne "$b" ]</userinput></para>
</listitem>
</varlistentry>
<varlistentry>
<term><token>-gt</token></term>
<listitem>
<para>is greater than</para>
<para><userinput>if ["$a" -gt "$b" ]</userinput></para>
</listitem>
</varlistentry>
<varlistentry>
<term><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><token>-lt</token></term>
<listitem>
<para>is less than</para>
<para><userinput>if [ "$a" -lt "$b" ]</userinput></para>
</listitem>
</varlistentry>
<varlistentry>
<term><token>-le</token></term>
<listitem>
<para>is less than or equal to</para>
<para><userinput>if [ "$a" -le "$b" ]</userinput></para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<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><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><token>&gt;</token></term>
<listitem>
<para>is greater than (within double parentheses)</para>
<para><userinput>(("$a" &gt; "$b"))</userinput></para>
</listitem>
</varlistentry>
<varlistentry>
<term><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>
2001-07-10 14:25:50 +00:00
</variablelist>
2001-09-04 13:27:31 +00:00
<variablelist id="scomparison">
<title><anchor id="scomparison1">string comparison</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><token>=</token></term>
<listitem>
2001-09-04 13:27:31 +00:00
<para><anchor id="equalsignref"></para>
2001-07-10 14:25:50 +00:00
<para>is equal to</para>
<para><userinput>if [ "$a" = "$b" ]</userinput></para>
</listitem>
</varlistentry>
<varlistentry>
<term><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>
<para>
<programlisting>[[ $a == z* ]] # true if $a starts with an "z" (pattern matching)
[[ $a == "z*" ]] # true if $a is equal to z*
[ $a == z* ] # file globbing and word splitting take place
[ "$a" == "z*" ] # true if $a is equal to z*
# Thanks, S.C.</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><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>
2001-09-04 13:27:31 +00:00
<term><anchor id="ltref"><token>&lt;</token></term>
2001-07-10 14:25:50 +00:00
<listitem>
<para>is less than, in ASCII alphabetical order</para>
2001-09-04 13:27:31 +00:00
<para><userinput>if [[ "$a" &lt; "$b" ]]</userinput></para>
2001-07-10 14:25:50 +00:00
<para><userinput>if [ "$a" \&lt; "$b" ]</userinput></para>
<para>Note that the <quote>&lt;</quote> needs to be
2001-09-04 13:27:31 +00:00
escaped within a <userinput>[ ]</userinput>
construct.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="gtref"><token>&gt;</token></term>
2001-07-10 14:25:50 +00:00
<listitem>
<para>is greater than, in ASCII alphabetical order</para>
2001-09-04 13:27:31 +00:00
<para><userinput>if [[ "$a" &gt; "$b" ]]</userinput></para>
2001-07-10 14:25:50 +00:00
<para><userinput>if [ "$a" \&gt; "$b" ]</userinput></para>
<para>Note that the <quote>&gt;</quote> needs to be
2001-09-04 13:27:31 +00:00
escaped within a <userinput>[ ]</userinput> construct.</para>
2001-07-10 14:25:50 +00:00
<para>See <xref linkend="bubble"> for an application of this
comparison operator.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><token>-z</token></term>
<listitem><para>string is <quote>null</quote>, that is, has zero length</para></listitem>
</varlistentry>
<varlistentry>
<term><token>-n</token></term>
<listitem>
<para>string is not <quote>null</quote>.</para>
<caution><para>The <userinput>-n</userinput> test absolutely
requires that the string be quoted within the
test brackets. Using an unquoted string with
<userinput>! -z</userinput>, 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 <emphasis>null</emphasis></title>
<programlisting>&strtest;</programlisting>
</example>
<example id="ex14">
<title><command>zmost</command></title>
<programlisting>&ex14;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
<variablelist id="ccomparison">
<title><anchor id="ccomparison1">compound comparison</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><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><token>-o</token></term>
<listitem>
<para>logical or </para>
<para><replaceable>exp1 -o exp2</replaceable> returns
true if either exp1 <emphasis>or</emphasis> exp2 are
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>
The <command>-o</command> and <command>-a</command> operators
work with the <command>test</command> command or occur within
2001-09-04 13:27:31 +00:00
single test brackets.
2001-07-10 14:25:50 +00:00
<programlisting>if [ "$exp1" -a "$exp2" ]</programlisting>
</para>
<para>Refer to <xref linkend="andor"> and <xref linkend="twodim">
to see compound comparison operators in action.</para>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Comparison operators (binary) -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="nestedifthen">
2001-07-10 14:25:50 +00:00
<title>Nested if/then Condition Tests</title>
<para>Condition tests using the <command>if/then</command>
construct may be nested. The net result is identical to using the
<command>&&</command> compound comparison operator above.</para>
<para><programlisting>if [ condition1 ]
then
if [ condition2 ]
then
do-something # But only if both "condition1" and "condition2" valid.
fi
fi</programlisting></para>
<para>See <xref linkend="ex79"> for an example of nested
<replaceable>if/then</replaceable> condition tests.</para>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Nested if/then Tests -->
2001-10-15 14:21:41 +00:00
<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
<emphasis>if/then</emphasis> tests, as the following excerpt
shows.</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 <quote>test</quote> constructs in the above excerpt,
then examine the entire file, <filename>/etc/X11/xinit/xinitrc</filename>,
and analyze the <emphasis>if/then</emphasis> 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 -->
2001-09-04 13:27:31 +00:00
</chapter> <!-- Tests -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="operations">
<title>Operations and Related Topics</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="ops">
2001-07-10 14:25:50 +00:00
<title>Operators</title>
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
<varlistentry>
<indexterm>
<primary>=</primary>
</indexterm>
<indexterm>
<primary>operation</primary>
<secondary>=</secondary>
</indexterm>
<term>=</term>
2001-09-04 13:27:31 +00:00
<listitem>
<para>All-purpose assignment operator, which works for both
arithmetic and string assignments.</para>
2001-07-10 14:25:50 +00:00
<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">=</link> test
operator.</para>
<para>
<programlisting># = as a test operator
if [ "$string1" = "$string2" ]
2002-04-01 16:04:17 +00:00
# if [ "X$string1" = "X$string2" ] is safer,
2001-07-10 14:25:50 +00:00
# to prevent an error message should one of the variables be empty.
# (The prepended "X" characters cancel out.)
then
command
fi</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>
2001-09-04 13:27:31 +00:00
<variablelist id="arops">
<title><anchor id="arops1">arithmetic operators</title>
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
<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
<programlisting># Bash, version 2.02, introduced the "**" exponentiation operator.
let "z=5**3"
echo "z = $z" # z = 125</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="moduloref"><token>%</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>%</primary>
</indexterm>
<indexterm>
<primary>operation</primary>
<secondary>%</secondary>
</indexterm>
<indexterm>
<primary>modulo</primary>
</indexterm>
<listitem>
<para>modulo, or mod (returns the remainder of an integer
division operation)</para>
<para>
<screen><prompt>bash$ </prompt><userinput>echo `expr 5 % 3`</userinput>
<computeroutput>2</computeroutput>
</screen>
</para>
<para>This operator finds use in, among other things,
generating numbers within a specific range (see <xref
2002-04-01 16:04:17 +00:00
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>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><token>+=</token></term>
<indexterm>
<primary>+=</primary>
</indexterm>
<indexterm>
<primary>operation</primary>
<secondary>+=</secondary>
</indexterm>
<indexterm>
<primary>plus-equal</primary>
</indexterm>
<listitem><para><quote>plus-equal</quote> (increment variable by a constant)</para>
<para><userinput>let "var += 5"</userinput> results in
<varname>var</varname> 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><quote>minus-equal</quote> (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><quote>times-equal</quote> (multiply variable by a constant)</para>
<para><userinput>let "var *= 4"</userinput> results in <varname>var</varname>
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><quote>slash-equal</quote> (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><quote>mod-equal</quote> (remainder 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>
2001-09-04 13:27:31 +00:00
<note><para>Integer variables in Bash are actually signed
<emphasis>long</emphasis> (32-bit) integers, in the range of
-2147483648 to 2147483647. An operation that takes a variable
outside these limits will give an erroneous result.
<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></note>
2001-07-10 14:25:50 +00:00
<caution><para>Bash does not understand floating point arithmetic. It
treats numbers containing a decimal point as strings.
<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>
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 sockets. <quote>Bit flipping</quote> is more
relevant to compiled languages, such as C and C++, which run
fast enough to permit its use on the fly.</para></formalpara>
2001-09-04 13:27:31 +00:00
<variablelist id="bitwsops">
<title><anchor id="bitwsops1">bitwise operators</title>
2001-07-10 14:25:50 +00:00
<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><quote>left-shift-equal</quote></para>
<para><userinput>let "var <<= 2"</userinput> results in <varname>var</varname>
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><quote>right-shift-equal</quote> (inverse of <token><<=</token>)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><token>&</token></term>
<indexterm>
<primary>&</primary>
</indexterm>
<indexterm>
<primary>operation</primary>
2001-09-04 13:27:31 +00:00
<secondary>&</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>AND</primary>
<secondary>bitwise</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem><para>bitwise and</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>&=</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>&=</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>operation</primary>
2001-09-04 13:27:31 +00:00
<secondary>&=</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>and-equal</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem><para><quote>bitwise and-equal</quote></para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>|</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>|</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>operation</primary>
2001-09-04 13:27:31 +00:00
<secondary>|</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>OR</primary>
<secondary>bitwise</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem><para>bitwise OR</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>|=</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>|=</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>operation</primary>
2001-09-04 13:27:31 +00:00
<secondary>|=</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>OR-equal</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem><para><quote>bitwise OR-equal</quote></para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>~</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>~</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>operation</primary>
2001-09-04 13:27:31 +00:00
<secondary>~</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>negate</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem><para>bitwise negate</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>!</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>!</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>operation</primary>
2001-09-04 13:27:31 +00:00
<secondary>!</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>NOT</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem><para>bitwise NOT</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>^</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>^</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>operation</primary>
2001-09-04 13:27:31 +00:00
<secondary>^</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>XOR</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem><para>bitwise XOR</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><token>^=</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>^=</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>operation</primary>
2001-09-04 13:27:31 +00:00
<secondary>^=</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>XOR-equal</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem><para><quote>bitwise XOR-equal</quote></para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
<variablelist id="logops">
<title><anchor id="logops1">logical operators</title>
2001-07-10 14:25:50 +00:00
<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 (logical)</para>
<para><programlisting>if [ $condition1 ] && [ $condition2 ]
2001-09-04 13:27:31 +00:00
# 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>
2001-07-10 14:25:50 +00:00
<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>
2002-06-03 14:35:48 +00:00
<term><anchor id="orref"><token>||</token></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>||</primary>
</indexterm>
<indexterm>
<primary>operator</primary>
<secondary>||</secondary>
</indexterm>
<indexterm>
<primary>OR</primary>
<secondary>logical</secondary>
</indexterm>
<listitem><para>or (logical)</para>
<para><programlisting>if [ $condition1 ] || [ $condition2 ]
2001-09-04 13:27:31 +00:00
# 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>
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
<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
2002-06-17 13:17:07 +00:00
evaluated (with possible <emphasis>side effects</emphasis>),
2001-09-04 13:27:31 +00:00
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
2001-10-15 14:21:41 +00:00
linkend="forloopref1">for loops</link>. See <xref
2001-09-04 13:27:31 +00:00
linkend="forloopc">.</para>
</listitem>
</varlistentry>
</variablelist>
</sect1> <!-- Operators -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="Numerical-Constants">
2001-07-10 14:25:50 +00:00
<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> is evaluated as
<replaceable>BASE#NUMBER</replaceable> (this option is of limited
usefulness because of range restrictions).</para>
<example id="numbers">
<title>Representation of numerical constants<token>:</token></title>
<programlisting>&numbers;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Numerical-Constants -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- Operations -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</part> <!-- Part 2 (Basics) -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<part label="Part 3" id="part3">
<title>Beyond the Basics</title>
<chapter id="variables2">
2001-07-10 14:25:50 +00:00
<title>Variables Revisited</title>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<para>Used properly, variables can add power and flexibility
to scripts. This requires learning their subtleties and
nuances.</para>
2001-09-04 13:27:31 +00:00
<sect1 id="internalvariables">
<title>Internal Variables</title>
<variablelist id="internalvariables1">
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><replaceable><link
linkend="builtinref">Builtin</link> variables</replaceable></term>
2001-07-10 14:25:50 +00:00
<listitem><para>variables affecting bash script behavior</para>
</listitem>
</varlistentry>
<varlistentry>
<term><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 <emphasis>Bash</emphasis>
2002-06-03 14:35:48 +00:00
binary itself
<screen><prompt>bash$ </prompt><userinput>echo $BASH</userinput>
<computeroutput>/bin/bash</computeroutput></screen>
</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><varname>$BASH_ENV</varname></term>
<indexterm>
<primary>$BASH_ENV</primary>
</indexterm>
<indexterm>
<primary>variable</primary>
<secondary>$BASH_ENV</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<listitem><para>an <link linkend="envref">environmental
variable</link> pointing to a Bash startup file to be read
when a script is invoked</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<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] = 2 # Major version no.
2002-06-03 14:35:48 +00:00
# BASH_VERSINFO[1] = 05 # Minor version no.
# BASH_VERSINFO[2] = 8 # Patch level.
2001-10-15 14:21:41 +00:00
# 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>
2001-07-10 14:25:50 +00:00
<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>2.04.12(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
2001-10-15 14:21:41 +00:00
shell is running. <link linkend="shellvarref">$SHELL</link>
does not necessarily give the correct answer.</para>
2001-07-10 14:25:50 +00:00
</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>
2002-04-01 16:04:17 +00:00
<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>
2001-07-10 14:25:50 +00:00
</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>
2001-09-04 13:27:31 +00:00
<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>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<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>
2001-09-04 13:27:31 +00:00
<varlistentry>
2001-07-10 14:25:50 +00:00
<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>.
</para>
2002-04-01 16:04:17 +00:00
<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>
2001-07-10 14:25:50 +00:00
</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 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>input field separator</primary>
</indexterm>
<listitem><para>input field separator</para>
<para>This 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 | cat -vte</userinput>
<computeroutput>$</computeroutput>
<prompt>bash$ </prompt><userinput>bash -c 'set w x y z; IFS=":-;"; echo "$*"'</userinput>
<computeroutput>w:x:y:z</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>(Thanks, S. C., for clarification and examples.)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>$IGNOREEOF</varname></term>
<indexterm>
<primary>$IGNOREEOF</primary>
</indexterm>
<indexterm>
<primary>variable</primary>
<secondary>$IGNOREEOF</secondary>
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>Ignore EOF</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem><para>ignore EOF: how many end-of-files (control-D)
the shell will ignore before logging out.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<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>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><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>
2002-06-03 14:35:48 +00:00
<para><programlisting># *** BEGIN DEBUG BLOCK ***
last_cmd_arg=$_ # Save it.
2001-07-10 14:25:50 +00:00
echo "At line number $LINENO, variable \"v1\" = $v1"
2002-06-03 14:35:48 +00:00
echo "Last command argument processed = $last_cmd_arg"
# *** END DEBUG BLOCK ***</programlisting></para>
2001-07-10 14:25:50 +00:00
</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-debian-linux-gnu</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-gnu</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
2002-06-03 14:35:48 +00:00
<emphasis>path</emphasis> 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
2001-07-10 14:25:50 +00:00
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>
<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>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><varname>$PIPESTATUS</varname></term>
<indexterm>
<primary>$PIPESTATUS</primary>
</indexterm>
<indexterm>
<primary>variable</primary>
<secondary>pipe</secondary>
</indexterm>
<listitem>
<para>Exit status of last executed <link
linkend="piperef">pipe</link>. Interestingly enough,
this does not give the same result as the <link
linkend="exitstatusref">exit status</link> of the last
executed command.</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</userinput>
<computeroutput>141</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>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<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><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><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>
2002-06-03 14:35:48 +00:00
<term><anchor id="replyref"><varname>$REPLY</varname></term>
2001-07-10 14:25:50 +00:00
<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>
2002-06-17 13:17:07 +00:00
<primary>seconds execution time</primary>
2001-07-10 14:25:50 +00:00
</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>
2002-06-03 14:35:48 +00:00
<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>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><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. If,
at the command line, $SHLVL is 1, then in a script it will
increment to 2.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><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
<emphasis>time</emphasis>, then the shell prompt will time out
after <emphasis>time</emphasis> seconds. This will cause a
logout.</para>
<note><para>Unfortunately, this works only while waiting
for input at the shell prompt console or in an xterm. While
it would be nice to speculate on the uses of this
internal variable for timed input, for example in
combination with <link linkend="readref">read</link>,
<replaceable>$TMOUT</replaceable> does not work
in that context and is virtually useless for shell
scripting. (Reportedly the <emphasis>ksh</emphasis> version
2002-06-17 13:17:07 +00:00
of a timed <command>read</command> does work.)</para></note>
2001-07-10 14:25:50 +00:00
<para>Implementing timed input in a script is certainly
2002-04-01 16:04:17 +00:00
possible, but may require complex machinations. One method
is to set up a timing loop to signal the script when it
times out. This also requires a signal handling routine to
trap (see <xref linkend="ex76">) the interrupt generated by
the timing loop (whew!).</para>
2001-07-10 14:25:50 +00:00
<example id="tmdin">
<title>Timed Input</title>
<programlisting>&tmdin;</programlisting>
</example>
<para>An alternative is using <link
linkend="sttyref">stty</link>.</para>
<example id="timeout">
<title>Once more, timed input</title>
<programlisting>&timeout;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<para>Perhaps the simplest method is using the
<option>-t</option> option to <link
linkend="readref">read</link>.</para>
<example id="tout">
<title>Timed <command>read</command></title>
<programlisting>&tout;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
</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 -->
2001-10-15 14:21:41 +00:00
<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>
2002-06-03 14:35:48 +00:00
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>,
2001-10-15 14:21:41 +00:00
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>
2001-09-04 13:27:31 +00:00
<!-- Nest note after $USER -->
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
</variablelist>
<!-- Last entry of intrinsic BASH variables -->
<variablelist id="posparmslist">
<title>Positional Parameters</title>
2001-09-04 13:27:31 +00:00
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="posparamref"><varname>$0</varname>, <varname>$1</varname>,
<varname>$2</varname>, etc.</term>
2001-09-04 13:27:31 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>$0</primary>
2001-09-04 13:27:31 +00:00
</indexterm>
<indexterm>
<primary>variable</primary>
2001-10-15 14:21:41 +00:00
<secondary>$0</secondary>
2001-09-04 13:27:31 +00:00
</indexterm>
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>positional parameter</primary>
2001-09-04 13:27:31 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<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><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, that of a variable passed
to a script or function.</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>
</listitem>
</varlistentry>
<varlistentry>
<term><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>
<example id="arglist">
<title><command>arglist</command>: Listing arguments with $* and $@</title>
<programlisting>&arglist;</programlisting>
2002-04-01 16:04:17 +00:00
</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>
2001-10-15 14:21:41 +00:00
<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>
2002-04-01 16:04:17 +00:00
2001-10-15 14:21:41 +00:00
<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</para>
2001-09-04 13:27:31 +00:00
<caution><para>This was originally a <emphasis>ksh</emphasis>
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><varname>$!</varname></term>
<indexterm>
<primary>$!</primary>
</indexterm>
<indexterm>
<primary>variable</primary>
<secondary>$!</secondary>
</indexterm>
<indexterm>
<primary>PID</primary>
2002-06-17 13:17:07 +00:00
<secondary>last job background</secondary>
2001-09-04 13:27:31 +00:00
</indexterm>
<listitem>
<para>PID (process id) of last job run in background</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
2002-06-03 14:35:48 +00:00
echo $_ # /bin/bash
# Just called /bin/bash to run the script.
2001-09-04 13:27:31 +00:00
2002-06-03 14:35:48 +00:00
du >/dev/null # So no output from command.
echo $_ # du
2001-09-04 13:27:31 +00:00
2002-06-03 14:35:48 +00:00
ls -al >/dev/null # So no output from command.
echo $_ # -al (last argument)
2001-09-04 13:27:31 +00:00
:
2002-06-03 14:35:48 +00:00
echo $_ # :</programlisting></example>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<varlistentry>
2002-06-03 14:35:48 +00:00
<term><anchor id="proccid"><varname>$$</varname></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>$$</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>variable</primary>
2001-10-15 14:21:41 +00:00
<secondary>$$</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>PID</primary>
<secondary>of script</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2002-06-03 14:35:48 +00:00
<listitem><para>process id of the script itself, often used
in scripts to construct <quote>unique</quote> temp file names
(see <xref linkend="ftpget">, <xref linkend="online">, <xref
linkend="derpm">, and <xref linkend="selfdestruct">)</para>
2001-10-15 14:21:41 +00:00
</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>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>string length</primary>
<secondary>parameter substitution</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem><para></para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term>expr length $string</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>string length</primary>
<secondary>expr</secondary>
</indexterm>
<listitem><para></para>
</listitem>
</varlistentry>
<varlistentry>
<term>expr "$string" : '.*'</term>
<indexterm>
<primary>string length</primary>
<secondary>expr</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem><para>
<programlisting>stringZ=abcABC123ABCabc
echo ${#stringZ} # 15
echo `expr length $stringZ` # 15
echo `expr "$stringZ" : '.*'` # 15</programlisting>
</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist id="lengthsubstring">
<title>Length of Matching Substring at Beginning of String</title>
<varlistentry>
<term>expr match "$string" '$substring'</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring length</primary>
<secondary>expr</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
<para><replaceable>$substring</replaceable> is a <link
linkend="regexref">regular expression</link>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>expr "$string" : '$substring'</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring length</primary>
<secondary>expr</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
<para><replaceable>$substring</replaceable> is a regular
expression.</para>
<para>
<programlisting>stringZ=abcABC123ABCabc
# |------|
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>expr index $string $substring</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring index</primary>
<secondary>expr</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
<para>Numerical position in $string of first character in
$substring that matches.</para>
<para><programlisting>stringZ=abcABC123ABCabc
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
<emphasis>strchr()</emphasis> in C.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
</variablelist>
<variablelist id="substringextraction">
<title>Substring Extraction</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-10-15 14:21:41 +00:00
<term>${string:position}</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>extraction</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
<para>Extracts substring from <replaceable>$string</replaceable> at
<replaceable>$position</replaceable>.</para>
2002-06-03 14:35:48 +00:00
<para>If the <varname>$string</varname> parameter is
2001-10-15 14:21:41 +00:00
<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>
2002-06-03 14:35:48 +00:00
starting at <varname>$position</varname>.</para>
2001-10-15 14:21:41 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term>${string:position:length}</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>extraction</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<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.</programlisting>
</para>
2002-06-03 14:35:48 +00:00
<para>If the <varname>$string</varname> parameter is
2001-10-15 14:21:41 +00:00
<quote><token>*</token></quote> or
<quote><token>@</token></quote>, then this extracts a maximum
2002-06-03 14:35:48 +00:00
of <varname>$length</varname> positional parameters, starting
at <varname>$position</varname>.</para>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>extraction expr</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<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>
2002-06-03 14:35:48 +00:00
<para><anchor id="exprparen"></para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term>expr match "$string" '\($substring\)'</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring extraction</primary>
<secondary>expr</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring extraction</primary>
<secondary>expr</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<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
2002-06-03 14:35:48 +00:00
# =======
2001-10-15 14:21:41 +00:00
echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1
echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1
2002-06-03 14:35:48 +00:00
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>
2001-10-15 14:21:41 +00:00
</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist id="substringremoval">
<title>Substring Removal</title>
<varlistentry>
<term>${string#substring}</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>removal</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
<para>Strips shortest match of
<replaceable>$substring</replaceable> from
<emphasis>front</emphasis> of
<replaceable>$string</replaceable>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term>${string##substring}</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>removal</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
<para>Strips longest match of
<replaceable>$substring</replaceable> from
<emphasis>front</emphasis> of
<replaceable>$string</replaceable>.</para>
<para>
<programlisting>stringZ=abcABC123ABCabc
# |----|
# |----------|
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>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>removal</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
<para>Strips shortest match of
<replaceable>$substring</replaceable> from
<emphasis>back</emphasis> of
<replaceable>$string</replaceable>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>${string%%substring}</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>removal</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
<para>Strips longest match of
<replaceable>$substring</replaceable> from
<emphasis>back</emphasis> of
<replaceable>$string</replaceable>.</para>
<para>
<programlisting>stringZ=abcABC123ABCabc
# ||
# |------------|
echo ${stringZ%b*c} # abcABC123ABCa
2002-01-07 15:24:19 +00:00
# Strip out shortest match between 'b' and 'c', from back of $stringZ.
2001-10-15 14:21:41 +00:00
echo ${stringZ%%b*c} # a
2002-01-07 15:24:19 +00:00
# Strip out longest match between 'b' and 'c', from back of $stringZ.</programlisting>
2001-10-15 14:21:41 +00:00
</para>
2002-01-07 15:24:19 +00:00
<example id="cvt">
<title>Converting graphic file formats, with filename change</title>
<programlisting>&cvt;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
</listitem>
</varlistentry>
</variablelist>
<variablelist id="substringreplacement">
<title>Substring Replacement</title>
<varlistentry>
<term>${string/substring/replacement}</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>replacement</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
<para>Replace first match of
<replaceable>$substring</replaceable> with
<replaceable>$replacement</replaceable>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term>${string//substring/replacement}</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>replacement</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<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'.</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>${string/#substring/replacement}</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>replacement</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<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>${string/%substring/replacement}</term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>substring</primary>
<secondary>replacement</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<para>If <replaceable>$substring</replaceable> matches
<emphasis>back</emphasis> end of
<replaceable>$string</replaceable>, substitute
<replaceable>$replacement</replaceable> for
<replaceable>$substring</replaceable>.</para>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<para>
<programlisting>stringZ=abcABC123ABCabc
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
echo ${stringZ/#abc/XYZ} # XYZABC123ABCabc
# Replaces front-end match of 'abc' with 'xyz'.
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ
# Replaces back-end match of 'abc' with 'xyz'.</programlisting>
</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
</variablelist>
2002-01-07 15:24:19 +00:00
<sect2 id="awkstringmanip">
<title>Manipulating strings using awk</title>
<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 substrings</title>
<programlisting>&substringex;</programlisting>
</example>
</sect2> <!-- Manipulating strings using awk -->
<sect2 id="strfdisc">
<title>Further Discussion</title>
<para>For more on string manipulation in scripts, refer to <xref
linkend="Parameter-Substitution"> and the
2001-10-15 14:21:41 +00:00
<link linkend="expextrsub">relevant section</link> of the <link
linkend="exprref">expr</link> command listing. For script examples,
see: <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>
</orderedlist>
</para>
2001-07-10 14:25:50 +00:00
2002-01-07 15:24:19 +00:00
</sect2> <!-- Further Discussion -->
2001-10-15 14:21:41 +00:00
</sect1> <!-- Manipulating Strings -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="Parameter-Substitution">
<title>Parameter Substitution</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para><anchor id="paramsubref"></para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="pssub">
<title><anchor id="pssub1">Manipulating and/or expanding variables</title>
<varlistentry>
<term>
<userinput>${parameter}</userinput></term>
<listitem>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>May be used for concatenating variables with strings.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<note><para>This is almost equivalent to
<replaceable>${parameter:-default}</replaceable>. The
extra <token>:</token> makes a difference only when
<emphasis>parameter</emphasis> has been declared,
but is null. </para></note>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para><programlisting>&paramsub;</programlisting></para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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 default.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>Both forms nearly equivalent. The <token>:</token>
makes a difference only when <emphasis>$parameter</emphasis>
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 code for
<quote>command not found</quote>).</para>
</footnote>
as above.
</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para><programlisting>
echo ${username=`whoami`}
# Variable "username" is now set to `whoami`.</programlisting></para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>Both forms nearly equivalent. The <token>:</token>
makes a difference only when <emphasis>parameter</emphasis>
has been declared and is null, see below.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para><programlisting>echo "###### \${parameter+alt_value} ########"
echo
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
a=${param1+xyz}
echo "a = $a" # a =
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
param2=
a=${param2+xyz}
echo "a = $a" # a = xyz
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
param3=123
a=${param3+xyz}
echo "a = $a" # a = xyz
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
echo
echo "###### \${parameter:+alt_value} ########"
echo
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
a=${param4:+xyz}
echo "a = $a" # a =
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
param5=
a=${param5:+xyz}
echo "a = $a" # a =
# Different result from a=${param5+xyz}
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
param6=123
a=${param6+xyz}
echo "a = $a" # a = xyz</programlisting></para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
2002-06-03 14:35:48 +00:00
<term><anchor id="qerrmsg"><userinput>${parameter?err_msg}</userinput></term>
2001-09-04 13:27:31 +00:00
<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 <emphasis>parameter</emphasis>
has been declared and is null, as above.</para>
</listitem>
</varlistentry>
</variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<example id="ex6">
<title>Using param substitution and <token>:</token></title>
<programlisting>&ex6;</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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="psorex">
<title><anchor id="psorex1">Variable length / Substring removal</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<note><para>
Exceptions:
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<itemizedlist>
<listitem><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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<example id="length">
<title>Length of a variable</title>
<programlisting>&length;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
2002-06-03 14:35:48 +00:00
<term><userinput>${var#Pattern}</userinput></term>
<term><userinput>${var##Pattern}</userinput></term>
2001-09-04 13:27:31 +00:00
<listitem>
<para>Remove from <varname>$var</varname>
2002-06-03 14:35:48 +00:00
the shortest/longest part of <varname>$Pattern</varname>
2001-09-04 13:27:31 +00:00
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 () # Better to strip possible leading zero(s)
{ # from day and/or month
val=${1#0} # since otherwise Bash will interpret them
return $val # as octal values (POSIX.2, sect 2.9.2.1).
}</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.
2001-10-15 14:21:41 +00:00
echo "${0##*/}" # Name of script.
echo
filename=test.data
echo "${filename##*.}" # data
# Extension of filename.</programlisting>
2001-09-04 13:27:31 +00:00
</para>
</listitem>
</varlistentry>
<varlistentry>
2002-06-03 14:35:48 +00:00
<term><anchor id="pctpatref"><userinput>${var%Pattern}</userinput></term>
<term><userinput>${var%%Pattern}</userinput></term>
2001-09-04 13:27:31 +00:00
<listitem><para>Remove from <varname>$var</varname>
2002-06-03 14:35:48 +00:00
the shortest/longest part of <varname>$Pattern</varname>
2001-09-04 13:27:31 +00:00
that matches the <replaceable>back end</replaceable>
of <varname>$var</varname>.
</para></listitem>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</varlistentry>
</variablelist>
<para><link linkend="bash2ref">Version 2</link> of Bash adds
additional options.</para>
<example id="pattmatching">
<title>Pattern matching in parameter substitution</title>
<programlisting>&pattmatching;</programlisting>
2001-07-10 14:25:50 +00:00
</example>
2001-09-04 13:27:31 +00:00
<example id="rfe">
<title>Renaming file extensions<token>:</token></title>
<programlisting>&rfe;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="exprepl">
<title><anchor id="exprepl1">Variable expansion / Substring
replacement</title>
<varlistentry>
<term></term>
<listitem>
<para>These constructs have been adopted from
<emphasis>ksh</emphasis>.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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>
2002-06-03 14:35:48 +00:00
<term><userinput>${var/Pattern/Replacement}</userinput></term>
2001-09-04 13:27:31 +00:00
<listitem>
2002-06-03 14:35:48 +00:00
<para>First match of <replaceable>Pattern</replaceable>,
2001-09-04 13:27:31 +00:00
within <replaceable>var</replaceable> replaced with
2002-06-03 14:35:48 +00:00
<replaceable>Replacement</replaceable>.</para>
<para>If <replaceable>Replacement</replaceable> is
2001-09-04 13:27:31 +00:00
omitted, then the first match of
2002-06-03 14:35:48 +00:00
<replaceable>Pattern</replaceable> is replaced by
2001-09-04 13:27:31 +00:00
<emphasis>nothing</emphasis>, that is, deleted.</para>
</listitem>
</varlistentry>
<varlistentry>
2002-06-03 14:35:48 +00:00
<term><userinput>${var//Pattern/Replacement}</userinput></term>
2001-09-04 13:27:31 +00:00
<listitem>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<formalpara><title>Global replacement</title>
2002-06-03 14:35:48 +00:00
<para>All matches of <replaceable>Pattern</replaceable>,
2001-09-04 13:27:31 +00:00
within <replaceable>var</replaceable> replaced with
2002-06-03 14:35:48 +00:00
<replaceable>Replacement</replaceable>.</para>
2001-09-04 13:27:31 +00:00
</formalpara>
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
<para>As above, if <replaceable>Replacement</replaceable>
2001-09-04 13:27:31 +00:00
is omitted, then all occurrences of
2002-06-03 14:35:48 +00:00
<replaceable>Pattern</replaceable> are replaced by
2001-09-04 13:27:31 +00:00
<emphasis>nothing</emphasis>, that is, deleted.</para>
<example id="ex7">
<title>Using pattern matching to parse arbitrary strings</title>
<programlisting>&ex7;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
2002-06-03 14:35:48 +00:00
<term><userinput>${var/#Pattern/Replacement}</userinput></term>
2001-09-04 13:27:31 +00:00
<listitem>
<para>If <emphasis>prefix</emphasis> of
<replaceable>var</replaceable> matches
2002-06-03 14:35:48 +00:00
<replaceable>Pattern</replaceable>, then substitute
<replaceable>Replacement</replaceable> for
<replaceable>Pattern</replaceable>.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
2002-06-03 14:35:48 +00:00
<term><userinput>${var/%Pattern/Replacement}</userinput></term>
2001-09-04 13:27:31 +00:00
<listitem>
<para>If <emphasis>suffix</emphasis> of
<replaceable>var</replaceable> matches
2002-06-03 14:35:48 +00:00
<replaceable>Pattern</replaceable>, then substitute
<replaceable>Replacement</replaceable> for
<replaceable>Pattern</replaceable>.</para>
2001-09-04 13:27:31 +00:00
<example id="varmatch">
<title>Matching patterns at prefix or suffix of string</title>
<programlisting>&varmatch;</programlisting>
2001-07-10 14:25:50 +00:00
</example>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><userinput>${!varprefix*}</userinput></term>
<term><userinput>${!varprefix@}</userinput></term>
<listitem>
<para>Matches all previously declared variables beginning
with <emphasis>varprefix</emphasis>.
<programlisting>xyz23=whatever
xyz24=
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
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
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
# Bash, version 2.04, adds this feature.</programlisting>
</para>
</listitem>
</varlistentry>
</variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1> <!-- Parameter Substitution -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="declareref">
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>declare</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>typeset</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>declare</secondary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>typeset</secondary>
</indexterm>
2001-09-04 13:27:31 +00:00
<title>Typing variables: <command>declare</command> or
<command>typeset</command></title>
2001-07-10 14:25:50 +00:00
<para>The <command>declare</command> or <command>typeset</command>
2001-09-04 13:27:31 +00:00
<link linkend="builtinref">builtins</link> (they are exact
synonyms) permit restricting the properties of variables. This
is a very weak form of the typing available in certain
programming languages. The <command>declare</command>
command is specific to version 2 or later of Bash. The
<command>typeset</command> command also works in ksh
scripts.</para>
<variablelist id="declareopsref">
<title><anchor id="declareopsref1">declare/typeset options</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><token>-r</token> <replaceable>readonly</replaceable></term>
<listitem><para><programlisting>declare -r var1</programlisting></para>
<para>(<userinput>declare -r var1</userinput> works the same as
<userinput>readonly var1</userinput>)</para>
<para>This is the rough equivalent of the C
<command>const</command> type qualifier. An
attempt to change the value of a readonly variable fails with an
error message.</para></listitem>
</varlistentry>
<varlistentry>
<term><token>-i</token> <replaceable>integer</replaceable></term>
2001-09-04 13:27:31 +00:00
<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 "three" as an integer.</programlisting>
Note that certain arithmetic operations are permitted
for declared integer variables without the need
for <link linkend="exprref">expr</link> or <link
2001-07-10 14:25:50 +00:00
linkend="letref">let</link>.</para></listitem>
</varlistentry>
<varlistentry>
<term><token>-a</token> <replaceable>array</replaceable></term>
<listitem><para><programlisting>declare -a indices</programlisting></para>
<para>The variable <varname>indices</varname> will be treated as
an array.</para></listitem>
</varlistentry>
<varlistentry>
<term><token>-f</token> <replaceable>functions</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
functions 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>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term>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>
2001-07-10 14:25:50 +00:00
</variablelist>
<example id="ex20">
<title>Using <command>declare</command> to type variables</title>
<programlisting>&ex20;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Typing variables: declare or typeset -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="ivr">
2001-07-10 14:25:50 +00:00
<title>Indirect References to Variables</title>
<para><anchor id="ivrref"></para>
<para>Assume that the value of a variable is the name of a second
variable. Is it somehow possible to retrieve the value
of this second variable from the first one? For example,
if <replaceable>a=letter_of_alphabet</replaceable>
and <replaceable>letter_of_alphabet=z</replaceable>,
can a reference to <replaceable>a</replaceable> return
<replaceable>z</replaceable>? This can indeed be done, and
it is called an <emphasis>indirect reference</emphasis>. It
uses the unusual <replaceable>eval var1=\$$var2</replaceable>
notation.</para>
<example id="indref">
<title>Indirect References</title>
<programlisting>&indref;</programlisting>
</example>
<example id="coltotaler2">
<title>Passing an indirect reference to <replaceable>awk</replaceable></title>
<programlisting>&coltotaler2;</programlisting>
</example>
<caution><para>This method of indirect referencing is a bit tricky.
2002-06-17 13:17:07 +00:00
If the second order variable changes its value, then the first
2001-07-10 14:25:50 +00:00
order variable must be properly dereferenced (as in the above
2001-09-04 13:27:31 +00:00
example). <anchor id="ivr2">Fortunately, the
<replaceable>${!variable}</replaceable> notation introduced
with <link linkend="bash2ref">version 2</link> of Bash
(see <xref linkend="ex78">) makes indirect referencing more
intuitive.</para></caution>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1> <!-- Indirect References to Variables -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="randomvar">
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>$RANDOM</primary>
</indexterm>
<indexterm>
<primary>variable</primary>
<secondary>$RANDOM</secondary>
</indexterm>
<title>$RANDOM: generate random integer</title>
2002-01-07 15:24:19 +00:00
<para>$RANDOM is an internal Bash function (not a constant) that
2001-07-10 14:25:50 +00:00
returns a <emphasis>pseudorandom</emphasis> integer in the range
0 - 32767. $RANDOM should <replaceable>not</replaceable> be used
2002-01-07 15:24:19 +00:00
to generate an encryption key.</para>
2001-07-10 14:25:50 +00:00
<example id="ex21">
<title>Generating random numbers</title>
<programlisting>&ex21;</programlisting>
</example>
<para>Just how random is RANDOM? The best way to test this is
to write a script that tracks the distribution of
<quote>random</quote> numbers generated by RANDOM. Let's roll
a RANDOM die a few times...</para>
<example id="randomtest">
<title>Rolling the die with RANDOM</title>
<programlisting>&randomtest;</programlisting>
</example>
<para>As we have seen in the last example, it is best to
<quote>reseed</quote> the <varname>RANDOM</varname>
generator each time it is invoked. Using the same seed
for <varname>RANDOM</varname> repeats the same series
of numbers. (This mirrors the behavior of the
<replaceable>random()</replaceable> function in C.)</para>
<example id="seedingrandom">
<title>Reseeding RANDOM</title>
<programlisting>&seedingrandom;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<para><anchor id="urandomref"></para>
2002-01-07 15:24:19 +00:00
<note>
<para>The <filename>/dev/urandom</filename> device-file provides
2001-07-10 14:25:50 +00:00
a means 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
2001-09-04 13:27:31 +00:00
filtering through <link linkend="odref">od</link> (as in
above example) or using <link linkend="ddref">dd</link>
2002-01-07 15:24:19 +00:00
(see <xref linkend="blotout">).</para>
<para><anchor id="awkrandomref"></para>
<para>There are also other means of generating 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>
</note>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1> <!-- RANDOM: generate random integer -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="dblparens">
2001-07-10 14:25:50 +00:00
<title>The Double Parentheses Construct</title>
<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 <quote>a</quote> to <quote>5 +
3</quote>, or 8. However, this double parentheses construct is
also a mechanism for allowing C-type manipulation of variables
in Bash.</para>
<example id="cvars">
<title>C-type manipulation of variables</title>
<programlisting>&cvars;</programlisting>
</example>
<para>See also <xref linkend="forloopc">.</para>
2001-09-04 13:27:31 +00:00
</sect1> <!-- The Double Parentheses Construct -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- Variables Revisited -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="loops">
<title>Loops and Branches</title>
2001-07-10 14:25:50 +00:00
<para>Operations on code blocks are the key to structured, organized
shell scripts. Looping and branching constructs provide the tools for
accomplishing this.</para>
2001-09-04 13:27:31 +00:00
<sect1 id="loops1">
2001-07-10 14:25:50 +00:00
<title>Loops</title>
<para>A <emphasis>loop</emphasis> is a block of code that iterates
(repeats) a list of commands as long as the loop control condition is
true.</para>
2001-09-04 13:27:31 +00:00
<variablelist id="forloopref">
<title><anchor id="forloopref1">for loops</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>for (in)</command></term>
2001-07-10 14:25:50 +00:00
<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 C counterpart.</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>
2002-06-03 14:35:48 +00:00
<arg rep=repeat choice=plain><replaceable>&nbsp;command(s)</replaceable></arg><sbr>
2001-07-10 14:25:50 +00:00
<arg choice="plain">done</arg>
</cmdsynopsis></para>
<note><para>During each pass through the loop,
<replaceable>arg</replaceable> takes on the value of each
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 wild cards.</para>
<para>If <command>do</command> is on same line as
<command>for</command>, 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 <command>for</command> loops</title>
<programlisting>&ex22;</programlisting>
</example>
<note><para>Each <userinput>[list]</userinput> element
may contain multiple parameters. This is useful when
processing parameters in groups. In such cases, use the
<command>set</command> command (see <xref linkend="ex34">)
to force parsing of each <userinput>[list]</userinput>
element and assignment of each component to the positional
parameters.</para></note>
<example id="ex22a">
<title><command>for</command> loop with two parameters in each
[list] element</title>
<programlisting>&ex22a;</programlisting>
</example>
<para>A variable may supply the <userinput>[list]</userinput> in a
<command>for</command> loop.</para>
<example id="fileinfo">
<title><emphasis>Fileinfo:</emphasis> operating on a file list
contained in a variable</title>
<programlisting>&fileinfo;</programlisting>
</example>
<para>The <userinput>[list]</userinput> in a
<command>for</command> loop may contain filename <link
linkend="globbingref">globbing</link>, that is, using
wildcards for filename expansion.</para>
<example id="listglob">
<title><command>Operating on files with a for</command> loop</title>
<programlisting>&listglob;</programlisting>
</example>
<para>Omitting the <userinput>in [list]</userinput> part of a
2001-10-15 14:21:41 +00:00
<command>for</command> loop causes the loop to operate
on <token>$@</token>, the list of arguments given
on the command line to the script. A particularly clever
illustration of this is <xref linkend="primes">.</para>
2001-07-10 14:25:50 +00:00
<example id="ex23">
<title>Missing <userinput>in [list]</userinput> in a
<command>for</command> loop</title>
<programlisting>&ex23;</programlisting>
</example>
<para>It is possible to use <link
linkend="commandsubref">command substitution</link>
to generate the <userinput>[list]</userinput> in a
<command>for</command> loop. See also <xref linkend="ex53">,
<xref linkend="symlinks"> and <xref linkend="base">.</para>
<example id="forloopcmd">
<title>Generating the [list] in a <command>for</command>
loop with command substitution</title>
<programlisting>&forloopcmd;</programlisting>
</example>
<para>This is a somewhat more complex example of using command
substitution to create the [list].</para>
<example id="bingrep">
<title>A <link linkend="grepref">grep</link> replacement
for binary files</title>
<programlisting>&bingrep;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<para>More of the same.</para>
<example id="userlist">
<title>Listing all users on the system</title>
<programlisting>&userlist;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
2002-04-01 16:04:17 +00:00
<para>A final example of the [list] resulting from command
substitution.</para>
2001-07-10 14:25:50 +00:00
<example id="findstring">
<title>Checking all the binaries in a directory for
authorship</title>
<programlisting>&findstring;</programlisting>
</example>
<para>The output of a <command>for</command> loop may be piped to
a command or commands.</para>
<example id="symlinks">
<title>Listing the symbolic links in a directory</title>
<programlisting>&symlinks;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<para>There is an alternative syntax to a <command>for</command>
loop that will look very familiar to C programmers. This
requires double parentheses.</para>
<example id="forloopc">
<title>A C-like <command>for</command> loop</title>
<programlisting>&forloopc;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<para>See also <xref linkend="qfunction">, <xref
linkend="twodim">, and <xref linkend="collatz">.</para>
2001-07-10 14:25:50 +00:00
<para>---</para>
2002-04-01 16:04:17 +00:00
<para>Now, a <emphasis>for-loop</emphasis> used in a
<quote>real-life</quote> context.</para>
2001-07-10 14:25:50 +00:00
<example id="ex24">
<title>Using <command>efax</command> 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
2002-04-01 16:04:17 +00:00
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
<emphasis>while loop</emphasis> finds use in situations
where the number of loop repetitions is not known
beforehand.</para>
2001-07-10 14:25:50 +00:00
<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</replaceable></arg><sbr>
<arg choice="plain">done</arg>
</cmdsynopsis></para>
2002-04-01 16:04:17 +00:00
2001-07-10 14:25:50 +00:00
<para>As is the case with <token>for/in</token> loops, placing the
<command>do</command> 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 certain specialized <command>while</command>
loops, as, for example, a <link
linkend="getoptsx">getopts construct</link>, deviate
somewhat from the standard template given here.</para>
<example id="ex25">
<title>Simple <command>while</command> loop</title>
<programlisting>&ex25;</programlisting>
</example>
<example id="ex26">
<title>Another <command>while</command> loop</title>
<programlisting>&ex26;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
<para>A <command>while</command> loop may have multiple
2001-07-10 14:25:50 +00:00
conditions. Only the final condition determines when the loop
terminates. This necessitates a slightly different loop syntax,
2001-09-04 13:27:31 +00:00
however.</para>
2001-07-10 14:25:50 +00:00
<example id="ex26a">
<title><command>while</command> loop with multiple conditions</title>
<programlisting>&ex26a;</programlisting>
</example>
<para>As with a <command>for</command> loop, a
<command>while</command> loop may employ C-like syntax
by using the double parentheses construct (see also <xref
linkend="cvars">).</para>
<example id="whloopc">
<title>C-like syntax in a <command>while</command> loop</title>
<programlisting>&whloopc;</programlisting>
</example>
<note><para>A <command>while</command> loop may have its
<filename>stdin</filename> <link
linkend="redirref">redirected to a file</link> by a
<token>&lt;</token> at its end.</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 false (opposite of
<command>while</command> loop).</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</replaceable></arg><sbr>
<arg choice="plain">done</arg>
</cmdsynopsis></para>
<para>Note that an <command>until</command> loop tests for the
terminating condition at the top of the loop, differing from a
similar construct in some programming languages.</para>
<para>As is the case with <token>for/in</token> loops, placing the
<command>do</command> 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><command>until</command> loop</title>
<programlisting>&ex27;</programlisting>
</example>
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Loops -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="nestedloops">
2001-07-10 14:25:50 +00:00
<title>Nested Loops</title>
<para>A nested loop is a loop within a loop, an inner loop within the
body of an outer one. What happens 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
<command>break</command> within either the inner or outer loop may
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
<quote>while</quote> loops, and <xref linkend="ex68"> to see a
<quote>while</quote> loop nested inside an <quote>until</quote>
loop.</para>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Nested Loops -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="loopcontrol">
<title>Loop Control</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="brkcont">
<title><anchor id="brkcont1">Commands Affecting Loop Behavior</title>
2001-07-10 14:25:50 +00:00
<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
2001-10-15 14:21:41 +00:00
linkend="builtinref">builtins</link>,
whereas other loop commands, such as <link
linkend="whileloopref">while</link> and <link
linkend="caseesac1">case</link>, are <link
2001-07-10 14:25:50 +00:00
linkend="keywordref">keywords</link>.</para></footnote>
2001-10-15 14:21:41 +00:00
correspond exactly to their counterparts in other
programming languages. The <command>break</command>
command terminates the loop (breaks out of it), while
<command>continue</command> causes a jump to the next
iteration of the loop, skipping all the remaining commands
in that particular loop cycle.</para>
2001-07-10 14:25:50 +00:00
<example id="ex28">
<title>Effects of <command>break</command> and
<command>continue</command> in a loop</title>
<programlisting>&ex28;</programlisting>
</example>
<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>
<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>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Loop Control Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="testbranch">
2001-07-10 14:25:50 +00:00
<title>Testing and Branching</title>
<para>The <command>case</command> and <command>select</command>
2001-09-04 13:27:31 +00:00
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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="caseesac">
<title><anchor id="caseesac1">Controlling program flow in a code
block</title>
2001-07-10 14:25:50 +00:00
<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 equivalent
of <command>switch</command> 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>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 <command>case</command></title>
<programlisting>&ex29;</programlisting>
</example>
<example id="ex30">
<title>Creating menus using <command>case</command></title>
<programlisting>&ex30;</programlisting>
</example>
<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 65;; # 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>
<example id="casecmd">
<title>Using command substitution to generate the
<command>case</command> variable</title>
<programlisting>&casecmd;</programlisting>
</example>
<para>A <command>case</command> construct can filter strings for
<link linkend="globbingref">globbing</link> patterns.</para>
2001-10-15 14:21:41 +00:00
<example id="matchstring">
<title>Simple string matching</title>
<programlisting>&matchstring;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
<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 that this may be changed.</para>
<example id="ex31">
<title>Creating menus using <command>select</command></title>
<programlisting>&ex31;</programlisting>
</example>
<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 <command>select</command> in a function</title>
<programlisting>&ex32;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<para>See also <xref linkend="resistor">.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Testing and Branching -->
</chapter> <!-- Loops -->
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
<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 <emphasis>built in</emphasis>. This is either
for performance reasons -- builtins execute faster than external
commands, which usually require forking off a separate process
-- or because a particular builtin needs direct access to the
shell internals.</para>
<para><anchor id="forkref"></para>
<sidebar>
<para>When a command or
the shell itself initiates (or
<emphasis>spawns</emphasis>) a new
subprocess to carry out a task, this is called
<emphasis>forking</emphasis>. This new process
is the <quote>child</quote>, and the process
that <emphasis>forked</emphasis> it off is the
<quote>parent</quote>. While the <emphasis>child
process</emphasis> is doing its work, the
<emphasis>parent process</emphasis> is still
executing.</para>
<para>Generally, a Bash <emphasis>builtin</emphasis>
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>
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
</sidebar>
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
<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
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
echo "This line uses the \"echo\" builtin."
/bin/echo "This line uses the /bin/echo system command."</programlisting>
</para>
2001-07-10 14:25:50 +00:00
<para><anchor id="keywordref">A <firstterm>keyword</firstterm>
is a <emphasis>reserved</emphasis> 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, <quote><token>for</token></quote>,
2002-04-01 16:04:17 +00:00
<quote><token>while</token></quote>, <quote>do</quote>, and
2001-07-10 14:25:50 +00:00
<quote><token>!</token></quote> are keywords. Similar to a
2002-04-01 16:04:17 +00:00
<emphasis>builtin</emphasis>, a keyword is hard-coded into Bash,
but unlike a builtin, a keyword is not by itself a command,
but part of a larger command structure.
<footnote><para>An exception to this is the <link
linkend="timref">time</link> command, listed in the official
Bash documentation as a keyword.</para></footnote>
</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="intio">
<title><anchor id="intio1">I/O</title>
2001-07-10 14:25:50 +00:00
<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>
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
<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>
<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>
2002-04-01 16:04:17 +00:00
<para>Be aware that <command>echo `command`</command>
2001-07-10 14:25:50 +00:00
deletes any linefeeds that the output
of <replaceable>command</replaceable>
2002-04-01 16:04:17 +00:00
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>
2001-07-10 14:25:50 +00:00
<para>
<screen>
2002-04-01 16:04:17 +00:00
<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>
2001-07-10 14:25:50 +00:00
2002-04-01 16:04:17 +00:00
<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 362 Nov 7 2000 seconds.au</computeroutput>
2001-07-10 14:25:50 +00:00
</screen>
</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>
2001-10-15 14:21:41 +00:00
<term><anchor id="printfref"><command>printf</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>printf</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>printf</secondary>
</indexterm>
<listitem>
<para>The <command>printf</command>, formatted print, command is an
2002-06-03 14:35:48 +00:00
enhanced <command>echo</command>. It is a limited variant
of the C language <function>printf()</function> library
function, and its syntax is somewhat different.</para>
2001-07-10 14:25:50 +00:00
<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 builtin version
of the <filename>/bin/printf</filename> or
<filename>/usr/bin/printf</filename> command. See the
2001-09-04 13:27:31 +00:00
<command>printf</command> manpage (of the system command)
2001-07-10 14:25:50 +00:00
for in-depth coverage.</para>
2001-09-04 13:27:31 +00:00
<caution><para>Older versions of Bash may not support
<command>printf</command>.</para></caution>
2001-07-10 14:25:50 +00:00
<example id="ex47">
<title><command>printf</command> in action</title>
<programlisting>&ex47;</programlisting>
</example>
<para>Formatting error messages is a useful application of
2001-09-04 13:27:31 +00:00
<command>printf</command></para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>
2001-07-10 14:25:50 +00:00
<programlisting>E_BADDIR=65
var=nonexistent_directory
error()
{
printf "$@" >&2
# Formats positional params passed, and sents them to stderr.
echo
exit $E_BADDIR
}
cd $var || error $"Can't cd to %s." "$var"
# Thanks, S.C.</programlisting>
</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<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 <command>read</command></title>
<programlisting>&ex36;</programlisting>
</example>
2002-06-03 14:35:48 +00:00
<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 <command>read</command> has no
variable</title>
<programlisting>&readnovar;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
<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 <command>read</command></title>
<programlisting>&readr;</programlisting>
</example>
<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>
2002-04-01 16:04:17 +00:00
<para>The <option>-t</option> option to <command>read</command>
permits timed input (see <xref linkend="tout">).</para>
2001-09-04 13:27:31 +00:00
<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 <command>read</command> with
<link linkend="ioredirref">file redirection</link></title>
<programlisting>&readredir;</programlisting>
</example>
2002-06-17 13:17:07 +00:00
<note>
<para><link linkend="piperef">Piping</link> output
to a <command>read</command>, using <link
linkend="echoref">echo</link> to set variables <link
linkend="badread0">will fail</link>.</para>
<para>However, piping the output of <link
linkend="catref">cat</link> does seem to work.
<programlisting>cat file1 file2 |
while read line
do
echo $line
done</programlisting></para>
</note>
2002-06-03 14:35:48 +00:00
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
</variablelist>
<variablelist id="intfilesystem">
<title><anchor id="intfilesystem1">Filesystem</title>
<varlistentry>
<term><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>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="pwd2ref"><command>pwd</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>pwd</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>pwd</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>$PWD</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>variable</primary>
2001-09-04 13:27:31 +00:00
<secondary>$PWD</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>directory</primary>
<secondary>working</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2002-04-01 16:04:17 +00:00
<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>
2001-09-04 13:27:31 +00:00
<para><command>dirs</command> lists the contents of the directory
2002-04-01 16:04:17 +00:00
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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<example id="ex37">
<title>Changing the current working directory </title>
<programlisting>&ex37;</programlisting>
2001-07-10 14:25:50 +00:00
</example>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="intvar">
<title><anchor id="intvar1">Variables</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="letref"><command>let</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>let</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>let</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<example id="ex46">
<title>Letting <command>let</command> do some arithmetic.</title>
<programlisting>&ex46;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="evalref"><command>eval</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>eval</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>eval</secondary>
</indexterm>
<listitem>
2001-10-15 14:21:41 +00:00
<para><userinput>eval arg1 [arg2] ... [argN]</userinput></para>
2001-07-10 14:25:50 +00:00
<para>Translates into commands the arguments in a list
(useful for code generation within a script).</para>
<example id="ex43">
<title>Showing the effect of <command>eval</command></title>
<programlisting>&ex43;</programlisting>
</example>
<example id="ex44">
<title>Forcing a log-off</title>
<programlisting>&ex44;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<example id="rot14">
2001-09-04 13:27:31 +00:00
<title>A version of <quote>rot13</quote></title>
2002-04-01 16:04:17 +00:00
<programlisting>&rot14;</programlisting>
2001-09-04 13:27:31 +00:00
</example>
<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>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><anchor id="setref"><command>set</command></term>
<indexterm>
<primary>set</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>set</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<listitem><para>The <command>set</command> command changes
the value of internal script variables. One use for
this is to toggle <link linkend="optionsref">option
2001-07-10 14:25:50 +00:00
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 <command>set</command> with positional
2002-06-03 14:35:48 +00:00
parameters</title>
<programlisting>&ex34;</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.
<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. When no variable follows the
<option>--</option>, it <emphasis>unsets</emphasis>
the positional parameters.</para>
<example id="setpos">
<title>Reassigning the positional parameters</title>
<programlisting>&setpos;</programlisting>
2001-07-10 14:25:50 +00:00
</example>
2002-06-03 14:35:48 +00:00
<para>See also <xref linkend="ex22a"> and <xref linkend="ex33a">.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="unsetref"><command>unset</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>unset</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>unset</secondary>
</indexterm>
<listitem><para>The <command>unset</command> command deletes a
2001-10-15 14:21:41 +00:00
shell variable, effectively setting it to
<emphasis>null</emphasis>. Note that this command does
not affect positional parameters.</para>
2001-07-10 14:25:50 +00:00
<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>The <command>export</command> command makes
available variables to all child processes of the
running script or shell. Unfortunately, there is no way
to <command>export</command> variables back to the parent
process, to the process that called or invoked the script
or shell. One important use of <command>export</command>
2002-06-03 14:35:48 +00:00
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>
2001-07-10 14:25:50 +00:00
<example id="coltotaler3">
<title>Using <command>export</command> to pass a variable to an
embedded <link linkend="awkref">awk</link> 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></tip>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><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>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><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 C language
<command>const</command> type qualifier.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<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>
2002-06-03 14:35:48 +00:00
<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 <command>getopt</command> library function familiar
to C programmers. It permits passing and concatenating
multiple options
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<footnote><para>A option 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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
and associated arguments to a script (for
example <userinput>scriptname -abc -e
/usr/local</userinput>).</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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 decrements the implicit
<varname>$OPTIND</varname> variable to step to the
next.</para>
<note>
<para>
<orderedlist>
<listitem>
2002-06-17 13:17:07 +00:00
<para>The arguments passed from the command line to
the script must be preceded by a
minus (<option>-</option>) or a plus
2001-09-04 13:27:31 +00:00
(<option>+</option>). It is the prefixed
<option>-</option> or <option>+</option> that lets
<command>getopts</command> recognize command-line
arguments as <emphasis>options</emphasis>.
In fact, <command>getopts</command> will not process
arguments without the prefixed <option>-</option>
or <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 <command>while</command>
loop, in that it lacks condition brackets.</para>
</listitem>
<listitem>
2002-06-03 14:35:48 +00:00
<para>The <command>getopts</command> construct replaces
the obsolete and less powerful <link
linkend="getopty">getopt</link> external
command.</para>
2001-09-04 13:27:31 +00:00
</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 <command>getopts</command> 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>. This is the
shell scripting equivalent of a C/C++ <userinput>#include</userinput>
directive. It 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>
</listitem>
</varlistentry>
<varlistentry>
<term><command>exit</command></term>
<indexterm>
<primary>exit</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>exit</secondary>
</indexterm>
<listitem>
<para>Unconditionally terminates a script. 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 a 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>.</para></note>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><anchor id="execref"><command>exec</command></term>
<indexterm>
<primary>exec</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>exec</secondary>
</indexterm>
<listitem>
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
<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
2001-09-04 13:27:31 +00:00
<command>exec</command> builtin, the shell does not fork,
and the command exec'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. For this
reason, if an <command>exec</command> appears in a script,
it would probably be the final command.</para>
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
<example id="ex54">
<title>Effects of <command>exec</command></title>
<programlisting>&ex54;</programlisting>
</example>
<example id="selfexec">
<title>A script that <command>exec's</command> itself</title>
<programlisting>&selfexec;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
<para>An <command>exec</command> also serves to reassign <link
linkend="fdref">file descriptors</link>. <userinput>exec
&lt;zzz-file</userinput> replaces <filename>stdin</filename>
with the file <filename>zzz-file</filename> (see <xref
linkend="redir1">).</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>shopt</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>shopt</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>shopt</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>This command permits changing shell options on the fly (see
<xref linkend="al"> and <xref linkend="unal">). It often
2002-06-03 14:35:48 +00:00
appears in the Bash <link linkend="filesref1">startup
2001-09-04 13:27:31 +00:00
files</link>, but also has its uses in scripts. Needs
<link linkend="bash2ref">version 2</link> or later of Bash.
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<programlisting>shopt -s cdspell
# Allows minor misspelling directory names with 'cd'
command.</programlisting></para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="intcommand">
<title><anchor id="intcommand1">Commands</title>
2001-07-10 14:25:50 +00:00
<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><programlisting># Endless loop
while true # alias for ":"
do
operation-1
operation-2
...
operation-n
# Need a way to break out of loop.
done</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
<term><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><programlisting># 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><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> gives the full pathname to
<quote>cmd</quote>. Unlike <command>which</command>,
<command>type</command> is a Bash builtin. The useful
<option>-a</option> option to <command>type</command>
2002-06-17 13:17:07 +00:00
identifies <replaceable>keywords</replaceable>
2001-07-10 14:25:50 +00:00
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>
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>hash [cmds]</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>hash</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<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), 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>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>help</command></term>
<indexterm>
<primary>help</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary></secondary>
</indexterm>
<listitem>
<para><command>help</command> COMMAND looks up
a short usage summary of the shell builtin COMMAND. 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>
2001-09-04 13:27:31 +00:00
<sect1>
2001-07-10 14:25:50 +00:00
<title>Job Control Commands</title>
2001-09-04 13:27:31 +00:00
<para>Certain of the following job control commands take a
<quote>job identifier</quote> as an argument. See the <link
linkend="jobidtable">table</link> at end of the chapter.</para>
<variablelist id="jccommandlist">
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><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 job number.
Not as useful as <command>ps</command>.</para>
<note>
<para>It is all too easy to confuse
<emphasis>jobs</emphasis> and
<emphasis>processes</emphasis>. 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 <command>fg</command>,
<command>bg</command> 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), and <quote>1384</quote>
is the process number (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><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>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><command>fg</command></term>
<term><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>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><anchor id="waitref"><command>wait</command></term>
<indexterm>
<primary>wait</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>wait</secondary>
</indexterm>
<listitem>
<para>Stop 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
orphan process).</para>
<example id="ex39">
<title>Waiting for a process to finish before proceeding</title>
<programlisting>&ex39;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
<para>Optionally, <command>wait</command> can take a job
identifier as an argument, for example,
<command>wait%1</command> or <command>wait
$PPID</command>. See the <link linkend="jobidtable">job
id table</link>.</para>
2001-10-15 14:21:41 +00:00
<para><anchor id="waithang"></para>
<tip>
<para>Within a script, running a command in the background
2002-01-07 15:24:19 +00:00
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.
2001-10-15 14:21:41 +00:00
<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>
<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>
2002-01-07 15:24:19 +00:00
<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.
2001-10-15 14:21:41 +00:00
</para>
</tip>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><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>
2001-09-04 13:27:31 +00:00
<term><command>logout</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>logout</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>log out</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Exit a login shell, optionally specifying an <link
linkend="exitstatusref">exit status</link>.</para>
2001-07-10 14:25:50 +00:00
</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 used in executing commands, in the
following form:
<screen><computeroutput>0m0.020s 0m0.020s</computeroutput></screen>
This capability is of very limited value, since it is uncommon 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 <emphasis>terminate</emphasis> signal (see <xref
linkend="killprocess">).</para>
2002-06-03 14:35:48 +00:00
<example id="selfdestruct">
<title>A script that kills itself</title>
<programlisting>&selfdestruct;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
<note><para><userinput>kill -l</userinput> lists all the
<link linkend="signald">signals</link>. A <userinput>kill
-9</userinput> is a <quote>sure kill</quote>, 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 <quote>zombie
process</quote>, that is, a process whose <link
linkend="forkref">parent</link> has terminated, cannot be
killed (you can't kill something that is already dead),
but <command>init</command> will usually clean it up
sooner or later.</para></note>
</listitem>
</varlistentry>
<varlistentry>
<term><command>command</command></term>
<indexterm>
<primary>command</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>command</secondary>
</indexterm>
<listitem><para>The <command>command COMMAND</command> directive
disables aliases and functions for the command
<quote>COMMAND</quote>.</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
<quote>BUILTIN_COMMAND</quote> 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>
2001-09-04 13:27:31 +00:00
<listitem>
<para>This either enables or disables a shell
2001-07-10 14:25:50 +00:00
builtin command. As an example, <command>enable -n
kill</command> disables the shell builtin <link
linkend="killref">kill</link>, so that when Bash
subsequently encounters <command>kill</command>, it invokes
2001-09-04 13:27:31 +00:00
<filename>/bin/kill</filename>.</para>
<para><anchor id="enableref1">The <option>-a</option>
option to <command>enable</command> lists all the
shell builtins, indicating whether or not they
are enabled. The <option>-f filename</option>
option lets <command>enable</command> load a <link
linkend="builtinref">builtin</link> as a shared library
(DLL) module from a properly compiled object file.
2001-10-15 14:21:41 +00:00
<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>.
2001-09-04 13:27:31 +00:00
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><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
<emphasis>ksh</emphasis> autoloader. With
<command>autoload</command> in place, a function with
an <quote>autoload</quote> 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 <command>autoload</command> is not a part of the
core Bash installation. It needs to be loaded in with
<command>enable -f</command> (see above).</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
<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 -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- Internal Commands and Builtins -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="external">
2001-07-10 14:25:50 +00:00
<title>External Filters, Programs and Commands</title>
2001-09-04 13:27:31 +00:00
<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">
2001-07-10 14:25:50 +00:00
<title>Basic Commands</title>
2001-09-04 13:27:31 +00:00
<variablelist id="basiccommands">
2002-06-17 13:17:07 +00:00
<title><anchor id="basiccommands1">The first commands a novice learns</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="lsref"><command>ls</command></term>
2001-07-10 14:25:50 +00:00
<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
2001-09-04 13:27:31 +00:00
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 interesting options are
2001-10-15 14:21:41 +00:00
<option>-S</option>, sort listing by file size,
<option>-t</option>, sort by file modification time, and
<option>-i</option>, show file inodes (see <xref
linkend="idelete">).</para>
2001-07-10 14:25:50 +00:00
<example id="ex40">
<title>Using <command>ls</command> to create a table of contents
for burning a <abbrev>CDR</abbrev> disk</title>
<programlisting>&ex40;</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="catref"><command>cat</command></term>
2001-07-10 14:25:50 +00:00
<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.
<programlisting>cat filename cat file.1 file.2 file.3 &gt; file.123</programlisting>
2002-04-01 16:04:17 +00:00
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>
2001-07-10 14:25:50 +00:00
<para>See also <xref linkend="lnum"> and <xref linkend="rot13">.</para>
<para><command>tac</command>, is the inverse of
<wordasword>cat</wordasword>, listing a file backwards from its end.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><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 is not the same effect
as <command>tac</command>, as it preserves the order of
the lines, but flips each one around.</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><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)
and the <option>-r</option> and <option>-R</option>
recursive flags.</para></tip>
</listitem>
</varlistentry>
<varlistentry>
<term><command>mv</command></term>
<listitem>
2001-10-15 14:21:41 +00:00
<para>This is the file <emphasis>move</emphasis> 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>
2002-04-01 16:04:17 +00:00
2002-06-03 14:35:48 +00:00
<note>
<para>When used in a non-interactive script,
2002-04-01 16:04:17 +00:00
<command>mv</command> takes the <option>-f</option>
(<emphasis>force</emphasis>) option to bypass user
2002-06-03 14:35:48 +00:00
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>
2002-04-01 16:04:17 +00:00
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><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>
2002-04-01 16:04:17 +00:00
option forces removal of even readonly files, and is useful
for bypassing user input in a script.</para>
2001-07-10 14:25:50 +00:00
<warning><para>When used with the recursive flag
<option>-r</option>, this command removes files all the way
down the directory tree.</para></warning>
</listitem>
</varlistentry>
<varlistentry>
<term><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 <anchor id="dotfilesref"> invisible
<quote>dotfiles</quote>,
<footnote><para>These are files whose names begin with
a dot, such as <filename>~/.Xdefaults</filename>. Such
filenames do not show up in a normal
<command>ls</command> listing, 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><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.
<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 (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).</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.</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>chattr</command></term>
<indexterm>
<primary>chattr</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>chattr</secondary>
</indexterm>
<listitem>
<para>Change file attributes. This has the same effect
as <command>chmod</command> above, but with a
different invocation syntax, and it works only on an
<emphasis>ext2</emphasis> filesystem.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>ln</command></term>
<listitem>
<para>Creates links to pre-existings files. Most often used
with the <option>-s</option>, symbolic or
<quote>soft</quote> link flag. This permits referencing
the linked file by more than one name and is a superior
alternative to aliasing (see <xref linkend="ex18">).</para>
<para><userinput>ln -s oldfile newfile</userinput>
links the previously existing
<filename>oldfile</filename> to the newly created link,
<filename>newfile</filename>.</para>
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- End Basic Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="moreadv">
2001-07-10 14:25:50 +00:00
<title>Complex Commands</title>
2001-09-04 13:27:31 +00:00
<variablelist id="cclisting">
2002-06-17 13:17:07 +00:00
<title><anchor id="cclisting1">Commands for more advanced users</title>
2001-07-10 14:25:50 +00:00
<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>-exec <replaceable>COMMAND</replaceable> \;</para>
<para>Carries out <replaceable>COMMAND</replaceable> on
each file that <command>find</command> scores a hit
on. <replaceable>COMMAND</replaceable> terminates
with <token>\;</token> (the <token>;</token>
is escaped to make certain the shell passes it to
<command>find</command> literally, which concludes the
command sequence). If <replaceable>COMMAND</replaceable>
contains <token>{}</token>, then <command>find</command>
substitutes the full path name of the selected file.</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>
<programlisting>find /home/bozo/projects -mtime 1
# Lists all files in /home/bozo/projects directory tree
# that were modified within the last day.</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 - how can they be filtered out?
# Perhaps by:
find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
| grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'
2001-09-04 13:27:31 +00:00
# [:digit:] is one of the character classes
# introduced with the POSIX 1003.2 standard.
2001-07-10 14:25:50 +00:00
# Thanks, S.C.
</programlisting></para>
<caution><para>The <option>-exec</option> option to
<command>find</command> should not be confused with the <link
linkend="execref">exec</link> shell builtin.</para></caution>
<example id="ex57">
<title><command>Badname</command>, eliminate file names
in current directory containing bad characters and <link
linkend="whitespaceref">whitespace</link>.</title>
<programlisting>&ex57;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<example id="idelete">
<title>Deleting a file by its <emphasis>inode</emphasis>
number</title>
<programlisting>&idelete;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
<para>See <xref linkend="ex48">, <xref linkend="ex58">,
and <xref linkend="findstring"> for scripts using
2001-09-04 13:27:31 +00:00
<command>find</command>. Its manpage provides more detail
2001-07-10 14:25:50 +00:00
on this complex and powerful command.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>xargs</command></term>
<indexterm>
<primary>xargs</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>xargs</secondary>
</indexterm>
<listitem>
2002-04-01 16:04:17 +00:00
<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 backquotes. In situations where backquotes
fail with a <errorname>too many arguments</errorname>
2001-07-10 14:25:50 +00:00
error, substituting <command>xargs</command> often
works. 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>
2002-04-01 16:04:17 +00:00
2001-07-10 14:25:50 +00:00
<para>The default command for <command>xargs</command> is
2002-04-01 16:04:17 +00:00
<link linkend="echoref">echo</link>. This means that input
piped to <command>xargs</command> may have linefeeds and
other whitespace characters stripped out.
<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 29 23:58 file2</computeroutput>
</screen>
</para>
2001-07-10 14:25:50 +00:00
<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>
<tip>
<para>An interesting <command>xargs</command>
2001-10-15 14:21:41 +00:00
option is <option>-n <replaceable>NN</replaceable></option>,
which limits to <replaceable>NN</replaceable> the number
of arguments passed.</para>
2001-07-10 14:25:50 +00:00
<para><userinput>ls | xargs -n 8 echo</userinput> lists the files in the
current directory in <literal>8</literal> columns.</para>
</tip>
<tip>
<para>Another useful option is
<option>-0</option>, in combination with <command>find
-print0</command> or <command>grep -lZ</command>. 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>
</tip>
<example id="ex41">
2001-10-15 14:21:41 +00:00
<title>Logfile using <command>xargs</command> to monitor system log</title>
2001-07-10 14:25:50 +00:00
<programlisting>&ex41;</programlisting>
</example>
<example id="ex42">
<title><command>copydir</command>, copying files in current
directory to another, using <command>xargs</command></title>
<programlisting>&ex42;</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="exprref"><userinput>expr</userinput></term>
2001-07-10 14:25:50 +00:00
<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>
2002-04-01 16:04:17 +00:00
<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>
2001-07-10 14:25:50 +00:00
<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
2002-06-17 13:17:07 +00:00
<userinput>y=$(($y+1))</userinput>. This is an
2001-07-10 14:25:50 +00:00
example of <link linkend="arithexpref">arithmetic
expansion</link>.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="expextrsub"><userinput>z=`expr substr
$string $position $length`</userinput></term>
2001-07-10 14:25:50 +00:00
<listitem>
2001-10-15 14:21:41 +00:00
<para>Extract substring of $length characters, starting
at $position.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
</variablelist>
<example id="ex45">
<title>Using <command>expr</command></title>
<programlisting>&ex45;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
<important>
<para>The <link linkend="nullref">:</link> operator
can substitute for <command>match</command>. For example,
2001-07-10 14:25:50 +00:00
<userinput>b=`expr $a : [0-9]*`</userinput> is the
exact equivalent of <userinput>b=`expr match $a
2001-09-04 13:27:31 +00:00
[0-9]*`</userinput> in the above listing.</para>
2002-06-03 14:35:48 +00:00
2001-09-04 13:27:31 +00:00
<para><programlisting>&ex45a;</programlisting></para>
</important>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
</variablelist>
2001-10-15 14:21:41 +00:00
2002-06-03 14:35:48 +00:00
<note>
<para>The above example illustrates how
<command>expr</command> uses the <emphasis>escaped
parentheses -- \( ... \) --</emphasis> grouping operator
in tandem with <link linkend="regexref">regular
expression</link> parsing to match a substring.</para>
</note>
<para><link linkend="perlref">Perl</link> and
<link linkend="sedref">sed</link> have far superior string
parsing facilities. A short <command>Perl</command> or
<command>sed</command> <quote>subroutine</quote> within
a script (see <xref linkend="wrapper">) is an attractive
alternative to using <command>expr</command>.</para>
2001-10-15 14:21:41 +00:00
2002-06-03 14:35:48 +00:00
<para>See <xref linkend="String-Manipulation"> for more on
string operations.</para>
2001-10-15 14:21:41 +00:00
</sect1> <!-- End Complex Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="timedate">
2001-07-10 14:25:50 +00:00
<title>Time / Date Commands</title>
2001-09-04 13:27:31 +00:00
<variablelist id="tdlisting">
2002-06-17 13:17:07 +00:00
<title><anchor id="tdlisting1">Manipulating the time and date</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="dateref"><command>date</command></term>
2001-07-10 14:25:50 +00:00
<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 <command>date</command></title>
<programlisting>&ex51;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<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>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>zdump</command></term>
<indexterm>
<primary>zdump</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>time zone dump</secondary>
</indexterm>
<listitem>
<para>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>
2001-07-10 14:25:50 +00:00
<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 very verbose timing statistics for executing a command.</para>
<para><userinput>time ls -l /</userinput> gives something like this:
<screen><computeroutput>0.00user 0.01system 0:00.05elapsed 16%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (149major+27minor)pagefaults 0swaps</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>
2002-06-03 14:35:48 +00:00
<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>
2001-07-10 14:25:50 +00:00
</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>
2001-10-15 14:21:41 +00:00
<primary>crond</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-10-15 14:21:41 +00:00
<secondary>crond</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-10-15 14:21:41 +00:00
<para>The <command>at</command> job control command executes
a given set of commands at a specified time. Superficially,
it resembles <link linkend="cronref">crond</link>, however,
<command>at</command> is chiefly useful for one-time execution
of a command set.</para>
2001-07-10 14:25:50 +00:00
<para><userinput>at 2pm January 15</userinput> prompts for a set of
2001-10-15 14:21:41 +00:00
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>
2001-07-10 14:25:50 +00:00
<para>Using either the <option>-f</option> option or input
redirection (<token><</token>), <command>at</command>
2001-10-15 14:21:41 +00:00
reads a command list from a file. This file is an
executable shell script, though it should, of course,
2001-09-04 13:27:31 +00:00
be noninteractive. Particularly clever is including the
<link linkend="runpartsref">run-parts</link> command in
2001-10-15 14:21:41 +00:00
the file to execute a different set of scripts.</para>
2001-07-10 14:25:50 +00:00
<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><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>
</listitem>
</varlistentry>
<varlistentry>
<term><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><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 wait loop. It pauses for a
specified number of seconds, doing nothing. This can be useful for
timing or in processes running in the background, checking for a
specific event every so often (see <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>
</listitem>
</varlistentry>
<varlistentry>
<term><command>usleep</command></term>
<indexterm>
<primary>usleep</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>usleep</secondary>
</indexterm>
<listitem>
<para><emphasis>Microsleep</emphasis> (the <quote>u</quote>
may be read as the Greek <quote>mu</quote>, or micro
prefix). This is the same as <command>sleep</command>,
above, but <quote>sleeps</quote> in microsecond
intervals. This can be used for fine-grain timing, or for
polling an ongoing process at very frequent intervals.
<programlisting>usleep 30
# Pauses 30 microseconds.</programlisting>
</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><command>hwclock</command></term>
<term><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 root 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>
2001-09-04 13:27:31 +00:00
</sect1> <!-- End Time / Date Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="textproc">
2001-07-10 14:25:50 +00:00
<title>Text Processing Commands</title>
2001-09-04 13:27:31 +00:00
<variablelist id="tpcommandlisting">
2002-06-17 13:17:07 +00:00
<title><anchor id="tpcommandlisting1">Commands affecting text and
text files</title>
2001-07-10 14:25:50 +00:00
<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 sorter, often used as a filter in a pipe. This
2001-10-15 14:21:41 +00:00
command sorts a text stream 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 <emphasis>info page</emphasis> lists its many
2002-06-03 14:35:48 +00:00
capabilities and options. See <xref linkend="findstring">,
<xref linkend="symlinks">, and <xref linkend="makedict">.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><command>tsort</command></term>
<indexterm>
<primary>tsort</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>topological sort</secondary>
</indexterm>
<listitem>
<para>Topological sort, reading in pairs of
whitespace-separated strings and sorting according to
input patterns.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<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>.
<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
2002-01-07 15:24:19 +00:00
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 <emphasis>frequency
of occurrence</emphasis> 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>
2001-07-10 14:25:50 +00:00
</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 pipe.</para>
<para>The <command>unexpand</command> filter
converts spaces to tabs. This reverses the effect of
<command>expand</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="cutref"><command>cut</command></term>
2001-07-10 14:25:50 +00:00
<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 <command>cut</command> in a script than
<command>awk</command>. 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>cat /etc/mtab | cut -d ' ' -f1,2</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>
2002-01-07 15:24:19 +00:00
<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>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<para><userinput>cut -d ' ' -f2,3 filename</userinput> is equivalent to
<userinput>awk -F'[ ]' '{ print $2, $3 }' filename</userinput></para>
<para>See also <xref linkend="base">.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><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
<command>cut</command>, useful for creating system log
files.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><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><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 this can be changed). It
has a number of interesting options.
2002-06-17 13:17:07 +00:00
<example id="scriptdetector">
<title>Which files are scripts?</title>
<programlisting>&scriptdetector;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
<example id="rnd">
<title>Generating 10-digit random numbers</title>
<programlisting>&rnd;</programlisting>
</example>
See also <xref linkend="ex52">.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>tail</command></term>
<indexterm>
<primary>tail</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>tail</secondary>
</indexterm>
<listitem>
<para>lists the end of a file to <filename>stdout</filename>
(the default is <literal>10</literal> lines). 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 <command>tail</command> to monitor the system log</title>
<programlisting>&ex12;</programlisting>
</example>
<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
2001-10-15 14:21:41 +00:00
<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>, that is, <emphasis>global -
2001-07-10 14:25:50 +00:00
regular expression - print</emphasis>.</para>
<para><cmdsynopsis>
<command>grep</command> <arg
choice="plain"><replaceable>pattern</replaceable></arg>
<arg choice="opt"
rep="repeat"><replaceable>file</replaceable></arg>
2001-10-15 14:21:41 +00:00
</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>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<para>The <option>-i</option> option causes a case-insensitive
search.</para>
2002-04-01 16:04:17 +00:00
<para>The <option>-w</option> option matches only whole
words.</para>
2001-07-10 14:25:50 +00:00
<para>The <option>-l</option> option lists only the files in which
matches were found, but not the matching lines.</para>
2002-04-01 16:04:17 +00:00
<para>The <option>-r</option> (recursive) option searches files in
the current working directory and all subdirectories below
it.</para>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<para>The <option>-v</option> (or <option>--invert-match</option>)
option <emphasis>filters out</emphasis> 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 . # 4
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>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<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
2002-01-07 15:24:19 +00:00
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 ]
then
echo "$word found in $filename"
else
echo "$word not found in $filename"
fi</programlisting>
</para>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<para><xref linkend="online"> demonstrates how to use
<command>grep</command> to search for a word pattern in
a system logfile.</para>
2001-07-10 14:25:50 +00:00
<example id="grp">
<title>Emulating <quote>grep</quote> in a script</title>
<programlisting>&grp;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<note>
<para><anchor id="egrepref"><command>egrep</command>
2001-09-04 13:27:31 +00:00
is the same as <command>grep -E</command>. This
uses a somewhat different, extended set of <link
linkend="regexref">regular expressions</link>, which can
2001-10-15 14:21:41 +00:00
make the search somewhat more flexible.</para>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<para><command>fgrep</command> is the same as <command>grep
2001-07-10 14:25:50 +00:00
-F</command>. It does a literal string search (no regular
2001-10-15 14:21:41 +00:00
expressions), which allegedly speeds things up a
bit.</para>
<para><command>agrep</command> 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>
</note>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<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>To search <link linkend="bzipref">bzipped</link>
files, use <command>bzgrep</command>.</para> </tip>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><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 batch 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><command>wc</command></term>
<indexterm>
<primary>wc</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>wc</secondary>
</indexterm>
<listitem>
<para><emphasis>wc</emphasis> gives a <quote>word count</quote> on a file or I/O stream:
<screen><prompt>bash $ </prompt><userinput>wc /usr/doc/sed-3.02/README</userinput>
<computeroutput>20 127 838 /usr/doc/sed-3.02/README</computeroutput>
[20 lines 127 words 838 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 character count.</para>
<para><userinput>wc -L</userinput> gives only the length of the longest line.</para>
2001-09-04 13:27:31 +00:00
<para>Using <command>wc</command> to count how many
2001-07-10 14:25:50 +00:00
<emphasis>.txt</emphasis> files are in current working directory:
<programlisting>$ ls *.txt | wc -l
# Will work as long as none of the "*.txt" files have a linefeed 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>
2001-09-04 13:27:31 +00:00
<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>
2001-10-15 14:21:41 +00:00
<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>
2001-07-10 14:25:50 +00:00
<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>
2001-10-15 14:21:41 +00:00
<term><anchor id="trref"><command>tr</command></term>
2001-07-10 14:25:50 +00:00
<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>The <option>-d</option> option deletes a range of
characters.
2002-04-01 16:04:17 +00:00
<programlisting>echo "abcdef" # abcdef
echo "abcdef" | tr -d b-d # aef
tr -d 0-9 &lt;filename
2001-07-10 14:25:50 +00:00
# Deletes all digits from the file "filename".</programlisting></para>
2002-04-01 16:04:17 +00:00
<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>.
2001-07-10 14:25:50 +00:00
<screen><prompt>bash$ </prompt><userinput>echo "XXXXX" | tr --squeeze-repeats 'X'</userinput>
<computeroutput>X</computeroutput></screen></para>
2002-04-01 16:04:17 +00:00
<para>The <option>-c</option> <quote>complement</quote>
option <emphasis>inverts</emphasis> 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
2002-06-03 14:35:48 +00:00
linkend="posixref">POSIX character classes</link>.
<footnote><para>This is only true of the GNU version of
<command>tr</command>, not the generic version often found on
commercial UNIX systems.</para></footnote>
</para>
2002-04-01 16:04:17 +00:00
<para>
<screen><prompt>bash$ </prompt><userinput>echo "abcd2ef1" | tr '[:alpha:]' -</userinput>
<computeroutput>----2--1</computeroutput>
</screen>
</para>
2001-07-10 14:25:50 +00:00
<example id="ex49">
<title><command>toupper</command>: Transforms a file to all uppercase.</title>
<programlisting>&ex49;</programlisting>
</example>
<example id="lowercase">
<title><command>lowercase</command>: Changes all filenames in working directory to lowercase.</title>
<programlisting>&lowercase;</programlisting>
</example>
<example id="du">
<title><command>du</command>: DOS to UNIX text file conversion.</title>
<programlisting>&du;</programlisting>
</example>
<example id="rot13">
<title><command>rot13</command>: rot13, ultra-weak encryption.</title>
<programlisting>&rot13;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
<example id="cryptoquote">
<title>Generating <quote>Crypto-Quote</quote> Puzzles</title>
<programlisting>&cryptoquote;</programlisting>
2002-04-01 16:04:17 +00:00
</example>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<sidebar><title><command>tr</command> variants</title>
<para>
The <command>tr</command> utility has two historic
variants. The BSD version does not use brackets
(<userinput>tr a-z A-Z</userinput>), but the SysV one does
(<userinput>tr '[a-z]' '[A-Z]'</userinput>). The GNU version
of <command>tr</command> resembles the BSD one, so quoting
letter ranges within brackets is mandatory.
</para>
</sidebar>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="foldref"><command>fold</command></term>
<indexterm>
<primary>fold</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>fold</secondary>
</indexterm>
<listitem>
<para>A filter that wraps lines of input to a specified width.
This is especially useful with the <option>-s</option>
option, which breaks lines at word spaces (see <xref
linkend="ex50"> and <xref linkend="mailformat">).</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>fmt</command></term>
<indexterm>
<primary>fmt</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>fmt</secondary>
</indexterm>
<listitem>
<para>Simple-minded file formatter, used as a filter in a
pipe to <quote>wrap</quote> long lines of text
output.</para>
<example id="ex50">
<title>Formatted file listing.</title>
<programlisting>&ex50;</programlisting>
</example>
<para>See also <xref linkend="ex41">.</para>
<tip><para>A powerful alternative to <command>fmt</command> is
Kamil Toman's <command>par</command>
utility, available from <ulink
url="http://www.cs.berkeley.edu/~amc/Par/">http://www.cs.berkeley.edu/~amc/Par/</ulink>.
</para></tip>
</listitem>
</varlistentry>
2002-04-01 16:04:17 +00:00
<varlistentry>
<term><command>col</command></term>
<indexterm>
<primary>col</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>reverse line feed</secondary>
</indexterm>
<listitem>
<para>This deceptively named filter removes reverse line feeds
from an input stream. It also attempts to replace
whitespace with equivalent tabs. The chief use of
<command>col</command> is in filtering the output
from certain text processing utilities, such as
<command>groff</command> and <command>tbl</command>.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>column</command></term>
<indexterm>
<primary>column</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>column</secondary>
</indexterm>
<listitem>
<para>Column formatter. This filter transforms list-type
text output into a <quote>pretty-printed</quote> table
by inserting tabs at appropriate places.</para>
<example id="col">
<title>Using <command>column</command> to format a directory
listing</title>
2002-04-01 16:04:17 +00:00
<programlisting>&colm;</programlisting>
2001-07-10 14:25:50 +00:00
</example>
</listitem>
</varlistentry>
2002-04-01 16:04:17 +00:00
<varlistentry>
<term><command>colrm</command></term>
<indexterm>
<primary>colrm</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>colrm</secondary>
</indexterm>
<listitem>
<para>Column removal filter. This removes columns (characters)
from a file and writes the file, lacking the range of
specified columns, back to <filename>stdout</filename>.
<userinput>colrm 2 4 &lt;filename</userinput> removes the
second through fourth characters from each line of the
text file <filename>filename</filename>.</para>
<warning><para>If the file contains tabs or nonprintable
characters, this may cause unpredictable
behavior. In such cases, consider using
<link linkend="expandref">expand</link> and
<command>unexpand</command> in a pipe preceding
<command>colrm</command>.</para></warning>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>nl</command></term>
<indexterm>
<primary>nl</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>fmt</secondary>
</indexterm>
<listitem>
<para>Line numbering filter. <userinput>nl filename</userinput>
lists <filename>filename</filename> to
<filename>stdout</filename>, but inserts consecutive
numbers at the beginning of each non-blank line. If
<filename>filename</filename> omitted, operates on
<filename>stdin.</filename></para>
2002-04-01 16:04:17 +00:00
<para>The output of <command>nl</command> is very similar to
<userinput>cat -n</userinput>, however, by default
<command>nl</command> does not list blank lines.</para>
2001-07-10 14:25:50 +00:00
<example id="lnum">
<title><command>nl</command>: A self-numbering script.</title>
<programlisting>&lnum;</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
<term><command>pr</command></term>
<indexterm>
<primary>pr</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>pr</secondary>
</indexterm>
<listitem>
<para>Print formatting filter. This will paginate files
(or <filename>stdout</filename>) into sections suitable for
hard copy printing or viewing on screen. Various options
permit row and column manipulation, joining lines, setting
margins, numbering lines, adding page headers, and merging
files, among other things. The <command>pr</command>
command combines much of the functionality of
<command>nl</command>, <command>paste</command>,
<command>fold</command>, <command>column</command>, and
<command>expand</command>.</para>
<para><userinput>pr -o 5 --width=65 fileZZZ | more</userinput>
gives a nice paginated listing to screen of
<filename>fileZZZ</filename> with margins set at 5 and
65.</para>
<para>A particularly useful option is <option>-d</option>,
forcing double-spacing (same effect as <command>sed
-G</command>).</para>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="gettextref"><command>gettext</command></term>
<indexterm>
<primary>gettext</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>gettext</secondary>
</indexterm>
<listitem>
<para>A GNU utility for <link
linkend="localization">localization</link> and
translating the text output of programs into
foreign languages. While primarily intended for C
programs, <command>gettext</command> also finds
use in shell scripts. See the <replaceable>info
page</replaceable>.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><command>iconv</command></term>
<indexterm>
<primary>iconv</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>encoding</secondary>
</indexterm>
<listitem>
<para>A utility for converting file(s) to a different encoding
(character set). Its chief use is for localization.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>recode</command></term>
<indexterm>
<primary>recode</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>encoding</secondary>
</indexterm>
<listitem>
<para>Consider this a fancier version of
<command>iconv</command>, above. This very versatile utility
for converting a file to a different encoding is not part
of the standard Linux installation.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><command>TeX</command></term>
2002-04-01 16:04:17 +00:00
<term><command>gs</command></term>
2001-09-04 13:27:31 +00:00
<indexterm>
2002-04-01 16:04:17 +00:00
<primary>TeX</primary>
2001-09-04 13:27:31 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2002-04-01 16:04:17 +00:00
<secondary>TeX</secondary>
2001-09-04 13:27:31 +00:00
</indexterm>
<indexterm>
<primary>gs</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>Postscript</secondary>
</indexterm>
2002-04-01 16:04:17 +00:00
<listitem>
<para><command>TeX</command> and <command>Postscript</command>
are text markup languages used for preparing copy for
printing or formatted video display.</para>
<para><command>TeX</command> is Donald Knuth's elaborate
typsetting system. It is often convenient to write a
shell script encapsulating all the options and arguments
passed to one of these markup languages.</para>
<para><emphasis>Ghostscript</emphasis>
(<command>gs</command>) is a GPL-ed Postscript
interpreter.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>groff</command></term>
<term><command>tbl</command></term>
<term><command>eqn</command></term>
2001-09-04 13:27:31 +00:00
<indexterm>
2002-04-01 16:04:17 +00:00
<primary>groff</primary>
2001-09-04 13:27:31 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2002-04-01 16:04:17 +00:00
<secondary>groff</secondary>
</indexterm>
<indexterm>
<primary>tbl</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>table</secondary>
</indexterm>
<indexterm>
<primary>eqn</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>equation</secondary>
2001-09-04 13:27:31 +00:00
</indexterm>
<listitem>
2002-04-01 16:04:17 +00:00
<para>Yet another text markup and display formatting language
is <command>groff</command>. This is the enhanced GNU version
of the venerable UNIX <command>roff/troff</command> display
and typesetting package. <emphasis>Manpages</emphasis>
use <command>groff</command> (see <xref linkend="manview">).</para>
<para>The <command>tbl</command> table processing utility
is considered part of <command>groff</command>, as its
function is to convert table markup into
<command>groff</command> commands.</para>
2001-09-04 13:27:31 +00:00
2002-04-01 16:04:17 +00:00
<para>The <command>eqn</command> equation processing utility
is likewise part of <command>groff</command>, and
its function is to convert equation markup into
<command>groff</command> commands.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><command>lex</command></term>
<term><command>yacc</command></term>
<indexterm>
<primary>lex</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>flex</secondary>
</indexterm>
<indexterm>
<primary>yacc</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>bison</secondary>
</indexterm>
<listitem>
<para>The <command>lex</command> lexical analyzer produces
programs for pattern matching. This has been replaced
by the nonproprietary <command>flex</command> on Linux
systems.</para>
<para>The <command>yacc</command> utility creates a
parser based on a set of specifications. This has been
replaced by the nonproprietary <command>bison</command>
on Linux systems.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- End Text Processing Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="filearchiv">
2001-07-10 14:25:50 +00:00
<title>File and Archiving Commands</title>
2001-09-04 13:27:31 +00:00
<variablelist id="faarchiving">
<title><anchor id="faarchiving1">Archiving</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><anchor id="tarref"><command>tar</command></term>
<indexterm>
<primary>tar</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>tar</secondary>
</indexterm>
<listitem>
<para>The standard UNIX archiving utility. Originally a
2002-06-03 14:35:48 +00:00
<wordasword>Tape ARchiving</wordasword> program, it has
developed into a general purpose package that can handle
all manner of archiving with all types of destination
devices, ranging from tape drives to regular files to even
<filename>stdout</filename> (see <xref linkend="ex58">). GNU
tar has been patched to accept various compression
filters, such as <command>tar czvf archive_name.tar.gz
*</command>, which recursively archives and <link
linkend="gzipref">gzips</link> all files in a directory
tree except <link linkend="dotfilesref">dotfiles</link>
in the current working directory (<command>$PWD</command>).
2002-01-07 15:24:19 +00:00
<footnote>
<para>
2002-06-03 14:35:48 +00:00
A <command>tar czvf archive_name.tar.gz *</command>
2002-01-07 15:24:19 +00:00
<emphasis>will</emphasis> include dotfiles in
directories <emphasis>below</emphasis> the current
2002-06-03 14:35:48 +00:00
working directory. This is an undocumented GNU
2002-01-07 15:24:19 +00:00
<command>tar</command> <quote>feature</quote>.
</para>
</footnote>
</para>
2001-07-10 14:25:50 +00:00
<para>Some useful <command>tar</command> options:
<orderedlist>
2002-06-03 14:35:48 +00:00
<listitem><para><option>-c</option> create (a new
archive)</para></listitem>
<listitem><para><option>-x</option> extract (files from
existing archive)</para></listitem>
<listitem>
<para><option>--delete</option> delete (files
from existing archive)</para>
<caution><para>This option will not work on magnetic tape
devices.</para></caution>
</listitem>
<listitem><para><option>-r</option> append (files to
existing archive)</para></listitem>
<listitem><para><option>-A</option> append
(<emphasis>tar</emphasis> files to
existing archive)</para></listitem>
<listitem><para><option>-t</option> list (contents of
existing archive)</para></listitem>
2001-07-10 14:25:50 +00:00
<listitem><para><option>-u</option> update archive</para></listitem>
2002-06-03 14:35:48 +00:00
<listitem><para><option>-d</option> compare archive with
specified filesystem</para></listitem>
<listitem>
<para><option>-z</option> <link
linkend="gzipref">gzip</link> the archive</para>
<para>(compress or uncompress, depending on whether
combined with the <option>-c</option> or
<option>-x</option>) option</para>
</listitem>
<listitem><para><option>-j</option>
<link linkend="bzipref">bzip2</link> the
archive</para></listitem>
2001-07-10 14:25:50 +00:00
</orderedlist>
</para>
<caution><para>It may be difficult to recover data from a
corrupted <emphasis>gzipped</emphasis> tar
archive. When archiving important files, make multiple
backups.</para></caution>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><command>shar</command></term>
<indexterm>
<primary>shar</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>archive</secondary>
</indexterm>
<listitem>
<para>Shell archiving utility. The files in a shell archive
are concatenated without compression, and the resultant
archive is essentially a shell script, complete with
<token>#!/bin/sh</token> header, and containing all
the necessary unarchiving commands. Shar archives
still show up in Internet newsgroups, but otherwise
<command>shar</command> has been pretty well replaced by
<command>tar</command>/<command>gzip</command>. The
<command>unshar</command> command unpacks
<command>shar</command> archives.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>ar</command></term>
<indexterm>
<primary>ar</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>archive</secondary>
</indexterm>
<listitem>
<para>Creation and manipulation utility for archives, mainly
used for binary object file libraries.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>cpio</command></term>
<indexterm>
<primary>cpio</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>cpio</secondary>
</indexterm>
<listitem>
2002-01-07 15:24:19 +00:00
<para>This specialized archiving copy command
(<command>c</command>o<command>p</command>y
<command>i</command>nput and <command>o</command>utput)
is rarely seen any more, having been supplanted by
2001-07-10 14:25:50 +00:00
<command>tar</command>/<command>gzip</command>. It still
has its uses, such as moving a directory tree.</para>
<example id="ex48">
<title>Using <command>cpio</command> to move a directory tree</title>
<programlisting>&ex48;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
<example id="derpm">
<title>Unpacking an <emphasis>rpm</emphasis> archive</title>
<programlisting>&derpm;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="facompression">
<title><anchor id="facompression1">Compression</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><anchor id="gzipref"><command>gzip</command></term>
<indexterm>
<primary>gzip</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>gzip</secondary>
</indexterm>
<listitem>
<para>The standard GNU/UNIX compression utility, replacing
the inferior and proprietary
<command>compress</command>. The corresponding decompression
command is <command>gunzip</command>, which is the equivalent of
<command>gzip -d</command>.</para>
<para>The <command>zcat</command> filter decompresses a
<emphasis>gzipped</emphasis> file to
<filename>stdout</filename>, as possible input to a pipe or
redirection. This is, in effect, a <command>cat</command>
command that works on compressed files (including files
processed with the older <command>compress</command>
utility). The <command>zcat</command> command is equivalent to
<command>gzip -dc</command>.</para>
<caution><para>On some commercial UNIX systems, <command>zcat</command>
is a synonym for <command>uncompress -c</command>,
and will not work on <emphasis>gzipped</emphasis>
files.</para></caution>
<para>See also <xref linkend="ex14">.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="bzipref"><command>bzip2</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>bzip2</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>bzip2</secondary>
</indexterm>
<listitem>
2002-06-03 14:35:48 +00:00
2001-07-10 14:25:50 +00:00
<para>An alternate compression utility, usually more efficient
2002-06-03 14:35:48 +00:00
(but slower) than <command>gzip</command>, especially on
large files. The corresponding decompression command is
2001-07-10 14:25:50 +00:00
<command>bunzip2</command>.</para>
2002-06-03 14:35:48 +00:00
<note><para>Newer versions of <link
linkend="tarref">tar</link> have been patched with
<command>bzip2</command> support.</para></note>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><command>compress</command></term>
<term><command>uncompress</command></term>
<indexterm>
<primary>compress</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>compress</secondary>
</indexterm>
<indexterm>
<primary>uncompress</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>uncompress</secondary>
</indexterm>
<listitem>
<para>This is an older, proprietary compression
utility found in commercial UNIX distributions. The
more efficient <command>gzip</command> has largely
replaced it. Linux distributions generally include a
<command>compress</command> workalike for compatibility,
although <command>gunzip</command> can unarchive files
treated with <command>compress</command>.</para>
2001-10-15 14:21:41 +00:00
<tip><para>The <command>znew</command> command transforms
<emphasis>compressed</emphasis> files into
<emphasis>gzipped</emphasis> ones.</para></tip>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><command>sq</command></term>
<indexterm>
<primary>sq</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>sq</secondary>
</indexterm>
<listitem>
<para>Yet another compression utility, a filter that works
only on sorted ASCII word lists. It uses the standard
invocation syntax for a filter, <command>sq < input-file >
output-file</command>. Fast, but not nearly as efficient
as <link linkend="gzipref">gzip</link>. The corresponding
uncompression filter is <command>unsq</command>, invoked
like <command>sq</command>.</para>
<tip><para>The output of <command>sq</command> may be
piped to <command>gzip</command> for further
compression.</para></tip>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>zip</command></term>
<term><command>unzip</command></term>
<indexterm>
<primary>zip</primary>
</indexterm>
<indexterm>
<primary>command</primary>
2002-06-03 14:35:48 +00:00
<secondary>pkzip.exe</secondary>
2001-10-15 14:21:41 +00:00
</indexterm>
<indexterm>
<primary>unzip</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>unzip</secondary>
</indexterm>
<listitem>
<para>Cross-platform file archiving and compression utility
2002-06-03 14:35:48 +00:00
compatible with DOS <emphasis>pkzip.exe</emphasis>.
2001-10-15 14:21:41 +00:00
<quote>Zipped</quote> archives seem to be a more
acceptable medium of exchange on the Internet than
<quote>tarballs</quote>.</para>
</listitem>
</varlistentry>
2002-06-03 14:35:48 +00:00
<varlistentry>
<term><command>unarc</command></term>
<term><command>unarj</command></term>
<term><command>unrar</command></term>
<indexterm>
<primary>unarc</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>arc.exe</secondary>
</indexterm>
<indexterm>
<primary>unarj</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>arj.exe</secondary>
</indexterm>
<indexterm>
<primary>unrar</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>rar.exe</secondary>
</indexterm>
<listitem>
<para>These Linux utilities permit unpacking archives
compressed with the DOS <emphasis>arc.exe</emphasis>,
<emphasis>arj.exe</emphasis>, and
<emphasis>rar.exe</emphasis> programs.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="fainformation">
<title><anchor id="fainformation1">File Information</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><anchor id="fileref"><command>file</command></term>
<indexterm>
<primary>file</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>file</secondary>
</indexterm>
<listitem>
<para>A utility for identifying file types. The command
<userinput>file file-name</userinput> will return a
file specification for <filename>file-name</filename>,
such as <computeroutput>ascii text</computeroutput> or
<computeroutput>data</computeroutput>. It references
the <link linkend="magnumref">magic numbers</link>
found in <filename>/usr/share/magic</filename>,
<filename>/etc/magic</filename>, or
<filename>/usr/lib/magic</filename>, depending on the
Linux/UNIX distribution.</para>
2001-10-15 14:21:41 +00:00
<para>The <option>-f</option> option causes
<command>file</command> to run in batch mode, to read from
a designated file a list of filenames to analyze. The
<option>-z</option> option, when used on a compressed
target file, forces an attempt to analyze the uncompressed
file type.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>file test.tar.gz</userinput>
<computeroutput>test.tar.gz: gzip compressed data, deflated, last modified: Sun Sep 16 13:34:51 2001, os: Unix</computeroutput>
<prompt>bash </prompt><userinput>file -z test.tar.gz</userinput>
<computeroutput>test.tar.gz: GNU tar archive (gzip compressed data, deflated, last modified: Sun Sep 16 13:34:51 2001, os: Unix)</computeroutput>
</screen>
</para>
2001-07-10 14:25:50 +00:00
<example id="stripc">
<title>stripping comments from C program files</title>
<programlisting>&stripc;</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="whichref"><command>which</command></term>
<indexterm>
<primary>which</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>which</secondary>
</indexterm>
<listitem>
<para><command>which command-xxx</command> gives the full path
to <quote>command-xxx</quote>. This is useful for finding
out whether a particular command or utility is installed
on the system.</para>
<para><userinput>$bash which rm</userinput>
<screen><computeroutput>/usr/bin/rm</computeroutput></screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>whereis</command></term>
<indexterm>
<primary>whereis</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>whereis</secondary>
</indexterm>
<listitem>
<para>Similar to <command>which</command>, above,
<command>whereis command-xxx</command> gives the
full path to <quote>command-xxx</quote>, but also to its
2001-09-04 13:27:31 +00:00
<emphasis>manpage</emphasis>.</para>
2001-07-10 14:25:50 +00:00
<para><userinput>$bash whereis rm</userinput>
<screen><computeroutput>rm: /bin/rm /usr/share/man/man1/rm.1.bz2</computeroutput></screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="whatisref"><command>whatis</command></term>
<indexterm>
<primary>whatis</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>whatis</secondary>
</indexterm>
<listitem>
<para><command>whatis filexxx</command> looks up
<quote>filexxx</quote> in the
<replaceable>whatis</replaceable> database. This is useful
for identifying system commands and important configuration
files. Consider it a simplified <command>man</command>
command.</para>
<para><userinput>$bash whatis whatis</userinput>
<screen><computeroutput>whatis (1) - search the whatis database for complete words</computeroutput></screen>
</para>
<example id="what">
<title><command>Exploring <filename
class="directory">/usr/X11R6/bin</filename></command></title>
<programlisting>&what;</programlisting>
</example>
<para>See also <xref linkend="fileinfo">.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>vdir</command></term>
<indexterm>
<primary>vdir</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>ls</secondary>
</indexterm>
<listitem>
<para>Show a detailed directory listing. The effect is similar to
<link linkend="lsref">ls -l</link>.</para>
<para>This is one of the GNU <emphasis>fileutils</emphasis>.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>vdir</userinput>
<computeroutput>total 10
-rw-r--r-- 1 bozo bozo 4034 Jul 18 22:04 data1.xrolo
-rw-r--r-- 1 bozo bozo 4602 May 25 13:58 data1.xrolo.bak
-rw-r--r-- 1 bozo bozo 877 Dec 17 2000 employment.xrolo</computeroutput>
<prompt>bash </prompt><userinput>ls -l</userinput>
<computeroutput>total 10
-rw-r--r-- 1 bozo bozo 4034 Jul 18 22:04 data1.xrolo
-rw-r--r-- 1 bozo bozo 4602 May 25 13:58 data1.xrolo.bak
-rw-r--r-- 1 bozo bozo 877 Dec 17 2000 employment.xrolo</computeroutput>
</screen>
2002-06-17 13:17:07 +00:00
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="shredref"><command>shred</command></term>
<indexterm>
<primary>shred</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>secure delete</secondary>
</indexterm>
<listitem>
<para>Securely erase a file by overwriting it multiple times with
random bit patterns before deleting it. This command has
the same effect as <xref linkend="blotout">, but does it
in a more thorough and elegant manner.</para>
<para>This is one of the GNU <emphasis>fileutils</emphasis>.</para>
<caution><para>Using <command>shred</command> on a file may
not prevent recovery of some or all of its contents using
advanced forensic technology.</para></caution>
</listitem>
</varlistentry>
<varlistentry>
<term><command>locate</command></term>
<term><command>slocate</command></term>
<indexterm>
<primary>locate</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>locate</secondary>
</indexterm>
<indexterm>
<primary>slocate</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>slocate</secondary>
</indexterm>
<listitem>
<para>The <command>locate</command> command searches for files using a
database stored for just that purpose. The
<command>slocate</command> command is the secure version of
<command>locate</command> (which may be aliased to
<command>slocate</command>).</para>
<para><userinput>$bash locate hickson</userinput>
<screen><computeroutput>/usr/lib/xephem/catalogs/hickson.edb</computeroutput></screen></para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>strings</command></term>
<indexterm>
<primary>strings</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>strings</secondary>
</indexterm>
<listitem>
<para>Use the <command>strings</command> command to find
printable strings in a binary or data file. It will list
sequences of printable characters found in the target
file. This might be handy for a quick 'n dirty examination
of a core dump or for looking at an unknown graphic image
file (<userinput>strings image-file | more</userinput> might
show something like <computeroutput>JFIF</computeroutput>,
which would identify the file as a <emphasis>jpeg</emphasis>
graphic). In a script, you would probably
parse the output of <command>strings</command>
with <link linkend="grepref">grep</link> or <link
linkend="sedref">sed</link>. See <xref linkend="bingrep">
and <xref linkend="findstring">.</para>
<example id="wstrings">
<title>An <quote>improved</quote> <emphasis>strings</emphasis>
command</title>
<programlisting>&wstrings;</programlisting>
</example>
</listitem>
</varlistentry>
</variablelist>
<variablelist id="comparisonn">
<title><anchor id="comparisonn1">Comparison</title>
<varlistentry>
<term><anchor id="diffref"><command>diff</command></term>
<term><command>patch</command></term>
<indexterm>
<primary>diff</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>diff</secondary>
</indexterm>
<indexterm>
<primary>patch</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>patch</secondary>
</indexterm>
<listitem>
<para><command>diff</command>: flexible file comparison
utility. It compares the target files line-by-line
sequentially. In some applications, such as comparing
word dictionaries, it may be helpful to filter the
files through <link linkend="sortref">sort</link>
and <command>uniq</command> before piping them
to <command>diff</command>. <userinput>diff file-1
file-2</userinput> outputs the lines in the files that
differ, with carets showing which file each particular
line belongs to.</para>
<para>The <option>--side-by-side</option> option to
<command>diff</command> outputs each compared file, line by line,
in separate columns, with non-matching lines marked.</para>
<para>There are available various fancy frontends for
<command>diff</command>, such as <command>spiff</command>,
<command>wdiff</command>, <command>xdiff</command>, and
<command>mgdiff</command>. </para>
<tip><para>The <command>diff</command> command returns an exit
status of 0 if the compared files are identical, and 1 if
they differ. This permits use of <command>diff</command>
in a test construct within a shell script (see
below).</para></tip>
<para>A common use for <command>diff</command> is generating
difference files to be used with <command>patch</command>
The <option>-e</option> option outputs files suitable
for <command>ed</command> or <command>ex</command>
scripts.</para>
<para><command>patch</command>: flexible versioning
utility. Given a difference file generated by
<command>diff</command>, <command>patch</command> can
upgrade a previous version of a package to a newer version.
It is much more convenient to distribute a relatively
small <quote>diff</quote> file than the entire body of a
newly revised package. Kernel <quote>patches</quote> have
become the preferred method of distributing the frequent
releases of the Linux kernel.</para>
<para><programlisting>patch -p1 &lt;patch-file
# Takes all the changes listed in 'patch-file'
# and applies them to the files referenced therein.
# This upgrades to a newer version of the package.</programlisting></para>
<para>Patching the kernel:</para>
<para><programlisting>cd /usr/src
gzip -cd patchXX.gz | patch -p0
# Upgrading kernel source using 'patch'.
# From the Linux kernel docs "README",
# by anonymous author (Alan Cox?).</programlisting></para>
<note>
<para>The <command>diff</command> command can also
recursively compare directories (for the filenames
present).</para>
<para>
<screen><prompt>bash$ </prompt><userinput>diff -r ~/notes1 ~/notes2</userinput>
<computeroutput>Only in /home/bozo/notes1: file02
Only in /home/bozo/notes1: file03
Only in /home/bozo/notes2: file04</computeroutput>
</screen>
</para>
</note>
<tip><para>Use <command>zdiff</command> to compare
<emphasis>gzipped</emphasis> files.</para></tip>
2001-10-15 14:21:41 +00:00
</listitem>
</varlistentry>
<varlistentry>
2002-06-17 13:17:07 +00:00
<term><command>diff3</command></term>
2001-10-15 14:21:41 +00:00
<indexterm>
2002-06-17 13:17:07 +00:00
<primary>diff3</primary>
2001-10-15 14:21:41 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2002-06-17 13:17:07 +00:00
<secondary>diff3</secondary>
2001-10-15 14:21:41 +00:00
</indexterm>
<listitem>
2002-06-17 13:17:07 +00:00
<para>An extended version of <command>diff</command> that compares
three files at a time. This command returns an exit value
of 0 upon successful execution, but unfortunately this gives
no information about the results of the comparison.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>diff3 file-1 file-2 file-3</userinput>
<computeroutput>====
1:1c
This is line 1 of "file-1".
2:1c
This is line 1 of "file-2".
3:1c
This is line 1 of "file-3"</computeroutput>
</screen>
</para>
2001-10-15 14:21:41 +00:00
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
2002-06-17 13:17:07 +00:00
<term><command>sdiff</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2002-06-17 13:17:07 +00:00
<primary>sdiff</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2002-06-17 13:17:07 +00:00
<secondary>sdiff</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2002-06-17 13:17:07 +00:00
<listitem>
<para>Compare and/or edit two files in order to merge
them into an output file. Because of its interactive nature,
this command would find little use in a script.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>cmp</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2002-06-17 13:17:07 +00:00
<primary>cmp</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2002-06-17 13:17:07 +00:00
<secondary>cmp</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2002-06-17 13:17:07 +00:00
<para>The <command>cmp</command> command is a simpler version of
<command>diff</command>, above. Whereas <command>diff</command>
reports the differences between two files,
<command>cmp</command> merely shows at what point they
differ.</para>
<note><para>Like <command>diff</command>, <command>cmp</command>
returns an exit status of 0 if the compared files are
identical, and 1 if they differ. This permits use in a test
construct within a shell script.</para></note>
<example id="filecomp">
<title>Using <command>cmp</command> to compare two files
within a script.</title>
<programlisting>&filecomp;</programlisting>
</example>
<tip><para>Use <command>zcmp</command> on
<emphasis>gzipped</emphasis> files.</para></tip>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
2002-06-17 13:17:07 +00:00
<term><command>comm</command></term>
2001-09-04 13:27:31 +00:00
<indexterm>
2002-06-17 13:17:07 +00:00
<primary>comm</primary>
2001-09-04 13:27:31 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2002-06-17 13:17:07 +00:00
<secondary>comm</secondary>
2001-09-04 13:27:31 +00:00
</indexterm>
<listitem>
2002-06-17 13:17:07 +00:00
<para>Versatile file comparison utility. The files must be
sorted for this to be useful.</para>
2002-04-01 16:04:17 +00:00
2002-06-17 13:17:07 +00:00
<para><command>comm
<replaceable>-options</replaceable>
<replaceable>first-file</replaceable>
<replaceable>second-file</replaceable></command></para>
2002-04-01 16:04:17 +00:00
2002-06-17 13:17:07 +00:00
<para><userinput>comm file-1 file-2</userinput> outputs three columns:
<itemizedlist>
<listitem><para>column 1 = lines unique to <filename>file-1</filename></para>
</listitem>
<listitem><para>column 2 = lines unique to <filename>file-2</filename></para>
</listitem>
<listitem><para>column 3 = lines common to both.</para>
</listitem>
</itemizedlist></para>
<para>The options allow suppressing output of one or more columns.
<itemizedlist>
<listitem><para><option>-1</option> suppresses column
<literal>1</literal></para>
</listitem>
<listitem><para><option>-2</option> suppresses column
<literal>2</literal></para>
</listitem>
<listitem><para><option>-3</option> suppresses column
<literal>3</literal></para>
</listitem>
<listitem><para><option>-12</option> suppresses both columns
<literal>1</literal> and <literal>2</literal>, etc.</para>
</listitem>
</itemizedlist>
</para>
</listitem>
2001-09-04 13:27:31 +00:00
</varlistentry>
2002-06-17 13:17:07 +00:00
</variablelist>
2001-09-04 13:27:31 +00:00
<variablelist id="fautils">
<title><anchor id="fautils1">Utilities</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>basename</command></term>
<indexterm>
<primary>basename</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>basename</secondary>
</indexterm>
<listitem><para>Strips the path information from a file name, printing
only the file name. The construction <userinput>basename
$0</userinput> lets the script know its name, that is, the name it
was invoked by. This can be used for <quote>usage</quote> messages if,
for example a script is called with missing arguments:
<programlisting>echo "Usage: `basename $0` arg1 arg2 ... argn"</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>dirname</command></term>
<indexterm>
<primary>dirname</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>dirname</secondary>
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem><para>Strips the <command>basename</command> from
a filename, printing only the path information.</para>
2001-07-10 14:25:50 +00:00
<note>
<para><command>basename</command> and <command>dirname</command>
2001-09-04 13:27:31 +00:00
can operate on any arbitrary string. The argument
does not need to refer to an existing file, or
even be a filename for that matter (see <xref
linkend="daysbetween">).</para>
2001-07-10 14:25:50 +00:00
</note>
<example id="ex35">
<title><command>basename</command> and <command>dirname</command></title>
<programlisting>&ex35;</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>split</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>split</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>split</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Utility for splitting a file into smaller chunks. Usually used
for splitting up large files in order to back them up on floppies or
preparatory to e-mailing or uploading them.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><command>sum</command></term>
<term><command>cksum</command></term>
2001-10-15 14:21:41 +00:00
<term><anchor id="md5sumref"><command>md5sum</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>sum</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>sum</secondary>
</indexterm>
<indexterm>
<primary>cksum</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>cksum</secondary>
</indexterm>
<indexterm>
<primary>md5sum</primary>
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>md5sum</secondary>
</indexterm>
<listitem>
<para>These are utilities for generating checksums. A
<emphasis>checksum</emphasis> is a number mathematically
calculated from the contents of a file, for the purpose
of checking its integrity. A script might refer to a list
of checksums for security purposes, such as ensuring that
2002-06-03 14:35:48 +00:00
the contents of key system files have not been altered
or corrupted. For security applications, use the 128-bit
<command>md5sum</command> (<command>m</command>essage
<command>d</command>igest check<command>sum</command>)
command.</para>
2002-04-01 16:04:17 +00:00
<para>
<screen>
<prompt>bash$ </prompt><userinput>cksum /boot/vmlinuz</userinput>
<computeroutput>1670054224 804083 /boot/vmlinuz</computeroutput>
<prompt>bash$ </prompt><userinput>md5sum /boot/vmlinuz</userinput>
<computeroutput>0f43eccea8f09e0a0b2b5cf1dcf333ba /boot/vmlinuz</computeroutput>
</screen>
2002-06-03 14:35:48 +00:00
</para>
<para>Note that <command>cksum</command> also shows the size,
in bytes, of the target file.</para>
<example id="fileintegrity">
<title>Checking file integrity</title>
<programlisting>&fileintegrity;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
</variablelist>
<variablelist id="faencencr">
<title><anchor id="faencencr1">Encoding and Encryption</title>
<varlistentry>
<term><command>uuencode</command></term>
<indexterm>
<primary>uuencode</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>uuencode</secondary>
</indexterm>
<listitem>
<para>This utility encodes binary files into ASCII characters, making them
suitable for transmission in the body of an e-mail message or in a
newsgroup posting.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>uudecode</command></term>
<indexterm>
<primary>uudecode</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>uudecode</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>This reverses the encoding, decoding uuencoded files back into the
original binaries.</para>
<example id="ex52">
<title>uudecoding encoded files</title>
<programlisting>&ex52;</programlisting>
</example>
<tip><para>The <link linkend="foldref">fold -s</link> command
may be useful (possibly in a pipe) to process long uudecoded
text messages downloaded from Usenet newsgroups.</para></tip>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2002-04-01 16:04:17 +00:00
<varlistentry>
<term><command>mimencode</command></term>
<term><command>mmencode</command></term>
<indexterm>
<primary>mimencode</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>mime</secondary>
</indexterm>
<indexterm>
<primary>mmencode</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>encode</secondary>
</indexterm>
<listitem>
<para>The <command>mimencode</command> and
<command>mmencode</command> commands process
multimedia-encoded e-mail attachments. Although
<emphasis>mail user agents</emphasis> (such as
<command>pine</command> or <command>kmail</command>)
normally handle this automatically, these particular
utilities permit manipulating such attachments manually
from the command line or in a batch by means of a shell
script.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>crypt</command></term>
<indexterm>
<primary>crypt</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>crypt</secondary>
</indexterm>
<listitem>
<para>At one time, this was the standard UNIX file encryption
utility.
<footnote><para>This is a symmetric block cipher, used to
encrypt files on a single system or local network, as opposed
to the <quote>public key</quote> cipher class, of which
<command>pgp</command> is a well-known
example.</para></footnote>
Politically motivated government regulations
prohibiting the export of encryption software resulted
in the disappearance of <command>crypt</command>
from much of the UNIX world, and it is still
missing from most Linux distributions. Fortunately,
programmers have come up with a number of decent
alternatives to it, among them the author's very own <ulink
url="ftp://metalab.unc.edu/pub/Linux/utils/file/cruft-0.2.tar.gz">cruft</ulink>
(see <xref linkend="encryptedpw">). </para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="famisc">
<title><anchor id="famisc1">Miscellaneous</title>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>make</command></term>
<indexterm>
<primary>make</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>Makefile</secondary>
</indexterm>
<listitem>
<para>Utility for building and compiling binary packages.
This can also be used for any set of operations that is
triggered by incremental changes in source files.</para>
<para><anchor id="makefileref"></para>
<para>The <command>make</command> command checks a
<filename>Makefile</filename>, a list of file dependencies and
operations to be carried out.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>install</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>install</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>install</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Special purpose file copying command, similar to
<command>cp</command>, but capable of setting permissions
and attributes of the copied files. This command seems
tailormade for installing software packages, and as such it
2001-10-15 14:21:41 +00:00
shows up frequently in <filename>Makefiles</filename>
(in the <replaceable>make install :</replaceable>
section). It could likewise find use in installation
scripts.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2002-06-17 13:17:07 +00:00
<varlistentry>
<term><command>ptx</command></term>
<indexterm>
<primary>ptx</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>index</secondary>
</indexterm>
<listitem>
<para>The <command>ptx [targetfile]</command> command
outputs a permuted index (cross-reference list) of the
targetfile. This may be further filtered and formatted in a
pipe, if necessary.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>more</command></term>
<term><command>less</command></term>
<indexterm>
<primary>more</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>more</secondary>
</indexterm>
<indexterm>
<primary>less</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>less</secondary>
</indexterm>
<listitem>
<para>Pagers that display a text file or stream to
<filename>stdout</filename>, one screenful at a time.
These may be used to filter the output of a script.</para>
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- End File and Archiving Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="communications">
2001-07-10 14:25:50 +00:00
<title>Communications Commands</title>
2001-09-04 13:27:31 +00:00
<variablelist id="communinfo">
<title><anchor id="communinfo1">Information and Statistics</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>host</command></term>
<indexterm>
<primary>host</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>host</secondary>
</indexterm>
<listitem>
<para>Searches for information about an Internet host by name or
IP address, using DNS.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>vrfy</command></term>
<indexterm>
<primary>vrfy</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>vrfy</secondary>
</indexterm>
<listitem>
<para>Verify an Internet e-mail address.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>nslookup</command></term>
<indexterm>
<primary>nslookup</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>name server lookup</secondary>
</indexterm>
<listitem>
<para>Do an Internet <quote>name server lookup</quote> on a host
by IP address. This may be run either interactively or
noninteractively, i.e., from within a script.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>dig</command></term>
<indexterm>
<primary>dig</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>domain information groper</secondary>
</indexterm>
<listitem>
<para>Similar to <command>nslookup</command>, do an Internet
<quote>name server lookup</quote> on a host. May be run
either interactively or noninteractively, i.e., from within
a script.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>traceroute</command></term>
<indexterm>
<primary>traceroute</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>traceroute</secondary>
</indexterm>
<listitem>
<para>Trace the route taken by packets sent to a remote host. This
command works within a LAN, WAN, or over the
Internet. The remote host may be specified by an IP
address. The output of this command may be filtered
by <link linkend="grepref">grep</link> or <link
linkend="sedref">sed</link> in a pipe.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>ping</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>ping</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>ping</secondary>
</indexterm>
<listitem>
<para>Broadcast an <quote>ICMP ECHO_REQUEST</quote> packet to
other machines, either on a local or remote network. This
is a diagnostic tool for testing network connections,
and it should be used with caution.</para>
<para>A successful <command>ping</command> returns an <link
linkend="exitstatusref">exit status</link> of
<errorcode>0</errorcode>. This can be tested for in a
script.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>ping localhost</userinput>
<computeroutput>PING localhost.localdomain (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data.
Warning: time of day goes back, taking countermeasures.
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=255 time=709 usec
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=255 time=286 usec
--- localhost.localdomain ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/mdev = 0.286/0.497/0.709/0.212 ms</computeroutput>
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="whoisref"><command>whois</command></term>
<indexterm>
<primary>whois</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>domain name server</secondary>
</indexterm>
<listitem>
<para>Perform a DNS (Domain Name System) lookup.
The <option>-h</option> option permits specifying which
<emphasis>whois</emphasis> server to query. See <xref
linkend="ex18">.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>finger</command></term>
<indexterm>
<primary>finger</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>finger</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Retrieve information about a particular user on
a network. Optionally, this command can display
the user's <filename>~/.plan</filename>,
<filename>~/.project</filename>, and
<filename>~/.forward</filename> files, if present.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>finger bozo</userinput>
<computeroutput>Login: bozo Name: Bozo Bozeman
Directory: /home/bozo Shell: /bin/bash
On since Fri Aug 31 20:13 (MST) on tty1 1 hour 38 minutes idle
On since Fri Aug 31 20:13 (MST) on pts/0 12 seconds idle
On since Fri Aug 31 20:13 (MST) on pts/1
On since Fri Aug 31 20:31 (MST) on pts/2 1 hour 16 minutes idle
No mail.
No Plan.</computeroutput>
</screen>
</para>
<para>Out of security considerations, many networks disable
<command>finger</command> and its associated daemon.
<footnote>
<para><anchor id="daemonref"></para>
<para>A <emphasis>daemon</emphasis> is a background
process not attached to a terminal session. Daemons
perform designated services either at specified times
or explicitly triggered by certain events.</para>
<para>The word <quote>daemon</quote> means ghost in
Greek, and there is certainly something mysterious,
almost supernatural, about the way UNIX daemons
silently wander about behind the scenes, carrying
out their appointed tasks.</para>
</footnote>
</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="commremote">
<title><anchor id="commremote1">Remote Host Access</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>sx</command></term>
<term><command>rx</command></term>
<indexterm>
<primary>sx</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>sx</secondary>
</indexterm>
<indexterm>
<primary>rx</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>rx</secondary>
</indexterm>
<listitem>
<para>The <command>sx</command> and <command>rx</command>
command set serves to transfer files to and from a remote
host using the <emphasis>xmodem</emphasis> protocol. These
are generally part of a communications package, such as
<command>minicom</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>sz</command></term>
<term><command>rz</command></term>
<indexterm>
<primary>sz</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>sz</secondary>
</indexterm>
<indexterm>
<primary>rz</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>rz</secondary>
</indexterm>
<listitem>
<para>The <command>sz</command> and <command>rz</command>
command set serves to transfer files to and from a remote
host using the <emphasis>zmodem</emphasis> protocol.
<emphasis>Zmodem</emphasis> has certain advantages over
<emphasis>xmodem</emphasis>, such as greater transmission
rate and resumption of interrupted file transfers.
Like <command>sx</command> and <command>rx</command>,
these are generally part of a communications package.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="ftpref"><command>ftp</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>ftp</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>file transfer</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-10-15 14:21:41 +00:00
<para>Utility and protocol for uploading / downloading
files to / from a remote host. An ftp session can be automated
in a script (see <xref linkend="ex72">, <xref
linkend="encryptedpw">, and <xref linkend="ftpget">).</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>cu</command></term>
<indexterm>
<primary>cu</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>call up</secondary>
</indexterm>
<listitem>
<para><emphasis>C</emphasis>all <emphasis>U</emphasis>p
a remote system and connect as a simple terminal. This
is a sort of dumbed-down version of <link
linkend="telnetref">telnet</link>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><command>uucp</command></term>
<indexterm>
<primary>uucp</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>uucp</secondary>
</indexterm>
<listitem>
<para><emphasis>UNIX to UNIX copy</emphasis>. This is a
communications package for transferring files between UNIX
servers. A shell script is an effective way to handle a
<command>uucp</command> command sequence.</para>
<para>Since the advent of the Internet and e-mail,
<command>uucp</command> seems to have faded into obscurity,
but it still exists and remains perfectly workable in
situations where an Internet connection is not available
or appropriate.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><anchor id="telnetref"><command>telnet</command></term>
<indexterm>
<primary>telnet</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>telnet</secondary>
</indexterm>
<listitem>
<para>Utility and protocol for connecting to a remote host.</para>
<caution><para>The telnet protocol contains security holes and
should therefore probably be avoided.</para></caution>
</listitem>
</varlistentry>
<varlistentry>
<term><command>rlogin</command></term>
<indexterm>
<primary>rlogin</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>remote login</secondary>
</indexterm>
<listitem>
<para><replaceable>Remote login</replaceable>, initates a
session on a remote host. This command has security issues,
so use <link linkend="sshref">ssh</link> instead.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>rsh</command></term>
<indexterm>
<primary>rsh</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>remote shell</secondary>
</indexterm>
<listitem>
<para><replaceable>Remote shell</replaceable>, executes
command(s) on a remote host. This has security issues,
so use <command>ssh</command> instead.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>rcp</command></term>
<indexterm>
<primary>rcp</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>remote copy</secondary>
</indexterm>
<listitem>
<para><replaceable>Remote copy</replaceable>, copies files
between two different networked machines. Using
<command>rcp</command> and similar utilities with
security implications in a shell script may not be
advisable. Consider, instead, using <command>ssh</command>
or an <command>expect</command> script.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="sshref"><command>ssh</command></term>
<indexterm>
<primary>ssh</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>secure shell</secondary>
</indexterm>
<listitem>
<para><replaceable>Secure shell</replaceable>, logs onto
a remote host and executes commands there. This
secure replacement for <command>telnet</command>,
<command>rlogin</command>, <command>rcp</command>, and
<command>rsh</command> uses identity authentication
and encryption. See its <emphasis>manpage</emphasis>
for details.</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist id="commlocal">
<title><anchor id="commlocal1">Local Network</title>
<varlistentry>
<term><anchor id="writeref"><command>write</command></term>
<indexterm>
<primary>write</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>write</secondary>
</indexterm>
<listitem>
<para>This is a utility for terminal-to-terminal communication.
It allows sending lines from your terminal (console
or xterm) to that of another user. The <link
linkend="mesgref">mesg</link> command may, of course,
be used to disable write access to a terminal</para>
<para>Since <command>write</command> is interactive, it
would not normally find use in a script.</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist id="commmail">
<title><anchor id="commmail1">Mail</title>
<varlistentry>
2002-04-01 16:04:17 +00:00
<term><command>mail</command></term>
2001-09-04 13:27:31 +00:00
<indexterm>
2002-04-01 16:04:17 +00:00
<primary>mail</primary>
2001-09-04 13:27:31 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>mail</secondary>
</indexterm>
<listitem>
2002-04-01 16:04:17 +00:00
<para>Send an e-mail message to a user.</para>
<para>This stripped-down command-line mail client
works fine as a command embedded in a script.</para>
<example id="selfmailer">
<title>A script that mails itself</title>
<programlisting>&selfmailer;</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
<term><command>vacation</command></term>
<indexterm>
<primary>vacation</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>mail</secondary>
</indexterm>
<listitem>
<para>This utility automatically replies to e-mails that
the intended recipient is on vacation and temporarily
unavailable. This runs on a network, in conjunction with
<command>sendmail</command>, and is not applicable to a
dial-up POPmail account.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- End Communications Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="terminalccmds">
2001-07-10 14:25:50 +00:00
<title>Terminal Control Commands</title>
2001-09-04 13:27:31 +00:00
<variablelist id="termcommandlisting">
2002-06-17 13:17:07 +00:00
<title><anchor id="termcommandlisting1">Command affecting the console
or terminal</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>tput</command></term>
<indexterm>
<primary>tput</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>terminal</secondary>
</indexterm>
<listitem>
<para>Initialize terminal and/or fetch information about it from
<filename>terminfo</filename> data. Various options permit
certain terminal operations. <command>tput clear</command>
is the equivalent of <command>clear</command>,
below. <command>tput reset</command> is the equivalent of
<command>reset</command>, below.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>tput longname</userinput>
<computeroutput>xterm terminal emulator (XFree86 4.0 Window System)</computeroutput>
</screen>
</para>
<para>Note that <link linkend="sttyref">stty</link> offers
a more powerful command set for controlling a terminal.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>reset</command></term>
<indexterm>
<primary>reset</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>reset</secondary>
</indexterm>
<listitem>
<para>Reset terminal parameters and clear text screen. As with
<command>clear</command>, the cursor and prompt reappear in the
upper lefthand corner of the terminal.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="clearref"><command>clear</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>clear</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>clear</secondary>
</indexterm>
<listitem>
<para>The <command>clear</command> command simply clears
the text screen at the console or in an xterm. The
prompt and cursor reappear at the upper lefthand corner
of the screen or xterm window. This command may be used
either at the command line or in a script. See <xref
linkend="ex30">.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>script</command></term>
<indexterm>
<primary>script</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>script</secondary>
</indexterm>
<listitem>
<para>This utility records (saves to a file) all the user keystrokes at
the command line in a console or an xterm window. This, in effect,
2002-06-17 13:17:07 +00:00
creates a record of a session.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- End Terminal Control Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="mathc">
2001-07-10 14:25:50 +00:00
<title>Math Commands</title>
2001-09-04 13:27:31 +00:00
<variablelist id="mathcommandlisting">
2002-06-17 13:17:07 +00:00
<title><anchor id="mathcommandlisting1"><quote>Doing the
numbers</quote></title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>factor</command></term>
<indexterm>
<primary>factor</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>factor</secondary>
</indexterm>
2001-10-15 14:21:41 +00:00
<listitem><para>Decompose an integer into prime factors.</para>
2001-07-10 14:25:50 +00:00
<para>
<screen><prompt>bash$ </prompt><userinput>factor 27417</userinput>
<computeroutput>27417: 3 13 19 37</computeroutput>
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="bcref"><command>bc</command></term>
<term><command>dc</command></term>
<indexterm>
<primary>bc</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>bc</secondary>
</indexterm>
<indexterm>
<primary>dc</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>dc</secondary>
</indexterm>
<listitem>
<para>These are flexible, arbitrary precision calculation
utilities.</para>
<para><command>bc</command> has a syntax vaguely resembling C.</para>
2002-06-17 13:17:07 +00:00
<para><command>dc</command> is stack-oriented and uses RPN
(<quote>Reverse Polish Notation</quote>).</para>
2001-07-10 14:25:50 +00:00
<para>Of the two, <command>bc</command> seems more useful in
scripting. It is a fairly well-behaved UNIX utility, and may
therefore be used in a pipe.</para>
<para>Bash can't handle floating point calculations, and
it lacks operators for certain important mathematical
functions. Fortunately, <command>bc</command> comes to
the rescue.</para>
<para>Here is a simple template for using
2002-01-07 15:24:19 +00:00
<command>bc</command> to calculate a script
variable. This uses <link linkend="commandsubref">command
substitution</link>.</para>
2001-07-10 14:25:50 +00:00
<para>
<screen>
<userinput>variable=$(echo "OPTIONS; OPERATIONS" | bc)</userinput>
</screen>
</para>
<example id="monthlypmt">
<title>Monthly Payment on a Mortgage</title>
<programlisting>&monthlypmt;</programlisting>
</example>
<example id="base">
<title>Base Conversion</title>
<programlisting>&base;</programlisting>
</example>
2002-01-07 15:24:19 +00:00
<para>An alternate method of invoking <command>bc</command>
involves using a <link linkend="heredocref">here
document</link> embedded within a <link
linkend="commandsubref">command substitution</link>
block. This is especially appropriate when a script
needs to pass a list of options and commands to
<command>bc</command>.</para>
<para>
<programlisting>variable=`bc << LIMIT_STRING
options
statements
operations
LIMIT_STRING
`
...or...
variable=$(bc << LIMIT_STRING
options
statements
operations
LIMIT_STRING
)</programlisting>
</para>
<example id="altbc">
<title>Another way to invoke <command>bc</command></title>
<programlisting>&altbc;</programlisting>
</example>
2002-06-17 13:17:07 +00:00
<para>Most persons avoid <command>dc</command>, since it
requires non-intuitive RPN input. Yet it has its uses.</para>
<example id="hexconvert">
<title>Converting a decimal number to hexadecimal</title>
<programlisting>&hexconvert;</programlisting>
</example>
<para>Studying the <emphasis>info</emphasis> page for
<command>dc</command> gives some insight into its
intricacies. However, there seems to be a small,
select group of <emphasis>dc wizards</emphasis> who
delight in showing off their mastery of this powerful,
but arcane utility.</para>
<example id="factr">
<title>Factoring</title>
<programlisting>&factr;</programlisting>
</example>
2002-01-07 15:24:19 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="awkmath"><command>awk</command></term>
<indexterm>
<primary>awk</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>math</secondary>
</indexterm>
<listitem>
<para>Yet another way of doing floating point math in
a script is using <link linkend="awkref">awk's</link>
built-in math functions in a <link linkend="shwrapper">shell
wrapper</link>.</para>
<example id="hypot">
<title>Calculating the hypotenuse of a triangle</title>
<programlisting>&hypot;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- End Math Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="extmisc">
2001-07-10 14:25:50 +00:00
<title>Miscellaneous Commands</title>
2001-09-04 13:27:31 +00:00
<variablelist id="misccommandlisting">
2002-06-17 13:17:07 +00:00
<title><anchor id="misccommandlisting1">Command that fit in no
special category</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>jot</command></term>
<term><command>seq</command></term>
<indexterm>
<primary>jot</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>jot</secondary>
</indexterm>
<indexterm>
<primary>seq</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>seq</secondary>
</indexterm>
<indexterm>
<primary>loop</primary>
<secondary>arguments</secondary>
</indexterm>
<listitem>
<para>These utilities emit a sequence of integers, with a
2002-04-01 16:04:17 +00:00
user-selected increment.</para>
<para>The normal separator character between each integer is a
newline, but this can be changed with the <option>-s</option>
option.</para>
<para>
<screen>
<prompt>bash$ </prompt><userinput>seq 5</userinput>
<computeroutput>1
2
3
4
5</computeroutput>
<prompt>bash$ </prompt><userinput>seq -s : 5</userinput>
<computeroutput>1:2:3:4:5</computeroutput>
</screen>
</para>
<para>Both <command>jot</command> and <command>seq</command>
come in handy in a <link linkend="forloopref1">for
loop</link>.</para>
2001-07-10 14:25:50 +00:00
<example id="ex53">
<title>Using <command>seq</command> to generate loop arguments</title>
<programlisting>&ex53;</programlisting>
</example>
</listitem>
</varlistentry>
2002-06-03 14:35:48 +00:00
<varlistentry>
<term><anchor id="getopty"><command>getopt</command></term>
<indexterm>
<primary>getopt</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>option</secondary>
</indexterm>
<listitem>
<para>The <command>getopt</command> command
parses command-line options preceded by a <link
linkend="dashref">dash</link>. This external command
corresponds to the <link linkend="getoptsx">getopts</link>
Bash builtin, but it is not nearly as flexible.</para>
<example id="ex33a">
<title>Using <command>getopt</command> to parse command-line
options</title>
<programlisting>&ex33a;</programlisting>
</example>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><anchor id="runpartsref"><command>run-parts</command></term>
<indexterm>
<primary>run-parts</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>run-parts</secondary>
</indexterm>
<listitem>
<para>The <command>run-parts</command> command
<footnote><para>This is actually a script adapted from
the Debian Linux distribution.</para></footnote>
2001-10-15 14:21:41 +00:00
executes all the scripts in a target directory, sequentially
in ASCII-sorted filename order. Of course, the scripts
need to have execute permission.</para>
<para>The <link linkend="cronref">crond</link> <link
linkend="daemonref">daemon</link> invokes
2001-09-04 13:27:31 +00:00
<command>run-parts</command> to run the scripts in
the <filename class="directory">/etc/cron.*</filename>
directories.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>yes</command></term>
<indexterm>
<primary>yes</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>yes</secondary>
</indexterm>
<listitem>
<para>In its default behavior the <command>yes</command>
command feeds a continuous string of the character
<computeroutput>y</computeroutput> followed
by a line feed to <filename>stdout</filename>. A
<keycombo><keycap>control</keycap><keycap>c</keycap></keycombo>
terminates the run. A different output string
may be specified, as in <userinput>yes different
string</userinput>, which would continually output
<computeroutput>different string</computeroutput> to
<filename>stdout</filename>. One might well ask the purpose
of this. From the command line or in a script, the output
of <command>yes</command> can be redirected or piped into a
program expecting user input. In effect, this becomes a sort
of poor man's version of <command>expect</command>.</para>
<para><userinput>yes | fsck /dev/hda1</userinput> runs
<command>fsck</command> non-interactively (careful!).</para>
<para><userinput>yes | rm -r dirname</userinput> has same effect as
<userinput>rm -rf dirname</userinput> (careful!).</para>
<warning><para>Be very cautious when piping <command>yes</command>
to a potentially dangerous system command, such as
<link linkend="fsckref">fsck</link> or
<link linkend="fdiskref">fdisk</link>.</para></warning>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>banner</command></term>
<indexterm>
<primary>banner</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>banner</secondary>
</indexterm>
<listitem>
<para>Prints arguments as a large vertical banner to
<filename>stdout</filename>, using an ASCII character
(default '#'). This may be redirected to a printer for
hardcopy.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>printenv</command></term>
<indexterm>
<primary>printenv</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>environment</secondary>
</indexterm>
<listitem>
2002-06-03 14:35:48 +00:00
<para>Show all the <link linkend="envref">environmental
variables</link> set for a particular user.</para>
2001-07-10 14:25:50 +00:00
<para>
<screen><prompt>bash$ </prompt><userinput>printenv | grep HOME</userinput>
<computeroutput>HOME=/home/bozo</computeroutput>
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>lp</command></term>
<indexterm>
<primary>lp</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>lpr</secondary>
</indexterm>
<listitem>
<para>The <command>lp</command> and <command>lpr</command>
commands send file(s) to the print queue, to be printed as
hard copy.
<footnote><para>The <emphasis>print queue</emphasis> is
the group of jobs <quote>waiting in line</quote> to be
printed.</para></footnote>
These commands trace the origin of their names to the
line printers of another era.</para>
<para><prompt>bash$ </prompt><userinput>lp file1.txt</userinput>
or <prompt>bash </prompt><userinput>lp
&lt;file1.txt</userinput></para>
<para>It is often useful to pipe the formatted output from
<command>pr</command> to <command>lp</command>.</para>
<para><prompt>bash$ </prompt><userinput>pr -options file1.txt | lp</userinput>
</para>
<para>Formatting packages, such as <command>groff</command> and
<emphasis>Ghostscript</emphasis> may send their output
directly to <command>lp</command>.</para>
<para><prompt>bash$ </prompt><userinput>groff -Tascii file.tr | lp</userinput>
</para>
<para><prompt>bash$ </prompt><userinput>gs -options | lp file.ps</userinput>
</para>
<para>Related commands are <command>lpq</command>, for viewing
the print queue, and <command>lprm</command>, for removing
jobs from the print queue.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>tee</command></term>
<indexterm>
<primary>tee</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>tee</secondary>
</indexterm>
<listitem>
<para>[UNIX borrows an idea here from the plumbing trade.]</para>
<para>This is a redirection operator, but with a difference. Like the
plumber's <emphasis>tee</emphasis>, it permits <quote>siponing
off</quote> the output of a command
or commands within a pipe, but without affecting the result. This is
useful for printing an ongoing process to a file or paper, perhaps to
keep track of it for debugging purposes.</para>
<screen>
tee
|------> to file
|
===============|===============
command--->----|-operator-->---> result of command(s)
===============================
</screen>
<para><programlisting>cat listfile* | sort | tee check.file | uniq > result.file</programlisting>
(The file <filename>check.file</filename> contains
the concatenated sorted <quote>listfiles</quote>,
before the duplicate lines are removed by <link
linkend="uniqref">uniq</link>.)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>mkfifo</command></term>
<indexterm>
<primary>mkfifo</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>mkfifo</secondary>
</indexterm>
<listitem>
<para><anchor id="namedpiperef">This obscure command
creates a <emphasis>named pipe</emphasis>, a temporary
<emphasis>first-in-first-out buffer</emphasis> for
transferring data between processes.
<footnote><para>For an excellent overview of this
topic, see Andy Vaught's article, <ulink
url="http://www2.linuxjournal.com/lj-issues/issue41/2156.html">Introduction
to Named Pipes</ulink>, in the September, 1997 issue
of <ulink url="http://www.linuxjournal.com">Linux
Journal</ulink>.</para></footnote>
Typically, one process writes to the FIFO, and the other
reads from it. See <xref linkend="fifo">.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>pathchk</command></term>
<indexterm>
<primary>pathchk</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>pathchk</secondary>
</indexterm>
<listitem>
<para>This command checks the validity of a filename. If the
filename exceeds the maximum allowable length (255
characters) or one or more of the directories in
its path is not searchable, then an error message
results. Unfortunately, <command>pathchk</command> does
not return a recognizable error code, and it is therefore
pretty much useless in a script.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="ddref"><command>dd</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>dd</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>dd</secondary>
</indexterm>
<listitem>
<para>This is the somewhat obscure and much feared <quote>data
duplicator</quote> command. Originally a utility
for exchanging data on magnetic tapes between UNIX
minicomputers and IBM mainframes, this command still
has its uses. The <command>dd</command> command simply
copies a file (or <filename>stdin/stdout</filename>), but
with conversions. Possible conversions are ASCII/EBCDIC,
2001-09-04 13:27:31 +00:00
2001-10-15 14:21:41 +00:00
<footnote><para>EBCDIC (pronounced
2001-09-04 13:27:31 +00:00
<quote>ebb-sid-ic</quote>) is an acronym for Extended
Binary Coded Decimal Interchange Code. This is an IBM
data format no longer in much use. A bizarre
application of the <option>conv=ebcdic</option> option
of <command>dd</command> is as a quick 'n easy, but
not very secure text file encoder.
<programlisting>cat $file | dd conv=swab,ebcdic > $file_encrypted
# Encode (looks like gibberish).
# Might as well switch bytes (swab), too, for a little extra obscurity.
cat $file_encrypted | dd conv=swab,ascii > $file_plaintext
# Decode.</programlisting>
</para></footnote>
2001-07-10 14:25:50 +00:00
upper/lower case, swapping of byte pairs between input
and output, and skipping and/or truncating the head or
tail of the input file. A <userinput>dd --help</userinput>
lists the conversion and other options that this powerful
utility takes.</para>
<para><programlisting># Exercising 'dd'.
n=3
p=5
input_file=project.txt
output_file=log.txt
dd if=$input_file of=$output_file bs=1 skip=$((n-1)) count=$((p-n+1)) 2> /dev/null
# Extracts characters n to p from file $input_file.
echo -n "hello world" | dd cbs=1 conv=unblock 2> /dev/null
# Echoes "hello world" vertically.
# Thanks, S.C.</programlisting></para>
<para>To demonstrate just how versatile <command>dd</command> is,
let's use it to capture keystrokes.</para>
<example id="ddkeypress">
<title>Capturing Keystrokes</title>
<programlisting>&ddkeypress;</programlisting>
</example>
<para>The <command>dd</command> command can do random access on a
data stream.
<programlisting>echo -n . | dd bs=1 seek=4 of=file conv=notrunc
# The "conv=notrunc" option means that the output file will not be truncated.
# Thanks, S.C.</programlisting>
</para>
<para>The <command>dd</command> command can copy raw data
and disk images to and from devices, such as floppies and
tape drives (<xref linkend="copycd">). A common use is
2002-01-07 15:24:19 +00:00
creating boot floppies.</para>
<para>
<userinput>dd if=kernel-image of=/dev/fd0H1440</userinput>
</para>
<para>Similarly, <command>dd</command> can copy the entire
contents of a floppy, even one formatted with a
<quote>foreign</quote> OS, to the hard drive as an
image file.</para>
<para>
<userinput>dd if=/dev/fd0 of=/home/bozo/projects/floppy.img</userinput>
</para>
<para>
2001-10-15 14:21:41 +00:00
Other applications of <command>dd</command> include
initializing temporary swap files (<xref linkend="ex73">)
and ramdisks (<xref linkend="ramdisk">). It can even do a
low-level copy of an entire hard drive partition, although
this is not necessarily recommended.</para>
2001-09-04 13:27:31 +00:00
<para>People (with presumably nothing better to do with
their time) are constantly thinking of interesting
applications of <command>dd</command>.</para>
<example id="blotout">
<title>Securely deleting a file</title>
<programlisting>&blotout;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="odref"><command>od</command></term>
<indexterm>
<primary>od</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>od</secondary>
</indexterm>
<listitem>
<para>The <command>od</command>, or <emphasis>octal
2001-10-15 14:21:41 +00:00
dump</emphasis> filter converts input (or files) to octal
2001-07-10 14:25:50 +00:00
(base-8) or other bases. This is useful for viewing or
processing binary data files or otherwise unreadable system
device files, such as <filename>/dev/urandom</filename>,
and as a filter for binary data. See <xref
linkend="seedingrandom"> and <xref linkend="rnd">.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>hexdump</command></term>
<indexterm>
<primary>hexdump</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>hexadecimal</secondary>
</indexterm>
<listitem>
<para>Performs a hexadecimal, octal, decimal, or ASCII
dump of a binary file. This command is the rough equivalent
of <command>od</command>, above, but not nearly as
useful.</para>
</listitem>
</varlistentry>
2002-06-17 13:17:07 +00:00
<varlistentry>
<term><command>mcookie</command></term>
<indexterm>
<primary>magic</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>cookie</secondary>
</indexterm>
<listitem>
<para>This command generates a <quote>magic cookie</quote>, a
128-bit (32-character) pseudorandom hexadecimal number,
normally used as an authorization <quote>signature</quote>
by the X server. This also available for use in a script as
a <quote>quick 'n dirty</quote> random number.
<programlisting>random000=`mcookie | sed -e '2p'`
# Uses 'sed' to strip off extraneous characters.</programlisting>
</para>
<para>Of course, a script could use <link
linkend="md5sumref">md5</link> for the same purpose.
<programlisting># Generate md5 checksum on the script itself.
random001=`md5sum $0 | awk '{print $1}'`
# Uses 'awk' to strip off the filename.</programlisting>
</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>m4</command></term>
<indexterm>
<primary>m4</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>macro</secondary>
</indexterm>
<listitem>
<para>A hidden treasure, <command>m4</command> is a
2002-04-01 16:04:17 +00:00
powerful macro processing filter,
2001-10-15 14:21:41 +00:00
<footnote><para>A <emphasis>macro</emphasis> is a
symbolic constant that expands into a command string
or a set of operations on parameters.</para></footnote>
2002-06-03 14:35:48 +00:00
virtually a complete language. Although
originally written as a pre-processor for
<emphasis>RatFor</emphasis>, <command>m4</command>
turned out to be useful as a stand-alone utility. In
fact, <command>m4</command> combines some of the
2001-10-15 14:21:41 +00:00
functionality of <link linkend="evalref">eval</link>,
<link linkend="trref">tr</link>, and <link
2002-04-01 16:04:17 +00:00
linkend="awkref">awk</link>, in addition to its extensive
macro expansion facilities.</para>
<para>The April, 2002 issue of <emphasis>Linux
Journal</emphasis> has a very nice article on
<command>m4</command> and its uses.</para>
2001-10-15 14:21:41 +00:00
<example id="m4">
<title>Using m4</title>
<programlisting>&m4;</programlisting>
</example>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- End Miscellaneous Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- External Filters, Programs and Commands -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="system">
<title>System and Administrative Commands</title>
2001-07-10 14:25:50 +00:00
<para>The startup and shutdown scripts in
<filename class="directory">/etc/rc.d</filename> illustrate the uses
(and usefulness) of many of these comands. These are usually
invoked by root and used for system maintenance or emergency
filesystem repairs. Use with caution, as some of these commands
may damage your system if misused.</para>
2001-09-04 13:27:31 +00:00
<variablelist id="usersgroups">
<title><anchor id="usersgroups1">Users and Groups</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>chown</command></term>
<term><command>chgrp</command></term>
<indexterm>
<primary>chown</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>chown</secondary>
</indexterm>
<indexterm>
<primary>chgrp</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>chgrp</secondary>
</indexterm>
<listitem>
<para>The <command>chown</command> command changes the
ownership of a file or files. This command is a useful
method that <replaceable>root</replaceable> can use to
shift file ownership from one user to another. An ordinary
user may not change the ownership of files, not even her
own files.
<footnote><para>This is the case on a Linux machine or a UNIX
system with disk quotas.</para></footnote>
</para>
<para>
<screen><prompt>root# </prompt><userinput>chown bozo *.txt</userinput>
<computeroutput></computeroutput>
</screen>
</para>
<para>The <command>chgrp</command> command changes the
<replaceable>group</replaceable> ownership of a file or
files. You must be owner of the file(s) as well as a member
of the destination group (or <replaceable>root</replaceable>)
to use this operation.
<programlisting>chgrp --recursive dunderheads *.data
2001-10-15 14:21:41 +00:00
# The "dunderheads" group will now own all the "*.data" files
#+ all the way down the $PWD directory tree (that's what "recursive" means).
2001-07-10 14:25:50 +00:00
</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>useradd</command></term>
<term><command>userdel</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>useradd</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>useradd</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>userdel</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>userdel</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>The <command>useradd</command> administrative command
adds a user account to the system and creates a home
directory for that particular user, if so specified. The
corresponding <command>userdel</command> command removes
a user account from the system
<footnote><para>The <command>userdel</command> command
will fail if the particular user being deleted is
still logged on.</para></footnote>
and deletes associated files.</para>
<note><para>The <command>adduser</command> command is a synonym
for <command>useradd</command> and is usually a symbolic link to
it.</para></note>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><anchor id="idref"><command>id</command></term>
<indexterm>
<primary>id</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>id</secondary>
</indexterm>
<listitem>
<para>The <command>id</command> command lists the real and
effective user IDs and the group IDs of
the current user. This is the counterpart
to the <link linkend="uidref">$UID</link>,
<link linkend="euidref">$EUID</link>, and <link
linkend="groupsref">$GROUPS</link> internal Bash
variables.</para>
<screen><prompt>bash$ </prompt><userinput>id</userinput>
<computeroutput>uid=501(bozo) gid=501(bozo) groups=501(bozo),22(cdrom),80(cdwriter),81(audio)</computeroutput>
<prompt>bash$ </prompt><userinput>echo $UID</userinput>
<computeroutput>501</computeroutput></screen>
2001-09-04 13:27:31 +00:00
<para>Also see <xref linkend="amiroot">.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="whoref"><command>who</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>who</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>whoami</secondary>
</indexterm>
<listitem>
<para>Show all users logged on to the system.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>who</userinput>
<computeroutput>bozo tty1 Apr 27 17:45
bozo pts/0 Apr 27 17:46
bozo pts/1 Apr 27 17:47
bozo pts/2 Apr 27 17:49
</computeroutput>
</screen>
</para>
<para>The <option>-m</option> gives detailed information about
only the current user. Passing any two arguments to
<command>who</command> is the equivalent of <command>who
-m</command>, as in <command>who am i</command> or <command>who
The Man</command>.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>who -m</userinput>
<computeroutput>localhost.localdomain!bozo pts/2 Apr 27 17:49</computeroutput>
</screen>
</para>
<para><anchor id="whoamiref"><command>whoami</command> is similar to <command>who
-m</command>, but only lists the user name.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>whoami</userinput>
<computeroutput>bozo</computeroutput>
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>w</command></term>
<indexterm>
<primary>w</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>w</secondary>
</indexterm>
<listitem>
<para>Show all logged on users and the processes belonging to them. This is
an extended version of <command>who</command>. The output of <command>w</command>
may be piped to <command>grep</command> to find a specific user and/or process.</para>
<screen><prompt>bash$ </prompt><userinput>w | grep startx</userinput>
<computeroutput>bozo tty1 - 4:22pm 6:41 4.47s 0.45s startx</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term><command>logname</command></term>
<indexterm>
<primary>logname</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>logname</secondary>
</indexterm>
<listitem>
<para>Show current user's login name (as found in
<filename>/var/run/utmp</filename>). This is a
near-equivalent to <link linkend="whoamiref">whoami</link>,
above.</para>
<screen><prompt>bash$ </prompt><userinput>logname</userinput>
<computeroutput>bozo</computeroutput>
<prompt>bash$ </prompt><userinput>whoami</userinput>
<computeroutput>bozo</computeroutput></screen>
<para>However...</para>
<screen><prompt>bash$ </prompt><userinput>su</userinput>
<computeroutput>Password: ......</computeroutput>
<prompt>bash# </prompt><userinput>whoami</userinput>
<computeroutput>root</computeroutput>
<prompt>bash# </prompt><userinput>logname</userinput>
<computeroutput>bozo</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="suref"><command>su</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>su</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>su</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Runs a program or script as a
2002-04-01 16:04:17 +00:00
<emphasis>s</emphasis>ubstitute <emphasis>u</emphasis>ser.
<command>su rjones</command> starts a shell as user
<emphasis>rjones</emphasis>. A naked <command>su</command>
defaults to <emphasis>root</emphasis>. See <xref
linkend="fifo">.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>sudo</command></term>
<indexterm>
<primary>sudo</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>sudo</secondary>
</indexterm>
<listitem>
<para>Runs a command as root (or another user). This may
be used in a script, thus permitting a regular user to
run the script.</para>
<para><programlisting>#!/bin/bash
# Some commands.
sudo cp /root/secretfile /home/bozo/secret
# Some more commands.</programlisting></para>
<para>The file <filename>/etc/sudoers</filename> holds
the names of users permitted to invoke
<command>sudo</command>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>users</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>users</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>users</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Show all logged on users. This is the approximate
equivalent of <command>who -q</command>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>ac</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>ac</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>accounting</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Show users' logged in time, as read from
<filename>/var/log/wtmp</filename>. This is one of the GNU
accounting utilities.</para>
<screen><prompt>bash$ </prompt><userinput>ac</userinput>
<computeroutput> total 68.08</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>last</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>last</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>logged in</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>List <emphasis>last</emphasis> logged in users, as read from
<filename>/var/log/wtmp</filename>. This command can also
show remote logins.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>groups</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>groups</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>groups</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Lists the current user and the groups she belongs to.
This corresponds to the <link
linkend="groupsref">$GROUPS</link> internal variable,
but gives the group names, rather than the numbers.</para>
<screen><prompt>bash$ </prompt><userinput>groups</userinput>
<computeroutput>bozita cdrom cdwriter audio xgrp</computeroutput>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<prompt>bash$ </prompt><userinput>echo $GROUPS</userinput>
<computeroutput>501</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>newgrp</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>newgrp</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>group</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Change user's group ID without logging out. This permits
access to the new group's files. Since users may be
members of multiple groups simultaneously, this command
finds little use.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="terminalssys">
<title><anchor id="terminalssys1">Terminals</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>tty</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>tty</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>tty</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Echoes the name of the current user's terminal.
Note that each separate xterm window counts as a different
terminal.</para>
<screen><prompt>bash$ </prompt><userinput>tty</userinput>
<computeroutput>/dev/pts/1</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="sttyref"><command>stty</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>stty</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>stty</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Shows and/or changes terminal settings. This complex
command, used in a script, can control terminal behavior
and the way output displays. See the info page, and study
it carefully.</para>
<example id="erase">
<title>setting an erase character</title>
<programlisting>&erase;</programlisting>
</example>
<example id="secretpw">
<title><command>secret password</command>:
Turning off terminal echoing </title>
<programlisting>&secretpw;</programlisting>
</example>
<para>A creative use of <command>stty</command> is detecting a
user keypress (without hitting
<keycap>ENTER</keycap>).</para>
<example id="keypress">
<title>Keypress detection</title>
<programlisting>&keypress;</programlisting>
</example>
<para>Also see <xref linkend="timeout">.</para>
<sidebar><title>terminals and modes</title>
<para>Normally, a terminal works in the
<emphasis>canonical</emphasis> mode. When a user hits a
key, the resulting character does not immediately go to
the program actually running in this terminal. A buffer
local to the terminal stores keystrokes. When the user
hits the <keycap>ENTER</keycap> key, this sends all the
stored keystrokes to the program running. There is even
a basic line editor inside the terminal.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>stty -a</userinput>
<computeroutput>speed 9600 baud; rows 36; columns 96; line = 0;
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = &lt;undef&gt;; eol2 = &lt;undef&gt;;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O;
...
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt</computeroutput>
</screen>
</para>
<para>Using canonical mode, it is possible to redefine the
special keys for the local terminal line editor.
<screen>
<prompt>bash$ </prompt><userinput>cat > filexxx</userinput>
<userinput>wha&lt;ctl-W&gt;I&lt;ctl-H&gt;foo bar&lt;ctl-U&gt;hello world&lt;ENTER&gt;</userinput>
<userinput>&lt;ctl-D&gt;</userinput>
<prompt>bash$ </prompt><userinput>cat filexxx</userinput>
<computeroutput>hello world</computeroutput>
<prompt>bash$ </prompt><userinput>bash$ wc -c < file</userinput>
<computeroutput>13</computeroutput>
</screen>
The process controlling the terminal receives only 13
characters (12 alphabetic ones, plus a newline), although
the user hit 26 keys.
</para>
<para>In non-canonical (<quote>raw</quote>) mode, every
key hit (including special editing keys such as
<keycap>ctl-H</keycap>) sends a character immediately to
the controlling process.</para>
<para>The Bash prompt disables both <option>icanon</option>
and <option>echo</option>, since it replaces the basic
terminal line editor with its own more elaborate one. For
example, when you hit <keycap>ctl-A</keycap> at the Bash
prompt, there's no <keycap>^A</keycap> echoed by the
terminal, but Bash gets a <keycap>\1</keycap> character,
interprets it, and moves the cursor to the begining of
the line.</para>
<para><emphasis>Stephane Chazelas</emphasis></para>
</sidebar>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>tset</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>tset</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>tset</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Show or initialize terminal settings.
This is a less capable version of
<command>stty</command>.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>tset -r</userinput>
<computeroutput>Terminal type is xterm-xfree86.
Kill is control-U (^U).
Interrupt is control-C (^C).</computeroutput>
</screen>
</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>setserial</command></term>
<indexterm>
<primary>setserial</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>serial</secondary>
</indexterm>
<listitem>
<para>Set or display serial port parameters. This command must be
run by root user and is usually found in a system setup
script.</para>
<para><programlisting># From /etc/pcmcia/serial script:
IRQ=`setserial /dev/$DEVICE | sed -e 's/.*IRQ: //'`
setserial /dev/$DEVICE irq 0 ; setserial /dev/$DEVICE irq $IRQ</programlisting></para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>getty</command></term>
<term><command>agetty</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>getty</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>getty</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>agetty</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>agetty</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>The initialization process for a terminal uses
<command>getty</command> or <command>agetty</command>
to set it up for login by a user. These commands are not
used within user shell scripts. Their scripting counterpart
is <command>stty</command>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="mesgref"><command>mesg</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>mesg</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>mesg</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Enables or disables write access to the current user's
terminal. Disabling access would prevent another user
on the network to <link linkend="writeref">write</link>
to the terminal.</para>
<tip><para>It can be very annoying to have a message
about ordering pizza suddenly appear in the middle of
the text file you are editing. On a multi-user network,
you might therefore wish to disable write access to your
terminal when you need to avoid interruptions.</para></tip>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>wall</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>wall</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>wall</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>This is an acronym for <quote><link
linkend="writeref">write</link> all</quote>, i.e., sending
a message to all users at every terminal logged into the
network. It is primarily a system administrator's tool,
useful, for example, when warning everyone that the
system will shortly go down due to a problem (see <xref
linkend="ex70">).</para>
<para>
<screen><prompt>bash$ </prompt><userinput>wall System going down for maintenance in 5 minutes!</userinput>
<computeroutput>Broadcast message from bozo (pts/1) Sun Jul 8 13:53:27 2001...
System going down for maintenance in 5 minutes!</computeroutput>
</screen>
</para>
<note><para>If write access to a particular terminal has been
disabled with <command>mesg</command>, then
<command>wall</command> cannot send a message to
it.</para></note>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>dmesg</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>dmesg</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>dmesg</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Lists all system bootup messages to
<filename>stdout</filename>. Handy for debugging and
ascertaining which device drivers were installed
and which system interrupts in use. The output
of <command>dmesg</command> may, of course, be
parsed with <link linkend="grepref">grep</link>,
<link linkend="sedref">sed</link>, or <link
linkend="awkref">awk</link> from within a script.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="statisticssys">
<title><anchor id="statisticssys1">Information and Statistics</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>uname</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>uname</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>uname</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Output system specifications (OS, kernel version,
etc.) to <filename>stdout</filename>. Invoked with the
<option>-a</option> option, gives verbose system info
2001-10-15 14:21:41 +00:00
(see <xref linkend="ex41">). The <option>-s</option>
option shows only the OS type.</para>
2001-09-04 13:27:31 +00:00
<screen><prompt>bash$ </prompt><userinput>uname -a</userinput>
2001-10-15 14:21:41 +00:00
<computeroutput>Linux localhost.localdomain 2.2.15-2.5.0 #1 Sat Feb 5 00:13:43 EST 2000 i686 unknown</computeroutput>
<prompt>bash$ </prompt><userinput>uname -s</userinput>
<computeroutput>Linux</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>arch</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>arch</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>arch</secondary>
</indexterm>
<listitem>
<para>Show system architecture.
Equivalent to <command>uname -m</command>. See <xref
linkend="casecmd">.</para>
<screen><prompt>bash$ </prompt><userinput>arch</userinput>
<computeroutput>i686</computeroutput>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<prompt>bash$ </prompt><userinput>uname -m</userinput>
<computeroutput>i686</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>lastcomm</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>lastcomm</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>last</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2002-01-07 15:24:19 +00:00
<para>Gives information about previous commands, as stored
2001-09-04 13:27:31 +00:00
in the <filename>/var/account/pacct</filename> file. Command
name and user name can be specified by options. This is
one of the GNU accounting utilities.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2002-01-07 15:24:19 +00:00
<varlistentry>
<term><command>lastlog</command></term>
<indexterm>
<primary>lastlog</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>last</secondary>
</indexterm>
<listitem>
<para>List the last login time of all system users. This
references the <filename>/var/log/lastlog</filename>
file.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>lastlog</userinput>
<computeroutput>root tty1 Fri Dec 7 18:43:21 -0700 2001
bin **Never logged in**
daemon **Never logged in**
...
bozo tty1 Sat Dec 8 21:14:29 -0700 2001</computeroutput>
<prompt>bash$ </prompt><userinput>lastlog | grep root</userinput>
<computeroutput>root tty1 Fri Dec 7 18:43:21 -0700 2001</computeroutput>
</screen>
</para>
<caution><para>This command will fail if the user invoking
it does not have read permission for the
<filename>/var/log/lastlog</filename> file.</para></caution>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>lsof</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>lsof</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>lsof</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>List open files. This command outputs a detailed
table of all currently open files and gives information
about their owner, size, the processes associated with
them, and more. Of course, <command>lsof</command> may
be piped to <link linkend="grepref">grep</link> and/or
<link linkend="awkref">awk</link> to parse and analyze
its results.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>lsof</userinput>
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
init 1 root mem REG 3,5 30748 30303 /sbin/init
init 1 root mem REG 3,5 73120 8069 /lib/ld-2.1.3.so
init 1 root mem REG 3,5 931668 8075 /lib/libc-2.1.3.so
cardmgr 213 root mem REG 3,5 36956 30357 /sbin/cardmgr
...</computeroutput>
</screen>
</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>strace</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>strace</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>strace</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Diagnostic and debugging tool for tracing system
calls and signals. The simplest way of invoking it is
<command>strace COMMAND</command>.</para>
2001-07-10 14:25:50 +00:00
<para>
2001-09-04 13:27:31 +00:00
<screen><prompt>bash$ </prompt><userinput>strace df</userinput>
<computeroutput>execve("/bin/df", ["df"], [/* 45 vars */]) = 0
uname({sys="Linux", node="bozo.localdomain", ...}) = 0
brk(0) = 0x804f5e4
...</computeroutput>
</screen>
2001-07-10 14:25:50 +00:00
</para>
2001-09-04 13:27:31 +00:00
<para>This is the Linux equivalent of
<command>truss</command>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="freeref"><command>free</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>free</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>free</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Shows memory and cache usage in tabular form. The
output of this command lends itself to parsing, using
<link linkend="grepref">grep</link>, <link
linkend="awkref">awk</link> or <command>Perl</command>. The
<command>procinfo</command> command shows all the
information that <command>free</command> does, and much
more.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<screen><prompt>bash$ </prompt><command>free</command>
<computeroutput> total used free shared buffers cached
Mem: 30504 28624 1880 15820 1608 16376
-/+ buffers/cache: 10640 19864
Swap: 68540 3128 65412</computeroutput></screen>
<para>To show unused RAM memory:</para>
<screen><prompt>bash$ </prompt><command>free | grep Mem | awk '{ print $4 }'</command>
<computeroutput>1880</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="procinforef"><command>procinfo</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>procinfo</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>procinfo</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem>
<para>Extract and list information and statistics from the
<link linkend="devprocref"><filename
class="directory">/proc</filename>
pseudo-filesystem</link>. This gives a very extensive and
detailed listing.</para>
<screen><prompt>bash$ </prompt><userinput>procinfo | grep Bootup</userinput>
<computeroutput>Bootup: Wed Mar 21 15:15:50 2001 Load average: 0.04 0.21 0.34 3/47 6829</computeroutput>
</screen>
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="lsdevref"><command>lsdev</command></term>
<indexterm>
<primary>lsdev</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>device</secondary>
</indexterm>
<listitem>
<para>List devices, that is, show installed hardware.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>lsdev</userinput>
<computeroutput>Device DMA IRQ I/O Ports
------------------------------------------------
cascade 4 2
dma 0080-008f
dma1 0000-001f
dma2 00c0-00df
fpu 00f0-00ff
ide0 14 01f0-01f7 03f6-03f6
...</computeroutput>
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="duref"><command>du</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>du</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>du</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Show (disk) file usage, recursively. Defaults to current
working directory, unless otherwise specified.</para>
<screen><prompt>bash$ </prompt><command>du -ach</command>
<computeroutput>1.0k ./wi.sh
1.0k ./tst.sh
1.0k ./random.file
6.0k .
6.0k total</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="dfref"><command>df</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>df</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>df</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Shows filesystem usage in tabular form.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<screen><prompt>bash$ </prompt><command>df</command>
<computeroutput>Filesystem 1k-blocks Used Available Use% Mounted on
/dev/hda5 273262 92607 166547 36% /
/dev/hda8 222525 123951 87085 59% /home
/dev/hda7 1408796 1075744 261488 80% /usr</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>stat</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>stat</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>stat</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Gives detailed and verbose <emphasis>stat</emphasis>istics
on a given file (even a directory or device file) or set
of files.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>stat test.cru</userinput>
<computeroutput> File: "test.cru"
Size: 49970 Allocated Blocks: 100 Filetype: Regular File
Mode: (0664/-rw-rw-r--) Uid: ( 501/ bozo) Gid: ( 501/ bozo)
Device: 3,8 Inode: 18185 Links: 1
Access: Sat Jun 2 16:40:24 2001
Modify: Sat Jun 2 16:40:24 2001
Change: Sat Jun 2 16:40:24 2001</computeroutput>
</screen>
</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>If the target file does not exist, <command>stat</command>
returns an error message.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>
<screen><prompt>bash$ </prompt><userinput>stat nonexistent-file</userinput>
<computeroutput>nonexistent-file: No such file or directory</computeroutput>
2001-07-10 14:25:50 +00:00
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="vmstatref"><command>vmstat</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>vmstat</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>virtual memory</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Display virtual memory statistics.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>vmstat</userinput>
<computeroutput> procs memory swap io system cpu
r b w swpd free buff cache si so bi bo in cs us sy id
0 0 0 0 11040 2636 38952 0 0 33 7 271 88 8 3 89</computeroutput>
</screen>
</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>netstat</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>netstat</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>netstat</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2002-01-07 15:24:19 +00:00
<para>Show current network statistics and information,
2001-09-04 13:27:31 +00:00
such as routing tables and active connections. This utility
accesses information in <filename>/proc/net</filename>
(<xref linkend="devproc">). See <xref
linkend="constat">.</para>
2002-01-07 15:24:19 +00:00
<para><command>netstat -r</command> is equivalent to <link
linkend="routeref">route</link>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="uptimeref"><command>uptime</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>uptime</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>uptime</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Shows how long the system has been running, along with
associated statistics.</para>
<screen><prompt>bash$ </prompt><userinput>uptime</userinput>
<computeroutput>10:28pm up 1:57, 3 users, load average: 0.17, 0.34, 0.27</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="hnameref"><command>hostname</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>hostname</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>hostname</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Lists the system's host name. This command sets the host
name in an <filename class="directory">/etc/rc.d</filename>
setup script (<filename>/etc/rc.d/rc.sysinit</filename>
or similar). It is equivalent to <command>uname
-n</command>, and a counterpart to the <link
linkend="hostnameref">$HOSTNAME</link> internal
variable.</para>
<screen><prompt>bash$ </prompt><userinput>hostname</userinput>
<computeroutput>localhost.localdomain</computeroutput>
<prompt>bash$ </prompt><userinput>echo $HOSTNAME</userinput>
<computeroutput>localhost.localdomain</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="hostidref"><command>hostid</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>hostid</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>host id</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Echo a 32-bit hexadecimal numerical identifier for the
host machine.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>hostid</userinput>
<computeroutput>7f0100</computeroutput></screen>
</para>
<note>
<para>This command allegedly fetches a <quote>unique</quote>
serial number for a particular system. Certain
product registration procedures use this number
to brand a particular user license. Unfortunately,
<command>hostid</command> only returns the machine
network address in hexadecimal, with pairs of bytes
transposed.</para>
<para>The network address of a typical non-networked Linux
machine, is found in <filename>/etc/hosts</filename>.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>cat /etc/hosts</userinput>
<computeroutput>127.0.0.1 localhost.localdomain localhost</computeroutput>
</screen>
2001-07-10 14:25:50 +00:00
</para>
2001-09-04 13:27:31 +00:00
<para>As it happens, transposing the bytes of
<userinput>127.0.0.1</userinput>, we get
<userinput>0.127.1.0</userinput>, which translates in
hex to <userinput>007f0100</userinput>, the exact equivalent
of what <command>hostid</command> returns, above. There
exist only a few million other Linux machines with this
identical <emphasis>hostid</emphasis>.</para>
</note>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2002-01-07 15:24:19 +00:00
<varlistentry>
<term><command>sar</command></term>
<indexterm>
<primary>sar</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>system activity report</secondary>
</indexterm>
<listitem>
<para>Invoking <command>sar</command> (system activity report)
gives a very detailed rundown on system statistics.
This command is found on some commercial UNIX
systems, but is not part of the base Linux
distribution. It is contained in the <ulink
url="http://perso.wanadoo.fr/sebastien.godard/">
sysstat utilities</ulink> package, written by <ulink
url="mailto:sebastien.godard@wanadoo.fr">Sebastien
Godard</ulink>.</para>
<screen>
<prompt>bash$ </prompt><userinput>sar</userinput>
<computeroutput>Linux 2.4.7-10 (localhost.localdomain) 12/31/2001
10:30:01 AM CPU %user %nice %system %idle
10:40:00 AM all 1.39 0.00 0.77 97.84
10:50:00 AM all 76.83 0.00 1.45 21.72
11:00:00 AM all 1.32 0.00 0.69 97.99
11:10:00 AM all 1.17 0.00 0.30 98.53
11:20:00 AM all 0.51 0.00 0.30 99.19
06:30:00 PM all 100.00 0.00 100.01 0.00
Average: all 1.39 0.00 0.66 97.95</computeroutput>
</screen>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="syslog">
<title><anchor id="syslog1">System Logs</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>logger</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>logger</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>logger</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Appends a user-generated message to the system log
(<filename>/var/log/messages</filename>). You do not have
to be root to invoke <command>logger</command>.
<programlisting>logger Experiencing instability in network connection at 23:10, 05/21.
# Now, do a 'tail /var/log/messages'.</programlisting></para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>By embedding a <command>logger</command> command in a script,
it is possible to write debugging information to
<filename>/var/log/messages</filename>.
<programlisting>logger -t $0 -i Logging at line "$LINENO".
# The "-t" option specifies the tag for the logger entry.
# The "-i" option records the process ID.
# tail /var/log/message
# ...
# Jul 7 20:48:58 localhost ./test.sh[1712]: Logging at line 3.</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>logrotate</command></term>
<indexterm>
<primary>logrotate</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>logrotate</secondary>
</indexterm>
<listitem>
<para>This utility manages the system log files, rotating,
compressing, deleting, and/or mailing them, as appropriate.
2002-01-07 15:24:19 +00:00
Usually <link linkend="cronref">crond</link> runs
2001-09-04 13:27:31 +00:00
<command>logrotate</command> on a daily basis.</para>
<para>Adding an appropriate entry to
<filename>/etc/logrotate.conf</filename> makes it possible
to manage personal log files, as well as system-wide
ones.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="jobcontrolsys">
<title><anchor id="jobcontrolsys1">Job Control</title>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>ps</command></term>
<indexterm>
<primary>ps</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>ps</secondary>
</indexterm>
<listitem>
<para><replaceable>P</replaceable>rocess
<replaceable>S</replaceable>tatistics: lists currently
executing processes by owner and PID (process id). This
is usually invoked with <option>ax</option> options,
and may be piped to <link linkend="grepref">grep</link>
or <link linkend="sedref">sed</link> to search for a
specific process (see <xref linkend="ex44"> and <xref
linkend="pidid">).</para>
<screen><prompt>bash$ </prompt><userinput> ps ax | grep sendmail</userinput>
<computeroutput>295 ? S 0:00 sendmail: accepting connections on port 25</computeroutput></screen>
</listitem>
</varlistentry>
<varlistentry>
<term><command>pstree</command></term>
<indexterm>
<primary>pstree</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>pstree</secondary>
</indexterm>
<listitem>
<para>Lists currently executing processes in
<quote>tree</quote> format. The <option>-p</option> option
shows the PIDs, as well as the process names.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>top</command></term>
<indexterm>
<primary>top</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>processes</secondary>
</indexterm>
<listitem>
<para>Continuously updated display of most cpu-intensive
processes. The <option>-b</option> option displays in text
mode, so that the output may be parsed or accessed from
a script.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>top -b</userinput>
<computeroutput> 8:30pm up 3 min, 3 users, load average: 0.49, 0.32, 0.13
45 processes: 44 sleeping, 1 running, 0 zombie, 0 stopped
CPU states: 13.6% user, 7.3% system, 0.0% nice, 78.9% idle
Mem: 78396K av, 65468K used, 12928K free, 0K shrd, 2352K buff
Swap: 157208K av, 0K used, 157208K free 37244K cached
PID USER PRI NI SIZE RSS SHARE STAT %CPU %MEM TIME COMMAND
848 bozo 17 0 996 996 800 R 5.6 1.2 0:00 top
1 root 8 0 512 512 444 S 0.0 0.6 0:04 init
2 root 9 0 0 0 0 SW 0.0 0.0 0:00 keventd
...</computeroutput>
</screen>
</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>nice</command></term>
<indexterm>
<primary>nice</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>nice</secondary>
</indexterm>
<listitem>
<para>Run a background job with an altered
priority. Priorities run from 19 (lowest) to -20
(highest). Only <emphasis>root</emphasis> may set the
negative (higher) priorities. Related commands are
<command>renice</command>, <command>snice</command>,
and <command>skill</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>nohup</command></term>
<indexterm>
<primary>nohup</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>nohup</secondary>
</indexterm>
<listitem>
<para>Keeps a command running even after user logs off.
The command will run as a foreground process unless followed
by <token>&</token>. If you use <command>nohup</command>
within a script, consider coupling it with a <link
linkend="waitref">wait</link> to avoid creating an orphan
or zombie process.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><anchor id="pidofref"><command>pidof</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>pidof</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>process id</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Identifies <emphasis>process id (pid)</emphasis> of a
running job. Since job control commands, such as <link
linkend="killref">kill</link> and <command>renice</command>
act on the <emphasis>pid</emphasis> of a process (not
its name), it is sometimes necessary to identify that
<emphasis>pid</emphasis>. The <command>pidof</command>
command is the approximate counterpart to the <link
linkend="ppidref">$PPID</link> internal variable.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>pidof xclock</userinput>
<computeroutput>880</computeroutput>
</screen>
</para>
<example id="killprocess">
<title><command>pidof</command> helps kill a process</title>
<programlisting>&killprocess;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>fuser</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>fuser</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>fuser</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Identifies the processes (by pid) that are accessing
a given file, set of files, or directory. May also be
invoked with the <option>-k</option> option, which kills
those processes. This has interesting implications for
system security, especially in scripts preventing
unauthorized users from accessing system services.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="cronref"><command>crond</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>crond</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>cron</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Administrative program scheduler, performing such
duties as cleaning up and deleting system log
files and updating the <database>slocate</database>
database. This is the superuser version of <link
linkend="atref">at</link> (although each user may have their
own <filename>crontab</filename> file which can be changed
with the <command>crontab</command> command). It runs
as a <link linkend="daemonref">daemon</link> and executes
scheduled entries from <filename>/etc/crontab</filename>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="runcontrolsys">
<title><anchor id="runcontrolsys1">Process Control and Booting</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>init</command></term>
<indexterm>
<primary>init</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>init</secondary>
</indexterm>
<listitem>
<para>The <command>init</command> command is the <link
linkend="forkref">parent</link> of all processes. Called
in the final step of a bootup, <command>init</command>
determines the runlevel of the system from
<filename>/etc/inittab</filename>. Invoked by its alias
<command>telinit</command>, and by root only.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>telinit</command></term>
<indexterm>
<primary>telinit</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>telinit</secondary>
</indexterm>
<listitem>
<para>Symlinked to <command>init</command>, this is a means of changing the system runlevel,
usually done for system maintenance or emergency filesystem
repairs. Invoked only by root. This command can be dangerous - be
certain you understand it well before using!</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>runlevel</command></term>
<indexterm>
<primary>runlevel</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>runlevel</secondary>
</indexterm>
<listitem>
<para>Shows the current and last runlevel, that is, whether the system
is halted (runlevel <literal>0</literal>), in single-user mode
(<literal>1</literal>), in multi-user mode (<literal>2</literal>
or <literal>3</literal>), in X Windows (<literal>5</literal>), or
rebooting (<literal>6</literal>). This command accesses the
<filename>/var/run/utmp</filename> file.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>halt</command></term>
<term><command>shutdown</command></term>
<term><command>reboot</command></term>
<indexterm>
<primary>halt</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>halt</secondary>
</indexterm>
<indexterm>
<primary>shutdown</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>shutdown</secondary>
</indexterm>
<indexterm>
<primary>reboot</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>reboot</secondary>
</indexterm>
<listitem>
<para>Command set to shut the system down, usually just prior to a power down.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="networksys">
<title><anchor id="networksys1">Network</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>ifconfig</command></term>
<indexterm>
<primary>ifconfig</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>ifconfig</secondary>
</indexterm>
<listitem>
<para>Network interface configuration and tuning utility.
It is most often used at bootup to set up the interfaces,
or to shut them down when rebooting.
<programlisting># Code snippets from /etc/rc.d/init.d/network
# ...
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
[ -x /sbin/ifconfig ] || exit 0
# ...
for i in $interfaces ; do
if ifconfig $i 2>/dev/null | grep -q "UP" >/dev/null 2>&1 ; then
action "Shutting down interface $i: " ./ifdown $i boot
fi
2002-06-17 13:17:07 +00:00
# The GNU-specific "-q" option to "grep" means "quiet", i.e., producing no output.
2001-07-10 14:25:50 +00:00
# Redirecting output to /dev/null is therefore not strictly necessary.
# ...
echo "Currently active devices:"
echo `/sbin/ifconfig | grep ^[a-z] | awk '{print $1}'`
# ^^^^^ should be quoted to prevent globbing.
# The following also work.
# echo $(/sbin/ifconfig | awk '/^[a-z]/ { print $1 })'
# echo $(/sbin/ifconfig | sed -e 's/ .*//')
# Thanks, S.C., for additional comments.</programlisting>
See also <xref linkend="online">.</para>
</listitem>
</varlistentry>
<varlistentry>
2002-01-07 15:24:19 +00:00
<term><anchor id="routeref"><command>route</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>route</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>route</secondary>
</indexterm>
<listitem>
<para>Show info about or make changes to the kernel routing table.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>route</userinput>
2002-01-07 15:24:19 +00:00
<computeroutput>Destination Gateway Genmask Flags MSS Window irtt Iface
pm3-67.bozosisp * 255.255.255.255 UH 40 0 0 ppp0
127.0.0.0 * 255.0.0.0 U 40 0 0 lo
default pm3-67.bozosisp 0.0.0.0 UG 40 0 0 ppp0</computeroutput>
2001-07-10 14:25:50 +00:00
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><command>chkconfig</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-10-15 14:21:41 +00:00
<primary>chkconfig</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-10-15 14:21:41 +00:00
<secondary>network configuration</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-10-15 14:21:41 +00:00
<para>Check network configuration. This command lists and
manages the network services started at bootup in the
<filename class="directory">/etc/rc?.d</filename>
directory.</para>
<para>Originally a port from IRIX to Red Hat Linux,
<command>chkconfig</command> may not be part of the core
installation of some Linux flavors.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>chkconfig --list</userinput>
<computeroutput>atd 0:off 1:off 2:off 3:on 4:on 5:on 6:off
rwhod 0:off 1:off 2:off 3:off 4:off 5:off 6:off
...</computeroutput>
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>tcpdump</command></term>
<indexterm>
<primary>tcpdump</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>tcp</secondary>
</indexterm>
<listitem>
<para>Network packet <quote>sniffer</quote>. This is a tool for
analyzing and troubleshooting traffic on a network by dumping
packet headers that match specified criteria.</para>
<para>Dump ip packet traffic between hosts
<emphasis>bozoville</emphasis> and
<emphasis>caduceus</emphasis>:
<screen><prompt>bash$ </prompt><userinput>tcpdump ip host bozoville and caduceus</userinput>
</screen>
</para>
<para>Of course, the output of <command>tcpdump</command> can be
parsed, using certain of the previously discussed <link
linkend="tpcommandlisting1">text processing
utilities</link>.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
2001-10-15 14:21:41 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="filesystemsys">
<title><anchor id="filesystemsys1">Filesystem</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>mount</command></term>
<indexterm>
<primary>mount</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>mount</secondary>
</indexterm>
<listitem>
<para>Mount a filesystem, usually on an external device,
such as a floppy or CDROM. The file
<filename>/etc/fstab</filename> provides a handy listing
of available filesystems, partitions, and devices,
including options, that may be automatically or manually
mounted. The file <filename>/etc/mtab</filename> shows
the currently mounted filesystems and partitions
(including the virtual ones, such as <filename
class="directory">/proc</filename>).</para>
<para><command>mount -a</command> mounts all filesystems and
partitions listed in <filename>/etc/fstab</filename>,
except those with a <option>noauto</option>
option. At bootup, a startup script in
<filename class="directory">/etc/rc.d</filename>
(<filename>rc.sysinit</filename> or something similar)
invokes this to get everything mounted.</para>
<para><programlisting>mount -t iso9660 /dev/cdrom /mnt/cdrom
# Mounts CDROM
mount /mnt/cdrom
# Shortcut, if /mnt/cdrom listed in /etc/fstab</programlisting>
</para>
2001-10-15 14:21:41 +00:00
<para>This versatile command can even mount an ordinary file
on a block device, and the file will act as if it were a
filesystem. <command>Mount</command> accomplishes that by
2001-07-10 14:25:50 +00:00
associating the file with a <link linkend="loopbackref">loopback
2001-10-15 14:21:41 +00:00
device</link>. One application of this is to mount and examine
an ISO9660 image before burning it onto a CDR.
2001-07-10 14:25:50 +00:00
<footnote><para>For more detail on burning CDRs, see Alex
Withers' article, <ulink
url="http://www2.linuxjournal.com/lj-issues/issue66/3335.html">Creating
CDs</ulink>, in the October, 1999 issue of <ulink
url="http://www.linuxjournal.com">Linux
Journal</ulink>.</para></footnote>
</para>
<example id="isomountref">
<title>Checking a CD image</title>
<programlisting># As root...
mkdir /mnt/cdtest # Prepare a mount point, if not already there.
mount -r -t iso9660 -o loop cd-image.iso /mnt/cdtest # Mount the image.
# "-o loop" option equivalent to "losetup /dev/loop0"
cd /mnt/cdtest # Now, check the image.
ls -alR # List the files in the directory tree there.
# And so forth.</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
<term><command>umount</command></term>
<indexterm>
<primary>umount</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>umount</secondary>
</indexterm>
<listitem>
<para>Unmount a currently mounted filesystem. Before physically removing a
previously mounted floppy or CDROM disk, the device must be
<command>umount</command>ed, else filesystem corruption may result.
<programlisting>umount /mnt/cdrom
# You may now press the eject button and safely remove the disk.</programlisting></para>
<note><para>The <command>automount</command> utility, if
properly installed, can mount and unmount floppies or
CDROM disks as they are accessed or removed. On laptops
with swappable floppy and CDROM drives, this can cause
problems, though.</para></note>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><command>sync</command></term>
<indexterm>
<primary>sync</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>sync</secondary>
</indexterm>
<listitem>
<para>Forces an immediate write of all updated data from
buffers to hard drive (synchronize drive
with buffers). While not strictly necessary, a
<command>sync</command> assures the sys admin or
user that the data just changed will survive a sudden
power failure. In the olden days, a <userinput>sync;
sync</userinput> (twice, just to make absolutely sure) was a
useful precautionary measure before a system reboot.</para>
<para>At times, you may wish to force an immediate buffer
2001-10-15 14:21:41 +00:00
flush, as when securely deleting a file (see <xref
linkend="blotout">) or when the lights begin to
flicker.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="losetupref"><command>losetup</command></term>
<indexterm>
<primary>losetup</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>losetup</secondary>
</indexterm>
<listitem>
<para>Sets up and configures <link linkend="loopbackref">
loopback devices</link>.</para>
<example id="createfs">
<title>Creating a filesystem in a file</title>
<programlisting>SIZE=1000000 # 1 meg
head -c $SIZE < /dev/zero > file # Set up file of designated size.
losetup /dev/loop0 file # Set it up as loopback device.
mke2fs /dev/loop0 # Create filesystem.
mount -o loop /dev/loop0 /mnt # Mount it.
# Thanks, S.C.</programlisting>
</example>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>mkswap</command></term>
<indexterm>
<primary>mkswap</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>mkswap</secondary>
</indexterm>
<listitem>
<para>Creates a swap partition or file. The swap area must
subsequently be enabled with
<command>swapon</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>swapon</command></term>
<term><command>swapoff</command></term>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>swapon</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>swapon</secondary>
</indexterm>
<indexterm>
<primary>swapoff</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>swapoff</secondary>
</indexterm>
<listitem>
<para>Enable / disable swap partitition or file.
These commands usually take effect at bootup and
shutdown.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="mke2fsref"><command>mke2fs</command></term>
2001-09-04 13:27:31 +00:00
<indexterm>
<primary>mke2fs</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>mke2fs</secondary>
</indexterm>
<listitem>
2001-10-15 14:21:41 +00:00
<para>Create a Linux ext2 filesystem. This command must
be invoked as root.</para>
2001-09-04 13:27:31 +00:00
<example id="adddrv">
<title>Adding a new hard drive</title>
<programlisting>&adddrv;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<para>See also <xref linkend="createfs"> and <xref
linkend="ramdisk">.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><command>tune2fs</command></term>
<indexterm>
<primary>tune2fs</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>tune2fs</secondary>
</indexterm>
<listitem>
<para>Tune ext2 filesystem. May be used to change filesystem
parameters, such as maximum mount count. This must be
invoked as root.</para>
<warning><para>This is an extremely dangerous command. Use it at
your own risk, as you may inadvertently destroy your filesystem.
</para></warning>
</listitem>
</varlistentry>
<varlistentry>
<term><command>dumpe2fs</command></term>
<indexterm>
<primary>dumpe2fs</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>dumpe2fs</secondary>
</indexterm>
<listitem>
<para>Dump (list to <filename>stdout</filename>) very verbose
filesystem info. This must be invoked as root.</para>
<screen><prompt>root# </prompt><command>dumpe2fs /dev/hda7 | grep 'ount count'</command>
<computeroutput>dumpe2fs 1.19, 13-Jul-2000 for EXT2 FS 0.5b, 95/08/09
Mount count: 6
Maximum mount count: 20</computeroutput></screen>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>hdparm</command></term>
<indexterm>
<primary>hdparm</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>hard disk parameters</secondary>
</indexterm>
<listitem>
<para>List or change hard disk parameters. This command must be
invoked as root, and it may be dangerous if misused.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><anchor id="fdiskref"><command>fdisk</command></term>
<indexterm>
<primary>fdisk</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>fdisk</secondary>
</indexterm>
<listitem>
<para>Create or change a partition table on a storage device,
usually a hard drive. This command must be invoked as
root.</para>
<warning><para>Use this command with extreme caution. If something
goes wrong, you may destroy an existing
filesystem.</para></warning>
</listitem>
</varlistentry>
<varlistentry>
<term><anchor id="fsckref"><command>fsck</command></term>
<term><command>e2fsck</command></term>
<term><command>debugfs</command></term>
<indexterm>
<primary>fsck</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>fsck</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>e2fsck</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>e2fsck</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>debugfs</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>debugfs</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2002-04-01 16:04:17 +00:00
2001-09-04 13:27:31 +00:00
<para>Filesystem check, repair, and debug command set.</para>
2002-04-01 16:04:17 +00:00
2001-09-04 13:27:31 +00:00
<para><command>fsck</command>: a front end for checking a UNIX
filesystem (may invoke other utilities). The actual
filesystem type generally defaults to ext2.</para>
2002-04-01 16:04:17 +00:00
2001-09-04 13:27:31 +00:00
<para><command>e2fsck</command>: ext2 filesystem checker.</para>
2002-04-01 16:04:17 +00:00
<para><command>debugfs</command>: ext2 filesystem debugger.
One of the uses of this versatile, but dangerous command
is to (attempt to) recover deleted files. For advanced users
only!</para>
2001-09-04 13:27:31 +00:00
<caution><para>All of these should be invoked as root, and they
can damage or destroy a filesystem if misused.</para></caution>
2002-04-01 16:04:17 +00:00
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>badblocks</command></term>
<indexterm>
<primary>badblocks</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>badblocks</secondary>
</indexterm>
<listitem>
<para>Checks for bad blocks (physical media flaws) on a
storage device. This command finds use when formatting
a newly installed hard drive or testing the integrity
of backup media.
<footnote><para>The <option>-c</option> option to <link
linkend="mke2fsref">mke2fs</link> also invokes a check for bad
blocks.</para></footnote>
As an example, <command>badblocks /dev/fd0</command>
tests a floppy disk.</para>
<para>The <command>badblocks</command> command
may be invoked destructively (overwrite all data) or in
non-destructive read-only mode. If root user owns the
device to be tested, as is generally the case, then root
must invoke this command.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>mkbootdisk</command></term>
<indexterm>
<primary>mkbootdisk</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>bootdisk</secondary>
</indexterm>
<listitem>
<para>Creates a boot floppy which can be used to bring up the
system if, for example, the MBR (master boot record) becomes
corrupted. The <command>mkbootdisk</command> command is actually
a Bash script, written by Erik Troan, in the <filename
class="directory">/sbin</filename> directory.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>chroot</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>chroot</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>chroot</secondary>
</indexterm>
<indexterm>
<primary>directory</primary>
<secondary>root</secondary>
<tertiary>change</tertiary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>CHange ROOT directory. Normally commands are fetched
from <link linkend="pathref">$PATH</link>, relative to
<filename class="directory">/</filename>, the default root
directory. This changes the root directory to a different
one (and also changes the working directory to there).
This is useful for security purposes, for instance when
the system administrator wishes to restrict certain users,
such as those <link linkend="telnetref">telnetting</link>
in, to a secured portion of the filesystem (this
is sometimes referred to as confining a guest user
to a <quote>chroot jail</quote>). Note that after a
<command>chroot</command>, the execution path for system
binaries is no longer valid.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>A <userinput>chroot /opt</userinput> would cause
references to <filename
class="directory">/usr/bin</filename>
to be translated to <filename
class="directory">/opt/usr/bin</filename>. Likewise,
<userinput>chroot /aaa/bbb /bin/ls</userinput> would
redirect future instances of <command>ls</command>
to <filename>/aaa/bbb</filename> as the base directory,
rather than <filename class="directory">/</filename> as is
normally the case. An <command>alias XX 'chroot /aaa/bbb
ls'</command> in a user's <filename>~/.bashrc</filename>
effectively restricts which portion of the filesystem
she may run command <quote>XX</quote> on.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>The <command>chroot</command> command is also handy
when running from an emergency boot floppy
(<command>chroot</command> to <filename>/dev/fd0</filename>),
or as an option to <command>lilo</command> when recovering
from a system crash. Other uses include installation
from a different filesystem (an <command>rpm</command>
option) or running a readonly filesystem from a CD ROM.
Invoke only as root, and use with care.</para>
<caution><para>It might be necessary to copy certain system
files to a <emphasis>chrooted</emphasis> directory,
since the normal <varname>$PATH</varname> can no longer
be relied upon.</para></caution>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>lockfile</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>lockfile</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>lockfile</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>This utility is part of the <command>procmail</command>
package (<ulink url="http://www.procmail.org">www.procmail.org</ulink>).
It creates a <emphasis>lock file</emphasis>, a semaphore file that
controls access to a file, device, or resource. The lock file
serves as a flag that this particular file, device, or resource is
in use by a particular process (<quote>busy</quote>), and
this permits only restricted access (or no access) to other
processes.</para>
<para>Lock files are used in such applications as protecting
system mail folders from simultaneously being changed by multiple
users, indicating that a modem port is being accessed, and showing
that an instance of <application>Netscape</application> is using its
cache. Scripts may check for the existence of a lock file created
by a certain process to check if that process is running. Note
that if a script attempts create a lock file that already exists,
the script will likely hang.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>Normally, applications create and check for lock files
in the <filename class="directory">/var/lock</filename>
directory. A script can test for the presence of a lock file by
something like the following.
<programlisting>appname=xyzip
# Application "xyzip" created lock file "/var/lock/xyzip.lock".
if [ -e "/var/lock/$appname.lock ]
then
...</programlisting></para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>mknod</command></term>
<indexterm>
<primary>mknod</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>mknod</secondary>
</indexterm>
<listitem>
<para>Creates block or character device files (may be necessary when installing
new hardware on the system).</para>
</listitem>
</varlistentry>
2002-01-07 15:24:19 +00:00
<varlistentry>
<term><command>tmpwatch</command></term>
<indexterm>
<primary>tmpwatch</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>tmpwatch</secondary>
</indexterm>
<listitem>
<para>Automatically deletes files which have not been accessed
within a specified period of time. Usually invoked by
<link linkend="cronref">crond</link> to remove stale log
files.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>MAKEDEV</command></term>
<indexterm>
<primary>MAKEDEV</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>make device file</secondary>
</indexterm>
<listitem>
<para>Utility for creating device files. It must be run as root,
and in the <filename class="directory">/dev</filename>
directory.
<screen><prompt>root# </prompt><command>./MAKEDEV</command></screen>
This is a sort of advanced version of
<command>mknod</command>.</para>
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="periphsys">
<title><anchor id="periphsys1">Backup</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>dump</command></term>
<term><command>restore</command></term>
<indexterm>
<primary>dump</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>dump</secondary>
</indexterm>
<indexterm>
<primary>restore</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>restore</secondary>
</indexterm>
<listitem>
<para>The <command>dump</command> command is an elaborate
filesystem backup utility, generally used on larger
installations and networks.
<footnote><para>Operators of single-user Linux systems
generally prefer something simpler for backups, such
as <command>tar</command>.</para></footnote>
It reads raw disk partitions and writes a backup file
in a binary format. Files to be backed up may be saved
to a variety of storage media, including disks and tape
drives. The <command>restore</command> command restores
backups made with <command>dump</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>fdformat</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>fdformat</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>floppy</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Perform a low-level format on a floppy disk.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
<variablelist id="sysresources">
<title><anchor id="sysresources1">System Resources</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>ulimit</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>ulimit</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>ulimit</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<listitem>
<para>Sets an <emphasis>upper limit</emphasis> on system
resources. Usually invoked with the <option>-f</option>
option, which sets a limit on file size (<command>ulimit
-f 1000</command> limits files to 1 meg maximum). The
<option>-t</option> option limits the coredump size
(<command>ulimit -c 0</command> eliminates coredumps).
Normally, the value of <command>ulimit</command>
would be set in <filename>/etc/profile</filename>
and/or <filename>~/.bash_profile</filename> (see <xref
linkend="files">).</para>
</listitem>
</varlistentry>
<varlistentry>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>umask</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>umask</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
2001-09-04 13:27:31 +00:00
<term><command>umask</command></term>
<listitem>
<para>User file creation MASK. Limit the default file attributes
for a particular user. All files created by that user take
on the attributes specified by <command>umask</command>. The
(octal) value passed to <command>umask</command> defines the
2002-06-17 13:17:07 +00:00
file permissions <emphasis>disabled</emphasis>. For example,
<command>umask 022</command> ensures that new files will
have at most 755 permissions (777 NAND 022).
2001-09-04 13:27:31 +00:00
<footnote><para>NAND is the logical <quote>not-and</quote>
operator. Its effect is somewhat similar to
subtraction.</para></footnote>
Of course, the user may later change the
attributes of particular files with <link
2002-06-17 13:17:07 +00:00
linkend="chmodref">chmod</link>. The usual practice
2001-09-04 13:27:31 +00:00
is to set the value of <command>umask</command>
in <filename>/etc/profile</filename> and/or
<filename>~/.bash_profile</filename> (see <xref
linkend="files">).</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>rdev</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>rdev</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>rdev</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Get info about or make changes to root device, swap space, or video
mode. The functionality of <command>rdev</command> has generally been taken over by
<command>lilo</command>, but <command>rdev</command> remains
useful for setting up a ram disk. This is another dangerous command, if misused.
</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist id="modulessys">
<title><anchor id="modulessys1">Modules</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>lsmod</command></term>
<indexterm>
<primary>lsmod</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>lsmod</secondary>
</indexterm>
<listitem>
<para>List installed kernel modules.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>lsmod</userinput>
<computeroutput>Module Size Used by
autofs 9456 2 (autoclean)
opl3 11376 0
serial_cs 5456 0 (unused)
sb 34752 0
uart401 6384 0 [sb]
sound 58368 0 [opl3 sb uart401]
soundlow 464 0 [sound]
soundcore 2800 6 [sb sound]
ds 6448 2 [serial_cs]
i82365 22928 2
pcmcia_core 45984 0 [serial_cs ds i82365]</computeroutput>
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>insmod</command></term>
<indexterm>
<primary>insmod</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>insmod</secondary>
</indexterm>
<listitem>
2002-04-01 16:04:17 +00:00
<para>Force installation of a kernel module. Must be invoked
as root.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>rmmod</command></term>
<indexterm>
<primary>rmmod</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>rmmod</secondary>
</indexterm>
<listitem>
<para>Force unloading of a kernel module. Must be invoked
as root.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><command>modprobe</command></term>
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>modprobe</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>modprobe</secondary>
</indexterm>
<listitem>
<para>Module loader that is normally invoked automatically in a startup script.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>depmod</command></term>
<indexterm>
<primary>depmod</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>depmod</secondary>
</indexterm>
<listitem>
<para>Creates module dependency file, usually invoked from startup script.</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist id="miscsys">
<title><anchor id="miscsys1">Miscellaneous</title>
<varlistentry>
<term><command>env</command></term>
<indexterm>
<primary>env</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>env</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2002-06-03 14:35:48 +00:00
<para>Runs a program or script with certain <link
linkend="envref">environmental variables</link>
set or changed (without changing the overall system
environment). The <option>[varname=xxx]</option>
2001-09-04 13:27:31 +00:00
permits changing the environmental variable
<varname>varname</varname> for the duration of the
script. With no options specified, this command lists all
the environmental variable settings.</para>
<note><para>In Bash and other Bourne shell derivatives, it is
possible to set variables in a single command's environment.
<programlisting>var1=value1 var2=value2 commandXXX
# $var1 and $var2 set in the environment of 'commandXXX' only.</programlisting>
</para></note>
<tip><para>The first line of a script (the
<quote>sha-bang</quote> line) may use <command>env</command>
when the path to the shell or interpreter is unknown.
<programlisting>#! /usr/bin/env perl
print "This Perl script will run,\n";
print "even when I don't know where to find Perl.\n";
# Good for portable cross-platform scripts,
# where the Perl binaries may not be in the expected place.
# Thanks, S.C.</programlisting>
</para></tip>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>ldd</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>ldd</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>ldd</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Show shared lib dependencies for an executable file.</para>
<screen><prompt>bash$ </prompt><userinput>ldd /bin/ls</userinput>
<computeroutput>libc.so.6 => /lib/libc.so.6 (0x4000c000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)</computeroutput></screen>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>strip</command></term>
<indexterm>
<primary>strip</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>symbol</secondary>
</indexterm>
<listitem>
<para>Remove the debugging symbolic references from an executable
binary. This decreases its size, but makes debugging of it
impossible.</para>
<para>This command often occurs in a <link
linkend="makefileref">Makefile</link>,
but rarely in a shell script.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>nm</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>nm</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>symbol</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>List symbols in an unstripped compiled binary.</para>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>rdist</command></term>
2001-07-10 14:25:50 +00:00
<indexterm>
2001-09-04 13:27:31 +00:00
<primary>rdist</primary>
2001-07-10 14:25:50 +00:00
</indexterm>
<indexterm>
<primary>command</primary>
2001-09-04 13:27:31 +00:00
<secondary>rdist</secondary>
2001-07-10 14:25:50 +00:00
</indexterm>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Remote distribution client: synchronizes, clones,
or backs up a file system on a remote server.</para>
</listitem>
</varlistentry>
2001-07-10 14:25:50 +00:00
</variablelist>
2001-09-04 13:27:31 +00:00
2001-10-15 14:21:41 +00:00
2001-07-10 14:25:50 +00:00
<para>Using our knowledge of administrative commands, let us examine a system
script. One of the shortest and simplest to understand scripts is
<command>killall</command>, used to suspend running processes at system shutdown.</para>
<example id="ex55">
<title><command>killall</command>, from <filename class="directory">/etc/rc.d/init.d</filename></title>
<programlisting>&ex55;</programlisting>
</example>
<para>That wasn't so bad. Aside from a little fancy footwork with variable
matching, there is no new material there.</para>
2001-10-15 14:21:41 +00:00
<formalpara><title>Exercise 1</title>
<para>In <filename class="directory">/etc/rc.d/init.d</filename>,
analyze the <command>halt</command> script. It is a bit longer
than <command>killall</command>, but similar in concept. Make
a copy of this script somewhere in your home directory and
experiment with it (do <emphasis>not</emphasis> run it as
root). Do a simulated run with the <option>-vn</option> flags
(<userinput>sh -vn scriptname</userinput>). Add extensive
comments. Change the <quote>action</quote> commands to
<quote>echos</quote>.</para></formalpara>
<formalpara><title>Exercise 2</title>
<para>Look at some of the more complex scripts in
2001-07-10 14:25:50 +00:00
<filename class="directory">/etc/rc.d/init.d</filename>. See if
you can understand parts of them. Follow the above procedure
to analyze them. For some additional insight, you might also
examine the file <filename>sysvinitfiles</filename> in <filename
2001-10-15 14:21:41 +00:00
class="directory">/usr/share/doc/initscripts-?.??</filename>,
which is part of the <quote>initscripts</quote>
documentation.</para></formalpara>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- System and Administrative Commands -->
<chapter id="commandsub">
<title>Command Substitution</title>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>$</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>`</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<para><anchor id="commandsubref"><command>Command
substitution</command> reassigns the output of a command
2002-01-07 15:24:19 +00:00
<footnote><para>For purposes of <emphasis>command
substitution</emphasis>, a <command>command</command> may
be an external system command, an internal scripting
<emphasis>builtin</emphasis>, or even a script
function.</para></footnote>
2001-07-10 14:25:50 +00:00
or even multiple commands; it literally plugs the command
output into another context.</para>
2002-06-03 14:35:48 +00:00
<para><anchor id="backquotesref">The classic form of command
substitution uses backquotes (`...`). Commands within
backquotes (backticks) generate command line text.
2001-07-10 14:25:50 +00:00
<programlisting>script_name=`basename $0`
echo "The name of this script is $script_name."</programlisting></para>
2001-10-15 14:21:41 +00:00
<formalpara>
<title>The output of commands can be used as arguments to
2001-07-10 14:25:50 +00:00
another command, to set a variable, and even for generating
2001-10-15 14:21:41 +00:00
the argument list in a <link linkend="forloopref1">for</link>
loop.</title>
<para></para>
</formalpara>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<para>
<programlisting>rm `cat filename` # <quote>filename</quote> contains a list of files to delete.
2001-07-10 14:25:50 +00:00
#
# 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_listing
# 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 )
#
2001-10-15 14:21:41 +00:00
# Thanks, S.C.</programlisting>
</para>
2001-07-10 14:25:50 +00:00
<caution><para>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
2002-04-01 16:04:17 +00:00
# Thanks, S.C.</programlisting></para>
2001-07-10 14:25:50 +00:00
<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>
2002-04-01 16:04:17 +00:00
</caution>
<caution>
<para>Using <command>echo</command> to output an
<emphasis>unquoted</emphasis> 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>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<para>Command substitution even permits setting a variable to the
contents of a file, using either <link
linkend="ioredirref">redirection</link> or the <link
2002-04-01 16:04:17 +00:00
linkend="catref">cat</link> command.</para>
<para>
2001-10-15 14:21:41 +00:00
<programlisting>variable1=`&lt;file1` # Set "variable1" to contents of "file1".
variable2=`cat file2` # Set "variable2" to contents of "file2".
# Be aware that the variables may contain embedded whitespace,
#+ or even (horrors), control characters.</programlisting>
</para>
2002-04-01 16:04:17 +00:00
<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
<emphasis>binary</emphasis> file, even as a joke.</para>
<example id="stupscr">
<title>Stupid script tricks</title>
<programlisting>&stupscr;</programlisting>
</example>
<para>Notice that a <emphasis>buffer overrun</emphasis>
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>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>
2001-10-15 14:21:41 +00:00
2002-01-07 15:24:19 +00:00
<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>
2001-10-15 14:21:41 +00:00
2002-01-07 15:24:19 +00:00
<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>
2001-07-10 14:25:50 +00:00
<note><para>The <command>$(COMMAND)</command> form has
superseded backticks for command substitution.
<programlisting>output=$(sed -n /"$1"/p $file)
# From "grp.sh" example.</programlisting></para></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>
2002-01-07 15:24:19 +00:00
<listitem><para><xref linkend="altbc"></para></listitem>
2001-07-10 14:25:50 +00:00
</orderedlist>
</para>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Command Substitution -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="arithexp">
<title>Arithmetic Expansion</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="arithexpref">Arithmetic expansion provides a
2001-09-04 13:27:31 +00:00
powerful tool for performing arithmetic operations
in scripts. Translating a string into a numerical
expression is relatively straightforward using
<link linkend="backquotesref">backticks</link>, <link
linkend="dblparens">double parentheses</link>, or <link
linkend="letref">let</link>.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="arithexpvar">
<title><anchor id="arithexpvar1">Variations</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term>Arithmetic expansion with backticks (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` # 'expr' does the expansion.</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
<term>Arithmetic expansion with double parentheses</term>
<indexterm><primary>double</primary>
<secondary>parentheses</secondary></indexterm>
2001-09-04 13:27:31 +00:00
<term>and using <command>let</command></term>
2001-07-10 14:25:50 +00:00
<indexterm><primary>let</primary>
<secondary>let</secondary></indexterm>
<listitem>
<para>The use of backticks in arithmetic
expansion has been superseded by double parentheses
<userinput>$((...))</userinput> or the very
convenient <command>let</command> construction.
<programlisting>z=$(($z+3))
# $((EXPRESSION)) is arithmetic expansion. # Not to be confused with
# command substitution.
let z=z+3
let "z += 3" #If quotes, then spaces and special operators allowed.
# 'let' is actually arithmetic evaluation, rather than expansion.</programlisting>
All the above are equivalent. You may use whichever one
<quote>rings your chimes</quote>.
</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>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Arithmetic Expansion -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="io-redirection">
<title>I/O Redirection</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="ioredirref"></para>
<para>There are always three default <quote>files</quote>
open, <filename>stdin</filename> (the keyboard),
<filename>stdout</filename> (the screen), and
<filename>stderr</filename> (error messages output to the
screen). These, and any other open files, can be redirected.
Redirection simply means capturing output from a file, command,
program, script, or even code block within a script (see <xref
linkend="ex8"> and <xref linkend="rpmcheck">) and sending it as
input to another file, command, program, or script.</para>
<para><anchor id="fdref">Each open file gets assigned a file descriptor.
<footnote><para>A <emphasis>file descriptor</emphasis>
is simply a number that the operating system assigns
to an open file to keep track of it. Consider it
a simplified version of a file pointer. It is
analogous to a <emphasis>file handle</emphasis> in
C.</para></footnote>
The file descriptors for <filename>stdin</filename>,
<filename>stdout</filename>, and <filename>stderr</filename> are
0, 1, and 2, respectively. For opening additional files, there
remain descriptors 3 to 9. It is sometimes useful to assign one of
these additional file descriptors to <filename>stdin</filename>,
<filename>stdout</filename>, or <filename>stderr</filename>
as a temporary duplicate link.
<footnote><para>Using <replaceable>file
descriptor 5</replaceable> might cause problems.
When Bash creates a child process, as with <link
linkend="execref">exec</link>, the child inherits
fd 5 (see Chet Ramey's archived e-mail, <ulink
url="http://www.geocrawler.com/archives/3/342/1996/1/0/1939805/">
SUBJECT: RE: File descriptor 5 is held open</ulink>).
Best leave this particular fd alone.</para></footnote>
This simplifies restoration to normal after complex redirection
and reshuffling (see <xref linkend="redir1">).</para>
<para><anchor id="ioredirectionref"></para>
2002-06-03 14:35:48 +00:00
<programlisting> COMMAND_OUTPUT >
2001-07-10 14:25:50 +00:00
# Redirect stdout to a file.
# Creates the file if not present, otherwise overwrites it.
ls -lR > dir-tree.list
# Creates a file containing a listing of the directory tree.
: > filename
# The > truncates file "filename" to zero length.
2002-01-07 15:24:19 +00:00
# If file not present, creates zero-length file (same effect as 'touch').
2001-07-10 14:25:50 +00:00
# The : serves as a dummy placeholder, producing no output.
2002-06-03 14:35:48 +00:00
> filename
# The > truncates file "filename" to zero length.
# If file not present, creates zero-length file (same effect as 'touch').
# (Same result as ": >", above, but this does not work with some shells.)
COMMAND_OUTPUT >>
2001-07-10 14:25:50 +00:00
# Redirect stdout to a file.
# Creates the file if not present, otherwise appends to it.
2002-01-07 15:24:19 +00:00
# Single-line redirection commands (affect only the line they are on):
# --------------------------------------------------------------------
2002-06-17 13:17:07 +00:00
2002-01-07 15:24:19 +00:00
1>filename
# Redirect stdout to file "filename".
1>>filename
# Redirect and append stdout to file "filename".
2>filename
# Redirect stderr to file "filename".
2>>filename
# Redirect and append stderr to file "filename".
2002-06-17 13:17:07 +00:00
&>filename
# Redirect both stdout and stderr to file "filename".
2002-01-07 15:24:19 +00:00
#==============================================================================
# Redirecting stdout, one line at a time.
LOGFILE=script.log
echo "This statement is sent to the log file, \"$LOGFILE\"." 1>$LOGFILE
echo "This statement is appended to \"$LOGFILE\"." 1>>$LOGFILE
echo "This statement is also appended to \"$LOGFILE\"." 1>>$LOGFILE
echo "This statement is echoed to stdout, and will not appear in \"$LOGFILE\"."
# These redirection commands automatically "reset" after each line.
# Redirecting stderr, one line at a time.
ERRORFILE=script.errors
bad_command1 2>$ERRORFILE # Error message sent to $ERRORFILE.
bad_command2 2>>$ERRORFILE # Error message appended to $ERRORFILE.
bad_command3 # Error message echoed to stderr,
#+ and does not appear in $ERRORFILE.
# These redirection commands also automatically "reset" after each line.
#==============================================================================
2001-07-10 14:25:50 +00:00
2>&amp;1
# Redirects stderr to stdout.
# Error messages get sent to same place as standard output.
i>&amp;j
# Redirects file descriptor <emphasis>i</emphasis> to <emphasis>j</emphasis>.
# All output of file pointed to by <emphasis>i</emphasis> gets sent to file pointed to by <emphasis>j</emphasis>.
>&amp;j
# Redirects, by default, file descriptor <emphasis>1</emphasis> (stdout) to <emphasis>j</emphasis>.
# All stdout gets sent to file pointed to by <emphasis>j</emphasis>.
2002-06-03 14:35:48 +00:00
0< FILENAME
< FILENAME
2001-07-10 14:25:50 +00:00
# Accept input from a file.
# Companion command to <quote>></quote>, and often used in combination with it.
#
# grep search-word &lt;filename
[j]&lt;&gt;filename
# Open file "filename" for reading and writing, and assign file descriptor "j" to it.
# If "filename" does not exist, create it.
# If file descriptor "j" is not specified, default to fd 0, stdin.
#
# An application of this is writing at a specified place in a file.
echo 1234567890 > File # Write string to "File".
exec 3&lt;&gt; File # Open "File" and assign fd 3 to it.
read -n 4 <&3 # Read only 4 characters.
echo -n . >&3 # Write a decimal point there.
exec 3>&- # Close fd 3.
cat File # ==> 1234.67890
# Random access, by golly.
|
# Pipe.
# General purpose process and command chaining tool.
# Similar to <quote>></quote>, but more general in effect.
# Useful for chaining commands, scripts, files, and programs together.
cat *.txt | sort | uniq > result-file
# Sorts the output of all the .txt files and deletes duplicate lines,
# finally saves results to <quote>result-file</quote>.
</programlisting>
<para>Multiple instances of input and output redirection
and/or pipes can be combined in a single command
line.
<programlisting>command &lt; input-file &gt; output-file
2001-09-04 13:27:31 +00:00
command1 | command2 | command3 > output-file</programlisting>
See <xref linkend="derpm"> and <xref linkend="fifo">.</para>
2001-07-10 14:25:50 +00:00
<para>Multiple output streams may be redirected to one file.
<programlisting>ls -yz >> command.log 2>&1
# Capture result of illegal options "yz" to "ls" in file "command.log".
# Because stderr redirected to the file, any error messages will also be there.
</programlisting></para>
2001-09-04 13:27:31 +00:00
<variablelist id="closingfiledescriptors">
<title><anchor id="cfd">Closing File Descriptors</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><token>n<&-</token></term>
<listitem>
<para>Close input file descriptor
<replaceable>n</replaceable>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><token>0<&-</token></term>
<term><token><&-</token></term>
<listitem>
<para>Close <filename>stdin</filename>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><token>n>&-</token></term>
<listitem>
<para>Close output file descriptor <replaceable>n</replaceable>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><token>1>&-</token></term>
<term><token>>&-</token></term>
<listitem>
<para>Close <filename>stdout</filename>.</para>
</listitem>
</varlistentry>
</variablelist>
<para>Child processes inherit open file descriptors. This is why pipes
work. To prevent an fd from being inherited, close it.
<programlisting># Redirecting only stderr to a pipe.
exec 3>&1 # Save current "value" of stdout.
2002-04-01 16:04:17 +00:00
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls').
# ^^^^ ^^^^
2001-07-10 14:25:50 +00:00
exec 3>&- # Now close it for the remainder of the script.
# Thanks, S.C.</programlisting>
</para>
<para>For a more detailed introduction to I/O redirection see
<xref linkend="ioredirintro">.</para>
2001-09-04 13:27:31 +00:00
<sect1><title>Using <command>exec</command></title>
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
<para>An <command>exec &lt;filename</command> command redirects
2001-07-10 14:25:50 +00:00
<filename>stdin</filename> to a file. From that point on, all
<filename>stdin</filename> comes from that file, rather than
its normal source (usually keyboard input). This provides a
method of reading a file line by line and possibly parsing
each line of input using <link linkend="sedref">sed</link>
and/or <link linkend="awkref">awk</link>.</para>
<example id="redir1">
<title>Redirecting <filename>stdin</filename> using
<command>exec</command></title>
<programlisting>&redir1;</programlisting>
</example>
2002-06-03 14:35:48 +00:00
<para>Similarly, an <command>exec &gt;filename</command>
command redirects <filename>stdout</filename> to a designated
file. This sends all command output that would normally go
to <filename>stdout</filename> to that file.</para>
<example id="reassignstdout">
<title>Redirecting <filename>stdout</filename> using
<command>exec</command></title>
<programlisting>&reassignstdout;</programlisting>
</example>
<example id="upperconv">
<title>Redirecting both <filename>stdin</filename> and
<filename>stdout</filename> in the same script with
<command>exec</command></title>
<programlisting>&upperconv;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
</sect1><!-- Using exec For Redirection -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="redircb"><title>Redirecting Code Blocks</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="redirref">Blocks of code, such as <link
linkend="whileloopref">while</link>, <link
linkend="untilloopref">until</link>, and <link
2001-10-15 14:21:41 +00:00
linkend="forloopref1">for</link> loops, even <link
2001-07-10 14:25:50 +00:00
linkend="ifthen">if/then</link> test blocks can also incorporate
redirection of <filename>stdin</filename>. Even a function may
use this form of redirection (see <xref linkend="realname">).
2002-06-17 13:17:07 +00:00
The <token>&lt;</token> operator at the end of the code block
accomplishes this.</para>
2001-07-10 14:25:50 +00:00
<example id="redir2">
<title>Redirected <emphasis>while</emphasis> loop</title>
<programlisting>&redir2;</programlisting>
</example>
<example id="redir2a">
<title>Alternate form of redirected <emphasis>while</emphasis> loop</title>
<programlisting>&redir2a;</programlisting>
</example>
<example id="redir3">
<title>Redirected <emphasis>until</emphasis> loop</title>
<programlisting>&redir3;</programlisting>
</example>
<example id="redir4">
<title>Redirected <emphasis>for</emphasis> loop</title>
<programlisting>&redir4;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<para>We can modify the previous example to also redirect the output of
the loop.</para>
<example id="redir4a">
<title>Redirected <emphasis>for</emphasis> loop (both
<filename>stdin</filename> and <filename>stdout</filename>
redirected)</title>
<programlisting>&redir4a;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
<example id="redir5">
<title>Redirected <emphasis>if/then</emphasis> test</title>
<programlisting>&redir5;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<example id="namesdata">
<title>Data file <quote>names.data</quote> for above examples</title>
<programlisting>&namesdata;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<para>Redirecting the <filename>stdout</filename> of a code
block has the effect of saving its output to a file. See <xref
linkend="rpmcheck">.</para>
2002-04-01 16:04:17 +00:00
<para><link linkend="heredocref">Here documents</link>
are a special case of redirected code blocks.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1><!-- Redirecting Code Blocks -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="redirapps"><title>Applications</title>
2001-07-10 14:25:50 +00:00
<para>Clever use of I/O redirection permits parsing and stitching
together snippets of command output (see <xref
linkend="readredir">). This permits
generating report and log files.</para>
<example id="logevents">
<title>Logging events</title>
<programlisting>&logevents;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
</sect1><!-- Applications -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- I/O Redirection -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="here-docs">
<title>Here Documents</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="heredocref"></para>
<indexterm>
<primary><<</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary><<</secondary>
</indexterm>
<para>A <firstterm>here document</firstterm> uses a special form
of <link linkend="ioredirref">I/O redirection</link>
2002-06-03 14:35:48 +00:00
to feed a command list to an interactive program or
command, such as <link linkend="ftpref">ftp</link>, <link
2001-09-04 13:27:31 +00:00
linkend="telnetref">telnet</link>, or <command>ex</command>.
2002-06-03 14:35:48 +00:00
A <quote>limit string</quote> delineates (frames) the command
list. The special symbol <token><<</token> designates the limit
string. This has the effect of redirecting the output of a file
into the program, similar to <userinput>interactive-program <
command-file</userinput>, where <filename>command-file</filename>
contains
2001-07-10 14:25:50 +00:00
<programlisting>command #1
command #2
...</programlisting></para>
<para>The <quote>here document</quote> alternative looks like this:
<programlisting>#!/bin/bash
interactive-program &lt;&lt;LimitString
command #1
command #2
...
LimitString</programlisting></para>
<para>Choose a limit string sufficiently unusual that it will not occur anywhere
in the command list and confuse matters.</para>
<para>Note that <emphasis>here documents</emphasis> may sometimes
be used to good effect with non-interactive utilities and
commands.</para>
<example id="ex69">
<title><command>dummyfile</command>: Creates a 2-line dummy file</title>
<programlisting>&ex69;</programlisting>
</example>
<para>The above script could just as effectively have been implemented with
<command>ex</command>, rather than <command>vi</command>. Here documents
containing a list of <command>ex</command> commands are common enough to
form their own category, known as <firstterm>ex scripts</firstterm>.</para>
<example id="ex70">
<title><command>broadcast</command>: Sends message to everyone logged in</title>
<programlisting>&ex70;</programlisting>
</example>
<example id="ex71">
<title>Multi-line message using <command>cat</command></title>
<programlisting>&ex71;</programlisting>
</example>
<para>The <option>-</option> option to mark a here document limit string
(<userinput>&lt;&lt;-LimitString</userinput>) suppresses tabs (but
not spaces) in the output. This may be useful in making a script
more readable.</para>
<example id="ex71a">
<title>Multi-line message, with tabs suppressed</title>
<programlisting>&ex71a;</programlisting>
</example>
<para>A here document supports parameter and command substitution.
It is therefore possible to pass different parameters to the
body of the here document, changing its output accordingly.</para>
<example id="ex71b">
<title>Here document with parameter substitution</title>
<programlisting>&ex71b;</programlisting>
</example>
<para>Quoting or escaping the <quote>limit string</quote> at the
head of a here document disables parameter substitution within its
body. This has very limited usefulness.</para>
<example id="ex71c">
<title>Parameter substitution turned off</title>
<programlisting>&ex71c;</programlisting>
</example>
<para>This is a useful script containing a here document with
parameter substitution.</para>
<example id="ex72">
<title><command>upload</command>: Uploads a file pair to <quote>Sunsite</quote>
incoming directory</title>
<programlisting>&ex72;</programlisting>
</example>
2002-06-03 14:35:48 +00:00
<para>A here document can supply input to a function in the same
script.</para>
<example id="hf">
<title>Here documents and functions</title>
<programlisting>&hf;</programlisting>
</example>
<para><anchor id="anonheredoc0"></para>
2001-07-10 14:25:50 +00:00
<para>It is possible to use <token>:</token> as a dummy command
accepting output from a here document. This, in effect, creates an
<quote>anonymous</quote> here document.</para>
<example id="anonheredoc">
<title><quote>Anonymous</quote> Here Document</title>
<programlisting>#!/bin/bash
: &lt;&lt;TESTVARIABLES
${HOSTNAME?}${USER?}${MAIL?} # Print error message if one of the variables not set.
TESTVARIABLES
exit 0</programlisting>
</example>
2002-06-03 14:35:48 +00:00
<tip><para>A variation of the above technique permits <quote>commenting
out</quote> blocks of code.</para></tip>
<example id="commentblock">
<title>Commenting out a block of code</title>
<programlisting>&commentblock;</programlisting>
</example>
<tip><para>Yet another twist of this nifty trick makes
<quote>self-documenting</quote> scripts possible.</para></tip>
<example id="selfdocument">
<title>A self-documenting script</title>
<programlisting>&selfdocument;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
<note>
<para>Here documents create temporary files, but these
files are deleted after opening and are not accessible to
any other process.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>bash -c 'lsof -a -p $$ -d0' << EOF</userinput>
<prompt>&gt; </prompt><userinput>EOF</userinput>
<computeroutput>lsof 1213 bozo 0r REG 3,5 0 30386 /tmp/t1213-0-sh (deleted)</computeroutput>
</screen>
</para>
</note>
2002-01-07 15:24:19 +00:00
<caution><para>Some utilities will not work inside a
<emphasis>here document</emphasis>.</para></caution>
2001-07-10 14:25:50 +00:00
<para>For those tasks too complex for a <quote>here
document</quote>, consider using the <command>expect</command>
scripting language, which is specifically tailored for feeding
input into interactive programs.</para>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Here Documents -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="Recess-Time">
<title>Recess Time</title>
2001-07-10 14:25:50 +00:00
<blockquote>
<literallayout>
This bizarre little intermission gives the reader a chance to
relax and maybe laugh a bit.
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 you make
the copies, send a 100-line Bash script to the first person
on the list given 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>xbill</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!
<emphasis>Courtesy 'NIX "fortune cookies", with some
alterations and many apologies</emphasis>
</literallayout>
</blockquote>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Recess Time -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</part> <!-- Part 3 (Beyond the Basics) -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<part label="Part 4" id="part4">
<title>Advanced Topics</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="regexp">
2001-07-10 14:25:50 +00:00
<title>Regular Expressions</title>
<para><anchor id="regexref"></para>
2001-09-04 13:27:31 +00:00
<para>To fully utilize the power of shell scripting, you need to
master Regular Expressions. Certain commands and
utilities commonly used in scripts, such as <link
linkend="exprref">expr</link>, <link linkend="sedref">sed</link>
and <link linkend="awkref">awk</link> interpret and use
REs.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1><title>A Brief Introduction to Regular Expressions</title>
2001-07-10 14:25:50 +00:00
<para>An expression is a string of characters. Those characters
that have an interpretation above and beyond their literal
meaning are called <emphasis>metacharacters</emphasis>. A
2001-09-04 13:27:31 +00:00
quote symbol, for example, may denote speech by a person,
<emphasis>ditto</emphasis>, or a meta-meaning for the symbols
that follow. Regular Expressions are sets of characters and/or
2001-07-10 14:25:50 +00:00
metacharacters that UNIX endows with special features.
2001-09-04 13:27:31 +00:00
<footnote><para>The simplest type of Regular Expression is a
2001-07-10 14:25:50 +00:00
character string that retains its literal meaning, not
containing any metacharacters.</para></footnote>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
</para>
<para>The main uses for Regular Expressions (REs) are text
searches and string manipulation. An RE
<firstterm>matches</firstterm> a single character or a set of
characters (a substring or an entire string).</para>
<itemizedlist>
<listitem>
<indexterm>
<primary>*</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>*</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<para>The asterisk -- <token>*</token> -- matches any number of
2001-07-10 14:25:50 +00:00
repeats of the character string or RE preceding it,
<emphasis>including zero</emphasis>.</para>
<para><quote>1133*</quote> matches <replaceable>11 +
one or more 3's + possibly other characters</replaceable>:
<replaceable>113</replaceable>, <replaceable>1133</replaceable>,
<replaceable>111312</replaceable>, and so forth.</para>
</listitem>
<listitem>
<indexterm>
<primary>.</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>.</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<para><anchor id="regexdot">The dot -- <token>.</token> -- matches
2001-09-04 13:27:31 +00:00
any one character, except a newline.
2001-07-10 14:25:50 +00:00
<footnote><para>Since <link linkend="sedref">sed</link>, <link
linkend="awkref">awk</link>, and <link
linkend="grepref">grep</link> process single lines, there
will usually not be a newline to match. In those cases where
there is a newline in a multiple line expression, the dot
will match the newline.
<programlisting>#!/bin/bash
sed -e 'N;s/.*/[&]/' &lt;&lt; EOF # Here Document
line1
line2
EOF
# OUTPUT:
# [line1
# line2]
echo
awk '{ $0=$1 "\n" $2; if (/line.1/) {print}}' &lt;&lt; EOF
line 1
line 2
EOF
# OUTPUT:
# line
# 1
# Thanks, S.C.
exit 0</programlisting></para></footnote>
</para>
<para><quote>13.</quote> matches <replaceable>13 + at
least one of any character (including a
space)</replaceable>: <replaceable>1133</replaceable>,
<replaceable>11333</replaceable>, but not
<replaceable>13</replaceable> (additional character
missing).</para>
</listitem>
<listitem>
<indexterm>
<primary>^</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>^</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<para>The caret -- <token>^</token> -- matches the beginning of
2001-07-10 14:25:50 +00:00
a line, but sometimes, depending on context, negates the
meaning of a set of characters in an RE.
</para>
</listitem>
<listitem>
<indexterm>
<primary>$</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>$</secondary>
</indexterm>
2001-09-04 13:27:31 +00:00
<para><anchor id="dollarsignref"></para>
2002-06-03 14:35:48 +00:00
<para>The dollar sign -- <token>$</token> -- at the end of an
2001-07-10 14:25:50 +00:00
RE matches the end of a line.</para>
<para><quote>^$</quote> matches blank lines.</para>
</listitem>
<listitem>
<indexterm>
<primary>[...]</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>[...]</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<para><anchor id="bracketsref"></para>
<para>Brackets -- <token>[...]</token> -- enclose a set of characters
2001-07-10 14:25:50 +00:00
to match in a single RE.</para>
<para><quote>[xyz]</quote> matches the characters
<replaceable>x</replaceable>, <replaceable>y</replaceable>,
or <replaceable>z</replaceable>.</para>
<para><quote>[c-n]</quote> matches any of the
characters in the range <replaceable>c</replaceable>
to <replaceable>n</replaceable>.</para>
<para><quote>[B-Pk-y]</quote> matches any of the
characters in the ranges <replaceable>B</replaceable>
to <replaceable>P</replaceable>
and <replaceable>k</replaceable> to
<replaceable>y</replaceable>.</para>
<para><quote>[a-z0-9]</quote> matches any lowercase letter or any
digit.</para>
<para><quote>[^b-d]</quote> matches all characters
<emphasis>except</emphasis> those in
the range <replaceable>b</replaceable> to
<replaceable>d</replaceable>. This is an instance of
<token>^</token> negating or inverting the meaning
of the following RE (taking on a role similar to
<token>!</token> in a different context).</para>
<para>Combined sequences of bracketed characters match
common word patterns. <quote>[Yy][Ee][Ss]</quote> matches
<replaceable>yes</replaceable>, <replaceable>Yes</replaceable>,
<replaceable>YES</replaceable>, <replaceable>yEs</replaceable>,
and so forth.
<quote>[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]</quote>
matches any Social Security number.</para>
</listitem>
<listitem>
<indexterm>
<primary>\</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>\</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<para>The backslash -- <token>\</token> -- <link
2001-07-10 14:25:50 +00:00
linkend="escp">escapes</link> a special character, which
means that character gets interpreted literally.</para>
<para>A <quote>\$</quote> reverts back to its
literal meaning of <quote>$</quote>, rather than its
RE meaning of end-of-line. Likewise a <quote>\\</quote>
has the literal meaning of <quote>\</quote>.</para>
</listitem>
2002-06-03 14:35:48 +00:00
<listitem>
<indexterm>
<primary>\&lt; \&gt;</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>\&lt; \&gt;</secondary>
</indexterm>
2002-06-17 13:17:07 +00:00
<para><anchor id="anglebrac"></para>
2002-06-03 14:35:48 +00:00
<para><link linkend="escp">Escaped</link> <quote>angle
brackets</quote> -- <token>\&lt;...\&gt;</token> -- mark word
boundaries.</para>
<para>The angle brackets must be escaped, since otherwise
they have only their literal character meaning.</para>
<para><quote>\&lt;the\&gt;</quote> matches the word
<quote>the</quote>, but not the words <quote>them</quote>,
<quote>there</quote>, <quote>other</quote>, etc.</para>
<para>
<screen>
<prompt>bash$ </prompt><userinput>cat textfile</userinput>
<computeroutput>This is line 1, of which there is only one instance.
This is the only instance of line 2.
This is line 3, another line.
This is line 4.</computeroutput>
<prompt>bash$ </prompt><userinput>grep 'the' textfile</userinput>
<computeroutput>This is line 1, of which there is only one instance.
This is the only instance of line 2.
This is line 3, another line.</computeroutput>
<prompt>bash$ </prompt><userinput>grep '\&lt;the\&gt;' textfile</userinput>
<computeroutput>This is the only instance of line 2.</computeroutput>
</screen>
</para>
</listitem>
2001-07-10 14:25:50 +00:00
</itemizedlist>
<itemizedlist>
2001-09-04 13:27:31 +00:00
<listitem override="square">
<formalpara>
2001-10-15 14:21:41 +00:00
<title><anchor id="extregex">Extended REs</title>
2001-09-04 13:27:31 +00:00
<para>Used in <link linkend="egrepref">egrep</link>,
<link linkend="awkref">awk</link>, and <link
linkend="perlref">Perl</link></para>
</formalpara>
</listitem>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<listitem>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>?</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>?</secondary>
</indexterm>
2001-10-15 14:21:41 +00:00
<para><anchor id="quexregex"></para>
2002-06-03 14:35:48 +00:00
<para>The question mark -- <token>?</token> -- matches zero or
2001-07-10 14:25:50 +00:00
one of the previous RE. It is generally used for matching
single characters.</para>
</listitem>
<listitem>
<indexterm>
<primary>+</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>+</secondary>
</indexterm>
2001-09-04 13:27:31 +00:00
<para><anchor id="plusref"></para>
2002-06-03 14:35:48 +00:00
<para>The plus -- <token>+</token> -- matches one or more of the
2001-07-10 14:25:50 +00:00
previous RE. It serves a role similar to the <token>*</token>, but
does <emphasis>not</emphasis> match zero occurrences.</para>
<para><programlisting># GNU versions of sed and awk can use "+",
# but it needs to be escaped.
echo a111b | sed -ne '/a1\+b/p'
echo a111b | grep 'a1\+b'
echo a111b | gawk '/a1+b/'
# All of above are equivalent.
# Thanks, S.C.</programlisting></para>
</listitem>
<listitem>
<indexterm>
<primary>\{ \}</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>\{ \}</secondary>
</indexterm>
<para><link linkend="escp">Escaped</link> <quote>curly
2002-06-03 14:35:48 +00:00
brackets</quote> -- <token>\{ \}</token> -- indicate the number
2001-07-10 14:25:50 +00:00
of occurrences of a preceding RE to match.</para>
<para>It is necessary to escape the curly brackets since
they have only their literal character meaning
otherwise. This usage is technically not part of the basic
RE set.</para>
<para><quote>[0-9]\{5\}</quote> matches exactly five digits
(characters in the range of 0 to 9).</para>
<caution>
<para>Curly brackets are not available as an RE in the
<quote>classic</quote> version of <link
linkend="awkref">awk</link>. However,
<command>gawk</command> has the
<option>--re-interval</option> option that permits them
(without being escaped).</para>
<para>
<screen><prompt>bash$ </prompt><userinput>echo 2222 | gawk --re-interval '/2{3}/'</userinput>
<computeroutput>2222</computeroutput>
</screen>
</para>
</caution>
</listitem>
2001-10-15 14:21:41 +00:00
<listitem>
<indexterm>
<primary>()</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>()</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<para>Parentheses -- <command>( )</command> -- enclose groups of
REs. They are useful with the following
<quote><token>|</token></quote> operator and in <link
linkend="exprparen">substring extraction</link> using <link
linkend="exprref">expr</link>.</para>
2001-10-15 14:21:41 +00:00
</listitem>
<listitem>
<indexterm>
<primary>|</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>|</secondary>
</indexterm>
2002-06-03 14:35:48 +00:00
<para>The -- <command>|</command> -- <quote>or</quote> RE operator
2001-10-15 14:21:41 +00:00
matches any of a set of alternate characters.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>egrep 're(a|e)d' misc.txt</userinput>
<computeroutput>People who read seem to be better informed than those who do not.
The clarinet produces sound by the vibration of its reed.</computeroutput>
</screen>
</para>
</listitem>
2001-07-10 14:25:50 +00:00
</itemizedlist>
2001-09-04 13:27:31 +00:00
<itemizedlist>
<listitem override="square">
2002-04-01 16:04:17 +00:00
<formalpara><title><anchor id="posixref">POSIX Character Classes</title>
2001-09-04 13:27:31 +00:00
<para><userinput>[:class:]</userinput></para></formalpara>
<indexterm>
<primary>[:</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>:]</secondary>
</indexterm>
<para>This is an alternate method of specifying a range of
characters to match.</para>
</listitem>
<listitem>
<indexterm>
<primary>alnum</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>alphabetic numeric</secondary>
</indexterm>
<para><userinput>[:alnum:]</userinput> matches alphabetic or
numeric characters. This is equivalent to
<userinput>[A-Za-z0-9]</userinput>.</para>
</listitem>
<listitem>
<indexterm>
<primary>alpha</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>alphabetic</secondary>
</indexterm>
<para><userinput>[:alpha:]</userinput> matches alphabetic
characters. This is equivalent to
<userinput>[A-Za-z]</userinput>.</para>
</listitem>
<listitem>
<indexterm>
<primary>blank</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>space tab</secondary>
</indexterm>
<para><userinput>[:blank:]</userinput> matches a space or a
tab.</para>
</listitem>
<listitem>
<indexterm>
<primary>cntrl</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>control</secondary>
</indexterm>
<para><userinput>[:cntrl:]</userinput> matches control
characters.</para>
</listitem>
<listitem>
<indexterm>
<primary>digit</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>decimal digit</secondary>
</indexterm>
<para><userinput>[:digit:]</userinput> matches (decimal)
digits. This is equivalent to
<userinput>[0-9]</userinput>.</para>
</listitem>
<listitem>
<indexterm>
<primary>graph</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>graph</secondary>
</indexterm>
<para><userinput>[:graph:]</userinput> (graphic printable
characters). Matches characters in the range of ASCII 33 -
126. This is the same as <userinput>[:print:]</userinput>,
below, but excluding the space character.</para>
</listitem>
<listitem>
<indexterm>
<primary>lower</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>lowercase</secondary>
</indexterm>
<para><userinput>[:lower:]</userinput> matches lowercase
alphabetic characters. This is equivalent to
<userinput>[a-z]</userinput>.</para>
</listitem>
<listitem>
<indexterm>
<primary>print</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>printable</secondary>
</indexterm>
<para><userinput>[:print:]</userinput> (printable
characters). Matches characters in the range of ASCII 32 -
126. This is the same as <userinput>[:graph:]</userinput>,
above, but adding the space character.</para>
</listitem>
<listitem>
<indexterm>
<primary>space</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>whitespace</secondary>
</indexterm>
<para><userinput>[:space:]</userinput> matches whitespace
characters (space and horizontal tab).</para>
</listitem>
<listitem>
<indexterm>
<primary>upper</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>uppercase</secondary>
</indexterm>
<para><userinput>[:upper:]</userinput> matches uppercase
alphabetic characters. This is equivalent to
<userinput>[A-Z]</userinput>.</para>
</listitem>
<listitem>
<indexterm>
<primary>xdigit</primary>
</indexterm>
<indexterm>
<primary>character range</primary>
<secondary>hexadecimal</secondary>
</indexterm>
<para><userinput>[:xdigit:]</userinput> matches hexadecimal
digits. This is equivalent to
<userinput>[0-9A-Fa-f]</userinput>.</para>
<important>
<para>POSIX character classes generally require quoting
or <link linkend="dblbrackets">double brackets</link>
([[ ]]).</para>
<para>
<screen><prompt>bash$ </prompt><userinput>grep [[:digit:]] test.file</userinput>
<computeroutput>abc=723</computeroutput>
</screen>
</para>
<para>These character classes may even be used with <link
linkend="globbingref">globbing</link>, to a limited
extent.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>ls -l ?[[:digit:]][[:digit:]]?</userinput>
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 21 14:47 a33b</computeroutput>
</screen>
</para>
<para>To see POSIX character classes used in scripts, refer to
<xref linkend="ex49"> and <xref linkend="lowercase">.</para>
</important>
</listitem>
</itemizedlist>
2001-07-10 14:25:50 +00:00
<para><link linkend="sedref">Sed</link>, <link
linkend="awkref">awk</link>, and <link
linkend="perlref">Perl</link>, used as filters in scripts, take
REs as arguments when "sifting" or transforming files or I/O
streams. See <xref linkend="behead"> and <xref linkend="tree">
for illustrations of this.</para>
2001-09-04 13:27:31 +00:00
<para>"Sed & Awk", by Dougherty and Robbins gives a very complete
and lucid treatment of REs (see the <xref
linkend="biblio">).</para>
</sect1> <!-- A Brief Introduction to Regular Expressions -->
<sect1 id="globbingref">
<title>Globbing</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>Bash itself cannot recognize Regular Expressions. In
scripts, commands and utilities, such as
<link linkend="sedref">sed</link> and <link
linkend="awkref">awk</link>, interpret RE's.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>Bash does carry out filename expansion, a process known
as <quote>globbing</quote>, but this does
<emphasis>not</emphasis> use the standard RE set. Instead,
globbing recognizes and expands wildcards. Globbing interprets
the standard wildcard characters, <token>*</token> and
<token>?</token>, character lists in square brackets, and
certain other special characters (such as <token>^</token>
for negating the sense of a match). There are some important
limitations on wildcard characters in globbing, however.
Strings containing <replaceable>*</replaceable> will not
match filenames that start with a dot, as, for example,
<filename>.bashrc</filename>.
2001-07-10 14:25:50 +00:00
<footnote>
<para>
Filename expansion <emphasis>can</emphasis>
match dotfiles, but only if the pattern explicitly includes the dot.
<programlisting>~/[.]bashrc # Will not expand to ~/.bashrc
~/?bashrc # Neither will this.
# Wild cards and metacharacters will not expand to a dot in globbing.
~/.[b]ashrc # Will expand to ~./bashrc
~/.ba?hrc # Likewise.
~/.bashr* # Likewise.
# Setting the "dotglob" option turns this off.
# Thanks, S.C.</programlisting>
</para>
</footnote>
Likewise, the <replaceable>?</replaceable> has a different
meaning in globbing than as part of an RE.</para>
2001-09-04 13:27:31 +00:00
<para>
<screen>
<prompt>bash$ </prompt><userinput>ls -l</userinput>
<computeroutput>total 2
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 a.1
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1
-rw-rw-r-- 1 bozo bozo 466 Aug 6 17:48 t2.sh
-rw-rw-r-- 1 bozo bozo 758 Jul 30 09:02 test1.txt</computeroutput>
<prompt>bash$ </prompt><userinput>ls -l t?.sh</userinput>
<computeroutput>-rw-rw-r-- 1 bozo bozo 466 Aug 6 17:48 t2.sh</computeroutput>
<prompt>bash$ </prompt><userinput>ls -l [ab]*</userinput>
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 a.1
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1</computeroutput>
<prompt>bash$ </prompt><userinput>ls -l [a-c]*</userinput>
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 a.1
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1</computeroutput>
<prompt>bash$ </prompt><userinput>ls -l [^ab]*</userinput>
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1
-rw-rw-r-- 1 bozo bozo 466 Aug 6 17:48 t2.sh
-rw-rw-r-- 1 bozo bozo 758 Jul 30 09:02 test1.txt</computeroutput>
<prompt>bash$ </prompt><userinput>ls -l {b*,c*,*est*}</userinput>
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1
-rw-rw-r-- 1 bozo bozo 758 Jul 30 09:02 test1.txt</computeroutput>
2001-10-15 14:21:41 +00:00
<prompt>bash$ </prompt><userinput>echo *</userinput>
<computeroutput>a.1 b.1 c.1 t2.sh test1.txt</computeroutput>
<prompt>bash$ </prompt><userinput>echo t*</userinput>
<computeroutput>t2.sh test1.txt</computeroutput>
2001-09-04 13:27:31 +00:00
</screen>
</para>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<para>Even an <link linkend="echoref">echo</link> command performs
wildcard expansion on filenames.</para>
2001-09-04 13:27:31 +00:00
<para>See also <xref linkend="listglob">.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1> <!-- Globbing -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- Regular Expressions -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="subshells">
<title>Subshells</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="subshellsref"></para>
<para>Running a shell script launches another instance of the
command processor. Just as your commands are interpreted at the
command line prompt, similarly does a script batch process a list
of commands in a file. Each shell script running is, in effect,
a subprocess of the <link linkend="forkref">parent</link> shell,
the one that gives you the prompt at the console or in an xterm
window.</para>
<para>A shell script can also launch subprocesses. These
<emphasis>subshells</emphasis> let the script do
parallel processing, in effect executing multiple subtasks
simultaneously.</para>
2001-09-04 13:27:31 +00:00
<variablelist id="subshellparens">
<title><anchor id="subshellparens1">Command List in Parentheses</title>
<varlistentry>
<term>( command1; command2; command3; ... )</term>
2001-07-10 14:25:50 +00:00
<listitem>
<para>A command list embedded between
<replaceable>parentheses</replaceable> runs as a
subshell.</para>
</listitem>
2001-09-04 13:27:31 +00:00
</varlistentry>
</variablelist>
2001-07-10 14:25:50 +00:00
<note><para><anchor id="parvis">Variables in a subshell are
<emphasis>not</emphasis> visible outside the block of code
in the subshell. They are not accessible to the <link
linkend="forkref">parent process</link>, to the shell
that launched the subshell. These are, in effect, <link
linkend="localref">local variables</link>.</para></note>
<example id="subshell">
<title>Variable scope in a subshell</title>
<programlisting>&subshell;</programlisting>
</example>
<para>See also <xref linkend="subpit">.</para>
<para>+</para>
<para>Directory changes made in a subshell do not carry over to the
parent shell.</para>
<example id="allprofs">
<title>List User Profiles</title>
<programlisting>&allprofs;</programlisting>
</example>
<para>A subshell may be used to set up a <quote>dedicated
environment</quote> for a command group.
<programlisting>COMMAND1
COMMAND2
COMMAND3
(
IFS=:
PATH=/bin
unset TERMINFO
set -C
shift 5
COMMAND4
COMMAND5
exit 3 # Only exits the subshell.
)
# The parent shell has not been affected, and the environment is preserved.
COMMAND6
COMMAND7</programlisting>
One application of this is testing whether a variable is defined.
<programlisting>if (set -u; : $variable) 2&gt; /dev/null
then
echo "Variable is set."
fi
# Could also be written [[ ${variable-x} != x || ${variable-y} != y ]]
# or [[ ${variable-x} != x$variable ]]
# or [[ ${variable+x} = x ]])</programlisting>
Another application is checking for a lock file:
<programlisting>if (set -C; : &gt; lock_file) 2&gt; /dev/null
then
echo "Another user is already running that script."
exit 65
fi
# Thanks, S.C.</programlisting>
</para>
<para>Processes may execute in parallel within different
subshells. This permits breaking a complex task into subcomponents
processed concurrently.</para>
<example id="parallel-processes">
<title>Running parallel processes in subshells</title>
<programlisting>
(cat list1 list2 list3 | sort | uniq > list123) &
(cat list4 list5 list6 | sort | uniq > list456) &
# Merges and sorts both sets of lists simultaneously.
# Running in background ensures parallel execution.
#
# Same effect as
# cat list1 list2 list3 | sort | uniq > list123 &
# cat list4 list5 list6 | sort | uniq > list456 &
wait # Don't execute the next command until subshells finish.
diff list123 list456</programlisting>
</example>
<para>Redirecting I/O to a subshell uses the <quote>|</quote> pipe
operator, as in <userinput>ls -al | (command)</userinput>.</para>
<note><para>A command block between <replaceable>curly
braces</replaceable> does <emphasis>not</emphasis> launch
a subshell.</para>
<para>{ command1; command2; command3; ... }</para></note>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Subshells -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="restricted-sh">
<title>Restricted Shells</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="disabledcommref0">
<title><anchor id="disabledcommref">Disabled commands in restricted
shells</title>
<varlistentry>
<term></term>
<listitem>
<formalpara><title></title>
2001-07-10 14:25:50 +00:00
<para>Running a script or portion of a script in
<emphasis>restricted</emphasis> mode disables certain commands that
would otherwise be available. This is a security measure intended
to limit the privileges of the script user and to minimize possible
damage from running the script.</para>
2001-09-04 13:27:31 +00:00
</formalpara>
</listitem>
</varlistentry>
<varlistentry>
<term></term>
2001-07-10 14:25:50 +00:00
<listitem>
2001-09-04 13:27:31 +00:00
<formalpara><title></title>
2001-07-10 14:25:50 +00:00
<para>Using <replaceable>cd</replaceable> to change the working
directory.</para>
2001-09-04 13:27:31 +00:00
</formalpara>
</listitem>
</varlistentry>
<varlistentry>
<term></term>
<listitem>
2002-06-03 14:35:48 +00:00
<para>Changing the values of the
<replaceable>$PATH</replaceable>,
<replaceable>$SHELL</replaceable>,
<replaceable>$BASH_ENV</replaceable>,
or <replaceable>$ENV</replaceable> <link
linkend="envref">environmental variables</link>.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term></term>
<listitem>
2001-07-10 14:25:50 +00:00
<para>Reading or changing the <replaceable>$SHELLOPTS</replaceable>,
shell environmental options.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term></term>
<listitem>
2001-07-10 14:25:50 +00:00
<para>Output redirection.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term></term>
<listitem>
2001-07-10 14:25:50 +00:00
<para>Invoking commands containing one or more
<token>/'s</token>.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term></term>
<listitem>
2001-07-10 14:25:50 +00:00
<para>Invoking <emphasis>exec</emphasis> to substitute a different
process for the shell.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term></term>
<listitem>
2001-07-10 14:25:50 +00:00
<para>Various other commands that would enable monkeying
with or attempting to subvert the script for an unintended
purpose.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term></term>
<listitem>
2001-07-10 14:25:50 +00:00
<para>Getting out of restricted mode within the script.</para>
</listitem>
2001-09-04 13:27:31 +00:00
</varlistentry>
</variablelist>
2001-07-10 14:25:50 +00:00
<example id="restricted">
<title>Running a script in restricted mode</title>
<programlisting>&restricted;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Restricted Shells -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="process-sub">
<title>Process Substitution</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="processsubref"><replaceable>Process
substitution</replaceable> is the counterpart to <link
linkend="commandsubref">command substitution</link>. Command
substitution sets a variable to the result of a command, as in
<command>dir_contents=`ls -al`</command> or <command>xref=$(
grep word datafile)</command>. Process substitution feeds the
output of a process to another process (in other words, it sends
the results of a command to another command).</para>
2001-09-04 13:27:31 +00:00
<variablelist id="commandsparens">
<title><anchor id="commandsparens1">Command substitution template</title>
<varlistentry>
<term>command within parentheses</term>
2001-07-10 14:25:50 +00:00
<listitem>
<para><command>&gt;(command)</command></para>
<para><command>&lt;(command)</command></para>
<para>These initiate process substitution. This uses
<filename>/dev/fd/&lt;n&gt;</filename> files to send the
results of the process within parentheses to another process.
<footnote><para>This has the same effect as a
<link linkend="namedpiperef">named pipe</link> (temp
file), and, in fact, named pipes were at one time used
in process substitution.</para></footnote>
2001-09-04 13:27:31 +00:00
</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<note><para>There is <emphasis>no</emphasis> space between the
the <quote><</quote> or <quote>></quote> and the parentheses.
Space there would give an error message.</para></note>
2001-07-10 14:25:50 +00:00
</listitem>
2001-09-04 13:27:31 +00:00
</varlistentry>
</variablelist>
2001-07-10 14:25:50 +00:00
<para>
<screen><prompt>bash$ </prompt><userinput>echo >(true)</userinput>
<computeroutput>/dev/fd/63</computeroutput>
<prompt>bash$ </prompt><userinput>echo <(true)</userinput>
<computeroutput>/dev/fd/63</computeroutput>
</screen>
Bash creates a pipe with two <link linkend="fdref">file
descriptors</link>, <filename>--fIn</filename> and
<filename>fOut--</filename>. The <filename>stdin</filename>
of <link linkend="trueref">true</link> connects
to <filename>fOut</filename> (dup2(fOut, 0)),
then Bash passes a <filename>/dev/fd/fIn</filename>
argument to <command>echo</command>. On systems lacking
<filename>/dev/fd/&lt;n&gt;</filename> files, Bash may use
temporary files. (Thanks, S.C.)</para>
<para><programlisting>cat <(ls -l)
# Same as ls -l | cat
sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) <(ls -l /usr/X11R6/bin)
# Lists all the files in the 3 main 'bin' directories, and sorts by filename.
# Note that three (count 'em) distinct commands are fed to 'sort'.
diff <(command1) <(command2) # Gives difference in command output.
2002-06-03 14:35:48 +00:00
tar cf >(bzip2 -c > file.tar.bz2) $directory_name
# Calls "tar cf /dev/fd/?? $directory_name", and "bzip2 -c > file.tar.bz2".
2001-07-10 14:25:50 +00:00
#
# Because of the /dev/fd/&lt;n&gt; system feature,
# the pipe between both commands does not need to be named.
#
# This can be emulated.
#
bzip2 -c < pipe > file.tar.bz2&
2002-06-03 14:35:48 +00:00
tar cf pipe $directory_name
2001-07-10 14:25:50 +00:00
rm pipe
# or
exec 3>&1
2002-06-03 14:35:48 +00:00
tar cf /dev/fd/4 $directory_name 4>&1 >&3 3>&- | bzip2 -c > file.tar.bz2 3>&-
2001-07-10 14:25:50 +00:00
exec 3>&-
# Thanks, S.C.</programlisting></para>
<para>A reader of this document sent in the following interesting
example of process substitution.</para>
<para><programlisting># Script fragment taken from SuSE distribution:
while read des what mask iface; do
# Some commands ...
done < <(route -n)
# To test it, let's make it do something.
while read des what mask iface; do
echo $des $what $mask $iface
done < <(route -n)
# Output:
# Kernel IP routing table
# Destination Gateway Genmask Flags Metric Ref Use Iface
# 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
# As S.C. points out, an easier-to-understand equivalent is:
route -n |
while read des what mask iface; do # Variables set from output of pipe.
echo $des $what $mask $iface
done # Same output as above.</programlisting></para>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Process Substitution -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="functions">
<title>Functions</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="functionref"></para>
<para>Like <quote>real</quote> programming languages,
Bash has functions, though in a somewhat limited implementation.
A function is a subroutine, a <link linkend="codeblockref">code
block</link> that implements a set of operations, a <quote>black
box</quote> that performs a specified task. Wherever there is
repetitive code, when a task repeats with only slight variations,
then consider using a function.</para>
<para><cmdsynopsis>
<command>function</command>
<arg choice="plain"><replaceable>function_name</replaceable></arg>
<arg choice="plain">{</arg><sbr>
<arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr>
<arg choice="plain">}</arg><sbr>
</cmdsynopsis>
or
<cmdsynopsis>
<arg choice="plain"><replaceable>function_name</replaceable></arg>
<arg choice="plain">()</arg>
<arg choice="plain">{</arg><sbr>
<arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr>
<arg choice="plain">}</arg><sbr>
</cmdsynopsis>
</para>
<para>This second form will cheer the hearts of C programmers
(and is more portable).</para>
<para>As in C, the function's opening bracket may optionally appear
on the second line.</para>
<para><cmdsynopsis>
<arg choice="plain"><replaceable>function_name</replaceable></arg>
<arg choice="plain">()</arg><sbr>
<arg choice="plain">{</arg><sbr>
<arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr>
<arg choice="plain">}</arg><sbr>
</cmdsynopsis>
</para>
<para>Functions are called, <firstterm>triggered</firstterm>, simply by
invoking their names.</para>
<example id="ex59">
<title>Simple function</title>
<programlisting>&ex59;</programlisting>
</example>
<para>The function definition must precede the first call to
it. There is no method of <quote>declaring</quote> the function,
as, for example, in C.
<programlisting># f1
# Will give an error message, since function "f1" not yet defined.
# However...
f1 ()
{
echo "Calling function \"f2\" from within function \"f1\"."
f2
}
f2 ()
{
echo "Function \"f2\"."
}
f1 # Function "f2" is not actually called until this point,
# although it is referenced before its definition.
# This is permissable.
# Thanks, S.C.</programlisting>
</para>
<para>It is even possible to nest a function within another function,
although this is not very useful.
<programlisting>f1 ()
{
f2 () # nested
{
echo "Function \"f2\", inside \"f1\"."
}
}
# f2
# Gives an error message.
f1 # Does nothing, since calling "f1" does not automatically call "f2".
f2 # Now, it's all right to call "f2",
# since its definition has been made visible by calling "f1".
# Thanks, S.C.</programlisting>
</para>
<para>Function declarations can appear in unlikely places, even where a
command would otherwise go.
<programlisting>ls -l | foo() { echo "foo"; } # Permissable, but useless.
if [ "$USER" = bozo ]
then
bozo_greet () # Function definition embedded in an if/then construct.
{
echo "Hello, Bozo."
}
fi
bozo_greet # Works only for Bozo, and other users get an error.
# Something like this might be useful in some contexts.
NO_EXIT=1 # Will enable function definition below.
[[ $NO_EXIT -eq 1 ]] && exit() { true; } # Function definition in an "and-list".
# If $NO_EXIT is 1, declares "exit ()".
# This disables the "exit" builtin by aliasing it to "true".
exit # Invokes "exit ()" function, not "exit" builtin.
# Thanks, S.C.</programlisting>
</para>
2001-09-04 13:27:31 +00:00
<sect1 id="complexfunct">
2001-07-10 14:25:50 +00:00
<title>Complex Functions and Function Complexities</title>
<para>Functions may process arguments passed to them and return
an <link linkend="exitstatusref">exit status</link> to the script
for further processing.</para>
<programlisting>function_name $arg1 $arg2</programlisting>
<para>The function refers to the passed arguments by position (as if they were
<link linkend="posparamref">positional parameters</link>),
that is, <varname>$1</varname>, <varname>$2</varname>, and
so forth.</para>
<example id="ex60">
<title>Function Taking Parameters</title>
<programlisting>&ex60;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<important><para>The <link linkend="shiftref">shift</link>
command works on arguments passed to functions (see <xref
linkend="multiplication">).</para></important>
2001-07-10 14:25:50 +00:00
<note><para>In contrast to certain other programming languages,
shell scripts normally pass only value parameters to functions.
<footnote><para><link linkend="ivrref">Indirect variable
references</link> (see <xref linkend="ex78">) provide a clumsy
sort of mechanism for passing variable pointers to functions.
<programlisting>&refparams;</programlisting>
</para></footnote>
Variable names (which are actually pointers), if passed as
parameters to functions, will be treated as string literals
and cannot be dereferenced. <emphasis>Functions interpret their
arguments literally.</emphasis></para></note>
2001-09-04 13:27:31 +00:00
<variablelist id="exitreturn">
<title><anchor id="exitreturn1">Exit and Return</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><command>exit status</command></term>
2001-07-10 14:25:50 +00:00
<listitem>
<para>Functions return a value, called an <firstterm>exit
status</firstterm>. The exit status may be explicitly
specified by a <command>return</command> statement,
otherwise it is the exit status of the last command
in the function (<returnvalue>0</returnvalue> if
successful, and a non-zero error code if not). This
<link linkend="exitstatusref">exit status</link>
may be used in the script by referencing it as
<link linkend="xstatvarref">$?</link>. This mechanism
effectively permits script functions to have a <quote>return
value</quote> similar to C functions.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>return</command></term>
<indexterm>
<primary>return</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>return</secondary>
</indexterm>
<listitem>
<para>Terminates a function. A <command>return</command> command
<footnote><para>The <command>return</command> command is a
Bash <link linkend="builtinref">builtin</link>.</para></footnote>
2001-09-04 13:27:31 +00:00
optionally takes an <emphasis>integer</emphasis>
argument, which is returned to the calling script as
the <quote>exit status</quote> of the function, and
this exit status is assigned to the variable <link
linkend="xstatvarref">$?</link>.</para>
2001-07-10 14:25:50 +00:00
<example id="max">
<title>Maximum of two numbers</title>
<programlisting>&max;</programlisting>
</example>
<tip>
<para>For a function to return a string or array, use a
dedicated variable.
<programlisting>count_lines_in_etc_passwd()
{
[[ -r /etc/passwd ]] && REPLY=$(echo $(wc -l < /etc/passwd))
# If /etc/passwd is readable, set REPLY to line count.
# Returns both a parameter value and status information.
}
if count_lines_in_etc_passwd
then
echo "There are $REPLY lines in /etc/passwd."
else
echo "Cannot count lines in /etc/passwd."
fi
# Thanks, S.C.</programlisting>
</para>
</tip>
<example id="ex61">
<title>Converting numbers to Roman numerals</title>
<programlisting>&ex61;</programlisting>
</example>
<para>See also <xref linkend="isalpha">.</para>
2001-09-04 13:27:31 +00:00
<important>
<para>The largest positive integer a function can return is
2002-04-01 16:04:17 +00:00
256. The <command>return</command> command is closely tied
to the concept of <link linkend="exitstatusref">exit
2001-09-04 13:27:31 +00:00
status</link>, which accounts for this particular
2002-04-01 16:04:17 +00:00
limitation. Fortunately, there are various <link
linkend="rvt">workarounds</link> for those situations
requiring a large integer return value from a
function.</para>
2001-09-04 13:27:31 +00:00
<example id="returntest">
<title>Testing large return values in a function</title>
<programlisting>&returntest;</programlisting>
</example>
<para>As we have seen, a function can return a large negative
value. This also permits returning large positive integer,
using a bit of trickery.</para>
2002-01-07 15:24:19 +00:00
<para>An alternate method of accomplishing this is to simply
assign the <quote>return value</quote> to a global variable.
<programlisting>Return_Val= # Global variable to hold oversize return value of function.
alt_return_test ()
{
fvar=$1
Return_Val=$fvar
return # Returns 0 (success).
}
alt_return_test 1
echo $? # 0
echo "return value = $Return_Val" # 1
alt_return_test 256
echo "return value = $Return_Val" # 256
alt_return_test 257
echo "return value = $Return_Val" # 257
alt_return_test 25701
echo "return value = $Return_Val" #25701</programlisting>
</para>
2001-09-04 13:27:31 +00:00
<example id="max2">
<title>Comparing two large integers</title>
<programlisting>&max2;</programlisting>
</example>
<para>See also <xref linkend="daysbetween">.</para>
2002-04-01 16:04:17 +00:00
<para><userinput>Exercise:</userinput> Using what we have
just learned, extend the previous <link
2001-09-04 13:27:31 +00:00
linkend="ex61">Roman numerals example</link> to accept
arbitrarily large input.</para>
</important>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
2001-09-04 13:27:31 +00:00
</variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="redstdinfunc">
<title><anchor id="redstdinfunc1">Redirection</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term><replaceable>Redirecting the stdin of a
function</replaceable></term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>redirection</primary>
<secondary>stdin</secondary>
</indexterm>
<listitem>
<para>A function is essentially a <link
linkend="codeblockref">code block</link>, which means its
<filename>stdin</filename> can be redirected (as in <xref
linkend="ex8">).</para>
<example id="realname">
<title>Real name from username</title>
<programlisting>&realname;</programlisting>
</example>
<para>There is an alternative, and perhaps less confusing
method of redirecting a function's
<filename>stdin</filename>. This involves redirecting the
<filename>stdin</filename> to an embedded bracketed code
block within the function.
<programlisting># Instead of:
Function ()
{
...
} < file
# Try this:
Function ()
{
{
...
} < file
}
# Similarly,
Function () # This works.
{
{
echo $*
} | tr a b
}
Function () # This doesn't work.
{
echo $*
} | tr a b # A nested code block is mandatory here.
# Thanks, S.C.</programlisting>
</para>
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Complex Functions and Function Complexities -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="localvar">
2002-01-07 15:24:19 +00:00
<title>Local Variables</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="localref">
2002-01-07 15:24:19 +00:00
<title><anchor id="localref1">What makes a variable <quote>local</quote>?</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
2001-09-04 13:27:31 +00:00
<term>local variables</term>
2001-07-10 14:25:50 +00:00
<indexterm>
<primary>variable</primary>
<secondary>local</secondary>
</indexterm>
<listitem>
<para>A variable declared as <firstterm>local</firstterm>
is one that is visible only within the <link
2001-09-04 13:27:31 +00:00
linkend="codeblockref">block of code</link> in which it
appears. It has local <quote>scope</quote>. In
a function, a <emphasis>local variable</emphasis> has
meaning only within that function block.</para>
2001-07-10 14:25:50 +00:00
<example id="ex62">
<title>Local variable visibility</title>
<programlisting>&ex62;</programlisting>
</example>
2002-01-07 15:24:19 +00:00
<caution>
<para>Before a function is called, <emphasis>all</emphasis>
variables declared within the function are invisible outside
the body of the function, not just those explicitly declared
as <emphasis>local</emphasis>.
<programlisting>#!/bin/bash
func ()
{
global_var=37 # Visible only within the function block
#+ before the function has been called.
} # END OF FUNCTION
echo "global_var = $global_var" # global_var =
# Function "func" has not yet been called,
#+ so $global_var is not visible here.
func
echo "global_var = $global_var" # global_var = 37
# Has been set by function call.</programlisting>
</para>
</caution>
</listitem>
</varlistentry>
</variablelist>
<sect2 id="locvarrecur">
<title>Local variables make recursion possible.</title>
2001-10-15 14:21:41 +00:00
<para>Local variables permit recursion,
<footnote>
<para><anchor id="recursionref">
<link linkend="mayerref">Herbert Mayer</link>
defines <emphasis>recursion</emphasis> as
<quote>...expressing an algorithm by using a simpler
version of that same algorithm...</quote> A recursive
function is one that calls itself.</para></footnote>
but this practice generally involves much computational
overhead and is definitely <emphasis>not</emphasis>
recommended in a shell script.
2001-07-10 14:25:50 +00:00
<footnote><para>Too many levels of recursion may crash a
script with a segfault.
<programlisting>#!/bin/bash
recursive_function ()
{
(( $1 < $2 )) && f $(( $1 + 1 )) $2;
2001-10-15 14:21:41 +00:00
# As long as 1st parameter is less than 2nd,
#+ increment 1st and recurse.
2001-07-10 14:25:50 +00:00
}
2001-10-15 14:21:41 +00:00
recursive_function 1 50000 # Recurse 50,000 levels!
# Segfaults, of course.
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
# Recursion this deep might cause even a C program to segfault,
#+ by using up all the memory allotted to the stack.
2001-07-10 14:25:50 +00:00
# Thanks, S.C.
exit 0 # This script will not exit normally.</programlisting>
</para></footnote>
</para>
<example id="ex63">
<title>Recursion, using a local variable</title>
<programlisting>&ex63;</programlisting>
</example>
<para>See also <xref linkend="primes"> for an example of
recursion in a script. Be aware that recursion is
2001-10-15 14:21:41 +00:00
resource-intensive and executes slowly, and is therefore
generally not appropriate to use in a script.</para>
2001-07-10 14:25:50 +00:00
2002-01-07 15:24:19 +00:00
</sect2>
2001-07-10 14:25:50 +00:00
2002-01-07 15:24:19 +00:00
</sect1> <!-- Local Variables -->
2001-09-04 13:27:31 +00:00
</chapter> <!-- Functions -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="aliases">
<title>Aliases</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="aliasref"></para>
<indexterm>
<primary>alias</primary>
</indexterm>
2001-09-04 13:27:31 +00:00
<para>A Bash <emphasis>alias</emphasis> is essentially nothing more than
2001-07-10 14:25:50 +00:00
a keyboard shortcut, an abbreviation, a means of avoiding
typing a long command sequence. If, for example, we include
<command>alias lm="ls -l | more"</command> in the <link
2002-06-03 14:35:48 +00:00
linkend="filesref1"><filename>~/.bashrc</filename> file</link>,
2001-07-10 14:25:50 +00:00
then each <userinput>lm</userinput> typed at the command
line will automatically be replaced by a <command>ls -l |
more</command>. This can save a great deal of typing at the
command line and avoid having to remember complex combinations of
commands and options. Setting <command>alias rm="rm -i"</command>
(interactive mode delete) may save a good deal of grief, since
it can prevent inadvertently losing important files.</para>
<para>In a script, aliases have very limited usefulness. It would be
2001-09-04 13:27:31 +00:00
quite nice if aliases could assume some of the functionality of
the C preprocessor, such as macro expansion, but unfortunately
Bash does not expand arguments within the alias body.
<footnote><para>However, aliases do seem to expand positional
parameters.</para></footnote>
Moreover, a script fails to expand an alias itself
within <quote>compound constructs</quote>, such as <link
linkend="ifthen">if/then</link> statements, loops, and
functions. An added limitation is that an alias will not expand
recursively. Almost invariably, whatever we would like an alias
2001-07-10 14:25:50 +00:00
to do could be accomplished much more effectively with a <link
linkend="functionref">function</link>.</para>
<example id="al">
<title>Aliases within a script</title>
<programlisting>&al;</programlisting>
</example>
2002-06-03 14:35:48 +00:00
<para>The <command>unalias</command> command removes a previously
set <emphasis>alias</emphasis>.</para>
2001-07-10 14:25:50 +00:00
<example id="unal">
<title><command>unalias</command>: Setting and unsetting an alias</title>
<programlisting>&unal;</programlisting>
</example>
<screen><prompt>bash$ </prompt><userinput>./unalias.sh</userinput>
<computeroutput>
total 6
drwxrwxr-x 2 bozo bozo 3072 Feb 6 14:04 .
drwxr-xr-x 40 bozo bozo 2048 Feb 6 14:04 ..
-rwxr-xr-x 1 bozo bozo 199 Feb 6 14:04 unalias.sh
./unalias.sh: llm: command not found
</computeroutput></screen>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Aliases -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="list-cons">
<title>List Constructs</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="listconsref"></para>
<indexterm>
<primary>&&</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>&&</secondary>
</indexterm>
<indexterm>
<primary>AND</primary>
<secondary>list</secondary>
</indexterm>
<indexterm>
<primary>||</primary>
</indexterm>
<indexterm>
<primary>special character</primary>
<secondary>||</secondary>
</indexterm>
<indexterm>
<primary>OR</primary>
<secondary>list</secondary>
</indexterm>
<para>The <quote>and list</quote> and <quote>or list</quote>
constructs provide a means of processing a number of commands
consecutively. These can effectively replace complex
nested <command>if</command>/<command>then</command> or even
<command>case</command> statements.</para>
2001-09-04 13:27:31 +00:00
<variablelist id="lcons">
<title><anchor id="lcons1">Chaining together commands</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term>and list</term>
<listitem>
<para><programlisting>command-1 && command-2 && command-3 && ... command-n</programlisting>
Each command executes in turn provided that
the previous command has given a return value of
<returnvalue>true</returnvalue> (zero). At the first
<returnvalue>false</returnvalue> (non-zero) return, the
command chain terminates (the first command returning
<returnvalue>false</returnvalue> is the last one to
execute).</para>
<example id="ex64">
<title>Using an <quote>and list</quote> to test for command-line arguments</title>
<programlisting>&ex64;</programlisting>
</example>
<example id="andlist2">
<title>Another command-line arg test using an <quote>and list</quote></title>
<programlisting>&andlist2;</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
<term>or list</term>
<listitem>
<para><programlisting>command-1 || command-2 || command-3 || ... command-n</programlisting>
Each command executes in turn for as long as the previous
command returns <returnvalue>false</returnvalue>. At
the first <returnvalue>true</returnvalue> return, the
command chain terminates (the first command returning
<returnvalue>true</returnvalue> is the last one to
execute). This is obviously the inverse of the <quote>and
list</quote>.</para>
<example id="ex65">
<title>Using <quote>or lists</quote> in combination with an <quote>and list</quote></title>
<programlisting>&ex65;</programlisting>
</example>
<caution><para>If the first command in an <quote>or list</quote>
returns <returnvalue>true</returnvalue>, it
<replaceable>will</replaceable> execute.</para></caution>
</listitem>
</varlistentry>
</variablelist>
<important><para>The <link linkend="exitstatusref">exit
status</link> of an <userinput>and list</userinput> or an
<userinput>or list</userinput> is the exit status of the last
command executed.</para></important>
<para>Clever combinations of <quote>and</quote> and <quote>or</quote>
lists are possible, but the logic may easily become convoluted and
require extensive debugging.
<programlisting>false && true || echo false # false
# Same result as
( false && true ) || echo false # false
# But *not*
false && ( true || echo false ) # (nothing echoed)
# Note left-to-right grouping and evaluation of statements,
# since the logic operators "&&" and "||" have equal precedence.
# It's best to avoid such complexities, unless you know what you're doing.
# Thanks, S.C.</programlisting>
</para>
2001-09-04 13:27:31 +00:00
<para>See <xref linkend="daysbetween"> for an illustration of using
an <userinput>and / or list</userinput> to test variables.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- List Constructs -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="arrays">
<title>Arrays</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="arrayref"></para>
2002-04-01 16:04:17 +00:00
<para>Newer versions of Bash support one-dimensional arrays.
Array elements may be initialized with the
2002-06-17 13:17:07 +00:00
<userinput>variable[xx]</userinput> notation. Alternatively,
2002-04-01 16:04:17 +00:00
a script may introduce the entire array by an explicit
<userinput>declare -a variable</userinput> statement. To
dereference (find the contents of) an array element, use
<firstterm>curly bracket</firstterm> notation, that is,
<userinput>${variable[xx]}</userinput>.</para>
2001-07-10 14:25:50 +00:00
<example id="ex66">
<title>Simple array usage</title>
<programlisting>&ex66;</programlisting>
</example>
2002-06-17 13:17:07 +00:00
<para>Array variables have a syntax all their own, and even
2001-10-15 14:21:41 +00:00
standard Bash commands and operators have special options adapted
for array use.</para>
<para>
2002-04-01 16:04:17 +00:00
<programlisting>array=( zero one two three four five )
2001-10-15 14:21:41 +00:00
echo ${array[0]} # zero
echo ${array:0} # zero
# Parameter expansion of first element.
echo ${array:1} # ero
# Parameter expansion of first element,
#+ starting at position #1 (2nd character).
echo ${#array} # 4
# Length of first element of array.</programlisting>
</para>
<para>In an array context, some Bash <link
linkend="builtinref">builtins</link> have a slightly altered
meaning. For example, <link linkend="unsetref">unset</link>
deletes array elements, or even an entire array.</para>
2001-07-10 14:25:50 +00:00
<example id="ex67">
<title>Some special properties of arrays</title>
<programlisting>&ex67;</programlisting>
</example>
<para>As seen in the previous example, either
<command>${array_name[@]}</command> or
<command>${array_name[*]}</command> refers to
<emphasis>all</emphasis> the elements of the array.
Similarly, to get a count of the number of elements in an
array, use either <command>${#array_name[@]}</command>
or <command>${#array_name[*]}</command>.
<command>${#array_name}</command> is the length (number of
characters) of <command>${array_name[0]}</command>, the first
element of the array.</para>
<example id="emptyarray">
<title>Of empty arrays and empty elements</title>
<programlisting>&emptyarray;</programlisting>
</example>
<para>The relationship of <command>${array_name[@]}</command>
and <command>${array_name[*]}</command> is analogous to that
between <link linkend="appref">$@ and $*</link>. This powerful
array notation has a number of uses.</para>
<para>
<programlisting># Copying an array.
array2=( "${array1[@]}" )
2002-04-01 16:04:17 +00:00
# or
array2="${array1[@]}"
2001-07-10 14:25:50 +00:00
# Adding an element to an array.
array=( "${array[@]}" "new element" )
# or
array[${#array[*]}]="new element"
# Thanks, S.C.</programlisting>
</para>
2002-04-01 16:04:17 +00:00
<tip>
<para>The <command>array=( element1 element2 ... elementN )</command>
initialization operation, with the help of <link
linkend="commandsubref">command substitution</link>, makes it
possible to load the contents of a text file into an array.</para>
<para>
<programlisting>#!/bin/bash
filename=sample_file
# cat sample_file
#
# 1 a b c
# 2 d e fg
declare -a array1
array1=( `cat "$filename" | tr '\n' ' '`) # Loads contents
# of $filename into array1.
# list file to stdout.
# change linefeeds in file to spaces.
echo ${array1[@]} # List the array.
# 1 a b c 2 d e fg
#
# Each whitespace-separated "word" in the file
#+ has been assigned to an element of the array.
element_count=${#array1[*]}
echo $element_count # 8</programlisting>
</para>
</tip>
2001-07-10 14:25:50 +00:00
<para>Arrays permit deploying old familiar algorithms as shell scripts.
Whether this is necessarily a good idea is left to the reader to
decide.</para>
<example id="bubble">
<title>An old friend:
<emphasis>The Bubble Sort</emphasis></title>
<programlisting>&bubble;</programlisting>
</example>
<para>--</para>
<para>Arrays enable implementing a shell script version of the <emphasis>Sieve of
2002-06-17 13:17:07 +00:00
Eratosthenes</emphasis>. Of course, a resource-intensive application of this
2001-07-10 14:25:50 +00:00
nature should really be written in a compiled language, such as C. It
runs excruciatingly slowly as a script.</para>
<example id="ex68">
<title>Complex array application:
2002-06-17 13:17:07 +00:00
<emphasis>Sieve of Eratosthenes</emphasis></title>
2001-07-10 14:25:50 +00:00
<programlisting>&ex68;</programlisting>
</example>
2002-06-17 13:17:07 +00:00
<para>Compare this array-based prime number generator with an
alternative that does not use arrays, <xref linkend="primes">.</para>
2001-07-10 14:25:50 +00:00
<para>--</para>
2002-04-01 16:04:17 +00:00
<para>Arrays lend themselves, to some extent, to emulating data
structures for which Bash has no native support.</para>
<example id="stackex">
<title>Emulating a push-down stack</title>
<programlisting>&stackex;</programlisting>
</example>
<para>--</para>
2001-07-10 14:25:50 +00:00
<para>Fancy manipulation of array <quote>subscripts</quote> may require
intermediate variables. For projects involving this, again consider
using a more powerful programming language, such as Perl or C.</para>
<example id="qfunction">
<title>Complex array application:
<emphasis>Exploring a weird mathematical series</emphasis></title>
<programlisting>&qfunction;</programlisting>
</example>
<para>--</para>
<para>Bash supports only one-dimensional arrays, however a little
trickery permits simulating multi-dimensional ones.</para>
<example id="twodim">
<title>Simulating a two-dimensional array, then tilting it</title>
<programlisting>&twodim;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<para>A two-dimensional array is essentially equivalent to a
one-dimensional one, but with additional addressing modes for
referencing and manipulating the individual elements by
<quote>row</quote> and <quote>column</quote> position.</para>
<para>For an even more elaborate example of simulating a
two-dimensional array, see <xref linkend="lifeslow">.</para>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Arrays -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="files">
<title>Files</title>
<variablelist id="filesref">
<title><anchor id="filesref1">startup files</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<term></term>
<listitem>
2002-06-03 14:35:48 +00:00
<para>These files contain the aliases and <link
linkend="envref">environmental variables</link>
made available to Bash running as a user shell and to all
Bash scripts invoked after system initialization.</para>
2001-09-04 13:27:31 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><filename>/etc/profile</filename></term>
2001-07-10 14:25:50 +00:00
<listitem>
<para>systemwide defaults, mostly setting the environment
(all Bourne-type shells, not just Bash
<footnote><para>This does not apply to <command>csh</command>,
<command>tcsh</command>, and other shells not related to or
descended from the classic Bourne shell
(<command>sh</command>).</para></footnote>)</para>
</listitem>
2001-09-04 13:27:31 +00:00
</varlistentry>
<varlistentry>
<term><filename>/etc/bashrc</filename></term>
2001-07-10 14:25:50 +00:00
<listitem>
2002-06-17 13:17:07 +00:00
<para>systemwide functions and <link
2001-07-10 14:25:50 +00:00
linkend="aliasref">aliases</link> for Bash</para>
</listitem>
2001-09-04 13:27:31 +00:00
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><filename><varname>$HOME</varname>/.bash_profile</filename></term>
2001-07-10 14:25:50 +00:00
<listitem>
<para>user-specific Bash environmental default settings,
found in each user's home directory (the local counterpart
to <filename>/etc/profile</filename>)</para>
</listitem>
2001-09-04 13:27:31 +00:00
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<varlistentry>
<term><filename><varname>$HOME</varname>/.bashrc</filename></term>
2001-07-10 14:25:50 +00:00
<listitem>
<para>user-specific Bash init file, found in each user's home
directory (the local counterpart to
<filename>/etc/bashrc</filename>). Only interactive
shells and user scripts read this file. See
<xref linkend="sample-bashrc"> for a sample
<filename>.bashrc</filename> file.</para>
</listitem>
2001-09-04 13:27:31 +00:00
</varlistentry>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<variablelist id="logoutfileref">
<title><anchor id="logoutfileref1">logout file</title>
<varlistentry>
<term><filename><varname>$HOME</varname>/.bash_logout</filename></term>
2001-07-10 14:25:50 +00:00
<listitem>
<para>user-specific instruction file, found in
each user's home directory. Upon exit from a login (Bash)
shell, the commands in this file execute.</para>
</listitem>
2001-09-04 13:27:31 +00:00
</varlistentry>
</variablelist>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- Files -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="devproc">
<title>/dev and /proc</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="devprocref"></para>
<para>A Linux or UNIX machine typically has two special-purpose
directories, <filename class="directory">/dev</filename> and
2001-10-15 14:21:41 +00:00
<filename class="directory">/proc</filename>.</para>
<sect1 id="devref1">
<title><filename class="directory">/dev</filename></title>
<para>The <filename class="directory">/dev</filename> directory
contains entries for the physical <emphasis>devices</emphasis>
that may or may not be present in the hardware.
<footnote>
<para>The entries in <filename class="directory">/dev</filename>
provide mount points for physical and virtual devices. These
entries use very little drive space.</para>
<para>Some devices, such as <filename>/dev/null</filename>,
<filename>/dev/zero</filename>,
2001-07-10 14:25:50 +00:00
and <filename>/dev/urandom</filename> are virtual. They
are not actual physical devices and exist only in
software.</para>
</footnote>
2001-10-15 14:21:41 +00:00
The hard drive partitions containing the mounted filesystem(s)
have entries in <filename class="directory">/dev</filename>,
as a simple <link linkend="dfref">df</link> shows.
<screen><prompt>bash$ </prompt><userinput>df</userinput>
<computeroutput>Filesystem 1k-blocks Used Available Use%
Mounted on
/dev/hda6 495876 222748 247527 48% /
/dev/hda1 50755 3887 44248 9% /boot
/dev/hda8 367013 13262 334803 4% /home
/dev/hda5 1714416 1123624 503704 70% /usr</computeroutput>
</screen>
</para>
<para><anchor id="loopbackref">Among other things, the <filename
class="directory">/dev</filename> directory also
contains <emphasis>loopback</emphasis> devices, such as
<filename>/dev/loop0</filename>. A loopback device is a gimmick
2002-06-17 13:17:07 +00:00
that allows an ordinary file to be accessed as if it were a
block device.
2001-10-15 14:21:41 +00:00
<footnote><para>A <emphasis>block device</emphasis> reads and/or
writes data in chunks, or blocks, in contrast to a
<emphasis>character device</emphasis>, which acesses data
in character units. Examples of block devices are a hard
drive and CD ROM drive. An example of a character device is
a keyboard.</para></footnote>
This enables mounting an entire filesystem within a
single large file. See <xref linkend="createfs"> and <xref
linkend="isomountref">.</para>
<para>A few of the pseudo-devices in <filename
class="directory">/dev</filename>
have other specialized uses, such as <link
linkend="zerosref"><filename>/dev/null</filename></link>, <link
linkend="zerosref1"><filename>/dev/zero</filename></link>
and <link
linkend="urandomref"><filename>/dev/urandom</filename></link>.</para>
</sect1> <!-- /dev -->
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<sect1 id="procref1">
<title><filename class="directory">/proc</filename></title>
<para>The <filename class="directory">/proc</filename> directory
2001-07-10 14:25:50 +00:00
is actually a pseudo-filesystem. The files in the <filename
class="directory">/proc</filename> directory mirror currently
running system and kernel <emphasis>processes</emphasis> and
contain information and statistics about them.</para>
<para>
<screen><prompt>bash$ </prompt><userinput>cat /proc/devices</userinput>
<computeroutput>Character devices:
1 mem
2 pty
3 ttyp
4 ttyS
5 cua
7 vcs
10 misc
14 sound
29 fb
36 netlink
128 ptm
136 pts
162 raw
254 pcmcia
Block devices:
1 ramdisk
2 fd
3 ide0
9 md</computeroutput>
2001-10-15 14:21:41 +00:00
<prompt>bash$ </prompt><userinput>cat /proc/interrupts</userinput>
<computeroutput> CPU0
0: 84505 XT-PIC timer
1: 3375 XT-PIC keyboard
2: 0 XT-PIC cascade
5: 1 XT-PIC soundblaster
8: 1 XT-PIC rtc
12: 4231 XT-PIC PS/2 Mouse
14: 109373 XT-PIC ide0
NMI: 0
ERR: 0</computeroutput>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<prompt>bash$ </prompt><userinput>cat /proc/partitions</userinput>
<computeroutput>major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
3 0 3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030
3 1 52416 hda1 27 395 844 960 4 2 14 180 0 800 1140
3 2 1 hda2 0 0 0 0 0 0 0 0 0 0 0
3 4 165280 hda4 10 0 20 210 0 0 0 0 0 210 210
...</computeroutput>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<prompt>bash$ </prompt><userinput>cat /proc/loadavg</userinput>
<computeroutput>0.13 0.42 0.27 2/44 1119</computeroutput>
</screen>
</para>
2001-07-10 14:25:50 +00:00
<para>Shell scripts may extract data from certain of the files in
2001-10-15 14:21:41 +00:00
<filename class="directory">/proc</filename>.
2001-07-10 14:25:50 +00:00
<footnote><para>Certain system commands, such as
<link linkend="procinforef">procinfo</link>,
2001-09-04 13:27:31 +00:00
<link linkend="freeref">free</link>,
<link linkend="vmstatref">vmstat</link>,
2001-10-15 14:21:41 +00:00
<link linkend="lsdevref">lsdev</link>,
2001-09-04 13:27:31 +00:00
and <link linkend="uptimeref">uptime</link>
do this as well.</para></footnote></para>
2001-07-10 14:25:50 +00:00
<para><programlisting>kernel_version=$( awk '{ print $3 }' /proc/version )</programlisting></para>
<para><programlisting>CPU=$( awk '/model name/ {print $4}' < /proc/cpuinfo )
if [ $CPU = Pentium ]
then
run_some_commands
...
else
run_different_commands
...
fi</programlisting></para>
<para>The <filename class="directory">/proc</filename> directory
contains subdirectories with unusual numerical
names. Every one of these names maps to the <link
linkend="ppidref">process ID</link> of a currently running
process. Within each of these subdirectories, there are
a number of files that hold useful information about the
corresponding process. The <filename>stat</filename> and
<filename>status</filename> files keep running statistics
on the process, the <filename>cmdline</filename> file holds
the command-line arguments the process was invoked with, and
the <filename>exe</filename> file is a symbolic link to the
complete path name of the invoking process. There are a few
more such files, but these seem to be the most interesting
from a scripting standpoint.</para>
<example id="pidid">
<title>Finding the process associated with a PID</title>
<programlisting>&pidid;</programlisting>
</example>
<example id="constat">
<title>On-line connect status</title>
<programlisting>&constat;</programlisting>
</example>
<warning><para>In general, it is dangerous to
<emphasis>write</emphasis> to the files in <filename
class="directory">/proc</filename>, as this can corrupt the
filesystem or crash the machine.</para></warning>
2001-10-15 14:21:41 +00:00
</sect1> <!-- /proc -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- /dev and /proc -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="zeros">
<title>Of Zeros and Nulls</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="zerosref"></para>
2001-09-04 13:27:31 +00:00
<variablelist id="zeronull">
<title><anchor id="zeronull1"><filename>/dev/zero</filename>
and <filename>/dev/null</filename></title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term>Uses of <filename>/dev/null</filename></term>
<listitem>
<para>Think of <filename>/dev/null</filename> as a <quote>black
hole</quote>. It is the nearest equivalent to a
write-only file. Everything written to it disappears
forever. Attempts to read or output from it result in
nothing. Nevertheless, <filename>/dev/null</filename>
can be quite useful from both the command line and in
scripts.</para>
2002-06-03 14:35:48 +00:00
<para>Suppressing <filename>stdout</filename>.
<programlisting>cat $filename >/dev/null
# Contents of the file will not list to stdout.</programlisting>
</para>
<para>Suppressing <filename>stderr</filename>
(from <xref linkend="ex57">).
2001-07-10 14:25:50 +00:00
<programlisting>rm $badname 2>/dev/null
# So error messages [stderr] deep-sixed.</programlisting>
2002-06-03 14:35:48 +00:00
</para>
<para>Suppressing output from <emphasis>both</emphasis>
<filename>stdout</filename> and <filename>stderr</filename>.
<programlisting>cat $filename 2>/dev/null >/dev/null
# If "$filename" does not exist, there will be no error message output.
# If "$filename" does exist, the contents of the file will not list to stdout.
# Therefore, no output at all will result from the above line of code.
#
# This can be useful in situations where the return code from a command
2002-06-17 13:17:07 +00:00
#+ needs to be tested, but no output is desired.
#
# cat $filename &>/dev/null
# also works, as Baris Cicek points out.</programlisting>
2002-06-03 14:35:48 +00:00
</para>
2001-07-10 14:25:50 +00:00
<para>Deleting contents of a file, but preserving the file itself, with
all attendant permissions (from <xref linkend="ex1"> and <xref linkend="ex2">):
<programlisting>cat /dev/null > /var/log/messages
# : > /var/log/messages has same effect, but does not spawn a new process.
cat /dev/null > /var/log/wtmp</programlisting>
</para>
2001-10-15 14:21:41 +00:00
<para>Automatically emptying the contents of a logfile
2001-07-10 14:25:50 +00:00
(especially good for dealing with those nasty
<quote>cookies</quote> sent by Web commercial sites):</para>
<example id="cookies">
<title>Hiding the cookie jar</title>
<programlisting>if [ -f ~/.netscape/cookies ] # Remove, if exists.
then
rm -f ~/.netscape/cookies
fi
ln -s /dev/null ~/.netscape/cookies
# All cookies now get sent to a black hole, rather than saved to disk.</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
2001-10-15 14:21:41 +00:00
<term><anchor id="zerosref1">Uses of <filename>/dev/zero</filename></term>
2001-07-10 14:25:50 +00:00
<listitem>
<para>Like <filename>/dev/null</filename>,
<filename>/dev/zero</filename> is a pseudo file,
2001-09-04 13:27:31 +00:00
but it actually contains nulls (numerical zeros,
not the ASCII kind). Output written to it disappears,
and it is fairly difficult to actually read the nulls in
<filename>/dev/zero</filename>, though it can be done with
<link linkend="odref">od</link> or a hex editor. The chief
2001-07-10 14:25:50 +00:00
use for <filename>/dev/zero</filename> is in creating an
initialized dummy file of specified length intended as a
temporary swap file.</para>
<example id="ex73">
<title>Setting up a swapfile using <filename>/dev/zero</filename></title>
<programlisting>&ex73;</programlisting>
</example>
<para>Another application of <filename>/dev/zero</filename>
2001-09-04 13:27:31 +00:00
is to <quote>zero out</quote> a file of a designated
size for a special purpose, such as mounting a filesystem
on a <link linkend="loopbackref">loopback device</link>
(see <xref linkend="createfs">) or securely deleting a file
(see <xref linkend="blotout">).</para>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<example id="ramdisk">
<title>Creating a ramdisk</title>
<programlisting>&ramdisk;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
</listitem>
</varlistentry>
</variablelist>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Zeros and Nulls -->
<chapter id="debugging">
<title>Debugging</title>
2001-07-10 14:25:50 +00:00
<para>The Bash shell contains no debugger, nor even any
debugging-specific commands or constructs. Syntax errors or
outright typos in the script generate cryptic error messages that
are often of no help in debugging a non-functional script.</para>
<example id="ex74">
2001-10-15 14:21:41 +00:00
<title>A buggy script</title>
2001-07-10 14:25:50 +00:00
<programlisting>&ex74;</programlisting>
</example>
<para>Output from script:
2001-10-15 14:21:41 +00:00
<screen><computeroutput>./ex74.sh: [37: command not found</computeroutput></screen>
2002-06-17 13:17:07 +00:00
What's wrong with the above script (hint: after the
<command>if</command>)?</para>
2001-07-10 14:25:50 +00:00
2002-06-17 13:17:07 +00:00
<example id="missingkeyword">
<title>Missing <link linkend="keywordref">keyword</link></title>
<programlisting>&missingkeyword;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
2002-06-17 13:17:07 +00:00
<para>Output from script:
<screen>
<computeroutput>missing-keyword.sh: line 10: syntax error: unexpected end of file</computeroutput>
</screen>
Note that the error message does <emphasis>not</emphasis> necessarily
reference the line in which the error occurs, but the line where the
Bash interpreter finally becomes aware of the error.
</para>
2001-07-10 14:25:50 +00:00
<para>What if the script executes, but does not work as expected? This is the
all too familiar logic error.</para>
<example id="ex75">
<title>test24, another buggy script</title>
<programlisting>&ex75;</programlisting>
</example>
<para>Try to find out what's wrong with <xref linkend="ex75">
by uncommenting the <userinput>echo "$badname"</userinput> line. Echo
statements are useful for seeing whether what you expect is
actually what you get.</para>
<para>In this particular case, <userinput>rm "$badname"</userinput>
will not give the desired results because
<varname>$badname</varname> should not be quoted. Placing it
in quotes ensures that <command>rm</command> has only one
argument (it will match only one filename). A partial fix
is to remove to quotes from <varname>$badname</varname> and
to reset <varname>$IFS</varname> to contain only a newline,
<userinput>IFS=$'\n'</userinput>. However, there are simpler
ways of going about it.
<programlisting># Correct methods of deleting filenames containing spaces.
rm *\ *
rm *" "*
rm *' '*
# Thank you. S.C.</programlisting>
</para>
<para>Summarizing the symptoms of a buggy script,
<orderedlist>
<listitem>
2002-06-17 13:17:07 +00:00
<para>It bombs with a <quote><errorname>syntax error</errorname></quote> message, or</para>
2001-07-10 14:25:50 +00:00
</listitem>
<listitem>
<para>It runs, but does not work as expected
2002-06-17 13:17:07 +00:00
(<errorname>logic error</errorname>).</para>
2001-07-10 14:25:50 +00:00
</listitem>
<listitem>
<para>It runs, works as expected, but has nasty side effects
(<errorname>logic bomb</errorname>).</para>
</listitem>
</orderedlist>
</para>
<para>Tools for debugging non-working scripts include
<orderedlist>
<listitem>
2001-10-15 14:21:41 +00:00
<para>echo statements at critical points in the script to
trace the variables, and otherwise give a snapshot of what
is going on.</para>
2001-07-10 14:25:50 +00:00
</listitem>
<listitem>
2001-10-15 14:21:41 +00:00
<para>using the <command>tee</command> filter to check
processes or data flows at critical points.</para>
2001-07-10 14:25:50 +00:00
</listitem>
<listitem>
<para>setting option flags <option>-n -v -x</option></para>
2001-09-04 13:27:31 +00:00
<para><userinput>sh -n scriptname</userinput> checks for
syntax errors without actually running the script. This is
the equivalent of inserting <userinput>set -n</userinput> or
<userinput>set -o noexec</userinput> into the script. Note
that certain types of syntax errors can slip past this
check.</para>
<para><userinput>sh -v scriptname</userinput> echoes each
command before executing it. This is the equivalent of
inserting <userinput>set -v</userinput> or <userinput>set
-o verbose</userinput> in the script.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>The <option>-n</option> and <option>-v</option>
flags work well together. <userinput>sh -nv
scriptname</userinput> gives a verbose syntax check.</para>
2001-07-10 14:25:50 +00:00
<para><userinput>sh -x scriptname</userinput> echoes the result each
command, but in an abbreviated manner. This is the equivalent of
inserting <userinput>set -x</userinput> or
<userinput>set -o xtrace</userinput> in the script.</para>
<para>Inserting <userinput>set -u</userinput> or
<userinput>set -o nounset</userinput> in the script runs it, but
gives an <errorname>unbound variable</errorname> error message
at each attempt to use an undeclared variable.</para>
</listitem>
2001-10-15 14:21:41 +00:00
<listitem>
<para>Using an <quote>assert</quote> function to test a
variable or condition at critical points in a script. (This is
an idea borrowed from C.)</para>
<example id="assert">
<title>Testing a condition with an <quote>assert</quote></title>
<programlisting>&assert;</programlisting>
</example>
</listitem>
2001-07-10 14:25:50 +00:00
<listitem>
2001-09-04 13:27:31 +00:00
<para>trapping at exit.</para>
2001-07-10 14:25:50 +00:00
<para>The <command>exit</command> command in a script triggers a
signal <returnvalue>0</returnvalue>, terminating the
process, that is, the script itself.
<footnote><para>By convention, <replaceable>signal
0</replaceable> is assigned to <link
linkend="exitcommandref">exit</link>. </para></footnote>
It is often useful to trap the
<command>exit</command>, forcing a <quote>printout</quote>
of variables, for example. The <command>trap</command>
must be the first command in the script.</para>
</listitem>
</orderedlist>
</para>
2001-09-04 13:27:31 +00:00
<variablelist id="trapref">
<title><anchor id="trapref1">Trapping signals</title>
2001-07-10 14:25:50 +00:00
<varlistentry>
<term><command>trap</command></term>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Specifies an action on receipt of a signal; also
useful for debugging.
2001-07-10 14:25:50 +00:00
<note><para><anchor id="signald">A
<emphasis>signal</emphasis> is simply a message
sent to a process, either by the kernel or another
process, telling it to take some specified action
(usually to terminate). For example, hitting a
<keycombo><keycap>Control</keycap><keycap>C</keycap></keycombo>,
sends a user interrupt, an INT signal, to a running
program.</para></note>
<programlisting>trap '' 2
# Ignore interrupt 2 (Control-C), with no action specified.
trap 'echo "Control-C disabled."' 2
# Message when Control-C pressed.</programlisting>
</para>
</listitem>
</varlistentry>
</variablelist>
<example id="ex76">
<title>Trapping at exit</title>
<programlisting>&ex76;</programlisting>
</example>
<example id="online">
<title>Cleaning up after Control-C</title>
<programlisting>&online;</programlisting>
</example>
<note>
<para>The <option>DEBUG</option> argument to
<command>trap</command> causes a specified action to execute
after every command in a script. This permits tracing variables,
for example.
<example id="vartrace">
<title>Tracing a variable</title>
<programlisting>&vartrace;</programlisting>
</example>
</para>
</note>
<note><para><userinput>trap '' SIGNAL</userinput> (two adjacent
apostrophes) disables SIGNAL for the remainder of the
script. <userinput>trap SIGNAL</userinput> restores
the functioning of SIGNAL once more. This is useful to
protect a critical portion of a script from an undesirable
interrupt.</para></note>
<para><programlisting>
trap '' 2 # Signal 2 is Control-C, now disabled.
command
command
command
trap 2 # Reenables Control-C
</programlisting></para>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Debugging -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="options">
<title>Options</title>
2001-07-10 14:25:50 +00:00
<para><anchor id="optionsref"></para>
<para>Options are settings that change shell and/or script
behavior.</para>
<para>The <link linkend="setref">set</link> command
enables options within a script. At the point in the script
where you want the options to take effect, use <command>set
-o option-name</command> or, in short form, <command>set
-option-abbrev</command>. These two forms are equivalent.</para>
<para><programlisting>
#!/bin/bash
set -o verbose
# Echoes all commands before executing.
</programlisting></para>
<para><programlisting>
#!/bin/bash
set -v
# Exact same effect as above.
</programlisting></para>
<note><para>To <emphasis>disable</emphasis> an option within a script,
use <command>set +o option-name</command> or <command>set
+option-abbrev</command>.</para></note>
<para><programlisting>
#!/bin/bash
set -o verbose
# Command echoing on.
command
...
command
set +o verbose
# Command echoing off.
command
# Not echoed.
set -v
# Command echoing on.
command
...
command
set +v
# Command echoing off.
command
exit 0
</programlisting></para>
<para>An alternate method of enabling options in a script is
to specify them immediately following the
<replaceable>#!</replaceable> script header.</para>
<para><programlisting>
#!/bin/bash -x
#
# Body of script follows.
</programlisting></para>
<para>It is also possible to enable script options from the command
line. Some options that will not work with
<command>set</command> are available this way. Among these
are <replaceable>-i</replaceable>, force script to run
interactive.</para>
<para><userinput>bash -v script-name</userinput></para>
<para><userinput>bash -o verbose script-name</userinput></para>
<para>The following is a listing of some useful options. They may be
specified in either abbreviated form or by complete name.</para>
<table>
<title>bash options</title>
<tgroup cols="3">
<thead>
<row>
<entry>Abbreviation</entry>
<entry>Name</entry>
<entry>Effect</entry>
</row>
</thead>
<tbody>
<row>
<entry><anchor id="noclobberref"><option>-C</option></entry>
<entry>noclobber</entry>
<entry>Prevent overwriting of files by redirection (may be
overridden by <token>>|</token>)</entry>
</row>
<row>
<entry><option>-D</option></entry>
<entry>(none)</entry>
<entry>List double-quoted strings prefixed by <token>$</token>,
but do not execute commands in script</entry>
</row>
<row>
<entry><option>-a</option></entry>
<entry>allexport</entry>
<entry>Export all defined variables</entry>
</row>
<row>
<entry><option>-b</option></entry>
<entry>notify</entry>
<entry>Notify when jobs running in background terminate (not of
much use in a script)</entry>
</row>
<row>
<entry><option>-c ...</option></entry>
<entry>(none)</entry>
<entry>Read commands from <command>...</command></entry>
</row>
<row>
<entry><option>-f</option></entry>
<entry>noglob</entry>
<entry>Filename expansion (globbing) disabled</entry>
</row>
<row>
<entry><option>-i</option></entry>
<entry>interactive</entry>
<entry>Script runs in <emphasis>interactive</emphasis> mode</entry>
</row>
<row>
<entry><option>-p</option></entry>
<entry>privileged</entry>
<entry>Script runs as <quote>suid</quote> (caution!)</entry>
</row>
<row>
<entry><option>-r</option></entry>
<entry>restricted</entry>
<entry>Script runs in <emphasis>restricted</emphasis>
mode (see <xref linkend="restricted-sh">).</entry>
</row>
<row>
<entry><option>-u</option></entry>
<entry>nounset</entry>
<entry>Attempt to use undefined variable
outputs error message, and forces an exit</entry>
</row>
<row>
<entry><option>-v</option></entry>
<entry>verbose</entry>
<entry>Print each command to <filename>stdout</filename> before executing it</entry>
</row>
<row>
<entry><option>-x</option></entry>
<entry>xtrace</entry>
<entry>Similar to <option>-v</option>, but expands commands</entry>
</row>
<row>
<entry><option>-e</option></entry>
<entry>errexit</entry>
<entry>Abort script at first error (when a command exits with
non-zero status)</entry>
</row>
<row>
<entry><option>-n</option></entry>
<entry>noexec</entry>
2001-09-04 13:27:31 +00:00
<entry>Read commands in script, but do not execute them (syntax check)</entry>
2001-07-10 14:25:50 +00:00
</row>
<row>
<entry><option>-s</option></entry>
<entry>stdin</entry>
<entry>Read commands from <filename>stdin</filename></entry>
</row>
<row>
<entry><option>-t</option></entry>
<entry>(none)</entry>
<entry>Exit after first command</entry>
</row>
<row>
<entry><option>-</option></entry>
<entry>(none)</entry>
<entry>End of options flag. All other arguments
are <link linkend="posparamref">positional
parameters</link>.</entry>
</row>
<row>
<entry><option>--</option></entry>
<entry>(none)</entry>
<entry>Unset positional parameters.
If arguments given (<varname>-- arg1 arg2</varname>),
positional parameters set to arguments.</entry>
</row>
</tbody>
</tgroup>
</table>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Options -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="gotchas">
<title>Gotchas</title>
2001-07-10 14:25:50 +00:00
<epigraph>
<attribution>Puccini</attribution>
<para>Turandot: Gli enigmi sono tre, la morte una!</para>
<para>Caleph: No, no! Gli enigmi sono tre, una la vita!</para>
</epigraph>
<para>Assigning reserved words or characters to variable names.
2001-09-04 13:27:31 +00:00
<programlisting>case=value0 # Causes problems.
23skidoo=value1 # Also problems.
# Variable names starting with a digit are reserved by the shell.
2001-07-10 14:25:50 +00:00
# Try _23skidoo=value1. Starting variables with an underscore is o.k.
2001-09-04 13:27:31 +00:00
# However... using just the underscore will not work.
_=25
echo $_ # $_ is a special variable set to last arg of last command.
xyz((!*=value2 # Causes severe problems.</programlisting>
2001-07-10 14:25:50 +00:00
</para>
<para>Using a hyphen or other reserved characters in a variable name.
<programlisting>var-1=23
# Use 'var_1' instead.</programlisting>
2001-09-04 13:27:31 +00:00
</para>
<para>Using the same name for a variable and a function. This can make a
script difficult to understand.
<programlisting>do_something ()
{
echo "This function does something with \"$1\"."
}
do_something=do_something
do_something do_something
# All this is legal, but highly confusing.</programlisting>
2001-07-10 14:25:50 +00:00
</para>
2001-09-04 13:27:31 +00:00
2001-07-10 14:25:50 +00:00
<para><anchor id="wsbad">Using <link
linkend="whitespaceref">whitespace</link> inappropriately
(in contrast to other programming languages, Bash can be quite
finicky about whitespace).
<programlisting>var1 = 23 # 'var1=23' is correct.
# On line above, Bash attempts to execute command "var1"
# with the arguments "=" and "23".
let c = $a - $b # 'let c=$a-$b' or 'let "c = $a - $b"' are correct.
if [ $a -le 5] # if [ $a -le 5 ] is correct.
# if [ "$a" -le 5 ] is even better.
# [[ $a -le 5 ]] also works.</programlisting>
</para>
<para>Assuming uninitialized variables (variables before a value is
assigned to them) are <quote>zeroed out</quote>. An
uninitialized variable has a value of <quote>null</quote>,
<emphasis>not</emphasis> zero.</para>
<para>Mixing up <emphasis>=</emphasis> and <emphasis>-eq</emphasis> in
a test. Remember, <emphasis>=</emphasis> is for comparing literal
variables and <emphasis>-eq</emphasis> for integers.
<programlisting>if [ "$a" = 273 ] # Is $a an integer or string?
if [ "$a" -eq 273 ] # If $a is an integer.
# Sometimes you can mix up -eq and = without adverse consequences.
# However...
a=273.0 # Not an integer.
if [ "$a" = 273 ]
then
echo "Comparison works."
else
echo "Comparison does not work."
fi # Comparison does not work.
# Same with a=" 273" and a="0273".
# Likewise, problems trying to use "-eq" with non-integer values.
if [ "$a" -eq 273.0 ]
then
echo "a = $a'
fi # Aborts with an error message.
# test.sh: [: 273.0: integer expression expected</programlisting>
</para>
2002-04-01 16:04:17 +00:00
<para>Mixing up <link linkend="icomparison1">integer</link> and
<link linkend="scomparison1">string comparison</link> operators.
<programlisting>#!/bin/bash
# bad-op.sh
number=1
while [ "$number" < 5 ] # Wrong! Should be while [ "number" -lt 5 ]
do
echo -n "$number "
let "number += 1"
done
# Attempt to run this bombs with the error message:
# bad-op.sh: 5: No such file or directory</programlisting>
</para>
2001-07-10 14:25:50 +00:00
<para>Sometimes variables within <quote>test</quote> brackets
([ ]) need to be quoted (double quotes). Failure to do so may
cause unexpected behavior. See <xref linkend="strtest">, <xref
linkend="redir2">, and <xref linkend="arglist">.</para>
<para>Commands issued from a script may fail to execute because
the script owner lacks execute permission for them. If a user
cannot invoke a command from the command line, then putting it
into a script will likewise fail. Try changing the attributes of
the command in question, perhaps even setting the suid bit
(as root, of course).</para>
<para>Attempting to use <command>-</command> as a redirection
operator (which it is not) will usually result in an unpleasant
surprise.
<programlisting>command1 2&gt; - | command2 # Trying to redirect error output of command1 into a pipe...
# ...will not work.
command1 2&gt;&amp; - | command2 # Also futile.
Thanks, S.C.</programlisting></para>
2001-10-15 14:21:41 +00:00
<para>Using Bash <link linkend="bash2ref">version 2+</link>
functionality may cause a bailout with error messages. Older
Linux machines may have version 1.XX of Bash as the default
installation.
<programlisting>#!/bin/bash
minimum_version=2
# Since Chet Ramey is constantly adding features to Bash,
# you may set $minimum_version to 2.XX, or whatever is appropriate.
E_BAD_VERSION=80
if [ "$BASH_VERSION" \< "$minimum_version" ]
then
echo "This script works only with Bash, version $minimum or greater."
echo "Upgrade strongly recommended."
exit $E_BAD_VERSION
fi
...</programlisting></para>
2001-07-10 14:25:50 +00:00
<para>Using Bash-specific functionality in a Bourne shell script
(<userinput>#!/bin/sh</userinput>) on a non-Linux machine
may cause unexpected behavior. A Linux system usually aliases
<command>sh</command> to <command>bash</command>, but this does
not necessarily hold true for a generic UNIX machine.</para>
<para>A script with DOS-type newlines (<replaceable>\r\n</replaceable>)
will fail to execute, since <userinput>#!/bin/bash\r\n</userinput>
is not recognized, <emphasis>not</emphasis> the same as the
expected <userinput>#!/bin/bash\n</userinput>. The fix is to
convert the script to UNIX-style newlines.</para>
<para>A shell script headed by <userinput>#!/bin/sh</userinput>
may not run in full Bash-compatibility mode. Some Bash-specific
functions might be disabled. Scripts that need complete
access to all the Bash-specific extensions should start with
<userinput>#!/bin/bash</userinput>.</para>
<para>A script may not <command>export</command> variables back
to its <link linkend="forkref">parent process</link>, the shell,
or to the environment. Just as we learned in biology, a child
process can inherit from a parent, but not vice versa.
<programlisting>WHATEVER=/home/bozo
export WHATEVER
exit 0</programlisting>
<screen><prompt>bash$ </prompt><command>echo $WHATEVER</command>
<computeroutput>
</computeroutput>
<prompt>bash$ </prompt></screen>
Sure enough, back at the command prompt, $WHATEVER remains unset.
</para>
<para>Setting and manipulating variables in a subshell, then attempting
to use those same variables outside the scope of the subshell will
result an unpleasant surprise.</para>
<example id="subpit">
<title>Subshell Pitfalls</title>
<programlisting>&subpit;</programlisting>
</example>
2002-06-03 14:35:48 +00:00
<para><anchor id="badread0"></para>
2002-06-17 13:17:07 +00:00
<para><link linkend="piperef">Piping</link>
<command>echo</command>output to a <link
2002-06-03 14:35:48 +00:00
linkend="readref">read</link> may produce unexpected
results. In this scenario, the <command>read</command>
acts as if it were running in a subshell. Instead, use
the <link linkend="setref">set</link> command (as in <xref
linkend="setpos">).</para>
<example id="badread">
2002-06-17 13:17:07 +00:00
<title>Piping the output of <command>echo</command> to a <command>read</command></title>
2002-06-03 14:35:48 +00:00
<programlisting>&badread;</programlisting>
</example>
<para>Using <quote>suid</quote> commands within scripts is risky,
2001-07-10 14:25:50 +00:00
as it may compromise system security.
<footnote><para>Setting the <emphasis>suid</emphasis> permission on
2002-06-03 14:35:48 +00:00
the script itself has no effect.</para></footnote>
2001-07-10 14:25:50 +00:00
</para>
<para>Using shell scripts for CGI programming may be problematic. Shell
script variables are not <quote>typesafe</quote>, and this can cause
undesirable behavior as far as CGI is concerned. Moreover, it is
2001-10-15 14:21:41 +00:00
difficult to <quote>cracker-proof</quote> shell scripts.</para>
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
<para>Bash scripts written for Linux or BSD systems may need
fixups to run on a commercial UNIX machine. Such scripts
often employ GNU commands and filters which have greater
functionality than their generic UNIX counterparts. This is
particularly true of such text processing utilites as <link
linkend="trref">tr</link>.</para>
2001-07-10 14:25:50 +00:00
<epigraph>
<attribution>A.J. Lamb and H.W. Petrie</attribution>
<para>Danger is near thee --</para>
<para>Beware, beware, beware, beware.</para>
<para>Many brave hearts are asleep in the deep.</para>
<para>So beware --</para>
<para>Beware.</para>
</epigraph>
2001-09-04 13:27:31 +00:00
</chapter> <!-- Gotchas -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="scrstyle">
<title>Scripting With Style</title>
2001-07-10 14:25:50 +00:00
<para>Get into the habit of writing shell scripts in a structured and
systematic manner. Even <quote>on-the-fly</quote> and
<quote>written on the back of an envelope</quote> scripts will
benefit if you take a few minutes to plan and organize your
thoughts before sitting down and coding.</para>
<para>Herewith are a few stylistic guidelines. This is not
intended as an <emphasis>Official Shell Scripting
Stylesheet</emphasis>.</para>
2001-09-04 13:27:31 +00:00
<sect1 id="unofficialst">
<title>Unofficial Shell Scripting Stylesheet</title>
2001-07-10 14:25:50 +00:00
<itemizedlist>
<listitem>
<para>Comment your code. This makes it easier for others to
understand (and appreciate), and easier for you to maintain.
<programlisting>PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}"
# It made perfect sense when you wrote it last year, but now it's a complete mystery.
# (From Antek Sawicki's "pw.sh" script.)</programlisting>
</para>
<para>Add descriptive headers to your scripts and functions.
<programlisting>#!/bin/bash
#************************************************#
# xyz.sh
# written by Bozo Bozeman
# July 05, 2001
# Clean up project files.
#************************************************#
BADDIR=65 # No such directory.
projectdir=/home/bozo/projects # Directory to clean up.
#-------------------------------------------------------#
# cleanup_pfiles ()
# Removes all files in designated directory.
# Parameter: $target_directory
# Returns: 0 on success, $BADDIR if something went wrong.
#-------------------------------------------------------#
cleanup_pfiles ()
{
if [ ! -d "$1" ] # Test if target directory exists.
then
echo "$1 is not a directory."
return $BADDIR
fi
rm -f "$1"/*
return 0 # Success.
}
cleanup_pfiles $projectdir
exit 0</programlisting>
Be sure to put the <emphasis>#!/bin/bash</emphasis> at the
beginning of the first line of the script, preceding any
comment headers.</para>
</listitem>
<listitem>
<para>Avoid using <quote>magic numbers</quote>,
<footnote><para>In this context, <quote> magic
numbers</quote> have an entirely different meaning than
the <link linkend="magnumref">magic numbers</link> used
to designate file types.</para></footnote>
that is, <quote>hard-wired</quote> literal constants. Use
meaningful variable names instead. This makes the script
easier to understand and permits making changes and updates
without breaking the application.
<programlisting>if [ -f /var/log/messages ]
then
...
fi
# A year later, you decide to change the script to check /var/log/syslog.
# It is now necessary to manually change the script, instance by instance,
# and hope nothing breaks.
# A better way:
LOGFILE=/var/log/messages # Only line that needs to be changed.
2001-10-15 14:21:41 +00:00
if [ -f "$LOGFILE" ]
2001-07-10 14:25:50 +00:00
then
...
fi</programlisting>
</para>
</listitem>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Choose descriptive names for variables and functions.
2001-10-15 14:21:41 +00:00
<programlisting>fl=`ls -al $dirname` # Cryptic.
2001-09-04 13:27:31 +00:00
file_listing=`ls -al $dirname` # Better.
2001-07-10 14:25:50 +00:00
MAXVAL=10 # All caps used for a script constant.
while [ "$index" -le "$MAXVAL" ]
...
2001-09-04 13:27:31 +00:00
E_NOTFOUND=75 # Uppercase for an errorcode,
# and name begins with "E_".
2001-07-10 14:25:50 +00:00
if [ ! -e "$filename" ]
then
echo "File $filename not found."
exit $E_NOTFOUND
fi
MAIL_DIRECTORY=/var/spool/mail/bozo # Uppercase for an environmental variable.
export MAIL_DIRECTORY
2001-09-04 13:27:31 +00:00
GetAnswer () # Mixed case works well for a function.
{
prompt=$1
echo -n $prompt
read answer
return $answer
}
GetAnswer "What is your favorite number? "
favorite_number=$?
echo $favorite_number
_uservariable=23 # Permissable, but not recommended.
2001-07-10 14:25:50 +00:00
# It's better for user-defined variables not to start with an underscore.
# Leave that for system variables.</programlisting>
</para>
</listitem>
<listitem>
<para>Use <link linkend="exitcommandref">exit codes</link>
in a systematic and meaningful way.
<programlisting>E_WRONG_ARGS=65
...
...
exit $E_WRONG_ARGS</programlisting>
See also <xref linkend="exitcodes">.</para>
</listitem>
<listitem>
<para>Break complex scripts into simpler modules. Use functions
where appropriate. See <xref linkend="ex79">.</para>
</listitem>
<listitem>
<para>Don't use a complex construct where a simpler one will do.
<programlisting>COMMAND
if [ $? -eq 0 ]
...
# Redundant and non-intuitive.
if COMMAND
...
# More concise (if perhaps not quite as legible).</programlisting>
</para>
</listitem>
</itemizedlist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Unofficial Shell Scripting Stylesheet -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</chapter> <!-- Scripting With Style -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<chapter id="miscellany">
<title>Miscellany</title>
2001-07-10 14:25:50 +00:00
<epigraph>
<attribution>Tom Duff</attribution>
<para>Nobody really knows what the Bourne shell's grammar is. Even
examination of the source code is little help.
</para>
</epigraph>
2001-09-04 13:27:31 +00:00
<sect1 id="intandnonint">
2001-07-10 14:25:50 +00:00
<title>Interactive and non-interactive shells and scripts</title>
<para>An <emphasis>interactive</emphasis> shell reads commands from
user input on a <filename>tty</filename>. Among other things,
such a shell reads startup files on activation, displays
a prompt, and enables job control by default. The user can
<emphasis>interact</emphasis> with the shell.</para>
<para>A shell running a script is always a non-interactive
shell. All the same, the script can still access its
<filename>tty</filename>. It is even possible to emulate an
interactive shell in a script.
<programlisting>#!/bin/bash
MY_PROMPT='$ '
while :
do
echo -n "$MY_PROMPT"
read line
eval "$line"
done
exit 0
# This example script, and much of the above explanation supplied by
# Stephane Chazelas (thanks again).</programlisting></para>
<para>Let us consider an <emphasis>interactive</emphasis> script
to be one that requires input from the user, usually with
<link linkend="readref">read</link> statements (see <xref
linkend="ex36">). <quote>Real life</quote> is actually a
bit messier than that. For now, assume an interactive script
is bound to a tty, a script that a user has invoked from the
console or an xterm.</para>
<para>Init and startup scripts are necessarily non-interactive,
since they must run without human intervention. Many
administrative and system maintenance scripts are likewise
non-interactive. Unvarying repetitive tasks cry out for
automation by non-interactive scripts.</para>
<para>Non-interactive scripts can run in the background, but
interactive ones hang, waiting for input that never comes.
Handle that difficulty by having an <command>expect</command>
script or embedded <link linkend="heredocref">here
document</link> feed input to an interactive script running
as a background job. In the simplest case, redirect a
file to supply input to a <command>read</command> statement
(<command>read variable &lt;file</command>). These particular
workarounds make possible general purpose scripts that run
in either interactive or non-interactive modes.</para>
<para>If a script needs to test whether it is running in an
interactive shell, it is simply a matter of finding
whether the <emphasis>prompt</emphasis> variable, <link
linkend="ps1ref">$PS1</link> is set. (If the user is being
prompted for input, then the script needs to display a prompt.)
<programlisting>if [ -z $PS1 ] # no prompt?
then
# non-interactive
...
else
# interactive
...
fi</programlisting>
<anchor id="iitest">Alternatively, the script can test
for the presence of option <quote>i</quote> in the <link
linkend="flpref">$-</link> flag.
<programlisting>case $- in
*i*) # interactive shell
;;
*) # non-interactive shell
;;
2002-06-03 14:35:48 +00:00
# (Courtesy of "UNIX F.A.Q.," 1993)</programlisting></para>
2001-07-10 14:25:50 +00:00
<note><para>Scripts may be forced to run in interactive
mode with the <token>-i</token> option or with a
2002-06-03 14:35:48 +00:00
<userinput>#!/bin/bash -i</userinput> header. Be aware that
this can cause erratic script behavior or show error messages
even when no error is present.</para></note>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1> <!-- Interactive and non-interactive scripts -->
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<sect1 id="wrapper">
<title>Shell Wrappers</title>
2002-01-07 15:24:19 +00:00
<para><anchor id="shwrapper"></para>
2001-10-15 14:21:41 +00:00
<para>A <quote>wrapper</quote> is a shell script that embeds
a system command or utility, that saves a set of parameters
2002-06-17 13:17:07 +00:00
passed to that command. Wrapping a script around a complex
2001-10-15 14:21:41 +00:00
command line simplifies invoking it. This is expecially
useful with <link linkend="sedref">sed</link> and <link
linkend="awkref">awk</link>.</para>
<para>A
<command>
<indexterm>
<primary>sed</primary>
</indexterm>
<indexterm>
<primary>script</primary>
<secondary>sed</secondary>
</indexterm>
sed</command> or
<command>
<indexterm>
<primary>awk</primary>
</indexterm>
<indexterm>
<primary>script</primary>
<secondary>awk</secondary>
</indexterm>
awk</command> script would normally be invoked
from the command line by a <userinput>sed -e
<replaceable>'commands'</replaceable></userinput>
or <userinput>awk
<replaceable>'commands'</replaceable></userinput>. Embedding
such a script in a Bash script permits calling it more simply,
and makes it <quote>reusable</quote>. This also enables
combining the functionality of <command>sed</command>
and <command>awk</command>, for example <link
linkend="piperef">piping</link> the output of a set of
<command>sed</command> commands to <command>awk</command>.
As a saved executable file, you can then repeatedly invoke it
in its original form or modified, without the inconvenience
of retyping it on the command line.</para>
<example id="ex3">
<title><command>shell wrapper</command></title>
<programlisting>&ex3;</programlisting>
</example>
<example id="ex4">
<title> A slightly more complex <command>shell wrapper</command></title>
<programlisting>&ex4;</programlisting>
</example>
<example id="coltotaler">
<title> A <command>shell wrapper</command> around an awk script</title>
<programlisting>&coltotaler;</programlisting>
</example>
<para><anchor id="perlref">For those scripts needing a single
do-it-all tool, a Swiss army knife, there is Perl. Perl
combines the capabilities of <command>sed</command> and
<command>awk</command>, and throws in a large subset of
<command>C</command>, to boot. It is modular and contains support
for everything ranging from object-oriented programming up to and
including the kitchen sink. Short Perl scripts lend themselves to
embedding in shell scripts, and there may even be some substance
to the claim that Perl can totally replace shell scripting
(though the author of this document remains skeptical).</para>
<example id="ex56">
<title>Perl embedded in a <command>Bash</command> script</title>
<programlisting>&ex56;</programlisting>
</example>
<para>It is even possible to combine a Bash script and Perl script
within the same file. Depending on how the script is invoked, either
the Bash part or the Perl part will execute.</para>
<example id="bashandperl">
<title>Bash and Perl scripts combined</title>
<programlisting>&bashandperl;</programlisting>
</example>
<para>
<screen><prompt>bash$ </prompt><userinput>bash bashandperl.sh</userinput>
<computeroutput>Greetings from the Bash part of the script.</computeroutput>
<prompt>bash$ </prompt><userinput>perl -x bashandperl.sh</userinput>
<computeroutput>Greetings from the Perl part of the script.</computeroutput>
</screen>
</para>
</sect1> <!-- Shell wrappers -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="testsandcomparisons">
2001-10-15 14:21:41 +00:00
<title>Tests and Comparisons: Alternatives</title>
2001-07-10 14:25:50 +00:00
<para>For tests, the <link linkend="dblbrackets">[[ ]]</link>
construct may be more appropriate than <userinput>[
]</userinput>. Likewise, arithmetic comparisons might benefit
from the <link linkend="dblparens">(( ))</link> construct.
<programlisting>a=8
# All of the comparisons below are equivalent.
test "$a" -lt 16 && echo "yes, $a < 16" # "and list"
/bin/test "$a" -lt 16 && echo "yes, $a < 16"
[ "$a" -lt 16 ] && echo "yes, $a < 16"
[[ $a -lt 16 ]] && echo "yes, $a < 16" # Quoting variables within
(( a < 16 )) && echo "yes, $a < 16" # [[ ]] and (( )) not necessary.
city="New York"
# Again, all of the comparisons below are equivalent.
test "$city" \< Paris && echo "Yes, Paris is greater than $city" # Greater ASCII order.
/bin/test "$city" \< Paris && echo "Yes, Paris is greater than $city"
[ "$city" \< Paris ] && echo "Yes, Paris is greater than $city"
[[ $city < Paris ]] && echo "Yes, Paris is greater than $city" # Need not quote $city.
# Thank you, S.C.</programlisting></para>
2001-10-15 14:21:41 +00:00
</sect1> <!-- Tests and Comparisons: Alternatives -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="optimizations">
2001-07-10 14:25:50 +00:00
<title>Optimizations</title>
<para>Most shell scripts are quick 'n dirty solutions to non-complex
problems. As such, optimizing them for speed is not much of an
issue. Consider the case, though, where a script carries out
an important task, does it well, but runs too slowly. Rewriting
it in a compiled language may not be a palatable option. The
simplest fix would be to rewrite the parts of the script
that slow it down. Is it possible to apply principles of code
optimization even to a lowly shell script?</para>
<para>Check the loops in the script. Time consumed by repetitive
2002-06-03 14:35:48 +00:00
operations adds up quickly. If at all possible, remove
time-consuming operations from within loops.</para>
2002-06-17 13:17:07 +00:00
<para>Use <link linkend="builtinref">builtin</link> commands in
preference to system commands. Builtins execute faster and
usually do not launch a subshell when invoked.</para>
2002-06-03 14:35:48 +00:00
<para>Use the <link linkend="timref">time</link> and <link
2001-07-10 14:25:50 +00:00
linkend="timesref">times</link> tools to profile
computation-intensive commands. Consider rewriting time-critical
code sections in C, or even in assembler.</para>
2002-06-03 14:35:48 +00:00
<para>Try to minimize file I/O. Bash is not particularly
efficient at handling files, so consider using
more appropriate tools for this within the script,
such as <link linkend="awkref">awk</link> or <link
linkend="perlref">Perl</link>.</para>
2001-07-10 14:25:50 +00:00
2002-06-03 14:35:48 +00:00
<para>Write your scripts in a structured, coherent form, so
they can be reorganized and tightened up as necessary. Some of
the optimization techniques applicable to high-level languages
may work for scripts, but others, such as loop unrolling,
are mostly irrelevant. Above all, use common sense.</para>
<para>For an excellent demonstration of how optimization can
drastically reduce the execution time of a script, see <xref
linkend="monthlypmt">.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1> <!-- Optimizations -->
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<sect1 id="assortedtips">
2001-07-10 14:25:50 +00:00
<title>Assorted Tips</title>
<itemizedlist>
<listitem>
<para>To keep a record of which user scripts have run
during a particular sesssion or over a number of sessions,
add the following lines to each script you want to keep track
of. This will keep a continuing file record of the script
names and invocation times. </para>
<para>
<programlisting># Append (>>) following to end of each script tracked.
date>> $SAVE_FILE #Date and time.
echo $0>> $SAVE_FILE #Script name.
echo>> $SAVE_FILE #Blank line as separator.
# Of course, SAVE_FILE defined and exported as environmental variable in ~/.bashrc
# (something like ~/.scripts-run)</programlisting>
</para>
</listitem>
2001-10-15 14:21:41 +00:00
<listitem>
<para><anchor id="prependref"></para>
<para>The <token>&gt;&gt;</token> operator appends lines to a file.
What if you wish to <emphasis>prepend</emphasis> a line to an
existing file, that is, to paste it in at the beginning?</para>
<para>
<programlisting>file=data.txt
title="***This is the title line of data text file***"
echo $title | cat - $file >$file.new
# "cat -" concatenates stdout to $file.
# End result is
#+ to write a new file with $title appended at *beginning*.</programlisting>
</para>
<para>Of course, <link linkend="sedref">sed</link> can also do
this.</para>
</listitem>
2001-07-10 14:25:50 +00:00
<listitem>
<para>A shell script may act as an embedded command inside
another shell script, a <emphasis>Tcl</emphasis> or
2001-10-15 14:21:41 +00:00
<emphasis>wish</emphasis> script, or even a <link
linkend="makefileref">Makefile</link>. It can be invoked
2002-06-17 13:17:07 +00:00
as an external shell command in a C program using the
2001-10-15 14:21:41 +00:00
<replaceable>system()</replaceable> call, i.e.,
2001-07-10 14:25:50 +00:00
<replaceable>system("script_name");</replaceable>.</para>
</listitem>
<listitem>
2001-09-04 13:27:31 +00:00
<para>Put together files containing your favorite and most useful
definitions and functions. As necessary,
<quote>include</quote> one or more of these
<quote>library files</quote> in scripts with either the
<link linkend="dotref">dot</link> (<command>.</command>)
or <link linkend="sourceref">source</link> command.</para>
<para>
<programlisting># SCRIPT LIBRARY
# ------ -------
# Note:
# No "#!" here.
# No "live code" either.
# Useful variable definitions
ROOT_UID=0 # Root has $UID 0.
E_NOTROOT=101 # Not root user error.
MAXRETVAL=256 # Maximum (positive) return value of a function.
SUCCESS=0
FAILURE=-1
# Functions
Usage () # "Usage:" message.
{
if [ -z "$1" ] # No arg passed.
then
msg=filename
else
msg=$@
fi
echo "Usage: `basename $0` "$msg""
}
Check_if_root () # Check if root running script.
{ # From "ex39.sh" example.
if [ "$UID" -ne "$ROOT_UID" ]
then
echo "Must be root to run this script."
exit $E_NOTROOT
fi
}
CreateTempfileName () # Creates a "unique" temp filename.
{ # From "ex51.sh" example.
prefix=temp
suffix=`eval date +%s`
Tempfilename=$prefix.$suffix
}
isalpha2 () # Tests whether *entire string* is alphabetic.
{ # From "isalpha.sh" example.
[ $# -eq 1 ] || return $FAILURE
case $1 in
*[!a-zA-Z]*|"") return $FAILURE;;
*) return $SUCCESS;;
esac # Thanks, S.C.
}
abs () # Absolute value.
{ # Caution: Max return value = 256.
E_ARGERR=-999999
if [ -z "$1" ] # Need arg passed.
then
return $E_ARGERR # Obvious error value returned.
fi
if [ "$1" -ge 0 ] # If non-negative,
then #
absval=$1 # stays as-is.
else # Otherwise,
let "absval = (( 0 - $1 ))" # change sign.
fi
return $absval
2002-04-01 16:04:17 +00:00
}
tolower () # Converts string(s) passed as argument(s)
{ #+ to lowercase.
if [ -z "$1" ] # If no argument(s) passed,
then #+ send error message
echo "(null)" #+ (C-style void-pointer error message)
return #+ and return from function.
fi
echo "$@" | tr A-Z a-z
# Translate all passed arguments ($@).
return
# Use command substitution to set a variable to function output.
# For example:
# oldvar="A seT of miXed-caSe LEtTerS"
# newvar=`tolower "$oldvar"`
# echo "$newvar" # a set of mixed-case letters
#
# Exercise: Rewrite this function to change lowercase passed argument(s)
# to uppercase ... toupper() [easy].
2001-09-04 13:27:31 +00:00
}</programlisting>
</para>
</listitem>
<listitem>
<para>Use special-purpose comment headers to increase clarity
and legibility in scripts.</para>
<para><programlisting>## Caution.
rm -rf *.zzy ## The "-rf" options to "rm" are very dangerous,
##+ especially with wildcards.
#+ Line continuation.
# This is line 1
#+ of a multi-line comment,
#+ and this is the final line.
#* Note.
#o List item.
#> Another point of view.
while [ "$var1" != "end" ] #> while test "$var1" != "end"</programlisting></para>
</listitem>
<listitem>
<para>Using the <link linkend="xstatvarref">$? exit status
variable</link>, a script may test if a parameter contains
only digits, so it can be treated as an integer.</para>
<para>
<programlisting>#!/bin/bash
SUCCESS=0
E_BADINPUT=65
test "$1" -ne 0 -o "$1" -eq 0 2>/dev/null
# An integer is either equal to 0 or not equal to 0.
# 2>/dev/null suppresses error message.
if [ $? -ne "$SUCCESS" ]
then
echo "Usage: `basename $0` integer-input"
exit $E_BADINPUT
fi
let "sum = $1 + 25" # Would give error if $1 not integer.
echo "Sum = $sum"
# Any variable, not just a command line parameter, can be tested this way.
exit 0</programlisting>
</para>
2001-07-10 14:25:50 +00:00
</listitem>
2002-04-01 16:04:17 +00:00
<listitem>
<para><anchor id="rvt">The 0 - 255 range for function return
values is a severe limitation. Global variables and other
workarounds are often problematic. An alternative method for
a function to communicate a value back to the main body of
the script is to have the function write to
<filename>stdout</filename> the <quote>return value</quote>,
and assign this to a variable.</para>
<example id="multiplication">
<title>Return value trickery</title>
<programlisting>&multiplication;</programlisting>
</example>
<para>The same technique also works for alphanumeric
strings. This means that a function can <quote>return</quote>
a non-numeric value.</para>
<para>
<programlisting>capitalize_ichar () # Capitalizes initial character
{ #+ of argument string(s) passed.
string0="$@" # Accepts multiple arguments.
firstchar=${string0:0:1} # First character.
string1=${string0:1} # Rest of string(s).
FirstChar=`echo "$firstchar" | tr a-z A-Z`
# Capitalize first character.
echo "$FirstChar$string1" # Output to stdout.
}
newstring=`capitalize_ichar "each sentence should start with a capital letter."`
echo "$newstring" # Each sentence should start with a capital letter.</programlisting>
</para>
<para>It is even possible for a function to <quote>return</quote>
multiple values with this method.</para>
<example id="sumproduct">
<title>Even more return value trickery</title>
<programlisting>&sumproduct;</programlisting>
</example>
</listitem>
<listitem>
<para>Next in our bag of trick are techniques for passing
an <link linkend="arrayref">array</link> to a
<link linkend="functionref">function</link>, then
<quote>returning</quote> an array back to the main body of
the script.</para>
<para>Passing an array involves loading the space-separated
elements of the array into a variable with <link
linkend="commandsubref">command substitution</link>. Getting
an array back as the <quote>return value</quote> from
a function uses the previously mentioned strategem of
<emphasis>echoing</emphasis> the array in the function,
then invoking command substitution and the <command>(
... )</command> operator to assign it to an array.</para>
<example id="arrfunc">
<title>Passing and returning arrays</title>
<programlisting>&arrfunc;</programlisting>
</example>
<para>For a more elaborate example of passing arrays to
functions, see <xref linkend="lifeslow">.</para>
</listitem>
2001-07-10 14:25:50 +00:00
<listitem>
<para>Using the double parentheses construct, it is possible
to use C-like syntax for setting and incrementing variables
2001-10-15 14:21:41 +00:00
and in <link linkend="forloopref1">for</link> and <link
2001-07-10 14:25:50 +00:00
linkend="whileloopref">while</link> loops. See <xref
linkend="forloopc"> and <xref linkend="whloopc">.</para>
</listitem>
2002-04-01 16:04:17 +00:00
<listitem>
<para>A useful scripting technique is to
<emphasis>repeatedly</emphasis> feed the output of a filter
(by piping) back to the <emphasis>same filter</emphasis>, but
with a different set of arguments and/or options. Especially
suitable for this is <command>tr</command>.</para>
<para>
<programlisting># From "wstrings.sh" example.
wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \
tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '`</programlisting>
</para>
</listitem>
2002-06-03 14:35:48 +00:00
<listitem>
<para>Use <quote><link linkend="anonheredoc0">anonymous here
documents</link></quote> to comment out blocks of code,
to save having to individually comment out each line with
a <token>#</token>. See <xref linkend="commentblock">.</para>
</listitem>
2001-09-04 13:27:31 +00:00
<listitem>
<para>The <link linkend="runpartsref">run-parts</link>
command is handy for running a set of command
scripts in sequence, particularly in combination
with <link linkend="cronref">cron</link> or <link
linkend="atref">at</link>.</para>
2002-06-03 14:35:48 +00:00
</listitem>
2001-07-10 14:25:50 +00:00
<listitem>
<para>It would be nice to be able to invoke X-Windows widgets
from a shell script. There happen to exist
several packages that purport to do so, namely
<emphasis>Xscript</emphasis>, <emphasis>Xmenu</emphasis>,
and <emphasis>widtools</emphasis>. The first two of
these no longer seem to be maintained. Fortunately, it is
still possible to obtain <emphasis>widtools</emphasis> <ulink
url="http://www.batse.msfc.nasa.gov/~mallozzi/home/software/xforms/src/widtools-2.0.tgz">here</ulink>.
</para>
<caution><para>The <emphasis>widtools</emphasis> (widget tools)
package requires the <emphasis>XForms</emphasis> library to
2001-10-15 14:21:41 +00:00
be installed. Additionally, the <link
linkend="makefileref">Makefile</link> needs some judicious
editing before the package will build on a typical Linux
system. Finally, three of the six widgets offered do not work
(and, in fact, segfault).</para></caution>
2001-07-10 14:25:50 +00:00
<para>For more effective scripting with widgets, try
<emphasis>Tk</emphasis> or <emphasis>wish</emphasis>
(<emphasis>Tcl</emphasis> derivatives),
<emphasis>PerlTk</emphasis> (Perl with Tk extensions),
<emphasis>tksh</emphasis> (ksh with Tk extensions),
<emphasis>XForms4Perl</emphasis> (Perl with XForms
extensions), <emphasis>Gtk-Perl</emphasis> (Perl with Gtk
extensions), or <emphasis>PyQt</emphasis> (Python with
Qt extensions).</para>
</listitem>
</itemizedlist>
2001-09-04 13:27:31 +00:00
</sect1> <!-- Assorted Tips -->
2001-10-15 14:21:41 +00:00
<sect1 id="oddities">
<title>Oddities</title>
<para>Can a script <link linkend="recursionref">recursively</link>
call itself? Indeed.</para>
<example id="recurse">
2002-06-03 14:35:48 +00:00
<title>A (useless) script that recursively calls itself</title>
2001-10-15 14:21:41 +00:00
<programlisting>&recurse;</programlisting>
</example>
2002-06-03 14:35:48 +00:00
<example id="pbook">
<title>A (useful) script that recursively calls itself</title>
<programlisting>&pbook;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<caution><para>Too many levels of recursion can exhaust the
script's stack space, causing a segfault.</para></caution>
</sect1> <!-- Oddities -->
2001-09-04 13:27:31 +00:00
2002-06-03 14:35:48 +00:00
<sect1 id="securityissues">
<title>Security Issues</title>
<para>A brief warning about script security is appropriate.
A shell script may contain a <emphasis>worm</emphasis>,
<emphasis>trojan</emphasis>, or even a <emphasis>virus</emphasis>.
For that reason, never run as root a script (or permit it
to be inserted into the system startup scripts in <filename
class="directory">/etc/rc.d</filename>) unless you have obtained
said script from a trusted source or you have carefully analyzed
it to make certain it does nothing harmful.</para>
<para>Various researchers at Bell Labs and other sites, including M.
Douglas McIlroy, Tom Duff, and Fred Cohen have investigated the
implications of shell script viruses. They conclude that it is
all to easy for even a novice, a <quote>script kiddie</quote>,
to write one.
2002-06-17 13:17:07 +00:00
<footnote><para>See Marius van Oers' article, <ulink
url="http://www.virusbtn.com/magazine/archives/200204/malshell.xml">Unix
Shell Scripting Malware</ulink>, and also the
<emphasis>Denning</emphasis> reference in the <link
2002-06-03 14:35:48 +00:00
linkend="biblioref">bibliography</link>.</para></footnote>
</para>
<para>Here is yet another reason to learn scripting. Being able to
look at and understand scripts may protect your system from
being hacked or damaged.</para>
</sect1> <!-- Security -->
2001-09-04 13:27:31 +00:00
<sect1 id="portabilityissues">
<title>Portability Issues</title>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>This book deals specifically with Bash scripting on
a GNU/Linux system. All the same, users of <command>sh</command>
and <command>ksh</command> will find much of value here.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>As it happens, many of the various shells and scripting
languages seem to be converging toward the POSIX 1003.2
standard. Invoking Bash with the <option>--posix</option>
option or inserting a <command>set -o posix</command> at the
head of a script causes Bash to conform very closely to this
standard. Even lacking this measure, most Bash scripts will run
as-is under <command>ksh</command>, and vice-versa, since
Chet Ramey has been busily porting <command>ksh</command>
features to the latest versions of Bash.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
<para>On a commercial UNIX machine, scripts using GNU-specific
features of standard commands may not work. This has become
less of a problem in the last few years, as the GNU utilities
have pretty much displaced their proprietary counterparts even
on <quote>big-iron</quote> UNIX. Caldera's recent release of
the source to many of the original UNIX utilities will only
accelerate the trend.</para>
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</sect1> <!-- Portability Issues -->
2002-01-07 15:24:19 +00:00
<sect1 id="winscript">
<title>Shell Scripting Under Windows</title>
<para>Even users running <emphasis>that other</emphasis> OS can
run UNIX-like shell scripts, and therefore benefit
from many of the lessons of this book. The <ulink
url="http://sourceware.cygnus.com/cygwin/">
Cygwin</ulink> package from Cygnus and the <ulink
url="http://www.mkssoftware.com/">MKS utilities</ulink> from
Mortice Kern Associates add shell scripting capabilities to
Windows.</para>
</sect1> <!-- Shell Scripting Under Windows -->
2001-09-04 13:27:31 +00:00
</chapter> <!-- Miscellany -->
<chapter id="bash2">
<title>Bash, version 2</title>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<para><anchor id="bash2ref"></para>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<para>The current version of <emphasis>Bash</emphasis>, the one
2002-06-03 14:35:48 +00:00
you have running on your machine, is actually version 2.XX.Y.
2001-10-15 14:21:41 +00:00
<screen><prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
2002-06-03 14:35:48 +00:00
<computeroutput>2.05.8(1)-release</computeroutput>
2001-10-15 14:21:41 +00:00
</screen>
This update of the classic Bash scripting language added array
variables,
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<footnote><para>Chet Ramey promises associative arrays (a Perl
feature) in a future Bash release.</para></footnote>
2001-09-04 13:27:31 +00:00
2001-10-15 14:21:41 +00:00
string and parameter expansion, and a better method
of indirect variable references, among other features.</para>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<example id="ex77">
<title>String expansion</title>
<programlisting>&ex77;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
<example id="ex78">
<title>Indirect variable references - the new way</title>
<programlisting>&ex78;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<example id="resistor">
<title>Simple database application, using indirect variable
referencing</title>
<programlisting>&resistor;</programlisting>
</example>
2001-10-15 14:21:41 +00:00
<example id="ex79">
<title>Using arrays and other miscellaneous trickery
to deal four random hands from a deck of cards</title>
<programlisting>&ex79;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
</chapter> <!-- Bash, version 2 -->
2001-07-10 14:25:50 +00:00
2001-10-15 14:21:41 +00:00
</part> <!-- Part 4 (Advanced Topics) -->
2001-07-10 14:25:50 +00:00
<chapter id="endnotes">
2001-09-04 13:27:31 +00:00
<title>Endnotes</title>
2001-07-10 14:25:50 +00:00
<sect1 id="authorsnote">
<title>Author's Note</title>
<para>How did I come to write a Bash scripting book? It's a strange
2002-06-03 14:35:48 +00:00
tale. It seems that a couple of years back, I needed to learn
shell scripting -- and what better way to do that than to read a
good book on the subject? I was looking to buy a tutorial and
reference covering all aspects of the subject. I was looking for a
book that would take difficult concepts, turn them inside out, and
explain them in excruciating detail with well-commented examples.
<footnote><para>This is the notorious <quote>flog it to
death</quote> technique.</para></footnote>
In fact, I was looking for this very book, or something much
like it. Unfortunately, it didn't exist, and if I wanted it,
I'd have to write it. And so, here we are, folks.</para>
2001-07-10 14:25:50 +00:00
<para>This reminds me of the apocryphal story about the mad
professor. Crazy as a loon, the fellow was. At the sight of a
2002-06-03 14:35:48 +00:00
book, any book -- at the library, at a bookstore, anywhere --
he would become totally obsessed with the idea that he could have
2001-07-10 14:25:50 +00:00
written it, should have written it, and done a better job of it to
boot. He would thereupon rush home and proceed to do just that,
2002-06-03 14:35:48 +00:00
write a book with the very same title. When he died some years
later, he allegedly had several thousand books to his credit,
probably putting even Asimov to shame. The books might not have
been any good, who knows, but does that really matter? Here's
a fellow who lived his dream, even if he was obsessed by it,
driven by it, and I can't help admiring the old coot...</para>
2001-07-10 14:25:50 +00:00
</sect1> <!-- Author's Note -->
2001-09-04 13:27:31 +00:00
<sect1 id="aboutauthor">
<title>About the Author</title>
<subtitle>Who is this guy anyhow?</subtitle>
<para>The author claims no credentials or special qualifications,
other than a compulsion to write.
<footnote><para>Those who can, do. Those who can't... get an
MCSE.</para></footnote>
This book is somewhat of a departure from his other major work,
2002-06-03 14:35:48 +00:00
<ulink url="http://personal.riverusers.com/~thegrendel/hmw50.zip">
2001-09-04 13:27:31 +00:00
HOW-2 Meet Women: The Shy Man's Guide to
2001-10-15 14:21:41 +00:00
Relationships</ulink>. He has also written the <ulink
2002-06-03 14:35:48 +00:00
url="http://tldp.org/HOWTO/Software-Building-HOWTO.html">Software-Building
2001-10-15 14:21:41 +00:00
HOWTO</ulink>.</para>
2001-09-04 13:27:31 +00:00
<para>A Linux user since 1995 (Slackware 2.2, kernel 1.2.1),
2001-10-15 14:21:41 +00:00
the author has emitted a few
2001-09-04 13:27:31 +00:00
software truffles, including the <ulink
url="http://ibiblio.org/pub/Linux/utils/file/cruft-0.2.tar.gz">cruft</ulink>
one-time pad encryption utility, the <ulink
url="http://ibiblio.org/pub/Linux/apps/financial/mcalc-1.6.tar.gz">mcalc</ulink>
mortgage calculator, the <ulink
url="http://ibiblio.org/pub/Linux/games/amusements/judge-1.0.tar.gz">judge</ulink>
Scrabble&reg; adjudicator, and the <ulink
url="http://ibiblio.org/pub/Linux/libs/yawl-0.2.tar.gz">yawl</ulink>
word gaming list package. He got his start in programming using
FORTRAN IV on a CDC 3800, but is not the least bit nostalgic
for those days.</para>
<para>Living in a secluded desert community with wife and dog,
he cherishes human frailty.</para>
</sect1> <!-- About the Author -->
2001-07-10 14:25:50 +00:00
<sect1 id="toolsused">
<title>Tools Used to Produce This Book</title>
2001-10-15 14:21:41 +00:00
<sect2 id="software-hardware">
<title>Hardware</title>
2002-06-03 14:35:48 +00:00
<para>A used IBM Thinkpad, model 760XL laptop (P166, 104 meg RAM)
running Red Hat 7.1/7.3. Sure, it's slow and has a funky
2002-04-01 16:04:17 +00:00
keyboard, but it beats the heck out of a No. 2 pencil and a
Big Chief tablet.</para>
2001-10-15 14:21:41 +00:00
</sect2> <!-- Hardware -->
2001-09-04 13:27:31 +00:00
<sect2 id="software-printware">
<title>Software and Printware</title>
<orderedlist id="software-printware2" numeration="lowerroman">
2001-07-10 14:25:50 +00:00
<listitem>
<para>Bram Moolenaar's powerful SGML-aware <ulink
url="http://www.vim.org">vim</ulink> text editor.</para>
</listitem>
<listitem>
<para><ulink
2001-09-04 13:27:31 +00:00
url="http://www.netfolder.com/DSSSL/">OpenJade</ulink>,
2001-07-10 14:25:50 +00:00
a DSSSL rendering engine for converting SGML documents into other
formats.</para>
</listitem>
<listitem>
<para><ulink url="http://nwalsh.com/docbook/dsssl/"> Norman
Walsh's DSSSL stylesheets</ulink>.</para>
</listitem>
<listitem>
<para><emphasis>DocBook, The Definitive Guide</emphasis>, by Norman
Walsh and Leonard Muellner (O'Reilly, ISBN 1-56592-580-7). This is
the standard reference for anyone attempting to write a document in
Docbook SGML format.</para>
</listitem>
</orderedlist>
2001-09-04 13:27:31 +00:00
</sect2> <!-- Software and Printware -->
2001-07-10 14:25:50 +00:00
</sect1> <!-- Tools Used -->
2001-10-15 14:21:41 +00:00
<sect1 id="credits">
<title>Credits</title>
<para>Community participation made this project possible. The author
gratefully acknowledges that writing this book would have been an
impossible task without help and feedback from all you people out
there.</para>
<para><ulink url="mailto:feloy@free.fr">Philippe Martin</ulink>
translated this document into DocBook/SGML. While not on
the job at a small French company as a software developer,
he enjoys working on GNU/Linux documentation and software,
reading literature, playing music, and for his peace of mind
making merry with friends. You may run across him somewhere
in France or in the Basque Country, or email him at <ulink
url="mailto:feloy@free.fr">feloy@free.fr</ulink>.</para>
<para>Philippe Martin also pointed out that positional parameters
past $9 are possible using {bracket} notation, see <xref
linkend="ex17">.</para>
<para><ulink url="mailto:stephane_chazelas@yahoo.fr">Stephane
Chazelas</ulink> sent a long list of corrections, additions, and
example scripts. More than a contributor, he has, in effect, taken
on the role of <command>editor</command> for this document. Merci
2002-06-03 14:35:48 +00:00
beaucoup!</para>
2001-10-15 14:21:41 +00:00
<para>I would like to especially thank <emphasis>Patrick
Callahan</emphasis>, <emphasis>Mike Novak</emphasis>, and
<emphasis>Pal Domokos</emphasis> for catching bugs, pointing out
ambiguities, and for suggesting clarifications and changes.
Their lively discussion of shell scripting and general
documentation issues inspired me to try to make this document
more readable.</para>
<para>I'm grateful to Jim Van Zandt for pointing out errors and
omissions in version 0.2 of this document. He also contributed
an instructive example script.</para>
<para>Many thanks to <ulink
url="mailto:mikaku@arrakis.es">Jordi Sanfeliu</ulink>
for giving permission to use his fine tree script (<xref
linkend="tree">).</para>
2002-06-17 13:17:07 +00:00
<para>Likewise, thanks to <ulink
url="mailto:charpov@cs.unh.edu">Michel Charpentier</ulink> for
permission to use his <link linkend="bcref">dc</link> factoring script
(<xref linkend="factr">).</para>
2001-10-15 14:21:41 +00:00
<para>Kudos to <ulink
url="mailto:friedman@prep.ai.mit.edu">Noah Friedman</ulink>
for permission to use his string function script (<xref
linkend="string">).</para>
<para><ulink url="mailto:emmanuel.rouat@wanadoo.fr">Emmanuel
Rouat</ulink> suggested corrections and additions on
<link linkend="commandsubref">command substitution</link> and
<link linkend="aliasref">aliases</link>. He also contributed
a very nice sample <filename>.bashrc</filename> file (<xref
linkend="sample-bashrc">).</para>
<para><ulink url="mailto:heiner.steven@odn.de">Heiner Steven</ulink>
kindly gave permission to use his base conversion script, <xref
linkend="base">. He also made a number of corrections and many
helpful suggestions. Special thanks.</para>
2002-06-03 14:35:48 +00:00
<para>Rick Boivie contributed the delightfully recursive
<emphasis>pb.sh</emphasis> script (<xref linkend="pbook">)
and suggested performance improvements for the
<emphasis>monthlypmt.sh</emphasis> script (<xref
linkend="monthlypmt">).</para>
2001-10-15 14:21:41 +00:00
<para>Florian Wisser enlightened me on some of the fine points of
testing strings (see <xref linkend="strtest">), and on other
matters.</para>
<para>Oleg Philon sent suggestions concerning <link
linkend="cutref">cut</link> and <link
linkend="pidofref">pidof</link>.</para>
<para>Marc-Jano Knopp sent corrections on DOS batch files.</para>
<para>Hyun Jin Cha found several typos in the document in the
process of doing a Korean translation. Thanks for pointing
these out.</para>
2002-06-17 13:17:07 +00:00
<para>Andreas Abraham sent in a long list of typographical
errors and other corrections. Special thanks!</para>
2001-10-15 14:21:41 +00:00
<para>Others making helpful suggestions and pointing out errors
2002-04-01 16:04:17 +00:00
were Gabor Kiss, Leopold Toetsch, Peter Tillier, Marcus Berglof,
2002-06-03 14:35:48 +00:00
Tony Richardson, Nick Drage (script ideas!), Rich Bartell,
2002-06-17 13:17:07 +00:00
Jess Thrysoee, Adam Lazur, Bram Moolenaar, Baris Cicek, and
David Lawyer (himself an author of 4 HOWTOs).</para>
2001-10-15 14:21:41 +00:00
<para>My gratitude to <ulink url="mailto:chet@po.cwru.edu">Chet
Ramey</ulink> and Brian Fox for writing <command>Bash</command>,
an elegant and powerful scripting tool.</para>
2002-06-03 14:35:48 +00:00
<para>Very special thanks to the hard-working volunteers at
the <ulink url="http://www.tldp.org">Linux Documentation
Project</ulink>. The LDP hosts a repository of Linux knowledge
and lore, and has, to a large extent, enabled the publication
of this book.</para>
2001-10-15 14:21:41 +00:00
<para>Thanks most of all to my wife, Anita, for her encouragement and
emotional support.</para>
</sect1> <!-- Credits -->
2001-07-10 14:25:50 +00:00
</chapter> <!-- End Notes -->
<bibliography id="biblio">
<anchor id="biblioref">
2002-06-03 14:35:48 +00:00
<biblioentry>
<authorgroup>
<editor><firstname>Peter</firstname><surname>Denning</surname></editor>
</authorgroup>
<title>Computers Under Attack: Intruders, Worms, and Viruses</title>
<publisher>
<publishername>ACM Press</publishername>
</publisher>
<copyright>
<year>1990</year>
</copyright>
<isbn>0-201-53067-8</isbn>
<abstract><para>This compendium contains a couple of articles on
shell script viruses.</para>
<para>*</para>
</abstract>
</biblioentry>
2001-07-10 14:25:50 +00:00
<biblioentry>
<authorgroup>
<author><firstname>Dale</firstname><surname>Dougherty</surname></author>
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
</authorgroup>
<title>Sed and Awk</title>
<edition>2nd edition</edition>
<publisher>
<publishername>O'Reilly and Associates</publishername>
</publisher>
<copyright>
<year>1997</year>
</copyright>
<isbn>1-156592-225-5</isbn>
<abstract><para>
To unfold the full power of shell scripting, you need at least a passing
familiarity with <command>sed</command> and
<command>awk</command>. This is the standard tutorial. It
includes an excellent introduction to <quote>regular expressions</quote>. Read this
book.</para>
<para>*</para>
</abstract>
</biblioentry>
<biblioentry>
<authorgroup>
<author><firstname>Aeleen</firstname><surname>Frisch</surname></author>
</authorgroup>
<title>Essential System Administration</title>
<edition>2nd edition</edition>
<publisher>
<publishername>O'Reilly and Associates</publishername>
</publisher>
<copyright>
<year>1995</year>
</copyright>
<isbn>1-56592-127-5</isbn>
<abstract><para>This excellent sys admin manual has a decent introduction to shell
scripting for sys administrators and does a nice job of explaining the
startup and initialization scripts. The book is long overdue for a third
edition (are you listening, Tim O'Reilly?).</para>
<para>*</para>
</abstract>
</biblioentry>
<biblioentry>
<authorgroup>
<author><firstname>Stephen</firstname><surname>Kochan</surname></author>
<author><firstname>Patrick</firstname><surname>Woods</surname></author>
</authorgroup>
<title>Unix Shell Programming</title>
<publisher>
<publishername>Hayden</publishername>
</publisher>
<copyright>
<year>1990</year>
</copyright>
<isbn>067248448X</isbn>
<abstract><para>The standard reference, though a bit dated by now.</para>
<para>*</para>
</abstract>
</biblioentry>
<biblioentry>
<authorgroup>
<author><firstname>Neil</firstname><surname>Matthew</surname></author>
<author><firstname>Richard</firstname><surname>Stones</surname></author>
</authorgroup>
<title>Beginning Linux Programming</title>
<publisher>
<publishername>Wrox Press</publishername>
</publisher>
<copyright>
<year>1996</year>
</copyright>
<isbn>1874416680</isbn>
<abstract><para>Good in-depth coverage of various programming
languages available for Linux, including a fairly strong chapter
on shell scripting.</para>
<para>*</para>
</abstract>
</biblioentry>
2001-10-15 14:21:41 +00:00
<biblioentry id="mayerref">
2001-07-10 14:25:50 +00:00
<authorgroup>
<author><firstname>Herbert</firstname><surname>Mayer</surname></author>
</authorgroup>
<title>Advanced C Programming on the IBM PC</title>
<publisher>
<publishername>Windcrest Books</publishername>
</publisher>
<copyright>
<year>1989</year>
</copyright>
<isbn>0830693637</isbn>
<abstract><para>Excellent coverage of algorithms and general
programming practices.</para>
<para>*</para>
</abstract>
</biblioentry>
<biblioentry>
<authorgroup>
<author><firstname>David</firstname><surname>Medinets</surname></author>
</authorgroup>
<title>Unix Shell Programming Tools</title>
<publisher>
<publishername>McGraw-Hill</publishername>
</publisher>
<copyright>
<year>1999</year>
</copyright>
<isbn>0070397333</isbn>
<abstract><para>Good info on shell scripting, with examples, and a short
intro to Tcl and Perl.</para>
<para>*</para>
</abstract>
</biblioentry>
<biblioentry>
<authorgroup>
<author><firstname>Cameron</firstname><surname>Newham</surname></author>
<author><firstname>Bill</firstname><surname>Rosenblatt</surname></author>
</authorgroup>
<title>Learning the Bash Shell</title>
<edition>2nd edition</edition>
<publisher>
<publishername>O'Reilly and Associates</publishername>
</publisher>
<copyright>
<year>1998</year>
</copyright>
<isbn>1-56592-347-2</isbn>
<abstract><para>This is a valiant effort at a decent shell primer, but somewhat deficient
in coverage on programming topics and lacking sufficient examples.</para>
<para>*</para>
</abstract>
</biblioentry>
<biblioentry>
<authorgroup>
<author><firstname>Anatole</firstname><surname>Olczak</surname></author>
</authorgroup>
<title>Bourne Shell Quick Reference Guide</title>
<publisher>
<publishername>ASP, Inc.</publishername>
</publisher>
<copyright>
<year>1991</year>
</copyright>
<isbn>093573922X</isbn>
<abstract><para>A very handy pocket reference, despite lacking
coverage of Bash-specific features.</para>
<para>*</para>
</abstract>
</biblioentry>
<biblioentry>
<authorgroup>
<author><firstname>Jerry</firstname><surname>Peek</surname></author>
<author><firstname>Tim</firstname><surname>O'Reilly</surname></author>
<author><firstname>Mike</firstname><surname>Loukides</surname></author>
</authorgroup>
<title>Unix Power Tools</title>
<edition>2nd edition</edition>
<publisher>
<publishername>O'Reilly and Associates</publishername>
</publisher>
<publisher>
<publishername>Random House</publishername>
</publisher>
<copyright>
<year>1997</year>
</copyright>
<isbn>1-56592-260-3</isbn>
<abstract><para>Contains a couple of sections of very informative
in-depth articles on shell programming, but falls short of being
a tutorial. It reproduces much of the regular expressions tutorial
from the Dougherty and Robbins book, above.</para>
<para>*</para>
</abstract>
</biblioentry>
2002-04-01 16:04:17 +00:00
<biblioentry>
<authorgroup>
<author><firstname>Clifford</firstname><surname>Pickover</surname></author>
</authorgroup>
<title>Computers, Pattern, Chaos, and Beauty</title>
<publisher>
<publishername>St. Martin's Press</publishername>
</publisher>
<copyright>
<year>1990</year>
</copyright>
<isbn>0-312-04123-3</isbn>
<abstract><para>A treasure trove of ideas and recipes for
computer-based exploration of mathematical oddities.</para>
<para>*</para>
</abstract>
</biblioentry>
2002-06-03 14:35:48 +00:00
<biblioentry>
<authorgroup>
<author><firstname>George</firstname><surname>Polya</surname></author>
</authorgroup>
<title>How To Solve It</title>
<publisher>
<publishername>Princeton University Press</publishername>
</publisher>
<copyright>
<year>1973</year>
</copyright>
<isbn>0-691-02356-5</isbn>
<abstract><para>The classic tutorial on problem solving methods
(i.e., algorithms).</para>
<para>*</para>
</abstract>
</biblioentry>
2001-07-10 14:25:50 +00:00
<biblioentry>
<authorgroup>
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
</authorgroup>
<title>Bash Reference Card</title>
<publisher>
<publishername>SSC</publishername>
</publisher>
<copyright>
<year>1998</year>
</copyright>
<isbn>1-58731-010-5</isbn>
<abstract>
<para>Excellent Bash pocket reference (don't leave home
without it). A bargain at $4.95, but
also available for free download <ulink
url="http://www.ssc.com/ssc/bash/">on-line</ulink> in pdf
format.</para>
<para>*</para>
</abstract>
</biblioentry>
2001-09-04 13:27:31 +00:00
<biblioentry>
<authorgroup>
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
</authorgroup>
<title>Effective Awk Programming</title>
<publisher>
<publishername>Free Software Foundation / O'Reilly and Associates</publishername>
</publisher>
<copyright>
<year>2000</year>
</copyright>
<isbn>1-882114-26-4</isbn>
<abstract>
<para>The absolute best <command>awk</command> tutorial and
reference. The free electronic version of this book is part of the
<command>awk</command> documentation, and printed copies of the
latest version are available from O'Reilly and Associates.</para>
<para>This book has served as an inspiration for the author of this
document.</para>
<para>*</para>
</abstract>
</biblioentry>
2001-10-15 14:21:41 +00:00
<biblioentry>
<authorgroup>
<author><firstname>Bill</firstname><surname>Rosenblatt</surname></author>
</authorgroup>
<title>Learning the Korn Shell</title>
<publisher>
<publishername>O'Reilly and Associates</publishername>
</publisher>
<copyright>
<year>1993</year>
</copyright>
<isbn>1-56592-054-6</isbn>
<abstract>
<para>This well-written book contains some excellent pointers on shell
scripting.</para>
<para>*</para>
</abstract>
</biblioentry>
2001-09-04 13:27:31 +00:00
<biblioentry>
<authorgroup>
<author><firstname>Paul</firstname><surname>Sheer</surname></author>
</authorgroup>
<title>LINUX: Rute User's Tutorial and Exposition</title>
<edition>1st edition</edition>
<publisher>
<publishername></publishername>
</publisher>
<copyright>
<year>2002</year>
</copyright>
<isbn>0-13-033351-4</isbn>
<abstract>
<para>Very detailed and readable introduction to Linux system
administration.</para>
<para>The book is available in print, or
<ulink url="http://rute.sourceforge.net/">on-line</ulink>.</para>
<para>*</para>
</abstract>
</biblioentry>
2001-07-10 14:25:50 +00:00
<biblioentry>
<authorgroup>
<author><firstname>Ellen</firstname><surname>Siever</surname></author>
2002-06-17 13:17:07 +00:00
<author><surname>the staff of O'Reilly and Associates</surname></author>
2001-07-10 14:25:50 +00:00
</authorgroup>
<title>Linux in a Nutshell</title>
<edition>2nd edition</edition>
<publisher>
<publishername>O'Reilly and Associates</publishername>
</publisher>
<copyright>
<year>1999</year>
</copyright>
<isbn>1-56592-585-8</isbn>
<abstract><para>The all-around best Linux command reference, even has a Bash section.</para>
<para>*</para>
</abstract>
</biblioentry>
<biblioentry>
<title>The UNIX CD Bookshelf</title>
<edition>2nd edition</edition>
<publisher>
<publishername>O'Reilly and Associates</publishername>
</publisher>
<copyright>
<year>2000</year>
</copyright>
<isbn>1-56592-815-6</isbn>
<abstract><para>An array of six UNIX books on CD ROM, including
<emphasis>UNIX Power Tools</emphasis>, <emphasis>Sed
and Awk</emphasis>, and <emphasis>Learning the Korn
Shell</emphasis>. A complete set of all the UNIX references
and tutorials you would ever need at about $70. Buy this one,
even if it means going into debt and not paying the rent.</para>
<para>Unfortunately, out of print at present.</para>
<para>*</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>The O'Reilly books on Perl. (Actually, any O'Reilly books.)</para>
2002-01-07 15:24:19 +00:00
<para>---</para>
2001-07-10 14:25:50 +00:00
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Ben Okopnik's well-written <emphasis>introductory Bash
scripting</emphasis> articles in issues 53, 54, 55, 57, and 59
of the <ulink url="http://www.linuxgazette.com">Linux Gazette
</ulink>, and his explanation of <quote>The Deep, Dark Secrets
of Bash</quote> in issue 56.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract><para>Chet Ramey's <emphasis>bash - The GNU Shell</emphasis>,
a two-part series published in issues 3 and 4 of the <ulink
url="http://www.linuxjournal.com">Linux Journal</ulink>,
July-August 1994.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Mike G's <ulink
2002-06-03 14:35:48 +00:00
url="http://www.tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html">Bash-Programming-Intro
2001-07-10 14:25:50 +00:00
HOWTO</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Richard's <ulink url="http://www.injunea.demon.co.uk/index.htm">UNIX
Scripting Universe</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Chet Ramey's <ulink
url="ftp://ftp.cwru.edu/pub/bash/FAQ">Bash F.A.Q.</ulink></para>
</abstract>
</biblioentry>
2002-06-03 14:35:48 +00:00
<biblioentry>
<abstract>
<para>Ed Schaefer's <ulink
url="http://www.unixreview.com/columns/schaefer/">Shell Corner</ulink>
in <ulink url="http://www.unixreview.com">Unix Review</ulink>.</para>
</abstract>
</biblioentry>
2001-07-10 14:25:50 +00:00
<biblioentry>
<abstract>
<para>Example shell scripts at <ulink
url="http://alge.anart.no/linux/scripts/">Lucc's Shell Scripts
</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Example shell scripts at <ulink
url="http://www.oase-shareware.org/shell/scripts">SHELLdorado
</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Example shell scripts at <ulink
url="http://clri6f.gsi.de/gnu/bash-2.01/examples/scripts.noah/">Noah
Friedman's script site</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Example shell scripts at <ulink
url="http://sourceforge.net/snippet/browse.php?by=lang&amp;lang=7">
SourceForge Snippet Library - shell scrips</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Giles Orr's <ulink
2002-06-03 14:35:48 +00:00
url="http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO.html">Bash-Prompt
2001-07-10 14:25:50 +00:00
HOWTO</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>The <ulink
url="http://www.cornerstonemag.com/sed/sedfaq.html">sed
F.A.Q.</ulink></para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Carlos Duarte's instructive <ulink
url="http://www.dbnet.ece.ntua.gr/~george/sed/sedtut_1.html"><quote>Do
It With Sed</quote></ulink> tutorial.</para>
</abstract>
</biblioentry>
2002-06-03 14:35:48 +00:00
<biblioentry>
<abstract>
<para>Very nice <command>sed</command>,
<command>awk</command>, and regular expression tutorials at
<ulink url="http://www.grymoire.com/Unix/index.html">The UNIX
Grymoire</ulink>.</para>
</abstract>
</biblioentry>
2001-07-10 14:25:50 +00:00
<biblioentry>
<abstract>
<para>The GNU <command>gawk</command> <ulink
url="http://sunsite.ualberta.ca/Documentation/Gnu/gawk-3.0.6/gawk.html">
reference manual</ulink> (<command>gawk</command> is the extended
GNU version of <command>awk</command> available on Linux and
BSD systems).</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Trent Fisher's <ulink
url="http://www.cs.pdx.edu/~trent/gnu/groff/groff.html">groff
tutorial</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Mark Komarinski's <ulink
2002-06-03 14:35:48 +00:00
url="http://www.tldp.org/HOWTO/Printing-Usage-HOWTO.html">Printing-Usage
2001-07-10 14:25:50 +00:00
HOWTO</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
2002-01-07 15:24:19 +00:00
<para>There is some nice material on <link
linkend="ioredirref">I/O redirection</link> in <ulink
2001-07-10 14:25:50 +00:00
url="http://sunsite.ualberta.ca/Documentation/Gnu/textutils-2.0/html_chapter/textutils_10.html">
chapter 10 of the textutils documentation</ulink> at the <ulink
url="http://sunsite.ualberta.ca/Documentation"> University of
Alberta site</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
2001-09-04 13:27:31 +00:00
<para><ulink url="mailto:humbubba@smarty.smart.net">Rick
Hohensee</ulink> has written the <ulink
url="ftp://ftp.gwdg.de/pub/linux/install/clienux/interim/osimpa.tgz">
osimpa</ulink> i386 assembler entirely as Bash scripts.</para>
2002-01-07 15:24:19 +00:00
<para>---</para>
2001-07-10 14:25:50 +00:00
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>The excellent "Bash Reference Manual", by Chet Ramey and Brian Fox,
distributed as part of the "bash-2-doc" package (available as an rpm).
See especially the instructive example scripts in this package.</para>
</abstract>
</biblioentry>
2002-01-07 15:24:19 +00:00
<biblioentry>
<abstract>
<para>The <ulink
url="news:comp.unix.shell">comp.os.unix.shell</ulink>
newsgroup.</para>
</abstract>
</biblioentry>
2001-07-10 14:25:50 +00:00
<biblioentry>
<abstract>
2001-09-04 13:27:31 +00:00
<para>The manpages for <command>bash</command> and
2001-07-10 14:25:50 +00:00
<command>bash2</command>, <command>date</command>,
<command>expect</command>, <command>expr</command>,
<command>find</command>, <command>grep</command>,
<command>gzip</command>, <command>ln</command>,
<command>patch</command>, <command>tar</command>,
<command>tr</command>, <command>bc</command>,
<command>xargs</command>. The texinfo documentation
on <command>bash</command>, <command>dd</command>,
2001-10-15 14:21:41 +00:00
<command>m4</command>, <command>gawk</command>, and
<command>sed</command>.</para>
2001-07-10 14:25:50 +00:00
</abstract>
</biblioentry>
</bibliography>
<appendix id="contributed-scripts">
<title>Contributed Scripts</title>
<para>These scripts, while not fitting into the text of this document, do
illustrate some interesting shell programming techniques. They are useful,
too. Have fun analyzing and running them.</para>
<example id="manview">
2001-09-04 13:27:31 +00:00
<title><command>manview</command>: Viewing formatted manpages
2001-07-10 14:25:50 +00:00
</title>
<programlisting>&manview;</programlisting>
</example>
<example id="mailformat">
<title><command>mailformat</command>: Formatting an e-mail message</title>
<programlisting>&mailformat;</programlisting>
</example>
<example id="rn">
<title><command>rn</command>: A simple-minded file rename utility</title>
<para>This script is a modification of <xref
linkend="lowercase">.</para>
<programlisting>&rn;</programlisting>
</example>
2002-06-17 13:17:07 +00:00
<example id="blankrename">
<title><command>blank-rename</command>: renames filenames containing
blanks</title>
<para>This is an even simpler-minded version of previous script.</para>
<programlisting>&blankrename;</programlisting>
</example>
2001-07-10 14:25:50 +00:00
<example id="encryptedpw">
2001-09-04 13:27:31 +00:00
<title><command>encryptedpw</command>: Uploading to an ftp site,
2001-07-10 14:25:50 +00:00
using a locally encrypted password</title>
<programlisting>&encryptedpw;</programlisting>
</example>
<example id="copycd">
2001-09-04 13:27:31 +00:00
<title><command>copy-cd</command>: Copying a data CD</title>
2001-07-10 14:25:50 +00:00
<programlisting>&copycd;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<example id="collatz">
<title>Collatz series</title>
<programlisting>&collatz;</programlisting>
</example>
2001-09-04 13:27:31 +00:00
<example id="daysbetween">
2002-04-01 16:04:17 +00:00
<title><command>days-between</command>: Calculate number of days
between two dates</title>
2001-09-04 13:27:31 +00:00
<programlisting>&daysbetween;</programlisting>
</example>
2002-06-03 14:35:48 +00:00
<example id="makedict">
<title>Make a <quote>dictionary</quote></title>
<programlisting>&makedict;</programlisting>
</example>
2002-04-01 16:04:17 +00:00
<example id="lifeslow">
<title><quote>Game of Life</quote></title>
<programlisting>&lifeslow;</programlisting>
</example>
<example id="gen0data">
<title>Data file for <quote>Game of Life</quote></title>
<programlisting>&gen0data;</programlisting>
</example>
<para>+++</para>
2001-07-10 14:25:50 +00:00
<para>The following two scripts are by Mark Moraes of the University
of Toronto. See the enclosed file <quote>Moraes-COPYRIGHT</quote>
for permissions and restrictions.</para>
<example id="behead">
2001-09-04 13:27:31 +00:00
<title><command>behead</command>: Removing mail and news message headers
2001-07-10 14:25:50 +00:00
</title>
<programlisting>&behead;</programlisting>
</example>
<example id="ftpget">
2001-09-04 13:27:31 +00:00
<title><command>ftpget</command>: Downloading files via ftp
2001-07-10 14:25:50 +00:00
</title>
<programlisting>&ftpget;</programlisting>
</example>
<para>+</para>
<para>Antek Sawicki contributed the following script, which makes very
clever use of the parameter substitution operators discussed in
<xref linkend="Parameter-Substitution">.</para>
<example id="pw">
2001-09-04 13:27:31 +00:00
<title><command>password</command>: Generating random
2001-07-10 14:25:50 +00:00
8-character passwords</title>
<programlisting>&pw;</programlisting>
</example>
<para>+</para>
<para>James R. Van Zandt contributed this script, which uses named pipes
and, in his words, <quote>really exercises quoting and escaping</quote>.
</para>
<example id="fifo">
2001-09-04 13:27:31 +00:00
<title><command>fifo</command>: Making daily backups, using named pipes</title>
2001-07-10 14:25:50 +00:00
<programlisting>&fifo;</programlisting>
</example>
<para>+</para>
<para>Stephane Chazelas contributed the following script to
demonstrate that generating prime numbers does not require
arrays.</para>
<example id="primes">
<title>Generating prime numbers using the modulo operator</title>
<programlisting>&primes;</programlisting>
</example>
<para>+</para>
<para>Jordi Sanfeliu gave permission to use his elegant
<emphasis>tree</emphasis> script.</para>
<example id="tree">
2001-09-04 13:27:31 +00:00
<title><command>tree</command>: Displaying a directory tree</title>
2001-07-10 14:25:50 +00:00
<programlisting>&tree;</programlisting>
</example>
<para>Noah Friedman gave permission to use his <emphasis>string
function</emphasis> script, which essentially reproduces some of the
C-library string manipulation functions.</para>
<example id="string">
<title><command>string functions</command>: C-like string functions</title>
<programlisting>&string;</programlisting>
</example>
<para>Stephane Chazelas demonstrates object-oriented programming a
Bash script.</para>
<example id="objoriented">
<title>Object-oriented database</title>
<programlisting>&objoriented;</programlisting>
</example>
</appendix>
<!-- End Contributed Scripts appendix -->
<appendix id="sedawk">
<title>A Sed and Awk Micro-Primer</title>
<para><anchor id="sedref"></para>
<para>This is a very brief introduction to the <command>sed</command>
and <command>awk</command> text processing utilities. We will
deal with only a few basic commands here, but that will suffice
for understanding simple sed and awk constructs within shell
scripts.</para>
<para><command>sed</command>: a non-interactive text file editor</para>
<para><command>awk</command>: a field-oriented pattern processing
language with a C-like syntax</para>
<para>For all their differences, the two utilities share a similar
invocation syntax, both use <link linkend="regexref">regular
expressions </link>, both read input by default
from <filename>stdin</filename>, and both output to
<filename>stdout</filename>. These are well-behaved UNIX tools,
and they work together well. The output from one can be piped
into the other, and their combined capabilities give shell
scripts some of the power of Perl.</para>
<note><para>One important difference between the utilities is
that while shell scripts can easily pass arguments to sed, it
is more complicated for awk (see <xref linkend="coltotaler">
and <xref linkend="coltotaler2">).
</para></note>
<sect1>
<title>Sed</title>
<para>Sed is a non-interactive line editor. It receives text
input, whether from <filename>stdin</filename> or from a
file, performs certain operations on specified lines of
the input, one line at a time, then outputs the result to
<filename>stdout</filename> or to a file. Within a shell script,
sed is usually one of several tool components in a pipe.</para>
<para>Sed determines which lines of its input that it will
operate on from the <emphasis>address range</emphasis> passed
to it.
<footnote><para>If no address range is specified, the default
is <emphasis>all</emphasis> lines.</para></footnote>
Specify this address range either by line number or by a
pattern to match. For example, <replaceable>3d</replaceable>
signals sed to delete line 3 of the input, and
<replaceable>/windows/d</replaceable> tells sed that
you want every line of the input containing a match to
<quote>windows</quote> deleted.</para>
<para>Of all the operations in the sed toolkit, we will focus
primarily on the three most commonly used
ones. These are <command>p</command>rinting (to
<filename>stdout</filename>), <command>d</command>eletion,
and <command>s</command>ubstitution.</para>
<table>
<title>Basic sed operators</title>
<tgroup cols="3">
<thead>
<row>
<entry>Operator</entry>
<entry>Name</entry>
<entry>Effect</entry>
</row>
</thead>
<tbody>
<row>
<entry><option>[address-range]/p</option></entry>
<entry>print</entry>
<entry>Print [specified address range]</entry>
</row>
<row>
<entry><option>[address-range]/d</option></entry>
<entry>delete</entry>
<entry>Delete [specified address range]</entry>
</row>
<row>
<entry><option>s/pattern1/pattern2/</option></entry>
<entry>substitute</entry>
<entry>Substitute pattern2 for first instance of pattern1 in a line</entry>
</row>
<row>
<entry><option>[address-range]/s/pattern1/pattern2/</option></entry>
<entry>substitute</entry>
<entry>Substitute pattern2 for first instance of pattern1 in a
line, over <replaceable>address-range</replaceable></entry>
</row>
<row>
<entry><option>[address-range]/y/pattern1/pattern2/</option></entry>
<entry>transform</entry>
<entry>replace any character in pattern1 with the
corresponding character in pattern2, over
<replaceable>address-range</replaceable> (equivalent of
<command>tr</command>)</entry>
</row>
<row>
<entry><option>g</option></entry>
<entry>global</entry>
<entry>Operate on <emphasis>every</emphasis> pattern match
within each matched line of input</entry>
</row>
</tbody>
</tgroup>
</table>
<note><para>Unless the <option>g</option>
(<emphasis>global</emphasis>) operator is appended to a
<emphasis>substitute</emphasis> command, the substitution
operates only on the first instance of a pattern match within
each line.</para></note>
<para>From the command line and in a shell script, a sed operation may
require quoting and certain options.</para>
2002-01-07 15:24:19 +00:00
<para><programlisting>sed -e '/^$/d' $filename
# The -e option causes the next string to be interpreted as an editing instruction.
# (If passing only a single instruction to "sed", the "-e" is optional.)
# The "strong" quotes ('') protect the RE characters in the instruction
#+ from reinterpretation as special characters by the body of the script.
2001-07-10 14:25:50 +00:00
# (This reserves RE expansion of the instruction for sed.)
2002-01-07 15:24:19 +00:00
#
# Operates on the text contained in file $filename.
2001-07-10 14:25:50 +00:00
</programlisting></para>
2001-10-15 14:21:41 +00:00
<note><para>Sed uses the <option>-e</option> option
2001-07-10 14:25:50 +00:00
to specify that the following string is an instruction or set
of instructions. If there is only a single instruction contained
in the string, then this option may be omitted.</para></note>
2002-01-07 15:24:19 +00:00
<para><programlisting>sed -n '/xzy/p' $filename
2001-07-10 14:25:50 +00:00
# The -n option tells sed to print only those lines matching the pattern.
# Otherwise all input lines would print.
# The -e option not necessary here since there is only a single editing instruction.
</programlisting></para>
<table>
<title>Examples</title>
<tgroup cols="2">
<thead>
<row>
<entry>Notation</entry>
<entry>Effect</entry>
</row>
</thead>
<tbody>
<row>
<entry><option>8d</option></entry>
<entry>Delete 8th line of input.</entry>
</row>
<row>
<entry><option>/^$/d</option></entry>
<entry>Delete all blank lines.</entry>
</row>
<row>
<entry><option>1,/^$/d</option></entry>
<entry>Delete from beginning of input up to, and including
first blank line.</entry>
</row>
<row>
<entry><option>/Jones/p</option></entry>
<entry>Print only lines containing <quote>Jones</quote> (with
<token>-n</token> option).</entry>
</row>
<row>
<entry><option>s/Windows/Linux/</option></entry>
<entry>Substitute <quote>Linux</quote> for first instance
2002-06-17 13:17:07 +00:00
of <quote>Windows</quote> found in each input line.</entry>
2001-07-10 14:25:50 +00:00
</row>
<row>
<entry><option>s/BSOD/stability/g</option></entry>
<entry>Substitute <quote>stability</quote> for every instance
2002-06-17 13:17:07 +00:00
of <quote>BSOD</quote> found in each input line.</entry>
2001-07-10 14:25:50 +00:00
</row>
<row>
<entry><option>s/ *$//</option></entry>
<entry>Delete all spaces at the end of every line.</entry>
</row>
<row>
<entry><option>s/00*/0/g</option></entry>
<entry>Compress all consecutive sequences of zeroes into
a single zero.</entry>
</row>
<row>
<entry><option>/GUI/d</option></entry>
<entry>Delete all lines containing <quote>GUI</quote>.</entry>
</row>
<row>
<entry><option>s/GUI//g</option></entry>
<entry>Delete all instances of <quote>GUI</quote>, leaving the
remainder of each line intact.</entry>
</row>
</tbody>
</tgroup>
</table>
2002-04-01 16:04:17 +00:00
<para>Substituting a zero-length string for another is equivalent
2001-07-10 14:25:50 +00:00
to deleting that string within a line of input. This leaves the
remainder of the line intact. Applying <userinput>s/GUI//</userinput>
2002-04-01 16:04:17 +00:00
to the line
<screen><userinput>The most important parts of any application are its GUI and sound effects</userinput></screen>
results in
<screen><computeroutput>The most important parts of any application are its and sound effects</computeroutput></screen></para>
<para>The backslash represents a <emphasis>newline</emphasis> as a
substitution character. In this special case, the replacement
expression continues on the next line.
<programlisting>s/^ */\
/g</programlisting>
This substitution replaces line-beginning spaces with a
newline. The net result is to replace paragraph indents with
a blank line between paragraphs.</para>
<para>An address range followed by one or more operations may require
open and closed curly brackets, with appropriate newlines.
<programlisting>/[0-9A-Za-z]/,/^$/{
/^$/d
}</programlisting>
This deletes only the first of each set of consecutive blank
lines. That might be useful for single-spacing a text file,
but retaining the blank line(s) between paragraphs.</para>
2001-07-10 14:25:50 +00:00
<tip><para>A quick way to double-space a text file is <userinput>sed G
filename</userinput>.</para></tip>
<para>For illustrative examples of sed within shell scripts, see:
<orderedlist>
<listitem><para><xref linkend="ex3"></para></listitem>
<listitem><para><xref linkend="ex4"></para></listitem>
<listitem><para><xref linkend="ex57"></para></listitem>
<listitem><para><xref linkend="rn"></para></listitem>
<listitem><para><xref linkend="grp"></para></listitem>
<listitem><para><xref linkend="col"></para></listitem>
<listitem><para><xref linkend="behead"></para></listitem>
<listitem><para><xref linkend="tree"></para></listitem>
<listitem><para><xref linkend="stripc"></para></listitem>
<listitem><para><xref linkend="findstring"></para></listitem>
<listitem><para><xref linkend="base"></para></listitem>
<listitem><para><xref linkend="mailformat"></para></listitem>
<listitem><para><xref linkend="rnd"></para></listitem>
2002-01-07 15:24:19 +00:00
<listitem><para><xref linkend="wf"></para></listitem>
2002-04-01 16:04:17 +00:00
<listitem><para><xref linkend="lifeslow"></para></listitem>
2002-06-03 14:35:48 +00:00
<listitem><para><xref linkend="selfdocument"></para></listitem>
2001-07-10 14:25:50 +00:00
</orderedlist>
</para>
<para>For a more extensive treatment of sed, check the appropriate
references in the <xref linkend="biblio">.</para>
</sect1>
<!-- End sed primer -->
<sect1 id="awk">
<title>Awk</title>
2002-04-01 16:04:17 +00:00
<para><anchor id="awkref"></para>
2001-07-10 14:25:50 +00:00
<para><command>Awk</command> is a full-featured text processing
language with a syntax reminiscent of <command>C</command>. While
it possesses an extensive set of operators and capabilities,
we will cover only a couple of these here - the ones most useful
for shell scripting.</para>
<para>Awk breaks each line of input passed to it into
<emphasis>fields</emphasis>. By default, a field is
a string of consecutive characters separated by <link
linkend="whitespaceref">whitespace</link>, though there are
options for changing the delimiter. Awk parses and operates on each
separate field. This makes awk ideal for handling structured text
files, especially tables, data organized into consistent chunks,
such as rows and columns.</para>
<para>Strong quoting (single quotes) and curly brackets enclose
segments of awk code within a shell script.</para>
2002-01-07 15:24:19 +00:00
<para><programlisting>awk '{print $3}' $filename
# Prints field #3 of file $filename to stdout.
2001-07-10 14:25:50 +00:00
2002-01-07 15:24:19 +00:00
awk '{print $1 $5 $6}' $filename
# Prints fields #1, #5, and #6 of file $filename.</programlisting></para>
2001-07-10 14:25:50 +00:00
<para>We have just seen the awk <command>print</command> command
in action. The only other feature of awk we need to deal with
here is variables. Awk handles variables similarly to shell
scripts, though a bit more flexibly.</para>
<para><programlisting>{ total += ${column_number} }</programlisting>
This adds the value of <emphasis>column_number</emphasis> to
the running total of <quote>total</quote>. Finally, to print
2002-01-07 15:24:19 +00:00
<quote>total</quote>, there is an <command>END</command> command
block, executed after the script has processed all its input.
2001-07-10 14:25:50 +00:00
<programlisting>END { print total }</programlisting></para>
<para>Corresponding to the <command>END</command>, there is a
<command>BEGIN</command>, for a code block to be performed before awk
starts processing its input.</para>
<para>For examples of awk within shell scripts, see:
<orderedlist>
<listitem><para><xref linkend="ex44"></para></listitem>
<listitem><para><xref linkend="redir4"></para></listitem>
<listitem><para><xref linkend="stripc"></para></listitem>
<listitem><para><xref linkend="coltotaler"></para></listitem>
<listitem><para><xref linkend="coltotaler2"></para></listitem>
<listitem><para><xref linkend="coltotaler3"></para></listitem>
<listitem><para><xref linkend="pidid"></para></listitem>
<listitem><para><xref linkend="constat"></para></listitem>
<listitem><para><xref linkend="fileinfo"></para></listitem>
2001-09-04 13:27:31 +00:00
<listitem><para><xref linkend="blotout"></para></listitem>
2001-07-10 14:25:50 +00:00
<listitem><para><xref linkend="seedingrandom"></para></listitem>
2001-10-15 14:21:41 +00:00
<listitem><para><xref linkend="idelete"></para></listitem>
2002-01-07 15:24:19 +00:00
<listitem><para><xref linkend="substringex"></para></listitem>
2002-04-01 16:04:17 +00:00
<listitem><para><xref linkend="sumproduct"></para></listitem>
<listitem><para><xref linkend="userlist"></para></listitem>
2001-07-10 14:25:50 +00:00
</orderedlist>
</para>
<para>That's all the awk we'll cover here, folks, but there's lots
more to learn. See the appropriate references in the <xref
linkend="biblio">.</para>
</sect1>
<!-- End awk primer -->
</appendix>
<!-- End sed/awk appendix -->
<appendix id="exitcodes">
<title>Exit Codes With Special Meanings</title>
<para><anchor id="exitcodesref"></para>
<table>
<title><quote>Reserved</quote> Exit Codes</title>
<tgroup cols="4">
<thead>
<row>
<entry>Exit Code Number</entry>
<entry>Meaning</entry>
<entry>Example</entry>
<entry>Comments</entry>
</row>
</thead>
<tbody>
<row>
<entry><option>1</option></entry>
<entry>catchall for general errors</entry>
<entry>let "var1 = 1/0"</entry>
<entry>miscellaneous errors, such as <quote>divide by
zero</quote></entry>
</row>
<row>
<entry><option>2</option></entry>
<entry>misuse of shell builtins, according to Bash documentation</entry>
<entry></entry>
<entry>Seldom seen, usually defaults to exit code 1</entry>
</row>
<row>
<entry><option>126</option></entry>
<entry>command invoked cannot execute</entry>
<entry></entry>
<entry>permission problem or command is not an executable</entry>
</row>
<row>
<entry><option>127</option></entry>
<entry><quote>command not found</quote></entry>
<entry></entry>
<entry>possible problem with <varname>$PATH</varname> or a typo</entry>
</row>
<row>
<entry><option>128</option></entry>
<entry>invalid argument to <link linkend="exitcommandref">exit</link></entry>
<entry>exit 3.14159</entry>
<entry><command>exit</command> takes only integer args in the
range 0 - 255</entry>
</row>
<row>
<entry><option>128+n</option></entry>
<entry>fatal error signal <quote>n</quote></entry>
2002-06-03 14:35:48 +00:00
<entry><command>kill -9</command> <varname>$PPID</varname> of script</entry>
2001-07-10 14:25:50 +00:00
<entry><userinput>$?</userinput> returns 137 (128 + 9)</entry>
</row>
<row>
<entry><option>130</option></entry>
<entry>script terminated by Control-C</entry>
<entry></entry>
<entry>Control-C is fatal error signal 2, (130 = 128 + 2,
see above)</entry>
</row>
<row>
2002-04-01 16:04:17 +00:00
<entry><option>255*</option></entry>
2001-07-10 14:25:50 +00:00
<entry>exit status out of range</entry>
<entry>exit -1</entry>
<entry><command>exit</command> takes only integer args in the
range 0 - 255</entry>
</row>
</tbody>
</tgroup>
</table>
2002-04-01 16:04:17 +00:00
<para>According to the table, exit codes 1 - 2, 126 - 165, and 255
<footnote><para>Out of range exit values can result in
unpredictable exit codes. For example,
<command>exit 3809</command> gives an exit code of
<errorcode>225</errorcode>.</para></footnote>
have special meanings, and should therefore be avoided as
user-specified exit parameters. Ending a script with <command>exit
127</command> would certainly cause confusion when troubleshooting
(is the error a <quote>command not found</quote> or a
user-defined one?). However, many scripts use an <command>exit
1</command> as a general bailout upon error. Since exit code
<returnvalue>1</returnvalue> signifies so many possible errors,
this might not add any additional ambiguity, but, on the other
hand, it probably would not be very informative either.</para>
2001-07-10 14:25:50 +00:00
<para>There has been an attempt to systematize exit status numbers
2002-06-03 14:35:48 +00:00
(see <filename class="headerfile">/usr/include/sysexits.h</filename>),
but this is intended for C and C++ programmers. A similar standard
for scripting might be appropriate. The author of this document
proposes restricting user-defined exit codes to the range 64 -
113 (in addition to <returnvalue>0</returnvalue>, for success), to
conform with the C/C++ standard. This would allot 50 valid codes,
and make troubleshooting scripts more straightforward.</para>
2001-07-10 14:25:50 +00:00
<para>All user-defined exit codes in the accompanying examples
to this document now conform to this standard, except
where overriding circumstances exist, as in <xref
linkend="tmdin">.</para>
<note><para>Issuing a <link linkend="xstatvarref">$?</link> from
the command line after a shell script exits gives results
consistent with the table above only from the Bash or
<emphasis>sh</emphasis> prompt. Running the C-shell or
<emphasis>tcsh</emphasis> may give different values in some
cases.</para></note>
</appendix>
<!-- End Reserved Exit Code appendix -->
<appendix id="ioredirintro">
<title>A Detailed Introduction to I/O and I/O Redirection</title>
<para><emphasis>written by Stephane Chazelas, and revised by the
document author</emphasis></para>
<para>A command expects the first three <link linkend="fdref">file
descriptors</link> to be available. The first, <emphasis>fd
0</emphasis> (standard input, <filename>stdin</filename>),
is for reading. The other two (<emphasis>fd 1</emphasis>,
<filename>stdout</filename> and <emphasis>fd 2</emphasis>,
<filename>stderr</filename>) are for writing.</para>
<para>There is a <filename>stdin</filename>, <filename>stdout</filename>,
and a <filename>stderr</filename> associated with each command.
<userinput>ls 2&gt;&1</userinput> means temporarily connecting the
<filename>stderr</filename> of the <command>ls</command> command to the
same <quote>resource</quote> as the shell's
<filename>stdout</filename>.</para>
<para>By convention, a command reads its input from fd 0
(<filename>stdin</filename>), prints normal output to fd
1 (<filename>stdout</filename>), and error ouput to fd 2
(<filename>stderr</filename>). If one of those three fd's is
not open, you may encounter problems:</para>
<screen>
<prompt>bash$ </prompt><userinput>cat /etc/passwd >&-</userinput>
<computeroutput>cat: standard output: Bad file descriptor</computeroutput>
</screen>
<para>For example, when <command>xterm</command> runs, it first
initializes itself. Before running the user's shell,
<command>xterm</command> opens the terminal device
(/dev/pts/&lt;n&gt; or something similar) three times.</para>
<para>At this point, Bash inherits these three file descriptors,
and each command (child process) run by Bash inherits
them in turn, except when you redirect the command. <link
linkend="ioredirref">Redirection</link> means reassigning
one of the file descriptors to another file (or a pipe, or
2002-06-17 13:17:07 +00:00
anything permissible). File descriptors may be reassigned
2001-07-10 14:25:50 +00:00
locally (for a command, a command group, a subshell, a <link
linkend="redirref">while or if or case or for loop</link>...),
or globally, for the remainder of the shell (using <link
linkend="execref">exec</link>).</para>
<para><userinput>ls &gt; /dev/null</userinput> means
running <command>ls</command> with its fd 1 connected to
<filename>/dev/null</filename>.</para>
<para>
<screen>
<prompt>bash$ </prompt><userinput>lsof -a -p $$ -d0,1,2</userinput>
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
bash 363 bozo 0u CHR 136,1 3 /dev/pts/1
bash 363 bozo 1u CHR 136,1 3 /dev/pts/1
bash 363 bozo 2u CHR 136,1 3 /dev/pts/1</computeroutput>
<prompt>bash$ </prompt><userinput>exec 2&gt; /dev/null</userinput>
<prompt>bash$ </prompt><userinput>lsof -a -p $$ -d0,1,2</userinput>
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
bash 371 bozo 0u CHR 136,1 3 /dev/pts/1
bash 371 bozo 1u CHR 136,1 3 /dev/pts/1
bash 371 bozo 2w CHR 1,3 120 /dev/null</computeroutput>
<prompt>bash$ </prompt><userinput>bash -c 'lsof -a -p $$ -d0,1,2' | cat</userinput>
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
lsof 379 root 0u CHR 136,1 3 /dev/pts/1
lsof 379 root 1w FIFO 0,0 7118 pipe
lsof 379 root 2u CHR 136,1 3 /dev/pts/1</computeroutput>
<prompt>bash$ </prompt><userinput>echo "$(bash -c 'lsof -a -p $$ -d0,1,2' 2&gt;&1)"</userinput>
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
lsof 426 root 0u CHR 136,1 3 /dev/pts/1
lsof 426 root 1w FIFO 0,0 7520 pipe
lsof 426 root 2w FIFO 0,0 7520 pipe</computeroutput>
</screen>
</para>
<para>This works for different types of redirection.</para>
2001-10-15 14:21:41 +00:00
<para><userinput>Exercise:</userinput> Analyze the following script.
2001-07-10 14:25:50 +00:00
<programlisting>#! /usr/bin/env bash
mkfifo /tmp/fifo1 /tmp/fifo2
while read a; do echo "FIFO1: $a"; done < /tmp/fifo1 &
exec 7> /tmp/fifo1
exec 8> >(while read a; do echo "FD8: $a, to fd7"; done >&7)
exec 3>&1
(
(
(
while read a; do echo "FIFO2: $a"; done < /tmp/fifo2 | tee /dev/stderr | tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 >&7 &
exec 3> /tmp/fifo2
echo 1st, to stdout
sleep 1
echo 2nd, to stderr >&2
sleep 1
echo 3rd, to fd 3 >&3
sleep 1
echo 4th, to fd 4 >&4
sleep 1
echo 5th, to fd 5 >&5
sleep 1
echo 6th, through a pipe | sed 's/.*/PIPE: &, to fd 5/' >&5
sleep 1
echo 7th, to fd 6 >&6
sleep 1
echo 8th, to fd 7 >&7
sleep 1
echo 9th, to fd 8 >&8
) 4>&1 >&3 3>&- | while read a; do echo "FD4: $a"; done 1>&3 5>&- 6>&-
) 5>&1 >&3 | while read a; do echo "FD5: $a"; done 1>&3 6>&-
) 6>&1 >&3 | while read a; do echo "FD6: $a"; done 3>&-
rm -f /tmp/fifo1 /tmp/fifo2
# For each command and subshell, figure out which fd points to what.
exit 0</programlisting>
</para>
</appendix>
<!-- A Detailed Introduction to I/O and I/O Redirection -->
<appendix id="localization">
<title>Localization</title>
<para>Localization is an undocumented Bash feature.</para>
<para>A localized shell script echoes its text output in the
language defined as the system's locale. A Linux user in Berlin,
Germany, would get script output in German, whereas his cousin
in Berlin, Maryland, would get output from the same script in
English.</para>
<para>To create a localized script, use the following template to
write all messages to the user (error messages, prompts,
etc.).</para>
<para>
<programlisting>#!/bin/bash
# localized.sh
E_CDERROR=65
error()
{
printf "$@" >&2
exit $E_CDERROR
}
cd $var || error $"Can't cd to %s." "$var"
read -p $"Enter the value: " var
# ...</programlisting>
</para>
<para>
<screen><prompt>bash$ </prompt><userinput>bash -D localized.sh</userinput>
<computeroutput>"Can't cd to %s."
"Enter the value: "</computeroutput></screen>
This lists all the localized text. (The <option>-D</option>
option lists double-quoted strings prefixed by a <token>$</token>,
without executing the script.)</para>
<para>
<screen><prompt>bash$ </prompt><userinput>bash --dump-po-strings localized.sh</userinput>
<computeroutput>#: a:6
msgid "Can't cd to %s."
msgstr ""
#: a:7
msgid "Enter the value: "
msgstr ""</computeroutput></screen>
The <option>--dump-po-strings</option> option to Bash
resembles the <option>-D</option> option, but uses <link
linkend="gettextref">gettext</link> <quote>po</quote> format.
</para>
<para>Now, build a <filename>language.po</filename>
file for each language that the script will be translated
into, specifying the <replaceable>msgstr</replaceable>. As an
example:</para>
<para>fr.po:
<programlisting>#: a:6
msgid "Can't cd to %s."
msgstr "Impossible de se positionner dans le r<>pertoire %s."
#: a:7
msgid "Enter the value: "
msgstr "Entrez la valeur : "</programlisting>
</para>
<para>Then, run <command>msgfmt</command>.</para>
<para><userinput>msgfmt -o localized.sh.mo fr.po</userinput></para>
<para>Place the resulting <filename>localized.sh.mo</filename> file in the
<filename class="directory">/usr/local/share/locale/fr/LC_MESSAGES</filename>
directory, and at the beginning of the script, insert the lines:
<programlisting>TEXTDOMAINDIR=/usr/local/share/locale
TEXTDOMAIN=localized.sh</programlisting>
</para>
<para>If a user on a French system runs the script, she will get
French messages.</para>
<note>
<para>With older versions of Bash or other shells, localization requires
<link linkend="gettextref">gettext</link>, using the
<option>-s</option> option. In this case, the script becomes:</para>
<para><anchor id="gettextexample">
<programlisting>#!/bin/bash
# localized.sh
E_CDERROR=65
error() {
local format=$1
shift
printf "$(gettext -s "$format")" "$@" >&2
exit $E_CDERROR
}
cd $var || error "Can't cd to %s." "$var"
read -p "$(gettext -s "Enter the value: ")" var
# ...</programlisting>
</para>
</note>
<para>The <varname>TEXTDOMAIN</varname> and
<varname>TEXTDOMAINDIR</varname> variables need to be exported
to the environment.</para>
<para>---</para>
<para>This appendix written by Stephane Chazelas.</para>
</appendix>
<!-- Localization -->
2002-01-07 15:24:19 +00:00
<appendix id="histcommands">
<title>History Commands</title>
<para>The Bash shell provides command-line tools for editing and
manipulating a user's <emphasis>command history</emphasis>. This
is primarily a convenience, a means of saving keystrokes.</para>
<para>Bash history commands:
<orderedlist>
<listitem><para><command>history</command></para></listitem>
<listitem><para><command>fc</command></para></listitem>
</orderedlist>
</para>
<para>
<screen><prompt>bash$ </prompt><userinput>history</userinput>
<computeroutput> 1 mount /mnt/cdrom
2 cd /mnt/cdrom
3 ls
...</computeroutput>
</screen>
</para>
<para>Internal variables associated with Bash history commands:
<orderedlist>
<listitem><para>$HISTCMD</para></listitem>
<listitem><para>$HISTCONTROL</para></listitem>
<listitem><para>$HISTIGNORE</para></listitem>
<listitem><para>$HISTFILE</para></listitem>
<listitem><para>$HISTFILESIZE</para></listitem>
<listitem><para>$HISTSIZE</para></listitem>
<listitem><para>!!</para></listitem>
<listitem><para>!$</para></listitem>
<listitem><para>!#</para></listitem>
<listitem><para>!N</para></listitem>
<listitem><para>!-N</para></listitem>
<listitem><para>!STRING</para></listitem>
<listitem><para>!?STRING?</para></listitem>
<listitem><para>^STRING^string^</para></listitem>
</orderedlist>
</para>
<para>Unfortunately, the Bash history tools find no use in scripting.
<programlisting>#!/bin/bash
# history.sh
# Attempt to use 'history' command in a script.
history
# Script produces no output.
# History commands do not work within a script.</programlisting>
</para>
<para>
<screen><prompt>bash$ </prompt><userinput>./history.sh</userinput>
<computeroutput>(no output)</computeroutput>
</screen>
</para>
</appendix>
<!-- History Commands -->
2001-07-10 14:25:50 +00:00
<appendix id="sample-bashrc">
<title>A Sample <filename>.bashrc</filename> File</title>
<para>The <filename>~/.bashrc</filename> file determines the
behavior of interactive shells. A good look at this file can
lead to a better understanding of Bash.</para>
2001-10-15 14:21:41 +00:00
<para><ulink url="mailto:emmanuel.rouat@wanadoo.fr">Emmanuel
Rouat</ulink> contributed the following very elaborate
<filename>.bashrc</filename> file, written for a Linux system.
He welcomes reader feedback on it.</para>
<para>Study the file carefully, and feel free to reuse code
snippets and functions from it in your own
<filename>.bashrc</filename> file or even in your scripts.</para>
2001-07-10 14:25:50 +00:00
<example id="bashrc">
<title>Sample <filename>.bashrc</filename> file</title>
<programlisting>&bashrc;</programlisting>
</example>
</appendix>
<!-- End Sample .bashrc File appendix -->
<appendix id="dosbatch">
<title>Converting DOS Batch Files to Shell Scripts</title>
<para>Quite a number of programmers learned scripting on a PC running
DOS. Even the crippled DOS batch file language allowed writing some
fairly powerful scripts and applications, though they often required
extensive kludges and workarounds. Occasionally, the need still
arises to convert an old DOS batch file to a UNIX shell script. This
is generally not difficult, as DOS batch file operators are only a
2002-04-01 16:04:17 +00:00
limited subset of the equivalent shell scripting ones.</para>
2001-07-10 14:25:50 +00:00
<table>
<title>Batch file keywords / variables / operators, and their shell equivalents</title>
<tgroup cols="3">
<thead>
<row>
<entry>Batch File Operator</entry>
<entry>Shell Script Equivalent</entry>
<entry>Meaning</entry>
</row>
</thead>
<tbody>
<row>
<entry><option>%</option></entry>
<entry>$</entry>
<entry>command-line parameter prefix</entry>
</row>
<row>
<entry><option>/</option></entry>
<entry>-</entry>
<entry>command option flag</entry>
</row>
<row>
<entry><option>\</option></entry>
<entry>/</entry>
<entry>directory path separator</entry>
</row>
<row>
<entry><option>==</option></entry>
<entry>=</entry>
<entry>(equal-to) string comparison test</entry>
</row>
<row>
<entry><option>!==!</option></entry>
<entry>!=</entry>
<entry>(not equal-to) string comparison test</entry>
</row>
<row>
<entry><option>|</option></entry>
<entry>|</entry>
<entry>pipe</entry>
</row>
<row>
<entry><option>@</option></entry>
<entry>set <option>+v</option></entry>
<entry>do not echo current command</entry>
</row>
<row>
<entry><option>*</option></entry>
<entry>*</entry>
<entry>filename <quote>wild card</quote></entry>
</row>
<row>
<entry><option>&gt;</option></entry>
<entry>&gt;</entry>
<entry>file redirection (overwrite)</entry>
</row>
<row>
<entry><option>&gt;&gt;</option></entry>
<entry>&gt;&gt;</entry>
<entry>file redirection (append)</entry>
</row>
<row>
<entry><option>&lt;</option></entry>
<entry>&lt;</entry>
<entry>redirect <filename>stdin</filename></entry>
</row>
<row>
<entry><option>%VAR%</option></entry>
<entry>$VAR</entry>
<entry>environmental variable</entry>
</row>
<row>
<entry><option>REM</option></entry>
<entry>#</entry>
<entry>comment</entry>
</row>
<row>
<entry><option>NOT</option></entry>
<entry>!</entry>
<entry>negate following test</entry>
</row>
<row>
<entry><option>NUL</option></entry>
<entry><filename>/dev/null</filename></entry>
<entry><quote>black hole</quote> for burying command output</entry>
</row>
<row>
<entry><option>ECHO</option></entry>
<entry>echo</entry>
<entry>echo (many more option in Bash)</entry>
</row>
2001-09-04 13:27:31 +00:00
<row>
<entry><option>ECHO.</option></entry>
<entry>echo</entry>
<entry>echo blank line</entry>
</row>
2001-07-10 14:25:50 +00:00
<row>
<entry><option>ECHO OFF</option></entry>
<entry>set <option>+v</option></entry>
<entry>do not echo command(s) following</entry>
</row>
<row>
<entry><option>FOR %%VAR IN (LIST) DO</option></entry>
<entry>for var in [list]; do</entry>
<entry><quote>for</quote> loop</entry>
</row>
<row>
<entry><option>:LABEL</option></entry>
<entry>none (unnecessary)</entry>
<entry>label</entry>
</row>
<row>
<entry><option>GOTO</option></entry>
<entry>none (use a function)</entry>
<entry>jump to another location in the script</entry>
</row>
<row>
<entry><option>PAUSE</option></entry>
<entry>sleep</entry>
<entry>pause or wait an interval</entry>
</row>
<row>
<entry><option>CHOICE</option></entry>
<entry>case or select</entry>
<entry>menu choice</entry>
</row>
<row>
<entry><option>IF</option></entry>
<entry>if</entry>
<entry>if-test</entry>
</row>
<row>
<entry><option>IF EXIST <replaceable>FILENAME</replaceable></option></entry>
<entry>if [ -e filename ]</entry>
<entry>test if file exists</entry>
</row>
<row>
<entry><option>IF !%N==!</option></entry>
<entry>if [ -z "$N" ]</entry>
<entry>if replaceable parameter <quote>N</quote> not present</entry>
</row>
<row>
<entry><option>CALL</option></entry>
<entry>source or . (dot operator)</entry>
<entry><quote>include</quote> another script</entry>
</row>
<row>
<entry><option>COMMAND /C</option></entry>
<entry>source or . (dot operator)</entry>
<entry><quote>include</quote> another script (same as
2001-09-04 13:27:31 +00:00
CALL)</entry>
2001-07-10 14:25:50 +00:00
</row>
<row>
<entry><option>SET</option></entry>
<entry>export</entry>
<entry>set an environmental variable</entry>
</row>
<row>
<entry><option>SHIFT</option></entry>
<entry>shift</entry>
<entry>left shift command-line argument list</entry>
</row>
<row>
<entry><option>SGN</option></entry>
<entry>-lt or -gt</entry>
<entry>sign (of integer)</entry>
</row>
<row>
<entry><option>ERRORLEVEL</option></entry>
<entry>$?</entry>
<entry>exit status</entry>
</row>
<row>
<entry><option>CON</option></entry>
<entry><filename>stdin</filename></entry>
<entry><quote>console</quote> (<filename>stdin</filename>)</entry>
</row>
<row>
<entry><option>PRN</option></entry>
<entry><filename>/dev/lp0</filename></entry>
<entry>(generic) printer device</entry>
</row>
<row>
2001-09-04 13:27:31 +00:00
<entry><option>LPT1</option></entry>
2001-07-10 14:25:50 +00:00
<entry><filename>/dev/lp0</filename></entry>
<entry>first printer device</entry>
</row>
<row>
<entry><option>COM1</option></entry>
<entry><filename>/dev/ttyS0</filename></entry>
<entry>first serial port</entry>
</row>
</tbody>
</tgroup>
</table>
<para>Batch files usually contain DOS commands. These must be
translated into their UNIX equivalents in order to convert a
batch file into a shell script.</para>
<table>
<title>DOS Commands and Their UNIX Equivalents</title>
<tgroup cols="3">
<thead>
<row>
<entry>DOS Command</entry>
<entry>UNIX Equivalent</entry>
<entry>Effect</entry>
</row>
</thead>
<tbody>
<row>
<entry><option>ASSIGN</option></entry>
<entry>ln</entry>
<entry>link file or directory</entry>
</row>
<row>
<entry><option>ATTRIB</option></entry>
<entry>chmod</entry>
<entry>change file permissions</entry>
</row>
<row>
<entry><option>CD</option></entry>
<entry>cd</entry>
<entry>change directory</entry>
</row>
<row>
<entry><option>CHDIR</option></entry>
<entry>cd</entry>
<entry>change directory</entry>
</row>
<row>
<entry><option>CLS</option></entry>
<entry>clear</entry>
<entry>clear screen</entry>
</row>
<row>
<entry><option>COMP</option></entry>
2001-09-04 13:27:31 +00:00
<entry>diff, comm, cmp</entry>
2001-07-10 14:25:50 +00:00
<entry>file compare</entry>
</row>
<row>
<entry><option>COPY</option></entry>
<entry>cp</entry>
<entry>file copy</entry>
</row>
<row>
<entry><option>Ctl-C</option></entry>
<entry>Ctl-C</entry>
<entry>break (signal)</entry>
</row>
<row>
<entry><option>Ctl-Z</option></entry>
<entry>Ctl-D</entry>
<entry>EOF (end-of-file)</entry>
</row>
<row>
<entry><option>DEL</option></entry>
<entry>rm</entry>
<entry>delete file(s)</entry>
</row>
2001-09-04 13:27:31 +00:00
<row>
<entry><option>DELTREE</option></entry>
<entry>rm -rf</entry>
<entry>delete directory recursively</entry>
</row>
2001-07-10 14:25:50 +00:00
<row>
<entry><option>DIR</option></entry>
<entry>ls -l</entry>
<entry>directory listing</entry>
</row>
2001-09-04 13:27:31 +00:00
<row>
<entry><option>ERASE</option></entry>
<entry>rm</entry>
<entry>delete file(s)</entry>
</row>
2001-07-10 14:25:50 +00:00
<row>
<entry><option>EXIT</option></entry>
<entry>exit</entry>
<entry>exit current process</entry>
</row>
2001-09-04 13:27:31 +00:00
<row>
<entry><option>FC</option></entry>
<entry>comm, cmp</entry>
<entry>file compare</entry>
</row>
2001-07-10 14:25:50 +00:00
<row>
<entry><option>FIND</option></entry>
<entry>grep</entry>
<entry>find strings in files</entry>
</row>
<row>
<entry><option>MD</option></entry>
<entry>mkdir</entry>
<entry>make directory</entry>
</row>
<row>
<entry><option>MKDIR</option></entry>
<entry>mkdir</entry>
<entry>make directory</entry>
</row>
<row>
<entry><option>MORE</option></entry>
<entry>more</entry>
<entry>text file paging filter</entry>
</row>
<row>
<entry><option>MOVE</option></entry>
<entry>mv</entry>
<entry>move</entry>
</row>
<row>
<entry><option>PATH</option></entry>
<entry>$PATH</entry>
<entry>path to executables</entry>
</row>
<row>
<entry><option>REN</option></entry>
<entry>mv</entry>
<entry>rename (move)</entry>
</row>
<row>
<entry><option>RENAME</option></entry>
<entry>mv</entry>
<entry>rename (move)</entry>
</row>
<row>
<entry><option>RD</option></entry>
<entry>rmdir</entry>
<entry>remove directory</entry>
</row>
<row>
<entry><option>RMDIR</option></entry>
<entry>rmdir</entry>
<entry>remove directory</entry>
</row>
<row>
<entry><option>SORT</option></entry>
<entry>sort</entry>
<entry>sort file</entry>
</row>
<row>
<entry><option>TIME</option></entry>
<entry>date</entry>
<entry>display system time</entry>
</row>
<row>
<entry><option>TYPE</option></entry>
<entry>cat</entry>
<entry>output file to <filename>stdout</filename></entry>
</row>
<row>
<entry><option>XCOPY</option></entry>
<entry>cp</entry>
<entry>(extended) file copy</entry>
</row>
</tbody>
</tgroup>
</table>
<note>
2001-09-04 13:27:31 +00:00
<para>Virtually all UNIX and shell operators and commands have
many more options and enhancements than their DOS and batch file
equivalents. Many DOS batch files rely on auxiliary utilities,
such as <command>ask.com</command>, a crippled counterpart to
<link linkend="readref">read</link>.</para>
2001-07-10 14:25:50 +00:00
<para>DOS supports a very limited and incompatible subset of
filename <link linkend="globbingref">wildcard expansion</link>,
recognizing only the <token>*</token> and <token>?</token>
characters.</para>
</note>
2001-09-04 13:27:31 +00:00
<para>Converting a DOS batch file into a shell script is generally
straightforward, and the result ofttimes reads better than the
2001-07-10 14:25:50 +00:00
original.</para>
<example id="VIEWDAT">
<title>VIEWDATA.BAT: DOS Batch File</title>
<programlisting>&VIEWDAT;</programlisting>
</example>
<para>The script conversion is somewhat of an improvement.</para>
<example id="viewdata">
<title>viewdata.sh: Shell Script Conversion of VIEWDATA.BAT</title>
<programlisting>&viewdata;</programlisting>
</example>
<para>Ted Davis' <ulink url="http://www.maem.umr.edu/~batch/">Shell
Scripts on the PC</ulink> site has a set of comprehensive
tutorials on the old-fashioned art of batch file
programming. Certain of his ingenious techniques could conceivably
have relevance for shell scripts.</para>
</appendix>
<!-- End DOS Batch File Conversion appendix -->
2001-10-15 14:21:41 +00:00
<appendix id="exercises">
<title>Exercises</title>
2002-04-01 16:04:17 +00:00
<sect1 id="scriptanalysis">
<title>Analyzing Scripts</title>
<para>Examine the following script. Run it, then explain what it
does. Annotate the script, then rewrite it in a more compact
and elegant manner.</para>
<para>
<programlisting>#!/bin/bash
MAX=10000
for((nr=1; nr<$MAX; nr++))
do
let "t1 = nr % 5"
if [ "$t1" -ne 3 ]
then
continue
fi
let "t2 = nr % 7"
if [ "$t2" -ne 4 ]
then
continue
fi
let "t3 = nr % 9"
if [ "$t3" -ne 5 ]
then
continue
fi
break # What heppens when you comment out this line? Why?
done
echo "Number = $nr"
exit 0</programlisting>
</para>
<para>---</para>
<para>A reader sent in the following code snippet.
<programlisting>while read LINE
do
echo $LINE
done < `tail -f /var/log/messages`</programlisting>
He wished to write a script tracking changes to the system log
file, <filename>/var/log/messages</filename>. Unfortunately,
the above code block hangs and does nothing
useful. Why? Fix this so it does work (hint:
rather than <link linkend="redirref">redirecting the
<filename>stdin</filename> of the loop</link>, try a <link
linkend="piperef">pipe</link>).</para>
<para>---</para>
<para>Analyze <xref linkend="lifeslow">, and reorganize it in a
simplified and more logical style. See how many of its variables
can be eliminated and try to optimize the script to speed up
its execution time.</para>
<para>Alter the script so that it accepts any ordinary ASCII
text file as input for its initial <quote>generation</quote>. The
script will read the first <varname>$ROW*$COL</varname>
characters, and set the occurrences of vowels as
<quote>living</quote> cells. Hint: be sure to translate the
spaces in the input file to underscore characters.</para>
</sect1>
<!-- End Analyzing Scripts section -->
<sect1 id="writingscripts">
<title>Writing Scripts</title>
<para><anchor id="writingscripts1"></para>
2001-10-15 14:21:41 +00:00
<para>Write a script to carry out each of the following tasks.</para>
<variablelist id="exeasy">
<title><anchor id="exeasy1">Easy</title>
<varlistentry>
<term><command>Home Directory Listing</command></term>
<listitem>
<para>Perform a recursive directory listing on the user's home
directory and save the information to a file. Compress
the file, have the script prompt the user to insert
a floppy, then press <keycap>ENTER</keycap>. Finally,
save the file to the floppy.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Converting <link linkend="forloopref1">for</link>
loops to <link linkend="whileloopref">while</link> and <link
linkend="untilloopref">until</link> loops</command></term>
<listitem>
<para>Convert the <emphasis>for loops</emphasis> in <xref
linkend="ex22"> to <emphasis>while
loops</emphasis>. Hint: store the data in an <link
linkend="arrayref">array</link> and step through the array
elements.</para>
<para>Having already done the <quote>heavy lifting</quote>,
now convert the loops in the example to <emphasis> until
loops</emphasis>.</para>
</listitem>
</varlistentry>
2002-04-01 16:04:17 +00:00
<varlistentry>
<term><command>Changing the line spacing of a text file</command></term>
<listitem>
<para>Write a script that reads each line of a target file, then
writes the line back to <filename>stdout</filename>, but with
an extra blank line following. This has the effect of
<emphasis>double-spacing</emphasis> the file.</para>
<para>Include all necessary code to check whether the script
gets the necessary command line argument (a filename),
and whether the specified file exists.</para>
<para>When the script runs correctly, modify it to
<emphasis>triple-space</emphasis> the target file.</para>
<para>Finally, write a script to remove all blank lines from
the target file, <emphasis>single-spacing</emphasis> it.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Backwards Listing</command></term>
<listitem>
<para>Write a script that echoes itself to
<filename>stdout</filename>, but
<emphasis>backwards</emphasis>.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
2002-06-17 13:17:07 +00:00
<term><command>Automatically Decompressing Files</command></term>
2001-10-15 14:21:41 +00:00
<listitem>
2002-06-17 13:17:07 +00:00
<para>Given a list of filenames as input, this script
queries each target file (parsing the output of the
<link linkend="fileref">file</link> command) for
the type of compression used on it. Then the script
automatically invokes the appropriate decompression command
(<command>gunzip</command>, <command>bunzip2</command>,
<command>unzip</command>, <command>uncompress</command>,
or whatever). If a target file is not compressed, the
script emits a warning message, but takes no other action
on that particular file.</para>
2001-10-15 14:21:41 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><command>Unique System ID</command></term>
<listitem>
<para>Generate a <quote>unique</quote> 6-digit hexadecimal
identifier for your computer. Do <emphasis>not</emphasis>
use the flawed <link linkend="hostidref">hostid</link>
command. Hint: <command><link
linkend="md5sumref">md5sum</link>
<filename>/etc/passwd</filename></command>, then select
the first 6 digits of output.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Backup</command></term>
<listitem>
<para>Archive as a <quote>tarball</quote>
(<filename>*.tar.gz</filename> file) all the files
in your home directory tree
(<filename>/home/your-name</filename>) that have
been modified in the last 24 hours. Hint: use <link
linkend="findref">find</link>.</para>
</listitem>
</varlistentry>
<varlistentry>
2002-06-17 13:17:07 +00:00
<term><command>Primes</command></term>
2001-10-15 14:21:41 +00:00
<listitem>
2002-06-17 13:17:07 +00:00
<para>Print (to stdout) all prime numbers between 60000 and
63000. The output should be nicely formatted in columns
(hint: use <link linkend="printfref">printf</link>).</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Lottery Numbers</command></term>
<listitem>
<para>One type of lottery involves picking five
different numbers, in the range of 1 - 50. Write a
script that generates five pseudorandom numbers in this
range, <emphasis>with no duplicates</emphasis>. The
script will give the option of echoing the numbers to
<filename>stdout</filename> or saving them to a file,
along with the date and time the particular number set
was generated.</para>
2001-10-15 14:21:41 +00:00
</listitem>
</varlistentry>
</variablelist>
2002-06-17 13:17:07 +00:00
2001-10-15 14:21:41 +00:00
<variablelist id="exmedium">
2002-06-17 13:17:07 +00:00
<title><anchor id="exmedium1">Intermediate</title>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>Managing Disk Space</command></term>
<listitem>
<para>List, one at a time, all files larger than 100K in
the <filename class="directory">/home/username</filename>
directory tree. Give the user the option to delete or
compress the file, then proceed to show the next one. Write
to a logfile the names of all deleted files and the
deletion times.</para>
</listitem>
</varlistentry>
2002-06-17 13:17:07 +00:00
<varlistentry>
<term><command>Safe Delete</command></term>
<listitem>
<para>Write, as a script, a <quote>safe</quote> delete
command, <filename>srm.sh</filename>. Filenames passed
as command-line arguments to this script are not deleted,
but instead <link linkend="gzipref">gzipped</link> if not
already compressed (use <link linkend="fileref">file</link>
to check), then moved to a <filename
class="directory">/home/username/trash</filename>
directory. At invocation, the script checks the
<quote>trash</quote> directory for files older than 48
hours and deletes them.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>Making Change</command></term>
<listitem>
<para>What is the most efficient way to make change for $1.68,
using only coins in common circulations (up to 25c)? It's
6 quarters, 1 dime, a nickel, and three cents.</para>
<para>Given any arbitrary command line input in dollars and
cents ($*.??), calculate the change, using the minimum
number of coins. If your home country is not the United
States, you may use your local currency units instead. The
script will need to parse the command line input, then
change it to multiples of the smallest monetary unit (cents
or whatever). Hint: look at <xref linkend="ex61">.</para>
</listitem>
</varlistentry>
2002-04-01 16:04:17 +00:00
<varlistentry>
<term><command>Quadratic Equations</command></term>
<listitem>
<para>Solve a <quote>quadratic</quote> equation of the form
<emphasis>Ax^2 + Bx + C = 0</emphasis>. Have a script take
as arguments the coefficients, <userinput>A</userinput>,
<userinput>B</userinput>, and <userinput>C</userinput>,
and return the solutions to four decimal places.</para>
<para>Hint: pipe the coefficients to <link
linkend="bcref">bc</link>, using the well-known formula,
<emphasis>x = ( -B +/- sqrt( B^2 - 4AC ) ) / 2A</emphasis>.</para>
</listitem>
</varlistentry>
2002-06-03 14:35:48 +00:00
<varlistentry>
<term><command>Sum of Matching Numbers</command></term>
<listitem>
<para>Find the sum of all five-digit numbers (in the range
10000 - 99999) containing <emphasis>exactly two</emphasis>
out of the following set of digits: { 4, 5, 6 }. These may
repeat within the same number, and if so, they count once
for each occurrence.</para>
<para>Some examples of matching numbers are
42057, 74638, and 89515.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>Lucky Numbers</command></term>
<listitem>
<para>A "lucky number" is one whose individual digits add
up to 7, in successive additions. For example, 62431 is a
"lucky number" (6 + 2 + 4 + 3 + 1 = 16, 1 + 6 = 7). Find
all the "lucky numbers" between 1000 and 10000.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Alphabetizing a String</command></term>
<listitem>
<para>Alphabetize (in ASCII order) an arbitrary string
read from the command line.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Parsing</command></term>
<listitem>
<para>Parse <filename>/etc/passwd</filename>, and output
its contents in nice, easy-to-read tabular form.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Pretty-Printing a Data File</command></term>
<listitem>
<para>Certain database and spreadsheet packages use save-files
with <emphasis>comma-separated values</emphasis>
(CSVs). Other applications often need to parse these
files.</para>
<para>Given a data file with comma-separated fields,
of the form:
<programlisting>Jones,Bill,235 S. Williams St.,Denver,CO,80221,(303) 244-7989
Smith,Tom,404 Polk Ave.,Los Angeles,CA,90003,(213) 879-5612
...</programlisting>
Reformat the data and print it out to
<filename>stdout</filename> in labeled, evenly-spaced columns.</para>
</listitem>
</varlistentry>
2002-06-17 13:17:07 +00:00
<varlistentry>
<term><command>Passwords</command></term>
<listitem>
<para>Generate pseudorandom 8-character passwords, using
characters in the ranges [0-9], [A-Z], [a-z]. Each password
must contain at least two digits.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
</variablelist>
<variablelist id="exdifficult">
<title><anchor id="exdifficult1">Difficult</title>
<varlistentry>
<term><command>Logging File Accesses</command></term>
<listitem>
<para>Log all accesses to the files in <filename
class="directory">/etc</filename> during the course of
a single day. This information should include the filename,
user name, and access time. If any alterations to the
files take place, that should be flagged. Write this data
as neatly formatted records in a logfile.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Strip Comments</command></term>
<listitem>
<para>Strip all comments from a shell script whose name
is specified on the command line. Note that the <quote>#!
line</quote> must not be stripped out.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>HTML Conversion</command></term>
<listitem>
<para>Convert a given text file to HTML. This non-interactive
script automatically inserts all appropriate HTML tags into
a file specified as an argument.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Strip HTML Tags</command></term>
<listitem>
<para>Strip all HTML tags from a specified HTML file, then
reformat it into lines between 60 and 75 characters
in length. Reset paragraph and block spacing, as
appropriate, and convert HTML tables to their approximate
text equivalent.</para>
</listitem>
</varlistentry>
2002-04-01 16:04:17 +00:00
<varlistentry>
<term><command>XML Conversion</command></term>
<listitem>
2002-06-17 13:17:07 +00:00
<para>Convert an XML file to both HTML and text format.</para>
2002-04-01 16:04:17 +00:00
</listitem>
</varlistentry>
<varlistentry>
<term><command>Morse Code</command></term>
<listitem>
<para>Convert a text file to Morse code. Each character of the
text file will be represented as a corresponding Morse
code group of dots and dashes (underscores), separated by
whitespace from the next. For example, <quote>script</quote>
===&gt; <quote>... _._. ._. .. .__. _</quote>.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>Hex Dump</command></term>
<listitem>
<para>Do a hex(adecimal) dump on a binary file
specified as an argument. The output should be in neat
tabular fields, with the first field showing the address,
each of the next 8 fields a 4-byte hex number, and the final
field the ASCII equivalent of the previous 8 fields.</para>
</listitem>
</varlistentry>
2002-04-01 16:04:17 +00:00
<varlistentry>
<term><command>Emulating a Shift Register</command></term>
<listitem>
<para>Using <xref linkend="stackex"> as an inspiration,
write a script that emulates a 64-bit shift register as
an <link linkend="arrayref">array</link>. Implement
functions to <emphasis>load</emphasis> the register,
<emphasis>shift left</emphasis>, and <emphasis>shift
right</emphasis>. Finally, write a function that
interprets the register contents as eight 8-bit ASCII
characters.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
<varlistentry>
<term><command>Determinant</command></term>
<listitem>
<para>Solve a 4 x 4 determinant.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Hidden Words</command></term>
<listitem>
<para>Write a <quote>word-find</quote> puzzle generator,
a script that hides 10 input words in a 10 x 10 matrix
of random letters. The words may be hidden across, down,
or diagonally.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>Anagramming</command></term>
<listitem>
<para> Anagram 4-letter input. For example, the
anagrams of <emphasis>word</emphasis> are:
<emphasis>do or rod row word</emphasis>. You may use
<filename>/usr/share/dict/linux.words</filename> as the
reference list.</para>
</listitem>
</varlistentry>
2002-06-17 13:17:07 +00:00
<varlistentry>
<term><command>Fog Index</command></term>
<listitem>
<para>The <quote>fog index</quote> of a passage of text
estimates its reading difficulty, as a number corresponding
roughly to a school grade level. For example, a passage
with a fog index of 12 should be comprehensible to anyone
with 12 years of schooling.</para>
<para>The Gunning version of the fog index uses the following
algorithm.</para>
<orderedlist>
<listitem><para>Choose a section of the text at least
100 words in length.</para></listitem>
<listitem><para>Count the number of sentences (a portion of
a sentence truncated by the boundary of the text section
counts as one).</para></listitem>
<listitem>
<para>Find the average number of words per
sentence.</para>
<para>AVE_WDS_SEN = TOTAL_WORDS / SENTENCES</para>
</listitem>
<listitem>
<para>Count the number of <quote>difficult</quote>
words in the segment -- those containing at least
3 syllables. Divide this quantity by total words to
get the proportion of difficult words.</para>
<para>PRO_DIFF_WORDS = LONG_WORDS / TOTAL_WORDS</para>
</listitem>
<listitem>
<para>The Gunning fog index is the sum of the above two
quantities, multiplied by 0.4, then rounded to the
nearest integer.</para>
<para>G_FOG_INDEX = int ( 0.4 * ( AVE_WDS_SEN + PRO_DIFF_WORDS ) )</para>
</listitem>
</orderedlist>
<para>Step 4 is by far the most difficult portion of the
exercise. There exist various algorithms for estimating
the syllable count of a word. A rule-of-thumb formula
might consider the number of letters in a word and the
vowel-consonant mix.</para>
<para>A strict interpretation of the Gunning Fog index does
not count compound words and proper nouns as
<quote>difficult</quote> words, but this would enormously
complicate the script.</para>
</listitem>
</varlistentry>
2002-04-01 16:04:17 +00:00
<varlistentry>
<term><command>Playfair Cipher</command></term>
<listitem>
<para>Implement the Playfair (Wheatstone) Cipher in a
script.</para>
<para>The Playfair Cipher encrypts text by substitution
of each 2-letter <quote>digram</quote>
(grouping). Traditionally, one would use a 5 x 5 letter
scrambled alphabet code key square for the encryption
and decryption.</para>
<para>
<programlisting> C O D E S
A B F G H
I K L M N
P Q R T U
V W X Y Z
Each letter of the alphabet appears once, except "I" also represents
"J". The arbitrarily chosen key word, "CODES" comes first, then all the
rest of the alphabet, skipping letters already used.
To encrypt, separate the plaintext message into digrams (2-letter
groups). If a group has two identical letters, delete the second, and
form a new group. If there is a single letter left over at the end,
insert a "null" character, typically an "X".
THIS IS A TOP SECRET MESSAGE
TH IS IS AT OP SE CR ET ME SA GE
For each digram, there are three possibilities.
----------------------------------------------
1) Both letters will be on the same row of the key square
For each letter, substitute the one immediately to the right, in that
row. If necessary, wrap around left to the beginning of the row.
or
2) Both letters will be in the same column of the key square
For each letter, substitute the one immediately below it, in that
row. If necessary, wrap around to the top of the column.
or
3) Both letters will form the corners of a rectangle within the key
square. For each letter, substitute the one on the other corner the
rectangle which lies on the same row.
The "TH" digram falls under case #3.
G H
M N
T U (Rectangle with "T" and "H" at corners)
T --&gt; U
H --&gt; G
The "SE" digram falls under case #1.
C O D E S (Row containing "S" and "E")
S --&gt; C (wraps around left to beginning of row)
E --&gt; S
=========================================================================
To decrypt encrypted text, reverse the above procedure under cases #1
and #2 (move in opposite direction for substitution). Under case #3,
just take the remaining two corners of the rectangle.
Helen Fouche Gaines' classic work, "Elementary Cryptoanalysis" (1939), gives a
fairly detailed rundown on the Playfair Cipher and its solution methods.</programlisting>
</para>
<para>This script will have three main sections</para>
<orderedlist id="playfairexref" numeration="upperroman">
<listitem><para>Generating the <quote>key square</quote>,
based on a user-input keyword.</para></listitem>
<listitem><para>Encrypting a <quote>plaintext</quote>
message.</para></listitem>
<listitem><para>Decrypting encrypted
text.</para></listitem>
</orderedlist>
<para>The script will make extensive use of <link
linkend="arrayref">arrays</link> and <link
linkend="functionref">functions</link>.</para>
</listitem>
</varlistentry>
2001-10-15 14:21:41 +00:00
</variablelist>
2002-04-01 16:04:17 +00:00
<para>--</para>
2001-10-15 14:21:41 +00:00
<para>Please do not send the author your solutions to these
exercises. There are better ways to impress him with your
cleverness, such as submitting bugfixes and suggestions for
improving this book.</para>
2002-04-01 16:04:17 +00:00
</sect1>
<!-- End Writing Scripts section -->
2001-10-15 14:21:41 +00:00
</appendix>
<!-- End Exercises appendix -->
2001-07-10 14:25:50 +00:00
<appendix id="copyright">
<title>Copyright</title>
2002-04-01 16:04:17 +00:00
2001-07-10 14:25:50 +00:00
<para>The <quote>Advanced Bash-Scripting Guide</quote> is copyright,
2002-06-03 14:35:48 +00:00
(c) 2000, by Mendel Cooper. This document may only be
distributed subject to the terms and conditions set forth in
the Open Publication License (version 1.0 or later), <ulink url="
http://www.opencontent.org/openpub/">http://www.opencontent.org/openpub/</ulink>.
The following license options also apply.
</para>
<para><programlisting>A. Distribution of substantively modified versions of this document
is prohibited without the explicit permission of the copyright holder.
B. Distribution of the work or derivative of the work in any standard
(paper) book form is prohibited unless prior permission is obtained from
the copyright holder.</programlisting></para>
2002-04-01 16:04:17 +00:00
<para>Essentially, you may freely distribute this book in
<emphasis>unaltered</emphasis> electronic form. You must obtain
2002-06-03 14:35:48 +00:00
the author's permission to distribute a substantially modified
version or derivative work. The purpose of this restriction is to
2002-04-01 16:04:17 +00:00
preserve the artistic integrity of this document and to prevent
<quote>forking</quote>.</para>
2002-06-03 14:35:48 +00:00
<para>These are very liberal terms, and they should not hinder any
legitimate distribution or use of this book. The author especially
encourages the use of this book for instructional purposes.</para>
2002-04-01 16:04:17 +00:00
<para>The commercial print rights to this book are available. Please
2002-06-03 14:35:48 +00:00
contact <ulink url="mailto:thegrendel@theriver.com">the
2002-04-01 16:04:17 +00:00
author</ulink> if interested.</para>
2002-06-03 14:35:48 +00:00
<para>The author produced this book in a manner consistent with the
spirit of the <ulink url="http://www.tldp.org/manifesto.html">LDP
Manifesto</ulink>.</para>
2002-04-01 16:04:17 +00:00
<para>---</para>
2001-07-10 14:25:50 +00:00
<para>Hyun Jin Cha has done a <ulink
url="http://kldp.org/HOWTO/html/Adv-Bash-Scr-HOWTO/index.html">Korean
2002-04-01 16:04:17 +00:00
translation</ulink> of version 1.0.11 of this book. Spanish,
2002-06-17 13:17:07 +00:00
Portuguese, French, German, and Chinese translations are
underway. If you wish to translate this document into another
language, please feel free to do so, subject to the terms stated
above. The author wishes to be notified of such efforts.</para>
2002-04-01 16:04:17 +00:00
2001-07-10 14:25:50 +00:00
2001-09-04 13:27:31 +00:00
</appendix> <!-- End Copyright appendix -->
2001-07-10 14:25:50 +00:00
<!-- Uncomment line below to generate index. -->
2001-09-04 13:27:31 +00:00
<!--
&indice;
-->
2001-07-10 14:25:50 +00:00
</book>
2001-10-15 14:21:41 +00:00
2001-07-10 14:25:50 +00:00
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-indent-step:2
sgml-indent-data:t
End:
-->