mirror of https://github.com/tLDP/LDP
30286 lines
964 KiB
Plaintext
30286 lines
964 KiB
Plaintext
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
|
|
<!--
|
|
Uncomment line below to generate index.
|
|
-->
|
|
<!--
|
|
<!ENTITY indice SYSTEM "indice.sgml">
|
|
-->
|
|
<!ENTITY ex1 SYSTEM "ex1.sh">
|
|
<!ENTITY ex1a SYSTEM "ex1a.sh">
|
|
<!ENTITY ex2 SYSTEM "ex2.sh">
|
|
<!ENTITY ex3 SYSTEM "ex3.sh">
|
|
<!ENTITY ex4 SYSTEM "ex4.sh">
|
|
<!ENTITY ex5 SYSTEM "ex5.sh">
|
|
<!ENTITY ex6 SYSTEM "ex6.sh">
|
|
<!ENTITY ex7 SYSTEM "ex7.sh">
|
|
<!ENTITY ex8 SYSTEM "ex8.sh">
|
|
<!ENTITY ex9 SYSTEM "ex9.sh">
|
|
<!ENTITY ex10 SYSTEM "ex10.sh">
|
|
<!ENTITY ex11 SYSTEM "ex11.sh">
|
|
<!ENTITY ex12 SYSTEM "ex12.sh">
|
|
<!ENTITY ex13 SYSTEM "ex13.sh">
|
|
<!ENTITY ex14 SYSTEM "ex14.sh">
|
|
<!ENTITY ex15 SYSTEM "ex15.sh">
|
|
<!ENTITY ex16 SYSTEM "ex16.sh">
|
|
<!ENTITY ex17 SYSTEM "ex17.sh">
|
|
<!ENTITY ex18 SYSTEM "ex18.sh">
|
|
<!ENTITY ex19 SYSTEM "ex19.sh">
|
|
<!ENTITY ex20 SYSTEM "ex20.sh">
|
|
<!ENTITY ex21 SYSTEM "ex21.sh">
|
|
<!ENTITY ex22 SYSTEM "ex22.sh">
|
|
<!ENTITY ex22a SYSTEM "ex22a.sh">
|
|
<!ENTITY ex23 SYSTEM "ex23.sh">
|
|
<!ENTITY ex24 SYSTEM "ex24.sh">
|
|
<!ENTITY ex25 SYSTEM "ex25.sh">
|
|
<!ENTITY ex26 SYSTEM "ex26.sh">
|
|
<!ENTITY ex26a SYSTEM "ex26a.sh">
|
|
<!ENTITY ex27 SYSTEM "ex27.sh">
|
|
<!ENTITY ex28 SYSTEM "ex28.sh">
|
|
<!ENTITY ex29 SYSTEM "ex29.sh">
|
|
<!ENTITY ex30 SYSTEM "ex30.sh">
|
|
<!ENTITY ex30a SYSTEM "ex30a.sh">
|
|
<!ENTITY ex31 SYSTEM "ex31.sh">
|
|
<!ENTITY ex32 SYSTEM "ex32.sh">
|
|
<!ENTITY ex33 SYSTEM "ex33.sh">
|
|
<!ENTITY ex33a SYSTEM "ex33a.sh">
|
|
<!ENTITY ex34 SYSTEM "ex34.sh">
|
|
<!ENTITY ex35 SYSTEM "ex35.sh">
|
|
<!ENTITY ex36 SYSTEM "ex36.sh">
|
|
<!ENTITY ex37 SYSTEM "ex37.sh">
|
|
<!ENTITY ex38 SYSTEM "ex38.sh">
|
|
<!ENTITY ex38bis SYSTEM "data-file">
|
|
<!ENTITY ex39 SYSTEM "ex39.sh">
|
|
<!ENTITY ex40 SYSTEM "ex40.sh">
|
|
<!ENTITY ex41 SYSTEM "ex41.sh">
|
|
<!ENTITY ex42 SYSTEM "ex42.sh">
|
|
<!ENTITY ex43 SYSTEM "ex43.sh">
|
|
<!ENTITY ex44 SYSTEM "ex44.sh">
|
|
<!ENTITY ex45 SYSTEM "ex45.sh">
|
|
<!ENTITY ex45a SYSTEM "ex45a.sh">
|
|
<!ENTITY ex46 SYSTEM "ex46.sh">
|
|
<!ENTITY ex47 SYSTEM "ex47.sh">
|
|
<!ENTITY ex48 SYSTEM "ex48.sh">
|
|
<!ENTITY ex49 SYSTEM "ex49.sh">
|
|
<!ENTITY ex50 SYSTEM "ex50.sh">
|
|
<!ENTITY ex51 SYSTEM "ex51.sh">
|
|
<!ENTITY ex52 SYSTEM "ex52.sh">
|
|
<!ENTITY ex53 SYSTEM "ex53.sh">
|
|
<!ENTITY ex54 SYSTEM "ex54.sh">
|
|
<!ENTITY ex55 SYSTEM "ex55.sh">
|
|
<!ENTITY ex56 SYSTEM "ex56.sh">
|
|
<!ENTITY ex57 SYSTEM "ex57.sh">
|
|
<!ENTITY ex58 SYSTEM "ex58.sh">
|
|
<!ENTITY ex59 SYSTEM "ex59.sh">
|
|
<!ENTITY ex60 SYSTEM "ex60.sh">
|
|
<!ENTITY ex61 SYSTEM "ex61.sh">
|
|
<!ENTITY ex62 SYSTEM "ex62.sh">
|
|
<!ENTITY ex63 SYSTEM "ex63.sh">
|
|
<!ENTITY ex64 SYSTEM "ex64.sh">
|
|
<!ENTITY ex65 SYSTEM "ex65.sh">
|
|
<!ENTITY ex66 SYSTEM "ex66.sh">
|
|
<!ENTITY ex67 SYSTEM "ex67.sh">
|
|
<!ENTITY ex68 SYSTEM "ex68.sh">
|
|
<!ENTITY 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">
|
|
<!ENTITY redir4a SYSTEM "redir4a.sh">
|
|
<!ENTITY redir5 SYSTEM "redir5.sh">
|
|
<!ENTITY wipedir SYSTEM "wipedir.sh">
|
|
<!ENTITY grp SYSTEM "grp.sh">
|
|
<!ENTITY killprocess SYSTEM "kill-process.sh">
|
|
<!ENTITY killbyname SYSTEM "kill-byname.sh">
|
|
<!ENTITY strtest SYSTEM "str-test.sh">
|
|
<!ENTITY colm SYSTEM "colm.sh">
|
|
<!ENTITY lookup SYSTEM "lookup.sh">
|
|
<!ENTITY arglist SYSTEM "arglist.sh">
|
|
<!ENTITY rot13 SYSTEM "rot13.sh">
|
|
<!ENTITY rot14 SYSTEM "rot14.sh">
|
|
<!ENTITY filecomp SYSTEM "file-comparison.sh">
|
|
<!ENTITY adddrv SYSTEM "add-drive.sh">
|
|
<!ENTITY whloopc SYSTEM "wh-loopc.sh">
|
|
<!ENTITY forloopc SYSTEM "for-loopc.sh">
|
|
<!ENTITY forloopcmd SYSTEM "for-loopcmd.sh">
|
|
<!ENTITY cvars SYSTEM "c-vars.sh">
|
|
<!ENTITY bingrep SYSTEM "bin-grep.sh">
|
|
<!ENTITY mailformat SYSTEM "mail-format.sh">
|
|
<!ENTITY symlinks SYSTEM "symlinks.sh">
|
|
<!ENTITY symlinks2 SYSTEM "symlinks2.sh">
|
|
<!ENTITY string SYSTEM "string.sh">
|
|
<!ENTITY nestedloop SYSTEM "nested-loop.sh">
|
|
<!ENTITY casecmd SYSTEM "case-cmd.sh">
|
|
<!ENTITY uns SYSTEM "unset.sh">
|
|
<!ENTITY base SYSTEM "base.sh">
|
|
<!ENTITY allprofs SYSTEM "allprofs.sh">
|
|
<!ENTITY pidid SYSTEM "pid-identifier.sh">
|
|
<!ENTITY constat SYSTEM "connect-stat.sh">
|
|
<!ENTITY subpit SYSTEM "subshell-pitfalls.sh">
|
|
<!ENTITY readredir SYSTEM "read-redir.sh">
|
|
<!ENTITY andlist2 SYSTEM "and-list2.sh">
|
|
<!ENTITY qfunction SYSTEM "q-function.sh">
|
|
<!ENTITY viewdata SYSTEM "viewdata.sh">
|
|
<!ENTITY VIEWDAT SYSTEM "VIEWDATA.BAT">
|
|
<!ENTITY what SYSTEM "what.sh">
|
|
<!ENTITY max SYSTEM "max.sh">
|
|
<!ENTITY max2 SYSTEM "max2.sh">
|
|
<!ENTITY findstring SYSTEM "findstring.sh">
|
|
<!ENTITY listglob SYSTEM "list-glob.sh">
|
|
<!ENTITY realname SYSTEM "realname.sh">
|
|
<!ENTITY escaped SYSTEM "escaped.sh">
|
|
<!ENTITY fileinfo SYSTEM "file-info.sh">
|
|
<!ENTITY weirdvars SYSTEM "weirdvars.sh">
|
|
<!ENTITY breaklevels SYSTEM "break-levels.sh">
|
|
<!ENTITY copycd SYSTEM "copy-cd.sh">
|
|
<!ENTITY arithops SYSTEM "arith-ops.sh">
|
|
<!ENTITY continuelevels SYSTEM "continue-nlevel.sh">
|
|
<!ENTITY timeout SYSTEM "timeout.sh">
|
|
<!ENTITY randomtest SYSTEM "random-test.sh">
|
|
<!ENTITY seedingrandom SYSTEM "seeding-random.sh">
|
|
<!ENTITY pattmatching SYSTEM "patt-matching.sh">
|
|
<!ENTITY isalpha SYSTEM "isalpha.sh">
|
|
<!ENTITY rnd SYSTEM "rnd.sh">
|
|
<!ENTITY du SYSTEM "Du.sh">
|
|
<!ENTITY refparams SYSTEM "ref-params.sh">
|
|
<!ENTITY indfunc SYSTEM "ind-func.sh">
|
|
<!ENTITY primes SYSTEM "primes.sh">
|
|
<!ENTITY vartrace SYSTEM "vartrace.sh">
|
|
<!ENTITY amiroot SYSTEM "am-i-root.sh">
|
|
<!ENTITY twodim SYSTEM "twodim.sh">
|
|
<!ENTITY arithtests SYSTEM "arith-tests.sh">
|
|
<!ENTITY incompat SYSTEM "incompat.sh">
|
|
<!ENTITY ifsh SYSTEM "ifs.sh">
|
|
<!ENTITY ifsempty SYSTEM "ifs-empty.sh">
|
|
<!ENTITY logevents SYSTEM "logevents.sh">
|
|
<!ENTITY keypress SYSTEM "keypress.sh">
|
|
<!ENTITY ddkeypress SYSTEM "dd-keypress.sh">
|
|
<!ENTITY objoriented SYSTEM "obj-oriented.sh">
|
|
<!ENTITY emptyarray SYSTEM "empty-array.sh">
|
|
<!ENTITY length SYSTEM "length.sh">
|
|
<!ENTITY monthlypmt SYSTEM "monthlypmt.sh">
|
|
<!ENTITY derpm SYSTEM "de-rpm.sh">
|
|
<!ENTITY blotout SYSTEM "blot-out.sh">
|
|
<!ENTITY readr SYSTEM "read-r.sh">
|
|
<!ENTITY cryptoquote SYSTEM "crypto-quote.sh">
|
|
<!ENTITY erase SYSTEM "erase.sh">
|
|
<!ENTITY returntest SYSTEM "return-test.sh">
|
|
<!ENTITY daysbetween SYSTEM "days-between.sh">
|
|
<!ENTITY varmatch SYSTEM "var-match.sh">
|
|
<!ENTITY recurse SYSTEM "recurse.sh">
|
|
<!ENTITY assert SYSTEM "assert.sh">
|
|
<!ENTITY intorstring SYSTEM "int-or-string.sh">
|
|
<!ENTITY ramdisk SYSTEM "ramdisk.sh">
|
|
<!ENTITY m4 SYSTEM "m4.sh">
|
|
<!ENTITY idelete SYSTEM "idelete.sh">
|
|
<!ENTITY matchstring SYSTEM "match-string.sh">
|
|
<!ENTITY bashandperl SYSTEM "bashandperl.sh">
|
|
<!ENTITY cvt SYSTEM "cvt.sh">
|
|
<!ENTITY wf SYSTEM "wf.sh">
|
|
<!ENTITY wf2 SYSTEM "wf2.sh">
|
|
<!ENTITY hypot SYSTEM "hypotenuse.sh">
|
|
<!ENTITY random2 SYSTEM "random2.sh">
|
|
<!ENTITY altbc SYSTEM "alt-bc.sh">
|
|
<!ENTITY substringex SYSTEM "substring-extraction.sh">
|
|
<!ENTITY stupscr SYSTEM "stupid-script-tricks.sh">
|
|
<!ENTITY resistor SYSTEM "resistor-inventory.sh">
|
|
<!ENTITY stackex SYSTEM "stack.sh">
|
|
<!ENTITY gcd SYSTEM "gcd.sh">
|
|
<!ENTITY selfmailer SYSTEM "self-mailer.sh">
|
|
<!ENTITY collatz SYSTEM "collatz.sh">
|
|
<!ENTITY wstrings SYSTEM "wstrings.sh">
|
|
<!ENTITY multiplication SYSTEM "multiplication.sh">
|
|
<!ENTITY sumproduct SYSTEM "sum-product.sh">
|
|
<!ENTITY userlist SYSTEM "userlist.sh">
|
|
<!ENTITY bgloop SYSTEM "background-loop.sh">
|
|
<!ENTITY tout SYSTEM "t-out.sh">
|
|
<!ENTITY csubloop SYSTEM "csubloop.sh">
|
|
<!ENTITY arrfunc SYSTEM "array-function.sh">
|
|
<!ENTITY lifeslow SYSTEM "life.sh">
|
|
<!ENTITY commentblock SYSTEM "commentblock.sh">
|
|
<!ENTITY selfdocument SYSTEM "self-document.sh">
|
|
<!ENTITY hf SYSTEM "here-function.sh">
|
|
<!ENTITY fileintegrity SYSTEM "file-integrity.sh">
|
|
<!ENTITY readnovar SYSTEM "read-novar.sh">
|
|
<!ENTITY setpos SYSTEM "set-pos.sh">
|
|
<!ENTITY badread SYSTEM "badread.sh">
|
|
<!ENTITY selfexec SYSTEM "self-exec.sh">
|
|
<!ENTITY selfdestruct SYSTEM "self-destruct.sh">
|
|
<!ENTITY reassignstdout SYSTEM "reassign-stdout.sh">
|
|
<!ENTITY upperconv SYSTEM "upperconv.sh">
|
|
<!ENTITY pbook SYSTEM "pb.sh">
|
|
<!ENTITY makedict SYSTEM "makedict.sh">
|
|
<!ENTITY missingkeyword SYSTEM "missing-keyword.sh">
|
|
<!ENTITY blankrename SYSTEM "blank-rename.sh">
|
|
<!ENTITY scriptdetector SYSTEM "script-detector.sh">
|
|
<!ENTITY hexconvert SYSTEM "hexconvert.sh">
|
|
<!ENTITY factr SYSTEM "factr.sh">
|
|
<!ENTITY cannon SYSTEM "cannon.sh">
|
|
<!ENTITY agram SYSTEM "agram.sh">
|
|
<!ENTITY poem SYSTEM "poem.sh">
|
|
<!ENTITY soundex SYSTEM "soundex.sh">
|
|
<!ENTITY tempfilename SYSTEM "tempfile-name.sh">
|
|
<!ENTITY unitconversion SYSTEM "unit-conversion.sh">
|
|
<!ENTITY usagemessage SYSTEM "usage-message.sh">
|
|
<!ENTITY colorecho SYSTEM "color-echo.sh">
|
|
<!ENTITY selfsource SYSTEM "self-source.sh">
|
|
<!ENTITY selfcopy SYSTEM "self-copy.sh">
|
|
<!ENTITY arrowdetect SYSTEM "arrow-detect.sh">
|
|
<!ENTITY paragraphspace SYSTEM "paragraph-space.sh">
|
|
<!ENTITY brokenlink SYSTEM "broken-link.sh">
|
|
<!ENTITY continuenex SYSTEM "continue-n.example">
|
|
<!ENTITY pickcard SYSTEM "pick-card.sh">
|
|
<!ENTITY copyarray SYSTEM "CopyArray.sh">
|
|
<!ENTITY directoryinfo SYSTEM "directory-info.sh">
|
|
<!ENTITY embarr SYSTEM "embedded-arrays.sh">
|
|
<!ENTITY generatescript SYSTEM "generate-script.sh">
|
|
<!ENTITY scriptarray SYSTEM "script-array.sh">
|
|
<!ENTITY randombetween SYSTEM "random-between.sh">
|
|
<!ENTITY arrayops SYSTEM "array-ops.sh">
|
|
<!ENTITY arraystrops SYSTEM "array-strops.sh">
|
|
<!ENTITY arrayappend SYSTEM "array-append.bash">
|
|
<!ENTITY arrayassign SYSTEM "array-assign.bash">
|
|
<!ENTITY lettercount SYSTEM "letter-count.sh">
|
|
<!ENTITY lettercount2 SYSTEM "letter-count2.sh">
|
|
<!ENTITY protectliteral SYSTEM "protect_literal.sh">
|
|
<!ENTITY unprotectliteral SYSTEM "unprotect_literal.sh">
|
|
<!ENTITY usbinst SYSTEM "usb.sh">
|
|
<!ENTITY basicsreviewed SYSTEM "basics-reviewed.bash">
|
|
<!ENTITY readpipe SYSTEM "readpipe.sh">
|
|
<!ENTITY usrmnt SYSTEM "usrmnt.sh">
|
|
<!ENTITY dialog SYSTEM "dialog.sh">
|
|
<!ENTITY hellol SYSTEM "hello.sh">
|
|
<!ENTITY hanoi SYSTEM "hanoi.bash">
|
|
<!ENTITY horserace SYSTEM "horserace.sh">
|
|
<!ENTITY remote SYSTEM "remote.bash">
|
|
<!ENTITY prependex SYSTEM "prepend.sh">
|
|
<!ENTITY setnewpw SYSTEM "setnew-passwd.sh">
|
|
<!ENTITY badop SYSTEM "bad-op.sh">
|
|
<!ENTITY dereferencecl SYSTEM "dereference.sh">
|
|
<!ENTITY archiveweblogs SYSTEM "archiveweblogs.sh">
|
|
<!ENTITY devtcp SYSTEM "dev-tcp.sh">
|
|
<!ENTITY multipleproc SYSTEM "multiple-processes.sh">
|
|
<!ENTITY funccmdlinearg SYSTEM "func-cmdlinearg.sh">
|
|
<!ENTITY isspammer SYSTEM "is-spammer.sh">
|
|
<!ENTITY isspammer2 SYSTEM "is_spammer.bash">
|
|
<!ENTITY wgetter2 SYSTEM "wgetter2.bash">
|
|
<!ENTITY exercisingdd SYSTEM "exercising-dd.sh">
|
|
<!ENTITY quotefetch SYSTEM "quote-fetch.sh">
|
|
<!ENTITY avoidsubshell SYSTEM "avoid-subshell.sh">
|
|
<!ENTITY loggingwrapper SYSTEM "logging-wrapper.sh">
|
|
<!ENTITY dictlookup SYSTEM "dict-lookup.sh">
|
|
<!ENTITY bashpodder SYSTEM "bashpodder.sh">
|
|
<!ENTITY drawbox SYSTEM "Draw-box.sh">
|
|
<!ENTITY evalex SYSTEM "eval.example">
|
|
<!ENTITY testcgi SYSTEM "test-cgi.sh">
|
|
<!ENTITY spawnscr SYSTEM "spawn.sh">
|
|
<!ENTITY namesdata SYSTEM "names.data">
|
|
<!ENTITY gen0data SYSTEM "gen0">
|
|
<!ENTITY cdll SYSTEM "cdll">
|
|
<!ENTITY bashrc SYSTEM "bashrc">
|
|
]>
|
|
|
|
<book>
|
|
<bookinfo>
|
|
<title>Advanced Bash-Scripting Guide</title>
|
|
<subtitle>An in-depth exploration of the art of shell scripting</subtitle>
|
|
|
|
|
|
<author>
|
|
<firstname>Mendel</firstname>
|
|
<surname>Cooper</surname>
|
|
<affiliation>
|
|
<orgname></orgname>
|
|
<address><email>thegrendel@theriver.com</email></address>
|
|
</affiliation>
|
|
</author>
|
|
|
|
<releaseinfo>3.3</releaseinfo>
|
|
<pubdate>20 March 2005</pubdate>
|
|
|
|
|
|
<revhistory>
|
|
|
|
<revision>
|
|
<revnumber>3.1</revnumber>
|
|
<date>14 Nov 2004</date>
|
|
<authorinitials>mc</authorinitials>
|
|
<revremark>'BAYBERRY' release: Bugfix update.</revremark>
|
|
</revision>
|
|
|
|
<revision>
|
|
<revnumber>3.2</revnumber>
|
|
<date>06 Feb 2005</date>
|
|
<authorinitials>mc</authorinitials>
|
|
<revremark>'BLUEBERRY' release: Minor update.</revremark>
|
|
</revision>
|
|
|
|
<revision>
|
|
<revnumber>3.3</revnumber>
|
|
<date>20 Mar 2005</date>
|
|
<authorinitials>mc</authorinitials>
|
|
<revremark>'RASPBERRY' release: Important Update.</revremark>
|
|
</revision>
|
|
|
|
</revhistory>
|
|
|
|
|
|
<abstract>
|
|
|
|
<para>This tutorial assumes no previous knowledge of
|
|
scripting or programming, but progresses rapidly toward an
|
|
intermediate/advanced level of instruction <emphasis>. . . all
|
|
the while sneaking in little snippets of <trademark
|
|
class=registered>UNIX</trademark> wisdom and lore</emphasis>. It
|
|
serves as a textbook, a manual for self-study, and a reference and
|
|
source of knowledge on shell scripting techniques. The exercises
|
|
and heavily-commented examples invite active reader participation,
|
|
under the premise that <userinput>the only way to really learn
|
|
scripting is to write scripts</userinput>.</para>
|
|
|
|
<para>This book is suitable for classroom use as a general
|
|
introduction to programming concepts.</para>
|
|
|
|
<para><ulink
|
|
url="http://personal.riverusers.com/~thegrendel/abs-guide-3.3.tar.bz2">
|
|
The latest update of this document</ulink>, as an archived, <link
|
|
linkend="bzipref">bzip2-ed</link> <quote>tarball</quote>
|
|
including both the SGML source and rendered HTML, may
|
|
be downloaded from the author's home site. A <ulink
|
|
url="http://www.tldp.org/LDP/abs/abs-guide.pdf">pdf
|
|
version</ulink> is also available. See the <ulink
|
|
url="http://personal.riverusers.com/~thegrendel/Change.log">change
|
|
log</ulink> for a revision history.</para>
|
|
|
|
</abstract>
|
|
</bookinfo>
|
|
|
|
<dedication>
|
|
<para>For Anita, the source of all the magic</para>
|
|
</dedication>
|
|
|
|
|
|
|
|
<part label="Part 1" id="part1">
|
|
<title>Introduction</title>
|
|
|
|
<partintro>
|
|
|
|
<para>The shell is a command interpreter. More than just the
|
|
insulating layer between the operating system kernel and the user,
|
|
it's also a fairly powerful programming language. A shell program,
|
|
called a <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>
|
|
|
|
</partintro>
|
|
|
|
<chapter id="why-shell">
|
|
<title>Why Shell Programming?</title>
|
|
|
|
<epigraph>
|
|
<attribution>Herbert Mayer</attribution>
|
|
<para>No programming language is perfect. There is not even a single
|
|
best language; there are only languages well suited or perhaps poorly
|
|
suited for particular purposes.</para>
|
|
</epigraph>
|
|
|
|
|
|
<para>A working knowledge of shell scripting is essential to anyone
|
|
wishing to become reasonably proficient at system administration,
|
|
even if they do not anticipate ever having to actually write a
|
|
script. Consider that as a Linux machine boots up, it executes the
|
|
shell scripts in <filename class="directory">/etc/rc.d</filename>
|
|
to restore the system configuration and set up services. A detailed
|
|
understanding of these startup scripts is important for analyzing
|
|
the behavior of a system, and possibly modifying it.</para>
|
|
|
|
<para>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 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 classic UNIX philosophy
|
|
of breaking complex projects into simpler subtasks, of chaining
|
|
together components and utilities. Many consider this a better,
|
|
or at least more esthetically pleasing approach to problem solving
|
|
than using one of the new generation of high powered all-in-one
|
|
languages, such as 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,
|
|
especially floating point arithmetic, arbitrary precision
|
|
calculations, or complex numbers (use C++ or FORTRAN
|
|
instead)</para>
|
|
</listitem> <listitem>
|
|
<para>Cross-platform portability required (use C instead)</para>
|
|
</listitem> <listitem>
|
|
<para>Complex applications, where structured programming is
|
|
a necessity (need type-checking 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
|
|
guarantee the integrity of your system and protect against
|
|
intrusion, cracking, and vandalism</para>
|
|
</listitem> <listitem>
|
|
<para>Project consists of subcomponents with interlocking
|
|
dependencies</para>
|
|
</listitem> <listitem>
|
|
<para>Extensive file operations required (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>
|
|
</listitem> <listitem>
|
|
<para>Need data structures, such as linked lists or trees</para>
|
|
</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 put the
|
|
source code right out in the open for all the world to see)</para>
|
|
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>If any of the above applies, consider a more powerful scripting
|
|
language -- perhaps Perl, Tcl, Python, Ruby -- 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 <acronym>Bash</acronym>, 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 the principles dealt with in this book apply equally
|
|
well to 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 an October, 1993 <ulink
|
|
url="http://www.etext.org/Quartz/computer/unix/csh.harmful.gz">Usenet
|
|
post</ulink> by Tom Christiansen.)
|
|
</para>
|
|
|
|
<para>What follows is a tutorial on shell scripting. It relies
|
|
heavily on examples to illustrate various features of the
|
|
shell. The example scripts work -- they've been tested --
|
|
and some of them are even useful in real life. The reader
|
|
can play with the actual working code of the examples in
|
|
the source archive (<filename>scriptname.sh</filename> or
|
|
<filename>scriptname.bash</filename>),
|
|
|
|
<footnote><para>By convention, user-written shell scripts that are
|
|
Bourne shell compliant generally take a name with a
|
|
<filename>.sh</filename> extension. System scripts, such as
|
|
those found in <filename class="directory">/etc/rc.d</filename>,
|
|
do not conform to this nomenclature.</para></footnote>
|
|
|
|
give them 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 <ulink
|
|
url="http://www.tldp.org/LDP/abs/abs-guide.html.tar.gz">HTML</ulink>,
|
|
<ulink url="http://www.tldp.org/LDP/abs/abs-guide.pdf">pdf</ulink>,
|
|
or <ulink
|
|
url="http://www.ibiblio.org/pub/Linux/docs/linux-doc-project/abs-guide/abs-guide.txt.gz">text</ulink>
|
|
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>
|
|
|
|
<para>Unless otherwise noted, <ulink
|
|
url="mailto:thegrendel@theriver.com">the author</ulink> of this
|
|
book wrote the example scripts that follow.</para>
|
|
|
|
</chapter> <!-- Why Shell Programming? -->
|
|
|
|
|
|
<chapter id="sha-bang">
|
|
<title>Starting Off With a Sha-Bang</title>
|
|
|
|
<epigraph>
|
|
<attribution>Larry Wall</attribution>
|
|
<para>Shell programming is a 1950s juke box . . .</para>
|
|
</epigraph>
|
|
|
|
<para>In the simplest case, a script is nothing more than a list of system
|
|
commands stored in a file. At the very least, this saves the
|
|
effort of retyping that particular sequence of commands each time
|
|
it is invoked.</para>
|
|
|
|
<example id="ex1">
|
|
<title><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="ex1a">
|
|
<title><command>cleanup</command>: An improved clean-up
|
|
script</title> <programlisting>&ex1a;</programlisting>
|
|
</example>
|
|
|
|
<para>Now that's beginning to look like a real script. But we can
|
|
go even farther . . .</para>
|
|
|
|
<example id="ex2">
|
|
<title><command>cleanup</command>: An enhanced
|
|
and generalized version of above scripts.</title>
|
|
<programlisting>&ex2;</programlisting>
|
|
</example>
|
|
|
|
<para>Since you may not wish to wipe out the entire system log,
|
|
this version of the script keeps the last section of the message
|
|
log intact. You will constantly discover ways of 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
|
|
|
|
<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>
|
|
|
|
<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>
|
|
<para>If, in fact, the script includes an
|
|
<emphasis>extra</emphasis> <token>#!</token> line, then
|
|
<command>bash</command> will interpret it as a comment.
|
|
<programlisting>#!/bin/bash
|
|
|
|
echo "Part 1 of script."
|
|
a=1
|
|
|
|
#!/bin/bash
|
|
# This does *not* launch a new script.
|
|
|
|
echo "Part 2 of script."
|
|
echo $a # Value of $a stays at 1.</programlisting></para>
|
|
</footnote>
|
|
|
|
</para>
|
|
|
|
|
|
<para><programlisting>#!/bin/sh
|
|
#!/bin/bash
|
|
#!/usr/bin/perl
|
|
#!/usr/bin/tcl
|
|
#!/bin/sed -f
|
|
#!/usr/awk -f</programlisting></para>
|
|
|
|
<para>Each of the above script header lines calls a different command
|
|
interpreter, be it <filename>/bin/sh</filename>, the default shell
|
|
(<command>bash</command> in a Linux system) or otherwise.
|
|
|
|
<footnote>
|
|
<para>This allows some cute tricks.</para>
|
|
<para><programlisting>#!/bin/rm
|
|
# Self-deleting script.
|
|
|
|
# Nothing much seems to happen when you run this... except that the file disappears.
|
|
|
|
WHATEVER=65
|
|
|
|
echo "This line will never print (betcha!)."
|
|
|
|
exit $WHATEVER # Doesn't matter. The script will not exit here.</programlisting></para>
|
|
<para>Also, try starting a <filename>README</filename> file with a
|
|
<userinput>#!/bin/more</userinput>, and making it executable.
|
|
The result is a self-listing documentation file. (A <link
|
|
linkend="heredocref">here document</link> using
|
|
<link linkend="catref">cat</link> is possibly a better alternative
|
|
-- see <xref linkend="ex71">).</para>
|
|
</footnote>
|
|
|
|
Using <userinput>#!/bin/sh</userinput>, the default Bourne shell
|
|
in most commercial variants of UNIX, makes the script <link
|
|
linkend="portabilityissues">portable</link> to non-Linux machines,
|
|
though you sacrifice Bash-specific features.
|
|
The script will, however, conform to the
|
|
<acronym>POSIX</acronym>
|
|
|
|
<footnote>
|
|
<para><anchor id="posix2ref"><emphasis role="strong">P</emphasis>ortable
|
|
<emphasis role="strong">O</emphasis>perating
|
|
<emphasis role="strong">S</emphasis>ystem <emphasis
|
|
role="bold">I</emphasis>nterface, an attempt to
|
|
standardize UNI<emphasis role="strong">X</emphasis>-like
|
|
OSes. The POSIX specifications are listed on the <ulink
|
|
url="http://www.opengroup.org/onlinepubs/007904975/toc.htm">Open
|
|
Group site</ulink>.</para>
|
|
</footnote>
|
|
|
|
<command>sh</command> standard.</para>
|
|
|
|
<para>Note that the path given at the <quote>sha-bang</quote> must
|
|
be correct, otherwise an error message -- usually <quote>Command
|
|
not found</quote> -- will be the only result of running the
|
|
script.</para>
|
|
|
|
<para><token>#!</token> can be omitted if the script consists only
|
|
of a set of generic system commands, using no internal
|
|
shell directives. The second example, above, requires the
|
|
initial <token>#!</token>, since the variable assignment line,
|
|
<userinput>lines=50</userinput>, uses a shell-specific construct.
|
|
Note again that <userinput>#!/bin/sh</userinput> invokes the default
|
|
shell interpreter, which defaults to <filename>/bin/bash</filename>
|
|
on a Linux machine.</para>
|
|
|
|
|
|
<tip>
|
|
<para>This tutorial encourages a modular approach
|
|
to constructing a script. Make note of and collect
|
|
<quote>boilerplate</quote> code snippets that might be useful
|
|
in future scripts. Eventually you can build quite an extensive
|
|
library of nifty routines. As an example, the following script
|
|
prolog tests whether the script has been invoked with the correct
|
|
number of parameters.</para>
|
|
|
|
<para><programlisting>E_WRONG_ARGS=65
|
|
script_parameters="-a -h -m -z"
|
|
# -a = all, -h = help, etc.
|
|
|
|
if [ $# -ne $Number_of_expected_args ]
|
|
then
|
|
echo "Usage: `basename $0` $script_parameters"
|
|
# `basename $0` is the script's filename.
|
|
exit $E_WRONG_ARGS
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
<para>Many times, you will write a script that carries out one
|
|
particular task. The first script in this chapter is an
|
|
example of this. Later, it might occur to you to generalize
|
|
the script to do other, similar tasks. Replacing the literal
|
|
(<quote>hard-wired</quote>) constants by variables is a step in
|
|
that direction, as is replacing repetitive code blocks by <link
|
|
linkend="functionref">functions</link>.</para>
|
|
|
|
</tip>
|
|
|
|
|
|
|
|
<sect1 id="invoking">
|
|
<title>Invoking the script</title>
|
|
<para>Having written the script, you can invoke it by <userinput>sh
|
|
scriptname</userinput>,
|
|
|
|
<footnote><para>Caution: invoking a Bash script by <userinput>sh
|
|
scriptname</userinput> turns off Bash-specific extensions, and the
|
|
script may therefore fail to execute.</para></footnote>
|
|
|
|
or alternatively <userinput>bash scriptname</userinput>. (Not
|
|
recommended is using <userinput>sh <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 -->
|
|
|
|
|
|
<sect1 id="prelimexer">
|
|
<title>Preliminary Exercises</title>
|
|
|
|
<orderedlist>
|
|
|
|
<listitem>
|
|
<para>System administrators often write scripts to automate common
|
|
tasks. Give several instances where such scripts would be
|
|
useful.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Write a script that upon invocation shows the
|
|
<link linkend="dateref">time and date</link>, <link
|
|
linkend="whoref">lists all logged-in users</link>, and gives
|
|
the system <link linkend="uptimeref">uptime</link>. The script
|
|
then <link linkend="ioredirref">saves this information</link>
|
|
to a logfile.</para>
|
|
</listitem>
|
|
|
|
</orderedlist>
|
|
|
|
</sect1> <!-- Preliminary Exercises -->
|
|
|
|
</chapter> <!-- Starting Off With a Sha-Bang -->
|
|
|
|
|
|
</part> <!-- Part 1 (Introduction) -->
|
|
|
|
|
|
|
|
<part label="Part 2" id="part2">
|
|
<title>Basics</title>
|
|
|
|
|
|
|
|
<chapter id="special-chars">
|
|
<title>Special Characters</title>
|
|
|
|
<variablelist id="scharlist">
|
|
<title><anchor id="scharlist1">Special Characters Found In
|
|
Scripts and Elsewhere</title>
|
|
|
|
<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 following the end of a command.</para>
|
|
|
|
<para><programlisting>echo "A comment will follow." # Comment here.
|
|
# ^ Note whitespace before #</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 (" ' \) escape the #.
|
|
</para></note>
|
|
|
|
<para>Certain <link linkend="psorex1">pattern matching
|
|
operations</link> also use the <token>#</token>.</para>
|
|
|
|
</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 [semicolon]</title>
|
|
<para>Permits putting two or more commands on the same
|
|
line.</para>
|
|
</formalpara>
|
|
|
|
<para>
|
|
<programlisting>echo hello; echo there
|
|
|
|
|
|
if [ -x "$filename" ]; then # Note that "if" and "then" need separation.
|
|
# Why?
|
|
echo "File $filename exists."; cp $filename $filename.bak
|
|
else
|
|
echo "File $filename not found."; touch $filename
|
|
fi; echo "File test complete."</programlisting>
|
|
</para>
|
|
|
|
<para>Note that the <quote><token>;</token></quote> sometimes
|
|
needs to be <link linkend="escp">escaped</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>;;</token></term>
|
|
<indexterm>
|
|
<primary>;;</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>case</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>;;</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<formalpara><title>Terminator in a <link
|
|
linkend="caseesac1">case</link> option [double semicolon]</title>
|
|
<para><anchor id="doublesemicolon"></para>
|
|
</formalpara>
|
|
|
|
<para><programlisting>case "$variable" in
|
|
abc) echo "\$variable = abc" ;;
|
|
xyz) echo "\$variable = xyz" ;;
|
|
esac</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry><term><token>.</token></term>
|
|
<indexterm>
|
|
<primary>.</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>.</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>dot command</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>source</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para><anchor id="dotref"></para>
|
|
<formalpara><title><quote>dot</quote> command [period]</title>
|
|
<para>Equivalent to <link
|
|
linkend="sourceref">source</link> (see
|
|
<xref linkend="ex38">). This is a bash <link
|
|
linkend="builtinref">builtin</link>.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry><term><token>.</token></term>
|
|
<indexterm>
|
|
<primary>.</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>.</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>filename</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>part of a filename</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<formalpara><title><quote>dot</quote>, as a component of a filename</title>
|
|
<para>When working with filenames, a dot is the prefix
|
|
of a <quote>hidden</quote> file, a file that an
|
|
<link linkend="lsref">ls</link> will not normally show.
|
|
<screen><prompt>bash$ </prompt><userinput>touch .hidden-file</userinput>
|
|
<prompt>bash$ </prompt><userinput>ls -l</userinput>
|
|
<computeroutput>total 10
|
|
-rw-r--r-- 1 bozo 4034 Jul 18 22:04 data1.addressbook
|
|
-rw-r--r-- 1 bozo 4602 May 25 13:58 data1.addressbook.bak
|
|
-rw-r--r-- 1 bozo 877 Dec 17 2000 employment.addressbook</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -al</userinput>
|
|
<computeroutput>total 14
|
|
drwxrwxr-x 2 bozo bozo 1024 Aug 29 20:54 ./
|
|
drwx------ 52 bozo bozo 3072 Aug 29 20:51 ../
|
|
-rw-r--r-- 1 bozo bozo 4034 Jul 18 22:04 data1.addressbook
|
|
-rw-r--r-- 1 bozo bozo 4602 May 25 13:58 data1.addressbook.bak
|
|
-rw-r--r-- 1 bozo bozo 877 Dec 17 2000 employment.addressbook
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 29 20:54 .hidden-file</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</formalpara>
|
|
|
|
<para>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>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>cp /home/bozo/current_work/junk/* .</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry><term><token>.</token></term>
|
|
<indexterm>
|
|
<primary>.</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>.</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character match</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>match single character</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<formalpara><title><quote>dot</quote> character match</title>
|
|
<para>When <link linkend="regexdot">matching
|
|
characters</link>, as part of a <link
|
|
linkend="regexref">regular expression</link>, a
|
|
<quote>dot</quote> matches a single character.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><token>"</token></term>
|
|
<listitem><formalpara><title><link linkend="dblquo">partial
|
|
quoting</link> [double quote]</title>
|
|
<para><emphasis>"STRING"</emphasis> preserves (from
|
|
interpretation) most of the special characters within
|
|
<emphasis>STRING</emphasis>. See also <xref
|
|
linkend="quoting">.</para>
|
|
</formalpara> </listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>'</token></term>
|
|
<listitem><formalpara><title><link linkend="snglquo">full
|
|
quoting</link> [single quote]</title>
|
|
<para><emphasis>'STRING'</emphasis> preserves all special
|
|
characters within <emphasis>STRING</emphasis>. This is a
|
|
stronger form of quoting than 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>
|
|
</formalpara> </listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>\</token></term>
|
|
<listitem><formalpara><title><link linkend="escp">escape</link> [backslash]</title>
|
|
<para>A quoting mechanism for single characters.</para>
|
|
</formalpara>
|
|
|
|
<para><userinput>\X</userinput>
|
|
<quote>escapes</quote> the character
|
|
<emphasis>X</emphasis>. This has the effect of
|
|
<quote>quoting</quote> <emphasis>X</emphasis>, equivalent
|
|
to <emphasis>'X'</emphasis>. The <token>\</token> may
|
|
be used to quote <token>"</token> and <token>'</token>,
|
|
so they are expressed literally.</para>
|
|
<para>See <xref linkend="quoting"> for an in-depth explanation
|
|
of escaped characters.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>/</token></term>
|
|
<listitem><formalpara><title>Filename path separator [forward slash]</title>
|
|
<para>Separates the components of a filename (as in
|
|
<filename>/home/bozo/projects/Makefile</filename>).</para>
|
|
</formalpara>
|
|
<para>This is also the division <link
|
|
linkend="arops1">arithmetic operator</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>`</token></term>
|
|
<listitem><formalpara><title><link
|
|
linkend="commandsubref">command substitution</link></title>
|
|
<para>The <command>`command`</command> construct makes
|
|
available the output of <emphasis>command</emphasis>
|
|
for setting a variable. This is also known as
|
|
<link linkend="backquotesref">backticks</link> or
|
|
backquotes.</para></formalpara> </listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>:</token></term>
|
|
<indexterm>
|
|
<primary>:</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>:</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>null command</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>true</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>endless loop</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para><anchor id="nullref"></para>
|
|
<formalpara><title>null command [colon]</title>
|
|
<para>This is the shell equivalent of a
|
|
<quote>NOP</quote> (<replaceable>no op</replaceable>, a
|
|
do-nothing operation). It may be considered a synonym for
|
|
the shell builtin <link linkend="trueref">true</link>. The
|
|
<quote><token>:</token></quote> command is a itself a Bash
|
|
builtin, and its <link linkend="exitstatusref">exit
|
|
status</link> is <quote>true</quote>
|
|
(<returnvalue>0</returnvalue>).</para>
|
|
</formalpara>
|
|
|
|
<para><programlisting>:
|
|
echo $? # 0</programlisting></para>
|
|
|
|
|
|
<para>Endless loop:</para>
|
|
|
|
<para><programlisting>
|
|
while :
|
|
do
|
|
operation-1
|
|
operation-2
|
|
...
|
|
operation-n
|
|
done
|
|
|
|
# Same as:
|
|
# while true
|
|
# do
|
|
# ...
|
|
# done</programlisting>
|
|
</para>
|
|
|
|
<para>Placeholder in if/then test:</para>
|
|
|
|
<para><programlisting>
|
|
if condition
|
|
then : # Do nothing and branch ahead
|
|
else
|
|
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
|
|
<link linkend="paramsubref">parameter substitution</link>
|
|
(as in <xref linkend="ex6">).
|
|
|
|
<programlisting>: ${HOSTNAME?} ${USER?} ${MAIL?}
|
|
#Prints error message if one or more of essential environmental variables not set.</programlisting>
|
|
</para>
|
|
|
|
<para><command><link linkend="exprepl1">Variable expansion / substring
|
|
replacement</link></command>.</para>
|
|
|
|
<para>In combination with the <token>></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>>></token>
|
|
redirection operator, has no effect on a pre-existing
|
|
target file (<userinput>: >> target_file</userinput>).
|
|
If the file did not previously exist, creates it.</para>
|
|
|
|
<note><para>This applies to regular files, not pipes,
|
|
symlinks, and certain special files.</para></note>
|
|
|
|
|
|
<para>May be used to begin a comment line, although this is not
|
|
recommended. Using <token>#</token> for a comment turns
|
|
off error checking for the remainder of that line, so
|
|
almost anything may 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>
|
|
</para>
|
|
|
|
<para>The <quote><token>:</token></quote> also serves as a field
|
|
separator, in <filename>/etc/passwd</filename>, and in the <link
|
|
linkend="pathref">$PATH</link> variable.
|
|
<screen><prompt>bash$ </prompt><userinput>echo $PATH</userinput>
|
|
<computeroutput>/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games</computeroutput></screen>
|
|
</para>
|
|
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>!</token></term>
|
|
<indexterm>
|
|
<primary>!</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>!</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>not</primary>
|
|
<secondary>logical</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>not</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para><anchor id="notref"></para>
|
|
<formalpara><title>reverse (or negate) the sense of
|
|
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>
|
|
<para>In a different context, the <token>!</token>
|
|
also appears in <link linkend="ivrref">indirect variable
|
|
references</link>.</para>
|
|
|
|
<para>In yet another context, from the <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>
|
|
|
|
</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 [asterisk]</title>
|
|
|
|
<para>The <token>*</token> character serves as a <quote>wild
|
|
card</quote> for filename expansion in
|
|
<link linkend="globbingref">globbing</link>. By itself,
|
|
it matches every filename in a given directory.</para>
|
|
</formalpara>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo *</userinput>
|
|
<computeroutput>abs-book.sgml add-drive.sh agram.sh alias.sh</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <token>*</token> also represents any number
|
|
(or zero) characters in a <link
|
|
linkend="regexref">regular expression</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>*</token></term>
|
|
<indexterm>
|
|
<primary>*</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>*</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>multiplication</primary>
|
|
<secondary>exponentiation</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>arithmetic operator</primary>
|
|
</indexterm>
|
|
|
|
<listitem><formalpara><title><link linkend="arops1">arithmetic operator</link></title>
|
|
|
|
<para>In the context of arithmetic operations, the
|
|
<token>*</token> denotes multiplication.</para>
|
|
|
|
</formalpara>
|
|
|
|
<para>A double asterisk, <token>**</token>, is the <link
|
|
linkend="exponentiationref">exponentiation
|
|
operator</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>?</token></term>
|
|
<indexterm>
|
|
<primary>?</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>?</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
<secondary>operator</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test token</primary>
|
|
</indexterm>
|
|
|
|
<listitem><formalpara><title>test operator</title>
|
|
<para>Within certain expressions, the <token>?</token> indicates
|
|
a test for a condition.</para>
|
|
</formalpara>
|
|
|
|
<para>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>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>$</token></term>
|
|
<indexterm>
|
|
<primary>$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>$</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable substitution</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<formalpara><title><link linkend="varsubn">Variable
|
|
substitution</link></title>
|
|
<para>
|
|
<programlisting>var1=5
|
|
var2=23skidoo
|
|
|
|
echo $var1 # 5
|
|
echo $var2 # 23skidoo</programlisting>
|
|
</para>
|
|
</formalpara>
|
|
|
|
<para>A <token>$</token> prefixing a variable name
|
|
indicates the <emphasis>value</emphasis> the variable
|
|
holds.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>$</token></term>
|
|
<indexterm>
|
|
<primary>$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>$</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>regular expression</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>end of line</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<formalpara><title>end-of-line</title>
|
|
<para>In a <link linkend="regexref">regular expression</link>, a
|
|
<quote>$</quote> addresses the end of a line of text.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>${}</token></term>
|
|
<indexterm>
|
|
<primary>${}</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>${}</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>parameter substitution</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<formalpara><title><link linkend="paramsubref">Parameter
|
|
substitution</link></title>
|
|
<para></para></formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>$*</token></term>
|
|
<term><token>$@</token></term>
|
|
<indexterm>
|
|
<primary>$*</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>$*</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>$@</primary>
|
|
<secondary>positional parameters</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>$@</primary>
|
|
</indexterm>
|
|
|
|
<listitem><formalpara><title><link linkend="appref">positional
|
|
parameters</link></title>
|
|
<para></para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>$?</token></term>
|
|
<indexterm>
|
|
<primary>$?</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>?</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>exit status</primary>
|
|
<secondary>variable</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>exit status</primary>
|
|
</indexterm>
|
|
|
|
<listitem><formalpara><title>exit status variable</title>
|
|
<para>The <link linkend="exsref">$? variable</link>
|
|
holds the <link linkend="exitstatusref">exit status</link>
|
|
of a command, a <link linkend="functionref">function</link>,
|
|
or of the script itself.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
|
|
<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><anchor id="braceexpref"><programlisting>grep Linux file*.{txt,htm*}
|
|
# Finds all instances of the word "Linux"
|
|
# 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>
|
|
<term><token>{}</token></term>
|
|
<indexterm>
|
|
<primary>{}</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>{}</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>block of code</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para><anchor id="codeblockref"></para>
|
|
<formalpara><title>Block of code [curly brackets]</title>
|
|
<para>Also referred to as an <quote>inline group</quote>,
|
|
this construct, in effect, creates an anonymous
|
|
function. However, unlike a <link
|
|
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>
|
|
<secondary>[ ]</secondary>
|
|
</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>
|
|
<secondary>[[ ]]</secondary>
|
|
</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
|
|
linkend="dblbrackets">[[ ... ]] construct</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>[ ]</token></term>
|
|
<indexterm>
|
|
<primary>[ ]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>array_element[ ]</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>array element</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<formalpara><title>array element</title>
|
|
<para></para></formalpara>
|
|
<para>In the context of an <link linkend="arrayref">array</link>,
|
|
brackets set off the numbering of each element of that array.
|
|
<programlisting>Array[1]=slot_1
|
|
echo ${Array[1]}</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>[ ]</token></term>
|
|
<indexterm>
|
|
<primary>[ ]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>character range</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>regular expression</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<formalpara><title>range of characters</title>
|
|
<para></para></formalpara>
|
|
<para>As part of a <link linkend="regexref">regular
|
|
expression</link>, brackets delineate a <link
|
|
linkend="bracketsref">range of characters</link> to
|
|
match.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>(( ))</token></term>
|
|
<indexterm>
|
|
<primary>(( ))</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>(( ))</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>integer comparison</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<formalpara><title>integer expansion</title>
|
|
<para></para></formalpara>
|
|
<para>Expand and evaluate integer expression between
|
|
<token>(( ))</token>.</para>
|
|
<para>See the discussion on the <link
|
|
linkend="dblparens">(( ... )) construct</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><token>></token> <token>&></token> <token>>&</token> <token>>></token> <token><</token></term>
|
|
<indexterm>
|
|
<primary>></primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>>&</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>>></primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary><</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>></secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>>&</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>>></secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary><</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>redirection</primary>
|
|
</indexterm>
|
|
|
|
<listitem><formalpara><title><link linkend="ioredirref">redirection</link></title>
|
|
<para></para>
|
|
</formalpara>
|
|
|
|
<para><userinput>scriptname >filename</userinput> redirects the output of
|
|
<filename>scriptname</filename> to file
|
|
<filename>filename</filename>. Overwrite
|
|
<filename>filename</filename> if it already exists.</para>
|
|
|
|
<para><userinput>command &>filename</userinput> redirects
|
|
both the <filename>stdout</filename> and the
|
|
<filename>stderr</filename> of <filename>command</filename>
|
|
to <filename>filename</filename>.</para>
|
|
|
|
<para><userinput>command >&2</userinput> redirects
|
|
<filename>stdout</filename> of <filename>command</filename>
|
|
to <filename>stderr</filename>.</para>
|
|
|
|
<para><userinput>scriptname >>filename</userinput> appends
|
|
the output of <filename>scriptname</filename>
|
|
to file <filename>filename</filename>. If
|
|
<filename>filename</filename> does not already exist,
|
|
it 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>
|
|
|
|
|
|
<para><link linkend="ltref">In a different context</link>,
|
|
the <quote><token><</token></quote> and
|
|
<quote><token>></token></quote> characters act
|
|
as <link linkend="scomparison1">string comparison
|
|
operators</link>.</para>
|
|
|
|
<para><link linkend="intlt">In yet another context</link>,
|
|
the <quote><token><</token></quote> and
|
|
<quote><token>></token></quote> characters act
|
|
as <link linkend="icomparison1">integer comparison
|
|
operators</link>. See also <xref linkend="ex45">.</para>
|
|
|
|
</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>
|
|
|
|
<varlistentry>
|
|
<term><token><<<</token></term>
|
|
<listitem><formalpara><title>redirection used in a <link
|
|
linkend="herestringsref">here string</link></title>
|
|
<para></para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token><</token></term>
|
|
<term><token>></token></term>
|
|
<indexterm>
|
|
<primary><</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary><</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>></primary>
|
|
<secondary>ASCII comparison</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>></primary>
|
|
</indexterm>
|
|
|
|
<listitem><formalpara><title><link linkend="ltref">ASCII
|
|
comparison</link></title>
|
|
<para><programlisting>veg1=carrots
|
|
veg2=tomatoes
|
|
|
|
if [[ "$veg1" < "$veg2" ]]
|
|
then
|
|
echo "Although $veg1 precede $veg2 in the dictionary,"
|
|
echo "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 '\<the\>' textfile</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>|</token></term>
|
|
<indexterm>
|
|
<primary>|</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>|</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>pipe</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para><anchor id="piperef"></para>
|
|
<formalpara><title>pipe</title>
|
|
<para>Passes the output of previous command to the input
|
|
of the next one, or to the shell. This is a method of
|
|
chaining commands together.</para>
|
|
</formalpara>
|
|
|
|
<para>
|
|
<programlisting>echo ls -l | sh
|
|
# Passes the output of "echo ls -l" to the shell,
|
|
#+ with the same result as a simple "ls -l".
|
|
|
|
|
|
cat *.lst | sort | uniq
|
|
# Merges and sorts all ".lst" files, then deletes duplicate lines.</programlisting>
|
|
</para>
|
|
|
|
<sidebar>
|
|
<para>A pipe, as a classic method of interprocess
|
|
communication, sends the <filename>stdout</filename>
|
|
of one process to the <filename>stdin</filename>
|
|
of another. In a typical case, a command,
|
|
such as <link linkend="catref">cat</link> or <link
|
|
linkend="echoref">echo</link>, pipes a stream of data to a
|
|
<quote>filter</quote> (a command that transforms its input)
|
|
for processing.</para>
|
|
<para>
|
|
<userinput>cat $filename1 $filename2 | grep $search_word</userinput>
|
|
</para>
|
|
</sidebar>
|
|
|
|
|
|
<para><anchor id="ucref">The output of a command or commands
|
|
may be piped to a script.
|
|
|
|
<programlisting>#!/bin/bash
|
|
# uppercase.sh : Changes input to uppercase.
|
|
|
|
tr 'a-z' 'A-Z'
|
|
# Letter ranges must be quoted
|
|
#+ to prevent filename generation from single-letter filenames.
|
|
|
|
exit 0</programlisting>
|
|
Now, let us pipe the output of <command>ls -l</command> to this
|
|
script.
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>ls -l | ./uppercase.sh</userinput>
|
|
<computeroutput>-RW-RW-R-- 1 BOZO BOZO 109 APR 7 19:49 1.TXT
|
|
-RW-RW-R-- 1 BOZO BOZO 109 APR 14 16:48 2.TXT
|
|
-RW-R--R-- 1 BOZO BOZO 725 APR 20 20:56 DATA-FILE</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note>
|
|
|
|
<para>The <filename>stdout</filename> of each process in
|
|
a pipe must be read as the <filename>stdin</filename>
|
|
of the next. If this is not the case, the data stream
|
|
will <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
|
|
aborts, this prematurely terminates execution of the
|
|
pipe. Called a <emphasis>broken pipe</emphasis>, this
|
|
condition sends a <emphasis>SIGPIPE</emphasis> <link
|
|
linkend="signald">signal</link>.</para>
|
|
|
|
</note>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>>|</token></term>
|
|
<indexterm>
|
|
<primary>>|</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>>|</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>redirection</primary>
|
|
<secondary>force</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>noclobber</primary>
|
|
</indexterm>
|
|
|
|
<listitem><formalpara><title>force redirection (even if
|
|
the <link linkend="noclobberref">noclobber option</link>
|
|
is set)</title>
|
|
<para>This will forcibly overwrite an existing file.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>||</token></term>
|
|
<indexterm>
|
|
<primary>||</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>||</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>or</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>logical operator</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<formalpara><title><link linkend="orref">OR logical operator</link></title>
|
|
<para>In a <link linkend="testconstructs1">test
|
|
construct</link>, the <token>||</token> operator causes
|
|
a return of <returnvalue>0</returnvalue> (success) if
|
|
<emphasis>either</emphasis> of the linked test conditions
|
|
is true.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><token>&</token></term>
|
|
<listitem><formalpara><title>Run job in background</title>
|
|
<para>A command followed by an <token>&</token>
|
|
will run in the background.</para>
|
|
</formalpara>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>sleep 10 &</userinput>
|
|
<computeroutput>[1] 850</computeroutput>
|
|
<computeroutput>[1]+ Done sleep 10</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Within a script, commands and even <link
|
|
linkend="forloopref1">loops</link> may run in the
|
|
background.</para>
|
|
|
|
<example id="bgloop">
|
|
<title>Running a loop in the background</title>
|
|
<programlisting>&bgloop;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>A command run in the background within a
|
|
script may cause the script to hang, waiting
|
|
for a keystroke. Fortunately, there is a <link
|
|
linkend="waithang">remedy</link> for this.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><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>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dashref2"><token>-</token></term>
|
|
<indexterm>
|
|
<primary>-</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>-</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>redirection</primary>
|
|
<secondary>from/to stdin/stdout</secondary>
|
|
</indexterm>
|
|
<listitem><formalpara><title>redirection from/to <filename>stdin</filename> or <filename>stdout</filename> [dash]</title>
|
|
<para><anchor id="coxex"></para>
|
|
</formalpara>
|
|
|
|
|
|
<para><programlisting>(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)
|
|
# Move entire file tree from one directory to another
|
|
# [courtesy Alan Cox <a.cox@swansea.ac.uk>, with a minor change]
|
|
|
|
# 1) cd /source/directory Source directory, where the files to be moved are.
|
|
# 2) && "And-list": if the 'cd' operation successful, then execute the next command.
|
|
# 3) tar cf - . The 'c' option 'tar' archiving command creates a new archive,
|
|
# the 'f' (file) option, followed by '-' designates the target file as stdout,
|
|
# and do it in current directory tree ('.').
|
|
# 4) | Piped to...
|
|
# 5) ( ... ) a subshell
|
|
# 6) cd /dest/directory Change to the destination directory.
|
|
# 7) && "And-list", as above
|
|
# 8) tar xpvf - Unarchive ('x'), preserve ownership and file permissions ('p'),
|
|
# and send verbose messages to stdout ('v'),
|
|
# reading data from stdin ('f' followed by '-').
|
|
#
|
|
# Note that 'x' is a command, and 'p', 'v', 'f' are options.
|
|
# Whew!
|
|
|
|
|
|
|
|
# More elegant than, but equivalent to:
|
|
# cd source/directory
|
|
# tar cf - . | (cd ../dest/directory; tar xpvf -)
|
|
#
|
|
# cp -a /source/directory /dest/directory 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>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo "whatever" | cat -</userinput>
|
|
<computeroutput>whatever</computeroutput> </screen>
|
|
</para>
|
|
|
|
|
|
<para>Where a filename is expected,
|
|
<replaceable>-</replaceable> redirects output to
|
|
<filename>stdout</filename> (sometimes seen with
|
|
<userinput>tar cf</userinput>), or accepts input from
|
|
<filename>stdin</filename>, rather than from a file. This
|
|
is a method of using a file-oriented utility as a filter
|
|
in a pipe.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>file</userinput>
|
|
<computeroutput>Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...</computeroutput>
|
|
</screen>
|
|
|
|
By itself on the command line, <link
|
|
linkend="fileref">file</link> fails with an error message.
|
|
</para>
|
|
|
|
<para>
|
|
Add a <quote>-</quote> for a more useful result. This causes the
|
|
shell to await user input.
|
|
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>file -</userinput>
|
|
<userinput>abc</userinput>
|
|
<computeroutput>standard input: ASCII text</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>file -</userinput>
|
|
<userinput>#!/bin/bash</userinput>
|
|
<computeroutput>standard input: Bourne-Again shell script text executable</computeroutput>
|
|
</screen>
|
|
|
|
Now the command accepts input from <filename>stdin</filename>
|
|
and analyzes it.
|
|
</para>
|
|
|
|
<para>The <quote>-</quote> can be used to pipe
|
|
<filename>stdout</filename> to other commands. This permits
|
|
such stunts as <link linkend="prependref">prepending lines
|
|
to a file</link>.</para>
|
|
|
|
<para>Using <link linkend="diffref">diff</link> to
|
|
compare a file with a <emphasis>section</emphasis>
|
|
of another:</para>
|
|
|
|
<para><userinput>grep Linux file1 | diff file2 -</userinput></para>
|
|
|
|
|
|
<para>Finally, a real-world example using
|
|
<replaceable>-</replaceable> with <link
|
|
linkend="tarref">tar</link>.</para>
|
|
|
|
<example id="ex58">
|
|
<title>Backup of all files changed in last day</title>
|
|
<programlisting>&ex58;</programlisting>
|
|
</example>
|
|
|
|
<caution>
|
|
|
|
<para>Filenames beginning with
|
|
<quote>-</quote> may cause problems when coupled with the
|
|
<quote>-</quote> redirection operator. A script should
|
|
check for this and add an appropriate prefix to such
|
|
filenames, for example <filename>./-FILENAME</filename>,
|
|
<filename>$PWD/-FILENAME</filename>, or
|
|
<filename>$PATHNAME/-FILENAME</filename>.</para>
|
|
|
|
<para>If the value of a variable begins with a
|
|
<replaceable>-</replaceable>, this may likewise create
|
|
problems.
|
|
<programlisting>var="-n"
|
|
echo $var
|
|
# Has the effect of "echo -n", and outputs nothing.</programlisting>
|
|
</para>
|
|
</caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><token>-</token></term>
|
|
<listitem><formalpara><title>previous working directory</title>
|
|
<para>A <command>cd -</command> command changes to the
|
|
previous working directory. This uses the
|
|
<link linkend="oldpwd">$OLDPWD</link> <link
|
|
linkend="envref">environmental variable</link>.</para>
|
|
</formalpara>
|
|
<caution><para>Do not confuse the <quote>-</quote> used in this
|
|
sense with the <quote>-</quote> redirection
|
|
operator just discussed. The interpretation of the
|
|
<quote>-</quote> depends on the context in which it
|
|
appears.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-</token></term>
|
|
<listitem><formalpara><title>Minus</title>
|
|
<para>Minus sign in an <link linkend="arops1">arithmetic
|
|
operation</link>.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>=</token></term>
|
|
<listitem><formalpara><title>Equals</title>
|
|
<para><link linkend="eqref">Assignment operator</link>
|
|
<programlisting>a=28
|
|
echo $a # 28</programlisting></para>
|
|
</formalpara>
|
|
<para>In a <link linkend="equalsignref">different context</link>,
|
|
the <quote><token>=</token></quote> is a <link
|
|
linkend="scomparison1">string comparison</link>
|
|
operator.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>+</token></term>
|
|
<listitem><formalpara><title>Plus</title>
|
|
<para>Addition <link linkend="arops1">arithmetic
|
|
operator</link>.</para>
|
|
</formalpara>
|
|
<para>In a <link linkend="plusref">different context</link>,
|
|
the <token>+</token> is a <link linkend="regexp">Regular
|
|
Expression</link> operator.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>+</token></term>
|
|
<listitem><formalpara><title>Option</title>
|
|
<para>Option flag for a command or filter.</para>
|
|
</formalpara>
|
|
<para>Certain commands and <link
|
|
linkend="builtinref">builtins</link> use the
|
|
<token>+</token> to enable certain options and the
|
|
<token>-</token> to disable them.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
<varlistentry>
|
|
<term><token>~</token></term>
|
|
<listitem><formalpara><title>home directory [tilde]</title>
|
|
|
|
<para>This corresponds to the <link
|
|
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>
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
<para>Control characters are not normally useful inside a
|
|
script.</para>
|
|
|
|
|
|
<itemizedlist id="ctlchar">
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-B</userinput></para>
|
|
<para>Backspace (nondestructive).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-C</userinput></para>
|
|
<para>Break. Terminate a foreground job.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="ctldref"></para>
|
|
<para><userinput>Ctl-D</userinput></para>
|
|
<para>Log out from a shell (similar to
|
|
<link linkend="exitcommandref">exit</link>).</para>
|
|
<para><quote>EOF</quote> (end of file). This also
|
|
terminates input from <filename>stdin</filename>.</para>
|
|
<para>When typing text on the console or in an xterm window,
|
|
<userinput>Ctl-D</userinput> erases the character under the
|
|
cursor. When there are no characters present,
|
|
<userinput>Ctl-D</userinput> logs out of the session, as
|
|
expected.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-G</userinput></para>
|
|
<para><quote>BEL</quote> (beep).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-H</userinput></para>
|
|
<para><quote>Rubout</quote> (destructive backspace).</para>
|
|
<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>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-I</userinput></para>
|
|
<para>Horizontal tab.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-J</userinput></para>
|
|
<para>Newline (line feed).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-K</userinput></para>
|
|
<para>Vertical tab.</para>
|
|
<para>When typing text on the console or in an xterm window,
|
|
<userinput>Ctl-K</userinput> erases from the character
|
|
under the cursor to end of line.</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>Carriage return.</para>
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# Thank you, Lee Maschmeyer, for this example.
|
|
|
|
read -n 1 -s -p $'Control-M leaves cursor at beginning of this line. Press Enter. \x0d'
|
|
# Of course, '0d' is the hex equivalent of Control-M.
|
|
echo >&2 # The '-s' makes anything typed silent,
|
|
#+ so it is necessary to go to new line explicitly.
|
|
|
|
read -n 1 -s -p $'Control-J leaves cursor on next line. \x0a'
|
|
echo >&2 # Control-J is linefeed.
|
|
|
|
###
|
|
|
|
read -n 1 -s -p $'And Control-K\x0bgoes straight down.'
|
|
echo >&2 # Control-K is vertical tab.
|
|
|
|
# A better example of the effect of a vertical tab is:
|
|
|
|
var=$'\x0aThis is the bottom line\x0bThis is the top line\x0a'
|
|
echo "$var"
|
|
# This works the same way as the above example. However:
|
|
echo "$var" | col
|
|
# This causes the right end of the line to be higher than the left end.
|
|
# It also explains why we started and ended with a line feed --
|
|
#+ to avoid a garbled screen.
|
|
|
|
# As Lee Maschmeyer explains:
|
|
# --------------------------
|
|
# In the [first vertical tab example] . . . the vertical tab
|
|
#+ makes the printing go straight down without a carriage return.
|
|
# This is true only on devices, such as the Linux console,
|
|
#+ that can't go "backward."
|
|
# The real purpose of VT is to go straight UP, not down.
|
|
# It can be used to print superscripts on a printer.
|
|
# The col utility can be used to emulate the proper behavior of VT.
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-Q</userinput></para>
|
|
<para>Resume (XON).</para>
|
|
<para>This resumes <filename>stdin</filename> in a terminal.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-S</userinput></para>
|
|
<para>Suspend (XOFF).</para>
|
|
<para>This freezes <filename>stdin</filename> in a terminal.
|
|
(Use Ctl-Q to restore input.)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-U</userinput></para>
|
|
<para>Erase a line of input, from the cursor backward to
|
|
beginning of line. In some settings,
|
|
<userinput>Ctl-U</userinput> erases the entire
|
|
line of input, <emphasis>regardless of cursor
|
|
position</emphasis>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-V</userinput></para>
|
|
<para>When inputting text, <userinput>Ctl-V</userinput>
|
|
permits inserting control characters. For example, the
|
|
following two are equivalent:
|
|
<programlisting>echo -e '\x0a'
|
|
echo <Ctl-V><Ctl-J></programlisting></para>
|
|
<para><userinput>Ctl-V</userinput> is primarily useful from
|
|
within a text editor.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-W</userinput></para>
|
|
<para>When typing text on the console or in an xterm window,
|
|
<userinput>Ctl-W</userinput> erases from the character
|
|
under the cursor backwards to the first instance of
|
|
whitespace. In some settings, <userinput>Ctl-W</userinput>
|
|
erases backwards to first non-alphanumeric character.</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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
</chapter> <!-- Special characters used in shell scripts -->
|
|
|
|
|
|
|
|
<chapter id="variables">
|
|
<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
|
|
locations in computer memory holding an item of data.</para>
|
|
|
|
<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">
|
|
|
|
<varlistentry>
|
|
<term><token>$</token></term> <indexterm>
|
|
<primary>$</primary>
|
|
</indexterm> <indexterm>
|
|
<primary>variable</primary> <secondary>$</secondary>
|
|
</indexterm> <indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>substitution</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
|
|
<para>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
|
|
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>
|
|
|
|
|
|
<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>
|
|
|
|
<caution>
|
|
|
|
<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 usually cause problems.</para>
|
|
|
|
<para>It is nevertheless possible to perform arithmetic operations
|
|
on an uninitialized variable.
|
|
|
|
<programlisting>echo "$uninitialized" # (blank line)
|
|
let "uninitialized += 5" # Add 5 to it.
|
|
echo "$uninitialized" # 5
|
|
|
|
# Conclusion:
|
|
# An uninitialized variable has no value, however
|
|
#+ it acts as if it were 0 in an arithmetic operation.
|
|
# This is undocumented (and probably non-portable) behavior.</programlisting>
|
|
|
|
See also <xref linkend="selfsource">.</para>
|
|
|
|
</caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</sect1> <!-- Variable Substitution -->
|
|
|
|
|
|
<sect1 id="varassignment">
|
|
<title>Variable Assignment</title>
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term><anchor id="eqref"><token>=</token></term>
|
|
<indexterm>
|
|
<primary>=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>assignment</secondary>
|
|
</indexterm>
|
|
<listitem><para>the assignment operator (<emphasis>no space before &
|
|
after</emphasis>)</para>
|
|
|
|
|
|
<caution>
|
|
<para>Do not confuse this with <link
|
|
linkend="equalsignref">=</link> and <link
|
|
linkend="equalref">-eq</link>, which test, rather than
|
|
assign!</para>
|
|
|
|
<para>Note that <token>=</token> can be either an assignment
|
|
or a test operator, depending on context.</para>
|
|
</caution>
|
|
|
|
|
|
<example id="ex15">
|
|
<title>Plain Variable Assignment</title>
|
|
<programlisting>&ex15;</programlisting>
|
|
</example>
|
|
|
|
<example id="ex16">
|
|
<title>Variable Assignment, plain and fancy</title>
|
|
<programlisting>&ex16;</programlisting>
|
|
</example>
|
|
|
|
<para>Variable assignment using the <token>$(...)</token> mechanism
|
|
(a newer method than <link
|
|
linkend="backquotesref">backquotes</link>)</para>
|
|
|
|
<para><programlisting># From /etc/rc.d/rc.local
|
|
R=$(cat /etc/redhat-release)
|
|
arch=$(uname -m)</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Variable Assignment -->
|
|
|
|
<sect1 id="untyped">
|
|
<title>Bash Variables Are Untyped</title>
|
|
|
|
<para><anchor id="bvuntyped"></para>
|
|
<para>Unlike many other programming languages, Bash does not segregate
|
|
its variables by <quote>type</quote>. Essentially, 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-->
|
|
|
|
|
|
<sect1 id="othertypesv">
|
|
<title>Special Variable Types</title>
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
<term><replaceable>local variables</replaceable></term>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>local</secondary>
|
|
</indexterm>
|
|
|
|
<listitem><para>variables 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>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="envref"><replaceable>environmental variables</replaceable></term>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>environmental</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>variables that affect the behavior of the shell and
|
|
user interface</para>
|
|
|
|
<note>
|
|
|
|
<para>In a more general context, each 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 environmental 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>
|
|
|
|
<anchor id="childref">
|
|
<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><anchor id="posparamref1"><replaceable>positional parameters</replaceable></term>
|
|
<indexterm>
|
|
<primary>parameter</primary>
|
|
<secondary>positional</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>arguments passed to the script from the command
|
|
line - $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>
|
|
|
|
<anchor id="bracketnotation">
|
|
After $9, the arguments must be enclosed in brackets,
|
|
for example, ${10}, ${11}, ${12}.</para>
|
|
|
|
<para>The special variables <link linkend="appref">$* and $@</link>
|
|
denote <emphasis>all</emphasis> the positional parameters.</para>
|
|
|
|
<example id="ex17">
|
|
<title>Positional Parameters</title>
|
|
<programlisting>&ex17;</programlisting>
|
|
</example>
|
|
|
|
<para>The <emphasis>bracket notation</emphasis> for positional
|
|
parameters leads to a fairly simple way of referencing
|
|
the <emphasis>last</emphasis> argument passed to a
|
|
script on the command line. This also requires <link
|
|
linkend="varrefnew">indirect referencing</link>.</para>
|
|
|
|
<para><programlisting>args=$# # Number of args passed.
|
|
lastarg=${!args}
|
|
# Or: lastarg=${!#}
|
|
# (Thanks, Chris Monson.)
|
|
# Note that lastarg=${!$#} doesn't work.
|
|
</programlisting></para>
|
|
|
|
|
|
<para>Some scripts can perform different operations,
|
|
depending on which name they are invoked with. For this
|
|
to work, the script needs to check <varname>$0</varname>,
|
|
the name it was invoked by. There must also exist symbolic
|
|
links to all the alternate names of the script. See <xref
|
|
linkend="hellol">.</para>
|
|
|
|
<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>
|
|
|
|
<programlisting>variable1_=$1_
|
|
# This will prevent an error, even if positional parameter is absent.
|
|
|
|
critical_argument01=$variable1_
|
|
|
|
# The extra character can be stripped off later, if desired, like so.
|
|
variable1=${variable1_/_/} # Side effects only if $variable1_ begins with "_".
|
|
# This uses one of the parameter substitution templates discussed in Chapter 9.
|
|
# Leaving out the replacement pattern results in a deletion.
|
|
|
|
# A more straightforward way of dealing with this is
|
|
#+ to simply test whether expected positional parameters have been passed.
|
|
if [ -z $1 ]
|
|
then
|
|
exit $POS_PARAMS_MISSING
|
|
fi
|
|
</programlisting>
|
|
|
|
<para>---</para>
|
|
|
|
<example id="ex18">
|
|
<title><command>wh</command>, <link
|
|
linkend="whoisref">whois</link> domain name lookup</title>
|
|
<programlisting>&ex18;</programlisting>
|
|
</example>
|
|
|
|
<para>---</para>
|
|
|
|
<para><anchor id="shiftref"></para>
|
|
<para>
|
|
<indexterm>
|
|
<primary>shift</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>shift</secondary>
|
|
</indexterm>
|
|
The <command>shift</command> command reassigns the positional
|
|
parameters, in effect shifting them to the left one notch.</para>
|
|
|
|
<para><varname>$1</varname> <--- <varname>$2</varname>, <varname>$2</varname> <--- <varname>$3</varname>, <varname>$3</varname> <--- <varname>$4</varname>, etc.</para>
|
|
|
|
<para>The old <varname>$1</varname> disappears, but
|
|
<emphasis><varname>$0</varname> (the script name)
|
|
does not change</emphasis>. If you use a large number of
|
|
positional parameters to a script, <command>shift</command>
|
|
lets you access those past <literal>10</literal>, although
|
|
<link linkend="bracketnotation">{bracket} notation</link>
|
|
also permits this.</para>
|
|
|
|
<example id="ex19">
|
|
<title>Using <command>shift</command></title>
|
|
<programlisting>&ex19;</programlisting>
|
|
</example>
|
|
|
|
<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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Special Variable Types -->
|
|
|
|
|
|
</chapter> <!-- Variables -->
|
|
|
|
|
|
|
|
<chapter id="quoting">
|
|
<title>Quoting</title>
|
|
|
|
<para><anchor id="quotingref"></para>
|
|
|
|
<indexterm>
|
|
<primary>"</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>"</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>'</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>'</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>quote</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>\</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>\</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escape</primary>
|
|
</indexterm>
|
|
<para>Quoting means just that, bracketing a string in quotes. This
|
|
has the effect of protecting 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 reinterpret or expand
|
|
special characters in a quoted string. An important use of
|
|
quoting is protecting a command-line parameter from the shell,
|
|
but still letting the calling program expand it.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep '[Ff]irst' *.txt</userinput>
|
|
<computeroutput>file1.txt:This is the first line of file1.txt.
|
|
file2.txt:This is the First line of file2.txt.</computeroutput></screen>
|
|
</para>
|
|
|
|
<para>Note that the unquoted <userinput>grep [Ff]irst *.txt</userinput>
|
|
works under the Bash shell, but <emphasis>not</emphasis> under
|
|
<command>tcsh</command>.</para>
|
|
</note>
|
|
|
|
|
|
<para>When referencing a variable, it is generally advisable to
|
|
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).
|
|
|
|
<footnote>
|
|
|
|
<para>Encapsulating <quote>!</quote> within double
|
|
quotes gives an error when used <emphasis>from the command
|
|
line</emphasis>. This is interpreted as a <link
|
|
linkend="histcommands">history command</link>. Within a script,
|
|
though, this problem does not occur, since the Bash history
|
|
mechanism is disabled then.</para>
|
|
|
|
<para>Of more concern is the inconsistent behavior of
|
|
<quote>\</quote> within double quotes.
|
|
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo hello\!</userinput>
|
|
<computeroutput>hello!</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo "hello\!"</userinput>
|
|
<computeroutput>hello\!</computeroutput>
|
|
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -e x\ty</userinput>
|
|
<computeroutput>xty</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -e "x\ty"</userinput>
|
|
<computeroutput>x y</computeroutput>
|
|
</screen>
|
|
|
|
(Thank you, Wayne Pollock, for pointing this out.)
|
|
</para>
|
|
|
|
</footnote>
|
|
|
|
Keeping <token>$</token> as a special character within
|
|
double quotes permits referencing a quoted variable
|
|
(<replaceable>"$variable"</replaceable>), that is, replacing the
|
|
variable with its value (see <xref linkend="ex9">, above).</para>
|
|
|
|
<para>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>
|
|
|
|
<variablelist id="specialmeanings">
|
|
<title><anchor id="spm">Special meanings of certain
|
|
escaped characters</title>
|
|
|
|
<varlistentry>
|
|
<term>used with <command>echo</command> and
|
|
<command>sed</command></term>
|
|
<listitem><para></para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\n</token></term>
|
|
<indexterm>
|
|
<primary>\n</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\n</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>newline</primary>
|
|
</indexterm>
|
|
<listitem><para>means newline</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\r</token></term>
|
|
<indexterm>
|
|
<primary>\r</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\r</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>carriage return</primary>
|
|
</indexterm>
|
|
<listitem><para>means return</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\t</token></term>
|
|
<indexterm>
|
|
<primary>\t</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\t</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>tabulation</primary>
|
|
</indexterm>
|
|
<listitem><para>means tab</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\v</token></term>
|
|
<indexterm>
|
|
<primary>\v</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\v</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>vertical tabulation</primary>
|
|
</indexterm>
|
|
<listitem><para> means vertical tab</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\b</token></term>
|
|
<indexterm>
|
|
<primary>\b</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\b</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>backspace</primary>
|
|
</indexterm>
|
|
<listitem><para>means backspace</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\a</token></term>
|
|
<indexterm>
|
|
<primary>\a</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\a</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>alert</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>beep</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>flash</primary>
|
|
</indexterm>
|
|
<listitem><para>means <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 \
|
|
|
|
# Whereas . . .
|
|
|
|
echo "\" # Invokes secondary prompt from the command line.
|
|
# In a script, gives an error message.</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<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
|
|
linkend="heredocref">here document</link>.
|
|
|
|
<programlisting> # Simple escaping and quoting
|
|
echo \z # z
|
|
echo \\z # \z
|
|
echo '\z' # \z
|
|
echo '\\z' # \\z
|
|
echo "\z" # \z
|
|
echo "\\z" # \z
|
|
|
|
# Command substitution
|
|
echo `echo \z` # z
|
|
echo `echo \\z` # z
|
|
echo `echo \\\z` # \z
|
|
echo `echo \\\\z` # \z
|
|
echo `echo \\\\\\z` # \z
|
|
echo `echo \\\\\\\z` # \\z
|
|
echo `echo "\z"` # \z
|
|
echo `echo "\\z"` # \z
|
|
|
|
# Here document
|
|
cat <<EOF
|
|
\z
|
|
EOF # \z
|
|
|
|
cat <<EOF
|
|
\\z
|
|
EOF # \z
|
|
|
|
# These examples supplied by Stephane Chazelas.</programlisting>
|
|
</para>
|
|
|
|
<para>Elements of a string assigned to a variable may be escaped, but
|
|
the escape character alone may not be assigned to a variable.
|
|
<programlisting>variable=\
|
|
echo "$variable"
|
|
# Will not work - gives an error message:
|
|
# test.sh: : command not found
|
|
# A "naked" escape cannot safely be assigned to a variable.
|
|
#
|
|
# What actually happens here is that the "\" escapes the newline and
|
|
#+ the effect is variable=echo "$variable"
|
|
#+ invalid variable assignment
|
|
|
|
variable=\
|
|
23skidoo
|
|
echo "$variable" # 23skidoo
|
|
# This works, since the second line
|
|
#+ is a valid variable assignment.
|
|
|
|
variable=\
|
|
# \^ escape followed by space
|
|
echo "$variable" # space
|
|
|
|
variable=\\
|
|
echo "$variable" # \
|
|
|
|
variable=\\\
|
|
echo "$variable"
|
|
# Will not work - gives an error message:
|
|
# test.sh: \: command not found
|
|
#
|
|
# First escape escapes second one, but the third one is left "naked",
|
|
#+ with same result as first instance, above.
|
|
|
|
variable=\\\\
|
|
echo "$variable" # \\
|
|
# Second and fourth escapes escaped.
|
|
# This is o.k.</programlisting>
|
|
</para>
|
|
|
|
</note>
|
|
|
|
|
|
|
|
<para>Escaping a space can prevent word splitting in a command's argument list.
|
|
<programlisting>file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
|
|
# List of files as argument(s) to a command.
|
|
|
|
# Add two files to the list, and list all.
|
|
ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list
|
|
|
|
echo "-------------------------------------------------------------------------"
|
|
|
|
# What happens if we escape a couple of spaces?
|
|
ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
|
|
# Error: the first three files concatenated into a single argument to 'ls -l'
|
|
# because the two escaped spaces prevent argument (word) splitting.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>The <token>escape</token> also provides a means of writing a
|
|
multi-line command. Normally, each separate line constitutes
|
|
a different command, but an <token>escape</token> at the end
|
|
of a line <emphasis>escapes the newline character</emphasis>,
|
|
and the command sequence continues on to the next line.</para>
|
|
<para><programlisting>(cd /source/directory && tar cf - . ) | \
|
|
(cd /dest/directory && tar xpvf -)
|
|
# Repeating Alan Cox's directory tree copy command,
|
|
# but split into two lines for increased legibility.
|
|
|
|
# As an alternative:
|
|
tar cf - -C /source/directory . |
|
|
tar xpvf - -C /dest/directory
|
|
# See note below.
|
|
# (Thanks, 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.
|
|
#foo\
|
|
#bar
|
|
|
|
# Examples suggested by Stephane Chazelas.</programlisting></para>
|
|
|
|
|
|
|
|
</chapter> <!-- Quoting -->
|
|
|
|
|
|
<chapter id="exit-status">
|
|
<title>Exit and Exit Status</title>
|
|
|
|
<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
|
|
<userinput>exit <replaceable>nnn</replaceable></userinput>
|
|
command may be used to deliver an
|
|
<returnvalue><replaceable>nnn</replaceable></returnvalue> exit status
|
|
to the shell (<returnvalue><replaceable>nnn</replaceable></returnvalue>
|
|
must be a decimal number in the <returnvalue>0</returnvalue> -
|
|
<returnvalue>255</returnvalue> range).</para>
|
|
|
|
<note>
|
|
|
|
<para>When a script ends with an <command>exit</command> that has
|
|
no parameter, the exit status of the script is the exit status of
|
|
the last command executed in the script (<emphasis>not</emphasis>
|
|
counting the <command>exit</command>).</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
COMMAND_1
|
|
|
|
. . .
|
|
|
|
# Will exit with status of last command.
|
|
COMMAND_LAST
|
|
|
|
exit</programlisting></para>
|
|
|
|
<para>The equivalent of a bare <command>exit</command> is
|
|
<command>exit $?</command> or even just omitting the
|
|
<command>exit</command>.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
COMMAND_1
|
|
|
|
. . .
|
|
|
|
# Will exit with status of last command.
|
|
COMMAND_LAST
|
|
|
|
exit $?</programlisting></para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
COMMAND1
|
|
|
|
. . .
|
|
|
|
# Will exit with status of last command.
|
|
COMMAND_LAST</programlisting></para>
|
|
|
|
</note>
|
|
|
|
<para><anchor id="exsref"></para>
|
|
|
|
<para>
|
|
<varname>
|
|
<indexterm>
|
|
<primary>$?</primary>
|
|
</indexterm> <indexterm>
|
|
<primary>variable</primary> <secondary>$?</secondary>
|
|
</indexterm> $?</varname> reads the exit status of the last
|
|
command executed. After a function returns,
|
|
<varname>$?</varname> gives the exit status of the last
|
|
command executed in the function. This is Bash's way of
|
|
giving functions a <quote>return value</quote>. After a
|
|
script terminates, a <varname>$?</varname> from the command
|
|
line gives the exit status of the script, that is, the last
|
|
command executed in the script, which is, by convention,
|
|
<userinput>0</userinput> on success or an integer in the
|
|
range 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
|
|
#
|
|
# The '!' operator prefixing a command invokes the Bash history mechanism.
|
|
|
|
true
|
|
!true
|
|
# No error this time, but no negation either.
|
|
# It just repeats the previous command (true).
|
|
|
|
# Thanks, Stephane Chazelas and Kristopher Newsome.</programlisting>
|
|
</example>
|
|
|
|
</para>
|
|
</note>
|
|
|
|
|
|
<caution><para>Certain exit status codes have <link
|
|
linkend="exitcodesref">reserved meanings</link> and should not
|
|
be user-specified in a script. </para></caution>
|
|
|
|
|
|
</chapter> <!-- Exit and Exit status -->
|
|
|
|
|
|
<chapter id="tests">
|
|
<title>Tests</title>
|
|
|
|
<para><anchor id="ifthen"></para>
|
|
|
|
<indexterm>
|
|
<primary>if</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
<secondary>if</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>then</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>else if</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>elif</primary>
|
|
</indexterm>
|
|
|
|
<para>Every reasonably complete programming language can test
|
|
for a condition, then act according to the result of
|
|
the test. Bash has the <command>test</command> command,
|
|
various bracket and parenthesis operators, and the
|
|
<command>if/then</command> construct.</para>
|
|
|
|
<sect1 id="testconstructs">
|
|
<title>Test Constructs</title>
|
|
|
|
<para><anchor id="testconstructs1"></para>
|
|
|
|
<itemizedlist id="testingref">
|
|
|
|
<listitem>
|
|
<para>An <command>if/then</command> construct tests whether the
|
|
<link linkend="exitstatusref">exit status</link> of a list
|
|
of commands is <returnvalue>0</returnvalue> (since 0 means
|
|
<quote>success</quote> by UNIX convention), and if so, executes
|
|
one or more commands.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>There exists a dedicated command called <command>
|
|
[</command> (<link linkend="leftbracket">left bracket</link>
|
|
special character). It is a synonym for <command>test</command>,
|
|
and a <link linkend="builtinref">builtin</link> for efficiency
|
|
reasons. This command considers its arguments as comparison
|
|
expressions or file tests and returns an exit status corresponding
|
|
to the result of the comparison (0 for true, 1 for false).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>With version 2.02, Bash introduced the <link
|
|
linkend="dblbrackets">[[ ... ]]</link> <emphasis>extended
|
|
test command</emphasis>, which performs comparisons
|
|
in a manner more familiar to programmers from other
|
|
languages. Note that <command>[[</command> is a <link
|
|
linkend="keywordref">keyword</link>, not a command.</para>
|
|
|
|
<para>Bash sees <userinput>[[ $a -lt $b ]]</userinput> as a
|
|
single element, which returns an exit status.</para>
|
|
|
|
<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<2" returns 0 (as "1<2" expands to "1")
|
|
(( 0 && 1 )) returns 1 (as "0 && 1" expands to "0")</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="ifgrepref"></para>
|
|
|
|
<para>An <command>if</command> can test any command, not just
|
|
conditions enclosed within brackets.
|
|
|
|
|
|
<programlisting>if cmp a b &> /dev/null # Suppress output.
|
|
then echo "Files a and b are identical."
|
|
else echo "Files a and b differ."
|
|
fi
|
|
|
|
# The very useful "if-grep" construct:
|
|
# -----------------------------------
|
|
if grep -q Bash file
|
|
then echo "File contains at least one occurrence of Bash."
|
|
fi
|
|
|
|
word=Linux
|
|
letter_sequence=inu
|
|
if echo "$word" | grep -q "$letter_sequence"
|
|
# The "-q" option to grep suppresses output.
|
|
then
|
|
echo "$letter_sequence found in $word"
|
|
else
|
|
echo "$letter_sequence not found in $word"
|
|
fi
|
|
|
|
|
|
if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED
|
|
then echo "Command succeeded."
|
|
else echo "Command failed."
|
|
fi</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>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>
|
|
|
|
<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>
|
|
|
|
<para><programlisting>if [ -x "$filename" ]; then</programlisting></para>
|
|
</note>
|
|
|
|
<variablelist id="elifref">
|
|
<title><anchor id="elifref1">Else if and elif</title>
|
|
<varlistentry>
|
|
<term><token>elif</token></term>
|
|
<listitem>
|
|
<para><userinput>elif</userinput> is a contraction
|
|
for <token>else if</token>. The effect is to nest an
|
|
inner <token>if/then</token> construct within an outer
|
|
one.</para>
|
|
|
|
<para><programlisting>if [ condition1 ]
|
|
then
|
|
command1
|
|
command2
|
|
command3
|
|
elif [ condition2 ]
|
|
# Same as else if
|
|
then
|
|
command4
|
|
command5
|
|
else
|
|
default-command
|
|
fi</programlisting>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<para>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
<secondary>test</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>[</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>[</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>]</secondary>
|
|
</indexterm>
|
|
|
|
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
|
|
<filename>/usr/bin/test</filename>.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>type test</userinput>
|
|
<computeroutput>test is a shell builtin</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type '['</userinput>
|
|
<computeroutput>[ is a shell builtin</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type '[['</userinput>
|
|
<computeroutput>[[ is a shell keyword</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type ']]'</userinput>
|
|
<computeroutput>]] is a shell keyword</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type ']'</userinput>
|
|
<computeroutput>bash: type: ]: not found</computeroutput>
|
|
</screen>
|
|
</para></note>
|
|
|
|
|
|
<example id="ex11">
|
|
<title>Equivalence of <token>test</token>,
|
|
<filename>/usr/bin/test</filename>, <token>[ ]</token>,
|
|
and <filename>/usr/bin/[</filename></title>
|
|
<programlisting>&ex11;</programlisting>
|
|
</example>
|
|
|
|
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
<secondary>test</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>[[</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>[[</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>]]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>]]</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="dblbrackets">The <token>[[ ]]</token> construct
|
|
is the more versatile Bash version 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>
|
|
|
|
<para>
|
|
<programlisting>file=/etc/passwd
|
|
|
|
if [[ -e $file ]]
|
|
then
|
|
echo "Password file exists."
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
<tip>
|
|
<para>Using the <command>[[ ... ]]</command> test construct,
|
|
rather than <command>[ ... ]</command> can prevent many
|
|
logic errors in scripts. For example, the <token>&&</token>,
|
|
<token>||</token>, <token><</token>, and <token>></token>
|
|
operators work within a <token>[[ ]]</token> test, despite
|
|
giving an error within a <token>[ ]</token> construct.</para>
|
|
</tip>
|
|
|
|
<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>/dev/null; then # "2>/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>
|
|
|
|
</sect1> <!-- Test Constructs -->
|
|
|
|
|
|
<sect1 id="fto">
|
|
<title>File test operators</title>
|
|
|
|
<variablelist>
|
|
<title><anchor id="rtif">Returns true if...</title>
|
|
<varlistentry>
|
|
<term><token>-e</token></term>
|
|
<listitem><para>file exists</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-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 <link linkend="socketref">socket</link></para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-t</token></term>
|
|
<listitem>
|
|
<para>file (<link linkend="fdref">descriptor</link>) is
|
|
associated with a terminal device</para>
|
|
<para>This test option may be used to check whether the
|
|
<filename>stdin</filename> (<userinput>[ -t 0 ]</userinput>)
|
|
or <filename>stdout</filename> (<userinput>[ -t 1 ]</userinput>)
|
|
in a given script is a terminal.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-r</token></term>
|
|
<listitem><para>file has read permission (<emphasis>for the
|
|
user running the test</emphasis>)</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-w</token></term>
|
|
<listitem><para>file has write permission (for the user running
|
|
the test)</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-x</token></term>
|
|
<listitem><para>file has execute permission (for the user running
|
|
the test)</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-g</token></term>
|
|
<listitem>
|
|
<para>set-group-id (sgid) flag set on file or directory</para>
|
|
<para>If a directory has the <replaceable>sgid</replaceable>
|
|
flag set, then a file created within that directory belongs
|
|
to the group that owns the directory, not necessarily to
|
|
the group of the user who created the file. This may be
|
|
useful for a directory shared by a workgroup.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-u</token></term>
|
|
<listitem>
|
|
<para>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
|
|
<emphasis>suid</emphasis> flag has no effect on
|
|
shell scripts.</para></footnote>
|
|
|
|
This is useful for executables (such as
|
|
<command>pppd</command> and <command>cdrecord</command>)
|
|
that need to access system hardware. Lacking the
|
|
<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>
|
|
|
|
<example id="brokenlink">
|
|
<title>Testing for broken links</title>
|
|
<programlisting>&brokenlink;</programlisting>
|
|
</example>
|
|
|
|
<para><xref linkend="cookies">, <xref linkend="bingrep">,
|
|
<xref linkend="fileinfo">, <xref linkend="ramdisk">, and <xref
|
|
linkend="mailformat"> also illustrate uses of the file test
|
|
operators.</para>
|
|
|
|
|
|
</sect1> <!-- File test operators -->
|
|
|
|
<sect1 id="comparison-ops">
|
|
<title>Other Comparison Operators</title>
|
|
|
|
<para>A <emphasis>binary</emphasis> comparison operator compares two
|
|
variables or quantities. Note the separation between integer and
|
|
string comparison.</para>
|
|
|
|
<variablelist id="icomparison">
|
|
<title><anchor id="icomparison1">integer comparison</title>
|
|
|
|
<varlistentry>
|
|
<term><token>-eq</token></term>
|
|
<listitem>
|
|
<para><anchor id="equalref"></para>
|
|
<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>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="intlt"><token><</token></term>
|
|
<listitem>
|
|
<para>is less than (within <link linkend="dblparens">double
|
|
parentheses</link>)</para>
|
|
<para><userinput>(("$a" < "$b"))</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token><=</token></term>
|
|
<listitem>
|
|
<para>is less than or equal to (within double parentheses)</para>
|
|
<para><userinput>(("$a" <= "$b"))</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>></token></term>
|
|
<listitem>
|
|
<para>is greater than (within double parentheses)</para>
|
|
<para><userinput>(("$a" > "$b"))</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>>=</token></term>
|
|
<listitem>
|
|
<para>is greater than or equal to (within double parentheses)</para>
|
|
<para><userinput>(("$a" >= "$b"))</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="scomparison">
|
|
<title><anchor id="scomparison1">string comparison</title>
|
|
<varlistentry>
|
|
<term><token>=</token></term>
|
|
<listitem>
|
|
<para><anchor id="equalsignref"></para>
|
|
<para>is equal to</para>
|
|
<para><userinput>if [ "$a" = "$b" ]</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>==</token></term>
|
|
<listitem>
|
|
<para>is equal to</para>
|
|
<para><userinput>if [ "$a" == "$b" ]</userinput></para>
|
|
<para>This is a synonym for <token>=</token>.</para>
|
|
|
|
<note><para>
|
|
The <token>==</token> comparison operator behaves differently
|
|
within a <link linkend="dblbrackets">double-brackets</link>
|
|
test than within single brackets.
|
|
<programlisting>[[ $a == z* ]] # True if $a starts with an "z" (pattern matching).
|
|
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
|
|
|
|
[ $a == z* ] # File globbing and word splitting take place.
|
|
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).
|
|
|
|
# Thanks, Stephane Chazelas</programlisting>
|
|
</para></note>
|
|
|
|
</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>
|
|
<term><anchor id="ltref"><token><</token></term>
|
|
<listitem>
|
|
<para>is less than, in ASCII alphabetical order</para>
|
|
<para><userinput>if [[ "$a" < "$b" ]]</userinput></para>
|
|
<para><userinput>if [ "$a" \< "$b" ]</userinput></para>
|
|
<para>Note that the <quote><</quote> needs to be
|
|
escaped within a <userinput>[ ]</userinput>
|
|
construct.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="gtref"><token>></token></term>
|
|
<listitem>
|
|
<para>is greater than, in ASCII alphabetical order</para>
|
|
<para><userinput>if [[ "$a" > "$b" ]]</userinput></para>
|
|
<para><userinput>if [ "$a" \> "$b" ]</userinput></para>
|
|
<para>Note that the <quote>></quote> needs to be
|
|
escaped within a <userinput>[ ]</userinput> construct.</para>
|
|
<para>See <xref linkend="bubble"> for an application of this
|
|
comparison operator.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>zmore</command></title>
|
|
<programlisting>&ex14;</programlisting>
|
|
</example>
|
|
|
|
<variablelist id="ccomparison">
|
|
<title><anchor id="ccomparison1">compound comparison</title>
|
|
|
|
<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
|
|
single test brackets.
|
|
<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>
|
|
|
|
</sect1> <!-- Comparison operators (binary) -->
|
|
|
|
<sect1 id="nestedifthen">
|
|
<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>
|
|
|
|
</sect1> <!-- Nested if/then Tests -->
|
|
|
|
<sect1 id="testtest">
|
|
<title>Testing Your Knowledge of Tests</title>
|
|
<para>The systemwide <filename>xinitrc</filename> file can be used
|
|
to launch the X server. This file contains quite a number of
|
|
<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 -->
|
|
|
|
</chapter> <!-- Tests -->
|
|
|
|
|
|
|
|
<chapter id="operations">
|
|
<title>Operations and Related Topics</title>
|
|
|
|
|
|
<sect1 id="ops">
|
|
<title>Operators</title>
|
|
|
|
<variablelist id="asnop">
|
|
<title><anchor id="asnop1">assignment</title>
|
|
|
|
<varlistentry>
|
|
<term><replaceable>variable assignment</replaceable></term>
|
|
<listitem><para>Initializing or changing the value of a variable</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<indexterm>
|
|
<primary>=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>=</secondary>
|
|
</indexterm>
|
|
<term>=</term>
|
|
<listitem>
|
|
<para>All-purpose assignment operator, which works for both
|
|
arithmetic and string assignments.</para>
|
|
|
|
<para>
|
|
<programlisting>var=27
|
|
category=minerals # No spaces allowed after the "=".</programlisting>
|
|
</para>
|
|
|
|
<caution>
|
|
<para>Do not confuse the <quote>=</quote> assignment
|
|
operator with the <link linkend="equalsignref">=</link> test
|
|
operator.</para>
|
|
|
|
<para>
|
|
<programlisting># = as a test operator
|
|
|
|
if [ "$string1" = "$string2" ]
|
|
# if [ "X$string1" = "X$string2" ] is safer,
|
|
# to prevent an error message should one of the variables be empty.
|
|
# (The prepended "X" characters cancel out.)
|
|
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>
|
|
|
|
|
|
<variablelist id="arops">
|
|
<title><anchor id="arops1">arithmetic operators</title>
|
|
|
|
<varlistentry>
|
|
<term><token>+</token></term>
|
|
<indexterm>
|
|
<primary>+</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>+</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>addition</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>plus</primary>
|
|
</indexterm>
|
|
<listitem><para>plus</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-</token></term>
|
|
<indexterm>
|
|
<primary>-</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>-</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>subtraction</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>minus</primary>
|
|
</indexterm>
|
|
<listitem><para>minus</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>*</token></term>
|
|
<indexterm>
|
|
<primary>*</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>*</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>multiplication</primary>
|
|
</indexterm>
|
|
<listitem><para>multiplication</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>/</token></term>
|
|
<indexterm>
|
|
<primary>/</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>/</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>division</primary>
|
|
</indexterm>
|
|
<listitem><para>division</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="exponentiationref"><token>**</token></term>
|
|
<indexterm>
|
|
<primary>**</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>**</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>exponentiation</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>exponentiation
|
|
<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>
|
|
<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
|
|
linkend="ex21"> and <xref linkend="randomtest">) and
|
|
formatting program output (see <xref linkend="qfunction"> and
|
|
<xref linkend="collatz">). It can even be used to generate
|
|
prime numbers, (see <xref linkend="primes">). Modulo turns
|
|
up surprisingly often in various numerical recipes.</para>
|
|
|
|
<example id="gcd">
|
|
<title>Greatest common divisor</title>
|
|
<programlisting>&gcd;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
<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>
|
|
|
|
<para>As of version 2.05b, Bash supports 64-bit integers.</para>
|
|
</note>
|
|
|
|
<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 <link linkend="socketref">sockets</link>. <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>
|
|
|
|
<variablelist id="bitwsops">
|
|
<title><anchor id="bitwsops1">bitwise operators</title>
|
|
|
|
<varlistentry>
|
|
<term><token><<</token></term>
|
|
<indexterm>
|
|
<primary><<</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary><<</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>left shift</primary>
|
|
</indexterm>
|
|
<listitem><para>bitwise left shift (multiplies by <literal>2</literal>
|
|
for each shift position)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token><<=</token></term>
|
|
<indexterm>
|
|
<primary><<=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary><<=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>left-shift-equal</primary>
|
|
</indexterm>
|
|
<listitem><para><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>
|
|
<secondary>&</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>AND</primary>
|
|
<secondary>bitwise</secondary>
|
|
</indexterm>
|
|
<listitem><para>bitwise and</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>&=</token></term>
|
|
<indexterm>
|
|
<primary>&=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>&=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>and-equal</primary>
|
|
</indexterm>
|
|
<listitem><para><quote>bitwise and-equal</quote></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>|</token></term>
|
|
<indexterm>
|
|
<primary>|</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>|</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>OR</primary>
|
|
<secondary>bitwise</secondary>
|
|
</indexterm>
|
|
<listitem><para>bitwise OR</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>|=</token></term>
|
|
<indexterm>
|
|
<primary>|=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>|=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>OR-equal</primary>
|
|
</indexterm>
|
|
<listitem><para><quote>bitwise OR-equal</quote></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>~</token></term>
|
|
<indexterm>
|
|
<primary>~</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>~</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>negate</primary>
|
|
</indexterm>
|
|
<listitem><para>bitwise negate</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>!</token></term>
|
|
<indexterm>
|
|
<primary>!</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>!</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>NOT</primary>
|
|
</indexterm>
|
|
<listitem><para>bitwise NOT</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>^</token></term>
|
|
<indexterm>
|
|
<primary>^</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>^</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>XOR</primary>
|
|
</indexterm>
|
|
<listitem><para>bitwise XOR</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>^=</token></term>
|
|
<indexterm>
|
|
<primary>^=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>^=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>XOR-equal</primary>
|
|
</indexterm>
|
|
<listitem><para><quote>bitwise XOR-equal</quote></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="logops">
|
|
<title><anchor id="logops1">logical operators</title>
|
|
|
|
<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 ]
|
|
# Same as: if [ $condition1 -a $condition2 ]
|
|
# Returns true if both condition1 and condition2 hold true...
|
|
|
|
if [[ $condition1 && $condition2 ]] # Also works.
|
|
# Note that && operator not permitted within [ ... ] construct.</programlisting></para>
|
|
|
|
<note><para><token>&&</token> may also, depending on context, be
|
|
used in an <link linkend="listconsref">and list</link>
|
|
to concatenate commands.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="orref"><token>||</token></term>
|
|
<indexterm>
|
|
<primary>||</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operator</primary>
|
|
<secondary>||</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>OR</primary>
|
|
<secondary>logical</secondary>
|
|
</indexterm>
|
|
<listitem><para>or (logical)</para>
|
|
<para><programlisting>if [ $condition1 ] || [ $condition2 ]
|
|
# Same as: if [ $condition1 -o $condition2 ]
|
|
# Returns true if either condition1 or condition2 holds true...
|
|
|
|
if [[ $condition1 || $condition2 ]] # Also works.
|
|
# Note that || operator not permitted within [ ... ] construct.</programlisting></para>
|
|
|
|
<note><para>Bash tests the <link linkend="exitstatusref">exit
|
|
status</link> of each statement linked with a logical
|
|
operator.</para></note>
|
|
|
|
<example id="andor">
|
|
<title>Compound Condition Tests Using && and ||</title>
|
|
<programlisting>&andor;</programlisting>
|
|
</example>
|
|
|
|
<para>The <token>&&</token> and <token>||</token> operators also
|
|
find use in an arithmetic context.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo $(( 1 && 2 )) $((3 && 0)) $((4 || 0)) $((0 || 0))</userinput>
|
|
<computeroutput>1 0 1 0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="miscop">
|
|
<title><anchor id="miscop1">miscellaneous operators</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="commaop"><token>,</token></term>
|
|
<indexterm>
|
|
<primary>,</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>,</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>linking</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>comma operator</para>
|
|
<para>The <command>comma operator</command> chains together
|
|
two or more arithmetic operations. All the operations are
|
|
evaluated (with possible <emphasis>side effects</emphasis>),
|
|
but only the last operation is returned.</para>
|
|
|
|
<para>
|
|
<programlisting>let "t1 = ((5 + 3, 7 - 1, 15 - 4))"
|
|
echo "t1 = $t1" # t1 = 11
|
|
|
|
let "t2 = ((a = 9, 15 / 3))" # Set "a" and calculate "t2".
|
|
echo "t2 = $t2 a = $a" # t2 = 5 a = 9</programlisting>
|
|
</para>
|
|
|
|
<para>The comma operator finds use mainly in <link
|
|
linkend="forloopref1">for loops</link>. See <xref
|
|
linkend="forloopc">.</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Operators -->
|
|
|
|
<sect1 id="Numerical-Constants">
|
|
<title>Numerical Constants</title>
|
|
|
|
<para><anchor id="numconstants">A shell script interprets a number
|
|
as decimal (base 10), unless that number has a
|
|
special prefix or notation. A number preceded by a
|
|
<replaceable>0</replaceable> is <replaceable>octal</replaceable>
|
|
(base 8). A number preceded by <replaceable>0x</replaceable>
|
|
is <replaceable>hexadecimal</replaceable> (base 16). A number
|
|
with an embedded <replaceable>#</replaceable> evaluates as
|
|
<replaceable>BASE#NUMBER</replaceable> (with range and notational
|
|
restrictions).</para>
|
|
|
|
<example id="numbers">
|
|
<title>Representation of numerical constants</title>
|
|
<programlisting>&numbers;</programlisting>
|
|
</example>
|
|
|
|
</sect1> <!-- Numerical-Constants -->
|
|
|
|
</chapter> <!-- Operations -->
|
|
|
|
</part> <!-- Part 2 (Basics) -->
|
|
|
|
|
|
|
|
<part label="Part 3" id="part3">
|
|
<title>Beyond the Basics</title>
|
|
|
|
<chapter id="variables2">
|
|
<title>Variables Revisited</title>
|
|
|
|
|
|
<para>Used properly, variables can add power and flexibility
|
|
to scripts. This requires learning their subtleties and
|
|
nuances.</para>
|
|
|
|
|
|
<sect1 id="internalvariables">
|
|
<title>Internal Variables</title>
|
|
|
|
<variablelist id="internalvariables1">
|
|
|
|
<varlistentry>
|
|
<term><replaceable><link
|
|
linkend="builtinref">Builtin</link> variables</replaceable></term>
|
|
<listitem><para>variables affecting bash script behavior</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
binary itself
|
|
<screen><prompt>bash$ </prompt><userinput>echo $BASH</userinput>
|
|
<computeroutput>/bin/bash</computeroutput></screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$BASH_ENV</varname></term>
|
|
<indexterm>
|
|
<primary>$BASH_ENV</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$BASH_ENV</secondary>
|
|
</indexterm>
|
|
<listitem><para>an <link linkend="envref">environmental
|
|
variable</link> pointing to a Bash startup file to be read
|
|
when a script is invoked</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="bashsubshellref"><varname>$BASH_SUBSHELL</varname></term>
|
|
<indexterm>
|
|
<primary>$BASH_SUBSHELL</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>subshell</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>a variable indicating the <link
|
|
linkend="subshellsref">subshell</link> level. This is a
|
|
new addition to <link linkend="bash3ref">Bash, version 3</link>.</para>
|
|
<para>See <xref linkend="subshell"> for usage.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$BASH_VERSINFO[n]</varname></term>
|
|
<indexterm>
|
|
<primary>$BASH_VERSINFO</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>version information</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>a 6-element <link linkend="arrayref">array</link>
|
|
containing version information about the installed release
|
|
of Bash. This is similar to <varname>$BASH_VERSION</varname>,
|
|
below, but a bit more detailed.</para>
|
|
<para>
|
|
<programlisting># Bash version info:
|
|
|
|
for n in 0 1 2 3 4 5
|
|
do
|
|
echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"
|
|
done
|
|
|
|
# BASH_VERSINFO[0] = 2 # Major version no.
|
|
# BASH_VERSINFO[1] = 05 # Minor version no.
|
|
# BASH_VERSINFO[2] = 8 # Patch level.
|
|
# BASH_VERSINFO[3] = 1 # Build version.
|
|
# BASH_VERSINFO[4] = release # Release status.
|
|
# BASH_VERSINFO[5] = i386-redhat-linux-gnu # Architecture
|
|
# (same as $MACHTYPE).</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$BASH_VERSION</varname></term>
|
|
<indexterm>
|
|
<primary>$BASH_VERSION</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$BASH_VERSION</secondary>
|
|
</indexterm>
|
|
<listitem><para>the version of Bash installed on the system</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
|
|
<computeroutput>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
|
|
shell is running. <link linkend="shellvarref">$SHELL</link>
|
|
does not necessarily give the correct answer.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dirstackref"><varname>$DIRSTACK</varname></term>
|
|
<indexterm>
|
|
<primary>$DIRSTACK</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$DIRSTACK</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>directory stack</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>directory</primary>
|
|
<secondary>stack</secondary>
|
|
</indexterm>
|
|
<listitem><para>the top value in the directory stack
|
|
(affected by <link linkend="pushdref">pushd</link> and <link
|
|
linkend="popdref">popd</link>)</para> <para>This builtin
|
|
variable corresponds to the <link linkend="dirsd">dirs</link>
|
|
command, however <command>dirs</command> shows the entire
|
|
contents of the directory stack.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$EDITOR</varname></term>
|
|
<indexterm>
|
|
<primary>$EDITOR</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$EDITOR</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>editor</primary>
|
|
</indexterm>
|
|
<listitem><para>the default editor invoked by a script, usually
|
|
<command>vi</command> or <command>emacs</command>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="euidref"><varname>$EUID</varname></term>
|
|
<indexterm>
|
|
<primary>$EUID</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$EUID</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>effective user ID</primary>
|
|
</indexterm>
|
|
<listitem><para><quote>effective</quote> user ID number</para>
|
|
<para>Identification number of whatever identity the
|
|
current user has assumed, perhaps by means of <link
|
|
linkend="suref">su</link>.</para>
|
|
<caution><para>The <varname>$EUID</varname> is not necessarily
|
|
the same as the <link
|
|
linkend="uidref">$UID</link>.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$FUNCNAME</varname></term>
|
|
<indexterm>
|
|
<primary>$FUNCNAME</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>function</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>name</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>name of the current function</para>
|
|
<para><programlisting>xyz23 ()
|
|
{
|
|
echo "$FUNCNAME now executing." # xyz23 now executing.
|
|
}
|
|
|
|
xyz23
|
|
|
|
echo "FUNCNAME = $FUNCNAME" # FUNCNAME =
|
|
# Null value outside a function.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$GLOBIGNORE</varname></term>
|
|
<indexterm>
|
|
<primary>$GLOBIGNORE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>globbing</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>ignore</primary>
|
|
</indexterm>
|
|
<listitem><para>A list of filename patterns to be excluded from
|
|
matching in <link linkend="globbingref">globbing</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="groupsref"><varname>$GROUPS</varname></term>
|
|
<indexterm>
|
|
<primary>$GROUPS</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$GROUPS</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>groups</primary>
|
|
</indexterm>
|
|
<listitem><para>groups current user belongs to</para>
|
|
<para>This is a listing (array) of the group id numbers for
|
|
current user, as recorded in
|
|
<filename>/etc/passwd</filename>.
|
|
</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>root# </prompt><userinput>echo $GROUPS</userinput>
|
|
<computeroutput>0</computeroutput>
|
|
|
|
|
|
<prompt>root# </prompt><userinput>echo ${GROUPS[1]}</userinput>
|
|
<computeroutput>1</computeroutput>
|
|
|
|
|
|
<prompt>root# </prompt><userinput>echo ${GROUPS[5]}</userinput>
|
|
<computeroutput>6</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="homedirref"><varname>$HOME</varname></term>
|
|
<indexterm>
|
|
<primary>$HOME</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$HOME</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>home directory</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>directory</primary>
|
|
<secondary>home</secondary>
|
|
</indexterm>
|
|
<listitem><para>home directory of the user, usually <filename
|
|
class="directory">/home/username</filename> (see <xref
|
|
linkend="ex6">)</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="hostnameref"><varname>$HOSTNAME</varname></term>
|
|
<indexterm>
|
|
<primary>$HOSTNAME</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$HOSTNAME</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>system name</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>name</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <link linkend="hnameref">hostname</link> command
|
|
assigns the system name at bootup in an init script.
|
|
However, the <function>gethostname()</function> function
|
|
sets the Bash internal variable <varname>$HOSTNAME</varname>.
|
|
See also <xref linkend="ex6">.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$HOSTTYPE</varname></term>
|
|
<indexterm>
|
|
<primary>$HOSTTYPE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$HOSTTYPE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>host type</primary>
|
|
</indexterm>
|
|
<listitem><para>host type</para>
|
|
<para>Like <link linkend="machtyperef">$MACHTYPE</link>,
|
|
identifies the system hardware.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo $HOSTTYPE</userinput>
|
|
<computeroutput>i686</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ifsref"><varname>$IFS</varname></term>
|
|
<indexterm>
|
|
<primary>$IFS</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$IFS</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>internal field separator</primary>
|
|
</indexterm>
|
|
<listitem><para>internal field separator</para>
|
|
|
|
<para>This variable determines how Bash recognizes fields, or word
|
|
boundaries when it interprets character strings.</para>
|
|
|
|
<para>$IFS defaults to <link
|
|
linkend="whitespaceref">whitespace</link> (space,
|
|
tab, and newline), but may be changed, for example,
|
|
to parse a comma-separated data file. Note that
|
|
<link linkend="appref">$*</link> uses the first
|
|
character held in <varname>$IFS</varname>. See <xref
|
|
linkend="weirdvars">.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo $IFS | 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>
|
|
|
|
<para>See also <xref linkend="isspammer"> for an instructive
|
|
example of using <varname>$IFS</varname>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$IGNOREEOF</varname></term>
|
|
<indexterm>
|
|
<primary>$IGNOREEOF</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$IGNOREEOF</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>Ignore EOF</primary>
|
|
</indexterm>
|
|
<listitem><para>ignore EOF: how many end-of-files (control-D)
|
|
the shell will ignore before logging out.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$LC_COLLATE</varname></term>
|
|
<indexterm>
|
|
<primary>$LC_COLLATE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$LC_COLLATE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>lowercase collate</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Often set in the <filename>.bashrc</filename> or
|
|
<filename>/etc/profile</filename> files, this
|
|
variable controls collation order in filename
|
|
expansion and pattern matching. If mishandled,
|
|
<varname>LC_COLLATE</varname> can cause unexpected results
|
|
in <link linkend="globbingref">filename
|
|
globbing</link>.</para>
|
|
|
|
<note><para>As of version 2.05 of Bash,
|
|
filename globbing no longer distinguishes between lowercase
|
|
and uppercase letters in a character range between
|
|
brackets. For example, <command>ls [A-M]*</command>
|
|
would match both <filename>File1.txt</filename>
|
|
and <filename>file1.txt</filename>. To revert to
|
|
the customary behavior of bracket matching, set
|
|
<varname>LC_COLLATE</varname> to <option>C</option>
|
|
by an <userinput>export LC_COLLATE=C</userinput>
|
|
in <filename>/etc/profile</filename> and/or
|
|
<filename>~/.bashrc</filename>.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$LC_CTYPE</varname></term>
|
|
<indexterm>
|
|
<primary>$LC_CTYPE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$LC_CTYPE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>lowercase character type</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>This internal variable controls character interpretation
|
|
in <link linkend="globbingref">globbing</link> and pattern
|
|
matching.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$LINENO</varname></term>
|
|
<indexterm>
|
|
<primary>$LINENO</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$LINENO</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>line number</primary>
|
|
</indexterm>
|
|
<listitem><para>This variable is the line number of the shell
|
|
script in which this variable appears. It has significance only
|
|
within the script in which it appears, and is chiefly useful for
|
|
debugging purposes.</para>
|
|
<para><programlisting># *** BEGIN DEBUG BLOCK ***
|
|
last_cmd_arg=$_ # Save it.
|
|
|
|
echo "At line number $LINENO, variable \"v1\" = $v1"
|
|
echo "Last command argument processed = $last_cmd_arg"
|
|
# *** END DEBUG BLOCK ***</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="machtyperef"><varname>$MACHTYPE</varname></term>
|
|
<indexterm>
|
|
<primary>$MACHTYPE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$MACHTYPE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>machine type</primary>
|
|
</indexterm>
|
|
<listitem><para>machine type</para>
|
|
<para>Identifies the system hardware.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo $MACHTYPE</userinput>
|
|
<computeroutput>i686</computeroutput></screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="oldpwd"><varname>$OLDPWD</varname></term>
|
|
<indexterm>
|
|
<primary>$OLDPWD</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$OLDPWD</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>previous working directory</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>directory</primary>
|
|
<secondary>working</secondary>
|
|
</indexterm>
|
|
<listitem><para>old working directory
|
|
(<quote>OLD-print-working-directory</quote>,
|
|
previous directory you were in)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$OSTYPE</varname></term>
|
|
<indexterm>
|
|
<primary>$OSTYPE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$OSTYPE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>os type</primary>
|
|
</indexterm>
|
|
<listitem><para>operating system type</para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo $OSTYPE</userinput>
|
|
<computeroutput>linux</computeroutput></screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pathref"><varname>$PATH</varname></term>
|
|
<indexterm>
|
|
<primary>$PATH</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PATH</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>path to binaries</primary>
|
|
</indexterm>
|
|
<listitem><para>path to binaries, usually
|
|
<filename class="directory">/usr/bin/</filename>,
|
|
<filename class="directory">/usr/X11R6/bin/</filename>,
|
|
<filename class="directory">/usr/local/bin</filename>, etc.</para>
|
|
|
|
<para>When given a command, the shell automatically does
|
|
a hash table search on the directories listed in the
|
|
<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
|
|
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>
|
|
|
|
<varlistentry>
|
|
<term><varname>$PIPESTATUS</varname></term>
|
|
<indexterm>
|
|
<primary>$PIPESTATUS</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>pipe</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para><link linkend="arrayref">Array</link> variable holding
|
|
exit status(es) of last executed
|
|
<emphasis>foreground</emphasis> <link
|
|
linkend="piperef">pipe</link>. Interestingly enough, this
|
|
does not necessarily 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>
|
|
|
|
|
|
<para>The members of the <varname>$PIPESTATUS</varname> array
|
|
hold the exit status of each respective command
|
|
executed in a pipe. <varname>$PIPESTATUS[0]</varname>
|
|
holds the exit status of the first command in the pipe,
|
|
<varname>$PIPESTATUS[1]</varname> the exit status of
|
|
the second command, and so on.</para>
|
|
|
|
|
|
<caution>
|
|
<para>
|
|
The <varname>$PIPESTATUS</varname> variable
|
|
may contain an erroneous <errorcode>0</errorcode> value
|
|
in a login shell (in releases prior to 3.0 of Bash).
|
|
</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>tcsh% </prompt><userinput>bash</userinput>
|
|
|
|
<prompt>bash$ </prompt><userinput>who | grep nobody | sort</userinput>
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[*]}</userinput>
|
|
<computeroutput>0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
The above lines contained in a script would produce the expected
|
|
<computeroutput>0 1 0</computeroutput> output.
|
|
</para>
|
|
|
|
<para>
|
|
Thank you, Wayne Pollock for pointing this out and supplying the
|
|
above example.
|
|
</para>
|
|
|
|
</caution>
|
|
|
|
|
|
<caution>
|
|
|
|
<para>In the version 2.05b.0(1)-release of Bash,
|
|
and possibly earlier versions as well, the
|
|
<varname>$PIPESTATUS</varname> variable appears to be
|
|
broken. This is a bug that has been (mostly) fixed in
|
|
Bash, version 3.0 and later.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
|
|
<computeroutput>2.05b.0(1)-release</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>$ ls | bogus_command | wc</userinput>
|
|
<computeroutput>bash: bogus_command: command not found
|
|
0 0 0</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
|
|
<computeroutput>141 127 0</computeroutput>
|
|
|
|
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
|
|
<computeroutput>3.00.0(1)-release</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>$ ls | bogus_command | wc</userinput>
|
|
<computeroutput>bash: bogus_command: command not found
|
|
0 0 0</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
|
|
<computeroutput>0 127 0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</caution>
|
|
|
|
<note>
|
|
|
|
<para><varname>$PIPESTATUS</varname> is a
|
|
<quote>volatile</quote> variable. It needs to be
|
|
captured immediately after the pipe in question, before
|
|
any other command intervenes.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>$ ls | bogus_command | wc</userinput>
|
|
<computeroutput>bash: bogus_command: command not found
|
|
0 0 0</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
|
|
<computeroutput>0 127 0</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
|
|
<computeroutput>0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ppidref"><varname>$PPID</varname></term>
|
|
<indexterm>
|
|
<primary>$PPID</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PPID</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>process ID</primary>
|
|
</indexterm>
|
|
<listitem><para></para>
|
|
<para>The <varname>$PPID</varname> of a process is
|
|
the process ID (<varname>pid</varname>) of its parent process.
|
|
|
|
<footnote><para>The PID of the currently running script is
|
|
<varname>$$</varname>, of course.</para></footnote>
|
|
</para>
|
|
|
|
<para>Compare this with the <link
|
|
linkend="pidofref">pidof</link> command.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$PROMPT_COMMAND</varname></term>
|
|
<indexterm>
|
|
<primary>$PROMPT_COMMAND</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>prompt</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>A variable holding a command to be executed
|
|
just before the primary prompt, <varname>$PS1</varname>
|
|
is to be displayed.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ps1ref"><varname>$PS1</varname></term>
|
|
<indexterm>
|
|
<primary>$PS1</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PS1</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>prompt</primary>
|
|
</indexterm>
|
|
<listitem><para>This is the main prompt, seen at the command line.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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><anchor id="secpromptref"></para>
|
|
<para>The secondary prompt, seen when additional input is
|
|
expected. It displays as <quote>></quote>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$PS3</varname></term>
|
|
<indexterm>
|
|
<primary>$PS3</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PS3</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>prompt</primary>
|
|
<secondary>tertiary</secondary>
|
|
</indexterm>
|
|
<listitem><para>The tertiary prompt, displayed in a
|
|
<link linkend="selectref">select</link> loop (see <xref
|
|
linkend="ex31">).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$PS4</varname></term>
|
|
<indexterm>
|
|
<primary>$PS4</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PS4</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>prompt</primary>
|
|
<secondary>quartenary</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The quartenary prompt, shown at the beginning of
|
|
each line of output when invoking a script with the
|
|
<token>-x</token> <link linkend="optionsref">option</link>.
|
|
It displays as <quote>+</quote>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pwdref"><varname>$PWD</varname></term>
|
|
<indexterm>
|
|
<primary>$PWD</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PWD</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>working directory</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>directory</primary>
|
|
<secondary>working</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>working directory (directory you are in at the time)</para>
|
|
<para>This is the analog to the <link linkend="pwd2ref">pwd</link>
|
|
builtin command.</para>
|
|
<para><programlisting>&wipedir;</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="replyref"><varname>$REPLY</varname></term>
|
|
<indexterm>
|
|
<primary>$REPLY</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$REPLY</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>default value of read</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>reply</primary>
|
|
<secondary>read</secondary>
|
|
</indexterm>
|
|
<listitem><para>The default value when a variable is not
|
|
supplied to <link linkend="readref">read</link>. Also
|
|
applicable to <link linkend="selectref">select</link> menus,
|
|
but only supplies the item number of the variable chosen,
|
|
not the value of the variable itself.</para>
|
|
<para><programlisting>&reply;</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$SECONDS</varname></term>
|
|
<indexterm>
|
|
<primary>$SECONDS</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$SECONDS</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>seconds execution time</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>runtime</primary>
|
|
<secondary>seconds</secondary>
|
|
</indexterm>
|
|
<listitem><para>The number of seconds the script has been running.</para>
|
|
<para><programlisting>&seconds;</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$SHELLOPTS</varname></term>
|
|
<indexterm>
|
|
<primary>$SHELLOPTS</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$SHELLOPTS</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>shell options</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>the list of enabled shell <link
|
|
linkend="optionsref">options</link>, a readonly variable
|
|
<screen><prompt>bash$ </prompt><userinput>echo $SHELLOPTS</userinput>
|
|
<computeroutput>braceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
<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>
|
|
|
|
|
|
<para>As of version 2.05b of Bash, it is now possible to use
|
|
<replaceable>$TMOUT</replaceable> in a script in combination
|
|
with <link linkend="readref">read</link>.</para>
|
|
|
|
<para>
|
|
<programlisting># Works in scripts for Bash, versions 2.05b and later.
|
|
|
|
TMOUT=3 # Prompt times out at three seconds.
|
|
|
|
echo "What is your favorite song?"
|
|
echo "Quickly now, you only have $TMOUT seconds to answer!"
|
|
read song
|
|
|
|
if [ -z "$song" ]
|
|
then
|
|
song="(no answer)"
|
|
# Default response.
|
|
fi
|
|
|
|
echo "Your favorite song is $song."</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>There are other, more complex, ways of implementing
|
|
timed input in a script. One alternative is to set up
|
|
a timing loop to signal the script when it times out.
|
|
This also requires a signal handling routine to trap (see
|
|
<xref linkend="ex76">) the interrupt generated by the timing
|
|
loop (whew!).</para>
|
|
|
|
<example id="tmdin">
|
|
<title>Timed Input</title>
|
|
<programlisting>&tmdin;</programlisting>
|
|
</example>
|
|
|
|
<para>An alternative is using <link
|
|
linkend="sttyref">stty</link>.</para>
|
|
|
|
<example id="timeout">
|
|
<title>Once more, timed input</title>
|
|
<programlisting>&timeout;</programlisting>
|
|
</example>
|
|
|
|
<para>Perhaps the simplest method is using the
|
|
<option>-t</option> option to <link
|
|
linkend="readref">read</link>.</para>
|
|
|
|
<example id="tout">
|
|
<title>Timed <command>read</command></title>
|
|
<programlisting>&tout;</programlisting>
|
|
</example>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="uidref"><varname>$UID</varname></term>
|
|
<indexterm>
|
|
<primary>$UID</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$UID</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>user ID</primary>
|
|
</indexterm>
|
|
<listitem><para>user ID number</para>
|
|
|
|
<para>current user's user identification number, as
|
|
recorded in <filename>/etc/passwd</filename>
|
|
</para>
|
|
|
|
<para>This is the current user's real id, even if she has
|
|
temporarily assumed another identity through <link
|
|
linkend="suref">su</link>. <varname>$UID</varname> is a
|
|
readonly variable, not subject to change from the command
|
|
line or within a script, and is the counterpart to the
|
|
<link linkend="idref">id</link> builtin.</para>
|
|
|
|
<example id="amiroot">
|
|
<title>Am I root?</title>
|
|
<programlisting>&amiroot;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="ex2">.</para>
|
|
|
|
|
|
<!-- Nest note within last entry -->
|
|
<note>
|
|
<para>The variables <varname>$ENV</varname>,
|
|
<varname>$LOGNAME</varname>, <varname>$MAIL</varname>,
|
|
<varname>$TERM</varname>, <varname>$USER</varname>, and
|
|
<varname>$USERNAME</varname> are <emphasis>not</emphasis>
|
|
Bash <link linkend="builtinref">builtins</link>. These are,
|
|
however, often set as <link linkend="envref">environmental
|
|
variables</link> in one of the Bash <link
|
|
linkend="filesref1">startup files</link>. <anchor
|
|
id="shellvarref"><varname>$SHELL</varname>,
|
|
the name of the user's login shell, may be set from
|
|
<filename>/etc/passwd</filename> or in an <quote>init</quote>
|
|
script, and it is likewise not a Bash builtin.</para>
|
|
<para>
|
|
<screen>
|
|
<prompt>tcsh% </prompt><userinput>echo $LOGNAME</userinput>
|
|
<computeroutput>bozo</computeroutput>
|
|
<prompt>tcsh% </prompt><userinput>echo $SHELL</userinput>
|
|
<computeroutput>/bin/tcsh</computeroutput>
|
|
<prompt>tcsh% </prompt><userinput>echo $TERM</userinput>
|
|
<computeroutput>rxvt</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $LOGNAME</userinput>
|
|
<computeroutput>bozo</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo $SHELL</userinput>
|
|
<computeroutput>/bin/tcsh</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo $TERM</userinput>
|
|
<computeroutput>rxvt</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
<!-- Nest note after $USER -->
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
<!-- Last entry of intrinsic BASH variables -->
|
|
|
|
<variablelist id="posparmslist">
|
|
<title>Positional Parameters</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="posparamref"><varname>$0</varname>, <varname>$1</varname>,
|
|
<varname>$2</varname>, etc.</term>
|
|
<indexterm>
|
|
<primary>$0</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$0</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>positional parameter</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>parameter</primary>
|
|
<secondary>positional</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>positional parameters, passed from command
|
|
line to script, passed to a function, or <link
|
|
linkend="setref">set</link> to a variable (see <xref
|
|
linkend="ex17"> and <xref linkend="ex34">)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
<note><para><quote><varname>$*</varname></quote> must be
|
|
quoted.</para></note>
|
|
</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>
|
|
|
|
<note><para>Of course, <quote><varname>$@</varname></quote>
|
|
should be quoted.</para></note>
|
|
|
|
<example id="arglist">
|
|
<title><command>arglist</command>: Listing arguments with $* and $@</title>
|
|
<programlisting>&arglist;</programlisting>
|
|
</example>
|
|
|
|
<para>Following a <command>shift</command>, the
|
|
<varname>$@</varname> holds the remaining command-line
|
|
parameters, lacking the previous <varname>$1</varname>,
|
|
which was lost.
|
|
<programlisting>#!/bin/bash
|
|
# Invoke with ./scriptname 1 2 3 4 5
|
|
|
|
echo "$@" # 1 2 3 4 5
|
|
shift
|
|
echo "$@" # 2 3 4 5
|
|
shift
|
|
echo "$@" # 3 4 5
|
|
|
|
# Each "shift" loses parameter $1.
|
|
# "$@" then contains the remaining parameters.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>The <varname>$@</varname> special parameter finds
|
|
use as a tool for filtering input into shell scripts. The
|
|
<command>cat "$@"</command> construction accepts input
|
|
to a script either from <filename>stdin</filename> or
|
|
from files given as parameters to the script. See <xref
|
|
linkend="rot13"> and <xref linkend="cryptoquote">.</para>
|
|
|
|
|
|
<caution><para>The <varname>$*</varname> and <varname>$@</varname>
|
|
parameters sometimes display inconsistent and
|
|
puzzling behavior, depending on the setting of <link
|
|
linkend="ifsref">$IFS</link>.</para></caution>
|
|
|
|
<example id="incompat">
|
|
<title>Inconsistent <varname>$*</varname> and <varname>$@</varname> behavior</title>
|
|
<programlisting>&incompat;</programlisting>
|
|
</example>
|
|
|
|
<note><para>The <command>$@</command> and <command>$*</command>
|
|
parameters differ only when between double quotes.</para></note>
|
|
|
|
<example id="ifsempty">
|
|
<title><varname>$*</varname> and <varname>$@</varname> when
|
|
<varname>$IFS</varname> is empty</title>
|
|
<programlisting>&ifsempty;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="otherspecparams">
|
|
<title>Other Special Parameters</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="flpref"><varname>$-</varname></term>
|
|
<indexterm>
|
|
<primary>$-</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$-</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>flags</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Flags passed to script (using <link
|
|
linkend="setref">set</link>). See <xref linkend="ex34">.</para>
|
|
<caution><para>This was originally a <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>
|
|
<secondary>last job background</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>PID (process ID) of last job run in background</para>
|
|
|
|
<para>
|
|
<programlisting>LOG=$0.log
|
|
|
|
COMMAND1="sleep 100"
|
|
|
|
echo "Logging PIDs background commands for script: $0" >> "$LOG"
|
|
# So they can be monitored, and killed as necessary.
|
|
echo >> "$LOG"
|
|
|
|
# Logging commands.
|
|
|
|
echo -n "PID of \"$COMMAND1\": " >> "$LOG"
|
|
${COMMAND1} &
|
|
echo $! >> "$LOG"
|
|
# PID of "sleep 100": 1506
|
|
|
|
# Thank you, Jacques Lederer, for suggesting this.</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting>possibly_hanging_job & { sleep ${TIMEOUT}; eval 'kill -9 $!' &> /dev/null; }
|
|
# Forces completion of an ill-behaved program.
|
|
# Useful, for example, in init scripts.
|
|
|
|
# Thank you, Sylvain Fourmanoit, for this creative use of the "!" variable.</programlisting>
|
|
|
|
</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="underscoreref"><varname>$_</varname></term>
|
|
<indexterm>
|
|
<primary>$_</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$_</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>underscore</primary>
|
|
<secondary>last argument</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Special variable set to last argument of previous command
|
|
executed.</para>
|
|
|
|
|
|
<example id="uscref">
|
|
<title>Underscore variable</title>
|
|
<programlisting>#!/bin/bash
|
|
|
|
echo $_ # /bin/bash
|
|
# Just called /bin/bash to run the script.
|
|
|
|
du >/dev/null # So no output from command.
|
|
echo $_ # du
|
|
|
|
ls -al >/dev/null # So no output from command.
|
|
echo $_ # -al (last argument)
|
|
|
|
:
|
|
echo $_ # :</programlisting></example>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="xstatvarref"><varname>$?</varname></term>
|
|
<indexterm>
|
|
<primary>$?</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$?</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>exit status</primary>
|
|
</indexterm>
|
|
<listitem><para><link linkend="exitstatusref">Exit status</link>
|
|
of a command, <link linkend="functionref">function</link>,
|
|
or the script itself (see <xref linkend="max">)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="proccid"><varname>$$</varname></term>
|
|
<indexterm>
|
|
<primary>$$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$$</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>PID</primary>
|
|
<secondary>of script</secondary>
|
|
</indexterm>
|
|
<listitem><para>Process ID of the script itself. The
|
|
<varname>$$</varname> variable often finds use
|
|
in scripts to construct <quote>unique</quote>
|
|
temp file names (see <xref linkend="ftpget">, <xref
|
|
linkend="online">, <xref linkend="derpm">, and <xref
|
|
linkend="selfdestruct">). This is usually simpler than
|
|
invoking <link linkend="mktempref">mktemp</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
</sect1> <!-- Internal Variables -->
|
|
|
|
<sect1 id="String-Manipulation">
|
|
<title>Manipulating Strings</title>
|
|
|
|
<para><anchor id="stringmanip"></para>
|
|
|
|
<para>Bash supports a surprising number of string manipulation
|
|
operations. Unfortunately, these tools lack
|
|
a unified focus. Some are a subset of <link
|
|
linkend="paramsubref">parameter substitution</link>, and
|
|
others fall under the functionality of the UNIX <link
|
|
linkend="exprref">expr</link> command. This results in
|
|
inconsistent command syntax and overlap of functionality,
|
|
not to mention confusion.</para>
|
|
|
|
<variablelist id="stringlength">
|
|
<title>String Length</title>
|
|
|
|
<varlistentry>
|
|
<term>${#string}</term>
|
|
<indexterm>
|
|
<primary>string length</primary>
|
|
<secondary>parameter substitution</secondary>
|
|
</indexterm>
|
|
|
|
<listitem><para></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr length $string</term>
|
|
<indexterm>
|
|
<primary>string length</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem><para></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr "$string" : '.*'</term>
|
|
<indexterm>
|
|
<primary>string length</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
|
|
echo ${#stringZ} # 15
|
|
echo `expr length $stringZ` # 15
|
|
echo `expr "$stringZ" : '.*'` # 15</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<example id="paragraphspace">
|
|
<title>Inserting a blank line between paragraphs in a text file</title>
|
|
<programlisting>¶graphspace;</programlisting>
|
|
</example>
|
|
|
|
<variablelist id="lengthsubstring">
|
|
<title>Length of Matching Substring at Beginning of String</title>
|
|
|
|
<varlistentry>
|
|
<term>expr match "$string" '$substring'</term>
|
|
<indexterm>
|
|
<primary>substring length</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para><replaceable>$substring</replaceable> is a <link
|
|
linkend="regexref">regular expression</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr "$string" : '$substring'</term>
|
|
<indexterm>
|
|
<primary>substring length</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para><replaceable>$substring</replaceable> is a regular
|
|
expression.</para>
|
|
<para>
|
|
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
# |------|
|
|
|
|
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>
|
|
<indexterm>
|
|
<primary>substring index</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
|
|
<para>Numerical position in $string of first character in
|
|
$substring that matches.</para>
|
|
|
|
<para><programlisting>stringZ=abcABC123ABCabc
|
|
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>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="substringextraction">
|
|
<title>Substring Extraction</title>
|
|
|
|
<varlistentry>
|
|
<term>${string:position}</term>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>extraction</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>Extracts substring from <replaceable>$string</replaceable> at
|
|
<replaceable>$position</replaceable>.</para>
|
|
<para>If the <varname>$string</varname> parameter is
|
|
<quote><token>*</token></quote>
|
|
or <quote><token>@</token></quote>, then this extracts the
|
|
<link linkend="posparamref">positional parameters</link>,
|
|
<footnote><para>This applies to either command line
|
|
arguments or parameters passed to a <link
|
|
linkend="functionref">function</link>.</para></footnote>
|
|
starting at <varname>$position</varname>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>${string:position:length}</term>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>extraction</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>Extracts <replaceable>$length</replaceable> characters
|
|
of substring from <replaceable>$string</replaceable> at
|
|
<replaceable>$position</replaceable>.</para>
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
# 0123456789.....
|
|
# 0-based indexing.
|
|
|
|
echo ${stringZ:0} # abcABC123ABCabc
|
|
echo ${stringZ:1} # bcABC123ABCabc
|
|
echo ${stringZ:7} # 23ABCabc
|
|
|
|
echo ${stringZ:7:3} # 23A
|
|
# Three characters of substring.
|
|
|
|
|
|
|
|
# Is it possible to index from the right end of the string?
|
|
|
|
echo ${stringZ:-4} # abcABC123ABCabc
|
|
# Defaults to full string, as in ${parameter:-default}.
|
|
# However . . .
|
|
|
|
echo ${stringZ:(-4)} # Cabc
|
|
echo ${stringZ: -4} # Cabc
|
|
# Now, it works.
|
|
# Parentheses or added space "escape" the position parameter.
|
|
|
|
# Thank you, Dan Jacobson, for pointing this out.</programlisting>
|
|
</para>
|
|
<para>If the <varname>$string</varname> parameter is
|
|
<quote><token>*</token></quote> or
|
|
<quote><token>@</token></quote>, then this extracts a maximum
|
|
of <varname>$length</varname> positional parameters, starting
|
|
at <varname>$position</varname>.</para>
|
|
|
|
<para>
|
|
<programlisting>echo ${*:2} # Echoes second and following positional parameters.
|
|
echo ${@:2} # Same as above.
|
|
|
|
echo ${*:2:3} # Echoes three positional parameters, starting at second.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr substr $string $position $length</term>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>extraction expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
|
|
<para>Extracts <replaceable>$length</replaceable> characters
|
|
from <replaceable>$string</replaceable> starting at
|
|
<replaceable>$position</replaceable>.</para>
|
|
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
# 123456789......
|
|
# 1-based indexing.
|
|
|
|
echo `expr substr $stringZ 1 2` # ab
|
|
echo `expr substr $stringZ 4 3` # ABC</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="exprparen"></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr match "$string" '\($substring\)'</term>
|
|
<indexterm>
|
|
<primary>substring extraction</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>Extracts <replaceable>$substring</replaceable>
|
|
at beginning of <replaceable>$string</replaceable>,
|
|
where <replaceable>$substring</replaceable> is a <link
|
|
linkend="regexref">regular expression</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr "$string" : '\($substring\)'</term>
|
|
<indexterm>
|
|
<primary>substring extraction</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
|
|
<para>Extracts <replaceable>$substring</replaceable>
|
|
at beginning of <replaceable>$string</replaceable>,
|
|
where <replaceable>$substring</replaceable> is a regular
|
|
expression.</para>
|
|
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
# =======
|
|
|
|
echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1
|
|
echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1
|
|
echo `expr "$stringZ" : '\(.......\)'` # abcABC1
|
|
# All of the above forms give an identical result.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr match "$string" '.*\($substring\)'</term>
|
|
<indexterm>
|
|
<primary>substring extraction</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>Extracts <replaceable>$substring</replaceable>
|
|
at <emphasis>end</emphasis> of
|
|
<replaceable>$string</replaceable>, where
|
|
<replaceable>$substring</replaceable> is a regular
|
|
expression.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr "$string" : '.*\($substring\)'</term>
|
|
<indexterm>
|
|
<primary>substring extraction</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
|
|
<para>Extracts <replaceable>$substring</replaceable>
|
|
at <emphasis>end</emphasis> of <replaceable>$string</replaceable>,
|
|
where <replaceable>$substring</replaceable> is a regular
|
|
expression.</para>
|
|
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
# ======
|
|
|
|
echo `expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)'` # ABCabc
|
|
echo `expr "$stringZ" : '.*\(......\)'` # ABCabc</programlisting>
|
|
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="substringremoval">
|
|
<title>Substring Removal</title>
|
|
|
|
<varlistentry>
|
|
<term>${string#substring}</term>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>removal</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>Strips shortest match of
|
|
<replaceable>$substring</replaceable> from
|
|
<emphasis>front</emphasis> of
|
|
<replaceable>$string</replaceable>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>${string##substring}</term>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>removal</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
|
|
<para>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>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>removal</secondary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>removal</secondary>
|
|
</indexterm>
|
|
|
|
<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
|
|
# Strip out shortest match between 'b' and 'c', from back of $stringZ.
|
|
|
|
echo ${stringZ%%b*c} # a
|
|
# Strip out longest match between 'b' and 'c', from back of $stringZ.</programlisting>
|
|
</para>
|
|
|
|
<example id="cvt">
|
|
<title>Converting graphic file formats, with filename change</title>
|
|
<programlisting>&cvt;</programlisting>
|
|
</example>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="substringreplacement">
|
|
<title>Substring Replacement</title>
|
|
|
|
<varlistentry>
|
|
<term>${string/substring/replacement}</term>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>replacement</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>Replace first match of
|
|
<replaceable>$substring</replaceable> with
|
|
<replaceable>$replacement</replaceable>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>${string//substring/replacement}</term>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>replacement</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
|
|
<para>Replace all matches of
|
|
<replaceable>$substring</replaceable> with
|
|
<replaceable>$replacement</replaceable>.</para>
|
|
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
|
|
echo ${stringZ/abc/xyz} # xyzABC123ABCabc
|
|
# Replaces first match of 'abc' with 'xyz'.
|
|
|
|
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
|
|
# Replaces all matches of 'abc' with # 'xyz'.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>${string/#substring/replacement}</term>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>replacement</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>If <replaceable>$substring</replaceable> matches
|
|
<emphasis>front</emphasis> end of
|
|
<replaceable>$string</replaceable>, substitute
|
|
<replaceable>$replacement</replaceable> for
|
|
<replaceable>$substring</replaceable>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>${string/%substring/replacement}</term>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>replacement</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
|
|
<para>If <replaceable>$substring</replaceable> matches
|
|
<emphasis>back</emphasis> end of
|
|
<replaceable>$string</replaceable>, substitute
|
|
<replaceable>$replacement</replaceable> for
|
|
<replaceable>$substring</replaceable>.</para>
|
|
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
|
|
echo ${stringZ/#abc/XYZ} # XYZABC123ABCabc
|
|
# Replaces front-end match of 'abc' with 'XYZ'.
|
|
|
|
echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ
|
|
# Replaces back-end match of 'abc' with 'XYZ'.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<sect2 id="awkstringmanip">
|
|
<title>Manipulating strings using awk</title>
|
|
|
|
<para>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
|
|
<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>
|
|
|
|
</sect2> <!-- Further Discussion -->
|
|
|
|
|
|
|
|
</sect1> <!-- Manipulating Strings -->
|
|
|
|
|
|
|
|
<sect1 id="Parameter-Substitution">
|
|
<title>Parameter Substitution</title>
|
|
|
|
<para><anchor id="paramsubref"></para>
|
|
|
|
<variablelist id="pssub">
|
|
<title><anchor id="pssub1">Manipulating and/or expanding variables</title>
|
|
<varlistentry>
|
|
<term>
|
|
<userinput>${parameter}</userinput></term>
|
|
<listitem>
|
|
|
|
<para>Same as <replaceable>$parameter</replaceable>, i.e.,
|
|
value of the variable
|
|
<replaceable>parameter</replaceable>.
|
|
In certain contexts, only the less ambiguous
|
|
<replaceable>${parameter}</replaceable> form
|
|
works.</para>
|
|
|
|
<para>May be used for concatenating variables with strings.</para>
|
|
|
|
<para><programlisting>
|
|
your_id=${USER}-on-${HOSTNAME}
|
|
echo "$your_id"
|
|
#
|
|
echo "Old \$PATH = $PATH"
|
|
PATH=${PATH}:/opt/bin #Add /opt/bin to $PATH for duration of script.
|
|
echo "New \$PATH = $PATH"
|
|
</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${parameter-default}</userinput></term>
|
|
<term><userinput>${parameter:-default}</userinput></term>
|
|
<listitem>
|
|
<para>If parameter not set, use default.</para>
|
|
<para><programlisting>
|
|
echo ${username-`whoami`}
|
|
# Echoes the result of `whoami`, if variable $username is still unset.</programlisting></para>
|
|
|
|
<note><para><replaceable>${parameter-default}</replaceable>
|
|
and <replaceable>${parameter:-default}</replaceable>
|
|
are almost equivalent. The extra <token>:</token> makes
|
|
a difference only when <emphasis>parameter</emphasis>
|
|
has been declared, but is null. </para></note>
|
|
|
|
<para><programlisting>¶msub;</programlisting></para>
|
|
|
|
<para>The <emphasis>default parameter</emphasis> construct
|
|
finds use in providing <quote>missing</quote> command-line
|
|
arguments in scripts.</para>
|
|
|
|
<para>
|
|
<programlisting>DEFAULT_FILENAME=generic.data
|
|
filename=${1:-$DEFAULT_FILENAME}
|
|
# If not otherwise specified, the following command block operates
|
|
#+ on the file "generic.data".
|
|
#
|
|
# Commands follow.</programlisting>
|
|
</para>
|
|
|
|
<para>See also <xref linkend="ex58">, <xref
|
|
linkend="ex73">, and <xref linkend="collatz">.</para>
|
|
|
|
<para>Compare this method with <link
|
|
linkend="anddefault">using an <emphasis>and
|
|
list</emphasis> to supply a default command-line
|
|
argument</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${parameter=default}</userinput></term>
|
|
<term><userinput>${parameter:=default}</userinput></term>
|
|
<listitem>
|
|
<para><anchor id="defparam"></para>
|
|
<para>If parameter not set, set it to default.</para>
|
|
|
|
<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 for
|
|
<quote>command not found</quote>).</para>
|
|
</footnote>
|
|
as above.
|
|
</para>
|
|
|
|
<para><programlisting>
|
|
echo ${username=`whoami`}
|
|
# Variable "username" is now set to `whoami`.</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${parameter+alt_value}</userinput></term>
|
|
<term><userinput>${parameter:+alt_value}</userinput></term>
|
|
<listitem>
|
|
<para>If parameter set, use
|
|
<userinput>alt_value</userinput>, else use null
|
|
string.</para>
|
|
|
|
<para>Both forms nearly equivalent. The <token>:</token>
|
|
makes a difference only when <emphasis>parameter</emphasis>
|
|
has been declared and is null, see below.</para>
|
|
|
|
<para><programlisting>echo "###### \${parameter+alt_value} ########"
|
|
echo
|
|
|
|
a=${param1+xyz}
|
|
echo "a = $a" # a =
|
|
|
|
param2=
|
|
a=${param2+xyz}
|
|
echo "a = $a" # a = xyz
|
|
|
|
param3=123
|
|
a=${param3+xyz}
|
|
echo "a = $a" # a = xyz
|
|
|
|
echo
|
|
echo "###### \${parameter:+alt_value} ########"
|
|
echo
|
|
|
|
a=${param4:+xyz}
|
|
echo "a = $a" # a =
|
|
|
|
param5=
|
|
a=${param5:+xyz}
|
|
echo "a = $a" # a =
|
|
# Different result from a=${param5+xyz}
|
|
|
|
param6=123
|
|
a=${param6+xyz}
|
|
echo "a = $a" # a = xyz</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><anchor id="qerrmsg"><userinput>${parameter?err_msg}</userinput></term>
|
|
<term><userinput>${parameter:?err_msg}</userinput></term>
|
|
<listitem><para>If parameter set, use it, else print err_msg.</para>
|
|
<para>Both forms nearly equivalent. The <token>:</token>
|
|
makes a difference only when <emphasis>parameter</emphasis>
|
|
has been declared and is null, as above.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<example id="ex6">
|
|
<title>Using parameter substitution and error messages</title>
|
|
<programlisting>&ex6;</programlisting>
|
|
</example>
|
|
|
|
<example id="usagemessage">
|
|
<title>Parameter substitution and <quote>usage</quote> messages</title>
|
|
<programlisting>&usagemessage;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<formalpara><title>Parameter substitution and/or expansion</title>
|
|
|
|
<para><anchor id="psub2">The following expressions are
|
|
the complement to the <command>match</command>
|
|
<replaceable>in</replaceable> <command>expr</command>
|
|
string operations (see <xref linkend="ex45">).
|
|
These particular ones are used mostly in parsing file
|
|
path names.</para></formalpara>
|
|
|
|
<variablelist id="psorex">
|
|
<title><anchor id="psorex1">Variable length / Substring removal</title>
|
|
|
|
<varlistentry>
|
|
|
|
<term><userinput>${#var}</userinput></term>
|
|
<listitem>
|
|
<para><userinput>String length</userinput> (number
|
|
of characters in <varname>$var</varname>). For
|
|
an <link linkend="arrayref">array</link>,
|
|
<command>${#array}</command> is the length of the
|
|
first element in the array.</para>
|
|
|
|
<note><para>
|
|
Exceptions:
|
|
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<command>${#*}</command> and
|
|
<command>${#@}</command> give the <emphasis>number
|
|
of positional parameters</emphasis>.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
For an array, <command>${#array[*]}</command> and
|
|
<command>${#array[@]}</command> give the number
|
|
of elements in the array.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para></note>
|
|
|
|
<example id="length">
|
|
<title>Length of a variable</title>
|
|
<programlisting>&length;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var#Pattern}</userinput></term>
|
|
<term><userinput>${var##Pattern}</userinput></term>
|
|
|
|
<listitem>
|
|
<para>Remove from <varname>$var</varname>
|
|
the shortest/longest part of <varname>$Pattern</varname>
|
|
that matches the <replaceable>front end</replaceable>
|
|
of <varname>$var</varname>.
|
|
</para>
|
|
|
|
<para>A usage illustration from <xref linkend="daysbetween">:
|
|
<programlisting># Function from "days-between.sh" example.
|
|
# Strips leading zero(s) from argument passed.
|
|
|
|
strip_leading_zero () # Strip possible leading zero(s)
|
|
{ #+ from argument passed.
|
|
return=${1#0} # The "1" refers to "$1" -- passed arg.
|
|
} # The "0" is what to remove from "$1" -- strips zeros.</programlisting>
|
|
</para>
|
|
|
|
<para>Manfred Schwarb's more elaborate variation of the above:
|
|
<programlisting>strip_leading_zero2 () # Strip possible leading zero(s), since otherwise
|
|
{ # Bash will interpret such numbers as octal values.
|
|
shopt -s extglob # Turn on extended globbing.
|
|
local val=${1##+(0)} # Use local variable, longest matching series of 0's.
|
|
shopt -u extglob # Turn off extended globbing.
|
|
_strip_leading_zero2=${val:-0}
|
|
# If input was 0, return 0 instead of "".
|
|
}</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>Another usage illustration:
|
|
<programlisting>echo `basename $PWD` # Basename of current working directory.
|
|
echo "${PWD##*/}" # Basename of current working directory.
|
|
echo
|
|
echo `basename $0` # Name of script.
|
|
echo $0 # Name of script.
|
|
echo "${0##*/}" # Name of script.
|
|
echo
|
|
filename=test.data
|
|
echo "${filename##*.}" # data
|
|
# Extension of filename.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pctpatref"><userinput>${var%Pattern}</userinput></term>
|
|
<term><userinput>${var%%Pattern}</userinput></term>
|
|
|
|
<listitem><para>Remove from <varname>$var</varname>
|
|
the shortest/longest part of <varname>$Pattern</varname>
|
|
that matches the <replaceable>back end</replaceable>
|
|
of <varname>$var</varname>.
|
|
</para></listitem>
|
|
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<para><link linkend="bash2ref">Version 2</link> of Bash added
|
|
additional options.</para>
|
|
|
|
<example id="pattmatching">
|
|
<title>Pattern matching in parameter substitution</title>
|
|
<programlisting>&pattmatching;</programlisting>
|
|
</example>
|
|
|
|
|
|
<example id="rfe">
|
|
<title>Renaming file extensions<token>:</token></title>
|
|
<programlisting>&rfe;</programlisting>
|
|
</example>
|
|
|
|
|
|
<variablelist id="exprepl">
|
|
<title><anchor id="exprepl1">Variable expansion / Substring
|
|
replacement</title>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>These constructs have been adopted from
|
|
<emphasis>ksh</emphasis>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var:pos}</userinput></term>
|
|
<listitem>
|
|
<para>Variable <replaceable>var</replaceable> expanded,
|
|
starting from offset <replaceable>pos</replaceable>.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var:pos:len}</userinput></term>
|
|
<listitem>
|
|
<para>Expansion to a max of <replaceable>len</replaceable>
|
|
characters of variable <replaceable>var</replaceable>, from offset
|
|
<replaceable>pos</replaceable>. See <xref linkend="pw">
|
|
for an example of the creative use of this operator.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var/Pattern/Replacement}</userinput></term>
|
|
<listitem>
|
|
<para>First match of <replaceable>Pattern</replaceable>,
|
|
within <replaceable>var</replaceable> replaced with
|
|
<replaceable>Replacement</replaceable>.</para>
|
|
<para>If <replaceable>Replacement</replaceable> is
|
|
omitted, then the first match of
|
|
<replaceable>Pattern</replaceable> is replaced by
|
|
<emphasis>nothing</emphasis>, that is, deleted.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var//Pattern/Replacement}</userinput></term>
|
|
<listitem>
|
|
|
|
<formalpara><title>Global replacement</title>
|
|
<para>All matches of <replaceable>Pattern</replaceable>,
|
|
within <replaceable>var</replaceable> replaced with
|
|
<replaceable>Replacement</replaceable>.</para>
|
|
</formalpara>
|
|
|
|
<para>As above, if <replaceable>Replacement</replaceable>
|
|
is omitted, then all occurrences of
|
|
<replaceable>Pattern</replaceable> are replaced by
|
|
<emphasis>nothing</emphasis>, that is, deleted.</para>
|
|
|
|
<example id="ex7">
|
|
<title>Using pattern matching to parse arbitrary strings</title>
|
|
<programlisting>&ex7;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var/#Pattern/Replacement}</userinput></term>
|
|
<listitem>
|
|
<para>If <emphasis>prefix</emphasis> of
|
|
<replaceable>var</replaceable> matches
|
|
<replaceable>Pattern</replaceable>, then substitute
|
|
<replaceable>Replacement</replaceable> for
|
|
<replaceable>Pattern</replaceable>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var/%Pattern/Replacement}</userinput></term>
|
|
<listitem>
|
|
<para>If <emphasis>suffix</emphasis> of
|
|
<replaceable>var</replaceable> matches
|
|
<replaceable>Pattern</replaceable>, then substitute
|
|
<replaceable>Replacement</replaceable> for
|
|
<replaceable>Pattern</replaceable>.</para>
|
|
|
|
<example id="varmatch">
|
|
<title>Matching patterns at prefix or suffix of string</title>
|
|
<programlisting>&varmatch;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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=
|
|
|
|
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
|
|
|
|
# Bash, version 2.04, adds this feature.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Parameter Substitution -->
|
|
|
|
|
|
<sect1 id="declareref">
|
|
<indexterm>
|
|
<primary>declare</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>typeset</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>declare</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>typeset</secondary>
|
|
</indexterm>
|
|
<title>Typing variables: <command>declare</command> or
|
|
<command>typeset</command></title>
|
|
|
|
<para>The <command>declare</command> or <command>typeset</command>
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<listitem>
|
|
|
|
<para><programlisting>declare -i number
|
|
# The script will treat subsequent occurrences of "number" as an integer.
|
|
|
|
number=3
|
|
echo "Number = $number" # Number = 3
|
|
|
|
number=three
|
|
echo "Number = $number" # Number = 0
|
|
# Tries to evaluate the string "three" as an integer.</programlisting></para>
|
|
|
|
<para>Certain arithmetic operations are permitted
|
|
for declared integer variables without the need
|
|
for <link linkend="exprref">expr</link> or <link
|
|
linkend="letref">let</link>.</para>
|
|
|
|
<para><programlisting>n=6/3
|
|
echo "n = $n" # n = 6/3
|
|
|
|
declare -i n
|
|
n=6/3
|
|
echo "n = $n" # n = 2</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
<varlistentry>
|
|
<term>-x var=$value</term>
|
|
<listitem>
|
|
<para><programlisting>declare -x var3=373</programlisting></para>
|
|
<para>The <command>declare</command> command permits
|
|
assigning a value to a variable in the same statement
|
|
as setting its properties.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
<example id="ex20">
|
|
<title>Using <command>declare</command> to type variables</title>
|
|
<programlisting>&ex20;</programlisting>
|
|
</example>
|
|
|
|
</sect1> <!-- Typing variables: declare or typeset -->
|
|
|
|
|
|
<sect1 id="ivr">
|
|
<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>
|
|
|
|
|
|
<para>
|
|
Nils Radtke shows how to build <quote>dynamic</quote>
|
|
variable names and evaluate their contents. This can be useful
|
|
when <link linkend="sourceref">sourcing</link> configuration files.
|
|
|
|
<programlisting>#!/bin/bash
|
|
|
|
|
|
# ---------------------------------------------
|
|
# This could be "sourced" from a separate file.
|
|
isdnMyProviderRemoteNet=172.16.0.100
|
|
isdnYourProviderRemoteNet=10.0.0.10
|
|
isdnOnlineService="MyProvider"
|
|
# ---------------------------------------------
|
|
|
|
|
|
remoteNet=$(eval "echo \$$(echo isdn${isdnOnlineService}RemoteNet)")
|
|
remoteNet=$(eval "echo \$$(echo isdnMyProviderRemoteNet)")
|
|
remoteNet=$(eval "echo \$isdnMyProviderRemoteNet")
|
|
remoteNet=$(eval "echo $isdnMyProviderRemoteNet")
|
|
|
|
echo "$remoteNet" # 172.16.0.100
|
|
|
|
# ================================================================
|
|
|
|
# And, it gets even better.
|
|
|
|
# Consider the following snippet given a variable named getSparc,
|
|
#+ but no such variable getIa64:
|
|
|
|
chkMirrorArchs () {
|
|
arch="$1";
|
|
if [ "$(eval "echo \${$(echo get$(echo -ne $arch |
|
|
sed 's/^\(.\).*/\1/g' | tr 'a-z' 'A-Z'; echo $arch |
|
|
sed 's/^.\(.*\)/\1/g')):-false}")" = true ]
|
|
then
|
|
return 0;
|
|
else
|
|
return 1;
|
|
fi;
|
|
}
|
|
|
|
getSparc="true"
|
|
unset getIa64
|
|
chkMirrorArchs sparc
|
|
echo $? # 0
|
|
# True
|
|
|
|
chkMirrorArchs Ia64
|
|
echo $? # 1
|
|
# False
|
|
|
|
# Notes:
|
|
# -----
|
|
# Even the to-be-substituted variable name part is built explicitly.
|
|
# The parameters to the chkMirrorArchs calls are all lower case.
|
|
# The variable name is composed of two parts: "get" and "Sparc" . . .</programlisting>
|
|
</para>
|
|
|
|
|
|
|
|
<example id="coltotaler2">
|
|
<title>Passing an indirect reference to <replaceable>awk</replaceable></title>
|
|
<programlisting>&coltotaler2;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>This method of indirect referencing is a bit tricky.
|
|
If the second order variable changes its value, then the first
|
|
order variable must be properly dereferenced (as in the above
|
|
example). <anchor id="ivr2">Fortunately, the
|
|
<replaceable>${!variable}</replaceable> notation introduced
|
|
with <link linkend="bash2ref">version 2</link> of Bash
|
|
(see <xref linkend="ex78">) makes indirect referencing more
|
|
intuitive.</para></caution>
|
|
|
|
</sect1> <!-- Indirect References to Variables -->
|
|
|
|
|
|
<sect1 id="randomvar">
|
|
|
|
<indexterm>
|
|
<primary>$RANDOM</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$RANDOM</secondary>
|
|
</indexterm>
|
|
<title>$RANDOM: generate random integer</title>
|
|
<para>$RANDOM is an internal Bash <link
|
|
linkend="functionref">function</link> (not a constant) that
|
|
returns a <emphasis>pseudorandom</emphasis>
|
|
|
|
<footnote><para>True <quote>randomness,</quote> insofar as
|
|
it exists at all, can only be found in certain
|
|
incompletely understood natural phenomena such as
|
|
radioactive decay. Computers can only simulate
|
|
randomness, and computer-generated sequences of
|
|
<quote>random</quote> numbers are therefore referred to as
|
|
<emphasis>pseudorandom.</emphasis></para></footnote>
|
|
|
|
integer in the range 0 - 32767. $RANDOM should
|
|
<replaceable>not</replaceable> be used to generate an encryption
|
|
key.</para>
|
|
|
|
<example id="ex21">
|
|
<title>Generating random numbers</title>
|
|
<programlisting>&ex21;</programlisting>
|
|
</example>
|
|
|
|
<example id="pickcard">
|
|
<title>Picking a random card from a deck</title>
|
|
<programlisting>&pickcard;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para>
|
|
<emphasis>Jipe</emphasis> points out a set of techniques for
|
|
generating random numbers within a range.
|
|
|
|
<programlisting># Generate random number between 6 and 30.
|
|
rnumber=$((RANDOM%25+6))
|
|
|
|
# Generate random number in the same 6 - 30 range,
|
|
#+ but the number must be evenly divisible by 3.
|
|
rnumber=$(((RANDOM%30/3+1)*3))
|
|
|
|
# Note that this will not work all the time.
|
|
# It fails if $RANDOM returns 0.
|
|
|
|
# Exercise: Try to figure out the pattern here.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
<emphasis>Bill Gradwohl</emphasis> came up with an improved
|
|
formula that works for positive numbers.
|
|
<programlisting>rnumber=$(((RANDOM%(max-min+divisibleBy))/divisibleBy*divisibleBy+min))</programlisting>
|
|
</para>
|
|
|
|
<para>Here Bill presents a versatile function that returns
|
|
a random number between two specified values.</para>
|
|
|
|
<example id="randombetween">
|
|
<title>Random between values</title>
|
|
<programlisting>&randombetween;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para>Just how random is $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 a single 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>
|
|
|
|
<para><anchor id="urandomref"></para>
|
|
<note>
|
|
<para>The <filename>/dev/urandom</filename> device-file provides
|
|
a method of generating much more <quote>random</quote>
|
|
pseudorandom numbers than the <varname>$RANDOM</varname>
|
|
variable. <userinput>dd if=/dev/urandom of=targetfile
|
|
bs=1 count=XX</userinput> creates a file of well-scattered
|
|
pseudorandom numbers. However, assigning these numbers
|
|
to a variable in a script requires a workaround, such as
|
|
filtering through <link linkend="odref">od</link> (as in
|
|
above example and <xref linkend="rnd">), or using <link
|
|
linkend="ddref">dd</link> (see <xref linkend="blotout">),
|
|
or even piping to <link linkend="md5sumref">md5sum</link>
|
|
(see <xref linkend="horserace">).</para>
|
|
|
|
<para><anchor id="awkrandomref"></para>
|
|
|
|
<para>There are also other ways to generate pseudorandom
|
|
numbers in a script. <command>Awk</command> provides a
|
|
convenient means of doing this.</para>
|
|
|
|
<example id="random2">
|
|
<title>Pseudorandom numbers, using <link
|
|
linkend="awkref">awk</link></title>
|
|
<programlisting>&random2;</programlisting>
|
|
</example>
|
|
|
|
<para>The <link linkend="dateref">date</link> command also lends
|
|
itself to <link linkend="daterandref">generating pseudorandom
|
|
integer sequences</link>.</para>
|
|
|
|
</note>
|
|
|
|
|
|
|
|
</sect1> <!-- RANDOM: generate random integer -->
|
|
|
|
|
|
<sect1 id="dblparens">
|
|
<title>The Double Parentheses Construct</title>
|
|
|
|
<para>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>
|
|
|
|
|
|
</sect1> <!-- The Double Parentheses Construct -->
|
|
|
|
|
|
</chapter> <!-- Variables Revisited -->
|
|
|
|
|
|
<chapter id="loops">
|
|
<title>Loops and Branches</title>
|
|
|
|
|
|
<para>Operations on code blocks are the key to structured, organized
|
|
shell scripts. Looping and branching constructs provide the tools for
|
|
accomplishing this.</para>
|
|
|
|
<sect1 id="loops1">
|
|
<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>
|
|
|
|
|
|
<variablelist id="forloopref">
|
|
<title><anchor id="forloopref1">for loops</title>
|
|
|
|
<varlistentry>
|
|
<term><command>for (in)</command></term>
|
|
<indexterm>
|
|
<primary>for</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>in</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>do</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>done</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>loop</primary>
|
|
<secondary>for</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This is the basic looping construct. It differs significantly
|
|
from its 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>
|
|
<arg rep=repeat choice=plain><replaceable> command(s)</replaceable></arg><sbr>
|
|
<arg choice="plain">done</arg>
|
|
</cmdsynopsis></para>
|
|
|
|
<note><para>During each pass through the loop,
|
|
<replaceable>arg</replaceable> takes on the
|
|
value of each successive variable in the
|
|
<replaceable>list</replaceable>.</para></note>
|
|
|
|
<para><programlisting>for arg in "$var1" "$var2" "$var3" ... "$varN"
|
|
# In pass 1 of the loop, $arg = $var1
|
|
# In pass 2 of the loop, $arg = $var2
|
|
# In pass 3 of the loop, $arg = $var3
|
|
# ...
|
|
# In pass N of the loop, $arg = $varN
|
|
|
|
# Arguments in [list] quoted to prevent possible word splitting.</programlisting></para>
|
|
|
|
|
|
<para>The argument <replaceable>list</replaceable> may contain 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
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<para>More of the same.</para>
|
|
|
|
<example id="userlist">
|
|
<title>Listing all users on the system</title>
|
|
<programlisting>&userlist;</programlisting>
|
|
</example>
|
|
|
|
<para>A final example of the [list] resulting from command
|
|
substitution.</para>
|
|
|
|
<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>
|
|
|
|
<para>The <filename>stdout</filename> of a loop may be <link
|
|
linkend="ioredirref">redirected</link> to a file, as this slight
|
|
modification to the previous example shows.</para>
|
|
|
|
<example id="symlinks2">
|
|
<title>Symbolic links in a directory, saved to a file</title>
|
|
<programlisting>&symlinks2;</programlisting>
|
|
</example>
|
|
|
|
<para>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>
|
|
|
|
<para>See also <xref linkend="qfunction">, <xref
|
|
linkend="twodim">, and <xref linkend="collatz">.</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para>Now, a <emphasis>for-loop</emphasis> used in a
|
|
<quote>real-life</quote> context.</para>
|
|
|
|
<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
|
|
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>
|
|
|
|
<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> command</replaceable></arg><sbr>
|
|
<arg choice="plain">done</arg>
|
|
</cmdsynopsis></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>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>
|
|
|
|
|
|
<para>A <command>while</command> loop may have multiple
|
|
conditions. Only the final condition determines when the loop
|
|
terminates. This necessitates a slightly different loop syntax,
|
|
however.</para>
|
|
|
|
<example id="ex26a">
|
|
<title><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><</token> at its end.</para>
|
|
|
|
<para>A <command>while</command> loop may have its
|
|
<filename>stdin</filename> <link linkend="readpiperef">
|
|
supplied by a pipe</link>.</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="untilloopref"><command>until</command></term>
|
|
<indexterm>
|
|
<primary>until</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>do</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>done</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>loop</primary>
|
|
<secondary>until</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>This construct tests for a condition at the top of a loop, and keeps
|
|
looping as long as that condition is 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> 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>
|
|
|
|
</sect1> <!-- Loops -->
|
|
|
|
|
|
|
|
<sect1 id="nestedloops">
|
|
<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>
|
|
|
|
</sect1> <!-- Nested Loops -->
|
|
|
|
|
|
<sect1 id="loopcontrol">
|
|
<title>Loop Control</title>
|
|
|
|
<variablelist id="brkcont">
|
|
<title><anchor id="brkcont1">Commands Affecting Loop Behavior</title>
|
|
|
|
<varlistentry>
|
|
<indexterm>
|
|
<primary>break</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>continue</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>loop</primary>
|
|
<secondary>break</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>loop</primary>
|
|
<secondary>continue</secondary>
|
|
</indexterm>
|
|
<term><command>break</command></term>
|
|
<term><command>continue</command></term>
|
|
<listitem>
|
|
<para>The <command>break</command> and <command>continue</command>
|
|
loop control commands
|
|
<footnote><para>These are shell <link
|
|
linkend="builtinref">builtins</link>,
|
|
whereas other loop commands, such as <link
|
|
linkend="whileloopref">while</link> and <link
|
|
linkend="caseesac1">case</link>, are <link
|
|
linkend="keywordref">keywords</link>.</para></footnote>
|
|
correspond exactly to their counterparts in other
|
|
programming languages. The <command>break</command>
|
|
command terminates the loop (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>
|
|
|
|
<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>
|
|
|
|
<example id="continuenex">
|
|
<title>Using <quote>continue N</quote> in an actual task</title>
|
|
<programlisting>&continuenex;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>The <command>continue N</command> construct is
|
|
difficult to understand and tricky to use in any meaningful
|
|
context. It is probably best avoided.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Loop Control Commands -->
|
|
|
|
|
|
|
|
<sect1 id="testbranch">
|
|
<title>Testing and Branching</title>
|
|
|
|
<para>The <command>case</command> and <command>select</command>
|
|
constructs are technically not loops, since they do not iterate the
|
|
execution of a code block. Like loops, however, they direct
|
|
program flow according to conditions at the top or bottom of
|
|
the block.</para>
|
|
|
|
<variablelist id="caseesac">
|
|
<title><anchor id="caseesac1">Controlling program flow in a code
|
|
block</title>
|
|
|
|
<varlistentry>
|
|
<term><command>case (in) / esac</command></term>
|
|
<indexterm>
|
|
<primary>case</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>in</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>esac</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>switch</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>;;</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>menus</primary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>The <command>case</command> construct is the shell 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"> "$<replaceable>condition1</replaceable>" )</arg><sbr>
|
|
<arg choice="plain" rep="repeat"> <replaceable>command</replaceable></arg><sbr>
|
|
<arg choice="plain"> ;;</arg><sbr><sbr>
|
|
<arg choice="plain"> "$<replaceable>condition2</replaceable>" )</arg><sbr>
|
|
<arg choice="plain" rep="repeat"> <replaceable>command</replaceable></arg><sbr>
|
|
<arg choice="plain"> ;;</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##*/} <filename>"; 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>
|
|
|
|
<example id="matchstring">
|
|
<title>Simple string matching</title>
|
|
<programlisting>&matchstring;</programlisting>
|
|
</example>
|
|
|
|
<example id="isalpha">
|
|
<title>Checking for alphabetic input</title>
|
|
<programlisting>&isalpha;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="selectref"><command>select</command></term>
|
|
<indexterm>
|
|
<primary>select</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>menus</primary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>select</command> construct, adopted from the Korn
|
|
Shell, is yet another tool for building menus.</para>
|
|
|
|
<para><cmdsynopsis>
|
|
<command>select</command>
|
|
<arg choice="plain"><replaceable>variable</replaceable></arg>
|
|
<arg choice="opt">in <replaceable>list</replaceable></arg><sbr>
|
|
<arg choice="plain">do</arg><sbr>
|
|
<arg choice="plain" rep="repeat"> <replaceable>command</replaceable></arg><sbr>
|
|
<arg choice="plain"> 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>
|
|
|
|
<para>See also <xref linkend="resistor">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Testing and Branching -->
|
|
|
|
|
|
</chapter> <!-- Loops -->
|
|
|
|
|
|
|
|
<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>
|
|
|
|
<example id="spawnscr">
|
|
<title>A script that forks off multiple instances of itself</title>
|
|
<programlisting>&spawnscr;</programlisting>
|
|
</example>
|
|
|
|
<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>
|
|
|
|
</sidebar>
|
|
|
|
|
|
<para>A builtin may be a synonym to a system command of the same
|
|
name, but Bash reimplements it internally. For example,
|
|
the Bash <command>echo</command> command is not the same as
|
|
<filename>/bin/echo</filename>, although their behavior is
|
|
almost identical.
|
|
<programlisting>#!/bin/bash
|
|
|
|
echo "This line uses the \"echo\" builtin."
|
|
/bin/echo "This line uses the /bin/echo system command."</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="keywordref">A <firstterm>keyword</firstterm>
|
|
is a <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>,
|
|
<quote><token>while</token></quote>, <quote>do</quote>, and
|
|
<quote><token>!</token></quote> are keywords. Similar to a
|
|
<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>
|
|
|
|
|
|
<variablelist id="intio">
|
|
<title><anchor id="intio1">I/O</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="echoref"><command>echo</command></term>
|
|
<indexterm>
|
|
<primary>echo</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>echo</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>prints (to <filename>stdout</filename>) an expression
|
|
or variable (see <xref linkend="ex9">).
|
|
<programlisting>echo Hello
|
|
echo $a</programlisting></para>
|
|
|
|
<para>An <command>echo</command> requires the
|
|
<option>-e</option> option to print escaped characters. See
|
|
<xref linkend="escaped">.</para>
|
|
|
|
<para>Normally, each <command>echo</command> command prints
|
|
a terminal newline, but the <option>-n</option> option
|
|
suppresses this.</para>
|
|
|
|
<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>
|
|
|
|
|
|
<para>Be aware that <command>echo `command`</command>
|
|
deletes any linefeeds that the output
|
|
of <replaceable>command</replaceable>
|
|
generates.</para>
|
|
|
|
<para>The <link linkend="ifsref">$IFS</link> (internal field
|
|
separator) variable normally contains
|
|
<token>\n</token> (linefeed) as one of its set of
|
|
<link linkend="whitespaceref">whitespace</link>
|
|
characters. Bash therefore splits the output of
|
|
<replaceable>command</replaceable> at linefeeds
|
|
into arguments to <command>echo</command>. Then
|
|
<command>echo</command> outputs these arguments,
|
|
separated by spaces.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>ls -l /usr/share/apps/kjezz/sounds</userinput>
|
|
<computeroutput>-rw-r--r-- 1 root root 1407 Nov 7 2000 reflect.au
|
|
-rw-r--r-- 1 root root 362 Nov 7 2000 seconds.au</computeroutput>
|
|
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo `ls -l /usr/share/apps/kjezz/sounds`</userinput>
|
|
<computeroutput>total 40 -rw-r--r-- 1 root root 716 Nov 7 2000 reflect.au -rw-r--r-- 1 root root 362 Nov 7 2000 seconds.au</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>
|
|
So, how can we embed a linefeed within an
|
|
<emphasis>echoed</emphasis> character string?
|
|
|
|
<programlisting># Embedding a linefeed?
|
|
echo "Why doesn't this string \n split on two lines?"
|
|
# Doesn't split.
|
|
|
|
# Let's try something else.
|
|
|
|
echo
|
|
|
|
echo $"A line of text containing
|
|
a linefeed."
|
|
# Prints as two distinct lines (embedded linefeed).
|
|
# But, is the "$" variable prefix really necessary?
|
|
|
|
echo
|
|
|
|
echo "This string splits
|
|
on two lines."
|
|
# No, the "$" is not needed.
|
|
|
|
echo
|
|
echo "---------------"
|
|
echo
|
|
|
|
echo -n $"Another line of text containing
|
|
a linefeed."
|
|
# Prints as two distinct lines (embedded linefeed).
|
|
# Even the -n option fails to suppress the linefeed here.
|
|
|
|
echo
|
|
echo
|
|
echo "---------------"
|
|
echo
|
|
echo
|
|
|
|
# However, the following doesn't work as expected.
|
|
# Why not?
|
|
string1=$"Yet another line of text containing
|
|
a linefeed (maybe)."
|
|
|
|
echo $string1
|
|
|
|
# Thanks, Steve Parker, for pointing this out.</programlisting>
|
|
</para>
|
|
|
|
<note>
|
|
<para>This command is a shell builtin, and not the same as
|
|
<filename>/bin/echo</filename>, although its behavior is
|
|
similar.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>type -a echo</userinput>
|
|
<computeroutput>echo is a shell builtin
|
|
echo is /bin/echo</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="printfref"><command>printf</command></term>
|
|
<indexterm>
|
|
<primary>printf</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>printf</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>printf</command>, formatted print, command is an
|
|
enhanced <command>echo</command>. It is a limited variant
|
|
of the C language <function>printf()</function> library
|
|
function, and its syntax is somewhat different.</para>
|
|
<cmdsynopsis>
|
|
<command>printf</command>
|
|
<arg choice=plain rep=repeat><replaceable>format-string</replaceable></arg>
|
|
<arg choice=plain rep=repeat><replaceable>parameter</replaceable></arg>
|
|
</cmdsynopsis>
|
|
|
|
<para>This is the Bash builtin version
|
|
of the <filename>/bin/printf</filename> or
|
|
<filename>/usr/bin/printf</filename> command. See the
|
|
<command>printf</command> manpage (of the system command)
|
|
for in-depth coverage.</para>
|
|
|
|
<caution><para>Older versions of Bash may not support
|
|
<command>printf</command>.</para></caution>
|
|
|
|
<example id="ex47">
|
|
<title><command>printf</command> in action</title>
|
|
<programlisting>&ex47;</programlisting>
|
|
</example>
|
|
|
|
<para>Formatting error messages is a useful application of
|
|
<command>printf</command></para>
|
|
|
|
<para>
|
|
<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>
|
|
|
|
<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>
|
|
|
|
|
|
<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>
|
|
|
|
|
|
<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>
|
|
|
|
|
|
<para>The <option>-n</option> option to <command>read</command>
|
|
also allows detection of the <emphasis>arrow keys</emphasis>
|
|
and certain of the other unusual keys.</para>
|
|
|
|
<example id="arrowdetect">
|
|
<title>Detecting the arrow keys</title>
|
|
<programlisting>&arrowdetect;</programlisting>
|
|
</example>
|
|
|
|
<note><para>The <option>-n</option> option to <command>read</command>
|
|
will not detect the <keycap>ENTER</keycap> (newline)
|
|
key.</para></note>
|
|
|
|
|
|
<para>The <option>-t</option> option to <command>read</command>
|
|
permits timed input (see <xref linkend="tout">).</para>
|
|
|
|
<para>The <command>read</command> command may also
|
|
<quote>read</quote> its variable value from a file
|
|
<link linkend="ioredirref">redirected</link> to
|
|
<filename>stdin</filename>. If the file contains
|
|
more than one line, only the first line is assigned
|
|
to the variable. If <command>read</command>
|
|
has more than one parameter, then each of
|
|
these variables gets assigned a successive <link
|
|
linkend="whitespaceref">whitespace-delineated</link>
|
|
string. Caution!</para>
|
|
|
|
<example id="readredir">
|
|
<title>Using <command>read</command> with
|
|
<link linkend="ioredirref">file redirection</link></title>
|
|
<programlisting>&readredir;</programlisting>
|
|
</example>
|
|
|
|
<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><anchor id="readpiperef">Yet, piping the output of <link
|
|
linkend="catref">cat</link> <emphasis>seems</emphasis> to
|
|
work.</para>
|
|
|
|
<para><programlisting>cat file1 file2 |
|
|
while read line
|
|
do
|
|
echo $line
|
|
done</programlisting></para>
|
|
|
|
|
|
<para>However, as Bjön Eriksson shows:</para>
|
|
|
|
<example id="readpipe">
|
|
<title>Problems reading from a pipe</title>
|
|
<programlisting>&readpipe;</programlisting>
|
|
</example>
|
|
|
|
<para>The <command>gendiff</command> script, usually found in
|
|
<filename>/usr/bin</filename> on many Linux distros, pipes the
|
|
output of <link linkend="findref">find</link> to a
|
|
<emphasis>while read</emphasis> construct.
|
|
|
|
<programlisting>find $1 \( -name "*$2" -o -name ".*$2" \) -print |
|
|
while read f; do
|
|
. . .</programlisting>
|
|
</para>
|
|
|
|
</note>
|
|
|
|
|
|
</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>
|
|
|
|
<para><anchor id="doubleslashref"></para>
|
|
|
|
<caution><para>The <command>cd</command> command does not function
|
|
as expected when presented with two forward slashes.
|
|
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>cd //</userinput>
|
|
<prompt>bash$ </prompt><userinput>pwd</userinput>
|
|
<computeroutput>//</computeroutput>
|
|
</screen>
|
|
The output should, of course, be <computeroutput>/</computeroutput>.
|
|
This is a problem both from the command line and in a script.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pwd2ref"><command>pwd</command></term>
|
|
<indexterm>
|
|
<primary>pwd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>pwd</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>$PWD</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PWD</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>directory</primary>
|
|
<secondary>working</secondary>
|
|
</indexterm>
|
|
<listitem><para>Print Working Directory. This gives the user's
|
|
(or script's) current directory (see <xref
|
|
linkend="ex37">). The effect is identical to
|
|
reading the value of the builtin variable <link
|
|
linkend="pwdref">$PWD</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dirsd"><command>pushd</command></term>
|
|
<term><command>popd</command></term>
|
|
<term><command>dirs</command></term>
|
|
<indexterm>
|
|
<primary>pushd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>pushd</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>popd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>popd</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>dirs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dirs</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>directory</primary>
|
|
<secondary>working</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>bookmark</primary>
|
|
</indexterm>
|
|
<listitem><para>This command set is a mechanism for bookmarking working directories,
|
|
a means of moving back and forth through directories in an orderly
|
|
manner. A pushdown stack is used to keep track of directory names.
|
|
Options allow various manipulations of the directory stack.</para>
|
|
|
|
<para><anchor id="pushdref"><userinput>pushd
|
|
dir-name</userinput> pushes the path
|
|
<replaceable>dir-name</replaceable> onto the directory
|
|
stack and simultaneously changes the current working
|
|
directory to <replaceable>dir-name</replaceable></para>
|
|
|
|
<para><anchor id="popdref"><command>popd</command> removes
|
|
(pops) the top directory path name off the directory stack
|
|
and simultaneously changes the current working directory
|
|
to that directory popped from the stack.</para>
|
|
|
|
<para><command>dirs</command> lists the contents of the directory
|
|
stack (compare this with the <link
|
|
linkend="dirstackref">$DIRSTACK</link> variable).
|
|
A successful <command>pushd</command> or
|
|
<command>popd</command> will automatically invoke
|
|
<command>dirs</command>.</para>
|
|
|
|
|
|
<para>Scripts that require various changes to the current
|
|
working directory without hard-coding the directory name
|
|
changes can make good use of these commands. Note that
|
|
the implicit <varname>$DIRSTACK</varname> array variable,
|
|
accessible from within a script, holds the contents of
|
|
the directory stack.
|
|
</para>
|
|
|
|
<example id="ex37">
|
|
<title>Changing the current working directory </title>
|
|
<programlisting>&ex37;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="intvar">
|
|
<title><anchor id="intvar1">Variables</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="letref"><command>let</command></term>
|
|
<indexterm>
|
|
<primary>let</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>let</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>let</command> command carries out arithmetic
|
|
operations on variables. In many cases, it functions as a less
|
|
complex version of <link linkend="exprref">expr</link>.</para>
|
|
|
|
<example id="ex46">
|
|
<title>Letting <quote>let</quote> do arithmetic.</title>
|
|
<programlisting>&ex46;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="evalref"><command>eval</command></term>
|
|
<indexterm>
|
|
<primary>eval</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>eval</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para><userinput>eval arg1 [arg2] ... [argN]</userinput></para>
|
|
|
|
<para>Combines the arguments in an expression or list of
|
|
expressions and <emphasis>evaluates</emphasis> them. Any
|
|
variables contained within the expression are expanded. The
|
|
result translates into a command. This can be useful for
|
|
code generation from the command line or within a script.</para>
|
|
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>process=xterm</userinput>
|
|
<prompt>bash$ </prompt><userinput>show_process="eval ps ax | grep $process"</userinput>
|
|
<prompt>bash$ </prompt><userinput>$show_process</userinput>
|
|
<computeroutput>1867 tty1 S 0:02 xterm
|
|
2779 tty1 S 0:00 xterm
|
|
2886 pts/1 S 0:00 grep xterm</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<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>
|
|
|
|
<example id="rot14">
|
|
<title>A version of <quote>rot13</quote></title>
|
|
<programlisting>&rot14;</programlisting>
|
|
</example>
|
|
|
|
<para>Rory Winston contributed the following instance of how
|
|
useful <command>eval</command> can be.</para>
|
|
|
|
<example id="evalex">
|
|
<title>Using <command>eval</command> to force variable
|
|
substitution in a Perl script</title>
|
|
<programlisting>&evalex;</programlisting>
|
|
</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>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="setref"><command>set</command></term>
|
|
<indexterm>
|
|
<primary>set</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>set</secondary>
|
|
</indexterm>
|
|
<listitem><para>The <command>set</command> command changes
|
|
the value of internal script variables. One use for
|
|
this is to toggle <link linkend="optionsref">option
|
|
flags</link> which help determine the behavior of the
|
|
script. Another application for it is to reset the <link
|
|
linkend="posparamref">positional parameters</link> that
|
|
a script sees as the result of a command (<userinput>set
|
|
`command`</userinput>). The script can then parse the
|
|
fields of the command output.</para>
|
|
|
|
<example id="ex34">
|
|
<title>Using <command>set</command> with positional
|
|
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>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="ex22a"> and <xref linkend="ex33a">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="unsetref"><command>unset</command></term>
|
|
<indexterm>
|
|
<primary>unset</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>unset</secondary>
|
|
</indexterm>
|
|
<listitem><para>The <command>unset</command> command deletes a
|
|
shell variable, effectively setting it to
|
|
<emphasis>null</emphasis>. Note that this command does
|
|
not affect positional parameters.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>unset PATH</userinput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $PATH</userinput>
|
|
<computeroutput>
|
|
|
|
|
|
</computeroutput>
|
|
<prompt>bash$ </prompt></screen>
|
|
</para>
|
|
|
|
<example id="uns">
|
|
<title><quote>Unsetting</quote> a variable</title>
|
|
<programlisting>&uns;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="exportref"><command>export</command></term>
|
|
<indexterm>
|
|
<primary>export</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>export</secondary>
|
|
</indexterm>
|
|
<listitem><para>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>
|
|
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>
|
|
|
|
|
|
<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>
|
|
|
|
<para>However, as Greg Keraunen points out, in certain
|
|
situations this may have a different effect than
|
|
setting a variable, then exporting it.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>export var=(a b); echo ${var[0]}</userinput>
|
|
<computeroutput>(a b)</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>var=(a b); export var; echo ${var[0]}</userinput>
|
|
<computeroutput>a</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
</tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>declare</command></term>
|
|
<term><command>typeset</command></term>
|
|
<indexterm>
|
|
<primary>declare</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>declare</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>typeset</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>typeset</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <link linkend="declareref">declare</link> and
|
|
<link linkend="declareref">typeset</link> commands specify
|
|
and/or restrict properties of variables.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
<term><anchor id="getoptsx"><command>getopts</command></term>
|
|
<indexterm>
|
|
<primary>getopts</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>getopts</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>$OPTIND</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$OPTIND</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>$OPTARG</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$OPTARG</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This powerful tool parses command-line arguments passed
|
|
to the script. This is the Bash analog of the <link
|
|
linkend="getopty">getopt</link> external command and
|
|
the <command>getopt</command> library function familiar
|
|
to C programmers. It permits passing and concatenating
|
|
multiple options
|
|
|
|
<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>
|
|
|
|
and associated arguments to a script (for
|
|
example <userinput>scriptname -abc -e
|
|
/usr/local</userinput>).</para>
|
|
|
|
<para>The <command>getopts</command> construct uses two implicit
|
|
variables. <varname>$OPTIND</varname> is the argument
|
|
pointer (<wordasword>OPTion INDex</wordasword>)
|
|
and <varname>$OPTARG</varname> (<wordasword>OPTion
|
|
ARGument</wordasword>) the (optional) argument attached
|
|
to an option. A colon following the option name in the
|
|
declaration tags that option as having an associated
|
|
argument.</para>
|
|
|
|
<para>A <command>getopts</command> construct usually comes
|
|
packaged in a <link linkend="whileloopref">while
|
|
loop</link>, which processes the options and
|
|
arguments one at a time, then decrements the implicit
|
|
<varname>$OPTIND</varname> variable to step to the
|
|
next.</para>
|
|
|
|
<note>
|
|
<para>
|
|
<orderedlist>
|
|
<listitem>
|
|
|
|
<para>The arguments passed from the command line to
|
|
the script must be preceded by a
|
|
minus (<option>-</option>) or a plus
|
|
(<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>
|
|
|
|
<para>The <command>getopts</command> construct replaces
|
|
the deprecated <link linkend="getopty">getopt</link>
|
|
external command.</para>
|
|
|
|
</listitem>
|
|
</orderedlist>
|
|
</para>
|
|
</note>
|
|
|
|
<para><programlisting>
|
|
while getopts ":abcde:fg" Option
|
|
# Initial declaration.
|
|
# a, b, c, d, e, f, and g are the options (flags) expected.
|
|
# The : after option 'e' shows it will have an argument passed with it.
|
|
do
|
|
case $Option in
|
|
a ) # Do something with variable 'a'.
|
|
b ) # Do something with variable 'b'.
|
|
...
|
|
e) # Do something with 'e', and also with $OPTARG,
|
|
# which is the associated argument passed with option 'e'.
|
|
...
|
|
g ) # Do something with variable 'g'.
|
|
esac
|
|
done
|
|
shift $(($OPTIND - 1))
|
|
# Move argument pointer to next.
|
|
|
|
# All this is not nearly as complicated as it looks <grin>.
|
|
</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>. Sourcing a file
|
|
(dot-command) <emphasis>imports</emphasis>
|
|
code into the script, appending to the script (same
|
|
effect as the <userinput>#include</userinput> directive
|
|
in a C program). The net result is the same as if the
|
|
<quote>sourced</quote> lines of code were in the body of
|
|
the script. This is useful in situations when multiple
|
|
scripts use a common data file or function library.</para>
|
|
|
|
<example id="ex38">
|
|
<title><quote>Including</quote> a data file</title>
|
|
<programlisting>&ex38;</programlisting>
|
|
|
|
<para>File <filename>data-file</filename> for <xref
|
|
linkend="ex38">, above. Must be present in same
|
|
directory.</para>
|
|
|
|
<programlisting>&ex38bis;</programlisting>
|
|
</example>
|
|
|
|
<para>It is even possible for a script to
|
|
<emphasis>source</emphasis> itself, though this does not
|
|
seem to have any practical applications.</para>
|
|
|
|
<example id="selfsource">
|
|
<title>A (useless) script that sources itself</title>
|
|
<programlisting>&selfsource;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><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 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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="execref"><command>exec</command></term>
|
|
<indexterm>
|
|
<primary>exec</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>exec</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>This shell builtin replaces the current process with
|
|
a specified command. Normally, when the shell encounters
|
|
a command, it <link linkend="forkref">forks off</link> a
|
|
child process to actually execute the command. Using the
|
|
<command>exec</command> builtin, the shell does not fork,
|
|
and the command 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>
|
|
|
|
<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>
|
|
|
|
<para>An <command>exec</command> also serves to reassign <link
|
|
linkend="fdref">file descriptors</link>. <userinput>exec
|
|
<zzz-file</userinput> replaces <filename>stdin</filename>
|
|
with the file <filename>zzz-file</filename> (see <xref
|
|
linkend="redir1">).</para>
|
|
|
|
<note><para>The <option>-exec</option> option to
|
|
<link linkend="findref">find</link> is
|
|
<replaceable>not</replaceable> the same as the
|
|
<command>exec</command> shell builtin.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>shopt</command><anchor id="shoptref"></term>
|
|
<indexterm>
|
|
<primary>shopt</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>shopt</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This command permits changing shell options on the fly (see
|
|
<xref linkend="al"> and <xref linkend="unal">). It often
|
|
appears in the Bash <link linkend="filesref1">startup
|
|
files</link>, but also has its uses in scripts. Needs
|
|
<link linkend="bash2ref">version 2</link> or later of Bash.
|
|
|
|
<programlisting>shopt -s cdspell
|
|
# Allows minor misspelling of directory names with 'cd'
|
|
|
|
cd /hpme # Oops! Mistyped '/home'.
|
|
pwd # /home
|
|
# The shell corrected the misspelling.</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="intcommand">
|
|
<title><anchor id="intcommand1">Commands</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="trueref"><command>true</command></term>
|
|
<indexterm>
|
|
<primary>true</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>true</secondary>
|
|
</indexterm>
|
|
<listitem><para>A command that returns a successful
|
|
(<returnvalue>zero</returnvalue>) <link
|
|
linkend="exitstatusref">exit status</link>, but does
|
|
nothing else.
|
|
</para>
|
|
|
|
<para><programlisting># Endless loop
|
|
while true # alias for ":"
|
|
do
|
|
operation-1
|
|
operation-2
|
|
...
|
|
operation-n
|
|
# Need a way to break out of loop or script will hang.
|
|
done</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
identifies <replaceable>keywords</replaceable>
|
|
and <replaceable>builtins</replaceable>, and also locates
|
|
system commands with identical names.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>type '['</userinput>
|
|
<computeroutput>[ is a shell builtin</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type -a '['</userinput>
|
|
<computeroutput>[ is a shell builtin
|
|
[ is /usr/bin/[</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>hash [cmds]</command></term>
|
|
<indexterm>
|
|
<primary>hash</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>hash</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>$PATH</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PATH</secondary>
|
|
</indexterm>
|
|
<listitem><para>Record the path name of specified commands (in the
|
|
shell hash table), so the shell or script will not need to search
|
|
the <varname>$PATH</varname> on subsequent calls to those
|
|
commands. When <command>hash</command> is called with no
|
|
arguments, it simply lists the commands that have been hashed.
|
|
The <option>-r</option> option resets the hash table.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>bind</command></term>
|
|
<indexterm>
|
|
<primary>bind</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>bind</primary>
|
|
<secondary>key bindings </secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>The <command>bind</command> builtin displays or modifies
|
|
<emphasis>readline</emphasis>
|
|
<footnote><para>The <emphasis>readline</emphasis> library
|
|
is what Bash uses for reading input in an interactive
|
|
shell.</para></footnote>
|
|
key bindings.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>help</command></term>
|
|
<indexterm>
|
|
<primary>help</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary></secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Gets a short usage summary of a shell builtin. This is
|
|
the counterpart to <link linkend="whatisref">whatis</link>,
|
|
but for builtins.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>help exit</userinput>
|
|
<computeroutput>exit: exit [n]
|
|
Exit the shell with a status of N. If N is omitted, the exit status
|
|
is that of the last command executed.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<sect1>
|
|
<title>Job Control Commands</title>
|
|
|
|
|
|
<para>Certain of the following job control commands take a
|
|
<quote>job identifier</quote> as an argument. See the <link
|
|
linkend="jobidtable">table</link> at end of the chapter.</para>
|
|
|
|
<variablelist id="jccommandlist">
|
|
|
|
<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>
|
|
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<para><anchor id="waithang"></para>
|
|
<tip>
|
|
<para>Within a script, running a command in the background
|
|
with an ampersand (&) may cause the script
|
|
to hang until <keycap>ENTER</keycap> is hit. This
|
|
seems to occur with commands that write to
|
|
<filename>stdout</filename>. It can be a major annoyance.
|
|
<programlisting>#!/bin/bash
|
|
# test.sh
|
|
|
|
ls -l &
|
|
echo "Done."</programlisting>
|
|
<screen><prompt>bash$ </prompt><userinput>./test.sh</userinput>
|
|
<computeroutput>Done.
|
|
[bozo@localhost test-scripts]$ total 1
|
|
-rwxr-xr-x 1 bozo bozo 34 Oct 11 15:09 test.sh
|
|
_
|
|
</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Placing a <command>wait</command> after the background
|
|
command seems to remedy this.
|
|
<programlisting>#!/bin/bash
|
|
# test.sh
|
|
|
|
ls -l &
|
|
echo "Done."
|
|
wait</programlisting>
|
|
<screen><prompt>bash$ </prompt><userinput>./test.sh</userinput>
|
|
<computeroutput>Done.
|
|
[bozo@localhost test-scripts]$ total 1
|
|
-rwxr-xr-x 1 bozo bozo 34 Oct 11 15:09 test.sh</computeroutput>
|
|
</screen>
|
|
<link linkend="ioredirref">Redirecting</link> the
|
|
output of the command to a file or even to
|
|
<filename>/dev/null</filename> also takes care of this
|
|
problem.
|
|
</para>
|
|
</tip>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>suspend</command></term>
|
|
<indexterm>
|
|
<primary>suspend</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>suspend</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This has a similar effect to
|
|
<keycombo><keycap>Control</keycap><keycap>Z</keycap></keycombo>,
|
|
but it suspends the shell (the shell's parent process should
|
|
resume it at an appropriate time).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>logout</command></term>
|
|
<indexterm>
|
|
<primary>logout</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>log out</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Exit a login shell, optionally specifying an <link
|
|
linkend="exitstatusref">exit status</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="timesref"><command>times</command></term>
|
|
<indexterm>
|
|
<primary>times</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>times</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Gives statistics on the system time 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>
|
|
|
|
<example id="selfdestruct">
|
|
<title>A script that kills itself</title>
|
|
<programlisting>&selfdestruct;</programlisting>
|
|
</example>
|
|
|
|
<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 child process that has
|
|
terminated, but that the <link linkend="forkref">parent
|
|
process </link> has not (yet) killed, cannot be killed by a
|
|
logged-on user -- you can't kill something that is already
|
|
dead -- but <command>init</command> will generally clean
|
|
it up sooner or later.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
<listitem>
|
|
|
|
<para>This either enables or disables a shell
|
|
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
|
|
<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.
|
|
<footnote>
|
|
<para>The C source for a number of loadable builtins is
|
|
typically found in the <filename
|
|
class="directory">/usr/share/doc/bash-?.??/functions</filename>
|
|
directory.</para>
|
|
<para>Note that the <option>-f</option> option to
|
|
<command>enable</command> is not portable to all
|
|
systems.</para>
|
|
</footnote>.
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<table id="jobidtable">
|
|
<title>Job identifiers</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Notation</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>%N</option></entry>
|
|
<entry>Job number [N]</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%S</option></entry>
|
|
<entry>Invocation (command line) of job begins with string <emphasis>S</emphasis></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%?S</option></entry>
|
|
<entry>Invocation (command line) of job contains within it string <emphasis>S</emphasis></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%%</option></entry>
|
|
<entry><quote>current</quote> job (last job stopped in
|
|
foreground or started in background)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%+</option></entry>
|
|
<entry><quote>current</quote> job (last job stopped in
|
|
foreground or started in background)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%-</option></entry>
|
|
<entry>Last job</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$!</option></entry>
|
|
<entry>Last background process</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
</sect1> <!-- Job Control Commands -->
|
|
|
|
</chapter> <!-- Internal Commands and Builtins -->
|
|
|
|
|
|
|
|
<chapter id="external">
|
|
<title>External Filters, Programs and Commands</title>
|
|
|
|
<para><anchor id="externalref"></para>
|
|
|
|
<para>Standard UNIX commands make shell scripts more versatile. The
|
|
power of scripts comes from coupling system commands and shell
|
|
directives with simple programming constructs.</para>
|
|
|
|
<sect1 id="basic">
|
|
<title>Basic Commands</title>
|
|
|
|
<variablelist id="basiccommands">
|
|
<title><anchor id="basiccommands1">The first commands a novice learns</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lsref"><command>ls</command></term>
|
|
<indexterm>
|
|
<primary>ls</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ls</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The basic file <quote>list</quote> command. It is all too easy
|
|
to underestimate the power of this humble command. For
|
|
example, using the <option>-R</option>, recursive option,
|
|
<command>ls</command> provides a tree-like listing of
|
|
a directory structure. Other useful options are
|
|
<option>-S</option>, sort listing by file size,
|
|
<option>-t</option>, sort by file modification time, and
|
|
<option>-i</option>, show file inodes (see <xref
|
|
linkend="idelete">).</para>
|
|
|
|
<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>
|
|
<term><anchor id="catref"><command>cat</command></term>
|
|
<term><command>tac</command></term>
|
|
<indexterm>
|
|
<primary>cat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cat</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>tac</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tac</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para><command>cat</command>, an acronym for
|
|
<wordasword>concatenate</wordasword>,
|
|
lists a file to <filename>stdout</filename>. When
|
|
combined with redirection (<token>></token> or
|
|
<token>>></token>), it is commonly used to concatenate
|
|
files.
|
|
|
|
<programlisting># Uses of 'cat'
|
|
cat filename # Lists the file.
|
|
|
|
cat file.1 file.2 file.3 > file.123 # Combines three files into one.</programlisting>
|
|
|
|
The <option>-n</option> option to <command>cat</command>
|
|
inserts consecutive numbers before all lines of the
|
|
target file(s). The <option>-b</option> option numbers
|
|
only the non-blank lines. The <option>-v</option> option
|
|
echoes nonprintable characters, using <token>^</token>
|
|
notation. The <option>-s</option> option squeezes multiple
|
|
consecutive blank lines into a single blank line.</para>
|
|
|
|
<para>See also <xref linkend="lnum"> and <xref linkend="rot13">.</para>
|
|
|
|
<note>
|
|
<para>
|
|
In a <link linkend="piperef">pipe</link>, it may be
|
|
more efficient to <link linkend="ioredirref">redirect</link>
|
|
the <filename>stdin</filename> to a file, rather than to
|
|
<command>cat</command> the file.
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting>cat filename | tr a-z A-Z
|
|
|
|
tr a-z A-Z < filename # Same effect, but starts one less process,
|
|
#+ and also dispenses with the pipe.</programlisting>
|
|
</para>
|
|
</note>
|
|
|
|
|
|
<para><command>tac</command>, is the inverse of
|
|
<wordasword>cat</wordasword>, listing a file backwards from its end.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>rev</command></term>
|
|
<indexterm>
|
|
<primary>rev</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>rev</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>reverses each line of a file, and outputs to
|
|
<filename>stdout</filename>. This does not have the same effect
|
|
as <command>tac</command>, as it preserves the order of
|
|
the lines, but flips each one around.</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>
|
|
<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>
|
|
|
|
<note>
|
|
<para>When used in a non-interactive script,
|
|
<command>mv</command> takes the <option>-f</option>
|
|
(<emphasis>force</emphasis>) option to bypass user
|
|
input.</para>
|
|
|
|
<para>When a directory is moved to a preexisting directory,
|
|
it becomes a subdirectory of the destination directory.</para>
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>mv source_directory target_directory</userinput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -lF target_directory</userinput>
|
|
<computeroutput>total 1
|
|
drwxrwxr-x 2 bozo bozo 1024 May 28 19:20 source_directory/</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>rm</command></term>
|
|
<indexterm>
|
|
<primary>rm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>rm</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Delete (remove) a file or files. The <option>-f</option>
|
|
option forces removal of even readonly files, and is useful
|
|
for bypassing user input in a script.</para>
|
|
|
|
<note>
|
|
<para>The <command>rm</command> command will, by
|
|
itself, fail to remove filenames beginning with a
|
|
dash.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>rm -badname</userinput>
|
|
<computeroutput>rm: invalid option -- b
|
|
Try `rm --help' for more information.</computeroutput></screen>
|
|
</para>
|
|
|
|
<para>The way to accomplish this is to preface the filename to be
|
|
removed with a <emphasis>dot-slash</emphasis> .</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>rm ./-badname</userinput></screen>
|
|
</para>
|
|
</note>
|
|
|
|
|
|
<warning><para>When used with the recursive flag
|
|
<option>-r</option>, this command removes files all
|
|
the way down the directory tree from the current
|
|
directory.</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. For example,
|
|
<userinput>mkdir -p project/programs/December</userinput>
|
|
creates the named directory. The
|
|
<replaceable>-p</replaceable> option automatically creates
|
|
any necessary parent directories.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="chmodref"><command>chmod</command></term>
|
|
<indexterm>
|
|
<primary>chmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>chmod</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Changes the attributes of an existing file (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 is analogous to
|
|
<command>chmod</command> above, but with different options
|
|
and a different invocation syntax, and it works only on
|
|
an <emphasis>ext2</emphasis> filesystem.</para>
|
|
|
|
<para>One particularly interesting <command>chattr</command>
|
|
option is <option>i</option>. A <command>chattr +i
|
|
<filename>filename</filename></command> marks the file
|
|
as immutable. The file cannot be modified, linked to,
|
|
or deleted , <emphasis>not even by root</emphasis>. This
|
|
file attribute can be set or removed only by root. In a
|
|
similar fashion, the <option>a</option> option marks the
|
|
file as append only.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>root# </prompt><userinput>chattr +i file1.txt</userinput>
|
|
|
|
|
|
<prompt>root# </prompt><userinput>rm file1.txt</userinput>
|
|
|
|
<computeroutput>rm: remove write-protected regular file `file1.txt'? y
|
|
rm: cannot remove `file1.txt': Operation not permitted</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>If a file has the <option>s</option> (secure)
|
|
attribute set, then when it is deleted its block is zeroed out
|
|
on the disk.</para>
|
|
|
|
<para>If a file has the <option>u</option> (undelete)
|
|
attribute set, then when it is deleted, its contents can still
|
|
be retrieved (undeleted).</para>
|
|
|
|
<para>If a file has the <option>c</option> (compress)
|
|
attribute set, then it will automatically be compressed
|
|
on writes to disk, and uncompressed on reads.</para>
|
|
|
|
<note><para>The file attributes set with
|
|
<command>chattr</command> do not show in a file listing
|
|
(<command>ls -l</command>).</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="linkref"><command>ln</command></term>
|
|
<listitem>
|
|
|
|
<para>Creates links to pre-existings files. A <quote>link</quote>
|
|
is a reference to a file, an alternate name for it.
|
|
The <command>ln</command> command permits referencing
|
|
the linked file by more than one name and is a superior
|
|
alternative to aliasing (see <xref linkend="ex18">).</para>
|
|
|
|
<para>The <command>ln</command> creates only a reference, a
|
|
pointer to the file only a few bytes in size.</para>
|
|
|
|
<para>The <command>ln</command> command is most often used
|
|
with the <option>-s</option>, symbolic or
|
|
<quote>soft</quote> link flag. An advantage of using the
|
|
<option>-s</option> flag is that it permits linking across
|
|
file systems.</para>
|
|
|
|
<para>The syntax of the command is a bit tricky. For example:
|
|
<userinput>ln -s oldfile newfile</userinput> links the
|
|
previously existing <filename>oldfile</filename> to the
|
|
newly created link, <filename>newfile</filename>.</para>
|
|
|
|
<caution><para>If a file named <filename>newfile</filename> has
|
|
previously existed, it will be deleted when the filename
|
|
<filename>newfile</filename> is preempted as the name for a
|
|
link.</para></caution>
|
|
|
|
|
|
<sidebar><title>Which type of link to use?</title>
|
|
|
|
<para>As John Macdonald explains it:</para>
|
|
|
|
<para>Both of these provide a certain measure of dual reference
|
|
-- if you edit the contents of the file using any
|
|
name, your changes will affect both the original name
|
|
and either a hard or soft new name. The differences
|
|
between them occurs when you work at a higher level.
|
|
The advantage of a hard link is that the new name is
|
|
totally independent of the old name -- if you remove or
|
|
rename the old name, that does not affect the hard link,
|
|
which continues to point to the data while it would leave
|
|
a soft link hanging pointing to the old name which is no
|
|
longer there. The advantage of a soft link is that it
|
|
can refer to a different file system (since it is just
|
|
a reference to a file name, not to actual data).</para>
|
|
|
|
</sidebar>
|
|
|
|
<para>Links give the ability to invoke a script (or any other type
|
|
of executable) with multiple names, and having that script
|
|
behave according to how it was invoked.</para>
|
|
|
|
<example id="hellol">
|
|
<title>Hello or Good-bye</title>
|
|
<programlisting>&hellol;</programlisting>
|
|
</example>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>man</command></term>
|
|
<term><command>info</command></term>
|
|
<indexterm>
|
|
<primary>man</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>man</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>info</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>info</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>These commands access the manual and information pages on
|
|
system commands and installed utilities. When available, the
|
|
<emphasis>info</emphasis> pages usually contain a more detailed
|
|
description than do the <emphasis>man</emphasis> pages.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
|
|
</sect1> <!-- End Basic Commands -->
|
|
|
|
|
|
<sect1 id="moreadv">
|
|
<title>Complex Commands</title>
|
|
|
|
<variablelist id="cclisting">
|
|
<title><anchor id="cclisting1">Commands for more advanced users</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="findref"><command>find</command></term>
|
|
<indexterm>
|
|
<primary>find</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>find</secondary>
|
|
</indexterm>
|
|
|
|
<indexterm>
|
|
<primary>{}</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>{}</secondary>
|
|
</indexterm>
|
|
|
|
<indexterm>
|
|
<primary>\;</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\;</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>-exec <replaceable>COMMAND</replaceable> \;</para>
|
|
<para>Carries out <replaceable>COMMAND</replaceable> on
|
|
each file that <command>find</command> matches.
|
|
The command sequence terminates with <token>\;</token>
|
|
(the <quote>;</quote> is escaped to make certain
|
|
the shell passes it to <command>find</command>
|
|
literally).</para>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>find ~/ -name '*.txt'</userinput>
|
|
<computeroutput>/home/bozo/.kde/share/apps/karm/karmdata.txt
|
|
/home/bozo/misc/irmeyc.txt
|
|
/home/bozo/test-scripts/1.txt</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="curlybracketsref"></para>
|
|
|
|
<para>If <replaceable>COMMAND</replaceable> contains
|
|
<token>{}</token>, then <command>find</command>
|
|
substitutes the full path name of the selected file for
|
|
<quote>{}</quote>.</para>
|
|
|
|
<para>
|
|
<programlisting>find ~/ -name 'core*' -exec rm {} \;
|
|
# Removes all core dump files from user's home directory.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
<programlisting>find /home/bozo/projects -mtime 1
|
|
# Lists all files in /home/bozo/projects directory tree
|
|
#+ that were modified within the last day.
|
|
#
|
|
# mtime = last modification time of the target file
|
|
# ctime = last status change time (via 'chmod' or otherwise)
|
|
# atime = last access time
|
|
|
|
DIR=/home/bozo/junk_files
|
|
find "$DIR" -type f -atime +5 -exec rm {} \;
|
|
# ^^
|
|
# Curly brackets are placeholder for the pathname output by "find."
|
|
#
|
|
# Deletes all files in "/home/bozo/junk_files"
|
|
#+ that have not been accessed in at least 5 days.
|
|
#
|
|
# "-type filetype", where
|
|
# f = regular file
|
|
# d = directory, etc.
|
|
# (The 'find' manpage has a complete listing.)</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 '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'
|
|
#
|
|
# [:digit:] is one of the character classes
|
|
#+ introduced with the POSIX 1003.2 standard.
|
|
|
|
# Thanks, Stephane Chazelas.
|
|
</programlisting></para>
|
|
|
|
|
|
<note><para>The <option>-exec</option> option to
|
|
<command>find</command> should not be confused with the <link
|
|
linkend="execref">exec</link> shell builtin.</para></note>
|
|
|
|
<example id="ex57">
|
|
<title><command>Badname</command>, eliminate file names
|
|
in current directory containing bad characters and <link
|
|
linkend="whitespaceref">whitespace</link>.</title>
|
|
<programlisting>&ex57;</programlisting>
|
|
</example>
|
|
|
|
<example id="idelete">
|
|
<title>Deleting a file by its <emphasis>inode</emphasis>
|
|
number</title>
|
|
<programlisting>&idelete;</programlisting>
|
|
</example>
|
|
|
|
<para>See <xref linkend="ex48">, <xref linkend="ex58">,
|
|
and <xref linkend="findstring"> for scripts using
|
|
<command>find</command>. Its manpage provides more detail
|
|
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>
|
|
<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>
|
|
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>
|
|
|
|
<para>The default command for <command>xargs</command> is
|
|
<link linkend="echoref">echo</link>. This means that input
|
|
piped to <command>xargs</command> may have linefeeds and
|
|
other whitespace characters stripped out.
|
|
|
|
<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>
|
|
|
|
<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>
|
|
option is <option>-n <replaceable>NN</replaceable></option>,
|
|
which limits to <replaceable>NN</replaceable> the number
|
|
of arguments passed.</para>
|
|
<para><userinput>ls | xargs -n 8 echo</userinput> lists the files in the
|
|
current directory in <literal>8</literal> columns.</para>
|
|
</tip>
|
|
|
|
|
|
<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">
|
|
<title>Logfile: Using <command>xargs</command> to monitor system log</title>
|
|
<programlisting>&ex41;</programlisting>
|
|
</example>
|
|
|
|
<para><link linkend="curlybracketsref">As in
|
|
<command>find</command></link>, a curly bracket
|
|
pair serves as a placeholder for replacement text.</para>
|
|
|
|
<example id="ex42">
|
|
<title>Copying files in current directory to another</title>
|
|
<programlisting>&ex42;</programlisting>
|
|
</example>
|
|
|
|
<example id="killbyname">
|
|
<title>Killing processes by name</title>
|
|
<programlisting>&killbyname;</programlisting>
|
|
</example>
|
|
|
|
<example id="wf2">
|
|
<title><command>Word frequency analysis</command>
|
|
using <command>xargs</command></title>
|
|
<programlisting>&wf2;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="exprref"><userinput>expr</userinput></term>
|
|
<indexterm>
|
|
<primary>expr</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>All-purpose expression evaluator:
|
|
Concatenates and evaluates the arguments according
|
|
to the operation given (arguments must be separated
|
|
by spaces). Operations may be arithmetic, comparison,
|
|
string, or logical.</para>
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term><userinput>expr 3 + 5</userinput></term>
|
|
<listitem>
|
|
<para>returns <literal>8</literal></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>expr 5 % 3</userinput></term>
|
|
<listitem>
|
|
<para>returns 2</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>expr 5 \* 3</userinput></term>
|
|
<listitem>
|
|
<para>returns 15</para>
|
|
<para>The multiplication operator
|
|
must be escaped when used in an arithmetic expression
|
|
with <command>expr</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>y=`expr $y + 1`</userinput></term>
|
|
<listitem>
|
|
<para>Increment a variable, with the same effect
|
|
as <userinput>let y=y+1</userinput> and
|
|
<userinput>y=$(($y+1))</userinput>. This is an
|
|
example of <link linkend="arithexpref">arithmetic
|
|
expansion</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="expextrsub"><userinput>z=`expr substr
|
|
$string $position $length`</userinput></term>
|
|
<listitem>
|
|
<para>Extract substring of $length characters, starting
|
|
at $position.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<example id="ex45">
|
|
<title>Using <command>expr</command></title>
|
|
<programlisting>&ex45;</programlisting>
|
|
</example>
|
|
|
|
<important>
|
|
<para>The <link linkend="nullref">:</link> operator
|
|
can substitute for <command>match</command>. For example,
|
|
<userinput>b=`expr $a : [0-9]*`</userinput> is the
|
|
exact equivalent of <userinput>b=`expr match $a
|
|
[0-9]*`</userinput> in the above listing.</para>
|
|
|
|
<para><programlisting>&ex45a;</programlisting></para>
|
|
</important>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<para>This 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>
|
|
|
|
|
|
<para><link linkend="perlref">Perl</link>,
|
|
<link linkend="sedref">sed</link>, and <link
|
|
linkend="awkref">awk</link> have far superior string
|
|
parsing facilities. A short <command>sed</command> or
|
|
<command>awk</command> <quote>subroutine</quote> within
|
|
a script (see <xref linkend="wrapper">) is an attractive
|
|
alternative to using <command>expr</command>.</para>
|
|
|
|
|
|
<para>See <xref linkend="String-Manipulation"> for more on
|
|
string operations.</para>
|
|
|
|
|
|
</sect1> <!-- End Complex Commands -->
|
|
|
|
|
|
|
|
<sect1 id="timedate">
|
|
<title>Time / Date Commands</title>
|
|
|
|
<variablelist id="tdlisting">
|
|
<title><anchor id="tdlisting1">Time/date and timing</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dateref"><command>date</command></term>
|
|
<indexterm>
|
|
<primary>date</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>date</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Simply invoked, <command>date</command> prints the date and
|
|
time to <filename>stdout</filename>. Where this command gets
|
|
interesting is in its formatting and parsing options.</para>
|
|
|
|
<example id="ex51">
|
|
<title>Using <command>date</command></title>
|
|
<programlisting>&ex51;</programlisting>
|
|
</example>
|
|
|
|
<para>The <option>-u</option> option gives the UTC (Universal
|
|
Coordinated Time).</para>
|
|
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>date</userinput>
|
|
<computeroutput>Fri Mar 29 21:07:39 MST 2002</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>date -u</userinput>
|
|
<computeroutput>Sat Mar 30 04:07:42 UTC 2002</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="daterandref"></para>
|
|
<para>The <command>date</command> command has quite a number of
|
|
output options. For example <option>%N</option> gives the
|
|
nanosecond portion of the current time. One interesting use for
|
|
this is to generate six-digit random integers.
|
|
<programlisting>date +%N | sed -e 's/000$//' -e 's/^0//'
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
# Strip off leading and trailing zeroes, if present.</programlisting>
|
|
</para>
|
|
|
|
<para>There are many more options (try <command>man date</command>).
|
|
<programlisting>date +%j
|
|
# Echoes day of the year (days elapsed since January 1).
|
|
|
|
date +%k%M
|
|
# Echoes hour and minute in 24-hour format, as a single digit string.</programlisting></para>
|
|
|
|
<para>See also <xref linkend="ex58">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>zdump</command></term>
|
|
<indexterm>
|
|
<primary>zdump</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>time zone dump</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Time zone dump: echoes the time in a specified time zone.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>zdump EST</userinput>
|
|
<computeroutput>EST Tue Sep 18 22:09:22 2001 EST</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="timref"><command>time</command></term>
|
|
<indexterm>
|
|
<primary>time</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>time</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Outputs 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>
|
|
|
|
<note><para>The <command>touch</command> command is
|
|
equivalent to <userinput>: >> newfile</userinput>
|
|
or <userinput>>> newfile</userinput> (for ordinary
|
|
files).</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="atref"><command>at</command></term>
|
|
<indexterm>
|
|
<primary>at</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>at</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>cron</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cron</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>at</command> job control command executes
|
|
a given set of commands at a specified time. Superficially,
|
|
it resembles <link linkend="cronref">cron</link>, however,
|
|
<command>at</command> is chiefly useful for one-time execution
|
|
of a command set.</para>
|
|
|
|
<para><userinput>at 2pm January 15</userinput> prompts for a set of
|
|
commands to execute at that time. These commands should be
|
|
shell-script compatible, since, for all practical
|
|
purposes, the user is typing in an executable shell
|
|
script a line at a time. Input terminates with a <link
|
|
linkend="ctldref">Ctl-D</link>.</para>
|
|
|
|
<para>Using either the <option>-f</option> option or input
|
|
redirection (<token><</token>), <command>at</command>
|
|
reads a command list from a file. This file is an
|
|
executable shell script, though it should, of course,
|
|
be noninteractive. Particularly clever is including the
|
|
<link linkend="runpartsref">run-parts</link> command in
|
|
the file to execute a different set of scripts.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>at 2:30 am Friday < at-jobs.list</userinput>
|
|
<computeroutput>job 2 at 2000-10-27 02:30</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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. It can be useful
|
|
for timing or in processes running in the background,
|
|
checking for a specific event every so often (polling),
|
|
as in <xref linkend="online">.
|
|
<programlisting>sleep 3 # Pauses 3 seconds.</programlisting>
|
|
</para>
|
|
|
|
<note><para>The <command>sleep</command> command defaults to
|
|
seconds, but minute, hours, or days may also be specified.
|
|
<programlisting>sleep 3 h # Pauses 3 hours!</programlisting>
|
|
</para></note>
|
|
|
|
<note><para>The <link linkend="watchref">watch</link> command may
|
|
be a better choice than <command>sleep</command> for running
|
|
commands at timed intervals.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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. It can be used for fine-grain timing, or for
|
|
polling an ongoing process at very frequent intervals.</para>
|
|
|
|
<para>
|
|
<programlisting>usleep 30 # Pauses 30 microseconds.</programlisting>
|
|
</para>
|
|
|
|
<para>This command is part of the Red Hat <emphasis>initscripts /
|
|
rc-scripts</emphasis> package.</para>
|
|
|
|
<caution><para>The <command>usleep</command> command does not
|
|
provide particularly accurate timing, and is therefore
|
|
unsuitable for critical timing loops.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
</sect1> <!-- End Time / Date Commands -->
|
|
|
|
|
|
|
|
|
|
<sect1 id="textproc">
|
|
<title>Text Processing Commands</title>
|
|
|
|
<variablelist id="tpcommandlisting">
|
|
<title><anchor id="tpcommandlisting1">Commands affecting text and
|
|
text files</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sortref"><command>sort</command></term>
|
|
<indexterm>
|
|
<primary>sort</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sort</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>File sorter, often used as a filter in a pipe. This
|
|
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
|
|
capabilities and options. See <xref linkend="findstring">,
|
|
<xref linkend="symlinks">, and <xref linkend="makedict">.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
<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
|
|
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>
|
|
|
|
</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>
|
|
<term><anchor id="cutref"><command>cut</command></term>
|
|
<indexterm>
|
|
<primary>cut</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cut</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>awk</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>awk</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>A tool for extracting fields from files. It is similar to the
|
|
<userinput>print $N</userinput> command set in <link
|
|
linkend="awkref">awk</link>, but more limited. It may be
|
|
simpler to use <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>
|
|
|
|
<para>Using <command>cut</command> to extract message headers from
|
|
an e-mail folder:
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>grep '^Subject:' read-messages | cut -c10-80</userinput>
|
|
<computeroutput>Re: Linux suitable for mission-critical apps?
|
|
MAKE MILLIONS WORKING AT HOME!!!
|
|
Spam complaint
|
|
Re: Spam complaint</computeroutput></screen>
|
|
</para>
|
|
|
|
<para>Using <command>cut</command> to parse a file:
|
|
<programlisting># List all the users in /etc/passwd.
|
|
|
|
FILENAME=/etc/passwd
|
|
|
|
for user in $(cut -d: -f1 $FILENAME)
|
|
do
|
|
echo $user
|
|
done
|
|
|
|
# Thanks, Oleg Philon for suggesting this.</programlisting></para>
|
|
|
|
<para><userinput>cut -d ' ' -f2,3 filename</userinput> is equivalent to
|
|
<userinput>awk -F'[ ]' '{ print $2, $3 }' filename</userinput></para>
|
|
|
|
<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.
|
|
|
|
<example id="scriptdetector">
|
|
<title>Which files are scripts?</title>
|
|
<programlisting>&scriptdetector;</programlisting>
|
|
</example>
|
|
|
|
<example id="rnd">
|
|
<title>Generating 10-digit random numbers</title>
|
|
<programlisting>&rnd;</programlisting>
|
|
</example>
|
|
|
|
See also <xref linkend="ex52">.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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
|
|
<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> -- <emphasis>global -
|
|
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>
|
|
</cmdsynopsis>Search the target file(s) for
|
|
occurrences of <replaceable>pattern</replaceable>, where
|
|
<replaceable>pattern</replaceable> may be literal text
|
|
or a Regular Expression.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep '[rst]ystem.$' osinfo.txt</userinput>
|
|
<computeroutput>The GPL governs the distribution of the Linux operating system.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>If no target file(s) specified, <command>grep</command>
|
|
works as a filter on <filename>stdout</filename>, as in
|
|
a <link linkend="piperef">pipe</link>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ps ax | grep clock</userinput>
|
|
<computeroutput>765 tty1 S 0:00 xclock
|
|
901 pts/1 S 0:00 grep clock</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <option>-i</option> option causes a case-insensitive
|
|
search.</para>
|
|
|
|
<para>The <option>-w</option> option matches only whole
|
|
words.</para>
|
|
|
|
<para>The <option>-l</option> option lists only the files in which
|
|
matches were found, but not the matching lines.</para>
|
|
|
|
<para>The <option>-r</option> (recursive) option searches files in
|
|
the current working directory and all subdirectories below
|
|
it.</para>
|
|
|
|
<para>The <option>-n</option> option lists the matching lines,
|
|
together with line numbers.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep -n Linux osinfo.txt</userinput>
|
|
<computeroutput>2:This is a file containing information about Linux.
|
|
6:The GPL governs the distribution of the Linux operating system.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <option>-v</option> (or <option>--invert-match</option>)
|
|
option <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>
|
|
|
|
<para>When invoked with more than one target file given,
|
|
<command>grep</command> specifies which file contains
|
|
matches.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep Linux osinfo.txt misc.txt</userinput>
|
|
<computeroutput>osinfo.txt:This is a file containing information about Linux.
|
|
osinfo.txt:The GPL governs the distribution of the Linux operating system.
|
|
misc.txt:The Linux operating system is steadily gaining in popularity.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<tip>
|
|
<para>To force <command>grep</command> to show the filename
|
|
when searching only one target file, simply give
|
|
<filename>/dev/null</filename> as the second file.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep Linux osinfo.txt /dev/null</userinput>
|
|
<computeroutput>osinfo.txt:This is a file containing information about Linux.
|
|
osinfo.txt:The GPL governs the distribution of the Linux operating system.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</tip>
|
|
|
|
|
|
<para>If there is a successful match, <command>grep</command>
|
|
returns an <link linkend="exitstatusref">exit status</link>
|
|
of 0, which makes it useful in a condition test in a
|
|
script, especially in combination with the <option>-q</option>
|
|
option to suppress output.
|
|
<programlisting>SUCCESS=0 # if grep lookup succeeds
|
|
word=Linux
|
|
filename=data.file
|
|
|
|
grep -q "$word" "$filename" # The "-q" option causes nothing to echo to stdout.
|
|
|
|
if [ $? -eq $SUCCESS ]
|
|
# if grep -q "$word" "$filename" can replace lines 5 - 7.
|
|
then
|
|
echo "$word found in $filename"
|
|
else
|
|
echo "$word not found in $filename"
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
|
|
<para><xref linkend="online"> demonstrates how to use
|
|
<command>grep</command> to search for a word pattern in
|
|
a system logfile.</para>
|
|
|
|
|
|
<example id="grp">
|
|
<title>Emulating <quote>grep</quote> in a script</title>
|
|
<programlisting>&grp;</programlisting>
|
|
</example>
|
|
|
|
<para>How can <command>grep</command> search for two (or
|
|
more) separate patterns? What if you want
|
|
<command>grep</command> to display all lines in a file
|
|
or files that contain both <quote>pattern1</quote>
|
|
<emphasis>and</emphasis> <quote>pattern2</quote>?</para>
|
|
|
|
<para>One method is to <link
|
|
linkend="piperef">pipe</link> the result of <command>grep
|
|
pattern1</command> to <command>grep pattern2</command>.</para>
|
|
|
|
<para>For example, given the following file:</para>
|
|
|
|
<para>
|
|
<programlisting># Filename: tstfile
|
|
|
|
This is a sample file.
|
|
This is an ordinary text file.
|
|
This file does not contain any unusual text.
|
|
This file is not unusual.
|
|
Here is some text.</programlisting>
|
|
</para>
|
|
|
|
<para>Now, let's search this file for lines containing
|
|
<emphasis>both</emphasis> <quote>file</quote> and
|
|
<quote>test</quote> . . . </para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>grep file tstfile</userinput>
|
|
<computeroutput># Filename: tstfile
|
|
This is a sample file.
|
|
This is an ordinary text file.
|
|
This file does not contain any unusual text.
|
|
This file is not unusual.</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>grep file tstfile | grep text</userinput>
|
|
<computeroutput>This is an ordinary text file.
|
|
This file does not contain any unusual text.</computeroutput></screen>
|
|
|
|
<para>--</para>
|
|
|
|
<para><anchor id="egrepref"><command>egrep</command>
|
|
- <emphasis>extended grep</emphasis> - is the same
|
|
as <command>grep -E</command>. This uses a somewhat
|
|
different, extended set of <link linkend="regexref">Regular
|
|
Expressions</link>, which can make the search a bit more
|
|
flexible.</para>
|
|
|
|
<para><command>fgrep</command> - <emphasis>fast grep</emphasis>
|
|
- is the same as <command>grep -F</command>. It does
|
|
a literal string search (no Regular Expressions), which
|
|
usually speeds things up a bit.</para>
|
|
|
|
<note><para>On some Linux distros, <command>egrep</command> and
|
|
<command>fgrep</command> are symbolic links to, or aliases for
|
|
<command>grep</command>, but invoked with the
|
|
<option>-E</option> and <option>-F</option> options,
|
|
respectively.</para></note>
|
|
|
|
<example id="dictlookup">
|
|
<title>Looking up definitions in <citetitle
|
|
pubwork="book">Webster's 1913 Dictionary</citetitle></title>
|
|
<programlisting>&dictlookup;</programlisting>
|
|
</example>
|
|
|
|
<para><command>agrep</command> (<emphasis>approximate
|
|
grep</emphasis>) 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>
|
|
|
|
|
|
<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>
|
|
|
|
</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/share/doc/sed-4.1.2/README</userinput>
|
|
<computeroutput>13 70 447 README</computeroutput>
|
|
[13 lines 70 words 447 characters]</screen></para>
|
|
|
|
<para><userinput>wc -w</userinput> gives only the word count.</para>
|
|
<para><userinput>wc -l</userinput> gives only the line count.</para>
|
|
<para><userinput>wc -c</userinput> gives only the byte count.</para>
|
|
<para><userinput>wc -m</userinput> gives only the character count.</para>
|
|
<para><userinput>wc -L</userinput> gives only the length of the longest line.</para>
|
|
|
|
<para>Using <command>wc</command> to count how many
|
|
<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>
|
|
|
|
<para>Using <command>wc</command> to total up the size of all the
|
|
files whose names begin with letters in the range d - h
|
|
<screen><prompt>bash$ </prompt><userinput>wc [d-h]* | grep total | awk '{print $3}'</userinput>
|
|
<computeroutput>71832</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Using <command>wc</command> to count the instances of the
|
|
word <quote>Linux</quote> in the main source file for
|
|
this book.
|
|
<screen><prompt>bash$ </prompt><userinput>grep Linux abs-book.sgml | wc -l</userinput>
|
|
<computeroutput>50</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>See also <xref linkend="ex52"> and <xref
|
|
linkend="redir4">.</para>
|
|
|
|
<para>Certain commands include some of the
|
|
functionality of <command>wc</command> as options.
|
|
|
|
<programlisting>... | grep foo | wc -l
|
|
# This frequently used construct can be more concisely rendered.
|
|
|
|
... | grep -c foo
|
|
# Just use the "-c" (or "--count") option of grep.
|
|
|
|
# Thanks, S.C.</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="trref"><command>tr</command></term>
|
|
<indexterm>
|
|
<primary>tr</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tr</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>character translation filter.</para>
|
|
|
|
<caution><para><link linkend="ucref">Must use quoting and/or
|
|
brackets</link>, as appropriate. Quotes prevent the
|
|
shell from reinterpreting the special characters in
|
|
<command>tr</command> command sequences. Brackets should be
|
|
quoted to prevent expansion by the shell. </para></caution>
|
|
|
|
<para>Either <userinput>tr "A-Z" "*" <filename</userinput>
|
|
or <userinput>tr A-Z \* <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.
|
|
<programlisting>echo "abcdef" # abcdef
|
|
echo "abcdef" | tr -d b-d # aef
|
|
|
|
|
|
tr -d 0-9 <filename
|
|
# Deletes all digits from the file "filename".</programlisting></para>
|
|
|
|
<para>The <option>--squeeze-repeats</option> (or
|
|
<option>-s</option>) option deletes all but the
|
|
first instance of a string of consecutive characters.
|
|
This option is useful for removing excess <link
|
|
linkend="whitespaceref">whitespace</link>.
|
|
|
|
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>echo "XXXXX" | tr --squeeze-repeats 'X'</userinput>
|
|
<computeroutput>X</computeroutput></screen></para>
|
|
|
|
<para>The <option>-c</option> <quote>complement</quote>
|
|
option <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
|
|
linkend="posixref">POSIX character classes</link>.
|
|
<footnote><para>This is only true of the GNU version of
|
|
<command>tr</command>, not the generic version often found on
|
|
commercial UNIX systems.</para></footnote>
|
|
</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo "abcd2ef1" | tr '[:alpha:]' -</userinput>
|
|
<computeroutput>----2--1</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<example id="ex49">
|
|
<title><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>
|
|
|
|
<example id="cryptoquote">
|
|
<title>Generating <quote>Crypto-Quote</quote> Puzzles</title>
|
|
<programlisting>&cryptoquote;</programlisting>
|
|
</example>
|
|
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
<programlisting>&colm;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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 <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>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<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>localization</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>The GNU <command>gettext</command> package is a set of
|
|
utilities for <link linkend="localization">localizing</link>
|
|
and translating the text output of programs into foreign
|
|
languages. While originally intended for C programs, it
|
|
now supports quite a number of programming and scripting
|
|
languages.</para>
|
|
|
|
<para>The <command>gettext</command>
|
|
<emphasis>program</emphasis> works on shell scripts. See
|
|
the <replaceable>info page</replaceable>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="msgfmtref"><command>msgfmt</command></term>
|
|
<indexterm>
|
|
<primary>msgfmt</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>localization</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>A program for generating binary
|
|
message catalogs. It is used for <link
|
|
linkend="localization">localization</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>iconv</command></term>
|
|
<indexterm>
|
|
<primary>iconv</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>encoding</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>A utility for converting file(s) to a different encoding
|
|
(character set). Its chief use is for <link
|
|
linkend="localization">localization</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
<varlistentry>
|
|
<term><command>TeX</command></term>
|
|
<term><command>gs</command></term>
|
|
<indexterm>
|
|
<primary>TeX</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>TeX</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>gs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>Postscript</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para><command>TeX</command> and <command>Postscript</command>
|
|
are text markup languages used for preparing copy for
|
|
printing or formatted video display.</para>
|
|
|
|
<para><command>TeX</command> is Donald Knuth's elaborate
|
|
typsetting system. It is often convenient to write a
|
|
shell script encapsulating all the options and arguments
|
|
passed to one of these markup languages.</para>
|
|
|
|
<para><emphasis>Ghostscript</emphasis>
|
|
(<command>gs</command>) is a GPL-ed Postscript
|
|
interpreter.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>enscript</command></term>
|
|
<indexterm>
|
|
<primary>enscript</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>PostScript</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Utility for converting plain text file to PostScript</para>
|
|
<para>For example, <command>enscript filename.txt -p filename.ps</command>
|
|
produces the PostScript output file
|
|
<filename>filename.ps</filename>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="groffref"><command>groff</command></term>
|
|
<term><command>tbl</command></term>
|
|
<term><command>eqn</command></term>
|
|
<indexterm>
|
|
<primary>groff</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>groff</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>tbl</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>table</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>eqn</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>equation</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Yet another text markup and display formatting language
|
|
is <command>groff</command>. This is the enhanced GNU version
|
|
of the venerable UNIX <command>roff/troff</command> display
|
|
and typesetting package. <emphasis>Manpages</emphasis>
|
|
use <command>groff</command>.</para>
|
|
|
|
<para>The <command>tbl</command> table processing utility
|
|
is considered part of <command>groff</command>, as its
|
|
function is to convert table markup into
|
|
<command>groff</command> commands.</para>
|
|
|
|
<para>The <command>eqn</command> equation processing utility
|
|
is likewise part of <command>groff</command>, and
|
|
its function is to convert equation markup into
|
|
<command>groff</command> commands.</para>
|
|
|
|
<example id="manview">
|
|
<title><command>manview</command>: Viewing formatted manpages
|
|
</title>
|
|
<programlisting>&manview;</programlisting>
|
|
</example>
|
|
|
|
</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>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Text Processing Commands -->
|
|
|
|
|
|
<sect1 id="filearchiv">
|
|
<title>File and Archiving Commands</title>
|
|
|
|
<variablelist id="faarchiving">
|
|
<title><anchor id="faarchiving1">Archiving</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tarref"><command>tar</command></term>
|
|
<indexterm>
|
|
<primary>tar</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tar</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>The standard UNIX archiving utility. Originally a
|
|
<wordasword>Tape ARchiving</wordasword> program, it has
|
|
developed into a general purpose package that can handle
|
|
all manner of archiving with all types of destination
|
|
devices, ranging from tape drives to regular files to even
|
|
<filename>stdout</filename> (see <xref linkend="ex58">). GNU
|
|
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>).
|
|
|
|
<footnote>
|
|
<para>
|
|
A <command>tar czvf archive_name.tar.gz *</command>
|
|
<emphasis>will</emphasis> include dotfiles in
|
|
directories <emphasis>below</emphasis> the current
|
|
working directory. This is an undocumented GNU
|
|
<command>tar</command> <quote>feature</quote>.
|
|
</para>
|
|
</footnote>
|
|
</para>
|
|
|
|
|
|
<para>Some useful <command>tar</command> options:
|
|
<orderedlist>
|
|
|
|
<listitem><para><option>-c</option> create (a new
|
|
archive)</para></listitem>
|
|
|
|
<listitem><para><option>-x</option> extract (files from
|
|
existing archive)</para></listitem>
|
|
|
|
<listitem>
|
|
<para><option>--delete</option> delete (files
|
|
from existing archive)</para>
|
|
<caution><para>This option will not work on magnetic tape
|
|
devices.</para></caution>
|
|
</listitem>
|
|
|
|
<listitem><para><option>-r</option> append (files to
|
|
existing archive)</para></listitem>
|
|
|
|
<listitem><para><option>-A</option> append
|
|
(<emphasis>tar</emphasis> files to
|
|
existing archive)</para></listitem>
|
|
|
|
<listitem><para><option>-t</option> list (contents of
|
|
existing archive)</para></listitem>
|
|
|
|
<listitem><para><option>-u</option> update archive</para></listitem>
|
|
|
|
<listitem><para><option>-d</option> compare archive with
|
|
specified filesystem</para></listitem>
|
|
|
|
<listitem>
|
|
<para><option>-z</option> <link
|
|
linkend="gzipref">gzip</link> the archive</para>
|
|
<para>(compress or uncompress, depending on whether
|
|
combined with the <option>-c</option> or
|
|
<option>-x</option>) option</para>
|
|
</listitem>
|
|
|
|
<listitem><para><option>-j</option>
|
|
<link linkend="bzipref">bzip2</link> the
|
|
archive</para></listitem>
|
|
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<caution><para>It may be difficult to recover data from a
|
|
corrupted <emphasis>gzipped</emphasis> tar
|
|
archive. When archiving important files, make multiple
|
|
backups.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rpmref"><command>rpm</command></term>
|
|
<indexterm>
|
|
<primary>rpm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>package manager</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>The <emphasis>Red Hat Package Manager</emphasis>, or
|
|
<command>rpm</command> utility provides a wrapper for
|
|
source or binary archives. It includes commands for
|
|
installing and checking the integrity of packages, among
|
|
other things.</para>
|
|
|
|
<para>A simple <command>rpm -i package_name.rpm</command>
|
|
usually suffices to install a package, though there are many
|
|
more options available.</para>
|
|
|
|
|
|
<tip>
|
|
<para><userinput>rpm -qf</userinput> identifies which package a
|
|
file originates from.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>rpm -qf /bin/ls</userinput>
|
|
<computeroutput>coreutils-5.2.1-31</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</tip>
|
|
|
|
<tip>
|
|
<para><userinput>rpm -qa</userinput> gives a
|
|
complete list of all installed <emphasis>rpm</emphasis> packages
|
|
on a given system. An <userinput>rpm -qa package_name</userinput>
|
|
lists only the package(s) corresponding to
|
|
<filename>package_name</filename>.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>rpm -qa</userinput>
|
|
<computeroutput>redhat-logos-1.1.3-1
|
|
glibc-2.2.4-13
|
|
cracklib-2.7-12
|
|
dosfstools-2.7-1
|
|
gdbm-1.8.0-10
|
|
ksymoops-2.4.1-1
|
|
mktemp-1.5-11
|
|
perl-5.6.0-17
|
|
reiserfs-utils-3.x.0j-2
|
|
...</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>rpm -qa docbook-utils</userinput>
|
|
<computeroutput>docbook-utils-0.6.9-2</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>rpm -qa docbook | grep docbook</userinput>
|
|
<computeroutput>docbook-dtd31-sgml-1.0-10
|
|
docbook-style-dsssl-1.64-3
|
|
docbook-dtd30-sgml-1.0-10
|
|
docbook-dtd40-sgml-1.0-11
|
|
docbook-utils-pdf-0.6.9-2
|
|
docbook-dtd41-sgml-1.0-10
|
|
docbook-utils-0.6.9-2</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>cpio</command></term>
|
|
<indexterm>
|
|
<primary>cpio</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cpio</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This specialized archiving copy command
|
|
(<command>c</command>o<command>p</command>y
|
|
<command>i</command>nput and <command>o</command>utput)
|
|
is rarely seen any more, having been supplanted by
|
|
<command>tar</command>/<command>gzip</command>. It still
|
|
has its uses, such as moving a directory tree.</para>
|
|
|
|
<example id="ex48">
|
|
<title>Using <command>cpio</command> to move a directory tree</title>
|
|
<programlisting>&ex48;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>rpm2cpio</command></term>
|
|
<indexterm>
|
|
<primary>rpm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cpio</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This command extracts a
|
|
<command>cpio</command> archive from an <link
|
|
linkend="rpmref">rpm</link> one.</para>
|
|
|
|
<example id="derpm">
|
|
<title>Unpacking an <emphasis>rpm</emphasis> archive</title>
|
|
<programlisting>&derpm;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="facompression">
|
|
<title><anchor id="facompression1">Compression</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="gzipref"><command>gzip</command></term>
|
|
<indexterm>
|
|
<primary>gzip</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>gzip</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>The standard GNU/UNIX compression utility, replacing
|
|
the inferior and proprietary
|
|
<command>compress</command>. The corresponding decompression
|
|
command is <command>gunzip</command>, which is the equivalent of
|
|
<command>gzip -d</command>.</para>
|
|
|
|
<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>
|
|
<term><anchor id="bzipref"><command>bzip2</command></term>
|
|
<indexterm>
|
|
<primary>bzip2</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>bzip2</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>An alternate compression utility, usually more efficient
|
|
(but slower) than <command>gzip</command>, especially on
|
|
large files. The corresponding decompression command is
|
|
<command>bunzip2</command>.</para>
|
|
|
|
<note><para>Newer versions of <link
|
|
linkend="tarref">tar</link> have been patched with
|
|
<command>bzip2</command> support.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
<tip><para>The <command>znew</command> command transforms
|
|
<emphasis>compressed</emphasis> files into
|
|
<emphasis>gzipped</emphasis> ones.</para></tip>
|
|
</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>
|
|
|
|
<varlistentry>
|
|
<term><command>zip</command></term>
|
|
<term><command>unzip</command></term>
|
|
<indexterm>
|
|
<primary>zip</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>pkzip.exe</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>unzip</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>unzip</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Cross-platform file archiving and compression utility
|
|
compatible with DOS <emphasis>pkzip.exe</emphasis>.
|
|
<quote>Zipped</quote> archives seem to be a more
|
|
acceptable medium of exchange on the Internet than
|
|
<quote>tarballs</quote>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="fainformation">
|
|
<title><anchor id="fainformation1">File Information</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="fileref"><command>file</command></term>
|
|
<indexterm>
|
|
<primary>file</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>file</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>A utility for identifying file types. The command
|
|
<userinput>file file-name</userinput> will return a
|
|
file specification for <filename>file-name</filename>,
|
|
such as <computeroutput>ascii text</computeroutput> or
|
|
<computeroutput>data</computeroutput>. It references
|
|
the <link linkend="magnumref">magic numbers</link>
|
|
found in <filename>/usr/share/magic</filename>,
|
|
<filename>/etc/magic</filename>, or
|
|
<filename>/usr/lib/magic</filename>, depending on the
|
|
Linux/UNIX distribution.</para>
|
|
|
|
<para>The <option>-f</option> option causes
|
|
<command>file</command> to run in 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>
|
|
|
|
<para>
|
|
<programlisting># Find sh and Bash scripts in a given directory:
|
|
|
|
DIRECTORY=/usrlocal/bin
|
|
KEYWORD=Bourne
|
|
# Bourne and Bourne-Again shell scripts
|
|
|
|
file $DIRECTORY/* | fgrep $KEYWORD
|
|
|
|
# Output:
|
|
|
|
# /usr/local/bin/burn-cd: Bourne-Again shell script text executable
|
|
# /usr/local/bin/burnit: Bourne-Again shell script text executable
|
|
# /usr/local/bin/cassette.sh: Bourne shell script text executable
|
|
# /usr/local/bin/copy-cd: Bourne-Again shell script text executable
|
|
# . . .</programlisting>
|
|
</para>
|
|
|
|
<example id="stripc">
|
|
<title>Stripping comments from C program files</title>
|
|
<programlisting>&stripc;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whichref"><command>which</command></term>
|
|
<indexterm>
|
|
<primary>which</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>which</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para><command>which command-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
|
|
<emphasis>manpage</emphasis>.</para>
|
|
<para><userinput>$bash whereis rm</userinput>
|
|
<screen><computeroutput>rm: /bin/rm /usr/share/man/man1/rm.1.bz2</computeroutput></screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whatisref"><command>whatis</command></term>
|
|
<indexterm>
|
|
<primary>whatis</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>whatis</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para><command>whatis 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>
|
|
|
|
<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>
|
|
</para>
|
|
</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>readlink</command></term>
|
|
<indexterm>
|
|
<primary>readlink</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>link</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Disclose the file that a symbolic link points to.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>readlink /usr/bin/awk</userinput>
|
|
<computeroutput>../../bin/gawk</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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. The
|
|
<option>-c</option> and <option>-u</option> options likewise
|
|
make the output of the command easier to interpret.</para>
|
|
|
|
<para>There are available various fancy frontends for
|
|
<command>diff</command>, such as <command>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 <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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>diff3</command></term>
|
|
<indexterm>
|
|
<primary>diff3</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>diff3</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>An extended version of <command>diff</command> that compares
|
|
three files at a time. This command returns an exit value
|
|
of 0 upon successful execution, but unfortunately this gives
|
|
no information about the results of the comparison.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>diff3 file-1 file-2 file-3</userinput>
|
|
<computeroutput>====
|
|
1:1c
|
|
This is line 1 of "file-1".
|
|
2:1c
|
|
This is line 1 of "file-2".
|
|
3:1c
|
|
This is line 1 of "file-3"</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>sdiff</command></term>
|
|
<indexterm>
|
|
<primary>sdiff</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sdiff</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Compare and/or edit two files in order to merge
|
|
them into an output file. Because of its interactive nature,
|
|
this command would find little use in a script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>cmp</command></term>
|
|
<indexterm>
|
|
<primary>cmp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cmp</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>cmp</command> command is a simpler version of
|
|
<command>diff</command>, above. Whereas <command>diff</command>
|
|
reports the differences between two files,
|
|
<command>cmp</command> merely shows at what point they
|
|
differ.</para>
|
|
|
|
<note><para>Like <command>diff</command>, <command>cmp</command>
|
|
returns an exit status of 0 if the compared files are
|
|
identical, and 1 if they differ. This permits use in a test
|
|
construct within a shell script.</para></note>
|
|
|
|
<example id="filecomp">
|
|
<title>Using <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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>comm</command></term>
|
|
<indexterm>
|
|
<primary>comm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>comm</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Versatile file comparison utility. The files must be
|
|
sorted for this to be useful.</para>
|
|
|
|
<para><command>comm
|
|
<replaceable>-options</replaceable>
|
|
<replaceable>first-file</replaceable>
|
|
<replaceable>second-file</replaceable></command></para>
|
|
|
|
<para><userinput>comm file-1 file-2</userinput> outputs three columns:
|
|
<itemizedlist>
|
|
<listitem><para>column 1 = lines unique to <filename>file-1</filename></para>
|
|
</listitem>
|
|
|
|
<listitem><para>column 2 = lines unique to <filename>file-2</filename></para>
|
|
</listitem>
|
|
|
|
<listitem><para>column 3 = lines common to both.</para>
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>The options allow suppressing output of one or more columns.
|
|
<itemizedlist>
|
|
<listitem><para><option>-1</option> suppresses column
|
|
<literal>1</literal></para>
|
|
</listitem>
|
|
<listitem><para><option>-2</option> suppresses column
|
|
<literal>2</literal></para>
|
|
</listitem>
|
|
<listitem><para><option>-3</option> suppresses column
|
|
<literal>3</literal></para>
|
|
</listitem>
|
|
<listitem><para><option>-12</option> suppresses both columns
|
|
<literal>1</literal> and <literal>2</literal>, etc.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="fautils">
|
|
<title><anchor id="fautils1">Utilities</title>
|
|
|
|
<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>
|
|
<listitem><para>Strips the <command>basename</command> from
|
|
a filename, printing only the path information.</para>
|
|
<note>
|
|
<para><command>basename</command> and <command>dirname</command>
|
|
can operate on any arbitrary string. The argument
|
|
does not need to refer to an existing file, or
|
|
even be a filename for that matter (see <xref
|
|
linkend="daysbetween">).</para>
|
|
</note>
|
|
|
|
<example id="ex35">
|
|
<title><command>basename</command> and <command>dirname</command></title>
|
|
<programlisting>&ex35;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>split</command></term>
|
|
<term><command>csplit</command></term>
|
|
<indexterm>
|
|
<primary>split</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>split</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>csplit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>csplit</secondary>
|
|
</indexterm>
|
|
|
|
<listitem>
|
|
<para>These are utilities for splitting a file into smaller
|
|
chunks. They are usually used for splitting up large files
|
|
in order to back them up on floppies or preparatory to
|
|
e-mailing or uploading them.</para>
|
|
|
|
<para>The <command>csplit</command> command splits a file
|
|
according to <emphasis>context</emphasis>, the split occuring
|
|
where patterns are matched.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>sum</command></term>
|
|
<term><command>cksum</command></term>
|
|
<term><anchor id="md5sumref"><command>md5sum</command></term>
|
|
<indexterm>
|
|
<primary>sum</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sum</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>cksum</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cksum</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>md5sum</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>md5sum</secondary>
|
|
</indexterm>
|
|
<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
|
|
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 <command>5</command>
|
|
check<command>sum</command>) command.</para>
|
|
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>cksum /boot/vmlinuz</userinput>
|
|
<computeroutput>1670054224 804083 /boot/vmlinuz</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -n "Top Secret" | cksum</userinput>
|
|
<computeroutput>3391003827 10</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>md5sum /boot/vmlinuz</userinput>
|
|
<computeroutput>0f43eccea8f09e0a0b2b5cf1dcf333ba /boot/vmlinuz</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -n "Top Secret" | md5sum</userinput>
|
|
<computeroutput>8babc97a6f62a4649716f4df8d61728f -</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<note>
|
|
<para>The <command>cksum</command> command shows the size,
|
|
in bytes, of its target, whether file or
|
|
<filename>stdout</filename>.</para>
|
|
<para>The <command>md5sum</command> command displays a
|
|
<link linkend="dashref2">dash</link> when it receives its input from
|
|
<filename>stdout</filename>.</para>
|
|
</note>
|
|
|
|
<example id="fileintegrity">
|
|
<title>Checking file integrity</title>
|
|
<programlisting>&fileintegrity;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="directoryinfo"> and <xref
|
|
linkend="horserace"> for creative uses of
|
|
the <command>md5sum</command> command.</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>Advanced forensic technology may still be able to
|
|
recover the contents of a file, even after application of
|
|
<command>shred</command>.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</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>
|
|
</indexterm>
|
|
<listitem>
|
|
<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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="famisc">
|
|
<title><anchor id="famisc1">Miscellaneous</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mktempref"><command>mktemp</command></term>
|
|
<indexterm>
|
|
<primary>temporary</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>filename</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Create a temporary file with a <quote>unique</quote>
|
|
filename.</para>
|
|
<para><programlisting>PREFIX=filename
|
|
tempfile=`mktemp $PREFIX.XXXXXX`
|
|
# ^^^^^^ Need at least 6 placeholders
|
|
#+ in the filename template.
|
|
echo "tempfile name = $tempfile"
|
|
# tempfile name = filename.QA2ZpY
|
|
# or something similar...</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
<varlistentry>
|
|
<term><command>install</command></term>
|
|
<indexterm>
|
|
<primary>install</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>install</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Special purpose file copying command, similar to
|
|
<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
|
|
shows up frequently in <filename>Makefiles</filename>
|
|
(in the <replaceable>make install :</replaceable>
|
|
section). It could likewise find use in installation
|
|
scripts.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>dos2unix</command></term>
|
|
<indexterm>
|
|
<primary>dos2unix</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>file converter</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This utility, written by Benjamin Lin and collaborators,
|
|
converts DOS-formatted text files (lines terminated by
|
|
CR-LF) to UNIX format (lines terminated by LF only),
|
|
and vice-versa.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
</sect1> <!-- End File and Archiving Commands -->
|
|
|
|
|
|
|
|
<sect1 id="communications">
|
|
<title>Communications Commands</title>
|
|
<para>Certain of the following commands find use in <link
|
|
linkend="cspammers">chasing spammers</link>, as well as in
|
|
network data transfer and analysis.</para>
|
|
|
|
<variablelist id="communinfo">
|
|
<title><anchor id="communinfo1">Information and Statistics</title>
|
|
|
|
<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>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>host surfacemail.com</userinput>
|
|
<computeroutput>surfacemail.com. has address 202.92.42.236</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>ipcalc</command></term>
|
|
<indexterm>
|
|
<primary>ipcalc</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ipcalc</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Displays IP information for a host.
|
|
With the <option>-h</option> option,
|
|
<command>ipcalc</command> does a reverse DNS lookup, finding
|
|
the name of the host (server) from the IP address.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ipcalc -h 202.92.42.236</userinput>
|
|
<computeroutput>HOSTNAME=surfacemail.com</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>nslookup</command></term>
|
|
<indexterm>
|
|
<primary>nslookup</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>name server lookup</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Do an Internet <quote>name server lookup</quote>
|
|
on a host by IP address. This is essentially equivalent
|
|
to <command>ipcalc -h</command> or <command>dig -x
|
|
</command>. The command may be run either interactively
|
|
or noninteractively, i.e., from within a script.</para>
|
|
|
|
<para>The <command>nslookup</command> command has allegedly
|
|
been <quote>deprecated,</quote> but it still has its
|
|
uses.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>nslookup -sil 66.97.104.180</userinput>
|
|
<computeroutput>nslookup kuhleersparnis.ch
|
|
Server: 135.116.137.2
|
|
Address: 135.116.137.2#53
|
|
|
|
Non-authoritative answer:
|
|
Name: kuhleersparnis.ch</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>dig</command></term>
|
|
<indexterm>
|
|
<primary>dig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>domain information groper</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para><command>D</command>omain <command>I</command>nformation
|
|
<command>G</command>roper. Similar to
|
|
<command>nslookup</command>, <command>dig</command> does
|
|
an Internet <quote>name server lookup</quote> on a host.
|
|
May be run either interactively or noninteractively, i.e.,
|
|
from within a script.</para>
|
|
|
|
<para>Some interesting options to <command>dig</command> are
|
|
<option>+time=N</option> for setting a query timeout to
|
|
<emphasis>N</emphasis> seconds, <option>+nofail</option> for
|
|
continuing to query servers until a reply is received, and
|
|
<option>-x</option> for doing a reverse address lookup.</para>
|
|
|
|
<para>Compare the output of <command>dig -x</command> with
|
|
<command>ipcalc -h</command> and
|
|
<command>nslookup</command>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>dig -x 81.9.6.2</userinput>
|
|
<computeroutput>;; Got answer:
|
|
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 11649
|
|
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
|
|
|
|
;; QUESTION SECTION:
|
|
;2.6.9.81.in-addr.arpa. IN PTR
|
|
|
|
;; AUTHORITY SECTION:
|
|
6.9.81.in-addr.arpa. 3600 IN SOA ns.eltel.net. noc.eltel.net.
|
|
2002031705 900 600 86400 3600
|
|
|
|
;; Query time: 537 msec
|
|
;; SERVER: 135.116.137.2#53(135.116.137.2)
|
|
;; WHEN: Wed Jun 26 08:35:24 2002
|
|
;; MSG SIZE rcvd: 91</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<example id="isspammer">
|
|
<title>Checking a spam domain</title>
|
|
<programlisting>&isspammer;</programlisting>
|
|
</example>
|
|
|
|
<para>For a much more elaborate version of the above script, see
|
|
<xref linkend="isspammer2">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>traceroute</command></term>
|
|
<indexterm>
|
|
<primary>traceroute</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>traceroute</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Trace the route taken by packets sent to a remote host. This
|
|
command works within a LAN, WAN, or over the
|
|
Internet. The remote host may be specified by an IP
|
|
address. The output of this command may be filtered
|
|
by <link linkend="grepref">grep</link> or <link
|
|
linkend="sedref">sed</link> in a pipe.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>traceroute 81.9.6.2</userinput>
|
|
<computeroutput>traceroute to 81.9.6.2 (81.9.6.2), 30 hops max, 38 byte packets
|
|
1 tc43.xjbnnbrb.com (136.30.178.8) 191.303 ms 179.400 ms 179.767 ms
|
|
2 or0.xjbnnbrb.com (136.30.178.1) 179.536 ms 179.534 ms 169.685 ms
|
|
3 192.168.11.101 (192.168.11.101) 189.471 ms 189.556 ms *
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pingref"><command>ping</command></term>
|
|
<indexterm>
|
|
<primary>ping</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ping</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Broadcast an <quote>ICMP ECHO_REQUEST</quote> packet to
|
|
another machine, either on a local or remote network. This
|
|
is a diagnostic tool for testing network connections,
|
|
and it should be used with caution.</para>
|
|
|
|
<para>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.
|
|
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
|
|
particular <emphasis>whois</emphasis> server to query. See
|
|
<xref linkend="ex18">.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>finger</command></term>
|
|
<indexterm>
|
|
<primary>finger</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>finger</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Retrieve information about users on a
|
|
network. Optionally, this command can display
|
|
a user's <filename>~/.plan</filename>,
|
|
<filename>~/.project</filename>, and
|
|
<filename>~/.forward</filename> files, if present.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>finger</userinput>
|
|
<computeroutput>Login Name Tty Idle Login Time Office Office Phone
|
|
bozo Bozo Bozeman tty1 8 Jun 25 16:59
|
|
bozo Bozo Bozeman ttyp0 Jun 25 16:59
|
|
bozo Bozo Bozeman ttyp1 Jun 25 17:07</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>finger bozo</userinput>
|
|
<computeroutput>Login: bozo Name: Bozo Bozeman
|
|
Directory: /home/bozo Shell: /bin/bash
|
|
Office: 2355 Clown St., 543-1234
|
|
On since Fri Aug 31 20:13 (MST) on tty1 1 hour 38 minutes idle
|
|
On since Fri Aug 31 20:13 (MST) on pts/0 12 seconds idle
|
|
On since Fri Aug 31 20:13 (MST) on pts/1
|
|
On since Fri Aug 31 20:31 (MST) on pts/2 1 hour 16 minutes idle
|
|
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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>chfn</command></term>
|
|
<indexterm>
|
|
<primary>chfn</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>finger</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Change information disclosed by the
|
|
<command>finger</command> command.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="commremote">
|
|
<title><anchor id="commremote1">Remote Host Access</title>
|
|
|
|
<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 faster transmission
|
|
rate and resumption of interrupted file transfers.
|
|
Like <command>sx</command> and <command>rx</command>,
|
|
these are generally part of a communications package.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ftpref"><command>ftp</command></term>
|
|
<indexterm>
|
|
<primary>ftp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>file transfer</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Utility and protocol for uploading / downloading
|
|
files to or from a remote host. An ftp session can be automated
|
|
in a script (see <xref linkend="ex72">, <xref
|
|
linkend="encryptedpw">, and <xref linkend="ftpget">).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
<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
|
|
command is part of the <command>uucp</command> package. It
|
|
is a sort of dumbed-down version of <link
|
|
linkend="telnetref">telnet</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="telnetref"><command>telnet</command></term>
|
|
<indexterm>
|
|
<primary>telnet</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>telnet</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Utility and protocol for connecting to a remote host.</para>
|
|
<caution><para>The telnet protocol contains security holes and
|
|
should therefore probably be avoided.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="wgetref"><command>wget</command></term>
|
|
<indexterm>
|
|
<primary>wget</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>download</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>wget</command> utility
|
|
<emphasis>non-interactively</emphasis> retrieves or
|
|
downloads files from a Web or ftp site. It works well in a
|
|
script.
|
|
<programlisting>wget -p http://www.xyz23.com/file01.html
|
|
wget -r ftp://ftp.xyz24.net/~bozo/project_files/ -O $SAVEFILE</programlisting>
|
|
</para>
|
|
|
|
<example id="quotefetch">
|
|
<title>Getting a stock quote</title>
|
|
<programlisting>"efetch;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="wgetter2"> and <xref
|
|
linkend="bashpodder">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>lynx</command></term>
|
|
<indexterm>
|
|
<primary>lynx</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>browser</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>lynx</command> Web and file browser
|
|
can be used inside a script (with the
|
|
<option>-dump</option> option) to retrieve a file from a Web or
|
|
ftp site non-interactively.
|
|
<programlisting>lynx -dump http://www.xyz23.com/file01.html >$SAVEFILE</programlisting>
|
|
</para>
|
|
</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>
|
|
|
|
<example id="remote">
|
|
<title>Using ssh</title>
|
|
<programlisting>&remote;</programlisting>
|
|
</example>
|
|
|
|
<caution>
|
|
<para>Within a loop, <command>ssh</command> may cause
|
|
unexpected behavior. According to a <ulink
|
|
url="http://groups-beta.google.com/group/comp.unix.shell/msg/dcb446b5fff7d230">
|
|
Usenet post</ulink> in the comp.unix shell archives,
|
|
<command>ssh</command> inherits the loop's
|
|
<filename>stdin</filename>. To remedy this, pass
|
|
<command>ssh</command> either the <option>-n</option>
|
|
or <option>-f</option> option.</para>
|
|
<para>Thanks, Jason Bechtel, for pointing this out.</para>
|
|
</caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</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>
|
|
|
|
<varlistentry>
|
|
<term><command>netconfig</command></term>
|
|
<indexterm>
|
|
<primary>netconfig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>network</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>A command-line utility for configuring a network adapter
|
|
(using DHCP). This command is native to Red Hat centric Linux
|
|
distros.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="commmail">
|
|
<title><anchor id="commmail1">Mail</title>
|
|
|
|
<varlistentry>
|
|
<term><command>mail</command></term>
|
|
<indexterm>
|
|
<primary>mail</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mail</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Send or read e-mail messages.</para>
|
|
|
|
<para>This stripped-down command-line mail client
|
|
works fine as a command embedded in a script.</para>
|
|
|
|
<example id="selfmailer">
|
|
<title>A script that mails itself</title>
|
|
<programlisting>&selfmailer;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>mailto</command></term>
|
|
<indexterm>
|
|
<primary>mailto</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>MIME mail</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Similar to the <command>mail</command> command,
|
|
<command>mailto</command> sends e-mail messages
|
|
from the command line or in a script. However,
|
|
<command>mailto</command> also permits sending MIME
|
|
(multimedia) messages.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Communications Commands -->
|
|
|
|
|
|
|
|
<sect1 id="terminalccmds">
|
|
<title>Terminal Control Commands</title>
|
|
|
|
<variablelist id="termcommandlisting">
|
|
<title><anchor id="termcommandlisting1">Command affecting the console
|
|
or terminal</title>
|
|
|
|
|
|
<varlistentry>
|
|
<term><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. <command>tput
|
|
sgr0</command> also resets the terminal, but without
|
|
clearing the screen.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>tput longname</userinput>
|
|
<computeroutput>xterm terminal emulator (XFree86 4.0 Window System)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Issuing a <command>tput cup X Y</command> moves
|
|
the cursor to the (X,Y) coordinates in the current
|
|
terminal. A <command>clear</command> to erase the terminal
|
|
screen would normally precede this.</para>
|
|
|
|
<para>Note that <link linkend="sttyref">stty</link> offers
|
|
a more powerful command set for controlling a terminal.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>infocmp</command></term>
|
|
<indexterm>
|
|
<primary>infocmp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>terminal</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>This command prints out extensive information about the
|
|
current terminal. It references the
|
|
<emphasis>terminfo</emphasis> database.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>infocmp</userinput>
|
|
<computeroutput># Reconstructed via infocmp from file:
|
|
/usr/share/terminfo/r/rxvt
|
|
rxvt|rxvt terminal emulator (X Window System),
|
|
am, bce, eo, km, mir, msgr, xenl, xon,
|
|
colors#8, cols#80, it#8, lines#24, pairs#64,
|
|
acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
|
|
bel=^G, blink=\E[5m, bold=\E[1m,
|
|
civis=\E[?25l,
|
|
clear=\E[H\E[2J, cnorm=\E[?25h, cr=^M,
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>reset</command></term>
|
|
<indexterm>
|
|
<primary>reset</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>reset</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Reset terminal parameters and clear text screen. As with
|
|
<command>clear</command>, the cursor and prompt reappear in the
|
|
upper lefthand corner of the terminal.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="clearref"><command>clear</command></term>
|
|
<indexterm>
|
|
<primary>clear</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>clear</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>clear</command> command simply clears
|
|
the text screen at the console or in an 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,
|
|
creates a record of a session.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Terminal Control Commands -->
|
|
|
|
|
|
<sect1 id="mathc">
|
|
<title>Math Commands</title>
|
|
|
|
<variablelist id="mathcommandlisting">
|
|
<title><anchor id="mathcommandlisting1"><quote>Doing the
|
|
numbers</quote></title>
|
|
|
|
<varlistentry>
|
|
<term><command>factor</command></term>
|
|
<indexterm>
|
|
<primary>factor</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>factor</secondary>
|
|
</indexterm>
|
|
<listitem><para>Decompose an integer into prime factors.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>factor 27417</userinput>
|
|
<computeroutput>27417: 3 13 19 37</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="bcref"><command>bc</command></term>
|
|
<indexterm>
|
|
<primary>bc</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>bc</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Bash can't handle floating point calculations, and
|
|
it lacks operators for certain important mathematical
|
|
functions. Fortunately, <command>bc</command> comes to
|
|
the rescue.</para>
|
|
|
|
<para>Not just a versatile, arbitrary precision calculation
|
|
utility, <command>bc</command> offers many of the facilities of
|
|
a programming language.</para>
|
|
|
|
<para><command>bc</command> has a syntax vaguely resembling C.</para>
|
|
|
|
<para>Since it is a fairly well-behaved UNIX utility, and may
|
|
therefore be used in a <link linkend="piperef">pipe</link>,
|
|
<command>bc</command> comes in handy in scripts.</para>
|
|
|
|
<para>Here is a simple template for using
|
|
<command>bc</command> to calculate a script
|
|
variable. This uses <link linkend="commandsubref">command
|
|
substitution</link>.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<userinput>variable=$(echo "OPTIONS; OPERATIONS" | bc)</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<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>
|
|
|
|
<para>An alternate method of invoking <command>bc</command>
|
|
involves using a <link linkend="heredocref">here
|
|
document</link> embedded within a <link
|
|
linkend="commandsubref">command substitution</link>
|
|
block. This is especially appropriate when a script
|
|
needs to pass a list of options and commands to
|
|
<command>bc</command>.</para>
|
|
|
|
<para>
|
|
<programlisting>variable=`bc << LIMIT_STRING
|
|
options
|
|
statements
|
|
operations
|
|
LIMIT_STRING
|
|
`
|
|
|
|
...or...
|
|
|
|
|
|
variable=$(bc << LIMIT_STRING
|
|
options
|
|
statements
|
|
operations
|
|
LIMIT_STRING
|
|
)</programlisting>
|
|
</para>
|
|
|
|
|
|
<example id="altbc">
|
|
<title>Invoking <command>bc</command> using a <quote>here
|
|
document</quote></title>
|
|
<programlisting>&altbc;</programlisting>
|
|
</example>
|
|
|
|
<example id="cannon">
|
|
<title>Calculating PI</title>
|
|
<programlisting>&cannon;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dcref"><command>dc</command></term>
|
|
<indexterm>
|
|
<primary>dc</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dc</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>The <command>dc</command> (<command>d</command>esk
|
|
<command>c</command>alculator) utility is stack-oriented
|
|
and uses RPN (<quote>Reverse Polish Notation</quote>). Like
|
|
<command>bc</command>, it has much of the power of a
|
|
programming language.</para>
|
|
|
|
<para>Most persons avoid <command>dc</command>, since it
|
|
requires non-intuitive 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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="awkmath"><command>awk</command></term>
|
|
<indexterm>
|
|
<primary>awk</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>math</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Yet another way of doing floating point math in
|
|
a script is using <link linkend="awkref">awk's</link>
|
|
built-in math functions in a <link linkend="shwrapper">shell
|
|
wrapper</link>.</para>
|
|
|
|
<example id="hypot">
|
|
<title>Calculating the hypotenuse of a triangle</title>
|
|
<programlisting>&hypot;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Math Commands -->
|
|
|
|
|
|
<sect1 id="extmisc">
|
|
<title>Miscellaneous Commands</title>
|
|
|
|
<variablelist id="misccommandlisting">
|
|
<title><anchor id="misccommandlisting1">Command that fit in no
|
|
special category</title>
|
|
|
|
<varlistentry>
|
|
<term><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
|
|
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>
|
|
|
|
<example id="ex53">
|
|
<title>Using <command>seq</command> to generate loop arguments</title>
|
|
<programlisting>&ex53;</programlisting>
|
|
</example>
|
|
|
|
<example id="lettercount">
|
|
<title>Letter Count"</title>
|
|
<programlisting>&lettercount;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="getopty"><command>getopt</command></term>
|
|
<indexterm>
|
|
<primary>getopt</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>option</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>getopt</command> command
|
|
parses command-line options preceded by a <link
|
|
linkend="dashref">dash</link>. This external command
|
|
corresponds to the <link linkend="getoptsx">getopts</link>
|
|
Bash builtin. The <command>getopt</command> permits
|
|
handling long options by use of the <option>-l</option>
|
|
flag, and it also allows parameter reshuffling.</para>
|
|
|
|
<example id="ex33a">
|
|
<title>Using <command>getopt</command> to parse command-line
|
|
options</title>
|
|
<programlisting>&ex33a;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="runpartsref"><command>run-parts</command></term>
|
|
<indexterm>
|
|
<primary>run-parts</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>run-parts</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>run-parts</command> command
|
|
|
|
<footnote><para>This is actually a script adapted from
|
|
the Debian Linux distribution.</para></footnote>
|
|
|
|
executes all the scripts in a target directory, sequentially
|
|
in ASCII-sorted filename order. Of course, the scripts
|
|
need to have execute permission.</para>
|
|
|
|
<para>The <link linkend="cronref">cron</link> <link
|
|
linkend="daemonref">daemon</link> invokes
|
|
<command>run-parts</command> to run the scripts in
|
|
the <filename class="directory">/etc/cron.*</filename>
|
|
directories.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>Caution advised when piping <command>yes</command>
|
|
to a potentially dangerous system command, such
|
|
as <link linkend="fsckref">fsck</link> or <link
|
|
linkend="fdiskref">fdisk</link>. It may have unintended
|
|
side-effects.</para></warning>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
<varlistentry>
|
|
<term><command>printenv</command></term>
|
|
<indexterm>
|
|
<primary>printenv</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>environment</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Show all the <link linkend="envref">environmental
|
|
variables</link> set for a particular user.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>printenv | grep HOME</userinput>
|
|
<computeroutput>HOME=/home/bozo</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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
|
|
<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><anchor id="teeref"><command>tee</command></term>
|
|
<indexterm>
|
|
<primary>tee</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tee</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>[UNIX borrows an idea here from the plumbing trade.]</para>
|
|
<para>This is a redirection operator, but with a difference. Like the
|
|
plumber's <quote>tee,</quote> it permits <quote>siponing
|
|
off</quote> <emphasis>to a file </emphasis>the output of a command
|
|
or commands within a pipe, but without affecting the result. This is
|
|
useful for printing an ongoing process to a file or paper, perhaps to
|
|
keep track of it for debugging purposes.</para>
|
|
|
|
<screen>
|
|
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"><citetitle
|
|
pubwork="journal">Linux
|
|
Journal</citetitle></ulink>.</para></footnote>
|
|
|
|
Typically, one process writes to the FIFO, and the other
|
|
reads from it. See <xref linkend="fifo">.</para>
|
|
</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.</para>
|
|
|
|
<para>Unfortunately, <command>pathchk</command> does
|
|
not return a recognizable error code, and it is therefore
|
|
pretty much useless in a script. Consider instead the
|
|
<link linkend="rtif">file test operators</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ddref"><command>dd</command></term>
|
|
<indexterm>
|
|
<primary>dd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dd</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This is the somewhat obscure and much feared <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,
|
|
|
|
<footnote><para><acronym>EBCDIC</acronym> (pronounced
|
|
<quote>ebb-sid-ick</quote>) is an acronym for Extended
|
|
Binary Coded Decimal Interchange Code. This is an IBM
|
|
data format no longer in much use. A bizarre
|
|
application of the <option>conv=ebcdic</option> option
|
|
of <command>dd</command> is as a quick 'n easy, but
|
|
not very secure text file encoder.
|
|
<programlisting>cat $file | dd conv=swab,ebcdic > $file_encrypted
|
|
# Encode (looks like gibberish).
|
|
# Might as well switch bytes (swab), too, for a little extra obscurity.
|
|
|
|
cat $file_encrypted | dd conv=swab,ascii > $file_plaintext
|
|
# Decode.</programlisting>
|
|
</para></footnote>
|
|
|
|
upper/lower case, swapping of byte pairs between input
|
|
and output, and skipping and/or truncating the head or
|
|
tail of the input file. A <userinput>dd --help</userinput>
|
|
lists the conversion and other options that this powerful
|
|
utility takes.</para>
|
|
|
|
<para>
|
|
<programlisting># Converting a file to all uppercase:
|
|
|
|
dd if=$filename conv=ucase > $filename.uppercase
|
|
# lcase # For lower case conversion</programlisting>
|
|
</para>
|
|
|
|
<example id="selfcopy">
|
|
<title>A script that copies itself</title>
|
|
<programlisting>&selfcopy;</programlisting>
|
|
</example>
|
|
|
|
<example id="exercisingdd">
|
|
<title>Exercising <command>dd</command></title>
|
|
<programlisting>&exercisingdd;</programlisting>
|
|
</example>
|
|
|
|
|
|
<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
|
|
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>
|
|
Other applications of <command>dd</command> include
|
|
initializing temporary swap files (<xref linkend="ex73">)
|
|
and ramdisks (<xref linkend="ramdisk">). It can even do a
|
|
low-level copy of an entire hard drive partition, although
|
|
this is not necessarily recommended.</para>
|
|
|
|
<para>People (with presumably nothing better to do with
|
|
their time) are constantly thinking of interesting
|
|
applications of <command>dd</command>.</para>
|
|
|
|
<example id="blotout">
|
|
<title>Securely deleting a file</title>
|
|
<programlisting>&blotout;</programlisting>
|
|
</example>
|
|
|
|
</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
|
|
dump</emphasis> filter converts input (or files) to octal
|
|
(base-8) or other bases. This is useful for viewing or
|
|
processing binary data files or otherwise unreadable system
|
|
device files, such as <filename>/dev/urandom</filename>,
|
|
and as a filter for binary data. See <xref
|
|
linkend="seedingrandom"> and <xref linkend="rnd">.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>
|
|
|
|
<varlistentry>
|
|
<term><command>objdump</command></term>
|
|
<indexterm>
|
|
<primary>objdump</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>object binary dump</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Displays information about an object file or binary
|
|
executable in either hexadecimal form or as a disassembled
|
|
listing (with the <option>-d</option> option).</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>objdump -d /bin/ls</userinput>
|
|
<computeroutput>/bin/ls: file format elf32-i386
|
|
|
|
Disassembly of section .init:
|
|
|
|
080490bc <.init>:
|
|
80490bc: 55 push %ebp
|
|
80490bd: 89 e5 mov %esp,%ebp
|
|
. . .</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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)</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>
|
|
|
|
<para>The <command>mcookie</command> command gives yet another way
|
|
to generate a <quote>unique</quote> filename.</para>
|
|
|
|
<example id="tempfilename">
|
|
<title>Filename generator</title>
|
|
<programlisting>&tempfilename;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>units</command></term>
|
|
<indexterm>
|
|
<primary>units</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>conversion</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This utility converts between different units of measure.
|
|
While normally invoked in interactive mode,
|
|
<command>units</command> may find use in a script.</para>
|
|
<example id="unitconversion">
|
|
<title>Converting meters to miles</title>
|
|
<programlisting>&unitconversion;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>m4</command></term>
|
|
<indexterm>
|
|
<primary>m4</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>macro</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>A hidden treasure, <command>m4</command> is a
|
|
powerful macro processing filter,
|
|
<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>
|
|
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
|
|
functionality of <link linkend="evalref">eval</link>,
|
|
<link linkend="trref">tr</link>, and <link
|
|
linkend="awkref">awk</link>, in addition to its extensive
|
|
macro expansion facilities.</para>
|
|
|
|
<para>The April, 2002 issue of <ulink
|
|
url="http://www.linuxjournal.com"><citetitle
|
|
pubwork="journal">Linux Journal</citetitle></ulink>
|
|
has a very nice article on <command>m4</command> and
|
|
its uses.</para>
|
|
|
|
<example id="m4">
|
|
<title>Using m4</title>
|
|
<programlisting>&m4;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>doexec</command></term>
|
|
<indexterm>
|
|
<primary>doexec</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>executable arg list</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>doexec</command> command enables passing
|
|
an arbitrary list of arguments to a <emphasis>binary
|
|
executable</emphasis>. In particular, passing
|
|
<varname>argv[0]</varname> (which corresponds to <link
|
|
linkend="posparamref1">$0</link> in a script) lets the
|
|
executable be invoked by various names, and it can then
|
|
carry out different sets of actions, according to the name
|
|
by which it was called. What this amounts to is roundabout
|
|
way of passing options to an executable.</para>
|
|
|
|
<para>For example, the <filename
|
|
class="directory">/usr/local/bin</filename> directory might
|
|
contain a binary called <quote>aaa</quote>. Invoking
|
|
<command>doexec /usr/local/bin/aaa list</command>
|
|
would <emphasis>list</emphasis> all those files
|
|
in the current working directory beginning with an
|
|
<quote>a</quote>, while invoking (the same executable
|
|
with) <command>doexec /usr/local/bin/aaa delete </command>
|
|
would <emphasis>delete</emphasis> those files.</para>
|
|
|
|
<note><para>The various behaviors of the executable
|
|
must be defined within the code of the executable itself,
|
|
analogous to something like the following in a shell script:
|
|
<programlisting>case `basename $0` in
|
|
"name1" ) do_something;;
|
|
"name2" ) do_something_else;;
|
|
"name3" ) do_yet_another_thing;;
|
|
* ) bail_out;;
|
|
esac</programlisting></para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>dialog</command></term>
|
|
<indexterm>
|
|
<primary>dialog</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dialog</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <link linkend="dialogref">dialog</link> family of tools
|
|
provide a method of calling interactive
|
|
<quote>dialog</quote> boxes from a script. The more
|
|
elaborate variations of <command>dialog</command> --
|
|
<command>gdialog</command>, <command>Xdialog</command>,
|
|
and <command>kdialog</command> -- actually invoke X-Windows
|
|
widgets. See <xref linkend="dialog">.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>sox</command></term>
|
|
<indexterm>
|
|
<primary>sox</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sound</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>The <command>sox</command>, or
|
|
<quote><emphasis>so</emphasis>und
|
|
e<emphasis>x</emphasis>change</quote> command plays and
|
|
performs transformations on sound files.</para>
|
|
|
|
<para>For example, <command>sox soundfile.wav
|
|
soundfile.au</command> changes a WAV sound file into a
|
|
(Sun audio format) AU sound file.</para>
|
|
|
|
<para>Shell scripts are ideally suited for batch processing
|
|
<command>sox</command> operations on sound files.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Miscellaneous Commands -->
|
|
|
|
</chapter> <!-- External Filters, Programs and Commands -->
|
|
|
|
|
|
|
|
<chapter id="system">
|
|
<title>System and Administrative Commands</title>
|
|
|
|
|
|
<para>The startup and shutdown scripts in
|
|
<filename class="directory">/etc/rc.d</filename> illustrate the uses
|
|
(and usefulness) of many of these comands. These are usually
|
|
invoked by 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>
|
|
|
|
<variablelist id="usersgroups">
|
|
<title><anchor id="usersgroups1">Users and Groups</title>
|
|
|
|
<varlistentry>
|
|
<term><command>users</command></term>
|
|
<indexterm>
|
|
<primary>users</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>users</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Show all logged on users. This is the approximate
|
|
equivalent of <command>who -q</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>groups</command></term>
|
|
<indexterm>
|
|
<primary>groups</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>groups</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Lists the current user and the groups she belongs to.
|
|
This corresponds to the <link
|
|
linkend="groupsref">$GROUPS</link> internal variable,
|
|
but gives the group names, rather than the numbers.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>groups</userinput>
|
|
<computeroutput>bozita cdrom cdwriter audio xgrp</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $GROUPS</userinput>
|
|
<computeroutput>501</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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
|
|
# The "dunderheads" group will now own all the "*.data" files
|
|
#+ all the way down the $PWD directory tree (that's what "recursive" means).
|
|
</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>useradd</command></term>
|
|
<term><command>userdel</command></term>
|
|
<indexterm>
|
|
<primary>useradd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>useradd</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>userdel</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>userdel</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>useradd</command> administrative command
|
|
adds a user account to the system and creates a home
|
|
directory for that particular user, if so specified. The
|
|
corresponding <command>userdel</command> command removes
|
|
a user account from the system
|
|
<footnote><para>The <command>userdel</command> command
|
|
will fail if the particular user being deleted is
|
|
still logged on.</para></footnote>
|
|
and deletes associated files.</para>
|
|
|
|
<note><para>The <command>adduser</command> command is a synonym
|
|
for <command>useradd</command> and is usually a symbolic link to
|
|
it.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>usermod</command></term>
|
|
<indexterm>
|
|
<primary>usermod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>usermod</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Modify a user account. Changes may be made to the password,
|
|
group membership, expiration date, and other attributes of
|
|
a given user's account. With this command, a user's password
|
|
may be locked, which has the effect of disabling the
|
|
account.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>groupmod</command></term>
|
|
<indexterm>
|
|
<primary>groupmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>group</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Modify a given group. The group name and/or ID number may be
|
|
changed using this command.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="idref"><command>id</command></term>
|
|
<indexterm>
|
|
<primary>id</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>id</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>The <command>id</command> command lists the real and
|
|
effective user IDs and the group IDs of the user
|
|
associated with the current process. This is the
|
|
counterpart to the <link linkend="uidref">$UID</link>,
|
|
<link linkend="euidref">$EUID</link>, and <link
|
|
linkend="groupsref">$GROUPS</link> internal Bash
|
|
variables.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>id</userinput>
|
|
<computeroutput>uid=501(bozo) gid=501(bozo) groups=501(bozo),22(cdrom),80(cdwriter),81(audio)</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $UID</userinput>
|
|
<computeroutput>501</computeroutput></screen>
|
|
|
|
<note><para>The <command>id</command> command shows the
|
|
<emphasis>effective</emphasis> IDs only when they differ
|
|
from the <emphasis>real</emphasis> ones.</para></note>
|
|
|
|
<para>Also see <xref linkend="amiroot">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whoref"><command>who</command></term>
|
|
<indexterm>
|
|
<primary>who</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>whoami</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Show all users logged on to the system.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>who</userinput>
|
|
<computeroutput>bozo tty1 Apr 27 17:45
|
|
bozo pts/0 Apr 27 17:46
|
|
bozo pts/1 Apr 27 17:47
|
|
bozo pts/2 Apr 27 17:49
|
|
</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <option>-m</option> gives detailed information about
|
|
only the current user. Passing any two arguments to
|
|
<command>who</command> is the equivalent of <command>who
|
|
-m</command>, as in <command>who am i</command> or <command>who
|
|
The Man</command>.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>who -m</userinput>
|
|
<computeroutput>localhost.localdomain!bozo pts/2 Apr 27 17:49</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="whoamiref"><command>whoami</command> is similar to <command>who
|
|
-m</command>, but only lists the user name.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>whoami</userinput>
|
|
<computeroutput>bozo</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
|
|
<note><para>While <command>logname</command> prints the name
|
|
of the logged in user, <command>whoami</command> gives the
|
|
name of the user attached to the current process. As we have
|
|
just seen, sometimes these are not the same.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="suref"><command>su</command></term>
|
|
<indexterm>
|
|
<primary>su</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>su</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Runs a program or script as a
|
|
<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>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>passwd</command></term>
|
|
<indexterm>
|
|
<primary>passwd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>password</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Sets, changes, or manages a user's password.</para>
|
|
|
|
<para>The <command>passwd</command> command can be used in
|
|
a script, but <emphasis>should not</emphasis> be.</para>
|
|
|
|
<example id="setnewpw">
|
|
<title>Setting a new password</title>
|
|
<programlisting>&setnewpw;</programlisting>
|
|
</example>
|
|
|
|
<para>The <command>passwd</command> command's <option>-l</option>,
|
|
<option>-u</option>, and <option>-d</option> options permit
|
|
locking, unlocking, and deleting a user's password. Only
|
|
root may use these options.</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>ac</command></term>
|
|
<indexterm>
|
|
<primary>ac</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>accounting</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Show users' logged in time, as read from
|
|
<filename>/var/log/wtmp</filename>. This is one of the GNU
|
|
accounting utilities.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>ac</userinput>
|
|
<computeroutput> total 68.08</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>last</command></term>
|
|
<indexterm>
|
|
<primary>last</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>logged in</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>List <emphasis>last</emphasis> logged in users, as read from
|
|
<filename>/var/log/wtmp</filename>. This command can also
|
|
show remote logins.</para>
|
|
|
|
<para>For example, to show the last few times the system
|
|
rebooted:</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>last reboot</userinput>
|
|
<computeroutput>reboot system boot 2.6.9-1.667 Fri Feb 4 18:18 (00:02)
|
|
reboot system boot 2.6.9-1.667 Fri Feb 4 15:20 (01:27)
|
|
reboot system boot 2.6.9-1.667 Fri Feb 4 12:56 (00:49)
|
|
reboot system boot 2.6.9-1.667 Thu Feb 3 21:08 (02:17)
|
|
. . .
|
|
|
|
wtmp begins Tue Feb 1 12:50:09 2005</computeroutput></screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>newgrp</command></term>
|
|
<indexterm>
|
|
<primary>newgrp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>group</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<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>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="terminalssys">
|
|
<title><anchor id="terminalssys1">Terminals</title>
|
|
|
|
<varlistentry>
|
|
<term><command>tty</command></term>
|
|
<indexterm>
|
|
<primary>tty</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tty</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sttyref"><command>stty</command></term>
|
|
<indexterm>
|
|
<primary>stty</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>stty</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Shows and/or changes terminal settings. This complex
|
|
command, used in a script, can control terminal behavior
|
|
and the way output displays. See the info page, and study
|
|
it carefully.</para>
|
|
|
|
<example id="erase">
|
|
<title>Setting an 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 = <undef>; eol2 = <undef>;
|
|
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<ctl-W>I<ctl-H>foo bar<ctl-U>hello world<ENTER></userinput>
|
|
<userinput><ctl-D></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>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>setterm</command></term>
|
|
<indexterm>
|
|
<primary>setterm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>terminal</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Set certain terminal attributes. This command writes
|
|
to its terminal's <filename>stdout</filename> a string that
|
|
changes the behavior of that terminal.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>setterm -cursor off</userinput>
|
|
<computeroutput>bash$</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <command>setterm</command> command can be used within a
|
|
script to change the appearance of text written to
|
|
<filename>stdout</filename>, although there are certainly
|
|
<link linkend="colorizingref">better tools</link> available
|
|
for this purpose.</para>
|
|
|
|
<para><programlisting>setterm -bold on
|
|
echo bold hello
|
|
|
|
setterm -bold off
|
|
echo normal hello</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>tset</command></term>
|
|
<indexterm>
|
|
<primary>tset</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tset</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Show or initialize terminal settings.
|
|
This is a less capable version of
|
|
<command>stty</command>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>tset -r</userinput>
|
|
<computeroutput>Terminal type is xterm-xfree86.
|
|
Kill is control-U (^U).
|
|
Interrupt is control-C (^C).</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
<varlistentry>
|
|
<term><command>getty</command></term>
|
|
<term><command>agetty</command></term>
|
|
<indexterm>
|
|
<primary>getty</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>getty</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>agetty</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>agetty</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The initialization process for a terminal uses
|
|
<command>getty</command> or <command>agetty</command>
|
|
to set it up for login by a user. These commands are not
|
|
used within user shell scripts. Their scripting counterpart
|
|
is <command>stty</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mesgref"><command>mesg</command></term>
|
|
<indexterm>
|
|
<primary>mesg</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mesg</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Enables or disables write access to the current user's
|
|
terminal. Disabling access would prevent another user
|
|
on the network to <link linkend="writeref">write</link>
|
|
to the terminal.</para>
|
|
|
|
<tip><para>It can be 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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>wall</command></term>
|
|
<indexterm>
|
|
<primary>wall</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>wall</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This is an acronym for <quote><link
|
|
linkend="writeref">write</link> all</quote>, i.e., sending
|
|
a message to all users at every terminal logged into the
|
|
network. It is primarily a system administrator's tool,
|
|
useful, for example, when warning everyone that the
|
|
system will shortly go down due to a problem (see <xref
|
|
linkend="ex70">).</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>wall System going down for maintenance in 5 minutes!</userinput>
|
|
<computeroutput>Broadcast message from bozo (pts/1) Sun Jul 8 13:53:27 2001...
|
|
|
|
System going down for maintenance in 5 minutes!</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>If write access to a particular terminal has been
|
|
disabled with <command>mesg</command>, then
|
|
<command>wall</command> cannot send a message to
|
|
it.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>dmesg</command></term>
|
|
<indexterm>
|
|
<primary>dmesg</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dmesg</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Lists all system bootup messages to
|
|
<filename>stdout</filename>. Handy for debugging and
|
|
ascertaining which device drivers were installed
|
|
and which system interrupts in use. The output
|
|
of <command>dmesg</command> may, of course, be
|
|
parsed with <link linkend="grepref">grep</link>,
|
|
<link linkend="sedref">sed</link>, or <link
|
|
linkend="awkref">awk</link> from within a script.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>dmesg | grep hda</userinput>
|
|
<computeroutput>Kernel command line: ro root=/dev/hda2
|
|
hda: IBM-DLGA-23080, ATA DISK drive
|
|
hda: 6015744 sectors (3080 MB) w/96KiB Cache, CHS=746/128/63
|
|
hda: hda1 hda2 hda3 < hda5 hda6 hda7 > hda4</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="statisticssys">
|
|
<title><anchor id="statisticssys1">Information and Statistics</title>
|
|
|
|
<varlistentry>
|
|
<term><command>uname</command></term>
|
|
<indexterm>
|
|
<primary>uname</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>uname</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Output system specifications (OS, kernel version,
|
|
etc.) to <filename>stdout</filename>. Invoked with the
|
|
<option>-a</option> option, gives verbose system info
|
|
(see <xref linkend="ex41">). The <option>-s</option>
|
|
option shows only the OS type.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>uname -a</userinput>
|
|
<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>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>arch</command></term>
|
|
<indexterm>
|
|
<primary>arch</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>arch</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Show system architecture.
|
|
Equivalent to <command>uname -m</command>. See <xref
|
|
linkend="casecmd">.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>arch</userinput>
|
|
<computeroutput>i686</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>uname -m</userinput>
|
|
<computeroutput>i686</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>lastcomm</command></term>
|
|
<indexterm>
|
|
<primary>lastcomm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>last</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Gives information about previous commands, as stored
|
|
in the <filename>/var/account/pacct</filename> file. Command
|
|
name and user name can be specified by options. This is
|
|
one of the GNU accounting utilities.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lastlogref"><command>lastlog</command></term>
|
|
<indexterm>
|
|
<primary>lastlog</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>last</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>List the last login time of all system users. This
|
|
references the <filename>/var/log/lastlog</filename>
|
|
file.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lastlog</userinput>
|
|
<computeroutput>root tty1 Fri Dec 7 18:43:21 -0700 2001
|
|
bin **Never logged in**
|
|
daemon **Never logged in**
|
|
...
|
|
bozo tty1 Sat Dec 8 21:14:29 -0700 2001</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>lastlog | grep root</userinput>
|
|
<computeroutput>root tty1 Fri Dec 7 18:43:21 -0700 2001</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<caution><para>This command will fail if the user invoking
|
|
it does not have read permission for the
|
|
<filename>/var/log/lastlog</filename> file.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>lsof</command></term>
|
|
<indexterm>
|
|
<primary>lsof</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>lsof</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>List open files. This command outputs a detailed
|
|
table of all currently open files and gives information
|
|
about their owner, size, the processes associated with
|
|
them, and more. Of course, <command>lsof</command> may
|
|
be piped to <link linkend="grepref">grep</link> and/or
|
|
<link linkend="awkref">awk</link> to parse and analyze
|
|
its results.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lsof</userinput>
|
|
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
|
|
init 1 root mem REG 3,5 30748 30303 /sbin/init
|
|
init 1 root mem REG 3,5 73120 8069 /lib/ld-2.1.3.so
|
|
init 1 root mem REG 3,5 931668 8075 /lib/libc-2.1.3.so
|
|
cardmgr 213 root mem REG 3,5 36956 30357 /sbin/cardmgr
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>strace</command></term>
|
|
<indexterm>
|
|
<primary>strace</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>strace</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Diagnostic and debugging tool for tracing system
|
|
calls and signals. The simplest way of invoking it is
|
|
<command>strace COMMAND</command>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>strace df</userinput>
|
|
<computeroutput>execve("/bin/df", ["df"], [/* 45 vars */]) = 0
|
|
uname({sys="Linux", node="bozo.localdomain", ...}) = 0
|
|
brk(0) = 0x804f5e4
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>This is the Linux equivalent of
|
|
<command>truss</command>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="nmapref"><command>nmap</command></term>
|
|
<indexterm>
|
|
<primary>nmap</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>port scan</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Network port scanner. This command scans a server to
|
|
locate open ports and the services associated with those
|
|
ports. It is an important security tool for locking down
|
|
a network against hacking attempts.</para>
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
SERVER=$HOST # localhost.localdomain (127.0.0.1).
|
|
PORT_NUMBER=25 # SMTP port.
|
|
|
|
nmap $SERVER | grep -w "$PORT_NUMBER" # Is that particular port open?
|
|
# grep -w matches whole words only,
|
|
#+ so this wouldn't match port 1025, for example.
|
|
|
|
exit 0
|
|
|
|
# 25/tcp open smtp</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="freeref"><command>free</command></term>
|
|
<indexterm>
|
|
<primary>free</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>free</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Shows memory and cache usage in tabular form. The
|
|
output of this command lends itself to parsing, using
|
|
<link linkend="grepref">grep</link>, <link
|
|
linkend="awkref">awk</link> or <command>Perl</command>. The
|
|
<command>procinfo</command> command shows all the
|
|
information that <command>free</command> does, and much
|
|
more.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><command>free</command>
|
|
<computeroutput> total used free shared buffers cached
|
|
Mem: 30504 28624 1880 15820 1608 16376
|
|
-/+ buffers/cache: 10640 19864
|
|
Swap: 68540 3128 65412</computeroutput></screen>
|
|
|
|
<para>To show unused RAM memory:</para>
|
|
<screen><prompt>bash$ </prompt><command>free | grep Mem | awk '{ print $4 }'</command>
|
|
<computeroutput>1880</computeroutput></screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="procinforef"><command>procinfo</command></term>
|
|
<indexterm>
|
|
<primary>procinfo</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>procinfo</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Extract and list information and statistics from the
|
|
<link linkend="devprocref"><filename
|
|
class="directory">/proc</filename>
|
|
pseudo-filesystem</link>. This gives a very extensive and
|
|
detailed listing.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>procinfo | grep Bootup</userinput>
|
|
<computeroutput>Bootup: Wed Mar 21 15:15:50 2001 Load average: 0.04 0.21 0.34 3/47 6829</computeroutput>
|
|
</screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lsdevref"><command>lsdev</command></term>
|
|
<indexterm>
|
|
<primary>lsdev</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>device</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>List devices, that is, show installed hardware.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lsdev</userinput>
|
|
<computeroutput>Device DMA IRQ I/O Ports
|
|
------------------------------------------------
|
|
cascade 4 2
|
|
dma 0080-008f
|
|
dma1 0000-001f
|
|
dma2 00c0-00df
|
|
fpu 00f0-00ff
|
|
ide0 14 01f0-01f7 03f6-03f6
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="duref"><command>du</command></term>
|
|
<indexterm>
|
|
<primary>du</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>du</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Show (disk) file usage, recursively. Defaults to current
|
|
working directory, unless otherwise specified.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><command>du -ach</command>
|
|
<computeroutput>1.0k ./wi.sh
|
|
1.0k ./tst.sh
|
|
1.0k ./random.file
|
|
6.0k .
|
|
6.0k total</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dfref"><command>df</command></term>
|
|
<indexterm>
|
|
<primary>df</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>df</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Shows filesystem usage in tabular form.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><command>df</command>
|
|
<computeroutput>Filesystem 1k-blocks Used Available Use% Mounted on
|
|
/dev/hda5 273262 92607 166547 36% /
|
|
/dev/hda8 222525 123951 87085 59% /home
|
|
/dev/hda7 1408796 1075744 261488 80% /usr</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>stat</command></term>
|
|
<indexterm>
|
|
<primary>stat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>stat</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Gives detailed and verbose <emphasis>stat</emphasis>istics
|
|
on a given file (even a directory or device file) or set
|
|
of files.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>stat test.cru</userinput>
|
|
<computeroutput> File: "test.cru"
|
|
Size: 49970 Allocated Blocks: 100 Filetype: Regular File
|
|
Mode: (0664/-rw-rw-r--) Uid: ( 501/ bozo) Gid: ( 501/ bozo)
|
|
Device: 3,8 Inode: 18185 Links: 1
|
|
Access: Sat Jun 2 16:40:24 2001
|
|
Modify: Sat Jun 2 16:40:24 2001
|
|
Change: Sat Jun 2 16:40:24 2001</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>If the target file does not exist, <command>stat</command>
|
|
returns an error message.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>stat nonexistent-file</userinput>
|
|
<computeroutput>nonexistent-file: No such file or directory</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="vmstatref"><command>vmstat</command></term>
|
|
<indexterm>
|
|
<primary>vmstat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>virtual memory</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Display virtual memory statistics.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>vmstat</userinput>
|
|
<computeroutput> procs memory swap io system cpu
|
|
r b w swpd free buff cache si so bi bo in cs us sy id
|
|
0 0 0 0 11040 2636 38952 0 0 33 7 271 88 8 3 89</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>netstat</command></term>
|
|
<indexterm>
|
|
<primary>netstat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>netstat</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Show current network statistics and information,
|
|
such as routing tables and active connections. This utility
|
|
accesses information in <filename>/proc/net</filename>
|
|
(<xref linkend="devproc">). See <xref
|
|
linkend="constat">.</para>
|
|
<para><command>netstat -r</command> is equivalent to <link
|
|
linkend="routeref">route</link>.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>netstat</userinput>
|
|
<computeroutput>Active Internet connections (w/o servers)
|
|
Proto Recv-Q Send-Q Local Address Foreign Address State
|
|
Active UNIX domain sockets (w/o servers)
|
|
Proto RefCnt Flags Type State I-Node Path
|
|
unix 11 [ ] DGRAM 906 /dev/log
|
|
unix 3 [ ] STREAM CONNECTED 4514 /tmp/.X11-unix/X0
|
|
unix 3 [ ] STREAM CONNECTED 4513
|
|
. . .</computeroutput></screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="uptimeref"><command>uptime</command></term>
|
|
<indexterm>
|
|
<primary>uptime</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>uptime</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Shows how long the system has been running, along with
|
|
associated statistics.</para>
|
|
<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>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="hnameref"><command>hostname</command></term>
|
|
<indexterm>
|
|
<primary>hostname</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>hostname</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Lists the system's host name. This command sets the host
|
|
name in an <filename class="directory">/etc/rc.d</filename>
|
|
setup script (<filename>/etc/rc.d/rc.sysinit</filename>
|
|
or similar). It is equivalent to <command>uname
|
|
-n</command>, and a counterpart to the <link
|
|
linkend="hostnameref">$HOSTNAME</link> internal
|
|
variable.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>hostname</userinput>
|
|
<computeroutput>localhost.localdomain</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $HOSTNAME</userinput>
|
|
<computeroutput>localhost.localdomain</computeroutput></screen>
|
|
|
|
<para>Similar to the <command>hostname</command> command are the
|
|
<command>domainname</command>,
|
|
<command>dnsdomainname</command>,
|
|
<command>nisdomainname</command>, and
|
|
<command>ypdomainname</command> commands. Use these to
|
|
display or set the system DNS or NIS/YP domain name. Various
|
|
options to <command>hostname</command> also perform these
|
|
functions.</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="hostidref"><command>hostid</command></term>
|
|
<indexterm>
|
|
<primary>hostid</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>host id</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Echo a 32-bit hexadecimal numerical identifier for the
|
|
host machine.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>hostid</userinput>
|
|
<computeroutput>7f0100</computeroutput></screen>
|
|
</para>
|
|
|
|
<note>
|
|
<para>This command allegedly fetches a <quote>unique</quote>
|
|
serial number for a particular system. Certain
|
|
product registration procedures use this number
|
|
to brand a particular user license. Unfortunately,
|
|
<command>hostid</command> only returns the machine
|
|
network address in hexadecimal, with pairs of bytes
|
|
transposed.</para>
|
|
|
|
<para>The network address of a typical non-networked Linux
|
|
machine, is found in <filename>/etc/hosts</filename>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>cat /etc/hosts</userinput>
|
|
<computeroutput>127.0.0.1 localhost.localdomain localhost</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>As it happens, transposing the bytes of
|
|
<userinput>127.0.0.1</userinput>, we get
|
|
<userinput>0.127.1.0</userinput>, which translates in
|
|
hex to <userinput>007f0100</userinput>, the exact equivalent
|
|
of what <command>hostid</command> returns, above. There
|
|
exist only a few million other Linux machines with this
|
|
identical <emphasis>hostid</emphasis>.</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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 Reporter)
|
|
gives a very detailed rundown on system statistics. The
|
|
Santa Cruz Operation (SCO) released
|
|
<command>sar</command> as Open Source in June, 1999.</para>
|
|
|
|
<para>This command is not part of the base Linux distribution,
|
|
but may be obtained as part of the<ulink
|
|
url="http://perso.wanadoo.fr/sebastien.godard/">
|
|
sysstat utilities</ulink> package, written by <ulink
|
|
url="mailto:sebastien.godard@wanadoo.fr">Sebastien
|
|
Godard</ulink>.</para>
|
|
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>sar</userinput>
|
|
<computeroutput>Linux 2.4.9 (brooks.seringas.fr) 09/26/03
|
|
|
|
10:30:00 CPU %user %nice %system %iowait %idle
|
|
10:40:00 all 2.21 10.90 65.48 0.00 21.41
|
|
10:50:00 all 3.36 0.00 72.36 0.00 24.28
|
|
11:00:00 all 1.12 0.00 80.77 0.00 18.11
|
|
Average: all 2.23 3.63 72.87 0.00 21.27
|
|
|
|
14:32:30 LINUX RESTART
|
|
|
|
15:00:00 CPU %user %nice %system %iowait %idle
|
|
15:10:00 all 8.59 2.40 17.47 0.00 71.54
|
|
15:20:00 all 4.07 1.00 11.95 0.00 82.98
|
|
15:30:00 all 0.79 2.94 7.56 0.00 88.71
|
|
Average: all 6.33 1.70 14.71 0.00 77.26</computeroutput>
|
|
</screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>readelf</command></term>
|
|
<indexterm>
|
|
<primary>elf</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>statistics</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Show information and statistics about a designated
|
|
<emphasis>elf</emphasis> binary. This is part of the
|
|
<emphasis>binutils</emphasis> package.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>readelf -h /bin/bash</userinput>
|
|
<computeroutput>ELF Header:
|
|
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
|
|
Class: ELF32
|
|
Data: 2's complement, little endian
|
|
Version: 1 (current)
|
|
OS/ABI: UNIX - System V
|
|
ABI Version: 0
|
|
Type: EXEC (Executable file)
|
|
. . .</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>size</command></term>
|
|
<indexterm>
|
|
<primary>size</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>segment</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>The <command>size [/path/to/binary]</command> command
|
|
gives the segment sizes of a binary executable or archive file.
|
|
This is mainly of use to programmers.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>size /bin/bash</userinput>
|
|
<computeroutput> text data bss dec hex filename
|
|
495971 22496 17392 535859 82d33 /bin/bash</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="syslog">
|
|
<title><anchor id="syslog1">System Logs</title>
|
|
|
|
<varlistentry>
|
|
<term><command>logger</command></term>
|
|
<indexterm>
|
|
<primary>logger</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>logger</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Appends a user-generated message to the system log
|
|
(<filename>/var/log/messages</filename>). You do not have
|
|
to be 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>
|
|
|
|
<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.
|
|
Usually <link linkend="cronref">cron</link> runs
|
|
<command>logrotate</command> on a daily basis.</para>
|
|
|
|
<para>Adding an appropriate entry to
|
|
<filename>/etc/logrotate.conf</filename> makes it possible
|
|
to manage personal log files, as well as system-wide
|
|
ones.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="jobcontrolsys">
|
|
<title><anchor id="jobcontrolsys1">Job Control</title>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
<term><anchor id="pidofref"><command>pidof</command></term>
|
|
<indexterm>
|
|
<primary>pidof</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>process ID</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Identifies <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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>fuser</command></term>
|
|
<indexterm>
|
|
<primary>fuser</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>fuser</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Identifies the processes (by PID) that are accessing
|
|
a given file, set of files, or directory. May also be
|
|
invoked with the <option>-k</option> option, which kills
|
|
those processes. This has interesting implications for
|
|
system security, especially in scripts preventing
|
|
unauthorized users from accessing system services.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>fuser -u /usr/bin/vim</userinput>
|
|
<computeroutput>/usr/bin/vim: 3207e(bozo)</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>fuser -u /dev/null</userinput>
|
|
<computeroutput>/dev/null: 3009(bozo) 3010(bozo) 3197(bozo) 3199(bozo)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>One important application for <command>fuser</command> is
|
|
when physically inserting or removing storage media, such
|
|
as CD ROM disks or USB flash drives. Sometimes trying
|
|
a <link linkend="umountref">umount</link> fails with a
|
|
<errorname>device is busy</errorname> error message. This
|
|
means that some user(s) and/or process(es) are accessing
|
|
the device. An <command>fuser -um /dev/device_name</command>
|
|
will clear up the mystery, so you can kill any relevant
|
|
processes.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>umount /mnt/usbdrive</userinput>
|
|
<computeroutput>umount: /mnt/usbdrive: device is busy</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>fuser -um /dev/usbdrive</userinput>
|
|
<computeroutput>/mnt/usbdrive: 1772c(bozo)</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>kill -9 1772</userinput>
|
|
<prompt>bash$ </prompt><userinput>umount /mnt/usbdrive</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para> The <command>fuser</command> command, invoked with the
|
|
<option>-n</option> option identifies the processes
|
|
accessing a <emphasis>port</emphasis>. This
|
|
is especially useful in combination with <link
|
|
linkend="nmapref">nmap</link>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>root# </prompt><userinput>nmap localhost.localdomain</userinput>
|
|
<computeroutput>PORT STATE SERVICE
|
|
25/tcp open smtp</computeroutput>
|
|
|
|
|
|
|
|
<prompt>root# </prompt><userinput>fuser -un tcp 25</userinput>
|
|
<computeroutput>25/tcp: 2095(root)</computeroutput>
|
|
|
|
<prompt>root# </prompt><userinput>ps ax | grep 2095 | grep -v grep</userinput>
|
|
<computeroutput>2095 ? Ss 0:00 sendmail: accepting connections</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cronref"><command>cron</command></term>
|
|
<indexterm>
|
|
<primary>cron</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>crond</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Administrative program scheduler, performing such
|
|
duties as cleaning up and deleting system log
|
|
files and updating the <database>slocate</database>
|
|
database. This is the 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>
|
|
|
|
<note><para>Some flavors of Linux run
|
|
<command>crond</command>, Matthew Dillon's version of
|
|
<command>cron</command>.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="runcontrolsys">
|
|
<title><anchor id="runcontrolsys1">Process Control and Booting</title>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="networksys">
|
|
<title><anchor id="networksys1">Network</title>
|
|
|
|
<varlistentry>
|
|
<term><command>ifconfig</command></term>
|
|
<indexterm>
|
|
<primary>ifconfig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ifconfig</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Network <emphasis>interface configuration</emphasis>
|
|
and tuning utility.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>ifconfig -a</userinput>
|
|
<computeroutput>lo Link encap:Local Loopback
|
|
inet addr:127.0.0.1 Mask:255.0.0.0
|
|
UP LOOPBACK RUNNING MTU:16436 Metric:1
|
|
RX packets:10 errors:0 dropped:0 overruns:0 frame:0
|
|
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
|
|
collisions:0 txqueuelen:0
|
|
RX bytes:700 (700.0 b) TX bytes:700 (700.0 b)</computeroutput></screen>
|
|
|
|
<para>The <command>ifconfig</command> command is most often used
|
|
at bootup to set up the interfaces, or to shut them down
|
|
when rebooting.</para>
|
|
|
|
<para><programlisting># Code snippets from /etc/rc.d/init.d/network
|
|
|
|
# ...
|
|
|
|
# Check that networking is up.
|
|
[ ${NETWORKING} = "no" ] && exit 0
|
|
|
|
[ -x /sbin/ifconfig ] || exit 0
|
|
|
|
# ...
|
|
|
|
for i in $interfaces ; do
|
|
if ifconfig $i 2>/dev/null | grep -q "UP" >/dev/null 2>&1 ; then
|
|
action "Shutting down interface $i: " ./ifdown $i boot
|
|
fi
|
|
# The GNU-specific "-q" option to "grep" means "quiet", i.e., producing no output.
|
|
# Redirecting output to /dev/null is therefore not strictly necessary.
|
|
|
|
# ...
|
|
|
|
echo "Currently active devices:"
|
|
echo `/sbin/ifconfig | grep ^[a-z] | awk '{print $1}'`
|
|
# ^^^^^ should be quoted to prevent globbing.
|
|
# The following also work.
|
|
# echo $(/sbin/ifconfig | awk '/^[a-z]/ { print $1 })'
|
|
# echo $(/sbin/ifconfig | sed -e 's/ .*//')
|
|
# Thanks, S.C., for additional comments.</programlisting></para>
|
|
|
|
<para>See also <xref linkend="online">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>iwconfig</command></term>
|
|
<indexterm>
|
|
<primary>iwconfig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>wireless</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This is the command set for configuring a wireless network.
|
|
It is the wireless equivalent of <command>ifconfig</command>,
|
|
above.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="routeref"><command>route</command></term>
|
|
<indexterm>
|
|
<primary>route</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>route</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Show info about or make changes to the kernel routing table.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>route</userinput>
|
|
<computeroutput>Destination Gateway Genmask Flags MSS Window irtt Iface
|
|
pm3-67.bozosisp * 255.255.255.255 UH 40 0 0 ppp0
|
|
127.0.0.0 * 255.0.0.0 U 40 0 0 lo
|
|
default pm3-67.bozosisp 0.0.0.0 UG 40 0 0 ppp0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>chkconfig</command></term>
|
|
<indexterm>
|
|
<primary>chkconfig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>network configuration</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<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>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
|
|
<variablelist id="filesystemsys">
|
|
<title><anchor id="filesystemsys1">Filesystem</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mountref"><command>mount</command></term>
|
|
<indexterm>
|
|
<primary>mount</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mount</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Mount a filesystem, usually on an external device,
|
|
such as a floppy or CDROM. The file
|
|
<filename>/etc/fstab</filename> provides a handy listing
|
|
of available filesystems, partitions, and devices,
|
|
including options, that may be automatically or manually
|
|
mounted. The file <filename>/etc/mtab</filename> shows
|
|
the currently mounted filesystems and partitions
|
|
(including the virtual ones, such as <filename
|
|
class="directory">/proc</filename>).</para>
|
|
|
|
<para><command>mount -a</command> mounts all filesystems and
|
|
partitions listed in <filename>/etc/fstab</filename>,
|
|
except those with a <option>noauto</option>
|
|
option. At bootup, a startup script in
|
|
<filename class="directory">/etc/rc.d</filename>
|
|
(<filename>rc.sysinit</filename> or something similar)
|
|
invokes this to get everything mounted.</para>
|
|
|
|
|
|
<para><programlisting>mount -t iso9660 /dev/cdrom /mnt/cdrom
|
|
# Mounts CDROM
|
|
mount /mnt/cdrom
|
|
# Shortcut, if /mnt/cdrom listed in /etc/fstab</programlisting>
|
|
</para>
|
|
|
|
<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
|
|
associating the file with a <link linkend="loopbackref">loopback
|
|
device</link>. One application of this is to mount and examine
|
|
an ISO9660 image before burning it onto a CDR.
|
|
|
|
<footnote><para>For more detail on burning CDRs, see Alex
|
|
Withers' article, <ulink
|
|
url="http://www2.linuxjournal.com/lj-issues/issue66/3335.html">Creating
|
|
CDs</ulink>, in the October, 1999 issue of <ulink
|
|
url="http://www.linuxjournal.com"><citetitle
|
|
pubwork="journal">Linux
|
|
Journal</citetitle></ulink>.</para></footnote>
|
|
|
|
</para>
|
|
|
|
<example id="isomountref">
|
|
<title>Checking a CD image</title>
|
|
<programlisting># As root...
|
|
|
|
mkdir /mnt/cdtest # Prepare a mount point, if not already there.
|
|
|
|
mount -r -t iso9660 -o loop cd-image.iso /mnt/cdtest # Mount the image.
|
|
# "-o loop" option equivalent to "losetup /dev/loop0"
|
|
cd /mnt/cdtest # Now, check the image.
|
|
ls -alR # List the files in the directory tree there.
|
|
# And so forth.</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="umountref"><command>umount</command></term>
|
|
<indexterm>
|
|
<primary>umount</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>umount</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Unmount a currently mounted filesystem. Before physically removing a
|
|
previously mounted floppy or CDROM disk, the device must be
|
|
<command>umount</command>ed, else filesystem corruption may result.
|
|
<programlisting>umount /mnt/cdrom
|
|
# You may now press the eject button and safely remove the disk.</programlisting></para>
|
|
|
|
<note><para>The <command>automount</command> utility, if
|
|
properly installed, can mount and unmount floppies or
|
|
CDROM disks as they are accessed or removed. On laptops
|
|
with swappable floppy and CDROM drives, this can cause
|
|
problems, though.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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
|
|
flush, as when securely deleting a file (see <xref
|
|
linkend="blotout">) or when the lights begin to
|
|
flicker.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="losetupref"><command>losetup</command></term>
|
|
<indexterm>
|
|
<primary>losetup</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>losetup</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Sets up and configures <link linkend="loopbackref">
|
|
loopback devices</link>.</para>
|
|
|
|
<example id="createfs">
|
|
<title>Creating a filesystem in a file</title>
|
|
<programlisting>SIZE=1000000 # 1 meg
|
|
|
|
head -c $SIZE < /dev/zero > file # Set up file of designated size.
|
|
losetup /dev/loop0 file # Set it up as loopback device.
|
|
mke2fs /dev/loop0 # Create filesystem.
|
|
mount -o loop /dev/loop0 /mnt # Mount it.
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
<primary>swapon</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>swapon</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>swapoff</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>swapoff</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Enable / disable swap partitition or file.
|
|
These commands usually take effect at bootup and
|
|
shutdown.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mke2fsref"><command>mke2fs</command></term>
|
|
<indexterm>
|
|
<primary>mke2fs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mke2fs</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Create a Linux ext2 filesystem. This command must
|
|
be invoked as root.</para>
|
|
|
|
|
|
<example id="adddrv">
|
|
<title>Adding a new hard drive</title>
|
|
<programlisting>&adddrv;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="createfs"> and <xref
|
|
linkend="ramdisk">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>fsck</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>e2fsck</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>e2fsck</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>debugfs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>debugfs</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Filesystem check, repair, and debug command set.</para>
|
|
|
|
<para><command>fsck</command>: a front end for checking a UNIX
|
|
filesystem (may invoke other utilities). The actual
|
|
filesystem type generally defaults to ext2.</para>
|
|
|
|
<para><command>e2fsck</command>: ext2 filesystem checker.</para>
|
|
|
|
<para><command>debugfs</command>: ext2 filesystem debugger.
|
|
One of the uses of this versatile, but dangerous command
|
|
is to (attempt to) recover deleted files. For advanced users
|
|
only!</para>
|
|
|
|
<caution><para>All of these should be invoked as root, and they
|
|
can damage or destroy a filesystem if misused.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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>lsusb</command></term>
|
|
<term><command>usbmodules</command></term>
|
|
<indexterm>
|
|
<primary>lsusb</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>usb</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>usbmodules</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>usb</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>The <command>lsusb</command> command lists all USB
|
|
(Universal Serial Bus) buses and the devices hooked up to
|
|
them.</para>
|
|
|
|
<para>The <command>usbmodules</command> command outputs
|
|
information about the driver modules for connected USB
|
|
devices.</para>
|
|
|
|
<para>
|
|
<screen><prompt>root# </prompt><userinput>lsusb</userinput>
|
|
<computeroutput>Bus 001 Device 001: ID 0000:0000
|
|
Device Descriptor:
|
|
bLength 18
|
|
bDescriptorType 1
|
|
bcdUSB 1.00
|
|
bDeviceClass 9 Hub
|
|
bDeviceSubClass 0
|
|
bDeviceProtocol 0
|
|
bMaxPacketSize0 8
|
|
idVendor 0x0000
|
|
idProduct 0x0000
|
|
. . .</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
<varlistentry>
|
|
<term><command>chroot</command></term>
|
|
<indexterm>
|
|
<primary>chroot</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>chroot</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>directory</primary>
|
|
<secondary>root</secondary>
|
|
<tertiary>change</tertiary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>CHange ROOT directory. Normally commands are fetched
|
|
from <link linkend="pathref">$PATH</link>, relative to
|
|
<filename class="directory">/</filename>, the default 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>
|
|
|
|
<para>A <userinput>chroot /opt</userinput> would cause
|
|
references to <filename
|
|
class="directory">/usr/bin</filename>
|
|
to be translated to <filename
|
|
class="directory">/opt/usr/bin</filename>. Likewise,
|
|
<userinput>chroot /aaa/bbb /bin/ls</userinput> would
|
|
redirect future instances of <command>ls</command>
|
|
to <filename>/aaa/bbb</filename> as the base directory,
|
|
rather than <filename class="directory">/</filename> as is
|
|
normally the case. An <command>alias XX 'chroot /aaa/bbb
|
|
ls'</command> in a user's <filename>~/.bashrc</filename>
|
|
effectively restricts which portion of the filesystem
|
|
she may run command <quote>XX</quote> on.</para>
|
|
|
|
|
|
<para>The <command>chroot</command> command is also handy
|
|
when running from an emergency boot floppy
|
|
(<command>chroot</command> to <filename>/dev/fd0</filename>),
|
|
or as an option to <command>lilo</command> when recovering
|
|
from a system crash. Other uses include installation from a
|
|
different filesystem (an <link linkend="rpmref">rpm</link>
|
|
option) or running a readonly filesystem from a CD ROM.
|
|
Invoke only as 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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>lockfile</command></term>
|
|
<indexterm>
|
|
<primary>lockfile</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>lockfile</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>This utility is part of the <command>procmail</command>
|
|
package (<ulink url="http://www.procmail.org">www.procmail.org</ulink>).
|
|
It creates a <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 to create a lock file that
|
|
already exists, the script will likely hang.</para>
|
|
|
|
<para>Normally, applications create and check for lock files
|
|
in the <filename class="directory">/var/lock</filename>
|
|
directory. 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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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). The
|
|
<command>MAKEDEV</command> utility has virtually
|
|
all of the functionality of <command>mknod</command>,
|
|
and is easier to use.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><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>
|
|
|
|
<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">cron</link> to remove stale log
|
|
files.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="periphsys">
|
|
<title><anchor id="periphsys1">Backup</title>
|
|
|
|
<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>
|
|
<term><command>fdformat</command></term>
|
|
<indexterm>
|
|
<primary>fdformat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>floppy</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Perform a low-level format on a floppy disk.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="sysresources">
|
|
<title><anchor id="sysresources1">System Resources</title>
|
|
|
|
<varlistentry>
|
|
<term><command>ulimit</command></term>
|
|
<indexterm>
|
|
<primary>ulimit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ulimit</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Sets an <emphasis>upper limit</emphasis> on use
|
|
of system resources. Usually invoked with the
|
|
<option>-f</option> option, which sets a limit on file size
|
|
(<command>ulimit -f 1000</command> limits files to 1 meg
|
|
maximum). The <option>-t</option> option limits the coredump
|
|
size (<command>ulimit -c 0</command> eliminates coredumps).
|
|
Normally, the value of <command>ulimit</command>
|
|
would be set in <filename>/etc/profile</filename>
|
|
and/or <filename>~/.bash_profile</filename> (see <xref
|
|
linkend="files">).</para>
|
|
|
|
<important>
|
|
|
|
<para>Judicious use of <command>ulimit</command> can
|
|
protect a system against the dreaded <emphasis>fork
|
|
bomb</emphasis>.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# This script is for illustrative purposes only.
|
|
# Run it at your own peril -- it *will* freeze your system.
|
|
|
|
while true # Endless loop.
|
|
do
|
|
$0 & # This script invokes itself . . .
|
|
#+ forks an infinite number of times . . .
|
|
#+ until the system freezes up because all resources exhausted.
|
|
done # This is the notorious <quote>sorcerer's appentice</quote> scenario.
|
|
|
|
exit 0 # Will not exit here, because this script will never terminate.</programlisting>
|
|
</para>
|
|
|
|
<para>A <command>ulimit -Hu XX</command> (where
|
|
<emphasis>XX</emphasis> is the user process limit) in
|
|
<filename>/etc/profile</filename> would abort
|
|
this script when it exceeds the preset limit.
|
|
</para>
|
|
|
|
</important>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>setquota</command></term>
|
|
<indexterm>
|
|
<primary>setquota</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>quota</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Set user or group disk quotas from the command line.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<indexterm>
|
|
<primary>umask</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>umask</secondary>
|
|
</indexterm>
|
|
<term><anchor id="umaskref"><command>umask</command></term>
|
|
<listitem>
|
|
<para>User file creation 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
|
|
file permissions <emphasis>disabled</emphasis>. For example,
|
|
<command>umask 022</command> ensures that new files will
|
|
have at most 755 permissions (777 NAND 022).
|
|
|
|
<footnote><para>NAND is the logical <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
|
|
linkend="chmodref">chmod</link>. The usual practice
|
|
is to set the value of <command>umask</command>
|
|
in <filename>/etc/profile</filename> and/or
|
|
<filename>~/.bash_profile</filename> (see <xref
|
|
linkend="files">).</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>rdev</command></term>
|
|
<indexterm>
|
|
<primary>rdev</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>rdev</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Get info about or make changes to root device, swap space, or video
|
|
mode. The functionality of <command>rdev</command> has generally been taken over by
|
|
<command>lilo</command>, but <command>rdev</command> remains
|
|
useful for setting up a ram disk. This is a dangerous command, if misused.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="modulessys">
|
|
<title><anchor id="modulessys1">Modules</title>
|
|
|
|
<varlistentry>
|
|
<term><command>lsmod</command></term>
|
|
<indexterm>
|
|
<primary>lsmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>List installed kernel modules.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lsmod</userinput>
|
|
<computeroutput>Module Size Used by
|
|
autofs 9456 2 (autoclean)
|
|
opl3 11376 0
|
|
serial_cs 5456 0 (unused)
|
|
sb 34752 0
|
|
uart401 6384 0 [sb]
|
|
sound 58368 0 [opl3 sb uart401]
|
|
soundlow 464 0 [sound]
|
|
soundcore 2800 6 [sb sound]
|
|
ds 6448 2 [serial_cs]
|
|
i82365 22928 2
|
|
pcmcia_core 45984 0 [serial_cs ds i82365]</computeroutput>
|
|
</screen>
|
|
</para>
|
|
<note><para>Doing a <command>cat /proc/modules</command> gives the
|
|
same information.</para></note>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>insmod</command></term>
|
|
<indexterm>
|
|
<primary>insmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Force installation of a kernel module (use
|
|
<command>modprobe</command> instead, when possible). Must
|
|
be invoked as root.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>rmmod</command></term>
|
|
<indexterm>
|
|
<primary>rmmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Force unloading of a kernel module. Must be invoked
|
|
as root.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>modprobe</command></term>
|
|
<indexterm>
|
|
<primary>modprobe</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Module loader that is normally invoked automatically
|
|
in a startup script. Must be invoked as root.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>depmod</command></term>
|
|
<indexterm>
|
|
<primary>depmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Creates module dependency file, usually invoked from
|
|
startup script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>modinfo</command></term>
|
|
<indexterm>
|
|
<primary>modinfo</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>Output information about a loadable module.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>modinfo hid</userinput>
|
|
<computeroutput>filename: /lib/modules/2.4.20-6/kernel/drivers/usb/hid.o
|
|
description: "USB HID support drivers"
|
|
author: "Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>"
|
|
license: "GPL"</computeroutput>
|
|
</screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="miscsys">
|
|
<title><anchor id="miscsys1">Miscellaneous</title>
|
|
|
|
<varlistentry>
|
|
<term><command>env</command></term>
|
|
<indexterm>
|
|
<primary>env</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>env</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Runs a program or script with certain <link
|
|
linkend="envref">environmental variables</link>
|
|
set or changed (without changing the overall system
|
|
environment). The <option>[varname=xxx]</option>
|
|
permits changing the environmental variable
|
|
<varname>varname</varname> for the duration of the
|
|
script. With no options specified, this command lists all
|
|
the environmental variable settings.</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>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>ldd</command></term>
|
|
<indexterm>
|
|
<primary>ldd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ldd</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Show shared lib dependencies for an executable file.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>ldd /bin/ls</userinput>
|
|
<computeroutput>libc.so.6 => /lib/libc.so.6 (0x4000c000)
|
|
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="watchref"><command>watch</command></term>
|
|
<indexterm>
|
|
<primary>watch</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>periodic</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Run a command repeatedly, at specified time intervals.</para>
|
|
<para>The default is two-second intervals, but this may be changed
|
|
with the <option>-n</option> option.</para>
|
|
<para><programlisting>watch -n 5 tail /var/log/messages
|
|
# Shows tail end of system log, /var/log/messages, every five seconds.</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<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 it
|
|
impossible.</para>
|
|
<para>This command often occurs in a <link
|
|
linkend="makefileref">Makefile</link>,
|
|
but rarely in a shell script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>nm</command></term>
|
|
<indexterm>
|
|
<primary>nm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>symbol</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>List symbols in an unstripped compiled binary.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>rdist</command></term>
|
|
<indexterm>
|
|
<primary>rdist</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>rdist</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>Remote distribution client: synchronizes, clones,
|
|
or backs up a file system on a remote server.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<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>
|
|
|
|
<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
|
|
<filename class="directory">/etc/rc.d/init.d</filename>. See if
|
|
you can understand parts of them. Follow the above procedure
|
|
to analyze them. For some additional insight, you might also
|
|
examine the file <filename>sysvinitfiles</filename> in <filename
|
|
class="directory">/usr/share/doc/initscripts-?.??</filename>,
|
|
which is part of the <quote>initscripts</quote>
|
|
documentation.</para></formalpara>
|
|
|
|
</chapter> <!-- System and Administrative Commands -->
|
|
|
|
|
|
|
|
<chapter id="commandsub">
|
|
<title>Command Substitution</title>
|
|
|
|
<indexterm>
|
|
<primary>$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>`</secondary>
|
|
</indexterm>
|
|
|
|
<para>
|
|
<anchor id="commandsubref"><command>Command
|
|
substitution</command> reassigns the output of a command
|
|
<footnote><para>For purposes of <emphasis>command
|
|
substitution</emphasis>, a <command>command</command>
|
|
may be an external system command, an internal
|
|
scripting <emphasis>builtin</emphasis>, or even <link
|
|
linkend="rvt">a script function</link>.</para></footnote>
|
|
or even multiple commands; it literally plugs the command
|
|
output into another context.
|
|
<footnote><para>In a more technically correct sense,
|
|
<emphasis>command substitution</emphasis> extracts the
|
|
<filename>stdout</filename> of a command, then assigns
|
|
it to a variable using the <token>=</token>
|
|
operator.</para></footnote>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="backquotesref">The classic form of command
|
|
substitution uses backquotes (`...`). Commands within
|
|
backquotes (backticks) generate command line text.
|
|
|
|
<programlisting>script_name=`basename $0`
|
|
echo "The name of this script is $script_name."</programlisting></para>
|
|
|
|
|
|
<formalpara>
|
|
<title>The output of commands can be used as arguments to
|
|
another command, to set a variable, and even for generating
|
|
the argument list in a <link linkend="forloopref1">for</link>
|
|
loop.</title>
|
|
<para></para>
|
|
</formalpara>
|
|
|
|
<para>
|
|
<programlisting>rm `cat filename` # <quote>filename</quote> contains a list of files to delete.
|
|
#
|
|
# S. C. points out that "arg list too long" error might result.
|
|
# Better is xargs rm -- < filename
|
|
# ( -- covers those cases where <quote>filename</quote> begins with a <quote>-</quote> )
|
|
|
|
textfile_listing=`ls *.txt`
|
|
# Variable contains names of all *.txt files in current working directory.
|
|
echo $textfile_listing
|
|
|
|
textfile_listing2=$(ls *.txt) # The alternative form of command substitution.
|
|
echo $textfile_listing2
|
|
# Same result.
|
|
|
|
# A possible problem with putting a list of files into a single string
|
|
# is that a newline may creep in.
|
|
#
|
|
# A safer way to assign a list of files to a parameter is with an array.
|
|
# shopt -s nullglob # If no match, filename expands to nothing.
|
|
# textfile_listing=( *.txt )
|
|
#
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<note><para>Command substitution invokes a <link
|
|
linkend="subshellsref">subshell</link>.</para></note>
|
|
|
|
|
|
|
|
<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
|
|
|
|
|
|
# Thanks, S.C.</programlisting></para>
|
|
|
|
|
|
<para>Even when there is no word splitting, command
|
|
substitution can remove trailing newlines.
|
|
|
|
<programlisting># cd "`pwd`" # This should always work.
|
|
# However...
|
|
|
|
mkdir 'dir with trailing newline
|
|
'
|
|
|
|
cd 'dir with trailing newline
|
|
'
|
|
|
|
cd "`pwd`" # Error message:
|
|
# bash: cd: /tmp/file with trailing newline: No such file or directory
|
|
|
|
cd "$PWD" # Works fine.
|
|
|
|
|
|
|
|
|
|
|
|
old_tty_setting=$(stty -g) # Save old terminal setting.
|
|
echo "Hit a key "
|
|
stty -icanon -echo # Disable "canonical" mode for terminal.
|
|
# Also, disable *local* echo.
|
|
key=$(dd bs=1 count=1 2> /dev/null) # Using 'dd' to get a keypress.
|
|
stty "$old_tty_setting" # Restore old setting.
|
|
echo "You hit ${#key} key." # ${#variable} = number of characters in $variable
|
|
#
|
|
# Hit any key except RETURN, and the output is "You hit 1 key."
|
|
# Hit RETURN, and it's "You hit 0 key."
|
|
# The newline gets eaten in the command substitution.
|
|
|
|
Thanks, S.C.</programlisting>
|
|
</para>
|
|
</caution>
|
|
|
|
|
|
<caution>
|
|
<para>Using <command>echo</command> to output an
|
|
<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>
|
|
|
|
|
|
|
|
<para>Command substitution even permits setting a variable to the
|
|
contents of a file, using either <link
|
|
linkend="ioredirref">redirection</link> or the <link
|
|
linkend="catref">cat</link> command.</para>
|
|
|
|
<para>
|
|
<programlisting>variable1=`<file1` # Set "variable1" to contents of "file1".
|
|
variable2=`cat file2` # Set "variable2" to contents of "file2".
|
|
# This, however, forks a new process,
|
|
#+ so the line of code executes slower than the above version.
|
|
|
|
# Note:
|
|
# The variables may contain embedded whitespace,
|
|
#+ or even (horrors), control characters.</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting># Excerpts from system file, /etc/rc.d/rc.sysinit
|
|
#+ (on a Red Hat Linux installation)
|
|
|
|
|
|
if [ -f /fsckoptions ]; then
|
|
fsckoptions=`cat /fsckoptions`
|
|
...
|
|
fi
|
|
#
|
|
#
|
|
if [ -e "/proc/ide/${disk[$device]}/media" ] ; then
|
|
hdmedia=`cat /proc/ide/${disk[$device]}/media`
|
|
...
|
|
fi
|
|
#
|
|
#
|
|
if [ ! -n "`uname -r | grep -- "-"`" ]; then
|
|
ktag="`cat /proc/version`"
|
|
...
|
|
fi
|
|
#
|
|
#
|
|
if [ $usb = "1" ]; then
|
|
sleep 5
|
|
mouseoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=02"`
|
|
kbdoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=01"`
|
|
...
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
<caution>
|
|
<para>Do not set a variable to the contents of a
|
|
<emphasis>long</emphasis> text file unless you have a very good
|
|
reason for doing so. Do not set a variable to the contents of a
|
|
<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>
|
|
|
|
|
|
|
|
<sidebar>
|
|
<para>Command substitution makes it possible to extend the
|
|
toolset available to Bash. It is simply a matter
|
|
of writing a program or script that outputs to
|
|
<filename>stdout</filename> (like a well-behaved UNIX
|
|
tool should) and assigning that output to a variable.</para>
|
|
|
|
<para>
|
|
<programlisting>#include <stdio.h>
|
|
|
|
/* "Hello, world." C program */
|
|
|
|
int main()
|
|
{
|
|
printf( "Hello, world." );
|
|
return (0);
|
|
}</programlisting>
|
|
<screen><prompt>bash$ </prompt><userinput>gcc -o hello hello.c</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# hello.sh
|
|
|
|
greeting=`./hello`
|
|
echo $greeting</programlisting>
|
|
<screen><prompt>bash$ </prompt><userinput>sh hello.sh</userinput>
|
|
<computeroutput>Hello, world.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</sidebar>
|
|
|
|
<note>
|
|
|
|
<para>The <command>$(COMMAND)</command> form has
|
|
superseded backticks for command substitution.</para>
|
|
|
|
<para><programlisting>output=$(sed -n /"$1"/p $file) # From "grp.sh" example.
|
|
|
|
# Setting a variable to the contents of a text file.
|
|
File_contents1=$(cat $file1)
|
|
File_contents2=$(<$file2) # Bash permits this also.</programlisting></para>
|
|
|
|
<para>The <command>$(...)</command> form of command substitution
|
|
treats a double backslash in a different way than
|
|
<command>`...`</command>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo `echo \\`</userinput>
|
|
<computeroutput></computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $(echo \\)</userinput>
|
|
<computeroutput>\</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
</note>
|
|
|
|
|
|
<para>Examples of command substitution in shell scripts:
|
|
<orderedlist>
|
|
<listitem><para><xref linkend="bingrep"></para></listitem>
|
|
<listitem><para><xref linkend="casecmd"></para></listitem>
|
|
<listitem><para><xref linkend="seedingrandom"></para></listitem>
|
|
<listitem><para><xref linkend="ex57"></para></listitem>
|
|
<listitem><para><xref linkend="lowercase"></para></listitem>
|
|
<listitem><para><xref linkend="grp"></para></listitem>
|
|
<listitem><para><xref linkend="ex53"></para></listitem>
|
|
<listitem><para><xref linkend="ex24"></para></listitem>
|
|
<listitem><para><xref linkend="symlinks"></para></listitem>
|
|
<listitem><para><xref linkend="stripc"></para></listitem>
|
|
<listitem><para><xref linkend="redir4"></para></listitem>
|
|
<listitem><para><xref linkend="tree"></para></listitem>
|
|
<listitem><para><xref linkend="pidid"></para></listitem>
|
|
<listitem><para><xref linkend="monthlypmt"></para></listitem>
|
|
<listitem><para><xref linkend="base"></para></listitem>
|
|
<listitem><para><xref linkend="altbc"></para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
</chapter> <!-- Command Substitution -->
|
|
|
|
|
|
|
|
<chapter id="arithexp">
|
|
<title>Arithmetic Expansion</title>
|
|
|
|
|
|
<para><anchor id="arithexpref">Arithmetic expansion provides a
|
|
powerful tool for performing 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>
|
|
|
|
<variablelist id="arithexpvar">
|
|
<title><anchor id="arithexpvar1">Variations</title>
|
|
|
|
<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` # The 'expr' command performs the expansion.</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term>Arithmetic expansion with double parentheses</term>
|
|
<indexterm><primary>double</primary>
|
|
<secondary>parentheses</secondary></indexterm>
|
|
<term>and using <command>let</command></term>
|
|
<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> and
|
|
<userinput>$((...))</userinput> -- and also by the very
|
|
convenient <command>let</command> construction.</para>
|
|
|
|
<para>
|
|
<programlisting>z=$(($z+3))
|
|
z=$((z+3)) # Also correct.
|
|
# Within double parentheses,
|
|
#+ parameter dereferencing
|
|
#+ is optional.
|
|
|
|
# $((EXPRESSION)) is arithmetic expansion. # Not to be confused with
|
|
#+ command substitution.
|
|
|
|
|
|
|
|
# You may also use operations within double parentheses without assignment.
|
|
|
|
n=0
|
|
echo "n = $n" # n = 0
|
|
|
|
(( n += 1 )) # Increment.
|
|
# (( $n += 1 )) is incorrect!
|
|
echo "n = $n" # n = 1
|
|
|
|
|
|
let z=z+3
|
|
let "z += 3" # Quotes permit the use of spaces.
|
|
# The 'let' operator actually performs arithmetic evaluation,
|
|
#+ rather than expansion.</programlisting>
|
|
</para>
|
|
|
|
<para>Examples of arithmetic expansion in scripts:
|
|
<orderedlist>
|
|
<listitem><para><xref linkend="ex45"></para></listitem>
|
|
<listitem><para><xref linkend="ex25"></para></listitem>
|
|
<listitem><para><xref linkend="ex66"></para></listitem>
|
|
<listitem><para><xref linkend="bubble"></para></listitem>
|
|
<listitem><para><xref linkend="tree"></para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</chapter> <!-- Arithmetic Expansion -->
|
|
|
|
|
|
|
|
<chapter id="io-redirection">
|
|
<title>I/O Redirection</title>
|
|
|
|
<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>
|
|
|
|
<programlisting> COMMAND_OUTPUT >
|
|
# Redirect stdout to a file.
|
|
# Creates the file if not present, otherwise overwrites it.
|
|
|
|
ls -lR > dir-tree.list
|
|
# Creates a file containing a listing of the directory tree.
|
|
|
|
: > filename
|
|
# The > truncates file "filename" to zero length.
|
|
# If file not present, creates zero-length file (same effect as 'touch').
|
|
# The : serves as a dummy placeholder, producing no output.
|
|
|
|
> filename
|
|
# The > truncates file "filename" to zero length.
|
|
# If file not present, creates zero-length file (same effect as 'touch').
|
|
# (Same result as ": >", above, but this does not work with some shells.)
|
|
|
|
COMMAND_OUTPUT >>
|
|
# Redirect stdout to a file.
|
|
# Creates the file if not present, otherwise appends to it.
|
|
|
|
|
|
# Single-line redirection commands (affect only the line they are on):
|
|
# --------------------------------------------------------------------
|
|
|
|
1>filename
|
|
# Redirect stdout to file "filename".
|
|
1>>filename
|
|
# Redirect and append stdout to file "filename".
|
|
2>filename
|
|
# Redirect stderr to file "filename".
|
|
2>>filename
|
|
# Redirect and append stderr to file "filename".
|
|
&>filename
|
|
# Redirect both stdout and stderr to file "filename".
|
|
|
|
#==============================================================================
|
|
# 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.
|
|
#==============================================================================
|
|
|
|
|
|
|
|
2>&1
|
|
# Redirects stderr to stdout.
|
|
# Error messages get sent to same place as standard output.
|
|
|
|
i>&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>.
|
|
|
|
>&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>.
|
|
|
|
0< FILENAME
|
|
< FILENAME
|
|
# Accept input from a file.
|
|
# Companion command to <quote>></quote>, and often used in combination with it.
|
|
#
|
|
# grep search-word <filename
|
|
|
|
|
|
[j]<>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<> 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 < input-file > output-file
|
|
|
|
command1 | command2 | command3 > output-file</programlisting>
|
|
See <xref linkend="derpm"> and <xref linkend="fifo">.</para>
|
|
|
|
|
|
<para>Multiple output streams may be redirected to one file.
|
|
|
|
<programlisting>ls -yz >> command.log 2>&1
|
|
# Capture result of illegal options "yz" in file "command.log."
|
|
# Because stderr is redirected to the file,
|
|
#+ any error messages will also be there.
|
|
|
|
# Note, however, that the following does *not* give the same result.
|
|
ls -yz 2>&1 >> command.log
|
|
# Outputs an error message and does not write to file.
|
|
|
|
# If redirecting both stdout and stderr,
|
|
#+ the order of the commands makes a difference.
|
|
</programlisting></para>
|
|
|
|
|
|
<variablelist id="closingfiledescriptors">
|
|
<title><anchor id="cfd">Closing File Descriptors</title>
|
|
|
|
<varlistentry>
|
|
<term><token>n<&-</token></term>
|
|
<listitem>
|
|
<para>Close input file descriptor
|
|
<replaceable>n</replaceable>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>0<&-</token></term>
|
|
<term><token><&-</token></term>
|
|
<listitem>
|
|
<para>Close <filename>stdin</filename>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>n>&-</token></term>
|
|
<listitem>
|
|
<para>Close output file descriptor <replaceable>n</replaceable>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>1>&-</token></term>
|
|
<term><token>>&-</token></term>
|
|
<listitem>
|
|
<para>Close <filename>stdout</filename>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<para>Child processes inherit open file descriptors. This is why pipes
|
|
work. To prevent an fd from being inherited, close it.
|
|
<programlisting># Redirecting only stderr to a pipe.
|
|
|
|
exec 3>&1 # Save current "value" of stdout.
|
|
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls').
|
|
# ^^^^ ^^^^
|
|
exec 3>&- # Now close it for the remainder of the script.
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<para>For a more detailed introduction to I/O redirection see
|
|
<xref linkend="ioredirintro">.</para>
|
|
|
|
|
|
<sect1><title>Using <command>exec</command></title>
|
|
|
|
|
|
<para>An <command>exec <filename</command> command redirects
|
|
<filename>stdin</filename> to a file. From that point on, all
|
|
<filename>stdin</filename> comes from that file, rather than
|
|
its normal source (usually keyboard input). This provides a
|
|
method of reading a file line by line and possibly parsing
|
|
each line of input using <link linkend="sedref">sed</link>
|
|
and/or <link linkend="awkref">awk</link>.</para>
|
|
|
|
<example id="redir1">
|
|
<title>Redirecting <filename>stdin</filename> using
|
|
<command>exec</command></title>
|
|
<programlisting>&redir1;</programlisting>
|
|
</example>
|
|
|
|
<para>Similarly, an <command>exec >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>
|
|
|
|
<para>I/O redirection is a clever way of avoiding the dreaded <link
|
|
linkend="parvis">inaccessible variables within a subshell</link>
|
|
problem.</para>
|
|
|
|
<example id="avoidsubshell">
|
|
<title>Avoiding a subshell</title>
|
|
<programlisting>&avoidsubshell;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
</sect1><!-- Using exec For Redirection -->
|
|
|
|
|
|
|
|
<sect1 id="redircb"><title>Redirecting Code Blocks</title>
|
|
|
|
<para><anchor id="redirref">Blocks of code, such as <link
|
|
linkend="whileloopref">while</link>, <link
|
|
linkend="untilloopref">until</link>, and <link
|
|
linkend="forloopref1">for</link> loops, even <link
|
|
linkend="ifthen">if/then</link> test blocks can also incorporate
|
|
redirection of <filename>stdin</filename>. Even a function may
|
|
use this form of redirection (see <xref linkend="realname">).
|
|
The <token><</token> operator at the end of the code block
|
|
accomplishes this.</para>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<example id="redir5">
|
|
<title>Redirected <emphasis>if/then</emphasis> test</title>
|
|
<programlisting>&redir5;</programlisting>
|
|
</example>
|
|
|
|
<example id="namesdata">
|
|
<title>Data file <quote>names.data</quote> for above examples</title>
|
|
<programlisting>&namesdata;</programlisting>
|
|
</example>
|
|
|
|
<para>Redirecting the <filename>stdout</filename> of a code
|
|
block has the effect of saving its output to a file. See <xref
|
|
linkend="rpmcheck">.</para>
|
|
|
|
<para><link linkend="heredocref">Here documents</link>
|
|
are a special case of redirected code blocks.</para>
|
|
|
|
</sect1><!-- Redirecting Code Blocks -->
|
|
|
|
|
|
<sect1 id="redirapps"><title>Applications</title>
|
|
|
|
<para>Clever use of I/O redirection permits parsing and stitching
|
|
together snippets of command output (see <xref
|
|
linkend="readredir">). This permits
|
|
generating report and log files.</para>
|
|
|
|
<example id="logevents">
|
|
<title>Logging events</title>
|
|
<programlisting>&logevents;</programlisting>
|
|
</example>
|
|
|
|
|
|
</sect1><!-- Applications -->
|
|
|
|
|
|
</chapter> <!-- I/O Redirection -->
|
|
|
|
|
|
|
|
<chapter id="here-docs">
|
|
<title>Here Documents</title>
|
|
|
|
<para><anchor id="heredocref"></para>
|
|
|
|
<indexterm>
|
|
<primary><<</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary><<</secondary>
|
|
</indexterm>
|
|
|
|
<para>A <firstterm>here document</firstterm> is a special-purpose
|
|
code block. It uses a form of <link linkend="ioredirref">I/O
|
|
redirection</link> to feed a command list to
|
|
an interactive program or a command, such as <link
|
|
linkend="ftpref">ftp</link>, <link linkend="catref">cat</link>,
|
|
or <command>ex</command>.</para>
|
|
|
|
<para><programlisting>COMMAND <<InputComesFromHERE
|
|
...
|
|
InputComesFromHERE</programlisting></para>
|
|
|
|
|
|
<para>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 <filename>stdin</filename> of the program
|
|
or command. It is similar to <userinput>interactive-program <
|
|
command-file</userinput>, where <filename>command-file</filename>
|
|
contains
|
|
|
|
<programlisting>command #1
|
|
command #2
|
|
...</programlisting></para>
|
|
|
|
<para>The <quote>here document</quote> alternative looks like
|
|
this:</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
interactive-program <<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>
|
|
|
|
<para>Analogous to <quote>ex scripts</quote> are <firstterm>cat
|
|
scripts</firstterm>.</para>
|
|
|
|
<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><<-LimitString</userinput>) suppresses leading
|
|
tabs (but not spaces) in the output. This may be useful in making
|
|
a script more readable.</para>
|
|
|
|
<example id="ex71a">
|
|
<title>Multi-line message, with tabs suppressed</title>
|
|
<programlisting>&ex71a;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>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>This is a useful script containing a here document with
|
|
parameter substitution.</para>
|
|
|
|
<example id="ex72">
|
|
<title>Upload a file pair to <quote>Sunsite</quote> incoming
|
|
directory</title>
|
|
<programlisting>&ex72;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>Quoting or escaping the <quote>limit string</quote> at the
|
|
head of a here document disables parameter substitution within its
|
|
body.</para>
|
|
|
|
<example id="ex71c">
|
|
<title>Parameter substitution turned off</title>
|
|
<programlisting>&ex71c;</programlisting>
|
|
</example>
|
|
|
|
<para>Disabling parameter substitution permits outputting literal text.
|
|
Generating scripts or even program code is one use for this.</para>
|
|
|
|
<example id="generatescript">
|
|
<title>A script that generates another script</title>
|
|
<programlisting>&generatescript;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para>
|
|
It is possible to set a variable from the output of a here document.
|
|
<programlisting>variable=$(cat <<SETVAR
|
|
This variable
|
|
runs over multiple lines.
|
|
SETVAR)
|
|
|
|
echo "$variable"</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>A here document can supply input to a function in the same
|
|
script.</para>
|
|
|
|
<example id="hf">
|
|
<title>Here documents and functions</title>
|
|
<programlisting>&hf;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="anonheredoc0"></para>
|
|
<para>It is possible to use <token>:</token> as a dummy command
|
|
accepting output from a here document. This, in effect, creates an
|
|
<quote>anonymous</quote> here document.</para>
|
|
|
|
<example id="anonheredoc">
|
|
<title><quote>Anonymous</quote> Here Document</title>
|
|
<programlisting>#!/bin/bash
|
|
|
|
: <<TESTVARIABLES
|
|
${HOSTNAME?}${USER?}${MAIL?} # Print error message if one of the variables not set.
|
|
TESTVARIABLES
|
|
|
|
exit 0</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="cblock1"></para>
|
|
<tip><para>A variation of the above technique permits <quote>commenting
|
|
out</quote> blocks of code.</para></tip>
|
|
|
|
<example id="commentblock">
|
|
<title>Commenting out a block of code</title>
|
|
<programlisting>&commentblock;</programlisting>
|
|
</example>
|
|
|
|
|
|
<tip><para>Yet another twist of this nifty trick makes
|
|
<quote>self-documenting</quote> scripts possible.</para></tip>
|
|
|
|
<example id="selfdocument">
|
|
<title>A self-documenting script</title>
|
|
<programlisting>&selfdocument;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="isspammer2"> for an excellent example
|
|
of a self-documenting script.</para>
|
|
|
|
<note>
|
|
<para>Here documents create temporary files, but these
|
|
files are deleted after opening and are not accessible to
|
|
any other process.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>bash -c 'lsof -a -p $$ -d0' << EOF</userinput>
|
|
<prompt>> </prompt><userinput>EOF</userinput>
|
|
<computeroutput>lsof 1213 bozo 0r REG 3,5 0 30386 /tmp/t1213-0-sh (deleted)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
<caution><para>Some utilities will not work inside a
|
|
<emphasis>here document</emphasis>.</para></caution>
|
|
|
|
<para><anchor id="indentedls"></para>
|
|
|
|
<warning>
|
|
|
|
<para>The closing <emphasis>limit string</emphasis>,
|
|
on the final line of a here document, must start in the
|
|
<emphasis>first</emphasis> character position. There can
|
|
be <emphasis>no leading whitespace</emphasis>. Trailing
|
|
whitespace after the limit string likewise causes unexpected
|
|
behavior. The whitespace prevents the limit string from being
|
|
recognized.</para>
|
|
|
|
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
echo "----------------------------------------------------------------------"
|
|
|
|
cat <<LimitString
|
|
echo "This is line 1 of the message inside the here document."
|
|
echo "This is line 2 of the message inside the here document."
|
|
echo "This is the final line of the message inside the here document."
|
|
LimitString
|
|
#^^^^Indented limit string. Error! This script will not behave as expected.
|
|
|
|
echo "----------------------------------------------------------------------"
|
|
|
|
# These comments are outside the 'here document',
|
|
#+ and should not echo.
|
|
|
|
echo "Outside the here document."
|
|
|
|
exit 0
|
|
|
|
echo "This line had better not echo." # Follows an 'exit' command.</programlisting>
|
|
</para>
|
|
</warning>
|
|
|
|
|
|
<para>For those tasks too complex for a <quote>here
|
|
document</quote>, consider using the <command>expect</command>
|
|
scripting language, which is specifically tailored for feeding
|
|
input into interactive programs.</para>
|
|
|
|
|
|
<sect1><title>Here Strings</title>
|
|
|
|
<para><anchor id="herestringsref"></para>
|
|
|
|
<para>A <emphasis>here string</emphasis> can be considered as
|
|
a stripped-down form of <emphasis>here document</emphasis>. It
|
|
consists of nothing more than <command>COMMAND
|
|
<<<$WORD</command>, where <varname>$WORD</varname>
|
|
is expanded and fed to the <filename>stdin</filename> of
|
|
<varname>COMMAND</varname>.</para>
|
|
|
|
<example id="prependex">
|
|
<title>Prepending a line to a file</title>
|
|
<programlisting>&prependex;</programlisting>
|
|
</example>
|
|
|
|
<para>Exercise: Find other uses for <emphasis>here
|
|
strings</emphasis>.</para>
|
|
|
|
</sect1><!-- Here Strings -->
|
|
|
|
|
|
</chapter> <!-- Here Documents -->
|
|
|
|
|
|
|
|
<chapter id="Recess-Time">
|
|
<title>Recess Time</title>
|
|
|
|
<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>
|
|
|
|
</chapter> <!-- Recess Time -->
|
|
|
|
</part> <!-- Part 3 (Beyond the Basics) -->
|
|
|
|
|
|
|
|
<part label="Part 4" id="part4">
|
|
<title>Advanced Topics</title>
|
|
|
|
<partintro>
|
|
<para>At this point, we are ready to delve into certain of the
|
|
difficult and unusual aspects of scripting. Along the way, we
|
|
will attempt to <quote>push the envelope</quote> in various
|
|
ways and examine <emphasis>boundary conditions</emphasis>
|
|
(what happens when we move into uncharted territory?).</para>
|
|
</partintro>
|
|
|
|
<chapter id="regexp">
|
|
<title>Regular Expressions</title>
|
|
|
|
<para><anchor id="regexref"></para>
|
|
|
|
<para>To fully utilize the power of shell scripting, you need to
|
|
master Regular Expressions. Certain commands and utilities
|
|
commonly used in scripts, such as
|
|
<link linkend="grepref">grep</link>, <link
|
|
linkend="exprref">expr</link>, <link linkend="sedref">sed</link>
|
|
and <link linkend="awkref">awk</link> interpret and use
|
|
REs.</para>
|
|
|
|
<sect1><title>A Brief Introduction to Regular Expressions</title>
|
|
|
|
<para>An expression is a string of characters. Those characters
|
|
having an interpretation above and beyond their literal
|
|
meaning are called <emphasis>metacharacters</emphasis>. A
|
|
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
|
|
metacharacters that match (or specify) patterns.</para>
|
|
|
|
<para>A Regular Expression contains one or more of the
|
|
following:</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>A character set. These are the characters retaining their
|
|
literal meaning. The simplest type of Regular Expression
|
|
consists <emphasis>only</emphasis> of a character set, with no
|
|
metacharacters.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>An anchor. These designate (<emphasis>anchor</emphasis>)
|
|
the position in the line of text that the RE is to
|
|
match. For example, <token>^</token>, and <token>$</token>
|
|
are anchors.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Modifiers. These expand or narrow
|
|
(<emphasis>modify</emphasis>) the range of text the RE is
|
|
to match. Modifiers include the asterisk, brackets, and
|
|
the backslash.</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<para>The main uses for Regular Expressions (REs) are text
|
|
searches and string manipulation. An RE
|
|
<firstterm>matches</firstterm> a single character or a set of
|
|
characters -- a string or a part of a string.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>*</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>*</secondary>
|
|
</indexterm>
|
|
|
|
<para>The asterisk -- <token>*</token> -- matches any number of
|
|
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>
|
|
|
|
<para><anchor id="regexdot">The dot -- <token>.</token> -- matches
|
|
any one character, except a newline.
|
|
<footnote><para>Since <link linkend="sedref">sed</link>, <link
|
|
linkend="awkref">awk</link>, and <link
|
|
linkend="grepref">grep</link> process single lines, there
|
|
will usually not be a newline to match. In those cases where
|
|
there is a newline in a multiple line expression, the dot
|
|
will match the newline.
|
|
<programlisting>#!/bin/bash
|
|
|
|
sed -e 'N;s/.*/[&]/' << EOF # Here Document
|
|
line1
|
|
line2
|
|
EOF
|
|
# OUTPUT:
|
|
# [line1
|
|
# line2]
|
|
|
|
|
|
|
|
echo
|
|
|
|
awk '{ $0=$1 "\n" $2; if (/line.1/) {print}}' << 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>
|
|
<para>The caret -- <token>^</token> -- matches the beginning of
|
|
a line, but sometimes, depending on context, negates the
|
|
meaning of a set of characters in an RE.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>$</secondary>
|
|
</indexterm>
|
|
<para><anchor id="dollarsignref"></para>
|
|
<para>The dollar sign -- <token>$</token> -- at the end of an
|
|
RE matches the end of a line.</para>
|
|
<para><quote>^$</quote> matches blank lines.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>[...]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>[...]</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="bracketsref"></para>
|
|
<para>Brackets -- <token>[...]</token> -- enclose a set of characters
|
|
to match in a single RE.</para>
|
|
|
|
<para><quote>[xyz]</quote> matches 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>
|
|
|
|
<para>The backslash -- <token>\</token> -- <link
|
|
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>
|
|
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\< \></primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>\< \></secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="anglebrac"></para>
|
|
<para><link linkend="escp">Escaped</link> <quote>angle
|
|
brackets</quote> -- <token>\<...\></token> -- mark word
|
|
boundaries.</para>
|
|
|
|
<para>The angle brackets must be escaped, since otherwise
|
|
they have only their literal character meaning.</para>
|
|
|
|
<para><quote>\<the\></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 '\<the\>' textfile</userinput>
|
|
<computeroutput>This is the only instance of line 2.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<sidebar>
|
|
<para>The only way to be certain that a particular RE works is to
|
|
test it.</para>
|
|
|
|
<para><programlisting>TEST FILE: tstfile # No match.
|
|
# No match.
|
|
Run grep "1133*" on this file. # Match.
|
|
# No match.
|
|
# No match.
|
|
This line contains the number 113. # Match.
|
|
This line contains the number 13. # No match.
|
|
This line contains the number 133. # No match.
|
|
This line contains the number 1133. # Match.
|
|
This line contains the number 113312. # Match.
|
|
This line contains the number 1112. # No match.
|
|
This line contains the number 113312312. # Match.
|
|
This line contains no numbers at all. # No match.</programlisting></para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>grep "1133*" tstfile</userinput>
|
|
<computeroutput>Run grep "1133*" on this file. # Match.
|
|
This line contains the number 113. # Match.
|
|
This line contains the number 1133. # Match.
|
|
This line contains the number 113312. # Match.
|
|
This line contains the number 113312312. # Match.</computeroutput>
|
|
</screen>
|
|
|
|
</sidebar>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem override="square">
|
|
<formalpara>
|
|
<title><anchor id="extregex">Extended REs</title>
|
|
|
|
<para>Additional metacharacters added to the basic set. Used
|
|
in <link linkend="egrepref">egrep</link>,
|
|
<link linkend="awkref">awk</link>, and <link
|
|
linkend="perlref">Perl</link>.</para>
|
|
|
|
</formalpara>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>?</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>?</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="quexregex"></para>
|
|
<para>The question mark -- <token>?</token> -- matches zero or
|
|
one of the previous RE. It is generally used for matching
|
|
single characters.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>+</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>+</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="plusref"></para>
|
|
<para>The plus -- <token>+</token> -- matches one or more of the
|
|
previous RE. It serves a role similar to the <token>*</token>, but
|
|
does <emphasis>not</emphasis> match zero occurrences.</para>
|
|
|
|
<para><programlisting># GNU versions of sed and awk can use "+",
|
|
# but it needs to be escaped.
|
|
|
|
echo a111b | sed -ne '/a1\+b/p'
|
|
echo a111b | grep 'a1\+b'
|
|
echo a111b | gawk '/a1+b/'
|
|
# All of above are equivalent.
|
|
|
|
# Thanks, S.C.</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\{ \}</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>\{ \}</secondary>
|
|
</indexterm>
|
|
|
|
<para><link linkend="escp">Escaped</link> <quote>curly
|
|
brackets</quote> -- <token>\{ \}</token> -- indicate the number
|
|
of occurrences of a preceding RE to match.</para>
|
|
|
|
|
|
<para>It is necessary to escape the curly brackets since
|
|
they have only their literal character meaning
|
|
otherwise. This usage is technically not part of the basic
|
|
RE set.</para>
|
|
|
|
<para><quote>[0-9]\{5\}</quote> matches exactly five digits
|
|
(characters in the range of 0 to 9).</para>
|
|
|
|
<note>
|
|
<para>Curly brackets are not available as an RE in the
|
|
<quote>classic</quote> (non-POSIX compliant) version
|
|
of <link linkend="awkref">awk</link>. However,
|
|
<command>gawk</command> has the
|
|
<option>--re-interval</option> option that permits them
|
|
(without being escaped).</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo 2222 | gawk --re-interval '/2{3}/'</userinput>
|
|
<computeroutput>2222</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><command>Perl</command> and some
|
|
<command>egrep</command> versions do not require escaping
|
|
the curly brackets.</para>
|
|
|
|
</note>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>()</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>()</secondary>
|
|
</indexterm>
|
|
|
|
<para>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>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>|</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>|</secondary>
|
|
</indexterm>
|
|
|
|
<para>The -- <command>|</command> -- <quote>or</quote> RE operator
|
|
matches any of a set of alternate characters.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>egrep 're(a|e)d' misc.txt</userinput>
|
|
<computeroutput>People who read seem to be better informed than those who do not.
|
|
The clarinet produces sound by the vibration of its reed.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<note><para>Some versions of <command>sed</command>,
|
|
<command>ed</command>, and <command>ex</command> support
|
|
escaped versions of the extended Regular Expressions
|
|
described above, as do the GNU utilities.</para></note>
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem override="square">
|
|
|
|
<formalpara><title><anchor id="posixref">POSIX Character Classes</title>
|
|
<para><userinput>[:class:]</userinput></para></formalpara>
|
|
|
|
<indexterm>
|
|
<primary>[:</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>:]</secondary>
|
|
</indexterm>
|
|
|
|
<para>This is an alternate method of specifying a range of
|
|
characters to match.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>alnum</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>alphabetic numeric</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:alnum:]</userinput> matches alphabetic or
|
|
numeric characters. This is equivalent to
|
|
<userinput>A-Za-z0-9</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>alpha</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>alphabetic</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:alpha:]</userinput> matches alphabetic
|
|
characters. This is equivalent to
|
|
<userinput>A-Za-z</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>blank</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>space tab</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:blank:]</userinput> matches a space or a
|
|
tab.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>cntrl</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>control</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:cntrl:]</userinput> matches control
|
|
characters.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>digit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>decimal digit</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:digit:]</userinput> matches (decimal)
|
|
digits. This is equivalent to
|
|
<userinput>0-9</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>graph</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>graph</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:graph:]</userinput> (graphic printable
|
|
characters). Matches characters in the range of ASCII 33 -
|
|
126. This is the same as <userinput>[:print:]</userinput>,
|
|
below, but excluding the space character.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>lower</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>lowercase</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:lower:]</userinput> matches lowercase
|
|
alphabetic characters. This is equivalent to
|
|
<userinput>a-z</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>print</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>printable</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:print:]</userinput> (printable
|
|
characters). Matches characters in the range of ASCII 32 -
|
|
126. This is the same as <userinput>[:graph:]</userinput>,
|
|
above, but adding the space character.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>space</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>whitespace</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:space:]</userinput> matches whitespace
|
|
characters (space and horizontal tab).</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>upper</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>uppercase</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:upper:]</userinput> matches uppercase
|
|
alphabetic characters. This is equivalent to
|
|
<userinput>A-Z</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>xdigit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>hexadecimal</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:xdigit:]</userinput> matches hexadecimal
|
|
digits. This is equivalent to
|
|
<userinput>0-9A-Fa-f</userinput>.</para>
|
|
|
|
<important>
|
|
|
|
<para>POSIX character classes generally require quoting
|
|
or <link linkend="dblbrackets">double brackets</link>
|
|
([[ ]]).</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep [[:digit:]] test.file</userinput>
|
|
<computeroutput>abc=723</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>These character classes may even be used with <link
|
|
linkend="globbingref">globbing</link>, to a limited
|
|
extent.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ls -l ?[[:digit:]][[:digit:]]?</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 21 14:47 a33b</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>To see POSIX character classes used in scripts, refer to
|
|
<xref linkend="ex49"> and <xref linkend="lowercase">.</para>
|
|
|
|
</important>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<para><link linkend="sedref">Sed</link>, <link
|
|
linkend="awkref">awk</link>, and <link
|
|
linkend="perlref">Perl</link>, used as filters in scripts, take
|
|
REs as arguments when "sifting" or transforming files or I/O
|
|
streams. See <xref linkend="behead"> and <xref linkend="tree">
|
|
for illustrations of this.</para>
|
|
|
|
<para>The standard reference on this complex topic is Friedl's
|
|
<citetitle pubwork="book">Mastering Regular
|
|
Expressions</citetitle>. <citetitle pubwork="book">Sed &
|
|
Awk</citetitle>, by Dougherty and Robbins also gives a very
|
|
lucid treatment of REs. See the <xref linkend="biblio"> for
|
|
more information on these books.</para>
|
|
|
|
</sect1> <!-- A Brief Introduction to Regular Expressions -->
|
|
|
|
<sect1 id="globbingref">
|
|
<title>Globbing</title>
|
|
|
|
<para>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>
|
|
|
|
|
|
<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>.
|
|
|
|
<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>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>ls -l</userinput>
|
|
<computeroutput>total 2
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 a.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1
|
|
-rw-rw-r-- 1 bozo bozo 466 Aug 6 17:48 t2.sh
|
|
-rw-rw-r-- 1 bozo bozo 758 Jul 30 09:02 test1.txt</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l t?.sh</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 466 Aug 6 17:48 t2.sh</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l [ab]*</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 a.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l [a-c]*</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 a.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l [^ab]*</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1
|
|
-rw-rw-r-- 1 bozo bozo 466 Aug 6 17:48 t2.sh
|
|
-rw-rw-r-- 1 bozo bozo 758 Jul 30 09:02 test1.txt</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l {b*,c*,*est*}</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1
|
|
-rw-rw-r-- 1 bozo bozo 758 Jul 30 09:02 test1.txt</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
|
|
<para>Bash performs filename expansion on unquoted command-line
|
|
arguments. The <link linkend="echoref">echo</link> command
|
|
demonstrates this.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo *</userinput>
|
|
<computeroutput>a.1 b.1 c.1 t2.sh test1.txt</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo t*</userinput>
|
|
<computeroutput>t2.sh test1.txt</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>It is possible to modify the way Bash interprets
|
|
special characters in globbing. A <command>set -f</command>
|
|
command disables globbing, and the
|
|
<option>nocaseglob</option> and <option>nullglob</option>
|
|
options to <link linkend="shoptref">shopt</link> change
|
|
globbing behavior.</para></note>
|
|
|
|
<para>See also <xref linkend="listglob">.</para>
|
|
|
|
</sect1> <!-- Globbing -->
|
|
|
|
|
|
</chapter> <!-- Regular Expressions -->
|
|
|
|
|
|
|
|
<chapter id="subshells">
|
|
<title>Subshells</title>
|
|
|
|
<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>
|
|
|
|
<sidebar>
|
|
<para>In general, an <link linkend="externalref">external
|
|
command</link> in a script <link linkend="forkref">forks
|
|
off</link> a subprocess, whereas a Bash <link
|
|
linkend="builtinref">builtin</link> does not. For this reason,
|
|
builtins execute more quickly than their external command
|
|
equivalents.</para>
|
|
</sidebar>
|
|
|
|
<variablelist id="subshellparens">
|
|
<title><anchor id="subshellparens1">Command List in
|
|
Parentheses</title>
|
|
|
|
<varlistentry>
|
|
<term>( command1; command2; command3; ... )</term>
|
|
<listitem>
|
|
<para>A command list embedded between
|
|
<replaceable>parentheses</replaceable> runs as a
|
|
subshell.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<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> /dev/null
|
|
then
|
|
echo "Variable is set."
|
|
fi # Variable has been set in current script,
|
|
#+ or is an an internal Bash variable,
|
|
#+ or is present in environment (has been exported).
|
|
|
|
# Could also be written [[ ${variable-x} != x || ${variable-y} != y ]]
|
|
# or [[ ${variable-x} != x$variable ]]
|
|
# or [[ ${variable+x} = x ]]
|
|
# or [[ ${variable-x} != x ]]</programlisting>
|
|
|
|
Another application is checking for a lock file:
|
|
<programlisting>if (set -C; : > lock_file) 2> /dev/null
|
|
then
|
|
: # lock_file didn't exist: no user running the script
|
|
else
|
|
echo "Another user is already running that script."
|
|
exit 65
|
|
fi
|
|
|
|
# Code snippet by Stephane Chazelas,
|
|
#+ with modifications by Paulo Marcel Coelho Aragao.</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>
|
|
|
|
|
|
</chapter> <!-- Subshells -->
|
|
|
|
|
|
|
|
<chapter id="restricted-sh">
|
|
<title>Restricted Shells</title>
|
|
|
|
<variablelist id="disabledcommref0">
|
|
<title><anchor id="disabledcommref">Disabled commands in restricted
|
|
shells</title>
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<formalpara><title></title>
|
|
<para>Running a script or portion of a script in
|
|
<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>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<formalpara><title></title>
|
|
|
|
<para>Using <replaceable>cd</replaceable> to change the working
|
|
directory.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>Changing the values of the
|
|
<replaceable>$PATH</replaceable>,
|
|
<replaceable>$SHELL</replaceable>,
|
|
<replaceable>$BASH_ENV</replaceable>,
|
|
or <replaceable>$ENV</replaceable> <link
|
|
linkend="envref">environmental variables</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>Reading or changing the <replaceable>$SHELLOPTS</replaceable>,
|
|
shell environmental options.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>Output redirection.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>Invoking commands containing one or more
|
|
<token>/'s</token>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>Invoking <emphasis>exec</emphasis> to substitute a different
|
|
process for the shell.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>Various other commands that would enable monkeying
|
|
with or attempting to subvert the script for an unintended
|
|
purpose.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>Getting out of restricted mode within the script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<example id="restricted">
|
|
<title>Running a script in restricted mode</title>
|
|
<programlisting>&restricted;</programlisting>
|
|
</example>
|
|
|
|
</chapter> <!-- Restricted Shells -->
|
|
|
|
|
|
|
|
|
|
<chapter id="process-sub">
|
|
<title>Process Substitution</title>
|
|
|
|
<para><anchor id="processsubref"><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>
|
|
|
|
<variablelist id="commandsparens">
|
|
<title><anchor id="commandsparens1">Command substitution template</title>
|
|
|
|
<varlistentry>
|
|
<term>command within parentheses</term>
|
|
|
|
<listitem>
|
|
<para><command>>(command)</command></para>
|
|
<para><command><(command)</command></para>
|
|
<para>These initiate process substitution. This uses
|
|
<filename>/dev/fd/<n></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>
|
|
</para>
|
|
|
|
<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>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo >(true)</userinput>
|
|
<computeroutput>/dev/fd/63</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo <(true)</userinput>
|
|
<computeroutput>/dev/fd/63</computeroutput>
|
|
</screen>
|
|
|
|
Bash creates a pipe with two <link linkend="fdref">file
|
|
descriptors</link>, <filename>--fIn</filename> and
|
|
<filename>fOut--</filename>. The <filename>stdin</filename>
|
|
of <link linkend="trueref">true</link> connects
|
|
to <filename>fOut</filename> (dup2(fOut, 0)),
|
|
then Bash passes a <filename>/dev/fd/fIn</filename>
|
|
argument to <command>echo</command>. On systems lacking
|
|
<filename>/dev/fd/<n></filename> files, Bash may use
|
|
temporary files. (Thanks, S.C.)</para>
|
|
|
|
|
|
<para>Process substitution can compare the output of two
|
|
different commands, or even the output of different options
|
|
to the same command.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>comm <(ls -l) <(ls -al)</userinput>
|
|
<computeroutput>total 12
|
|
-rw-rw-r-- 1 bozo bozo 78 Mar 10 12:58 File0
|
|
-rw-rw-r-- 1 bozo bozo 42 Mar 10 12:58 File2
|
|
-rw-rw-r-- 1 bozo bozo 103 Mar 10 12:58 t2.sh
|
|
total 20
|
|
drwxrwxrwx 2 bozo bozo 4096 Mar 10 18:10 .
|
|
drwx------ 72 bozo bozo 4096 Mar 10 17:58 ..
|
|
-rw-rw-r-- 1 bozo bozo 78 Mar 10 12:58 File0
|
|
-rw-rw-r-- 1 bozo bozo 42 Mar 10 12:58 File2
|
|
-rw-rw-r-- 1 bozo bozo 103 Mar 10 12:58 t2.sh</computeroutput></screen>
|
|
|
|
<para>
|
|
Using process substitution to compare the contents
|
|
of two directories (to see which filenames are in one,
|
|
but not the other):
|
|
<programlisting>diff <(ls $first_directory) <(ls $second_directory)</programlisting>
|
|
</para>
|
|
|
|
<para>Some other usages and uses of process substitution:</para>
|
|
|
|
<para><programlisting>cat <(ls -l)
|
|
# Same as ls -l | cat
|
|
|
|
sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) <(ls -l /usr/X11R6/bin)
|
|
# Lists all the files in the 3 main 'bin' directories, and sorts by filename.
|
|
# Note that three (count 'em) distinct commands are fed to 'sort'.
|
|
|
|
|
|
diff <(command1) <(command2) # Gives difference in command output.
|
|
|
|
tar cf >(bzip2 -c > file.tar.bz2) $directory_name
|
|
# Calls "tar cf /dev/fd/?? $directory_name", and "bzip2 -c > file.tar.bz2".
|
|
#
|
|
# Because of the /dev/fd/<n> system feature,
|
|
# the pipe between both commands does not need to be named.
|
|
#
|
|
# This can be emulated.
|
|
#
|
|
bzip2 -c < pipe > file.tar.bz2&
|
|
tar cf pipe $directory_name
|
|
rm pipe
|
|
# or
|
|
exec 3>&1
|
|
tar cf /dev/fd/4 $directory_name 4>&1 >&3 3>&- | bzip2 -c > file.tar.bz2 3>&-
|
|
exec 3>&-
|
|
|
|
|
|
# Thanks, Stepane Chazelas</programlisting></para>
|
|
|
|
|
|
<para>A reader sent in the following interesting example of process
|
|
substitution.</para>
|
|
|
|
<para><programlisting># Script fragment taken from SuSE distribution:
|
|
|
|
while read des what mask iface; do
|
|
# Some commands ...
|
|
done < <(route -n)
|
|
|
|
|
|
# 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 Stephane Chazelas points out, an easier-to-understand equivalent is:
|
|
route -n |
|
|
while read des what mask iface; do # Variables set from output of pipe.
|
|
echo $des $what $mask $iface
|
|
done # This yields the same output as above.
|
|
# However, as Ulrich Gayer points out . . .
|
|
#+ this simplified equivalent uses a subshell for the while loop,
|
|
#+ and therefore the variables disappear when the pipe terminates.
|
|
|
|
|
|
|
|
# However, Filip Moritz comments that there is a subtle difference
|
|
#+ between the above two examples, as the following shows.
|
|
|
|
(
|
|
route -n | while read x; do ((y++)); done
|
|
echo $y # $y is still unset
|
|
|
|
while read x; do ((y++)); done < <(route -n)
|
|
echo $y # $y has the number of lines of output of route -n
|
|
)
|
|
|
|
More generally spoken
|
|
(
|
|
: | x=x
|
|
# seems to start a subshell like
|
|
: | ( x=x )
|
|
# while
|
|
x=x < <(:)
|
|
# does not
|
|
)
|
|
|
|
# This is useful, when parsing csv and the like.
|
|
# That is, in effect, what the original SuSE code fragment does.</programlisting></para>
|
|
|
|
|
|
|
|
</chapter> <!-- Process Substitution -->
|
|
|
|
|
|
|
|
|
|
<chapter id="functions">
|
|
<title>Functions</title>
|
|
|
|
<para><anchor id="functionref"></para>
|
|
|
|
<para>Like <quote>real</quote> programming languages,
|
|
Bash has functions, though in a somewhat limited implementation.
|
|
A function is a subroutine, a <link linkend="codeblockref">code
|
|
block</link> that implements a set of operations, a <quote>black
|
|
box</quote> that performs a specified task. Wherever there is
|
|
repetitive code, when a task repeats with only slight variations,
|
|
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 functions</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.
|
|
|
|
declare -f f1 # This doesn't help either.
|
|
f1 # Still an error message.
|
|
|
|
# However...
|
|
|
|
|
|
f1 ()
|
|
{
|
|
echo "Calling function \"f2\" from within function \"f1\"."
|
|
f2
|
|
}
|
|
|
|
f2 ()
|
|
{
|
|
echo "Function \"f2\"."
|
|
}
|
|
|
|
f1 # Function "f2" is not actually called until this point,
|
|
#+ although it is referenced before its definition.
|
|
# This is 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.
|
|
# Even a preceding "declare -f f2" wouldn't help.
|
|
|
|
echo
|
|
|
|
f1 # Does nothing, since calling "f1" does not automatically call "f2".
|
|
f2 # Now, it's all right to call "f2",
|
|
#+ since its definition has been made visible by calling "f1".
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<para>Function declarations can appear in unlikely places, even where a
|
|
command would otherwise go.
|
|
<programlisting>ls -l | foo() { echo "foo"; } # 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>
|
|
|
|
|
|
<sect1 id="complexfunct">
|
|
<title>Complex Functions and Function Complexities</title>
|
|
|
|
<para>Functions may process arguments passed to them and return
|
|
an <link linkend="exitstatusref">exit status</link> to the script
|
|
for further processing.</para>
|
|
|
|
<programlisting>function_name $arg1 $arg2</programlisting>
|
|
|
|
<para>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>
|
|
|
|
<important><para>The <link linkend="shiftref">shift</link>
|
|
command works on arguments passed to functions (see <xref
|
|
linkend="multiplication">).</para></important>
|
|
|
|
<para>But, what about command-line arguments passed to the script?
|
|
Does a function see them? Well, let's clear up the confusion.</para>
|
|
|
|
<example id="funccmdlinearg">
|
|
<title>Functions and command-line args passed to the script</title>
|
|
<programlisting>&funccmdlinearg;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>In contrast to certain other programming languages,
|
|
shell scripts normally pass only value parameters to
|
|
functions. Variable names (which are actually pointers), if
|
|
passed as parameters to functions, will be treated as string
|
|
literals. <emphasis>Functions interpret their arguments
|
|
literally.</emphasis></para>
|
|
|
|
<para><link linkend="ivrref">Indirect variable
|
|
references</link> (see <xref linkend="ex78">) provide a clumsy
|
|
sort of mechanism for passing variable pointers to
|
|
functions.</para>
|
|
|
|
<example id="indfunc">
|
|
<title>Passing an indirect reference to a function</title>
|
|
<programlisting>&indfunc;</programlisting>
|
|
</example>
|
|
|
|
<para>The next logical question is whether parameters can be
|
|
dereferenced <emphasis>after</emphasis> being passed to a
|
|
function.</para>
|
|
|
|
<example id="dereferencecl">
|
|
<title>Dereferencing a parameter passed to a function</title>
|
|
<programlisting>&dereferencecl;</programlisting>
|
|
</example>
|
|
|
|
<example id="refparams">
|
|
<title>Again, dereferencing a parameter passed to a function</title>
|
|
<programlisting>&refparams;</programlisting>
|
|
</example>
|
|
|
|
|
|
<variablelist id="exitreturn">
|
|
<title><anchor id="exitreturn1">Exit and Return</title>
|
|
|
|
<varlistentry>
|
|
<term><command>exit status</command></term>
|
|
<listitem>
|
|
<para>Functions return a value, called an <firstterm>exit
|
|
status</firstterm>. The exit status may be explicitly
|
|
specified by a <command>return</command> statement,
|
|
otherwise it is the exit status of the last command
|
|
in the function (<returnvalue>0</returnvalue> if
|
|
successful, and a non-zero error code if not). This
|
|
<link linkend="exitstatusref">exit status</link>
|
|
may be used in the script by referencing it as
|
|
<link linkend="xstatvarref">$?</link>. This mechanism
|
|
effectively permits script functions to have a <quote>return
|
|
value</quote> similar to C functions.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>return</command></term>
|
|
<indexterm>
|
|
<primary>return</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>return</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para><anchor id="returnref"></para>
|
|
<para>Terminates a function. A <command>return</command> command
|
|
<footnote><para>The <command>return</command> command is a
|
|
Bash <link linkend="builtinref">builtin</link>.</para></footnote>
|
|
optionally takes an <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>
|
|
|
|
<example id="max">
|
|
<title>Maximum of two numbers</title>
|
|
<programlisting>&max;</programlisting>
|
|
</example>
|
|
|
|
<tip>
|
|
<para>For a function to return a string or array, use a
|
|
dedicated variable.
|
|
<programlisting>count_lines_in_etc_passwd()
|
|
{
|
|
[[ -r /etc/passwd ]] && REPLY=$(echo $(wc -l < /etc/passwd))
|
|
# If /etc/passwd is readable, set REPLY to line count.
|
|
# Returns both a parameter value and status information.
|
|
# The 'echo' seems unnecessary, but . . .
|
|
#+ it removes excess whitespace from the output.
|
|
}
|
|
|
|
if count_lines_in_etc_passwd
|
|
then
|
|
echo "There are $REPLY lines in /etc/passwd."
|
|
else
|
|
echo "Cannot count lines in /etc/passwd."
|
|
fi
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
</tip>
|
|
|
|
|
|
|
|
|
|
<example id="ex61">
|
|
<title>Converting numbers to Roman numerals</title>
|
|
<programlisting>&ex61;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="isalpha">.</para>
|
|
|
|
<important>
|
|
|
|
<para>The largest positive integer a function can return is
|
|
255. The <command>return</command> command is closely tied
|
|
to the concept of <link linkend="exitstatusref">exit
|
|
status</link>, which accounts for this particular
|
|
limitation. Fortunately, there are various <link
|
|
linkend="rvt">workarounds</link> for those situations
|
|
requiring a large integer return value from a
|
|
function.</para>
|
|
|
|
|
|
<example id="returntest">
|
|
<title>Testing large return values in a function</title>
|
|
<programlisting>&returntest;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>A workaround for obtaining large integer <quote>return
|
|
values</quote> is to simply assign the <quote>return
|
|
value</quote> to a global variable.
|
|
|
|
<programlisting>Return_Val= # Global variable to hold oversize return value of function.
|
|
|
|
alt_return_test ()
|
|
{
|
|
fvar=$1
|
|
Return_Val=$fvar
|
|
return # Returns 0 (success).
|
|
}
|
|
|
|
alt_return_test 1
|
|
echo $? # 0
|
|
echo "return value = $Return_Val" # 1
|
|
|
|
alt_return_test 256
|
|
echo "return value = $Return_Val" # 256
|
|
|
|
alt_return_test 257
|
|
echo "return value = $Return_Val" # 257
|
|
|
|
alt_return_test 25701
|
|
echo "return value = $Return_Val" #25701</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>An even more elegant method is to simply have the
|
|
function <command>echo</command> its <quote>return
|
|
value to <filename>stdout</filename>,</quote> and to
|
|
then capture it by <link linkend="commandsubref">command
|
|
substitution</link>. See the <link linkend="rvt">discussion
|
|
of this</link> in <xref linkend="assortedtips">.</para>
|
|
|
|
<example id="max2">
|
|
<title>Comparing two large integers</title>
|
|
<programlisting>&max2;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="daysbetween">.</para>
|
|
|
|
<para><userinput>Exercise:</userinput> Using what we have
|
|
just learned, extend the previous <link
|
|
linkend="ex61">Roman numerals example</link> to accept
|
|
arbitrarily large input.</para>
|
|
|
|
</important>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="redstdinfunc">
|
|
<title><anchor id="redstdinfunc1">Redirection</title>
|
|
|
|
<varlistentry>
|
|
<term><replaceable>Redirecting the stdin of a
|
|
function</replaceable></term>
|
|
<indexterm>
|
|
<primary>redirection</primary>
|
|
<secondary>stdin</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
|
|
<para>A function is essentially a <link
|
|
linkend="codeblockref">code block</link>, which means its
|
|
<filename>stdin</filename> can be redirected (as in <xref
|
|
linkend="ex8">).</para>
|
|
|
|
<example id="realname">
|
|
<title>Real name from username</title>
|
|
<programlisting>&realname;</programlisting>
|
|
</example>
|
|
|
|
<para>There is an 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>
|
|
|
|
</sect1> <!-- Complex Functions and Function Complexities -->
|
|
|
|
|
|
<sect1 id="localvar">
|
|
<title>Local Variables</title>
|
|
|
|
<variablelist id="localref">
|
|
<title><anchor id="localref1">What makes a variable <quote>local</quote>?</title>
|
|
|
|
<varlistentry>
|
|
<term>local variables</term>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>local</secondary>
|
|
</indexterm>
|
|
<listitem>
|
|
<para>A variable declared as <firstterm>local</firstterm>
|
|
is one that is visible only within the <link
|
|
linkend="codeblockref">block of code</link> in which it
|
|
appears. It has local <quote>scope</quote>. In
|
|
a function, a <emphasis>local variable</emphasis> has
|
|
meaning only within that function block.</para>
|
|
|
|
<example id="ex62">
|
|
<title>Local variable visibility</title>
|
|
<programlisting>&ex62;</programlisting>
|
|
</example>
|
|
|
|
<caution>
|
|
<para>Before a function is called, <emphasis>all</emphasis>
|
|
variables declared within the function are invisible outside
|
|
the body of the function, not just those explicitly declared
|
|
as <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 help make recursion possible.</title>
|
|
|
|
<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.
|
|
|
|
<footnote><para>Too many levels of recursion may crash a
|
|
script with a segfault.
|
|
<programlisting>#!/bin/bash
|
|
|
|
# Warning: Running this script could possibly lock up your system!
|
|
# If you're lucky, it will segfault before using up all available memory.
|
|
|
|
recursive_function ()
|
|
{
|
|
(( $1 < $2 )) && recursive_function $(( $1 + 1 )) $2;
|
|
# As long as 1st parameter is less than 2nd,
|
|
#+ increment 1st and recurse.
|
|
}
|
|
|
|
recursive_function 1 50000 # Recurse 50,000 levels!
|
|
# Most likely segfaults (depending on stack size, set by ulimit -m).
|
|
|
|
# Recursion this deep might cause even a C program to segfault,
|
|
#+ by using up all the memory allotted to the stack.
|
|
|
|
|
|
echo "This will probably not print."
|
|
exit 0 # This script will not exit normally.
|
|
|
|
# Thanks, Stephane Chazelas.</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
|
|
resource-intensive and executes slowly, and is therefore
|
|
generally not appropriate to use in a script.</para>
|
|
|
|
</sect2>
|
|
</sect1> <!-- Local Variables -->
|
|
|
|
<sect1 id="recurnolocvar">
|
|
<title>Recursion Without Local Variables</title>
|
|
|
|
<para>A function may recursively call itself even without use of
|
|
local variables.</para>
|
|
|
|
<example id="hanoi">
|
|
<title>The Towers of Hanoi</title>
|
|
<programlisting>&hanoi;</programlisting>
|
|
</example>
|
|
|
|
</sect1> <!-- Recursion Without Local Variables -->
|
|
|
|
|
|
|
|
</chapter> <!-- Functions -->
|
|
|
|
|
|
|
|
<chapter id="aliases">
|
|
<title>Aliases</title>
|
|
|
|
<para><anchor id="aliasref"></para>
|
|
|
|
<indexterm>
|
|
<primary>alias</primary>
|
|
</indexterm>
|
|
|
|
<para>A Bash <emphasis>alias</emphasis> is essentially nothing more than
|
|
a keyboard shortcut, an abbreviation, a means of avoiding
|
|
typing a long command sequence. If, for example, we include
|
|
<command>alias lm="ls -l | more"</command> in the <link
|
|
linkend="filesref1"><filename>~/.bashrc</filename> file</link>,
|
|
then each <userinput>lm</userinput> typed at the command
|
|
line will automatically be replaced by a <command>ls -l |
|
|
more</command>. This can save a great deal of typing at the
|
|
command line and avoid having to remember complex combinations of
|
|
commands and options. Setting <command>alias rm="rm -i"</command>
|
|
(interactive mode delete) may save a good deal of grief, since
|
|
it can prevent inadvertently losing important files.</para>
|
|
|
|
<para>In a script, aliases have very limited usefulness. It would be
|
|
quite nice if aliases could assume some of the functionality of
|
|
the C preprocessor, such as macro expansion, but unfortunately
|
|
Bash does not expand arguments within the alias body.
|
|
<footnote><para>However, aliases do seem to expand positional
|
|
parameters.</para></footnote>
|
|
Moreover, a script fails to expand an alias itself
|
|
within <quote>compound constructs</quote>, such as <link
|
|
linkend="ifthen">if/then</link> statements, loops, and
|
|
functions. An added limitation is that an alias will not expand
|
|
recursively. Almost invariably, whatever we would like an alias
|
|
to do could be accomplished much more effectively with a <link
|
|
linkend="functionref">function</link>.</para>
|
|
|
|
<example id="al">
|
|
<title>Aliases within a script</title>
|
|
<programlisting>&al;</programlisting>
|
|
</example>
|
|
|
|
<para>The <command>unalias</command> command removes a previously
|
|
set <emphasis>alias</emphasis>.</para>
|
|
|
|
<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>
|
|
|
|
|
|
</chapter> <!-- Aliases -->
|
|
|
|
|
|
|
|
|
|
<chapter id="list-cons">
|
|
<title>List Constructs</title>
|
|
|
|
<para><anchor id="listconsref"></para>
|
|
|
|
<indexterm>
|
|
<primary>&&</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>&&</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>AND</primary>
|
|
<secondary>list</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>||</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>||</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>OR</primary>
|
|
<secondary>list</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <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>
|
|
|
|
|
|
<variablelist id="lcons">
|
|
<title><anchor id="lcons1">Chaining together commands</title>
|
|
|
|
<varlistentry>
|
|
<term>and list</term>
|
|
<listitem>
|
|
<para><programlisting>command-1 && command-2 && command-3 && ... command-n</programlisting>
|
|
Each command executes in turn provided that
|
|
the previous command has given a return value of
|
|
<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>
|
|
|
|
<para><anchor id="anddefault"></para>
|
|
<para>
|
|
Of course, an <emphasis>and list</emphasis> can also
|
|
<emphasis>set</emphasis> variables to a default value.
|
|
<programlisting>arg1=$@ # Set $arg1 to command line arguments, if any.
|
|
|
|
[ -z "$arg1" ] && arg1=DEFAULT
|
|
# Set to DEFAULT if not specified on command line.</programlisting>
|
|
</para>
|
|
|
|
</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>
|
|
|
|
|
|
<para><programlisting># ==> The following snippets from the /etc/rc.d/init.d/single script by Miquel van Smoorenburg
|
|
#+==> illustrate use of "and" and "or" lists.
|
|
# ==> "Arrowed" comments added by document author.
|
|
|
|
[ -x /usr/bin/clear ] && /usr/bin/clear
|
|
# ==> If /usr/bin/clear exists, then invoke it.
|
|
# ==> Checking for the existence of a command before calling it
|
|
#+==> avoids error messages and other awkward consequences.
|
|
|
|
# ==> . . .
|
|
|
|
# If they want to run something in single user mode, might as well run it...
|
|
for i in /etc/rc1.d/S[0-9][0-9]* ; do
|
|
# Check if the script is there.
|
|
[ -x "$i" ] || continue
|
|
# ==> If corresponding file in $PWD *not* found,
|
|
#+==> then "continue" by jumping to the top of the loop.
|
|
|
|
# Reject backup files and files generated by rpm.
|
|
case "$1" in
|
|
*.rpmsave|*.rpmorig|*.rpmnew|*~|*.orig)
|
|
continue;;
|
|
esac
|
|
[ "$i" = "/etc/rc1.d/S00single" ] && continue
|
|
# ==> Set script name, but don't execute it yet.
|
|
$i start
|
|
done
|
|
|
|
# ==> . . .</programlisting></para>
|
|
|
|
|
|
<important><para>The <link linkend="exitstatusref">exit
|
|
status</link> of an <userinput>and list</userinput> or an
|
|
<userinput>or list</userinput> is the exit status of the last
|
|
command executed.</para></important>
|
|
|
|
<para>Clever combinations of <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>
|
|
|
|
<para>See <xref linkend="daysbetween"> and <xref
|
|
linkend="brokenlink"> for illustrations of using an <userinput>and
|
|
/ or list</userinput> to test variables.</para>
|
|
|
|
|
|
</chapter> <!-- List Constructs -->
|
|
|
|
|
|
|
|
|
|
<chapter id="arrays">
|
|
<title>Arrays</title>
|
|
|
|
<para><anchor id="arrayref"></para>
|
|
|
|
<para>Newer versions of Bash support one-dimensional arrays.
|
|
Array elements may be initialized with the
|
|
<userinput>variable[xx]</userinput> notation. Alternatively,
|
|
a script may introduce the entire array by an explicit
|
|
<userinput>declare -a variable</userinput> statement. To
|
|
dereference (find the contents of) an array element, use
|
|
<firstterm>curly bracket</firstterm> notation, that is,
|
|
<userinput>${variable[xx]}</userinput>.</para>
|
|
|
|
<example id="ex66">
|
|
<title>Simple array usage</title>
|
|
<programlisting>&ex66;</programlisting>
|
|
</example>
|
|
|
|
|
|
<note><para>Bash permits array operations on variables, even if
|
|
the variables are not explicitly declared as arrays.
|
|
<programlisting>string=abcABC123ABCabc
|
|
echo ${string[@]} # abcABC123ABCabc
|
|
echo ${string[*]} # abcABC123ABCabc
|
|
echo ${string[0]} # abcABC123ABCabc
|
|
echo ${string[1]} # No output!
|
|
# Why?
|
|
echo ${#string[@]} # 1
|
|
# One element in the array.
|
|
# The string itself.
|
|
|
|
# Thank you, Michael Zick, for pointing this out.</programlisting>
|
|
Once again this demonstrates that <link linkend="bvuntyped">Bash
|
|
variables are untyped</link>.
|
|
</para></note>
|
|
|
|
|
|
<example id="poem">
|
|
<title>Formatting a poem</title>
|
|
<programlisting>&poem;</programlisting>
|
|
</example>
|
|
|
|
<para>Array variables have a syntax all their own, and even
|
|
standard Bash commands and operators have special options adapted
|
|
for array use.</para>
|
|
|
|
<example id="arrayops">
|
|
<title>Various array operations</title>
|
|
<programlisting>&arrayops;</programlisting>
|
|
</example>
|
|
|
|
<para>Many of the standard <link linkend="stringmanip">string
|
|
operations</link> work on arrays.</para>
|
|
|
|
<example id="arraystrops">
|
|
<title>String operations on arrays</title>
|
|
<programlisting>&arraystrops;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><link linkend="commandsubref">Command substitution</link> can
|
|
construct the individual elements of an array.</para>
|
|
|
|
<example id="scriptarray">
|
|
<title>Loading the contents of a script into an array</title>
|
|
<programlisting>&scriptarray;</programlisting>
|
|
</example>
|
|
|
|
<para>In an array context, some Bash <link
|
|
linkend="builtinref">builtins</link> have a slightly altered
|
|
meaning. For example, <link linkend="unsetref">unset</link>
|
|
deletes array elements, or even an entire array.</para>
|
|
|
|
<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[@]}" )
|
|
# or
|
|
array2="${array1[@]}"
|
|
|
|
# Adding an element to an array.
|
|
array=( "${array[@]}" "new element" )
|
|
# or
|
|
array[${#array[*]}]="new element"
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
|
|
<tip>
|
|
<para>The <command>array=( element1 element2 ... elementN )</command>
|
|
initialization operation, with the help of <link
|
|
linkend="commandsubref">command substitution</link>, makes it
|
|
possible to load the contents of a text file into an array.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
filename=sample_file
|
|
|
|
# cat sample_file
|
|
#
|
|
# 1 a b c
|
|
# 2 d e fg
|
|
|
|
|
|
declare -a array1
|
|
|
|
array1=( `cat "$filename"`) # Loads contents
|
|
# List file to stdout #+ of $filename into array1.
|
|
#
|
|
# array1=( `cat "$filename" | tr '\n' ' '`)
|
|
# change linefeeds in file to spaces.
|
|
# Not necessary because Bash does word splitting,
|
|
#+ changing linefeeds to spaces.
|
|
|
|
echo ${array1[@]} # List the array.
|
|
# 1 a b c 2 d e fg
|
|
#
|
|
# Each whitespace-separated "word" in the file
|
|
#+ has been assigned to an element of the array.
|
|
|
|
element_count=${#array1[*]}
|
|
echo $element_count # 8</programlisting>
|
|
</para>
|
|
</tip>
|
|
|
|
<para>Clever scripting makes it possible to add array operations.</para>
|
|
|
|
<example id="arrayassign">
|
|
<title>Initializing arrays</title>
|
|
<programlisting>&arrayassign;</programlisting>
|
|
</example>
|
|
|
|
<note><para>Adding a superfluous <command>declare -a</command>
|
|
statement to an array declaration may speed up execution of
|
|
subsequent operations on the array.</para></note>
|
|
|
|
<example id="copyarray">
|
|
<title>Copying and concatenating arrays</title>
|
|
<programlisting>©array;</programlisting>
|
|
</example>
|
|
|
|
<example id="arrayappend">
|
|
<title>More on concatenating arrays</title>
|
|
<programlisting>&arrayappend;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>--</para>
|
|
|
|
<para>Arrays permit deploying old familiar algorithms as shell scripts.
|
|
Whether this is necessarily a good idea is left to the reader to
|
|
decide.</para>
|
|
|
|
<example id="bubble">
|
|
<title>An old friend:
|
|
<emphasis>The Bubble Sort</emphasis></title>
|
|
<programlisting>&bubble;</programlisting>
|
|
</example>
|
|
|
|
<para>--</para>
|
|
|
|
<para>Is it possible to nest arrays within arrays?</para>
|
|
<para><programlisting>#!/bin/bash
|
|
# "Nested" array.
|
|
|
|
# Michael Zick provided this example,
|
|
#+ with corrections and clarifications by William Park.
|
|
|
|
AnArray=( $(ls --inode --ignore-backups --almost-all \
|
|
--directory --full-time --color=none --time=status \
|
|
--sort=time -l ${PWD} ) ) # Commands and options.
|
|
|
|
# Spaces are significant . . . and don't quote anything in the above.
|
|
|
|
SubArray=( ${AnArray[@]:11:1} ${AnArray[@]:6:5} )
|
|
# This array has six elements:
|
|
#+ SubArray=( [0]=${AnArray[11]} [1]=${AnArray[6]} [2]=${AnArray[7]}
|
|
# [3]=${AnArray[8]} [4]=${AnArray[9]} [5]=${AnArray[10]} )
|
|
#
|
|
# Arrays in Bash are (circularly) linked lists
|
|
#+ of type string (char *).
|
|
# So, this isn't actually a nested array,
|
|
#+ but it's functionally similar.
|
|
|
|
echo "Current directory and date of last status change:"
|
|
echo "${SubArray[@]}"
|
|
|
|
exit 0</programlisting></para>
|
|
|
|
<para>--</para>
|
|
|
|
<para>Embedded arrays in combination with <link
|
|
linkend="varrefnew">indirect references</link> create some fascinating
|
|
possibilities</para>
|
|
|
|
<example id="embarr">
|
|
<title>Embedded arrays and indirect references</title>
|
|
<programlisting>&embarr;</programlisting>
|
|
</example>
|
|
|
|
<para>--</para>
|
|
|
|
<para>Arrays enable implementing a shell script version of the <emphasis>Sieve of
|
|
Eratosthenes</emphasis>. Of course, a resource-intensive application of this
|
|
nature should really be written in a compiled language, such as C. It
|
|
runs excruciatingly slowly as a script.</para>
|
|
|
|
<example id="ex68">
|
|
<title>Complex array application:
|
|
<emphasis>Sieve of Eratosthenes</emphasis></title>
|
|
<programlisting>&ex68;</programlisting>
|
|
</example>
|
|
|
|
<para>Compare this array-based prime number generator with an
|
|
alternative that does not use arrays, <xref linkend="primes">.</para>
|
|
|
|
<para>--</para>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
</chapter> <!-- Arrays -->
|
|
|
|
|
|
|
|
<chapter id="files">
|
|
<title>Files</title>
|
|
|
|
<variablelist id="filesref">
|
|
<title><anchor id="filesref1">startup files</title>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>These files contain the aliases and <link
|
|
linkend="envref">environmental variables</link>
|
|
made available to Bash running as a user shell and to all
|
|
Bash scripts invoked after system initialization.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><filename>/etc/profile</filename></term>
|
|
<listitem>
|
|
<para>systemwide defaults, mostly setting the environment
|
|
(all Bourne-type shells, not just Bash
|
|
<footnote><para>This does not apply to <command>csh</command>,
|
|
<command>tcsh</command>, and other shells not related to or
|
|
descended from the classic Bourne shell
|
|
(<command>sh</command>).</para></footnote>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><filename>/etc/bashrc</filename></term>
|
|
<listitem>
|
|
<para>systemwide functions and <link
|
|
linkend="aliasref">aliases</link> for Bash</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><filename><varname>$HOME</varname>/.bash_profile</filename></term>
|
|
<listitem>
|
|
<para>user-specific Bash environmental default settings,
|
|
found in each user's home directory (the local counterpart
|
|
to <filename>/etc/profile</filename>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><filename><varname>$HOME</varname>/.bashrc</filename></term>
|
|
<listitem>
|
|
<para>user-specific Bash init file, found in each user's home
|
|
directory (the local counterpart to
|
|
<filename>/etc/bashrc</filename>). Only interactive
|
|
shells and user scripts read this file. See
|
|
<xref linkend="sample-bashrc"> for a sample
|
|
<filename>.bashrc</filename> file.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="logoutfileref">
|
|
<title><anchor id="logoutfileref1">logout file</title>
|
|
<varlistentry>
|
|
<term><filename><varname>$HOME</varname>/.bash_logout</filename></term>
|
|
|
|
<listitem>
|
|
<para>user-specific instruction file, found in
|
|
each user's home directory. Upon exit from a login (Bash)
|
|
shell, the commands in this file execute.</para>
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
</chapter> <!-- Files -->
|
|
|
|
|
|
|
|
<chapter id="devproc">
|
|
<title>/dev and /proc</title>
|
|
|
|
<para><anchor id="devprocref"></para>
|
|
|
|
<para>A Linux or UNIX machine typically has the
|
|
<filename class="directory">/dev</filename> and
|
|
<filename class="directory">/proc</filename> special-purpose
|
|
directories.</para>
|
|
|
|
<sect1 id="devref1">
|
|
<title><filename class="directory">/dev</filename></title>
|
|
|
|
<para>The <filename class="directory">/dev</filename> directory
|
|
contains entries for the 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>,
|
|
and <filename>/dev/urandom</filename> are virtual. They
|
|
are not actual physical devices and exist only in
|
|
software.</para>
|
|
</footnote>
|
|
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
|
|
that allows an ordinary file to be accessed as if it were a
|
|
block device.
|
|
|
|
<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>, <link
|
|
linkend="urandomref"><filename>/dev/urandom</filename></link>,
|
|
<filename>/dev/sda1</filename>, <filename>/dev/udp</filename>,
|
|
and <filename>/dev/tcp</filename>.</para>
|
|
|
|
<para>For instance:</para>
|
|
|
|
<para>To <link linkend="mountref">mount</link> a USB flash drive,
|
|
append the following line to <filename>/etc/fstab</filename>.
|
|
|
|
<footnote>
|
|
<para>Of course, the mount point
|
|
<filename>/mnt/flashdrive</filename> must exist. If not,
|
|
then, as root, <command>mkdir /mnt/flashdrive</command>.</para>
|
|
<para>To actually mount the drive, use the following command:
|
|
<command>mount /mnt/flashdrive</command></para>
|
|
<para>Newer Linux distros automount flash drives in the
|
|
<filename class="directory">/media</filename> directory.</para>
|
|
</footnote>
|
|
|
|
<programlisting>/dev/sda1 /mnt/flashdrive auto noauto,user,noatime 0 0</programlisting>
|
|
|
|
(See also <xref linkend="usbinst">.)</para>
|
|
|
|
<para><anchor id="socketref"></para>
|
|
|
|
<para>When executing a command on a
|
|
<filename>/dev/tcp/$host/$port</filename> pseudo-device file, Bash
|
|
opens a TCP connection to the associated <emphasis>socket</emphasis>.
|
|
|
|
<footnote><para>A <emphasis>socket</emphasis> is a communications
|
|
node associated with a specific I/O port. It permits data
|
|
transfer between hardware devices on the same machine,
|
|
between machines on the same network, between machines
|
|
across different networks, and, of course, between machines
|
|
at different locations on the Internet.</para></footnote>
|
|
|
|
</para>
|
|
|
|
|
|
<para>Getting the time from <filename>nist.gov</filename>:</para>
|
|
<screen><prompt>bash$ </prompt><userinput>cat </dev/tcp/time.nist.gov/13</userinput>
|
|
<computeroutput>53082 04-03-18 04:26:54 68 0 0 502.3 UTC(NIST) *</computeroutput>
|
|
</screen>
|
|
|
|
<para>[Mark contributed the above example.]</para>
|
|
|
|
<para>Downloading a URL:</para>
|
|
<screen><prompt>bash$ </prompt><userinput>exec 5<>/dev/tcp/www.net.cn/80</userinput>
|
|
<prompt>bash$ </prompt><userinput>echo -e "GET / HTTP/1.0\n" >&5</userinput>
|
|
<prompt>bash$ </prompt><userinput>cat <&5</userinput>
|
|
</screen>
|
|
|
|
<para>[Thanks, Mark and Mihai Maties.]</para>
|
|
|
|
|
|
|
|
|
|
<example id="devtcp">
|
|
<title>Using <filename>/dev/tcp</filename> for troubleshooting</title>
|
|
<programlisting>&devtcp;</programlisting>
|
|
</example>
|
|
|
|
|
|
</sect1> <!-- /dev -->
|
|
|
|
|
|
|
|
<sect1 id="procref1">
|
|
<title><filename class="directory">/proc</filename></title>
|
|
|
|
|
|
<para>The <filename class="directory">/proc</filename> directory
|
|
is actually a pseudo-filesystem. The files in <filename
|
|
class="directory">/proc</filename> mirror currently running
|
|
system and kernel <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>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>cat /proc/interrupts</userinput>
|
|
<computeroutput> CPU0
|
|
0: 84505 XT-PIC timer
|
|
1: 3375 XT-PIC keyboard
|
|
2: 0 XT-PIC cascade
|
|
5: 1 XT-PIC soundblaster
|
|
8: 1 XT-PIC rtc
|
|
12: 4231 XT-PIC PS/2 Mouse
|
|
14: 109373 XT-PIC ide0
|
|
NMI: 0
|
|
ERR: 0</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>cat /proc/partitions</userinput>
|
|
<computeroutput>major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
|
|
|
|
3 0 3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030
|
|
3 1 52416 hda1 27 395 844 960 4 2 14 180 0 800 1140
|
|
3 2 1 hda2 0 0 0 0 0 0 0 0 0 0 0
|
|
3 4 165280 hda4 10 0 20 210 0 0 0 0 0 210 210
|
|
...</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>cat /proc/loadavg</userinput>
|
|
<computeroutput>0.13 0.42 0.27 2/44 1119</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>cat /proc/apm</userinput>
|
|
<computeroutput>1.16 1.2 0x03 0x01 0xff 0x80 -1% -1 ?</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Shell scripts may extract data from certain of the files in
|
|
<filename class="directory">/proc</filename>.
|
|
|
|
<footnote><para>Certain system commands, such as
|
|
<link linkend="procinforef">procinfo</link>,
|
|
<link linkend="freeref">free</link>,
|
|
<link linkend="vmstatref">vmstat</link>,
|
|
<link linkend="lsdevref">lsdev</link>,
|
|
and <link linkend="uptimeref">uptime</link>
|
|
do this as well.</para></footnote></para>
|
|
|
|
<para><programlisting>FS=iso # ISO filesystem support in kernel?
|
|
|
|
grep $FS /proc/filesystems # iso9660</programlisting></para>
|
|
|
|
|
|
<para><programlisting>kernel_version=$( awk '{ print $3 }' /proc/version )</programlisting></para>
|
|
|
|
<para><programlisting>CPU=$( awk '/model name/ {print $4}' < /proc/cpuinfo )
|
|
|
|
if [ $CPU = Pentium ]
|
|
then
|
|
run_some_commands
|
|
...
|
|
else
|
|
run_different_commands
|
|
...
|
|
fi</programlisting></para>
|
|
|
|
<para><programlisting>devfile="/proc/bus/usb/devices"
|
|
USB1="Spd=12"
|
|
USB2="Spd=480"
|
|
|
|
|
|
bus_speed=$(grep Spd $devfile | awk '{print $9}')
|
|
|
|
if [ "$bus_speed" = "$USB1" ]
|
|
then
|
|
echo "USB 1.1 port found."
|
|
# Do something appropriate for USB 1.1.
|
|
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>
|
|
|
|
</sect1> <!-- /proc -->
|
|
|
|
</chapter> <!-- /dev and /proc -->
|
|
|
|
|
|
|
|
<chapter id="zeros">
|
|
<title>Of Zeros and Nulls</title>
|
|
|
|
<para><anchor id="zerosref"></para>
|
|
|
|
<variablelist id="zeronull">
|
|
<title><anchor id="zeronull1"><filename>/dev/zero</filename>
|
|
and <filename>/dev/null</filename></title>
|
|
<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>
|
|
|
|
<para>Suppressing <filename>stdout</filename>.
|
|
<programlisting>cat $filename >/dev/null
|
|
# Contents of the file will not list to stdout.</programlisting>
|
|
</para>
|
|
|
|
<para>Suppressing <filename>stderr</filename>
|
|
(from <xref linkend="ex57">).
|
|
<programlisting>rm $badname 2>/dev/null
|
|
# So error messages [stderr] deep-sixed.</programlisting>
|
|
</para>
|
|
|
|
<para>Suppressing output from <emphasis>both</emphasis>
|
|
<filename>stdout</filename> and <filename>stderr</filename>.
|
|
<programlisting>cat $filename 2>/dev/null >/dev/null
|
|
# If "$filename" does not exist, there will be no error message output.
|
|
# If "$filename" does exist, the contents of the file will not list to stdout.
|
|
# Therefore, no output at all will result from the above line of code.
|
|
#
|
|
# This can be useful in situations where the return code from a command
|
|
#+ needs to be tested, but no output is desired.
|
|
#
|
|
# cat $filename &>/dev/null
|
|
# also works, as Baris Cicek points out.</programlisting>
|
|
</para>
|
|
|
|
<para>Deleting contents of a file, but preserving the file itself, with
|
|
all attendant permissions (from <xref linkend="ex1"> and <xref linkend="ex2">):
|
|
<programlisting>cat /dev/null > /var/log/messages
|
|
# : > /var/log/messages has same effect, but does not spawn a new process.
|
|
|
|
cat /dev/null > /var/log/wtmp</programlisting>
|
|
</para>
|
|
|
|
<para>Automatically emptying the contents of a logfile
|
|
(especially good for dealing with those nasty
|
|
<quote>cookies</quote> sent by 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>
|
|
<term><anchor id="zerosref1">Uses of <filename>/dev/zero</filename></term>
|
|
<listitem>
|
|
<para>Like <filename>/dev/null</filename>,
|
|
<filename>/dev/zero</filename> is a pseudo file, but
|
|
it actually produces a stream of nulls (binary zeros,
|
|
not the ASCII kind). Output written to it disappears,
|
|
and it is fairly difficult to actually read the nulls from
|
|
<filename>/dev/zero</filename>, though it can be done with
|
|
<link linkend="odref">od</link> or a hex editor. The chief
|
|
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>
|
|
is to <quote>zero out</quote> a file of a designated
|
|
size for a special purpose, such as mounting a filesystem
|
|
on a <link linkend="loopbackref">loopback device</link>
|
|
(see <xref linkend="createfs">) or <quote>securely</quote>
|
|
deleting a file (see <xref linkend="blotout">).</para>
|
|
|
|
<example id="ramdisk">
|
|
<title>Creating a ramdisk</title>
|
|
<programlisting>&ramdisk;</programlisting>
|
|
</example>
|
|
|
|
<para>In addition to all the above,
|
|
<filename>/dev/zero</filename> is needed by ELF binaries.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</chapter> <!-- Zeros and Nulls -->
|
|
|
|
|
|
|
|
<chapter id="debugging">
|
|
<title>Debugging</title>
|
|
|
|
<epigraph>
|
|
<attribution>Brian Kernighan</attribution>
|
|
<para>Debugging is twice as hard as writing the code in the first
|
|
place. Therefore, if you write the code as cleverly as possible,
|
|
you are, by definition, not smart enough to debug it.</para>
|
|
</epigraph>
|
|
|
|
<para>The Bash shell contains no debugger, nor even any
|
|
debugging-specific commands or constructs.
|
|
|
|
<footnote><para>Rocky Bernstein's
|
|
<ulink
|
|
url="http://bashdb.sourceforge.net"> Bash debugger</ulink>
|
|
partially makes up for this lack.</para></footnote>
|
|
|
|
Syntax errors or outright typos in the script generate cryptic
|
|
error messages that are often of no help in debugging a
|
|
non-functional script.</para>
|
|
|
|
<example id="ex74">
|
|
<title>A buggy script</title>
|
|
<programlisting>&ex74;</programlisting>
|
|
</example>
|
|
|
|
<para>Output from script:
|
|
<screen><computeroutput>./ex74.sh: [37: command not found</computeroutput></screen>
|
|
What's wrong with the above script (hint: after the
|
|
<command>if</command>)?</para>
|
|
|
|
<example id="missingkeyword">
|
|
<title>Missing <link linkend="keywordref">keyword</link></title>
|
|
<programlisting>&missingkeyword;</programlisting>
|
|
</example>
|
|
|
|
<para>Output from script:
|
|
<screen>
|
|
<computeroutput>missing-keyword.sh: line 10: syntax error: unexpected end of file</computeroutput>
|
|
</screen>
|
|
Note that the error message does <emphasis>not</emphasis> necessarily
|
|
reference the line in which the error occurs, but the line where the
|
|
Bash interpreter finally becomes aware of the error.
|
|
</para>
|
|
|
|
<para>Error messages may disregard comment lines in a script when
|
|
reporting the line number of a syntax error.</para>
|
|
|
|
<para>What if the script executes, but does not work as expected? This is the
|
|
all too familiar logic error.</para>
|
|
|
|
<example id="ex75">
|
|
<title>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>
|
|
<para>It bombs with a <quote><errorname>syntax error</errorname></quote> message, or</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>It runs, but does not work as expected
|
|
(<errorname>logic error</errorname>).</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>It runs, works as expected, but has nasty side effects
|
|
(<errorname>logic bomb</errorname>).</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<para>Tools for debugging non-working scripts include
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>echo statements at critical points in the script to
|
|
trace the variables, and otherwise give a snapshot of what
|
|
is going on.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>using the <link linkend="teeref">tee</link> filter
|
|
to check processes or data flows at critical points.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>setting option flags <option>-n -v -x</option></para>
|
|
|
|
<para><userinput>sh -n scriptname</userinput> checks for
|
|
syntax errors without actually running the script. This is
|
|
the equivalent of inserting <userinput>set -n</userinput> or
|
|
<userinput>set -o noexec</userinput> into the script. Note
|
|
that certain types of syntax errors can slip past this
|
|
check.</para>
|
|
|
|
<para><userinput>sh -v scriptname</userinput> echoes each
|
|
command before executing it. This is the equivalent of
|
|
inserting <userinput>set -v</userinput> or <userinput>set
|
|
-o verbose</userinput> in the script.</para>
|
|
|
|
<para>The <option>-n</option> and <option>-v</option>
|
|
flags work well together. <userinput>sh -nv
|
|
scriptname</userinput> gives a verbose syntax check.</para>
|
|
|
|
<para><userinput>sh -x scriptname</userinput> echoes the result each
|
|
command, but in an abbreviated manner. This is the equivalent of
|
|
inserting <userinput>set -x</userinput> or
|
|
<userinput>set -o xtrace</userinput> in the script.</para>
|
|
|
|
<para>Inserting <userinput>set -u</userinput> or
|
|
<userinput>set -o nounset</userinput> in the script runs it, but
|
|
gives an <errorname>unbound variable</errorname> error message
|
|
at each attempt to use an undeclared variable.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>Using an <quote>assert</quote> function to test a
|
|
variable or condition at critical points in a script. (This is
|
|
an idea borrowed from C.)</para>
|
|
|
|
<example id="assert">
|
|
<title>Testing a condition with an <quote>assert</quote></title>
|
|
<programlisting>&assert;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para>trapping at exit.</para>
|
|
|
|
<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>
|
|
|
|
<variablelist id="trapref">
|
|
<title><anchor id="trapref1">Trapping signals</title>
|
|
|
|
<varlistentry>
|
|
<term><command>trap</command></term>
|
|
<listitem>
|
|
<para>Specifies an action on receipt of a signal; also
|
|
useful for debugging.
|
|
|
|
<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>
|
|
|
|
|
|
<para>Of course, the <command>trap</command> command has other uses
|
|
aside from debugging.</para>
|
|
|
|
<example id="multipleproc">
|
|
<title>Running multiple processes (on an SMP box)</title>
|
|
<programlisting>&multipleproc;</programlisting>
|
|
</example>
|
|
|
|
|
|
<note><para><userinput>trap '' SIGNAL</userinput> (two adjacent
|
|
apostrophes) disables SIGNAL for the remainder of the
|
|
script. <userinput>trap SIGNAL</userinput> restores
|
|
the functioning of SIGNAL once more. This is useful to
|
|
protect a critical portion of a script from an undesirable
|
|
interrupt.</para></note>
|
|
|
|
<para><programlisting>
|
|
trap '' 2 # Signal 2 is Control-C, now disabled.
|
|
command
|
|
command
|
|
command
|
|
trap 2 # Reenables Control-C
|
|
</programlisting></para>
|
|
|
|
<sidebar>
|
|
<para><link linkend="bash3ref">Version 3</link> of Bash adds the
|
|
following special variables for use by the debugger.
|
|
|
|
<orderedlist>
|
|
<listitem><para>$BASH_ARGC</para></listitem>
|
|
<listitem><para>$BASH_ARGV</para></listitem>
|
|
<listitem><para>$BASH_COMMAND</para></listitem>
|
|
<listitem><para>$BASH_EXECUTION_STRING</para></listitem>
|
|
<listitem><para>$BASH_LINENO</para></listitem>
|
|
<listitem><para>$BASH_SOURCE</para></listitem>
|
|
<listitem><para><link linkend="bashsubshellref">$BASH_SUBSHELL</link></para></listitem>
|
|
</orderedlist></para>
|
|
</sidebar>
|
|
|
|
</chapter> <!-- Debugging -->
|
|
|
|
|
|
|
|
<chapter id="options">
|
|
<title>Options</title>
|
|
|
|
<para><anchor id="optionsref"></para>
|
|
|
|
<para>Options are settings that change shell and/or script
|
|
behavior.</para>
|
|
|
|
<para>The <link linkend="setref">set</link> command
|
|
enables options within a script. At the point in the script
|
|
where you want the options to take effect, use <command>set
|
|
-o option-name</command> or, in short form, <command>set
|
|
-option-abbrev</command>. These two forms are equivalent.</para>
|
|
|
|
<para><programlisting>
|
|
#!/bin/bash
|
|
|
|
set -o verbose
|
|
# Echoes all commands before executing.
|
|
</programlisting></para>
|
|
|
|
<para><programlisting>
|
|
#!/bin/bash
|
|
|
|
set -v
|
|
# Exact same effect as above.
|
|
</programlisting></para>
|
|
|
|
<note><para>To <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><anchor id="invocationoptionsref"></para>
|
|
<para>It is also possible to enable script options from the command
|
|
line. Some options that will not work with
|
|
<command>set</command> are available this way. Among these
|
|
are <replaceable>-i</replaceable>, force script to run
|
|
interactive.</para>
|
|
|
|
<para><userinput>bash -v script-name</userinput></para>
|
|
|
|
<para><userinput>bash -o verbose script-name</userinput></para>
|
|
|
|
|
|
<para>The following is a listing of some useful options. They may be
|
|
specified in either abbreviated form (preceded by a single dash)
|
|
or by complete name (preceded by a <emphasis>double</emphasis>
|
|
dash or by <option>-o</option>).</para>
|
|
|
|
<table>
|
|
<title>Bash options</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Abbreviation</entry>
|
|
<entry>Name</entry>
|
|
<entry>Effect</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><anchor id="noclobberref"><option>-C</option></entry>
|
|
<entry>noclobber</entry>
|
|
<entry>Prevent overwriting of files by redirection (may be
|
|
overridden by <token>>|</token>)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-D</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>List double-quoted strings prefixed by <token>$</token>,
|
|
but do not execute commands in script</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-a</option></entry>
|
|
<entry>allexport</entry>
|
|
<entry>Export all defined variables</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-b</option></entry>
|
|
<entry>notify</entry>
|
|
<entry>Notify when jobs running in background terminate (not of
|
|
much use in a script)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-c ...</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>Read commands from <command>...</command></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-e</option></entry>
|
|
<entry>errexit</entry>
|
|
<entry>Abort script at first error, when a command
|
|
exits with non-zero status (except in <link
|
|
linkend="untilloopref">until</link> or <link
|
|
linkend="whileloopref">while loops</link>, <link
|
|
linkend="testconstructs1">if-tests</link>, <link
|
|
linkend="lcons1">list constructs</link>)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-f</option></entry>
|
|
<entry>noglob</entry>
|
|
<entry>Filename expansion (globbing) disabled</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-i</option></entry>
|
|
<entry>interactive</entry>
|
|
<entry>Script runs in <emphasis>interactive</emphasis> mode</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-n</option></entry>
|
|
<entry>noexec</entry>
|
|
<entry>Read commands in script, but do not execute them (syntax check)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-o Option-Name</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>Invoke the <emphasis>Option-Name</emphasis>
|
|
option</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-o posix</option></entry>
|
|
<entry>POSIX</entry>
|
|
<entry>Change the behavior of Bash, or invoked script, to
|
|
conform to <link linkend="posix2ref">POSIX</link>
|
|
standard.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-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>-s</option></entry>
|
|
<entry>stdin</entry>
|
|
<entry>Read commands from <filename>stdin</filename></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-t</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>Exit after first command</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-u</option></entry>
|
|
<entry>nounset</entry>
|
|
<entry>Attempt to use undefined variable
|
|
outputs error message, and forces an exit</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-v</option></entry>
|
|
<entry>verbose</entry>
|
|
<entry>Print each command to <filename>stdout</filename> before executing it</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-x</option></entry>
|
|
<entry>xtrace</entry>
|
|
<entry>Similar to <option>-v</option>, but expands commands</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>End of options flag. All other arguments
|
|
are <link linkend="posparamref">positional
|
|
parameters</link>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>--</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>Unset positional parameters.
|
|
If arguments given (<varname>-- arg1 arg2</varname>),
|
|
positional parameters set to arguments.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</chapter> <!-- Options -->
|
|
|
|
|
|
|
|
<chapter id="gotchas">
|
|
<title>Gotchas</title>
|
|
|
|
<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.
|
|
<programlisting>case=value0 # Causes problems.
|
|
23skidoo=value1 # Also problems.
|
|
# Variable names starting with a digit are reserved by the shell.
|
|
# Try _23skidoo=value1. Starting variables with an underscore is o.k.
|
|
|
|
# However... using just the underscore will not work.
|
|
_=25
|
|
echo $_ # $_ is a special variable set to last arg of last command.
|
|
|
|
xyz((!*=value2 # Causes severe problems.</programlisting>
|
|
</para>
|
|
|
|
<para>Using a hyphen or other reserved characters in a variable name (or
|
|
function name).
|
|
<programlisting>var-1=23
|
|
# Use 'var_1' instead.
|
|
|
|
function-whatever ()
|
|
# Use 'function_whatever ()' instead.</programlisting>
|
|
</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>
|
|
</para>
|
|
|
|
|
|
<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.
|
|
|
|
<programlisting>#!/bin/bash
|
|
|
|
echo "uninitialized_var = $uninitialized_var"
|
|
# uninitialized_var =</programlisting>
|
|
|
|
</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>
|
|
|
|
|
|
<para>Misusing <link linkend="scomparison1">string comparison</link>
|
|
operators.</para>
|
|
|
|
<example id="badop">
|
|
<title>Numerical and string comparison are not equivalent</title>
|
|
<programlisting>&badop;</programlisting>
|
|
</example>
|
|
|
|
|
|
<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> - | command2 # Trying to redirect error output of command1 into a pipe...
|
|
# ...will not work.
|
|
|
|
command1 2>& - | command2 # Also futile.
|
|
|
|
Thanks, S.C.</programlisting></para>
|
|
|
|
|
|
<para>Using Bash <link linkend="bash2ref">version 2+</link>
|
|
functionality may cause a bailout with error messages. Older
|
|
Linux machines may have version 1.XX of Bash as the default
|
|
installation.
|
|
<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>
|
|
|
|
|
|
<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>Using undocumented features in Bash turns out to be a
|
|
dangerous practice. In previous releases of this
|
|
book there were several scripts that depended on the
|
|
<quote>feature</quote> that, although the maximum value
|
|
of an <link linkend="exitstatusref">exit</link> or <link
|
|
linkend="returnref">return</link> value was 255, that limit
|
|
did not apply to <emphasis>negative</emphasis> integers.
|
|
Unfortunately, in version 2.05b and later, that loophole
|
|
disappeared. See <xref linkend="returntest">.</para>
|
|
|
|
<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.
|
|
<programlisting>#!/bin/bash
|
|
|
|
echo "Here"
|
|
|
|
unix2dos $0 # Script changes itself to DOS format.
|
|
chmod 755 $0 # Change back to execute permission.
|
|
# The 'unix2dos' command removes execute permission.
|
|
|
|
./$0 # Script tries to run itself again.
|
|
# But it won't work as a DOS file.
|
|
|
|
echo "There"
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
<para>A shell script headed by <userinput>#!/bin/sh</userinput>
|
|
will not run in full Bash-compatibility mode. Some Bash-specific
|
|
functions might be disabled. Scripts that need complete
|
|
access to all the Bash-specific extensions should start with
|
|
<userinput>#!/bin/bash</userinput>.</para>
|
|
|
|
<para><link linkend="indentedls">Putting whitespace in front of
|
|
the terminating limit string</link> of a <link
|
|
linkend="heredocref">here document</link> will cause unexpected
|
|
behavior in a script.</para>
|
|
|
|
<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 <link
|
|
linkend="subshellsref">subshell</link>, then attempting
|
|
to use those same variables outside the scope of the subshell will
|
|
result an unpleasant surprise.</para>
|
|
|
|
<example id="subpit">
|
|
<title>Subshell Pitfalls</title>
|
|
<programlisting>&subpit;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="badread0"></para>
|
|
<para><link linkend="piperef">Piping</link>
|
|
<command>echo</command> output to a <link
|
|
linkend="readref">read</link> may produce unexpected
|
|
results. In this scenario, the <command>read</command>
|
|
acts as if it were running in a subshell. Instead, use
|
|
the <link linkend="setref">set</link> command (as in <xref
|
|
linkend="setpos">).</para>
|
|
|
|
<example id="badread">
|
|
<title>Piping the output of <command>echo</command> to a <command>read</command></title>
|
|
<programlisting>&badread;</programlisting>
|
|
</example>
|
|
|
|
<para>In fact, as Anthony Richardson points out, piping to
|
|
<emphasis>any</emphasis> loop can cause a similar problem.</para>
|
|
|
|
<para>
|
|
<programlisting># Loop piping troubles.
|
|
# This example by Anthony Richardson,
|
|
#+ with addendum by Wilbert Berendsen.
|
|
|
|
|
|
foundone=false
|
|
find $HOME -type f -atime +30 -size 100k |
|
|
while true
|
|
do
|
|
read f
|
|
echo "$f is over 100KB and has not been accessed in over 30 days"
|
|
echo "Consider moving the file to archives."
|
|
foundone=true
|
|
# ------------------------------------
|
|
echo "Subshell level = $BASH_SUBSHELL"
|
|
# Subshell level = 1
|
|
# Yes, we're inside a subshell.
|
|
# ------------------------------------
|
|
done
|
|
|
|
# foundone will always be false here since it is
|
|
#+ set to true inside a subshell
|
|
if [ $foundone = false ]
|
|
then
|
|
echo "No files need archiving."
|
|
fi
|
|
|
|
# =====================Now, here is the correct way:=================
|
|
|
|
foundone=false
|
|
for f in $(find $HOME -type f -atime +30 -size 100k) # No pipe here.
|
|
do
|
|
echo "$f is over 100KB and has not been accessed in over 30 days"
|
|
echo "Consider moving the file to archives."
|
|
foundone=true
|
|
done
|
|
|
|
if [ $foundone = false ]
|
|
then
|
|
echo "No files need archiving."
|
|
fi
|
|
|
|
# ==================And here is another alternative==================
|
|
|
|
# Places the part of the script that reads the variables
|
|
#+ within a code block, so they share the same subshell.
|
|
# Thank you, W.B.
|
|
|
|
find $HOME -type f -atime +30 -size 100k | {
|
|
foundone=false
|
|
while read f
|
|
do
|
|
echo "$f is over 100KB and has not been accessed in over 30 days"
|
|
echo "Consider moving the file to archives."
|
|
foundone=true
|
|
done
|
|
|
|
if ! $foundone
|
|
then
|
|
echo "No files need archiving."
|
|
fi
|
|
}</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
A related problem occurs when trying to write the
|
|
<filename>stdout</filename> of a <command>tail -f</command>
|
|
piped to <link linkend="grepref">grep</link>.
|
|
<programlisting>tail -f /var/log/messages | grep "$ERROR_MSG" >> error.log
|
|
# The "error.log" file will not have anything written to it.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>--</para>
|
|
|
|
|
|
<para>Using <quote>suid</quote> commands within scripts is risky,
|
|
as it may compromise system security.
|
|
<footnote><para>Setting the <emphasis>suid</emphasis> permission on
|
|
the script itself has no effect.</para></footnote>
|
|
</para>
|
|
|
|
|
|
<para>Using shell scripts for CGI programming may be problematic. Shell
|
|
script variables are not <quote>typesafe</quote>, and this can cause
|
|
undesirable behavior as far as CGI is concerned. Moreover, it is
|
|
difficult to <quote>cracker-proof</quote> shell scripts.</para>
|
|
|
|
<para>Bash does not handle the <link linkend="doubleslashref">double slash
|
|
(<token>//</token>) string</link> correctly.</para>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
</chapter> <!-- Gotchas -->
|
|
|
|
|
|
|
|
<chapter id="scrstyle">
|
|
<title>Scripting With Style</title>
|
|
|
|
<para>Get into the habit of writing shell scripts in a structured and
|
|
systematic manner. Even <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>
|
|
|
|
|
|
<sect1 id="unofficialst">
|
|
<title>Unofficial Shell Scripting Stylesheet</title>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>Comment your code. This makes it easier for others to
|
|
understand (and appreciate), and easier for you to maintain.
|
|
<programlisting>PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}"
|
|
# It made perfect sense when you wrote it last year, but now it's a complete mystery.
|
|
# (From Antek Sawicki's "pw.sh" script.)</programlisting>
|
|
</para>
|
|
|
|
<para>Add descriptive headers to your scripts and functions.
|
|
<programlisting>#!/bin/bash
|
|
|
|
#************************************************#
|
|
# xyz.sh #
|
|
# written by Bozo Bozeman #
|
|
# July 05, 2001 #
|
|
# #
|
|
# Clean up project files. #
|
|
#************************************************#
|
|
|
|
E_BADDIR=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, $E_BADDIR if something went wrong. #
|
|
# --------------------------------------------------------- #
|
|
cleanup_pfiles ()
|
|
{
|
|
if [ ! -d "$1" ] # Test if target directory exists.
|
|
then
|
|
echo "$1 is not a directory."
|
|
return $E_BADDIR
|
|
fi
|
|
|
|
rm -f "$1"/*
|
|
return 0 # Success.
|
|
}
|
|
|
|
cleanup_pfiles $projectdir
|
|
|
|
exit 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.
|
|
if [ -f "$LOGFILE" ]
|
|
then
|
|
...
|
|
fi</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para>Choose descriptive names for variables and functions.
|
|
<programlisting>fl=`ls -al $dirname` # Cryptic.
|
|
file_listing=`ls -al $dirname` # Better.
|
|
|
|
|
|
MAXVAL=10 # All caps used for a script constant.
|
|
while [ "$index" -le "$MAXVAL" ]
|
|
...
|
|
|
|
|
|
E_NOTFOUND=75 # Uppercase for an errorcode,
|
|
# and name begins with "E_".
|
|
if [ ! -e "$filename" ]
|
|
then
|
|
echo "File $filename not found."
|
|
exit $E_NOTFOUND
|
|
fi
|
|
|
|
|
|
MAIL_DIRECTORY=/var/spool/mail/bozo # Uppercase for an environmental variable.
|
|
export MAIL_DIRECTORY
|
|
|
|
|
|
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.
|
|
# 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>
|
|
|
|
|
|
<para><emphasis>Ender</emphasis> suggests using the exit codes
|
|
in <filename>/usr/include/sysexits.h</filename> in shell
|
|
scripts, though these are primarily intended for C and C++
|
|
programming.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
|
<para>Use standardized parameter flags for script invocation.
|
|
<emphasis>Ender</emphasis> proposes the following set
|
|
of flags.</para>
|
|
|
|
<para>
|
|
<programlisting>-a All: Return all information (including hidden file info).
|
|
-b Brief: Short version, usually for other scripts.
|
|
-c Copy, concatenate, etc.
|
|
-d Daily: Use information from the whole day, and not merely
|
|
information for a specific instance/user.
|
|
-e Extended/Elaborate: (often does not include hidden file info).
|
|
-h Help: Verbose usage w/descs, aux info, discussion, help.
|
|
See also -V.
|
|
-l Log output of script.
|
|
-m Manual: Launch man-page for base command.
|
|
-n Numbers: Numerical data only.
|
|
-r Recursive: All files in a directory (and/or all sub-dirs).
|
|
-s Setup & File Maintenance: Config files for this script.
|
|
-u Usage: List of invocation flags for the script.
|
|
-v Verbose: Human readable output, more or less formatted.
|
|
-V Version / License / Copy(right|left) / Contribs (email too).</programlisting>
|
|
</para>
|
|
|
|
<para>See also <xref linkend="standard-options">.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para>Break complex scripts into simpler modules. Use functions
|
|
where appropriate. See <xref linkend="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>
|
|
|
|
|
|
<epigraph>
|
|
<attribution>Landon Noll</attribution>
|
|
<para>... reading the UNIX source code to the Bourne shell (/bin/sh). I
|
|
was shocked at how much simple algorithms could be made cryptic, and
|
|
therefore useless, by a poor choice of code style. I asked myself,
|
|
<quote>Could someone be proud of this code?</quote></para>
|
|
</epigraph>
|
|
|
|
</sect1> <!-- Unofficial Shell Scripting Stylesheet -->
|
|
|
|
|
|
</chapter> <!-- Scripting With Style -->
|
|
|
|
|
|
|
|
<chapter id="miscellany">
|
|
<title>Miscellany</title>
|
|
|
|
<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>
|
|
|
|
<sect1 id="intandnonint">
|
|
<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 <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
|
|
;;
|
|
# (Courtesy of "UNIX F.A.Q.," 1993)</programlisting></para>
|
|
|
|
|
|
<note><para>Scripts may be forced to run in interactive
|
|
mode with the <token>-i</token> option or with a
|
|
<userinput>#!/bin/bash -i</userinput> header. Be aware that
|
|
this can cause erratic script behavior or show error messages
|
|
even when no error is present.</para></note>
|
|
|
|
|
|
</sect1> <!-- Interactive and non-interactive scripts -->
|
|
|
|
|
|
<sect1 id="wrapper">
|
|
<title>Shell Wrappers</title>
|
|
|
|
<para><anchor id="shwrapper"></para>
|
|
|
|
<para>A <quote>wrapper</quote> is a shell script that embeds
|
|
a system command or utility, that saves a set of parameters
|
|
passed to that command.
|
|
|
|
<footnote><para>Quite a number of Linux utilities are, in fact,
|
|
shell wrappers. Some examples are
|
|
<filename>/usr/bin/pdf2ps</filename>,
|
|
<filename>/usr/bin/batch</filename>, and
|
|
<filename>/usr/X11R6/bin/xmkmf</filename>.</para></footnote>
|
|
|
|
Wrapping a script around a complex command line
|
|
simplifies invoking it. This is expecially useful
|
|
with <link linkend="sedref">sed</link> and <link
|
|
linkend="awkref">awk</link>.</para>
|
|
|
|
<para>A
|
|
<command>
|
|
<indexterm>
|
|
<primary>sed</primary>
|
|
</indexterm> <indexterm>
|
|
<primary>script</primary> <secondary>sed</secondary>
|
|
</indexterm> sed</command> or
|
|
<command>
|
|
<indexterm>
|
|
<primary>awk</primary>
|
|
</indexterm> <indexterm>
|
|
<primary>script</primary> <secondary>awk</secondary>
|
|
</indexterm>
|
|
awk</command> script would normally be invoked
|
|
from the command line by a <userinput>sed -e
|
|
<replaceable>'commands'</replaceable></userinput>
|
|
or <userinput>awk
|
|
<replaceable>'commands'</replaceable></userinput>. Embedding
|
|
such a script in a Bash script permits calling it more simply,
|
|
and makes it <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="loggingwrapper">
|
|
<title> A generic <command>shell wrapper</command> that writes to a logfile</title>
|
|
<programlisting>&loggingwrapper;</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 -->
|
|
|
|
|
|
<sect1 id="testsandcomparisons">
|
|
<title>Tests and Comparisons: Alternatives</title>
|
|
|
|
<para>For tests, the <link linkend="dblbrackets">[[ ]]</link>
|
|
construct may be more appropriate than <userinput>[
|
|
]</userinput>. Likewise, 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>
|
|
|
|
</sect1> <!-- Tests and Comparisons: Alternatives -->
|
|
|
|
|
|
<sect1 id="recursionsct">
|
|
<title>Recursion</title>
|
|
|
|
<para>Can a script <link linkend="recursionref">recursively</link>
|
|
call itself? Indeed.</para>
|
|
|
|
<example id="recurse">
|
|
<title>A (useless) script that recursively calls itself</title>
|
|
<programlisting>&recurse;</programlisting>
|
|
</example>
|
|
|
|
<example id="pbook">
|
|
<title>A (useful) script that recursively calls itself</title>
|
|
<programlisting>&pbook;</programlisting>
|
|
</example>
|
|
|
|
<example id="usrmnt">
|
|
<title>Another (useful) script that recursively calls itself</title>
|
|
<programlisting>&usrmnt;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>Too many levels of recursion can exhaust the
|
|
script's stack space, causing a segfault.</para></caution>
|
|
|
|
</sect1> <!-- Recursion -->
|
|
|
|
|
|
<sect1 id="colorizing">
|
|
<title><quote>Colorizing</quote> Scripts</title>
|
|
|
|
<para><anchor id="colorizingref"></para>
|
|
|
|
<para>The ANSI
|
|
<footnote><para><acronym>ANSI</acronym> is, of course, the
|
|
acronym for the American National Standards
|
|
Institute.</para></footnote>
|
|
escape sequences set screen attributes, such as bold
|
|
text, and color of foreground and background. <link
|
|
linkend="dosbatch1">DOS batch files</link> commonly used
|
|
ANSI escape codes for <emphasis>color</emphasis> output,
|
|
and so can Bash scripts.</para>
|
|
|
|
<example id="ex30a">
|
|
<title>A <quote>colorized</quote> address database</title>
|
|
<programlisting>&ex30a;</programlisting>
|
|
</example>
|
|
|
|
<example id="draw-box">
|
|
<title>Drawing a box</title>
|
|
<programlisting>&drawbox;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>The simplest, and perhaps most useful ANSI escape sequence is
|
|
bold text, <command>\033[1m ... \033[0m</command>. The
|
|
<token>\033</token> represents an <emphasis>escape</emphasis>,
|
|
the <quote>[1</quote> turns on the bold attribute, while the
|
|
<quote>[0</quote> switches it off. The <quote>m</quote> terminates
|
|
each term of the escape sequence.
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo -e "\033[1mThis is bold text.\033[0m"</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>A similar escape sequence switches on the underline
|
|
attribute (on an <emphasis>rxvt</emphasis> and an
|
|
<emphasis>aterm</emphasis>).
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo -e "\033[4mThis is underlined text.\033[0m"</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>With an <command>echo</command>, the
|
|
<option>-e</option> option enables the escape
|
|
sequences.</para></note>
|
|
|
|
<para>Other escape sequences change the text and/or background
|
|
color.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo -e '\E[34;47mThis prints in blue.'; tput sgr0</userinput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -e '\E[33;44m'"yellow text on blue background"; tput sgr0</userinput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -e '\E[1;33;44m'"BOLD yellow text on blue background"; tput sgr0</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>It's usually advisable to set the
|
|
<emphasis>bold</emphasis> attribute for light-colored foreground
|
|
text.</para></note>
|
|
|
|
<para>The <command>tput sgr0</command> restores the
|
|
terminal settings to normal. Omitting this lets all
|
|
subsequent output from that particular terminal remain
|
|
blue.</para>
|
|
|
|
<note><para>Since <command>tput sgr0</command> fails to restore
|
|
terminal settings under certain circumstances,
|
|
<command>echo -ne \E[0m</command> may be a better choice.</para></note>
|
|
|
|
<sidebar>
|
|
<para>Use the following template for writing colored text on a colored
|
|
background.</para>
|
|
|
|
<para>
|
|
<userinput>echo -e '\E[COLOR1;COLOR2mSome text goes here.'</userinput>
|
|
</para>
|
|
|
|
<para>The <quote>\E[</quote> begins the escape sequence.
|
|
The semicolon-separated numbers <quote>COLOR1</quote> and
|
|
<quote>COLOR2</quote> specify a foreground and a background
|
|
color, according to the table below. (The order of the
|
|
numbers does not matter, since the foreground and background
|
|
numbers fall in non-overlapping ranges.) The <quote>m</quote>
|
|
terminates the escape sequence, and the text begins immediately
|
|
after that.</para>
|
|
|
|
<para>Note also that <link linkend="snglquo">single quotes</link>
|
|
enclose the remainder of the command sequence following the
|
|
<command>echo -e</command>.</para>
|
|
</sidebar>
|
|
|
|
|
|
<para>The numbers in the following table work for an
|
|
<emphasis>rxvt</emphasis> terminal. Results may vary for other
|
|
terminal emulators.</para>
|
|
|
|
<table>
|
|
<title>Numbers representing colors in Escape Sequences</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Color</entry>
|
|
<entry>Foreground</entry>
|
|
<entry>Background</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>black</option></entry>
|
|
<entry>30</entry>
|
|
<entry>40</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>red</option></entry>
|
|
<entry>31</entry>
|
|
<entry>41</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>green</option></entry>
|
|
<entry>32</entry>
|
|
<entry>42</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>yellow</option></entry>
|
|
<entry>33</entry>
|
|
<entry>43</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>blue</option></entry>
|
|
<entry>34</entry>
|
|
<entry>44</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>magenta</option></entry>
|
|
<entry>35</entry>
|
|
<entry>45</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>cyan</option></entry>
|
|
<entry>36</entry>
|
|
<entry>46</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>white</option></entry>
|
|
<entry>37</entry>
|
|
<entry>47</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<example id="colorecho">
|
|
<title>Echoing colored text</title>
|
|
<programlisting>&colorecho;</programlisting>
|
|
</example>
|
|
|
|
<example id="horserace">
|
|
<title>A <quote>horserace</quote> game</title>
|
|
<programlisting>&horserace;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>There is, however, a major problem with all
|
|
this. <emphasis>ANSI escape sequences are emphatically
|
|
non-portable.</emphasis> What works fine on some terminal
|
|
emulators (or the console) may work differently, or not
|
|
at all, on others. A <quote>colorized</quote> script that
|
|
looks stunning on the script author's machine may produce
|
|
unreadable output on someone else's. This greatly compromises
|
|
the usefulness of <quote>colorizing</quote> scripts, and
|
|
possibly relegates this technique to the status of a gimmick
|
|
or even a <quote>toy</quote>.</para></caution>
|
|
|
|
<para>Moshe Jacobson's <command>color</command> utility
|
|
(<ulink
|
|
url="http://runslinux.net/projects.html#color">http://runslinux.net/projects.html#color</ulink>)
|
|
considerably simplifies using ANSI escape sequences. It
|
|
substitutes a clean and logical syntax for the clumsy constructs
|
|
just discussed.</para>
|
|
|
|
<para>Henry/teikedvl has likewise created a utility (<ulink
|
|
url="http://scriptechocolor.sourceforge.net/">http://scriptechocolor.sourceforge.net/</ulink>) to simplify creation of colorized scripts.</para>
|
|
|
|
|
|
</sect1> <!-- "Colorizing" scripts -->
|
|
|
|
|
|
|
|
<sect1 id="optimizations">
|
|
<title>Optimizations</title>
|
|
|
|
<para>Most shell scripts are quick 'n dirty solutions to non-complex
|
|
problems. As such, optimizing them for speed is not much of an
|
|
issue. Consider the case, though, where a script carries out
|
|
an important task, does it well, but runs too slowly. Rewriting
|
|
it in a compiled language may not be a palatable option. The
|
|
simplest fix would be to rewrite the parts of the script
|
|
that slow it down. Is it possible to apply principles of code
|
|
optimization even to a lowly shell script?</para>
|
|
|
|
<para>Check the loops in the script. Time consumed by repetitive
|
|
operations adds up quickly. If at all possible, remove
|
|
time-consuming operations from within loops.</para>
|
|
|
|
<para>Use <link linkend="builtinref">builtin</link> commands in
|
|
preference to system commands. Builtins execute faster and
|
|
usually do not launch a subshell when invoked.</para>
|
|
|
|
<para>Avoid unnecessary commands, particularly in a <link
|
|
linkend="piperef">pipe</link>.
|
|
<programlisting>cat "$file" | grep "$word"
|
|
|
|
grep "$word" "$file"
|
|
|
|
# The above command lines have an identical effect,
|
|
#+ but the second runs faster since it launches one fewer subprocess.</programlisting>
|
|
The <link linkend="catref">cat</link> command seems especially
|
|
prone to overuse in scripts.</para>
|
|
|
|
<para>Use the <link linkend="timref">time</link> and <link
|
|
linkend="timesref">times</link> tools to profile
|
|
computation-intensive commands. Consider rewriting time-critical
|
|
code sections in C, or even in assembler.</para>
|
|
|
|
<para>Try to minimize file I/O. Bash is not particularly
|
|
efficient at handling files, so consider using
|
|
more appropriate tools for this within the script,
|
|
such as <link linkend="awkref">awk</link> or <link
|
|
linkend="perlref">Perl</link>.</para>
|
|
|
|
<para>Write your scripts in a 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>
|
|
|
|
</sect1> <!-- Optimizations -->
|
|
|
|
|
|
<sect1 id="assortedtips">
|
|
<title>Assorted Tips</title>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>To keep a record of which user scripts have run
|
|
during a particular session or over a number of sessions,
|
|
add the following lines to each script you want to keep track
|
|
of. This will keep a continuing file record of the script
|
|
names and invocation times. </para>
|
|
|
|
<para>
|
|
<programlisting># Append (>>) following to end of each script tracked.
|
|
|
|
whoami>> $SAVE_FILE # User invoking the script.
|
|
echo $0>> $SAVE_FILE # Script name.
|
|
date>> $SAVE_FILE # Date and time.
|
|
echo>> $SAVE_FILE # Blank line as separator.
|
|
|
|
# Of course, SAVE_FILE defined and exported as environmental variable in ~/.bashrc
|
|
#+ (something like ~/.scripts-run)</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="prependref"></para>
|
|
<para>The <token>>></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>This is a simplified variant of the <xref
|
|
linkend="prependex"> script given earlier. And, of course,
|
|
<link linkend="sedref">sed</link> can also do this.</para>
|
|
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>A shell script may act as an embedded command inside
|
|
another shell script, a <emphasis>Tcl</emphasis> or
|
|
<emphasis>wish</emphasis> script, or even a <link
|
|
linkend="makefileref">Makefile</link>. It can be invoked
|
|
as an external shell command in a C program using the
|
|
<replaceable>system()</replaceable> call, i.e.,
|
|
<replaceable>system("script_name");</replaceable>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Put together files containing your favorite and most useful
|
|
definitions and functions. As necessary,
|
|
<quote>include</quote> one or more of these
|
|
<quote>library files</quote> in scripts with either the
|
|
<link linkend="dotref">dot</link> (<command>.</command>)
|
|
or <link linkend="sourceref">source</link> command.</para>
|
|
|
|
<para>
|
|
<programlisting># SCRIPT LIBRARY
|
|
# ------ -------
|
|
|
|
# Note:
|
|
# No "#!" here.
|
|
# No "live code" either.
|
|
|
|
|
|
# Useful variable definitions
|
|
|
|
ROOT_UID=0 # Root has $UID 0.
|
|
E_NOTROOT=101 # Not root user error.
|
|
MAXRETVAL=255 # Maximum (positive) return value of a function.
|
|
SUCCESS=0
|
|
FAILURE=-1
|
|
|
|
|
|
|
|
# Functions
|
|
|
|
Usage () # "Usage:" message.
|
|
{
|
|
if [ -z "$1" ] # No arg passed.
|
|
then
|
|
msg=filename
|
|
else
|
|
msg=$@
|
|
fi
|
|
|
|
echo "Usage: `basename $0` "$msg""
|
|
}
|
|
|
|
|
|
Check_if_root () # Check if root running script.
|
|
{ # From "ex39.sh" example.
|
|
if [ "$UID" -ne "$ROOT_UID" ]
|
|
then
|
|
echo "Must be root to run this script."
|
|
exit $E_NOTROOT
|
|
fi
|
|
}
|
|
|
|
|
|
CreateTempfileName () # Creates a "unique" temp filename.
|
|
{ # From "ex51.sh" example.
|
|
prefix=temp
|
|
suffix=`eval date +%s`
|
|
Tempfilename=$prefix.$suffix
|
|
}
|
|
|
|
|
|
isalpha2 () # Tests whether *entire string* is alphabetic.
|
|
{ # From "isalpha.sh" example.
|
|
[ $# -eq 1 ] || return $FAILURE
|
|
|
|
case $1 in
|
|
*[!a-zA-Z]*|"") return $FAILURE;;
|
|
*) return $SUCCESS;;
|
|
esac # Thanks, S.C.
|
|
}
|
|
|
|
|
|
abs () # Absolute value.
|
|
{ # Caution: Max return value = 255.
|
|
E_ARGERR=-999999
|
|
|
|
if [ -z "$1" ] # Need arg passed.
|
|
then
|
|
return $E_ARGERR # Obvious error value returned.
|
|
fi
|
|
|
|
if [ "$1" -ge 0 ] # If non-negative,
|
|
then #
|
|
absval=$1 # stays as-is.
|
|
else # Otherwise,
|
|
let "absval = (( 0 - $1 ))" # change sign.
|
|
fi
|
|
|
|
return $absval
|
|
}
|
|
|
|
|
|
tolower () # Converts string(s) passed as argument(s)
|
|
{ #+ to lowercase.
|
|
|
|
if [ -z "$1" ] # If no argument(s) passed,
|
|
then #+ send error message
|
|
echo "(null)" #+ (C-style void-pointer error message)
|
|
return #+ and return from function.
|
|
fi
|
|
|
|
echo "$@" | tr A-Z a-z
|
|
# Translate all passed arguments ($@).
|
|
|
|
return
|
|
|
|
# Use command substitution to set a variable to function output.
|
|
# For example:
|
|
# oldvar="A seT of miXed-caSe LEtTerS"
|
|
# newvar=`tolower "$oldvar"`
|
|
# echo "$newvar" # a set of mixed-case letters
|
|
#
|
|
# Exercise: Rewrite this function to change lowercase passed argument(s)
|
|
# to uppercase ... toupper() [easy].
|
|
}</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>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>A particularly clever use of <link
|
|
linkend="testconstructs1">if-test</link> constructs
|
|
is commenting out blocks of code.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
COMMENT_BLOCK=
|
|
# Try setting the above variable to some value
|
|
#+ for an unpleasant surprise.
|
|
|
|
if [ $COMMENT_BLOCK ]; then
|
|
|
|
Comment block --
|
|
=================================
|
|
This is a comment line.
|
|
This is another comment line.
|
|
This is yet another comment line.
|
|
=================================
|
|
|
|
echo "This will not echo."
|
|
|
|
Comment blocks are error-free! Whee!
|
|
|
|
fi
|
|
|
|
echo "No more comments, please."
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
<para>Compare this with <link linkend="cblock1">using
|
|
here documents to comment out code blocks</link>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Using the <link linkend="xstatvarref">$? exit status
|
|
variable</link>, a script may test if a parameter contains
|
|
only digits, so it can be treated as an integer.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
SUCCESS=0
|
|
E_BADINPUT=65
|
|
|
|
test "$1" -ne 0 -o "$1" -eq 0 2>/dev/null
|
|
# An integer is either equal to 0 or not equal to 0.
|
|
# 2>/dev/null suppresses error message.
|
|
|
|
if [ $? -ne "$SUCCESS" ]
|
|
then
|
|
echo "Usage: `basename $0` integer-input"
|
|
exit $E_BADINPUT
|
|
fi
|
|
|
|
let "sum = $1 + 25" # Would give error if $1 not integer.
|
|
echo "Sum = $sum"
|
|
|
|
# Any variable, not just a command line parameter, can be tested this way.
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="rvt">The 0 - 255 range for function return
|
|
values is a severe limitation. Global variables and
|
|
other workarounds are often problematic. An alternative
|
|
method for a function to communicate a value back to
|
|
the main body of the script is to have the function
|
|
write to <filename>stdout</filename> (usually with
|
|
<link linkend="echoref">echo</link>) the <quote>return
|
|
value,</quote> and assign this to a variable. This is
|
|
actually a variant of <link linkend="commandsubref">command
|
|
substitution.</link></para>
|
|
|
|
<example id="multiplication">
|
|
<title>Return value trickery</title>
|
|
<programlisting>&multiplication;</programlisting>
|
|
</example>
|
|
|
|
<para>The same technique also works for alphanumeric
|
|
strings. This means that a function can <quote>return</quote>
|
|
a non-numeric value.</para>
|
|
|
|
<para>
|
|
<programlisting>capitalize_ichar () # Capitalizes initial character
|
|
{ #+ of argument string(s) passed.
|
|
|
|
string0="$@" # Accepts multiple arguments.
|
|
|
|
firstchar=${string0:0:1} # First character.
|
|
string1=${string0:1} # Rest of string(s).
|
|
|
|
FirstChar=`echo "$firstchar" | tr a-z A-Z`
|
|
# Capitalize first character.
|
|
|
|
echo "$FirstChar$string1" # Output to stdout.
|
|
|
|
}
|
|
|
|
newstring=`capitalize_ichar "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>
|
|
|
|
<listitem>
|
|
<para>Using the double parentheses construct, it is possible
|
|
to use C-like syntax for setting and incrementing variables
|
|
and in <link linkend="forloopref1">for</link> and <link
|
|
linkend="whileloopref">while</link> loops. See <xref
|
|
linkend="forloopc"> and <xref linkend="whloopc">.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Setting the <link linkend="pathref">path</link> and <link
|
|
linkend="umaskref">umask</link> at the beginning of a script makes
|
|
it more <quote>portable</quote> -- more likely to run on a
|
|
<quote>foreign</quote> machine whose user may have bollixed up the
|
|
<varname>$PATH</varname> and <command>umask</command>.
|
|
<programlisting>#!/bin/bash
|
|
PATH=/bin:/usr/bin:/usr/local/bin ; export PATH
|
|
umask 022
|
|
|
|
# Thanks to Ian D. Allen, for this tip.</programlisting></para>
|
|
</listitem>
|
|
|
|
<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 are <link linkend="trref">tr</link> and
|
|
<link linkend="grepref">grep</link>.</para>
|
|
|
|
<para>
|
|
<programlisting># From "wstrings.sh" example.
|
|
|
|
wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \
|
|
tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '`</programlisting>
|
|
</para>
|
|
|
|
<example id="agram">
|
|
<title>Fun with anagrams</title>
|
|
<programlisting>&agram;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="constat">, <xref
|
|
linkend="cryptoquote">, and <xref linkend="soundex">.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Use <quote><link linkend="anonheredoc0">anonymous here
|
|
documents</link></quote> to comment out blocks of code,
|
|
to save having to individually comment out each line with
|
|
a <token>#</token>. See <xref linkend="commentblock">.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Running a script on a machine that relies on a command
|
|
that might not be installed is dangerous. Use <link
|
|
linkend="whatisref">whatis</link> to avoid potential problems
|
|
with this.</para>
|
|
|
|
<para>
|
|
<programlisting>CMD=command1 # First choice.
|
|
PlanB=command2 # Fallback option.
|
|
|
|
command_test=$(whatis "$CMD" | grep 'nothing appropriate')
|
|
# If 'command1' not found on system , 'whatis' will return
|
|
#+ "command1: nothing appropriate."
|
|
#
|
|
# A safer alternative is:
|
|
# command_test=$(whereis "$CMD" | grep \/)
|
|
# But then the sense of the following test would have to be reversed,
|
|
#+ since the $command_test variable holds content only if
|
|
#+ the $CMD exists on the system.
|
|
# (Thanks, bojster.)
|
|
|
|
|
|
if [[ -z "$command_test" ]] # Check whether command present.
|
|
then
|
|
$CMD option1 option2 # Run command1 with options.
|
|
else # Otherwise,
|
|
$PlanB #+ run command2.
|
|
fi</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>An <link linkend="ifgrepref">if-grep test</link> may not
|
|
return expected results in an error case, when text is output to
|
|
<filename>stderr</filename>, rather that
|
|
<filename>stdout</filename>.
|
|
<programlisting>if ls -l nonexistent_filename | grep -q 'No such file or directory'
|
|
then echo "File \"nonexistent_filename\" does not exist."
|
|
fi</programlisting></para>
|
|
|
|
<para><link linkend="ioredirref">Redirecting</link>
|
|
<filename>stderr</filename> to <filename>stdout</filename> fixes
|
|
this.
|
|
<programlisting>if ls -l nonexistent_filename 2>&1 | grep -q 'No such file or directory'
|
|
# ^^^^
|
|
then echo "File \"nonexistent_filename\" does not exist."
|
|
fi
|
|
|
|
# Thanks, Chris Martin, for pointing this out.</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para>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>
|
|
</listitem>
|
|
|
|
<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
|
|
be installed. Additionally, the <link
|
|
linkend="makefileref">Makefile</link> needs some judicious
|
|
editing before the package will build on a typical Linux
|
|
system. Finally, three of the six widgets offered do not work
|
|
(and, in fact, segfault).</para></caution>
|
|
|
|
|
|
<para><anchor id="dialogref"></para>
|
|
|
|
<para>The <emphasis>dialog</emphasis> family of tools offers a method
|
|
of calling <quote>dialog</quote> widgets from a shell script. The
|
|
original <command>dialog</command> utility works in a text
|
|
console, but its successors, <command>gdialog</command>,
|
|
<command>Xdialog</command>, and <command>kdialog</command>
|
|
use X-Windows-based widget sets.</para>
|
|
|
|
<example id="dialog">
|
|
<title><command>Widgets invoked from a shell script</command></title>
|
|
<programlisting>&dialog;</programlisting>
|
|
</example>
|
|
|
|
<para>For other methods of 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>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para>For doing multiple revisions on a complex script, use the
|
|
<emphasis>rcs</emphasis> Revision Control System package.</para>
|
|
|
|
<para> Among
|
|
other benefits of this is automatically updated ID
|
|
header tags. The <command>co</command> command in
|
|
<emphasis>rcs</emphasis> does a parameter replacement of
|
|
certain reserved key words, for example, replacing
|
|
<parameter>#$Id$</parameter> in a script with something like:
|
|
<programlisting>#$Id$</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
</sect1> <!-- Assorted Tips -->
|
|
|
|
|
|
<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.
|
|
<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
|
|
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 -->
|
|
|
|
|
|
<sect1 id="portabilityissues">
|
|
<title>Portability Issues</title>
|
|
|
|
<para>This book deals specifically with Bash scripting on
|
|
a GNU/Linux system. All the same, users of <command>sh</command>
|
|
and <command>ksh</command> will find much of value here.</para>
|
|
|
|
<para>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. Another alternative is to use a
|
|
<programlisting>#!/bin/sh</programlisting>
|
|
header in the script, rather than
|
|
<programlisting>#!/bin/bash</programlisting>
|
|
Note that <filename>/bin/sh</filename> is a <link
|
|
linkend="linkref">link</link> to <filename>/bin/bash</filename>
|
|
in Linux and certain other flavors of UNIX, and a script invoked
|
|
this way disables extended Bash functionality.</para>
|
|
|
|
<para>Most Bash scripts will run as-is under
|
|
<command>ksh</command>, and vice-versa, since Chet Ramey has
|
|
been busily porting <command>ksh</command> features to the
|
|
latest versions of Bash.</para>
|
|
|
|
<para>On a commercial UNIX machine, scripts using GNU-specific
|
|
features of standard commands may not work. This has become less
|
|
of a problem in the last few years, as the GNU utilities have
|
|
pretty much displaced their proprietary
|
|
counterparts even on <quote>big-iron</quote> UNIX.
|
|
<ulink url="http://linux.oreillynet.com/pub/a/linux/2002/02/28/caldera.html">Caldera's
|
|
release of the source</ulink> to many of the original UNIX
|
|
utilities has accelerated the trend.</para>
|
|
|
|
<para>Bash has certain features that the traditional Bourne shell
|
|
lacks. Among these are:
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>Certain extended <link
|
|
linkend="invocationoptionsref">invocation options</link></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><link linkend="commandsubref">Command substitution</link> using
|
|
<command>$( )</command> notation</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Certain <link linkend="stringmanip">string manipulation</link>
|
|
operations</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><link linkend="processsubref">Process substitution</link></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Bash-specific <link linkend="builtinref">builtins</link></para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>See the <ulink url="ftp://ftp.cwru.edu/pub/bash/FAQ">Bash
|
|
F.A.Q.</ulink> for a complete listing.</para>
|
|
|
|
</sect1> <!-- Portability Issues -->
|
|
|
|
|
|
<sect1 id="winscript">
|
|
<title>Shell Scripting Under Windows</title>
|
|
|
|
<para>Even users running <emphasis>that other</emphasis> OS can
|
|
run UNIX-like shell scripts, and therefore benefit
|
|
from many of the lessons of this book. The <ulink
|
|
url="http://sourceware.cygnus.com/cygwin/">
|
|
Cygwin</ulink> package from Cygnus and the <ulink
|
|
url="http://www.mkssoftware.com/">MKS utilities</ulink> from
|
|
Mortice Kern Associates add shell scripting capabilities to
|
|
Windows.</para>
|
|
|
|
<para>There have been intimations that a future release of Windows
|
|
will contain Bash-like command line scripting capabilities,
|
|
but that remains to be seen.</para>
|
|
|
|
</sect1> <!-- Shell Scripting Under Windows -->
|
|
|
|
</chapter> <!-- Miscellany -->
|
|
|
|
|
|
|
|
<chapter id="bash2">
|
|
<title>Bash, versions 2 and 3</title>
|
|
|
|
<sect1 id="bashver2">
|
|
<title>Bash, version2</title>
|
|
|
|
<para><anchor id="bash2ref"></para>
|
|
|
|
<para>The current version of <emphasis>Bash</emphasis>, the one
|
|
you have running on your machine, is version 2.xx.y or 3.xx.y.
|
|
<screen><prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
|
|
<computeroutput>2.05.b.0(1)-release</computeroutput>
|
|
</screen>
|
|
The version 2 update of the classic Bash scripting language added array
|
|
variables,
|
|
|
|
<footnote><para>Chet Ramey promises associative arrays (a Perl
|
|
feature) in a future Bash release. As of version 3, this has not yet
|
|
happened.</para></footnote>
|
|
|
|
string and parameter expansion, and a better method
|
|
of indirect variable references, among other features.</para>
|
|
|
|
<example id="ex77">
|
|
<title>String expansion</title>
|
|
<programlisting>&ex77;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="varrefnew"></para>
|
|
<example id="ex78">
|
|
<title>Indirect variable references - the new way</title>
|
|
<programlisting>&ex78;</programlisting>
|
|
</example>
|
|
|
|
<example id="resistor">
|
|
<title>Simple database application, using indirect variable
|
|
referencing</title>
|
|
<programlisting>&resistor;</programlisting>
|
|
</example>
|
|
|
|
<example id="ex79">
|
|
<title>Using arrays and other miscellaneous trickery
|
|
to deal four random hands from a deck of cards</title>
|
|
<programlisting>&ex79;</programlisting>
|
|
</example>
|
|
|
|
</sect1> <!-- Bash, Version 2 -->
|
|
|
|
|
|
|
|
<sect1 id="bashver3">
|
|
<title>Bash, version3</title>
|
|
|
|
<para><anchor id="bash3ref"></para>
|
|
|
|
<para>On July 27, 2004, Chet Ramey released version 3 of Bash. This
|
|
update fixes quite a number of bug in Bash and adds some new
|
|
features.</para>
|
|
|
|
<para>Some of the added features are:
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>A new, more generalized <command>{a..z}</command> <link
|
|
linkend="braceexpref">brace expansion</link> operator.
|
|
<programlisting>#!/bin/bash
|
|
|
|
for i in {1..10}
|
|
# Simpler and more straightforward than
|
|
#+ for i in $(seq 10)
|
|
do
|
|
echo -n "$i "
|
|
done
|
|
|
|
echo
|
|
|
|
# 1 2 3 4 5 6 7 8 9 10
|
|
</programlisting>
|
|
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <command>${!array[@]}</command> operator, which
|
|
expands to all the indices of a given <link
|
|
linkend="arrayref">array</link>.
|
|
<programlisting>#!/bin/bash
|
|
|
|
Array=(element-zero element-one element-two element-three)
|
|
|
|
echo ${Array[0]} # element-zero
|
|
# First element of array.
|
|
|
|
echo ${!Array[@]} # 0 1 2 3
|
|
# All the indices of Array.
|
|
|
|
for i in ${!Array[@]}
|
|
do
|
|
echo ${Array[i]} # element-zero
|
|
# element-one
|
|
# element-two
|
|
# element-three
|
|
#
|
|
# All the elements in Array.
|
|
done</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <command>=~</command> <link linkend="regexref">Regular
|
|
Expression</link> matching operator within a <link
|
|
linkend="dblbrackets">double brackets</link> test expression.
|
|
(Perl has a similar operator.)
|
|
<programlisting>#!/bin/bash
|
|
|
|
variable="This is a fine mess."
|
|
|
|
echo "$variable"
|
|
|
|
if [[ "$variable" =~ "T*fin*es*" ]]
|
|
# Regex matching with =~ operator within [[ double brackets ]].
|
|
then
|
|
echo "match found"
|
|
# match found
|
|
fi</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
</para>
|
|
|
|
|
|
</sect1> <!-- Bash, Version 3 -->
|
|
|
|
|
|
</chapter> <!-- Bash, versions 2 and 3 -->
|
|
|
|
</part> <!-- Part 4 (Advanced Topics) -->
|
|
|
|
|
|
|
|
<chapter id="endnotes">
|
|
<title>Endnotes</title>
|
|
|
|
|
|
<sect1 id="authorsnote">
|
|
<title>Author's Note</title>
|
|
|
|
<epigraph>
|
|
<para>doce ut discas</para>
|
|
<para>(Teach, that you yourself may learn.)</para>
|
|
</epigraph>
|
|
|
|
|
|
<para>How did I come to write a Bash scripting book? It's a strange
|
|
tale. It seems that a 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 <emphasis>this very book</emphasis>,
|
|
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>
|
|
|
|
<para>This reminds me of the apocryphal story about the mad
|
|
professor. Crazy as a loon, the fellow was. At the sight of a
|
|
book, any book -- at the library, at a bookstore, anywhere --
|
|
he would become totally obsessed with the idea that he could have
|
|
written it, should have written it -- and done a better job of it
|
|
to boot. He would thereupon rush home and proceed to do just that,
|
|
write a book with the very same title. When he died some years
|
|
later, he allegedly had several thousand books to his credit,
|
|
probably putting even Asimov to shame. The books might not have
|
|
been any good -- who knows -- but does that really matter? Here's
|
|
a fellow who lived his dream, even if he was obsessed by it,
|
|
driven by it . . . and somehow I can't help admiring the old
|
|
coot.</para>
|
|
|
|
</sect1> <!-- Author's Note -->
|
|
|
|
|
|
<sect1 id="aboutauthor">
|
|
<title>About the Author</title>
|
|
<subtitle>Who is this guy anyhow?</subtitle>
|
|
|
|
<para>The author claims no credentials or special qualifications,
|
|
other than a compulsion to write.
|
|
<footnote><para>Those who can, do. Those who can't... get an
|
|
MCSE.</para></footnote>
|
|
This book is somewhat of a departure from his other major work,
|
|
<ulink url="http://personal.riverusers.com/~thegrendel/hmw50.zip">
|
|
HOW-2 Meet Women: The Shy Man's Guide to
|
|
Relationships</ulink>. He has also written the <ulink
|
|
url="http://tldp.org/HOWTO/Software-Building-HOWTO.html">Software-Building
|
|
HOWTO</ulink>. Lately, he has been trying his hand at short fiction.</para>
|
|
|
|
<para>A Linux user since 1995 (Slackware 2.2, kernel 1.2.1),
|
|
the author has emitted a few
|
|
software truffles, including the <ulink
|
|
url="http://ibiblio.org/pub/Linux/utils/file/cruft-0.2.tar.gz">cruft</ulink>
|
|
one-time pad encryption utility, the <ulink
|
|
url="http://ibiblio.org/pub/Linux/apps/financial/mcalc-1.6.tar.gz">mcalc</ulink>
|
|
mortgage calculator, the <ulink
|
|
url="http://ibiblio.org/pub/Linux/games/amusements/judge-1.0.tar.gz">judge</ulink>
|
|
Scrabble® adjudicator, and the <ulink
|
|
url="http://ibiblio.org/pub/Linux/libs/yawl-0.3.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 -->
|
|
|
|
|
|
|
|
<sect1 id="wherehelp">
|
|
<title>Where to Go For Help</title>
|
|
|
|
<para><ulink url="mailto:thegrendel@theriver.com">The author</ulink>
|
|
will usually, if not too busy (and in a good mood),
|
|
answer general scripting questions. However, if
|
|
you have a problem getting a specific script to
|
|
work, you would be well advised to post to the <ulink
|
|
url="news:comp.unix.shell">comp.os.unix.shell</ulink> Usenet
|
|
newsgroup.</para>
|
|
|
|
</sect1> <!-- Where to Go For Help -->
|
|
|
|
|
|
|
|
<sect1 id="toolsused">
|
|
<title>Tools Used to Produce This Book</title>
|
|
|
|
|
|
<sect2 id="software-hardware">
|
|
<title>Hardware</title>
|
|
|
|
<para>A used IBM Thinkpad, model 760XL laptop (P166, 104 meg RAM)
|
|
running Red Hat 7.1/7.3. Sure, it's slow and has a funky
|
|
keyboard, but it beats the heck out of a No. 2 pencil and a
|
|
Big Chief tablet.</para>
|
|
|
|
</sect2> <!-- Hardware -->
|
|
|
|
|
|
<sect2 id="software-printware">
|
|
<title>Software and Printware</title>
|
|
|
|
<orderedlist id="software-printware2" numeration="lowerroman">
|
|
|
|
<listitem>
|
|
<para>Bram Moolenaar's powerful SGML-aware <ulink
|
|
url="http://www.vim.org">vim</ulink> text editor.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><ulink
|
|
url="http://www.netfolder.com/DSSSL/">OpenJade</ulink>,
|
|
a DSSSL rendering engine for converting SGML documents into other
|
|
formats.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><ulink url="http://nwalsh.com/docbook/dsssl/"> Norman
|
|
Walsh's DSSSL stylesheets</ulink>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><citetitle pubwork="book">DocBook, The Definitive Guide</citetitle>, by Norman
|
|
Walsh and Leonard Muellner (O'Reilly, ISBN 1-56592-580-7). This is
|
|
the standard reference for anyone attempting to write a document in
|
|
Docbook SGML format.</para>
|
|
</listitem>
|
|
|
|
</orderedlist>
|
|
|
|
</sect2> <!-- Software and Printware -->
|
|
|
|
</sect1> <!-- Tools Used -->
|
|
|
|
|
|
<sect1 id="credits">
|
|
<title>Credits</title>
|
|
|
|
<para>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
|
|
beaucoup!</para>
|
|
|
|
<para>Paulo Marcel Coelho Aragao offered many corrections, both major
|
|
and minor, and contributed quite a number of helpful
|
|
suggestions.</para>
|
|
|
|
<para>I would like to especially thank <emphasis>Patrick
|
|
Callahan</emphasis>, <emphasis>Mike Novak</emphasis>, and
|
|
<emphasis>Pal Domokos</emphasis> for catching bugs, pointing out
|
|
ambiguities, and for suggesting clarifications and changes.
|
|
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@fiwix.org">Jordi Sanfeliu</ulink>
|
|
for giving permission to use his fine tree script (<xref
|
|
linkend="tree">), and to Rick Boivie for revising it.</para>
|
|
|
|
<para>Likewise, thanks to <ulink
|
|
url="mailto:charpov@cs.unh.edu">Michel Charpentier</ulink> for
|
|
permission to use his <link linkend="dcref">dc</link> factoring script
|
|
(<xref linkend="factr">).</para>
|
|
|
|
<para>Kudos to <ulink
|
|
url="mailto:friedman@prep.ai.mit.edu">Noah Friedman</ulink>
|
|
for permission to use his string function script (<xref
|
|
linkend="string">).</para>
|
|
|
|
<para><ulink url="mailto:emmanuel.rouat@wanadoo.fr">Emmanuel
|
|
Rouat</ulink> suggested corrections and additions on
|
|
<link linkend="commandsubref">command substitution</link> and
|
|
<link linkend="aliasref">aliases</link>. He also contributed
|
|
a very nice sample <filename>.bashrc</filename> file (<xref
|
|
linkend="sample-bashrc">).</para>
|
|
|
|
<para><ulink url="mailto:heiner.steven@odn.de">Heiner Steven</ulink>
|
|
kindly gave permission to use his base conversion script, <xref
|
|
linkend="base">. He also made a number of corrections and many
|
|
helpful suggestions. Special thanks.</para>
|
|
|
|
<para>Rick Boivie contributed the delightfully recursive
|
|
<emphasis>pb.sh</emphasis> script (<xref linkend="pbook">),
|
|
revised the <emphasis>tree.sh</emphasis> script (<xref
|
|
linkend="tree">), and suggested performance improvements
|
|
for the <emphasis>monthlypmt.sh</emphasis> script (<xref
|
|
linkend="monthlypmt">).</para>
|
|
|
|
<para>Florian Wisser enlightened me on some of the fine points of
|
|
testing strings (see <xref linkend="strtest">), and on other
|
|
matters.</para>
|
|
|
|
<para>Oleg Philon sent suggestions concerning <link
|
|
linkend="cutref">cut</link> and <link
|
|
linkend="pidofref">pidof</link>.</para>
|
|
|
|
<para>Michael Zick extended the <link linkend="emptyarray">empty
|
|
array</link> example to demonstrate some surprising array
|
|
properties. He also provided other examples of this.</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>
|
|
|
|
<para>Andreas Abraham sent in a long list of typographical
|
|
errors and other corrections. Special thanks!</para>
|
|
|
|
<para>Others contributing scripts, making helpful suggestions, and
|
|
pointing out errors were Gabor Kiss, Leopold Toetsch, Peter
|
|
Tillier, Marcus Berglof, Tony Richardson, Nick Drage (script
|
|
ideas!), Rich Bartell, Jess Thrysoee, Adam Lazur, Bram Moolenaar,
|
|
Baris Cicek, Greg Keraunen, Keith Matthews, Sandro Magi, Albert
|
|
Reiner, Dim Segebart, Rory Winston, Lee Bigelow, Wayne Pollock,
|
|
<quote>jipe,</quote> <quote>Mark,</quote> <quote>bojster,</quote>
|
|
<quote>Ender</quote>, Emilio Conti, Ian. D. Allen, Arun
|
|
Giridhar, Dennis Leeuw, Dan Jacobson, Aurelio Marinho Jargas,
|
|
Edward Scholtz, Jean Helou, Chris Martin, Lee Maschmeyer, Bruno
|
|
Haible, Wilbert Berendsen, Sebastien Godard, Bjön Eriksson,
|
|
<quote>nyal,</quote> John MacDonald, Joshua Tschida, Troy Engel,
|
|
Manfred Schwarb, Amit Singh, Bill Gradwohl, David Lombard,
|
|
Jason Parker, Steve Parker, Bruce W. Clare, William Park, Vernia
|
|
Damiano, Mihai Maties, Jeremy Impson, Ken Fuchs, Frank Wang,
|
|
Sylvain Fourmanoit, Matthew Walker, Kenny Stauffer, Filip Moritz,
|
|
Andrzej Stefanski, Daniel Albers, Stefano Palmeri, Nils Radtke,
|
|
Jeroen Domburg, Alfredo Pironti, Phil Braham, Bruno de Oliveira
|
|
Schneider, <quote>Little Monster</quote> (Alexis), Linc Fessenden,
|
|
and David Lawyer (himself an author of four HOWTOs).</para>
|
|
|
|
<para>My gratitude to <ulink url="mailto:chet@po.cwru.edu">Chet
|
|
Ramey</ulink> and Brian Fox for writing <command>Bash</command>,
|
|
an elegant and powerful scripting tool.</para>
|
|
|
|
<para>Very special thanks to the hard-working volunteers at
|
|
the <ulink url="http://www.tldp.org">Linux Documentation
|
|
Project</ulink>. The LDP hosts a repository of Linux knowledge
|
|
and lore, and has, to a large extent, enabled the publication
|
|
of this book.</para>
|
|
|
|
<para>Thanks and appreciation to IBM, Novell, Red Hat, the <ulink
|
|
url="http://www.fsf.org">Free Software Foundation</ulink>, and
|
|
all the good people fighting the good fight to keep Open Source
|
|
software free and open.</para>
|
|
|
|
<para>Thanks most of all to my wife, Anita, for her encouragement and
|
|
emotional support.</para>
|
|
|
|
</sect1> <!-- Credits -->
|
|
|
|
</chapter> <!-- End Notes -->
|
|
|
|
|
|
|
|
<bibliography id="biblio">
|
|
<anchor id="biblioref">
|
|
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<editor><firstname>Peter</firstname><surname>Denning</surname></editor>
|
|
</authorgroup>
|
|
<title>Computers Under Attack: Intruders, Worms, and Viruses</title>
|
|
<publisher>
|
|
<publishername>ACM Press</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1990</year>
|
|
</copyright>
|
|
<isbn>0-201-53067-8</isbn>
|
|
<abstract><para>This compendium contains a couple of articles on
|
|
shell script viruses.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Ken</firstname><surname>Burtch</surname></author>
|
|
</authorgroup>
|
|
<title><ulink url="http://www.samspublishing.com/title/0672326426">Linux Shell Scripting with Bash</ulink></title>
|
|
<edition>1st edition</edition>
|
|
<publisher>
|
|
<publishername>Sams Publishing (Pearson)</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2004</year>
|
|
</copyright>
|
|
<isbn>0672326426</isbn>
|
|
<abstract><para>
|
|
Covers much of the same material as this guide. Dead tree
|
|
media does have its advantages, though.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Dale</firstname><surname>Dougherty</surname></author>
|
|
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
|
|
</authorgroup>
|
|
<title>Sed and Awk</title>
|
|
<edition>2nd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1997</year>
|
|
</copyright>
|
|
<isbn>1-156592-225-5</isbn>
|
|
<abstract><para>
|
|
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>Jeffrey</firstname><surname>Friedl</surname></author>
|
|
</authorgroup>
|
|
<title>Mastering Regular Expressions</title>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2002</year>
|
|
</copyright>
|
|
<isbn>0-596-00289-0</isbn>
|
|
<abstract><para>The best, all-around reference on <link
|
|
linkend="regexref">Regular Expressions</link>.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Aeleen</firstname><surname>Frisch</surname></author>
|
|
</authorgroup>
|
|
<title>Essential System Administration</title>
|
|
<edition>3rd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2002</year>
|
|
</copyright>
|
|
<isbn>0-596-00343-9</isbn>
|
|
<abstract><para>This excellent sys admin manual has a decent introduction to shell
|
|
scripting for sys administrators and does a nice job of explaining the
|
|
startup and initialization scripts. The long overdue third edition of this
|
|
classic has finally been released.</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>
|
|
|
|
<biblioentry id="mayerref">
|
|
<authorgroup>
|
|
<author><firstname>Herbert</firstname><surname>Mayer</surname></author>
|
|
</authorgroup>
|
|
<title>Advanced C Programming on the IBM PC</title>
|
|
<publisher>
|
|
<publishername>Windcrest Books</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1989</year>
|
|
</copyright>
|
|
<isbn>0830693637</isbn>
|
|
<abstract><para>Excellent coverage of algorithms and general
|
|
programming practices.</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>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Clifford</firstname><surname>Pickover</surname></author>
|
|
</authorgroup>
|
|
<title>Computers, Pattern, Chaos, and Beauty</title>
|
|
<publisher>
|
|
<publishername>St. Martin's Press</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1990</year>
|
|
</copyright>
|
|
<isbn>0-312-04123-3</isbn>
|
|
<abstract><para>A treasure trove of ideas and recipes for
|
|
computer-based exploration of mathematical oddities.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>George</firstname><surname>Polya</surname></author>
|
|
</authorgroup>
|
|
<title>How To Solve It</title>
|
|
<publisher>
|
|
<publishername>Princeton University Press</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1973</year>
|
|
</copyright>
|
|
<isbn>0-691-02356-5</isbn>
|
|
<abstract><para>The classic tutorial on problem solving methods
|
|
(i.e., algorithms).</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Chet</firstname><surname>Ramey</surname></author>
|
|
<author><firstname>Brian</firstname><surname>Fox</surname></author>
|
|
</authorgroup>
|
|
<title><ulink
|
|
url="http://www.network-theory.co.uk/bash/manual/">The GNU Bash Reference Manual</ulink></title>
|
|
<publisher>
|
|
<publishername>Network Theory Ltd</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2003</year>
|
|
</copyright>
|
|
<isbn>0-9541617-7-7</isbn>
|
|
<abstract><para>This manual is the definitive reference for
|
|
GNU Bash. The authors of this manual, Chet Ramey and Brian Fox,
|
|
are the original developers of GNU Bash. For each copy sold the
|
|
publisher donates $1 to the Free Software Foundation.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
|
|
</authorgroup>
|
|
<title>Bash Reference Card</title>
|
|
<publisher>
|
|
<publishername>SSC</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1998</year>
|
|
</copyright>
|
|
<isbn>1-58731-010-5</isbn>
|
|
<abstract>
|
|
<para>Excellent Bash pocket reference (don't leave home
|
|
without it). 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>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Ellen</firstname><surname>Siever</surname></author>
|
|
<author><surname>the staff of O'Reilly and Associates</surname></author>
|
|
</authorgroup>
|
|
<title>Linux in a Nutshell</title>
|
|
<edition>2nd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1999</year>
|
|
</copyright>
|
|
<isbn>1-56592-585-8</isbn>
|
|
<abstract><para>The all-around best Linux command reference, even has a Bash section.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<title>The UNIX CD Bookshelf</title>
|
|
<edition>3rd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2003</year>
|
|
</copyright>
|
|
<isbn>0-596-00392-7</isbn>
|
|
<abstract><para>An array of seven UNIX books on CD ROM, including
|
|
<citetitle pubwork="book">UNIX Power Tools</citetitle>,
|
|
<citetitle pubwork="book">Sed and Awk</citetitle>, and <citetitle
|
|
pubwork="book">Learning the Korn Shell</citetitle>. A complete
|
|
set of all the UNIX references and tutorials you would ever need
|
|
at about $130. Buy this one, even if it means going into debt
|
|
and not paying the rent.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The O'Reilly books on Perl. (Actually, any O'Reilly books.)</para>
|
|
<para>---</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract><para>Fioretti, Marco, <quote>Scripting for X
|
|
Productivity,</quote> <ulink url="linuxjournal.com"><citetitle
|
|
pubwork="journal">Linux Journal</citetitle></ulink>, Issue 113,
|
|
September, 2003, pp. 86-9.</para></abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Ben Okopnik's well-written <emphasis>introductory Bash
|
|
scripting</emphasis> articles in issues 53, 54, 55, 57, and
|
|
59 of the <ulink url="http://www.linuxgazette.com"><citetitle
|
|
pubwork="journal">Linux Gazette</citetitle></ulink>, and his
|
|
explanation of <quote>The Deep, Dark Secrets of Bash</quote>
|
|
in issue 56.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract><para>Chet Ramey's <emphasis>bash - The GNU Shell</emphasis>,
|
|
a two-part series published in issues 3 and 4 of the
|
|
<ulink url="http://www.linuxjournal.com"><citetitle
|
|
pubwork="journal">Linux Journal</citetitle></ulink>, July-August
|
|
1994.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Mike G's <ulink
|
|
url="http://www.tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html">Bash-Programming-Intro
|
|
HOWTO</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Richard's <ulink url="http://www.injunea.demon.co.uk/index.htm">Unix
|
|
Scripting Universe</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Chet Ramey's <ulink
|
|
url="ftp://ftp.cwru.edu/pub/bash/FAQ">Bash F.A.Q.</ulink></para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Ed Schaefer's <ulink
|
|
url="http://www.unixreview.com/columns/schaefer/">Shell
|
|
Corner</ulink>
|
|
in <ulink url="http://www.unixreview.com"><citetitle
|
|
pubwork="journal">Unix Review</citetitle></ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Example shell scripts at <ulink
|
|
url="http://alge.anart.no/linux/scripts/">Lucc's Shell Scripts
|
|
</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Example shell scripts at <ulink
|
|
url="http://www.shelldorado.com">SHELLdorado </ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Example shell scripts at <ulink
|
|
url="http://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://www.zazzybob.com">zazzybob</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Steve Parker's <ulink
|
|
url="http://steve-parker.org/sh/sh.shtml">Shell Programming
|
|
Stuff</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Example shell scripts at <ulink
|
|
url="http://sourceforge.net/snippet/browse.php?by=lang&lang=7">
|
|
SourceForge Snippet Library - shell scrips</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><quote>Mini-scripts</quote> at <ulink
|
|
url="http://www.primaat.com/unix_oneliners">Unix
|
|
Oneliners</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Giles Orr's <ulink
|
|
url="http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/">Bash-Prompt
|
|
HOWTO</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Very nice <command>sed</command>,
|
|
<command>awk</command>, and regular expression tutorials at
|
|
<ulink url="http://www.grymoire.com/Unix/index.html">The UNIX
|
|
Grymoire</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Eric Pement's
|
|
<ulink url="http://www.student.northpark.edu/pemente/sed/">sed resources page</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The GNU <command>gawk</command> <ulink
|
|
url="http://sunsite.ualberta.ca/Documentation/Gnu/gawk-3.0.6/gawk.html">
|
|
reference manual</ulink> (<command>gawk</command> is the extended
|
|
GNU version of <command>awk</command> available on Linux and
|
|
BSD systems).</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Trent Fisher's <ulink
|
|
url="http://www.cs.pdx.edu/~trent/gnu/groff/groff.html">groff
|
|
tutorial</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Mark Komarinski's <ulink
|
|
url="http://www.tldp.org/HOWTO/Printing-Usage-HOWTO.html">Printing-Usage
|
|
HOWTO</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><ulink url="http://www.linux-usb.org/USB-guide/book1.html">The
|
|
Linux USB subsystem</ulink> (helpful in writing scripts affecting
|
|
USB peripherals).</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>There is some nice material on <link
|
|
linkend="ioredirref">I/O redirection</link> in <ulink
|
|
url="http://sunsite.ualberta.ca/Documentation/Gnu/textutils-2.0/html_chapter/textutils_10.html">
|
|
chapter 10 of the textutils documentation</ulink> at the <ulink
|
|
url="http://sunsite.ualberta.ca/Documentation"> University of
|
|
Alberta site</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><ulink url="mailto:humbubba@smarty.smart.net">Rick
|
|
Hohensee</ulink> has written the <ulink
|
|
url="ftp://ftp.gwdg.de/pub/linux/install/clienux/interim/osimpa.tgz">
|
|
osimpa</ulink> i386 assembler entirely as Bash scripts.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Aurelio Marinho Jargas has written a <ulink
|
|
url="http://txt2regex.sf.net">Regular expression
|
|
wizard</ulink>. He has also written an informative <ulink
|
|
url="http://guia-er.sf.net">book</ulink> on Regular Expressions,
|
|
in Portuguese.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><ulink url="mailto:brtompkins@comcast.net">Ben
|
|
Tomkins</ulink> has created the <ulink
|
|
url="http://bashnavigator.sourceforge.net">
|
|
Bash Navigator</ulink> directory management tool.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><ulink url="mailto:opengeometry@yahoo.ca">William Park</ulink>
|
|
has been working on a <ulink
|
|
url="http://home.eol.ca/~parkw/index.html">project</ulink>
|
|
to incorporate certain Awk and Python
|
|
features into Bash. Among these is a
|
|
<emphasis>gdbm</emphasis> interface. He has released <ulink
|
|
url="http://freshmeat.net/projects/bashdiff/">bashdiff</ulink>
|
|
on <ulink url="http://freshmeat.net">Freshmeat.net</ulink>. He
|
|
has an <ulink
|
|
url="http://linuxgazette.net/108/park.html">article</ulink>
|
|
in the November, 2004 issue of the <ulink
|
|
url="http://www.linuxgazette.net"><citetitle
|
|
pubwork="journal">Linux Gazette</citetitle></ulink>
|
|
on adding string functions to Bash, with a <ulink
|
|
url="http://linuxgazette.net/109/park.html">followup
|
|
article</ulink> in the December issue, and <ulink
|
|
url="http://linuxgazette.net/110/park.htm">yet another</ulink>
|
|
in the January, 2005 issue.</para>
|
|
</abstract>
|
|
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Rocky Bernstein is in the process of developing a
|
|
<quote>full-fledged</quote> <ulink
|
|
url="http://bashdb.sourceforge.net"> debugger</ulink> for
|
|
Bash.</para>
|
|
<para>---</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The excellent <citetitle pubwork="book"> Bash Reference Manual</citetitle>, by Chet Ramey and Brian Fox,
|
|
distributed as part of the "bash-2-doc" package (available as an rpm).
|
|
See especially the instructive example scripts in this package.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The <ulink
|
|
url="news:comp.unix.shell">comp.os.unix.shell</ulink>
|
|
newsgroup.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The <ulink
|
|
url="http://home.comcast.net/~j.p.h/">comp.os.unix.shell
|
|
FAQ</ulink> and <ulink
|
|
url="http://www.newsville.com/cgi-bin/getfaq?file=comp.unix.shell/comp.unix.shell_FAQ_-_Answers_to_Frequently_Asked_Questions">its
|
|
mirror site</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Assorted comp.os.unix <ulink
|
|
url="http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.shell.html">
|
|
FAQs</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The manpages for <command>bash</command> and
|
|
<command>bash2</command>, <command>date</command>,
|
|
<command>expect</command>, <command>expr</command>,
|
|
<command>find</command>, <command>grep</command>,
|
|
<command>gzip</command>, <command>ln</command>,
|
|
<command>patch</command>, <command>tar</command>,
|
|
<command>tr</command>, <command>bc</command>,
|
|
<command>xargs</command>. The texinfo documentation
|
|
on <command>bash</command>, <command>dd</command>,
|
|
<command>m4</command>, <command>gawk</command>, and
|
|
<command>sed</command>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
|
|
</bibliography>
|
|
|
|
|
|
|
|
<appendix id="contributed-scripts">
|
|
<title>Contributed Scripts</title>
|
|
|
|
<para>These scripts, while not fitting into the text of this document, do
|
|
illustrate some interesting shell programming techniques. They are useful,
|
|
too. Have fun analyzing and running them.</para>
|
|
|
|
<example id="mailformat">
|
|
<title><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>
|
|
|
|
<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>
|
|
|
|
<example id="encryptedpw">
|
|
<title><command>encryptedpw</command>: Uploading to an ftp site,
|
|
using a locally encrypted password</title>
|
|
<programlisting>&encryptedpw;</programlisting>
|
|
</example>
|
|
|
|
<example id="copycd">
|
|
<title><command>copy-cd</command>: Copying a data CD</title>
|
|
<programlisting>©cd;</programlisting>
|
|
</example>
|
|
|
|
<example id="collatz">
|
|
<title>Collatz series</title>
|
|
<programlisting>&collatz;</programlisting>
|
|
</example>
|
|
|
|
<example id="daysbetween">
|
|
<title><command>days-between</command>: Calculate number of days
|
|
between two dates</title>
|
|
<programlisting>&daysbetween;</programlisting>
|
|
</example>
|
|
|
|
<example id="makedict">
|
|
<title>Make a <quote>dictionary</quote></title>
|
|
<programlisting>&makedict;</programlisting>
|
|
</example>
|
|
|
|
<example id="soundex">
|
|
<title>Soundex conversion</title>
|
|
<programlisting>&soundex;</programlisting>
|
|
</example>
|
|
|
|
<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>
|
|
|
|
<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">
|
|
<title><command>behead</command>: Removing mail and news message headers
|
|
</title>
|
|
<programlisting>&behead;</programlisting>
|
|
</example>
|
|
|
|
<example id="ftpget">
|
|
<title><command>ftpget</command>: Downloading files via ftp
|
|
</title>
|
|
<programlisting>&ftpget;</programlisting>
|
|
</example>
|
|
|
|
<para>+</para>
|
|
|
|
<para>Antek Sawicki contributed the following script, which makes very
|
|
clever use of the parameter substitution operators discussed in
|
|
<xref linkend="Parameter-Substitution">.</para>
|
|
|
|
<example id="pw">
|
|
<title><command>password</command>: Generating random
|
|
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">
|
|
<title><command>fifo</command>: Making daily backups, using named pipes</title>
|
|
<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>ℙ</programlisting>
|
|
</example>
|
|
|
|
<para>+</para>
|
|
|
|
<para>This is Rick Boivie's revision of Jordi Sanfeliu's
|
|
<emphasis>tree</emphasis> script.</para>
|
|
|
|
<example id="tree">
|
|
<title><command>tree</command>: Displaying a directory tree</title>
|
|
<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>Michael Zick's complex array example uses the <link
|
|
linkend="md5sumref">md5sum</link> check sum command to encode directory
|
|
information.</para>
|
|
|
|
<example id="directoryinfo">
|
|
<title>Directory information</title>
|
|
<programlisting>&directoryinfo;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>Stephane Chazelas demonstrates object-oriented programming in a
|
|
Bash script.</para>
|
|
|
|
<example id="objoriented">
|
|
<title>Object-oriented database</title>
|
|
<programlisting>&objoriented;</programlisting>
|
|
</example>
|
|
|
|
<para>Now for a script that does something useful: installing and mounting
|
|
those cute USB keychain solid-state <quote>hard drives.</quote></para>
|
|
|
|
<example id="usbinst">
|
|
<title>Mounting USB keychain storage devices</title>
|
|
<programlisting>&usbinst;</programlisting>
|
|
</example>
|
|
|
|
<para>Here is something to warm the hearts of webmasters and mistresses
|
|
everywhere: a script that saves weblogs.</para>
|
|
|
|
<example id="archivweblogs">
|
|
<title>Preserving weblogs</title>
|
|
<programlisting>&archiveweblogs;</programlisting>
|
|
</example>
|
|
|
|
<para>How do you keep the shell from expanding and reinterpreting
|
|
strings?</para>
|
|
|
|
<example id="protectliteral">
|
|
<title>Protecting literal strings</title>
|
|
<programlisting>&protectliteral;</programlisting>
|
|
</example>
|
|
|
|
<para>What if you <emphasis>want</emphasis> the shell to expand
|
|
and reinterpret strings?</para>
|
|
|
|
<example id="unprotectliteral">
|
|
<title>Unprotecting literal strings</title>
|
|
<programlisting>&unprotectliteral;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>This powerful script helps hunt down spammers.</para>
|
|
|
|
<example id="isspammer2">
|
|
<title>Spammer Identification</title>
|
|
<programlisting>&isspammer2;</programlisting>
|
|
</example>
|
|
|
|
<para><quote>Little Monster's</quote> front end to <link
|
|
linkend="wgetref">wget</link>.</para>
|
|
|
|
<example id="wgetter2">
|
|
<title>Making <command>wget</command> easier to use</title>
|
|
<programlisting>&wgetter2;</programlisting>
|
|
</example>
|
|
|
|
<example id="bashpodder">
|
|
<title>A <quote>podcasting</quote> script</title>
|
|
<programlisting>&bashpodder;</programlisting>
|
|
</example>
|
|
|
|
<para>To end this section, a review of the basics . . . and more.</para>
|
|
|
|
<example id="basicsreviewed">
|
|
<title>Basics Reviewed</title>
|
|
<programlisting>&basicsreviewed;</programlisting>
|
|
</example>
|
|
|
|
<example id="cdll">
|
|
<title>An expanded <command>cd</command> command</title>
|
|
<programlisting>&cdll;</programlisting>
|
|
</example>
|
|
|
|
</appendix>
|
|
<!-- End Contributed Scripts appendix -->
|
|
|
|
|
|
|
|
|
|
<appendix id="refcards">
|
|
<title>Reference Cards</title>
|
|
|
|
<para>The following reference cards provide a useful
|
|
<emphasis>summary</emphasis> of certain scripting concepts.
|
|
The foregoing text treats these matters in more depth and gives
|
|
usage examples.</para>
|
|
|
|
<table pgwide=0>
|
|
<title>Special Shell Variables</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Variable</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>$0</option></entry>
|
|
<entry>Name of script</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$1</option></entry>
|
|
<entry>Positional parameter #1</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$2 - $9</option></entry>
|
|
<entry>Positional parameters #2 - #9</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${10}</option></entry>
|
|
<entry>Positional parameter #10</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$#</option></entry>
|
|
<entry>Number of positional parameters</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>"$*"</option></entry>
|
|
<entry>All the positional parameters (as a single word) *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>"$@"</option></entry>
|
|
<entry>All the positional parameters (as separate strings)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${#*}</option></entry>
|
|
<entry>Number of command line parameters passed to
|
|
script</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${#@}</option></entry>
|
|
<entry>Number of command line parameters passed to
|
|
script</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$?</option></entry>
|
|
<entry>Return value</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$$</option></entry>
|
|
<entry>Process ID (PID) of script</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$-</option></entry>
|
|
<entry>Flags passed to script (using
|
|
<emphasis>set</emphasis>)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$_</option></entry>
|
|
<entry>Last argument of previous command</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$!</option></entry>
|
|
<entry>Process ID (PID) of last job run in background</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para><command>*</command> <emphasis>Must be quoted</emphasis>,
|
|
otherwise it defaults to
|
|
<quote><varname>$@</varname></quote>.</para>
|
|
|
|
|
|
<table>
|
|
<title>TEST Operators: Binary Comparison</title>
|
|
<tgroup cols="5">
|
|
<thead>
|
|
<row>
|
|
<entry>Operator</entry>
|
|
<entry>Meaning</entry>
|
|
<entry>-----</entry>
|
|
<entry>Operator</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry>Arithmetic Comparison</entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry>String Comparison</entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-eq</option></entry>
|
|
<entry>Equal to</entry>
|
|
<entry></entry>
|
|
<entry><option>=</option></entry>
|
|
<entry>Equal to</entry>
|
|
</row>
|
|
<row>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry><option>==</option></entry>
|
|
<entry>Equal to</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-ne</option></entry>
|
|
<entry>Not equal to</entry>
|
|
<entry></entry>
|
|
<entry><option>!=</option></entry>
|
|
<entry>Not equal to</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-lt</option></entry>
|
|
<entry>Less than</entry>
|
|
<entry></entry>
|
|
<entry><option>\<</option></entry>
|
|
<entry>Less than (ASCII) *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-le</option></entry>
|
|
<entry>Less than or equal to</entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-gt</option></entry>
|
|
<entry>Greater than</entry>
|
|
<entry></entry>
|
|
<entry><option>\></option></entry>
|
|
<entry>Greater than (ASCII) *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-ge</option></entry>
|
|
<entry>Greater than or equal to</entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry><option>-z</option></entry>
|
|
<entry>String is empty</entry>
|
|
</row>
|
|
<row>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry><option>-n</option></entry>
|
|
<entry>String is not empty</entry>
|
|
</row>
|
|
<row>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry>Arithmetic Comparison</entry>
|
|
<entry>within double parentheses (( ... ))</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>></option></entry>
|
|
<entry>Greater than</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>>=</option></entry>
|
|
<entry>Greater than or equal to</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option><</option></entry>
|
|
<entry>Less than</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option><=</option></entry>
|
|
<entry>Less than or equal to</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
<para><command>*</command> <emphasis>If within a
|
|
double-bracket</emphasis> [[ ... ]] <emphasis>test construct,
|
|
then no escape</emphasis> \ <emphasis>is
|
|
needed.</emphasis></para>
|
|
|
|
<table>
|
|
<title>TEST Operators: Files</title>
|
|
<tgroup cols="5">
|
|
<thead>
|
|
<row>
|
|
<entry>Operator</entry>
|
|
<entry>Tests Whether</entry>
|
|
<entry>-----</entry>
|
|
<entry>Operator</entry>
|
|
<entry>Tests Whether</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>-e</option></entry>
|
|
<entry>File exists</entry>
|
|
<entry></entry>
|
|
<entry><option>-s</option></entry>
|
|
<entry>File is not zero size</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-f</option></entry>
|
|
<entry>File is a <emphasis>regular</emphasis> file</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-d</option></entry>
|
|
<entry>File is a <emphasis>directory</emphasis></entry>
|
|
<entry></entry>
|
|
<entry><option>-r</option></entry>
|
|
<entry>File has <emphasis>read</emphasis>
|
|
permission</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-h</option></entry>
|
|
<entry>File is a <emphasis>symbolic link</emphasis></entry>
|
|
<entry></entry>
|
|
<entry><option>-w</option></entry>
|
|
<entry>File has <emphasis>write</emphasis>
|
|
permission</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-L</option></entry>
|
|
<entry>File is a <emphasis>symbolic link</emphasis></entry>
|
|
<entry></entry>
|
|
<entry><option>-x</option></entry>
|
|
<entry>File has <emphasis>execute</emphasis>
|
|
permission</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-b</option></entry>
|
|
<entry>File is a <emphasis>block device</emphasis></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-c</option></entry>
|
|
<entry>File is a <emphasis>character device</emphasis></entry>
|
|
<entry></entry>
|
|
<entry><option>-g</option></entry>
|
|
<entry><emphasis>sgid</emphasis> flag set</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-p</option></entry>
|
|
<entry>File is a <emphasis>pipe</emphasis></entry>
|
|
<entry></entry>
|
|
<entry><option>-u</option></entry>
|
|
<entry><emphasis>suid</emphasis> flag set</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-S</option></entry>
|
|
<entry>File is a <link linkend="socketref">socket</link></entry>
|
|
<entry></entry>
|
|
<entry><option>-k</option></entry>
|
|
<entry><quote>sticky bit</quote> set</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-t</option></entry>
|
|
<entry>File is associated with a
|
|
<emphasis>terminal</emphasis></entry>
|
|
</row>
|
|
<row><entry></entry></row>
|
|
<row>
|
|
<entry><option>-N</option></entry>
|
|
<entry>File modified since it was last read</entry>
|
|
<entry></entry>
|
|
<entry><option>F1 -nt F2</option></entry>
|
|
<entry>File F1 is <emphasis>newer</emphasis> than F2 *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-O</option></entry>
|
|
<entry>You own the file</entry>
|
|
<entry></entry>
|
|
<entry><option>F1 -ot F2</option></entry>
|
|
<entry>File F1 is <emphasis>older</emphasis> than F2 *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-G</option></entry>
|
|
<entry><emphasis>Group id</emphasis> of file same as
|
|
yours</entry>
|
|
<entry></entry>
|
|
<entry><option>F1 -ef F2</option></entry>
|
|
<entry>Files F1 and F2 are <emphasis>hard links</emphasis>
|
|
to the same file *</entry>
|
|
</row>
|
|
<row><entry></entry></row>
|
|
<row>
|
|
<entry><option>!</option></entry>
|
|
<entry><quote>NOT</quote> (reverses sense of above
|
|
tests)</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
<para><command>*</command> <emphasis>Binary</emphasis> operator
|
|
(requires two operands).</para>
|
|
|
|
|
|
|
|
|
|
<table pgwide=0>
|
|
<title>Parameter Substitution and Expansion</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>${var}</option></entry>
|
|
<entry>Value of <parameter>var</parameter>, same as
|
|
<parameter>$var</parameter></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${var-DEFAULT}</option></entry>
|
|
<entry>If <parameter>var</parameter> not set, evaluate expression
|
|
as <parameter>$DEFAULT</parameter> *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${var:-DEFAULT}</option></entry>
|
|
<entry>If <parameter>var</parameter> not set or is empty,
|
|
evaluate expression as <parameter>$DEFAULT</parameter>
|
|
*</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${var=DEFAULT}</option></entry>
|
|
<entry>If <parameter>var</parameter> not set, evaluate expression
|
|
as <parameter>$DEFAULT</parameter> *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${var:=DEFAULT}</option></entry>
|
|
<entry>If <parameter>var</parameter> not set, evaluate expression
|
|
as <parameter>$DEFAULT</parameter> *</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${var+OTHER}</option></entry>
|
|
<entry>If <parameter>var</parameter> set, evaluate expression as
|
|
<parameter>$OTHER</parameter>, otherwise as null string</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${var:+OTHER}</option></entry>
|
|
<entry>If <parameter>var</parameter> set, evaluate expression as
|
|
<parameter>$OTHER</parameter>, otherwise as null string</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${var?ERR_MSG}</option></entry>
|
|
<entry>If <parameter>var</parameter> not set, print
|
|
<parameter>$ERR_MSG</parameter> *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${var:?ERR_MSG}</option></entry>
|
|
<entry>If <parameter>var</parameter> not set, print
|
|
<parameter>$ERR_MSG</parameter> *</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${!varprefix*}</option></entry>
|
|
<entry>Matches all previously declared variables beginning with
|
|
<parameter>varprefix</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${!varprefix@}</option></entry>
|
|
<entry>Matches all previously declared variables beginning with
|
|
<parameter>varprefix</parameter></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para><command>*</command> Of course if <parameter>var</parameter>
|
|
<emphasis>is</emphasis> set, evaluate the expression as
|
|
<parameter>$var</parameter>.</para>
|
|
|
|
|
|
<table pgwide=0>
|
|
<title>String Operations</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>${#string}</option></entry>
|
|
<entry>Length of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${string:position}</option></entry>
|
|
<entry>Extract substring from <parameter>$string</parameter>
|
|
at <parameter>$position</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${string:position:length}</option></entry>
|
|
<entry>Extract <parameter>$length</parameter>
|
|
characters substring from <parameter>$string</parameter>
|
|
at <parameter>$position</parameter></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${string#substring}</option></entry>
|
|
<entry>Strip shortest match of
|
|
<parameter>$substring</parameter> from front of
|
|
<parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${string##substring}</option></entry>
|
|
<entry>Strip longest match of
|
|
<parameter>$substring</parameter> from front of
|
|
<parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${string%substring}</option></entry>
|
|
<entry>Strip shortest match of
|
|
<parameter>$substring</parameter> from back of
|
|
<parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${string%%substring}</option></entry>
|
|
<entry>Strip longest match of
|
|
<parameter>$substring</parameter> from back of
|
|
<parameter>$string</parameter></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${string/substring/replacement}</option></entry>
|
|
<entry>Replace first match of
|
|
<parameter>$substring</parameter> with
|
|
<parameter>$replacement</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${string//substring/replacement}</option></entry>
|
|
<entry>Replace <emphasis>all</emphasis> matches of
|
|
<parameter>$substring</parameter> with
|
|
<parameter>$replacement</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${string/#substring/replacement}</option></entry>
|
|
<entry>If <parameter>$substring</parameter>
|
|
matches <emphasis>front</emphasis> end of
|
|
<parameter>$string</parameter>, substitute
|
|
<parameter>$replacement</parameter> for
|
|
<parameter>$substring</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${string/%substring/replacement}</option></entry>
|
|
<entry>If <parameter>$substring</parameter>
|
|
matches <emphasis>back</emphasis> end of
|
|
<parameter>$string</parameter>, substitute
|
|
<parameter>$replacement</parameter> for
|
|
<parameter>$substring</parameter></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>expr match "$string" '$substring'</option></entry>
|
|
<entry>Length of matching <parameter>$substring</parameter>*
|
|
at beginning of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr "$string" : '$substring'</option></entry>
|
|
<entry>Length of matching <parameter>$substring</parameter>*
|
|
at beginning of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr index "$string" $substring</option></entry>
|
|
<entry>Numerical position in <parameter>$string</parameter>
|
|
of first character in <parameter>$substring</parameter>
|
|
that matches</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr substr $string $position
|
|
$length</option></entry>
|
|
<entry>Extract <parameter>$length</parameter> characters
|
|
from <parameter>$string</parameter> starting at
|
|
<parameter>$position</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr match "$string"
|
|
'\($substring\)'</option></entry>
|
|
<entry>Extract <parameter>$substring</parameter>* at
|
|
beginning of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr "$string" :
|
|
'\($substring\)'</option></entry>
|
|
<entry>Extract <parameter>$substring</parameter>* at
|
|
beginning of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr match "$string"
|
|
'.*\($substring\)'</option></entry>
|
|
<entry>Extract <parameter>$substring</parameter>* at
|
|
end of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr "$string" :
|
|
'.*\($substring\)'</option></entry>
|
|
<entry>Extract <parameter>$substring</parameter>* at
|
|
end of <parameter>$string</parameter></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para><command>*</command> Where <parameter>$substring</parameter> is a
|
|
<emphasis>regular expression</emphasis>.</para>
|
|
|
|
|
|
|
|
<table pgwide=0>
|
|
<title>Miscellaneous Constructs</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Interpretation</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><emphasis>Brackets</emphasis></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>if [ CONDITION ]</option></entry>
|
|
<entry>Test construct</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>if [[ CONDITION ]]</option></entry>
|
|
<entry>Extended test construct</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>Array[1]=element1</option></entry>
|
|
<entry>Array initialization</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option> [a-z]</option></entry>
|
|
<entry>Range of characters within a <link linkend="regexref">Regular Expression</link></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><emphasis>Curly Brackets</emphasis></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${variable}</option></entry>
|
|
<entry>Parameter substitution</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${!variable}</option></entry>
|
|
<entry><link linkend="ivrref">Indirect variable reference</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>{ command1; command2 }</option></entry>
|
|
<entry>Block of code</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>{string1,string2,string3,...}</option></entry>
|
|
<entry>Brace expansion</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><emphasis>Parentheses</emphasis></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>( command1; command2 )</option></entry>
|
|
<entry>Command group executed within a <link
|
|
linkend="subshellsref">subshell</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>Array=(element1 element2 element3)</option></entry>
|
|
<entry>Array initialization</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>result=$(COMMAND)</option></entry>
|
|
<entry>Execute command in subshell and assign result to
|
|
variable</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>>(COMMAND)</option></entry>
|
|
<entry><link linkend="processsubref">Process substitution</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option><(COMMAND)</option></entry>
|
|
<entry>Process substitution</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><emphasis>Double Parentheses</emphasis></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>(( var = 78 ))</option></entry>
|
|
<entry>Integer arithmetic</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>var=$(( 20 + 5 ))</option></entry>
|
|
<entry>Integer arithmetic, with variable assignment</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><emphasis>Quoting</emphasis></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>"$variable"</option></entry>
|
|
<entry>"Weak" quoting</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>'string'</option></entry>
|
|
<entry>"Strong" quoting</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><emphasis>Back Quotes</emphasis></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>result=`COMMAND`</option></entry>
|
|
<entry>Execute command in subshell and assign result to variable</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
</appendix>
|
|
<!-- Reference Cards appendix -->
|
|
|
|
|
|
|
|
|
|
|
|
<appendix id="sedawk">
|
|
<title>A Sed and Awk Micro-Primer</title>
|
|
|
|
<para><anchor id="sedref"></para>
|
|
|
|
<para>This is a very brief introduction to the <command>sed</command>
|
|
and <command>awk</command> text processing utilities. We will
|
|
deal with only a few basic commands here, but that will suffice
|
|
for understanding simple sed and awk constructs within shell
|
|
scripts.</para>
|
|
|
|
|
|
<para><command>sed</command>: a non-interactive text file editor</para>
|
|
|
|
<para><command>awk</command>: a field-oriented pattern processing
|
|
language with a C-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>
|
|
|
|
<para><programlisting>sed -e '/^$/d' $filename
|
|
# The -e option causes the next string to be interpreted as an editing instruction.
|
|
# (If passing only a single instruction to "sed", the "-e" is optional.)
|
|
# The "strong" quotes ('') protect the RE characters in the instruction
|
|
#+ from reinterpretation as special characters by the body of the script.
|
|
# (This reserves RE expansion of the instruction for sed.)
|
|
#
|
|
# Operates on the text contained in file $filename.
|
|
</programlisting></para>
|
|
|
|
<para>In certain cases, a <command>sed</command> editing command will
|
|
not work with single quotes.</para>
|
|
|
|
<para><programlisting>
|
|
filename=file1.txt
|
|
pattern=BEGIN
|
|
|
|
sed "/^$pattern/d" "$filename" # Works as specified.
|
|
# sed '/^$pattern/d' "$filename" has unexpected results.
|
|
# In this instance, with strong quoting (' ... '),
|
|
#+ "$pattern" will not expand to "BEGIN".</programlisting></para>
|
|
|
|
|
|
<note><para>Sed uses the <option>-e</option> option
|
|
to specify that the following string is an instruction or set
|
|
of instructions. If there is only a single instruction contained
|
|
in the string, then this option may be omitted.</para></note>
|
|
|
|
<para><programlisting>sed -n '/xzy/p' $filename
|
|
# The -n option tells sed to print only those lines matching the pattern.
|
|
# Otherwise all input lines would print.
|
|
# The -e option not necessary here since there is only a single editing instruction.
|
|
</programlisting></para>
|
|
|
|
<table>
|
|
<title>Examples of sed operators</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Notation</entry>
|
|
<entry>Effect</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>8d</option></entry>
|
|
<entry>Delete 8th line of input.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>/^$/d</option></entry>
|
|
<entry>Delete all blank lines.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1,/^$/d</option></entry>
|
|
<entry>Delete from beginning of input up to, and including
|
|
first blank line.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>/Jones/p</option></entry>
|
|
<entry>Print only lines containing <quote>Jones</quote> (with
|
|
<token>-n</token> option).</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/Windows/Linux/</option></entry>
|
|
<entry>Substitute <quote>Linux</quote> for first instance
|
|
of <quote>Windows</quote> found in each input line.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/BSOD/stability/g</option></entry>
|
|
<entry>Substitute <quote>stability</quote> for every instance
|
|
of <quote>BSOD</quote> found in each input line.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/ *$//</option></entry>
|
|
<entry>Delete all spaces at the end of every line.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/00*/0/g</option></entry>
|
|
<entry>Compress all consecutive sequences of zeroes into
|
|
a single zero.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>/GUI/d</option></entry>
|
|
<entry>Delete all lines containing <quote>GUI</quote>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/GUI//g</option></entry>
|
|
<entry>Delete all instances of <quote>GUI</quote>, leaving the
|
|
remainder of each line intact.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
<para>Substituting a zero-length string for another is equivalent
|
|
to deleting that string within a line of input. This leaves the
|
|
remainder of the line intact. Applying <userinput>s/GUI//</userinput>
|
|
to the line
|
|
<screen><userinput>The most important parts of any application are its GUI and sound effects</userinput></screen>
|
|
results in
|
|
<screen><computeroutput>The most important parts of any application are its and sound effects</computeroutput></screen></para>
|
|
|
|
<para>A backslash forces the <command>sed</command> replacement
|
|
command to continue on to the next line. This has the effect of
|
|
using the <emphasis>newline</emphasis> at the end of the first
|
|
line as the <emphasis>replacement string</emphasis>.
|
|
|
|
<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>
|
|
|
|
|
|
<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>
|
|
<listitem><para><xref linkend="wf"></para></listitem>
|
|
<listitem><para><xref linkend="lifeslow"></para></listitem>
|
|
<listitem><para><xref linkend="selfdocument"></para></listitem>
|
|
<listitem><para><xref linkend="dictlookup"></para></listitem>
|
|
</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>
|
|
|
|
<para><anchor id="awkref"></para>
|
|
|
|
<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>
|
|
|
|
<para><programlisting>awk '{print $3}' $filename
|
|
# Prints field #3 of file $filename to stdout.
|
|
|
|
awk '{print $1 $5 $6}' $filename
|
|
# Prints fields #1, #5, and #6 of file $filename.</programlisting></para>
|
|
|
|
<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
|
|
<quote>total</quote>, there is an <command>END</command> command
|
|
block, executed after the script has processed all its input.
|
|
<programlisting>END { print total }</programlisting></para>
|
|
|
|
<para>Corresponding to the <command>END</command>, there is a
|
|
<command>BEGIN</command>, for a code block to be performed before awk
|
|
starts processing its input.</para>
|
|
|
|
<para>The following example illustrates how <command>awk</command> can
|
|
add text-parsing tools to a shell script.</para>
|
|
|
|
<example id="lettercount2">
|
|
<title>Counting Letter Occurrences</title>
|
|
<programlisting>&lettercount2;</programlisting>
|
|
</example>
|
|
|
|
<para>For simpler examples of awk within shell scripts, see:
|
|
<orderedlist>
|
|
<listitem><para><xref linkend="ex44"></para></listitem>
|
|
<listitem><para><xref linkend="redir4"></para></listitem>
|
|
<listitem><para><xref linkend="stripc"></para></listitem>
|
|
<listitem><para><xref linkend="coltotaler"></para></listitem>
|
|
<listitem><para><xref linkend="coltotaler2"></para></listitem>
|
|
<listitem><para><xref linkend="coltotaler3"></para></listitem>
|
|
<listitem><para><xref linkend="pidid"></para></listitem>
|
|
<listitem><para><xref linkend="constat"></para></listitem>
|
|
<listitem><para><xref linkend="fileinfo"></para></listitem>
|
|
<listitem><para><xref linkend="blotout"></para></listitem>
|
|
<listitem><para><xref linkend="seedingrandom"></para></listitem>
|
|
<listitem><para><xref linkend="idelete"></para></listitem>
|
|
<listitem><para><xref linkend="substringex"></para></listitem>
|
|
<listitem><para><xref linkend="sumproduct"></para></listitem>
|
|
<listitem><para><xref linkend="userlist"></para></listitem>
|
|
</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 (see footnote)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>128+n</option></entry>
|
|
<entry>fatal error signal <quote>n</quote></entry>
|
|
<entry><command>kill -9</command> <varname>$PPID</varname> of script</entry>
|
|
<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>
|
|
<entry><option>255*</option></entry>
|
|
<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>
|
|
|
|
<para>According to the table, exit codes 1 - 2, 126 - 165, and 255
|
|
|
|
<footnote><para>Out of range exit values can result in
|
|
unexpected exit codes. An exit value greater than 255 returns an
|
|
exit code modulo 256. For example, <command>exit 3809</command>
|
|
gives an exit code of <errorcode>225</errorcode> (3809 % 256 =
|
|
225).</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>
|
|
|
|
<para>There has been an attempt to systematize exit status numbers
|
|
(see <filename class="headerfile">/usr/include/sysexits.h</filename>),
|
|
but this is intended for C and C++ programmers. A similar standard
|
|
for scripting might be appropriate. The author of this document
|
|
proposes restricting user-defined exit codes to the range 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>
|
|
|
|
<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>&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/<n> or something similar) three times.</para>
|
|
|
|
<para>At this point, Bash inherits these three file descriptors,
|
|
and each command (child process) run by Bash inherits
|
|
them in turn, except when you redirect the command. <link
|
|
linkend="ioredirref">Redirection</link> means reassigning
|
|
one of the file descriptors to another file (or a pipe, or
|
|
anything permissible). File descriptors may be reassigned
|
|
locally (for a command, a command group, a 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 > /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> /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>&1)"</userinput>
|
|
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
|
|
lsof 426 root 0u CHR 136,1 3 /dev/pts/1
|
|
lsof 426 root 1w FIFO 0,0 7520 pipe
|
|
lsof 426 root 2w FIFO 0,0 7520 pipe</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>This works for different types of redirection.</para>
|
|
|
|
<para><userinput>Exercise:</userinput> Analyze the following script.
|
|
|
|
<programlisting>#! /usr/bin/env bash
|
|
|
|
mkfifo /tmp/fifo1 /tmp/fifo2
|
|
while read a; do echo "FIFO1: $a"; done < /tmp/fifo1 &
|
|
exec 7> /tmp/fifo1
|
|
exec 8> >(while read a; do echo "FD8: $a, to fd7"; done >&7)
|
|
|
|
exec 3>&1
|
|
(
|
|
(
|
|
(
|
|
while read a; do echo "FIFO2: $a"; done < /tmp/fifo2 | tee /dev/stderr | tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 >&7 &
|
|
exec 3> /tmp/fifo2
|
|
|
|
echo 1st, to stdout
|
|
sleep 1
|
|
echo 2nd, to stderr >&2
|
|
sleep 1
|
|
echo 3rd, to fd 3 >&3
|
|
sleep 1
|
|
echo 4th, to fd 4 >&4
|
|
sleep 1
|
|
echo 5th, to fd 5 >&5
|
|
sleep 1
|
|
echo 6th, through a pipe | sed 's/.*/PIPE: &, to fd 5/' >&5
|
|
sleep 1
|
|
echo 7th, to fd 6 >&6
|
|
sleep 1
|
|
echo 8th, to fd 7 >&7
|
|
sleep 1
|
|
echo 9th, to fd 8 >&8
|
|
|
|
) 4>&1 >&3 3>&- | while read a; do echo "FD4: $a"; done 1>&3 5>&- 6>&-
|
|
) 5>&1 >&3 | while read a; do echo "FD5: $a"; done 1>&3 6>&-
|
|
) 6>&1 >&3 | while read a; do echo "FD6: $a"; done 3>&-
|
|
|
|
rm -f /tmp/fifo1 /tmp/fifo2
|
|
|
|
|
|
# For each command and subshell, figure out which fd points to what.
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
</appendix>
|
|
<!-- A Detailed Introduction to I/O and I/O Redirection -->
|
|
|
|
|
|
<appendix id="standard-options">
|
|
<title>Standard Command-Line Options</title>
|
|
|
|
<para>Over time, there has evolved a loose standard for the
|
|
meanings of command line option flags. The GNU utilities conform
|
|
more closely to this <quote>standard</quote> than older UNIX
|
|
utilities.</para>
|
|
|
|
<para>Traditionally, UNIX command-line options consist of a dash,
|
|
followed by one or more lowercase letters. The GNU utilities
|
|
added a double-dash, followed by a complete word or compound
|
|
word.</para>
|
|
|
|
|
|
<para>The two most widely-accepted options are:</para>
|
|
|
|
<itemizedlist id="widelyaccopt">
|
|
|
|
<listitem>
|
|
<para><option>-h</option></para>
|
|
<para><option>--help</option></para>
|
|
<para><emphasis>Help</emphasis>: Give usage message and exit.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-v</option></para>
|
|
<para><option>--version</option></para>
|
|
<para><emphasis>Version</emphasis>: Show program version and exit.</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<para>Other common options are:</para>
|
|
|
|
<itemizedlist id="otheroptns">
|
|
|
|
<listitem>
|
|
<para><option>-a</option></para>
|
|
<para><option>--all</option></para>
|
|
<para><emphasis>All</emphasis>: show <emphasis>all</emphasis>
|
|
information or operate on <emphasis>all</emphasis> arguments.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-l</option></para>
|
|
<para><option>--list</option></para>
|
|
<para><emphasis>List</emphasis>: list files or arguments without
|
|
taking other action.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-o</option></para>
|
|
<para><emphasis>Output</emphasis> filename</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-q</option></para>
|
|
<para><option>--quiet</option></para>
|
|
<para><emphasis>Quiet</emphasis>: suppress <filename>stdout</filename>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-r</option></para>
|
|
<para><option>-R</option></para>
|
|
<para><option>--recursive</option></para>
|
|
<para><emphasis>Recursive</emphasis>: Operate recursively (down
|
|
directory tree).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-v</option></para>
|
|
<para><option>--verbose</option></para>
|
|
<para><emphasis>Verbose</emphasis>: output additional information to
|
|
<filename>stdout</filename> or <filename>stderr</filename>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-z</option></para>
|
|
<para><option>--compress</option></para>
|
|
<para><emphasis>Compress</emphasis>: apply compression (usually
|
|
<link linkend="gzipref">gzip</link>).</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<para>However:</para>
|
|
|
|
<itemizedlist id="exceptionsopts">
|
|
|
|
<listitem>
|
|
<para>In <command>tar</command> and <command>gawk</command>:</para>
|
|
<para><option>-f</option></para>
|
|
<para><option>--file</option></para>
|
|
<para><emphasis>File</emphasis>: filename follows.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>In <command>cp</command>, <command>mv</command>,
|
|
<command>rm</command>:</para>
|
|
<para><option>-f</option></para>
|
|
<para><option>--force</option></para>
|
|
<para><emphasis>Force</emphasis>: force overwrite of target file(s).</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<caution><para>Many UNIX and Linux utilities deviate from this
|
|
<quote>standard,</quote> so it is dangerous to
|
|
<emphasis>assume</emphasis> that a given option will behave in a
|
|
standard way. Always check the man page for the command in question
|
|
when in doubt.</para></caution>
|
|
|
|
<para>A complete table of recommended options for the GNU utilities
|
|
is available at <ulink
|
|
url="http://www.gnu.org/prep/standards_19.html">http://www.gnu.org/prep/standards_19.html</ulink>.</para>
|
|
|
|
</appendix>
|
|
<!-- End Standard Command-Line Options appendix -->
|
|
|
|
|
|
<appendix id="systemdirs">
|
|
|
|
<title>Important System Directories</title>
|
|
|
|
|
|
<para>Sysadmins and anyone else writing administrative scripts
|
|
should be intimately familiar with the following system
|
|
directories.</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/bin</filename></para>
|
|
<para>Binaries (executables). Basic system programs
|
|
and utilities (such as <command>bash</command>).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/bin</filename>
|
|
|
|
<footnote>
|
|
<para>Some early UNIX systems had a fast, small-capacity fixed
|
|
disk (containing <filename class="directory">/</filename>,
|
|
the root partition), and a second drive which
|
|
was larger, but slower (containing <filename
|
|
class="directory">/usr</filename> and other
|
|
partitions). The most frequently used programs and
|
|
utilities therefore resided on the small-but-fast
|
|
drive, in <filename class="directory">/bin</filename>,
|
|
and the others on the slower drive, in <filename
|
|
class="directory">/usr/bin</filename>.</para>
|
|
|
|
<para>This likewise accounts for the split between
|
|
<filename class="directory">/sbin</filename> and
|
|
<filename class="directory">/usr/sbin</filename>,
|
|
<filename class="directory">/lib</filename> and <filename
|
|
class="directory">/usr/lib</filename>, etc.</para>
|
|
</footnote>
|
|
|
|
</para>
|
|
|
|
<para>More system binaries.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/local/bin</filename></para>
|
|
<para>Miscellaneous binaries local to the particular machine.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/sbin</filename></para>
|
|
<para>System binaries. Basic system administrative programs
|
|
and utilities (such as <command>fsck</command>).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/sbin</filename></para>
|
|
<para>More system administrative programs and utilities.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/etc</filename></para>
|
|
<para><emphasis>Et cetera</emphasis>. Systemwide configuration
|
|
scripts.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/etc/rc.d</filename></para>
|
|
<para>Boot scripts, on Red Hat and derivative distributions
|
|
of Linux.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/share/doc</filename></para>
|
|
<para>Documentation for installed packages.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/man</filename></para>
|
|
<para>The systemwide manpages.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/dev</filename></para>
|
|
<para>Device directory. Entries (but <emphasis>not</emphasis>
|
|
mount points) for physical and virtual devices.
|
|
See <xref linkend="devproc">.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/proc</filename></para>
|
|
<para>Process directory. Contains information and statistics
|
|
about running processes and kernel parameters.
|
|
See <xref linkend="devproc">.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/sys</filename></para>
|
|
<para>Systemwide device directory. Contains information and
|
|
statistics about device and device names. This is newly
|
|
added to Linux with the 2.6.X kernels.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/mnt</filename></para>
|
|
<para><emphasis>Mount</emphasis>. Directory for mounting
|
|
hard drive partitions, such as <filename
|
|
class="directory">/mnt/dos</filename>, and physical
|
|
devices. In newer Linux distros, the <filename
|
|
class="directory">/media</filename> directory has taken
|
|
over as the preferred mount point for I/O devices.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/media</filename></para>
|
|
<para>In newer Linux distros, the preferred mount point for
|
|
I/O devices, such as CD ROMs or USB flash drives.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/var</filename></para>
|
|
<para><emphasis>Variable</emphasis> (changeable) system
|
|
files. This is a catchall <quote>scratchpad</quote>
|
|
directory for data generated while a Linux/UNIX machine
|
|
is running.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/var/log</filename></para>
|
|
<para>Systemwide log files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/var/spool/mail</filename></para>
|
|
<para>User mail spool.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/lib</filename></para>
|
|
<para>Systemwide library files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/lib</filename></para>
|
|
<para>More systemwide library files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/tmp</filename></para>
|
|
<para>System temporary files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/boot</filename></para>
|
|
<para>System <emphasis>boot</emphasis> directory. The kernel,
|
|
module links, system map, and boot manager reside here.</para>
|
|
<warning><para>Altering files in this directory may result in an
|
|
unbootable system.</para></warning>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</appendix>
|
|
|
|
|
|
|
|
<appendix id="localization">
|
|
<title>Localization</title>
|
|
|
|
|
|
<para>Localization is an undocumented Bash feature.</para>
|
|
|
|
<para>A localized shell script echoes its text output in the
|
|
language defined as the system's locale. A Linux user in Berlin,
|
|
Germany, would get script output in German, whereas his cousin
|
|
in Berlin, Maryland, would get output from the same script in
|
|
English.</para>
|
|
|
|
<para>To create a localized script, use the following template to
|
|
write all messages to the user (error messages, prompts,
|
|
etc.).</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# localized.sh
|
|
# Script by Stephane Chazelas,
|
|
#+ modified by Bruno Haible, bugfixed by Alfredo Pironti.
|
|
|
|
. gettext.sh
|
|
|
|
E_CDERROR=65
|
|
|
|
error()
|
|
{
|
|
printf "$@" >&2
|
|
exit $E_CDERROR
|
|
}
|
|
|
|
cd $var || error "`eval_gettext \"Can\'t cd to \\\$var.\"`"
|
|
# The triple backslashes (escapes) in front of $var needed
|
|
#+ "because eval_gettext expects a string
|
|
#+ where the variable values have not yet been substituted."
|
|
# -- per Bruno Haible
|
|
read -p "`gettext \"Enter the value: \"`" var
|
|
# ...
|
|
|
|
|
|
# ------------------------------------------------------------------
|
|
# Alfredo Pironti comments:
|
|
|
|
# This script has been modified to not use the $"..." syntax in
|
|
#+ favor of the "`gettext \"...\"`" syntax.
|
|
# This is ok, but with the new localized.sh program, the commands
|
|
#+ "bash -D filename" and "bash --dump-po-string filename"
|
|
#+ will produce no output
|
|
#+ (because those command are only searching for the $"..." strings)!
|
|
# The ONLY way to extract strings from the new file is to use the
|
|
# 'xgettext' program. However, the xgettext program is buggy.
|
|
|
|
# Note that 'xgettext' has another bug.
|
|
#
|
|
# The shell fragment:
|
|
# gettext -s "I like Bash"
|
|
# will be correctly extracted, but . . .
|
|
# xgettext -s "I like Bash"
|
|
# . . . fails!
|
|
# 'xgettext' will extract "-s" because
|
|
#+ the command only extracts the
|
|
#+ very first argument after the 'gettext' word.
|
|
|
|
|
|
# Escape characters:
|
|
#
|
|
# To localize a sentence like
|
|
# echo -e "Hello\tworld!"
|
|
#+ you must use
|
|
# echo -e "`gettext \"Hello\\tworld\"`"
|
|
# The "double escape character" before the `t' is needed because
|
|
#+ 'gettext' will search for a string like: 'Hello\tworld'
|
|
# This is because gettext will read one literal `\')
|
|
#+ and will output a string like "Bonjour\tmonde",
|
|
#+ so the 'echo' command will display the message correctly.
|
|
#
|
|
# You may not use
|
|
# echo "`gettext -e \"Hello\tworld\"`"
|
|
#+ due to the xgettext bug explained above.
|
|
|
|
|
|
|
|
# Let's localize the following shell fragment:
|
|
# echo "-h display help and exit"
|
|
#
|
|
# First, one could do this:
|
|
# echo "`gettext \"-h display help and exit\"`"
|
|
# This way 'xgettext' will work ok,
|
|
#+ but the 'gettext' program will read "-h" as an option!
|
|
#
|
|
# One solution could be
|
|
# echo "`gettext -- \"-h display help and exit\"`"
|
|
# This way 'gettext' will work,
|
|
#+ but 'xgettext' will extract "--", as referred to above.
|
|
#
|
|
# The workaround you may use to get this string localized is
|
|
# echo -e "`gettext \"\\0-h display help and exit\"`"
|
|
# We have added a \0 (NULL) at the beginning of the sentence.
|
|
# This way 'gettext' works correctly, as does 'xgettext.'
|
|
# Moreover, the NULL character won't change the behavior
|
|
#+ of the 'echo' command.
|
|
# ------------------------------------------------------------------</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>bash -D localized.sh</userinput>
|
|
<computeroutput>"Can't cd to %s."
|
|
"Enter the value: "</computeroutput></screen>
|
|
|
|
This lists all the localized text. (The <option>-D</option>
|
|
option lists double-quoted strings prefixed by a <token>$</token>,
|
|
without executing the script.)</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>bash --dump-po-strings localized.sh</userinput>
|
|
<computeroutput>#: a:6
|
|
msgid "Can't cd to %s."
|
|
msgstr ""
|
|
#: a:7
|
|
msgid "Enter the value: "
|
|
msgstr ""</computeroutput></screen>
|
|
|
|
The <option>--dump-po-strings</option> option to Bash
|
|
resembles the <option>-D</option> option, but uses <link
|
|
linkend="gettextref">gettext</link> <quote>po</quote> format.
|
|
|
|
</para>
|
|
|
|
<note>
|
|
<para>Bruno Haible points out:</para>
|
|
|
|
<para>Starting with gettext-0.12.2, <command>xgettext -o - localized.sh</command>
|
|
is recommended instead of <command>bash --dump-po-strings
|
|
localized.sh</command>, because <command>xgettext</command> . . .</para>
|
|
|
|
<para>1. understands the gettext and eval_gettext commands
|
|
(whereas bash --dump-po-strings understands only its deprecated
|
|
$"..." syntax)</para>
|
|
|
|
<para>2. can extract comments placed by the programmer, intended
|
|
to be read by the translator.</para>
|
|
|
|
<para>This shell code is then not specific to Bash any
|
|
more; it works the same way with Bash 1.x and other /bin/sh
|
|
implementations.</para>
|
|
</note>
|
|
|
|
|
|
<para>Now, build a <filename>language.po</filename>
|
|
file for each language that the script will be translated
|
|
into, specifying the <replaceable>msgstr</replaceable>. Alfredo
|
|
Pironti gives the following example:</para>
|
|
|
|
<para>fr.po:
|
|
|
|
<programlisting>#: a:6
|
|
msgid "Can't cd to $var."
|
|
msgstr "Impossible de se positionner dans le repertoire $var."
|
|
#: a:7
|
|
msgid "Enter the value: "
|
|
msgstr "Entrez la valeur : "
|
|
|
|
# The string are dumped with the variable names, not with the %s syntax,
|
|
#+ similar to C programs.
|
|
#+ This is a very cool feature if the programmer uses
|
|
#+ variable names that make sense!</programlisting>
|
|
</para>
|
|
|
|
<para>Then, run <link linkend="msgfmtref">msgfmt</link>.</para>
|
|
<para><userinput>msgfmt -o localized.sh.mo fr.po</userinput></para>
|
|
|
|
<para>Place the resulting <filename>localized.sh.mo</filename> file in the
|
|
<filename class="directory">/usr/local/share/locale/fr/LC_MESSAGES</filename>
|
|
directory, and at the beginning of the script, insert the lines:
|
|
|
|
<programlisting>TEXTDOMAINDIR=/usr/local/share/locale
|
|
TEXTDOMAIN=localized.sh</programlisting>
|
|
</para>
|
|
|
|
<para>If a user on a French system runs the script, she will get
|
|
French messages.</para>
|
|
|
|
<note>
|
|
<para>With older versions of Bash or other shells, localization requires
|
|
<link linkend="gettextref">gettext</link>, using the
|
|
<option>-s</option> option. In this case, the script becomes:</para>
|
|
|
|
<para><anchor id="gettextexample">
|
|
<programlisting>#!/bin/bash
|
|
# localized.sh
|
|
|
|
E_CDERROR=65
|
|
|
|
error() {
|
|
local format=$1
|
|
shift
|
|
printf "$(gettext -s "$format")" "$@" >&2
|
|
exit $E_CDERROR
|
|
}
|
|
cd $var || error "Can't cd to %s." "$var"
|
|
read -p "$(gettext -s "Enter the value: ")" var
|
|
# ...</programlisting>
|
|
</para>
|
|
</note>
|
|
|
|
<para>The <varname>TEXTDOMAIN</varname> and
|
|
<varname>TEXTDOMAINDIR</varname> variables need to be set and
|
|
exported to the environment. This should be done within the
|
|
script itself.</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para>This appendix written by Stephane Chazelas, with modifications
|
|
suggested by Alfredo Pironti, and by Bruno Haible, maintainer
|
|
of GNU <link linkend="gettextref">gettext</link>.</para>
|
|
|
|
</appendix>
|
|
<!-- Localization -->
|
|
|
|
|
|
|
|
<appendix id="histcommands">
|
|
<title>History Commands</title>
|
|
|
|
<para>The Bash shell provides command-line tools for editing and
|
|
manipulating a user's <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>$HISTTIMEFORMAT (Bash, ver. 3.0 or later)</para></listitem>
|
|
<listitem><para>!!</para></listitem>
|
|
<listitem><para>!$</para></listitem>
|
|
<listitem><para>!#</para></listitem>
|
|
<listitem><para>!N</para></listitem>
|
|
<listitem><para>!-N</para></listitem>
|
|
<listitem><para>!STRING</para></listitem>
|
|
<listitem><para>!?STRING?</para></listitem>
|
|
<listitem><para>^STRING^string^</para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<para>Unfortunately, the Bash history tools find no use in scripting.
|
|
<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>
|
|
|
|
<para>The <ulink url="http://www.deadman.org/bash.html">Advancing in the
|
|
Bash Shell</ulink> site gives a good introduction to the use of
|
|
history commands in Bash.</para>
|
|
|
|
|
|
|
|
</appendix>
|
|
<!-- History Commands -->
|
|
|
|
|
|
<appendix id="sample-bashrc">
|
|
<title>A Sample <filename>.bashrc</filename> File</title>
|
|
|
|
<para>The <filename>~/.bashrc</filename> file determines the
|
|
behavior of interactive shells. A good look at this file can
|
|
lead to a better understanding of Bash.</para>
|
|
|
|
<para><ulink url="mailto:emmanuel.rouat@wanadoo.fr">Emmanuel
|
|
Rouat</ulink> contributed the following very elaborate
|
|
<filename>.bashrc</filename> file, written for a Linux system.
|
|
He welcomes reader feedback on it.</para>
|
|
|
|
<para>Study the file carefully, and feel free to reuse code
|
|
snippets and functions from it in your own
|
|
<filename>.bashrc</filename> file or even in your scripts.</para>
|
|
|
|
|
|
<example id="bashrc">
|
|
<title>Sample <filename>.bashrc</filename> file</title>
|
|
<programlisting>&bashrc;</programlisting>
|
|
</example>
|
|
|
|
</appendix>
|
|
<!-- End Sample .bashrc File appendix -->
|
|
|
|
|
|
<appendix id="dosbatch">
|
|
<title>Converting DOS Batch Files to Shell Scripts</title>
|
|
|
|
<para><anchor id="dosbatch1"></para>
|
|
<para>Quite a number of programmers learned scripting on a PC running
|
|
DOS. Even the crippled DOS batch file language allowed writing some
|
|
fairly powerful scripts and applications, though they often required
|
|
extensive kludges and workarounds. Occasionally, the need still
|
|
arises to convert an old DOS batch file to a UNIX shell script. This
|
|
is generally not difficult, as DOS batch file operators are only a
|
|
limited subset of the equivalent shell scripting ones.</para>
|
|
|
|
<table>
|
|
<title>Batch file keywords / variables / operators, and their shell equivalents</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Batch File Operator</entry>
|
|
<entry>Shell Script Equivalent</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>%</option></entry>
|
|
<entry>$</entry>
|
|
<entry>command-line parameter prefix</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>/</option></entry>
|
|
<entry>-</entry>
|
|
<entry>command option flag</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>\</option></entry>
|
|
<entry>/</entry>
|
|
<entry>directory path separator</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>==</option></entry>
|
|
<entry>=</entry>
|
|
<entry>(equal-to) string comparison test</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>!==!</option></entry>
|
|
<entry>!=</entry>
|
|
<entry>(not equal-to) string comparison test</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>|</option></entry>
|
|
<entry>|</entry>
|
|
<entry>pipe</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>@</option></entry>
|
|
<entry>set <option>+v</option></entry>
|
|
<entry>do not echo current command</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>*</option></entry>
|
|
<entry>*</entry>
|
|
<entry>filename <quote>wild card</quote></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>></option></entry>
|
|
<entry>></entry>
|
|
<entry>file redirection (overwrite)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>>></option></entry>
|
|
<entry>>></entry>
|
|
<entry>file redirection (append)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option><</option></entry>
|
|
<entry><</entry>
|
|
<entry>redirect <filename>stdin</filename></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%VAR%</option></entry>
|
|
<entry>$VAR</entry>
|
|
<entry>environmental variable</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>REM</option></entry>
|
|
<entry>#</entry>
|
|
<entry>comment</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>NOT</option></entry>
|
|
<entry>!</entry>
|
|
<entry>negate following test</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>NUL</option></entry>
|
|
<entry><filename>/dev/null</filename></entry>
|
|
<entry><quote>black hole</quote> for burying command output</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>ECHO</option></entry>
|
|
<entry>echo</entry>
|
|
<entry>echo (many more option in Bash)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>ECHO.</option></entry>
|
|
<entry>echo</entry>
|
|
<entry>echo blank line</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>ECHO OFF</option></entry>
|
|
<entry>set <option>+v</option></entry>
|
|
<entry>do not echo command(s) following</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>FOR %%VAR IN (LIST) DO</option></entry>
|
|
<entry>for var in [list]; do</entry>
|
|
<entry><quote>for</quote> loop</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>:LABEL</option></entry>
|
|
<entry>none (unnecessary)</entry>
|
|
<entry>label</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>GOTO</option></entry>
|
|
<entry>none (use a function)</entry>
|
|
<entry>jump to another location in the script</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>PAUSE</option></entry>
|
|
<entry>sleep</entry>
|
|
<entry>pause or wait an interval</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>CHOICE</option></entry>
|
|
<entry>case or select</entry>
|
|
<entry>menu choice</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>IF</option></entry>
|
|
<entry>if</entry>
|
|
<entry>if-test</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>IF EXIST <replaceable>FILENAME</replaceable></option></entry>
|
|
<entry>if [ -e filename ]</entry>
|
|
<entry>test if file exists</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>IF !%N==!</option></entry>
|
|
<entry>if [ -z "$N" ]</entry>
|
|
<entry>if replaceable parameter <quote>N</quote> not present</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>CALL</option></entry>
|
|
<entry>source or . (dot operator)</entry>
|
|
<entry><quote>include</quote> another script</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>COMMAND /C</option></entry>
|
|
<entry>source or . (dot operator)</entry>
|
|
<entry><quote>include</quote> another script (same as
|
|
CALL)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>SET</option></entry>
|
|
<entry>export</entry>
|
|
<entry>set an environmental variable</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>SHIFT</option></entry>
|
|
<entry>shift</entry>
|
|
<entry>left shift command-line argument list</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>SGN</option></entry>
|
|
<entry>-lt or -gt</entry>
|
|
<entry>sign (of integer)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>ERRORLEVEL</option></entry>
|
|
<entry>$?</entry>
|
|
<entry>exit status</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>CON</option></entry>
|
|
<entry><filename>stdin</filename></entry>
|
|
<entry><quote>console</quote> (<filename>stdin</filename>)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>PRN</option></entry>
|
|
<entry><filename>/dev/lp0</filename></entry>
|
|
<entry>(generic) printer device</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>LPT1</option></entry>
|
|
<entry><filename>/dev/lp0</filename></entry>
|
|
<entry>first printer device</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>COM1</option></entry>
|
|
<entry><filename>/dev/ttyS0</filename></entry>
|
|
<entry>first serial port</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
|
|
<para>Batch files usually contain DOS commands. These must be
|
|
translated into their UNIX equivalents in order to convert a
|
|
batch file into a shell script.</para>
|
|
|
|
<table>
|
|
<title>DOS commands and their UNIX equivalents</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>DOS Command</entry>
|
|
<entry>UNIX Equivalent</entry>
|
|
<entry>Effect</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>ASSIGN</option></entry>
|
|
<entry>ln</entry>
|
|
<entry>link file or directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>ATTRIB</option></entry>
|
|
<entry>chmod</entry>
|
|
<entry>change file permissions</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>CD</option></entry>
|
|
<entry>cd</entry>
|
|
<entry>change directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>CHDIR</option></entry>
|
|
<entry>cd</entry>
|
|
<entry>change directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>CLS</option></entry>
|
|
<entry>clear</entry>
|
|
<entry>clear screen</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>COMP</option></entry>
|
|
<entry>diff, comm, cmp</entry>
|
|
<entry>file compare</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>COPY</option></entry>
|
|
<entry>cp</entry>
|
|
<entry>file copy</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>Ctl-C</option></entry>
|
|
<entry>Ctl-C</entry>
|
|
<entry>break (signal)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>Ctl-Z</option></entry>
|
|
<entry>Ctl-D</entry>
|
|
<entry>EOF (end-of-file)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>DEL</option></entry>
|
|
<entry>rm</entry>
|
|
<entry>delete file(s)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>DELTREE</option></entry>
|
|
<entry>rm -rf</entry>
|
|
<entry>delete directory recursively</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>DIR</option></entry>
|
|
<entry>ls -l</entry>
|
|
<entry>directory listing</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>ERASE</option></entry>
|
|
<entry>rm</entry>
|
|
<entry>delete file(s)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>EXIT</option></entry>
|
|
<entry>exit</entry>
|
|
<entry>exit current process</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>FC</option></entry>
|
|
<entry>comm, cmp</entry>
|
|
<entry>file compare</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>FIND</option></entry>
|
|
<entry>grep</entry>
|
|
<entry>find strings in files</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>MD</option></entry>
|
|
<entry>mkdir</entry>
|
|
<entry>make directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>MKDIR</option></entry>
|
|
<entry>mkdir</entry>
|
|
<entry>make directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>MORE</option></entry>
|
|
<entry>more</entry>
|
|
<entry>text file paging filter</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>MOVE</option></entry>
|
|
<entry>mv</entry>
|
|
<entry>move</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>PATH</option></entry>
|
|
<entry>$PATH</entry>
|
|
<entry>path to executables</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>REN</option></entry>
|
|
<entry>mv</entry>
|
|
<entry>rename (move)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>RENAME</option></entry>
|
|
<entry>mv</entry>
|
|
<entry>rename (move)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>RD</option></entry>
|
|
<entry>rmdir</entry>
|
|
<entry>remove directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>RMDIR</option></entry>
|
|
<entry>rmdir</entry>
|
|
<entry>remove directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>SORT</option></entry>
|
|
<entry>sort</entry>
|
|
<entry>sort file</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>TIME</option></entry>
|
|
<entry>date</entry>
|
|
<entry>display system time</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>TYPE</option></entry>
|
|
<entry>cat</entry>
|
|
<entry>output file to <filename>stdout</filename></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>XCOPY</option></entry>
|
|
<entry>cp</entry>
|
|
<entry>(extended) file copy</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
<note>
|
|
<para>Virtually all UNIX and shell operators and commands have
|
|
many more options and enhancements than their DOS and batch file
|
|
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>
|
|
|
|
<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>
|
|
|
|
<para>Converting a DOS batch file into a shell script is generally
|
|
straightforward, and the result ofttimes reads better than the
|
|
original.</para>
|
|
|
|
<example id="VIEWDAT">
|
|
<title>VIEWDATA.BAT: DOS Batch File</title>
|
|
<programlisting>&VIEWDAT;</programlisting>
|
|
</example>
|
|
|
|
<para>The script conversion is somewhat of an improvement.</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 -->
|
|
|
|
|
|
<appendix id="exercises">
|
|
<title>Exercises</title>
|
|
|
|
<sect1 id="scriptanalysis">
|
|
<title>Analyzing Scripts</title>
|
|
|
|
<para>Examine the following script. Run it, then explain what it
|
|
does. Annotate the script and rewrite it in a more compact and
|
|
elegant manner.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
MAX=10000
|
|
|
|
|
|
for((nr=1; nr<$MAX; nr++))
|
|
do
|
|
|
|
let "t1 = nr % 5"
|
|
if [ "$t1" -ne 3 ]
|
|
then
|
|
continue
|
|
fi
|
|
|
|
let "t2 = nr % 7"
|
|
if [ "$t2" -ne 4 ]
|
|
then
|
|
continue
|
|
fi
|
|
|
|
let "t3 = nr % 9"
|
|
if [ "$t3" -ne 5 ]
|
|
then
|
|
continue
|
|
fi
|
|
|
|
break # What happens when you comment out this line? Why?
|
|
|
|
done
|
|
|
|
echo "Number = $nr"
|
|
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para>Explain what the following script does. It is really just
|
|
a parameterized command-line pipe.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
DIRNAME=/usr/bin
|
|
FILETYPE="shell script"
|
|
LOGFILE=logfile
|
|
|
|
file "$DIRNAME"/* | fgrep "$FILETYPE" | tee $LOGFILE | wc -l
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para>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 the variables
|
|
can be eliminated, and try to optimize the script to speed up
|
|
its execution time.</para>
|
|
|
|
<para>Alter the script so that it accepts any ordinary ASCII
|
|
text file as input for its initial <quote>generation</quote>. The
|
|
script will read the first <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>
|
|
|
|
<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>
|
|
|
|
<varlistentry>
|
|
<term><command>Changing the line spacing of a text file</command></term>
|
|
<listitem>
|
|
|
|
<para>Write a script that reads each line of a target file, then
|
|
writes the line back to <filename>stdout</filename>, but with
|
|
an extra blank line following. This has the effect of
|
|
<emphasis>double-spacing</emphasis> the file.</para>
|
|
|
|
<para>Include all necessary code to check whether the script
|
|
gets the necessary command line argument (a filename),
|
|
and whether the specified file exists.</para>
|
|
|
|
<para>When the script runs correctly, modify it to
|
|
<emphasis>triple-space</emphasis> the target file.</para>
|
|
|
|
<para>Finally, write a script to remove all blank lines from
|
|
the target file, <emphasis>single-spacing</emphasis> it.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Backwards Listing</command></term>
|
|
<listitem>
|
|
<para>Write a script that echoes itself to
|
|
<filename>stdout</filename>, but
|
|
<emphasis>backwards</emphasis>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Automatically Decompressing Files</command></term>
|
|
<listitem>
|
|
<para>Given a list of filenames as input, this script
|
|
queries each target file (parsing the output of the
|
|
<link linkend="fileref">file</link> command) for
|
|
the type of compression used on it. Then the script
|
|
automatically invokes the appropriate decompression command
|
|
(<command>gunzip</command>, <command>bunzip2</command>,
|
|
<command>unzip</command>, <command>uncompress</command>,
|
|
or whatever). If a target file is not compressed, the
|
|
script emits a warning message, but takes no other action
|
|
on that particular file.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Unique System ID</command></term>
|
|
<listitem>
|
|
<para>Generate a <quote>unique</quote> 6-digit hexadecimal
|
|
identifier for your computer. Do <emphasis>not</emphasis>
|
|
use the flawed <link linkend="hostidref">hostid</link>
|
|
command. Hint: <command><link
|
|
linkend="md5sumref">md5sum</link>
|
|
<filename>/etc/passwd</filename></command>, then select
|
|
the first 6 digits of output.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Backup</command></term>
|
|
<listitem>
|
|
<para>Archive as a <quote>tarball</quote>
|
|
(<filename>*.tar.gz</filename> file) all the files
|
|
in your home directory tree
|
|
(<filename>/home/your-name</filename>) that have
|
|
been modified in the last 24 hours. Hint: use <link
|
|
linkend="findref">find</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Primes</command></term>
|
|
<listitem>
|
|
<para>Print (to stdout) all prime numbers between 60000 and
|
|
63000. The output should be nicely formatted in columns
|
|
(hint: use <link linkend="printfref">printf</link>).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Lottery Numbers</command></term>
|
|
<listitem>
|
|
<para>One type of lottery involves picking five
|
|
different numbers, in the range of 1 - 50. Write a
|
|
script that generates five pseudorandom numbers in this
|
|
range, <emphasis>with no duplicates</emphasis>. The
|
|
script will give the option of echoing the numbers to
|
|
<filename>stdout</filename> or saving them to a file,
|
|
along with the date and time the particular number set
|
|
was generated.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="exmedium">
|
|
<title><anchor id="exmedium1">INTERMEDIATE</title>
|
|
|
|
<varlistentry>
|
|
<term><command>Integer or String</command></term>
|
|
<listitem>
|
|
<para>Write a script <link linkend="functionref">function</link>
|
|
that determines if an argument passed to it is an integer
|
|
or a string. The function will return TRUE (0) if
|
|
passed an integer, and FALSE (1) if passed a string.</para>
|
|
<para>Hint: What does the following expression return
|
|
when <varname>$1</varname> is <emphasis>not</emphasis> an
|
|
integer?</para>
|
|
<para><varname>expr $1 + 0</varname></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Managing Disk Space</command></term>
|
|
<listitem>
|
|
<para>List, one at a time, all files larger than 100K in
|
|
the <filename class="directory">/home/username</filename>
|
|
directory tree. Give the user the option to delete or
|
|
compress the file, then proceed to show the next one. Write
|
|
to a logfile the names of all deleted files and the
|
|
deletion times.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Enforcing Disk Quotas</command></term>
|
|
<listitem>
|
|
<para>Write a script for a multi-user system that checks users'
|
|
disk usage. If a user surpasses the preset limit
|
|
(100 MB, for example) in her <filename
|
|
class="directory">/home/username</filename> directory,
|
|
then the script will automatically send her a warning
|
|
e-mail.</para>
|
|
<para>The script will use the <link linkend="duref">du</link> and
|
|
<link linkend="commmail1">mail</link> commands.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Logged in User Information</command></term>
|
|
<listitem>
|
|
|
|
<para>For all logged in users, show their real names and the time
|
|
and date of their last login.</para>
|
|
|
|
<para>Hint: use <link linkend="whoref">who</link>,
|
|
<link linkend="lastlogref">lastlog</link>,
|
|
and parse <filename>/etc/passwd</filename>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Safe Delete</command></term>
|
|
<listitem>
|
|
<para>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>
|
|
|
|
<varlistentry>
|
|
<term><command>Making Change</command></term>
|
|
<listitem>
|
|
<para>What is the most efficient way to make change for $1.68,
|
|
using only coins in common circulations (up to 25c)? It's
|
|
6 quarters, 1 dime, a nickel, and three cents.</para>
|
|
<para>Given any arbitrary command line input in dollars and
|
|
cents ($*.??), calculate the change, using the minimum
|
|
number of coins. If your home country is not the United
|
|
States, you may use your local currency units instead. The
|
|
script will need to parse the command line input, then
|
|
change it to multiples of the smallest monetary unit (cents
|
|
or whatever). Hint: look at <xref linkend="ex61">.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Quadratic Equations</command></term>
|
|
<listitem>
|
|
<para>Solve a <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>
|
|
|
|
<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>
|
|
|
|
<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>Logging Logins</command></term>
|
|
<listitem>
|
|
<para>Parse <filename>/var/log/messages</filename> to
|
|
produce a nicely formatted file of user logins and login
|
|
times. The script may need to run as root. (Hint: Search
|
|
for the string <quote>LOGIN.</quote>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Pretty-Printing a Data File</command></term>
|
|
<listitem>
|
|
<para>Certain database and spreadsheet packages use save-files
|
|
with <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>
|
|
|
|
<varlistentry>
|
|
<term><command>Justification</command></term>
|
|
<listitem>
|
|
<para>Given ASCII text input either from
|
|
<filename>stdin</filename> or a file, adjust
|
|
the word spacing to right-justify each line to a
|
|
user-specified line-width, then send the output to
|
|
<filename>stdout</filename>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Mailing List</command></term>
|
|
<listitem>
|
|
<para>Using the <link linkend="commmail1">mail</link> command,
|
|
write a script that manages a simple mailing list. The
|
|
script automatically e-mails the monthly company newsletter,
|
|
read from a specified text file, and sends it to all the
|
|
addresses on the mailing list, which the script reads from
|
|
another specified file.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Generating Passwords</command></term>
|
|
<listitem>
|
|
<para>Generate pseudorandom 8-character passwords, using
|
|
characters in the ranges [0-9], [A-Z], [a-z]. Each password
|
|
must contain at least two digits.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="exdifficult">
|
|
<title><anchor id="exdifficult1">DIFFICULT</title>
|
|
|
|
<varlistentry>
|
|
<term><command>Testing Passwords</command></term>
|
|
<listitem>
|
|
<para>Write a script to check and validate passwords. The object
|
|
is to flag <quote>weak</quote> or easily guessed password
|
|
candidates.</para>
|
|
|
|
<para>A trial password will be input to the script as a
|
|
command line parameter. To be considered acceptable,
|
|
a password must meet the following minimum qualifications:
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Minimum length of 8 characters</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Must contain at least one numeric character</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Must contain at least one of the following
|
|
non-alphabetic characters: <token>@</token>,
|
|
<token>#</token>, <token>$</token>, <token>%</token>,
|
|
<token>&</token>, <token>*</token>, <token>+</token>,
|
|
<token>-</token>, <token>=</token></para>
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>Optional:
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Do a dictionary check on every sequence of at least
|
|
four consecutive alphabetic characters in the password under
|
|
test. This will eliminate passwords containing embedded
|
|
<quote>words</quote> found in a standard dictionary.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Enable the script to check all the passwords on your
|
|
system. These may or may not reside in
|
|
<filename>/etc/passwd</filename>.</para>
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>This exercise tests mastery of <link
|
|
linkend="regexref">Regular Expressions</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>Logging File Accesses</command></term>
|
|
<listitem>
|
|
<para>Log all accesses to the files in <filename
|
|
class="directory">/etc</filename> during the course of
|
|
a single day. This information should include the filename,
|
|
user name, and access time. If any alterations to the
|
|
files take place, that should be flagged. Write this data
|
|
as neatly formatted records in a logfile.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Monitoring Processes</command></term>
|
|
<listitem>
|
|
<para>Write a script to continually monitor all running
|
|
processes and to keep track of how many child processes each
|
|
parent spawns. If a process spawns more than five children,
|
|
then the script sends an e-mail to the system administrator
|
|
(or root) with all relevant information, including the
|
|
time, PID of the parent, PIDs of the children, etc. The
|
|
script writes a report to a log file every ten minutes.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Strip Comments</command></term>
|
|
<listitem>
|
|
<para>Strip all comments from a shell script whose name
|
|
is specified on the command line. Note that the <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>
|
|
|
|
<varlistentry>
|
|
<term><command>XML Conversion</command></term>
|
|
<listitem>
|
|
<para>Convert an XML file to both HTML and text format.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cspammers"><command>Chasing Spammers</command></term>
|
|
<listitem>
|
|
|
|
<para> Write a script that analyzes a spam e-mail by doing
|
|
DNS lookups on the IP addresses in the headers to identify
|
|
the relay hosts as well as the originating ISP. The
|
|
script will forward the unaltered spam message to the
|
|
responsible ISPs. Of course, it will be necessary to
|
|
filter out <emphasis>your own ISP's IP address</emphasis>,
|
|
so you don't end up complaining about yourself.</para>
|
|
|
|
<para>As necessary, use the appropriate <link
|
|
linkend="communinfo1">network analysis commands</link>.</para>
|
|
|
|
<para>For some ideas, see <xref linkend="isspammer"> and <xref
|
|
linkend="isspammer2">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Creating man pages</command></term>
|
|
<listitem>
|
|
|
|
<para>Write a script that automates the process of creating
|
|
<emphasis>man pages</emphasis>.</para>
|
|
|
|
<para>Given a text file which contains information to be
|
|
formatted into a <emphasis>man page</emphasis>, the
|
|
script will read the file, then invoke the appropriate
|
|
<link linkend="groffref">groff</link> commands to
|
|
output the corresponding <emphasis>man page</emphasis>
|
|
to <filename>stdout</filename>. The text file contains
|
|
blocks of information under the standard <emphasis>man
|
|
page</emphasis> headings, i.e., <quote>NAME,</quote>
|
|
<quote>SYNOPSIS,</quote> <quote>DESCRIPTION,</quote>
|
|
etc.</para>
|
|
|
|
<para>See <xref linkend="manview">.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Morse Code</command></term>
|
|
<listitem>
|
|
<para>Convert a text file to Morse code. Each character of the
|
|
text file will be represented as a corresponding Morse
|
|
code group of dots and dashes (underscores), separated by
|
|
whitespace from the next. For example, <quote>script</quote>
|
|
===> <quote>... _._. ._. .. .__. _</quote>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Hex Dump</command></term>
|
|
<listitem>
|
|
<para>Do a hex(adecimal) dump on a binary file
|
|
specified as an argument. The output should be in neat
|
|
tabular fields, with the first field showing the address,
|
|
each of the next 8 fields a 4-byte hex number, and the final
|
|
field the ASCII equivalent of the previous 8 fields.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Emulating a Shift Register</command></term>
|
|
<listitem>
|
|
<para>Using <xref linkend="stackex"> as an inspiration,
|
|
write a script that emulates a 64-bit shift register as
|
|
an <link linkend="arrayref">array</link>. Implement
|
|
functions to <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>
|
|
|
|
<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>
|
|
<para>Optional: Write a script that <emphasis>solves</emphasis>
|
|
word-find puzzles. To keep this from becoming too difficult,
|
|
the solution script will find only horizontal and vertical
|
|
words. (Hint: Treat each row and column as a string, and
|
|
search for substrings.)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Anagramming</command></term>
|
|
<listitem>
|
|
<para> Anagram 4-letter input. For example, the
|
|
anagrams of <emphasis>word</emphasis> are:
|
|
<emphasis>do or rod row word</emphasis>. You may use
|
|
<filename>/usr/share/dict/linux.words</filename> as the
|
|
reference list.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><quote><command>Word Ladders</command></quote></term>
|
|
<listitem>
|
|
<para>A <quote>word ladder</quote> is a sequence of words,
|
|
with each successive word in the sequence differing from
|
|
the previous one by a single letter.</para>
|
|
|
|
<para>For example, to <quote>ladder</quote> from
|
|
<emphasis>mark</emphasis> to
|
|
<emphasis>vase</emphasis>:</para>
|
|
|
|
<para>
|
|
<programlisting>mark --> park --> part --> past --> vast --> vase</programlisting>
|
|
</para>
|
|
|
|
<para>Write a script that solves <quote>word ladder</quote>
|
|
puzzles. Given a starting and an ending word,
|
|
the script will list all intermediate steps in the
|
|
<quote>ladder</quote>. Note that <emphasis>all</emphasis>
|
|
words in the sequence must be <quote>legal.</quote></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Fog Index</command></term>
|
|
<listitem>
|
|
|
|
<para>The <quote>fog index</quote> of a passage of text
|
|
estimates its reading difficulty, as a number corresponding
|
|
roughly to a school grade level. For example, a passage
|
|
with a fog index of 12 should be comprehensible to anyone
|
|
with 12 years of schooling.</para>
|
|
|
|
<para>The Gunning version of the fog index uses the following
|
|
algorithm.</para>
|
|
|
|
<orderedlist>
|
|
|
|
<listitem><para>Choose a section of the text at least
|
|
100 words in length.</para></listitem>
|
|
|
|
<listitem><para>Count the number of sentences (a portion of
|
|
a sentence truncated by the boundary of the text section
|
|
counts as one).</para></listitem>
|
|
|
|
<listitem>
|
|
<para>Find the average number of words per
|
|
sentence.</para>
|
|
|
|
<para>AVE_WDS_SEN = TOTAL_WORDS / SENTENCES</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Count the number of <quote>difficult</quote>
|
|
words in the segment -- those containing at least
|
|
3 syllables. Divide this quantity by total words to
|
|
get the proportion of difficult words.</para>
|
|
|
|
<para>PRO_DIFF_WORDS = LONG_WORDS / TOTAL_WORDS</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The Gunning fog index is the sum of the above two
|
|
quantities, multiplied by 0.4, then rounded to the
|
|
nearest integer.</para>
|
|
|
|
<para>G_FOG_INDEX = int ( 0.4 * ( AVE_WDS_SEN + PRO_DIFF_WORDS ) )</para>
|
|
</listitem>
|
|
|
|
</orderedlist>
|
|
|
|
<para>Step 4 is by far the most difficult portion of the
|
|
exercise. There exist various algorithms for estimating
|
|
the syllable count of a word. A rule-of-thumb formula
|
|
might consider the number of letters in a word and the
|
|
vowel-consonant mix.</para>
|
|
|
|
<para>A strict interpretation of the Gunning Fog index does
|
|
not count compound words and proper nouns as
|
|
<quote>difficult</quote> words, but this would enormously
|
|
complicate the script.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Calculating PI using Buffon's Needle</command></term>
|
|
<listitem>
|
|
|
|
<para>The Eighteenth Century French mathematician de Buffon
|
|
came up with a novel experiment. Repeatedly drop a
|
|
needle of length <quote>n</quote> onto a wooden floor
|
|
composed of long and narrow parallel boards. The cracks
|
|
separating the equal-width floorboards are a fixed distance
|
|
<quote>d</quote> apart. Keep track of the total drops and
|
|
the number of times the needle intersects a crack on the
|
|
floor. The ratio of these two quantities turns out to be
|
|
a fractional multiple of PI.</para>
|
|
|
|
<para>In the spirit of <xref linkend="cannon">, write a
|
|
script that runs a Monte Carlo simulation of Buffon's
|
|
Needle. To simplify matters, set the needle length equal to
|
|
the distance between the cracks, <emphasis>n = d</emphasis>.</para>
|
|
|
|
<para>Hint: there are actually two critical variables:
|
|
the distance from the center of the needle to the crack
|
|
nearest to it, and the angle of the needle to that
|
|
crack. You may use <link linkend="bcref">bc</link> to
|
|
handle the calculations.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Playfair Cipher</command></term>
|
|
<listitem>
|
|
|
|
<para>Implement the Playfair (Wheatstone) Cipher in a
|
|
script.</para>
|
|
|
|
<para>The Playfair Cipher encrypts text by substitution
|
|
of <quote>digrams</quote> (2-letter groupings). It is
|
|
traditional to use a 5 x 5 letter scrambled-alphabet
|
|
<emphasis>key square</emphasis> for the encryption and
|
|
decryption.</para>
|
|
|
|
<para>
|
|
<programlisting> C O D E S
|
|
A B F G H
|
|
I K L M N
|
|
P Q R T U
|
|
V W X Y Z
|
|
|
|
Each letter of the alphabet appears once, except "I" also represents
|
|
"J". The arbitrarily chosen key word, "CODES" comes first, then all
|
|
the rest of the alphabet, in order from left to right, skipping letters
|
|
already used.
|
|
|
|
To encrypt, separate the plaintext message into digrams (2-letter
|
|
groups). If a group has two identical letters, delete the second, and
|
|
form a new group. If there is a single letter left over at the end,
|
|
insert a "null" character, typically an "X".
|
|
|
|
THIS IS A TOP SECRET MESSAGE
|
|
|
|
TH IS IS AT OP SE CR ET ME SA GE
|
|
|
|
For each digram, there are three possibilities.
|
|
----------------------------------------------
|
|
1) Both letters will be on the same row of the key square
|
|
For each letter, substitute the one immediately to the right, in that
|
|
row. If necessary, wrap around left to the beginning of the row.
|
|
|
|
or
|
|
|
|
2) Both letters will be in the same column of the key square
|
|
For each letter, substitute the one immediately below it, in that
|
|
row. If necessary, wrap around to the top of the column.
|
|
|
|
or
|
|
|
|
3) Both letters will form the corners of a rectangle within the key
|
|
square. For each letter, substitute the one on the other corner the
|
|
rectangle which lies on the same row.
|
|
|
|
|
|
The "TH" digram falls under case #3.
|
|
G H
|
|
M N
|
|
T U (Rectangle with "T" and "H" at corners)
|
|
|
|
T --> U
|
|
H --> G
|
|
|
|
|
|
The "SE" digram falls under case #1.
|
|
C O D E S (Row containing "S" and "E")
|
|
|
|
S --> C (wraps around left to beginning of row)
|
|
E --> S
|
|
|
|
=========================================================================
|
|
|
|
To decrypt encrypted text, reverse the above procedure under cases #1
|
|
and #2 (move in opposite direction for substitution). Under case #3,
|
|
just take the remaining two corners of the rectangle.
|
|
|
|
|
|
Helen Fouche Gaines' classic work, "Elementary Cryptanalysis" (1939), gives a
|
|
fairly detailed 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>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<para>--</para>
|
|
<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>
|
|
|
|
|
|
</sect1>
|
|
<!-- End Writing Scripts section -->
|
|
|
|
</appendix>
|
|
<!-- End Exercises appendix -->
|
|
|
|
|
|
|
|
<appendix id="revisionhistory">
|
|
<title>Revision History</title>
|
|
|
|
<synopsis>
|
|
This document first appeared as a HOWTO in the late spring
|
|
of 2000. Since then, it has gone through many updates and
|
|
revisions. This book could not have been written without the
|
|
assistance of the Linux community, and especially of the volunteers of
|
|
the <ulink url="http://www.tldp.org">Linux Documentation Project</ulink>.
|
|
</synopsis>
|
|
|
|
|
|
<table frame=none>
|
|
<title>Revision History</title>
|
|
<tgroup cols="3" colsep=0 rowsep=0>
|
|
<thead>
|
|
<row>
|
|
<entry>Release</entry>
|
|
<entry>Date</entry>
|
|
<entry>Comments</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>0.1</entry>
|
|
<entry>14 Jun 2000</entry>
|
|
<entry>Initial release.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>0.2</option></entry>
|
|
<entry>30 Oct 2000</entry>
|
|
<entry>Bugs fixed, plus much additional material and more
|
|
example scripts.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>0.3</option></entry>
|
|
<entry>12 Feb 2001</entry>
|
|
<entry>Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>0.4</option></entry>
|
|
<entry>08 Jul 2001</entry>
|
|
<entry>Complete revision and expansion of the book.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>0.5</option></entry>
|
|
<entry>03 Sep 2001</entry>
|
|
<entry>Major update: Bugfixes, material added,
|
|
sections reorganized.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.0</option></entry>
|
|
<entry>14 Oct 2001</entry>
|
|
<entry>Stable release: Bugfixes, reorganization, material
|
|
added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.1</option></entry>
|
|
<entry>06 Jan 2002</entry>
|
|
<entry>Bugfixes, material and scripts added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.2</option></entry>
|
|
<entry>31 Mar 2002</entry>
|
|
<entry>Bugfixes, material and scripts added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.3</option></entry>
|
|
<entry>02 Jun 2002</entry>
|
|
<entry>TANGERINE release: A few bugfixes, much more material and
|
|
scripts added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.4</option></entry>
|
|
<entry>16 Jun 2002</entry>
|
|
<entry>MANGO release: A number of typos fixed, more
|
|
material and scripts.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.5</option></entry>
|
|
<entry>13 Jul 2002</entry>
|
|
<entry>PAPAYA release: A few bugfixes, much more material and
|
|
scripts added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.6</option></entry>
|
|
<entry>29 Sep 2002</entry>
|
|
<entry>POMEGRANATE release: Bugfixes, more material,
|
|
one more script.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.7</option></entry>
|
|
<entry>05 Jan 2003</entry>
|
|
<entry>COCONUT release: A couple of bugfixes, more material,
|
|
one more script.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.8</option></entry>
|
|
<entry>10 May 2003</entry>
|
|
<entry>BREADFRUIT release: A number of bugfixes, more scripts and
|
|
material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.9</option></entry>
|
|
<entry>21 Jun 2003</entry>
|
|
<entry>PERSIMMON release: Bugfixes, and more material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.0</option></entry>
|
|
<entry>24 Aug 2003</entry>
|
|
<entry>GOOSEBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.1</option></entry>
|
|
<entry>14 Sep 2003</entry>
|
|
<entry>HUCKLEBERRY release: Bugfixes, and more material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.2</option></entry>
|
|
<entry>31 Oct 2003</entry>
|
|
<entry>CRANBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.3</option></entry>
|
|
<entry>03 Jan 2004</entry>
|
|
<entry>STRAWBERRY release: Bugfixes and more material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.4</option></entry>
|
|
<entry>25 Jan 2004</entry>
|
|
<entry>MUSKMELON release: Bugfixes.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.5</option></entry>
|
|
<entry>15 Feb 2004</entry>
|
|
<entry>STARFRUIT release: Bugfixes and more material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.6</option></entry>
|
|
<entry>15 Mar 2004</entry>
|
|
<entry>SALAL release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.7</option></entry>
|
|
<entry>18 Apr 2004</entry>
|
|
<entry>MULBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.8</option></entry>
|
|
<entry>11 Jul 2004</entry>
|
|
<entry>ELDERBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.0</option></entry>
|
|
<entry>03 Oct 2004</entry>
|
|
<entry>LOGANBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.1</option></entry>
|
|
<entry>14 Nov 2004</entry>
|
|
<entry>BAYBERRY release: Bugfix update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.2</option></entry>
|
|
<entry>06 Feb 2005</entry>
|
|
<entry>BLUEBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.3</option></entry>
|
|
<entry>20 Mar 2005</entry>
|
|
<entry>RASPBERRY release: Bugfixes, much material added.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
</appendix> <!-- End Revision History appendix -->
|
|
|
|
<appendix id="mirrorsites">
|
|
<title>Mirror Sites</title>
|
|
|
|
<para><ulink
|
|
url="http://personal.riverusers.com/~thegrendel/abs-guide-3.0.tar.bz2">
|
|
The latest update of this document</ulink>, as an archived
|
|
<quote>tarball</quote>
|
|
including both the SGML source and rendered HTML, may
|
|
be downloaded from the author's home site.</para>
|
|
|
|
<para>The main mirror site for this document is the <ulink
|
|
url="http://www.tldp.org/LDP/abs/">Linux Documentation Project</ulink>,
|
|
which maintains many other Guides and HOWTOs as well.</para>
|
|
|
|
<para><ulink
|
|
url="http://www.ibiblio.org/pub/Linux/docs/linux-doc-project/abs-guide/">Sunsite/Metalab/ibiblio.org</ulink>
|
|
also mirrors the <emphasis>ABS Guide</emphasis>.</para>
|
|
|
|
<para>Yet another mirror site for this document is
|
|
<ulink url="ftp://ftp.morethan.org">the morethan.org ftp site</ulink>.</para>
|
|
|
|
|
|
</appendix> <!-- Mirror Sites appendix -->
|
|
|
|
|
|
<appendix id="todolist">
|
|
<title>To Do List</title>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>A comprehensive survey of incompatibilities between Bash
|
|
and the classic Bourne shell.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Same as above, but for the Korn shell (ksh).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>A primer on CGI programming, using Bash.</para>
|
|
|
|
<para>Here's a simple CGI script to get you started.</para>
|
|
|
|
<example id="testcgi">
|
|
<title>Print the server environment</title>
|
|
<programlisting>&testcgi;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Any volunteers?</para>
|
|
|
|
</appendix> <!-- End Todo List appendix -->
|
|
|
|
|
|
<appendix id="copyright">
|
|
<title>Copyright</title>
|
|
|
|
<para>The <citetitle pubwork="book">Advanced Bash Scripting
|
|
Guide</citetitle> is <trademark class=copyright>copyright
|
|
</trademark> 2000, by Mendel Cooper. The author also asserts
|
|
copyright on all previous versions of this document.</para>
|
|
|
|
<para>This blanket copyright recognizes and protects the rights of the
|
|
contributors to this document.</para>
|
|
|
|
|
|
<para>This document may only be distributed subject to the terms
|
|
and conditions set forth in the Open Publication
|
|
License (version 1.0 or later), <ulink url="
|
|
http://www.opencontent.org/openpub/">http://www.opencontent.org/openpub/</ulink>.
|
|
The following license options also apply.
|
|
</para>
|
|
|
|
<para><programlisting>A. Distribution of substantively modified versions of this document
|
|
is 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>
|
|
|
|
<para><emphasis>Provision A</emphasis>, above, explicitly prohibits
|
|
<emphasis>relabeling</emphasis> this document. An example of
|
|
relabeling is the insertion of company logos or navigation bars
|
|
into the cover, title page, or the text. The author grants the
|
|
following exemptions.</para>
|
|
|
|
<orderedlist>
|
|
|
|
<listitem>
|
|
<para>Non-profit organizations, such as the <ulink
|
|
url="http://www.tldp.org">Linux Documentation Project</ulink>
|
|
and <ulink url="http://ibiblio.org">Sunsite</ulink>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><quote>Pure-play</quote> Linux distributors, such as Debian,
|
|
Red Hat, Mandrake, SuSE, and others.</para>
|
|
</listitem>
|
|
|
|
</orderedlist>
|
|
|
|
<para>Without explicit written permission from the author,
|
|
distributors and publishers (including on-line publishers) are
|
|
prohibited from imposing any additional conditions, strictures,
|
|
or provisions on this document or any previous version of it. As of
|
|
this update, the author asserts that he has <emphasis>not</emphasis>
|
|
entered into any contractual obligations that would alter the
|
|
foregoing declarations.</para>
|
|
|
|
<para>Essentially, you may freely distribute this book in
|
|
<emphasis>unaltered</emphasis> electronic form. You must obtain
|
|
the author's permission to distribute a substantially modified
|
|
version or derivative work. The purpose of this restriction is to
|
|
preserve the artistic integrity of this document and to prevent
|
|
<quote>forking.</quote></para>
|
|
|
|
<para>If you display or distribute this document or any previous
|
|
version thereof under any license except the one above, then you
|
|
are required to obtain the author's written permission. Failure
|
|
to do so may terminate your distribution rights.</para>
|
|
|
|
<para>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 classroom and instructional
|
|
purposes.</para>
|
|
|
|
<note><para>Certain of the scripts contained in this document are,
|
|
where noted, released into the Public Domain. These scripts are
|
|
exempt from the foregoing license and copyright
|
|
restrictions.</para></note>
|
|
|
|
<para>The commercial print and other rights to this book are
|
|
available. Please contact <ulink
|
|
url="mailto:thegrendel@theriver.com">the author</ulink> if
|
|
interested.</para>
|
|
|
|
<para>The author produced this book in a manner consistent with the
|
|
spirit of the <ulink url="http://www.tldp.org/manifesto.html">LDP
|
|
Manifesto</ulink>.</para>
|
|
|
|
|
|
<sidebar>
|
|
<para>Linux is a trademark registered to Linus Torvalds.</para>
|
|
<para>Unix and UNIX are trademarks registered to the Open Group.</para>
|
|
<para>MS Windows is a trademark registered to the Microsoft Corp.</para>
|
|
<para>Pentium is a trademark registered to Intel, Inc.</para>
|
|
<para>Scrabble is a trademark registered to Hasbro, Inc.</para>
|
|
<para>All other commercial trademarks mentioned in the body of this work
|
|
are registered to their respective owners.</para>
|
|
</sidebar>
|
|
|
|
|
|
<para>Hyun Jin Cha has done a <ulink
|
|
url="http://kldp.org/HOWTO/html/Adv-Bash-Scr-HOWTO/index.html">Korean
|
|
translation</ulink> of version 1.0.11 of this book. Spanish,
|
|
Portuguese, <ulink url="http://abs.ptithibou.org/">French</ulink>,
|
|
<ulink url="http://abs.traduc.org/">(another French)</ulink>,
|
|
German, <ulink
|
|
url="http://it.tldp.org/guide/abs/index.html">Italian</ulink>,
|
|
<ulink
|
|
url="http://gazette.linux.ru.net/rus/articles/index-abs-guide.html">Russian</ulink>,
|
|
Chinese, and Dutch translations are also available or in
|
|
progress. If you wish to translate this document into another
|
|
language, please feel free to do so, subject to the terms stated
|
|
above. The author wishes to be notified of such efforts.</para>
|
|
|
|
|
|
</appendix> <!-- End Copyright appendix -->
|
|
|
|
|
|
<!-- Uncomment line below to generate index. -->
|
|
<!--
|
|
&indice;
|
|
-->
|
|
|
|
</book>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-indent-step:2
|
|
sgml-indent-data:t
|
|
End:
|
|
-->
|