mirror of https://github.com/tLDP/LDP
40334 lines
1.3 MiB
40334 lines
1.3 MiB
<?xml version='1.0' encoding='utf-8'?>
|
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
|
|
[
|
|
|
|
<!ENTITY INDEX00 SYSTEM "INDEX00.xml">
|
|
<!ENTITY TABEXP SYSTEM "TABEXP.xml">
|
|
<!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 ex56py SYSTEM "ex56py.sh">
|
|
<!ENTITY ex57 SYSTEM "ex57.sh">
|
|
<!ENTITY ex58 SYSTEM "ex58.sh">
|
|
<!ENTITY ex59 SYSTEM "ex59.sh">
|
|
<!ENTITY ex60 SYSTEM "ex60.sh">
|
|
<!ENTITY ex61 SYSTEM "ex61.sh">
|
|
<!ENTITY ex62 SYSTEM "ex62.sh">
|
|
<!ENTITY ex63 SYSTEM "ex63.sh">
|
|
<!ENTITY ex64 SYSTEM "ex64.sh">
|
|
<!ENTITY ex65 SYSTEM "ex65.sh">
|
|
<!ENTITY ex66 SYSTEM "ex66.sh">
|
|
<!ENTITY ex67 SYSTEM "ex67.sh">
|
|
<!ENTITY ex68 SYSTEM "ex68.sh">
|
|
<!ENTITY ex68a SYSTEM "ex68a.sh">
|
|
<!ENTITY ex69 SYSTEM "ex69.sh">
|
|
<!ENTITY ex70 SYSTEM "ex70.sh">
|
|
<!ENTITY ex71 SYSTEM "ex71.sh">
|
|
<!ENTITY ex71a SYSTEM "ex71a.sh">
|
|
<!ENTITY ex71b SYSTEM "ex71b.sh">
|
|
<!ENTITY ex71c SYSTEM "ex71c.sh">
|
|
<!ENTITY ex72 SYSTEM "ex72.sh">
|
|
<!ENTITY ex73 SYSTEM "ex73.sh">
|
|
<!ENTITY ex74 SYSTEM "ex74.sh">
|
|
<!ENTITY ex75 SYSTEM "ex75.sh">
|
|
<!ENTITY ex76 SYSTEM "ex76.sh">
|
|
<!ENTITY ex77 SYSTEM "ex77.sh">
|
|
<!ENTITY ex78 SYSTEM "ex78.sh">
|
|
<!ENTITY cards SYSTEM "cards.sh">
|
|
<!ENTITY andor SYSTEM "and-or.sh">
|
|
<!ENTITY lnum SYSTEM "line-number.sh">
|
|
<!ENTITY manview SYSTEM "manview.sh">
|
|
<!ENTITY rfe SYSTEM "rfe.sh">
|
|
<!ENTITY behead SYSTEM "behead.sh">
|
|
<!ENTITY encryptedpw SYSTEM "encryptedpw.sh">
|
|
<!ENTITY rpmcheck SYSTEM "rpm-check.sh">
|
|
<!ENTITY subshell SYSTEM "subshell.sh">
|
|
<!ENTITY lowercase SYSTEM "lowercase.sh">
|
|
<!ENTITY online SYSTEM "online.sh">
|
|
<!ENTITY reply SYSTEM "reply.sh">
|
|
<!ENTITY seconds SYSTEM "seconds.sh">
|
|
<!ENTITY numbers SYSTEM "numbers.sh">
|
|
<!ENTITY indref SYSTEM "ind-ref.sh">
|
|
<!ENTITY bubble SYSTEM "bubble.sh">
|
|
<!ENTITY paramsub SYSTEM "param-sub.sh">
|
|
<!ENTITY restricted SYSTEM "restricted.sh">
|
|
<!ENTITY pw SYSTEM "pw.sh">
|
|
<!ENTITY rn SYSTEM "rn.sh">
|
|
<!ENTITY coltotaler SYSTEM "col-totaler.sh">
|
|
<!ENTITY coltotaler2 SYSTEM "col-totaler2.sh">
|
|
<!ENTITY coltotaler3 SYSTEM "col-totaler3.sh">
|
|
<!ENTITY tmdin SYSTEM "timed-input.sh">
|
|
<!ENTITY fifo SYSTEM "fifo.sh">
|
|
<!ENTITY tree SYSTEM "tree.sh">
|
|
<!ENTITY tree2 SYSTEM "tree2.sh">
|
|
<!ENTITY secretpw SYSTEM "secret-pw.sh">
|
|
<!ENTITY stripc SYSTEM "strip-comments.sh">
|
|
<!ENTITY al SYSTEM "alias.sh">
|
|
<!ENTITY unal SYSTEM "unalias.sh">
|
|
<!ENTITY redir1 SYSTEM "redir1.sh">
|
|
<!ENTITY redir2 SYSTEM "redir2.sh">
|
|
<!ENTITY redir2a SYSTEM "redir2a.sh">
|
|
<!ENTITY redir3 SYSTEM "redir3.sh">
|
|
<!ENTITY redir4 SYSTEM "redir4.sh">
|
|
<!ENTITY redir4a SYSTEM "redir4a.sh">
|
|
<!ENTITY redir5 SYSTEM "redir5.sh">
|
|
<!ENTITY wipedir SYSTEM "wipedir.sh">
|
|
<!ENTITY grp SYSTEM "grp.sh">
|
|
<!ENTITY killprocess SYSTEM "kill-process.sh">
|
|
<!ENTITY killbyname SYSTEM "kill-byname.sh">
|
|
<!ENTITY strtest SYSTEM "str-test.sh">
|
|
<!ENTITY colm SYSTEM "colm.sh">
|
|
<!ENTITY lookup SYSTEM "lookup.sh">
|
|
<!ENTITY arglist SYSTEM "arglist.sh">
|
|
<!ENTITY rot13 SYSTEM "rot13.sh">
|
|
<!ENTITY rot13a SYSTEM "rot13a.sh">
|
|
<!ENTITY rot14 SYSTEM "rot14.sh">
|
|
<!ENTITY filecomp SYSTEM "file-comparison.sh">
|
|
<!ENTITY adddrv SYSTEM "add-drive.sh">
|
|
<!ENTITY whloopc SYSTEM "wh-loopc.sh">
|
|
<!ENTITY forloopc SYSTEM "for-loopc.sh">
|
|
<!ENTITY forloopcmd SYSTEM "for-loopcmd.sh">
|
|
<!ENTITY cvars SYSTEM "c-vars.sh">
|
|
<!ENTITY bingrep SYSTEM "bin-grep.sh">
|
|
<!ENTITY mailformat SYSTEM "mail-format.sh">
|
|
<!ENTITY symlinks SYSTEM "symlinks.sh">
|
|
<!ENTITY symlinks2 SYSTEM "symlinks2.sh">
|
|
<!ENTITY string SYSTEM "string.sh">
|
|
<!ENTITY nestedloop SYSTEM "nested-loop.sh">
|
|
<!ENTITY casecmd SYSTEM "case-cmd.sh">
|
|
<!ENTITY uns SYSTEM "unset.sh">
|
|
<!ENTITY base SYSTEM "base.sh">
|
|
<!ENTITY allprofs SYSTEM "allprofs.sh">
|
|
<!ENTITY pidid SYSTEM "pid-identifier.sh">
|
|
<!ENTITY constat SYSTEM "connect-stat.sh">
|
|
<!ENTITY subpit SYSTEM "subshell-pitfalls.sh">
|
|
<!ENTITY readredir SYSTEM "read-redir.sh">
|
|
<!ENTITY andlist2 SYSTEM "and-list2.sh">
|
|
<!ENTITY qfunction SYSTEM "q-function.sh">
|
|
<!ENTITY viewdata SYSTEM "viewdata.sh">
|
|
<!ENTITY VIEWDAT SYSTEM "VIEWDATA.BAT">
|
|
<!ENTITY what SYSTEM "what.sh">
|
|
<!ENTITY max SYSTEM "max.sh">
|
|
<!ENTITY max2 SYSTEM "max2.sh">
|
|
<!ENTITY findstring SYSTEM "findstring.sh">
|
|
<!ENTITY listglob SYSTEM "list-glob.sh">
|
|
<!ENTITY realname SYSTEM "realname.sh">
|
|
<!ENTITY escaped SYSTEM "escaped.sh">
|
|
<!ENTITY fileinfo SYSTEM "file-info.sh">
|
|
<!ENTITY fileinfo01 SYSTEM "file-info01.sh">
|
|
<!ENTITY weirdvars SYSTEM "weirdvars.sh">
|
|
<!ENTITY breaklevels SYSTEM "break-levels.sh">
|
|
<!ENTITY copycd SYSTEM "copy-cd.sh">
|
|
<!ENTITY arithops SYSTEM "arith-ops.sh">
|
|
<!ENTITY continuelevels SYSTEM "continue-nlevel.sh">
|
|
<!ENTITY timeout SYSTEM "timeout.sh">
|
|
<!ENTITY randomtest SYSTEM "random-test.sh">
|
|
<!ENTITY seedingrandom SYSTEM "seeding-random.sh">
|
|
<!ENTITY pattmatching SYSTEM "patt-matching.sh">
|
|
<!ENTITY isalpha SYSTEM "isalpha.sh">
|
|
<!ENTITY rnd SYSTEM "rnd.sh">
|
|
<!ENTITY du SYSTEM "Du.sh">
|
|
<!ENTITY refparams SYSTEM "ref-params.sh">
|
|
<!ENTITY indfunc SYSTEM "ind-func.sh">
|
|
<!ENTITY primes SYSTEM "primes.sh">
|
|
<!ENTITY primes2 SYSTEM "primes2.sh">
|
|
<!ENTITY vartrace SYSTEM "vartrace.sh">
|
|
<!ENTITY amiroot SYSTEM "am-i-root.sh">
|
|
<!ENTITY twodim SYSTEM "twodim.sh">
|
|
<!ENTITY arithtests SYSTEM "arith-tests.sh">
|
|
<!ENTITY incompat SYSTEM "incompat.sh">
|
|
<!ENTITY ifsh SYSTEM "ifs.sh">
|
|
<!ENTITY ifsempty SYSTEM "ifs-empty.sh">
|
|
<!ENTITY logevents SYSTEM "logevents.sh">
|
|
<!ENTITY keypress SYSTEM "keypress.sh">
|
|
<!ENTITY ddkeypress SYSTEM "dd-keypress.sh">
|
|
<!ENTITY emptyarray SYSTEM "empty-array.sh">
|
|
<!ENTITY length SYSTEM "length.sh">
|
|
<!ENTITY monthlypmt SYSTEM "monthlypmt.sh">
|
|
<!ENTITY derpm SYSTEM "de-rpm.sh">
|
|
<!ENTITY blotout SYSTEM "blot-out.sh">
|
|
<!ENTITY readr SYSTEM "read-r.sh">
|
|
<!ENTITY cryptoquote SYSTEM "crypto-quote.sh">
|
|
<!ENTITY erase SYSTEM "erase.sh">
|
|
<!ENTITY returntest SYSTEM "return-test.sh">
|
|
<!ENTITY daysbetween SYSTEM "days-between.sh">
|
|
<!ENTITY varmatch SYSTEM "var-match.sh">
|
|
<!ENTITY recurse SYSTEM "recurse.sh">
|
|
<!ENTITY assert SYSTEM "assert.sh">
|
|
<!ENTITY intorstring SYSTEM "int-or-string.sh">
|
|
<!ENTITY ramdisk SYSTEM "ramdisk.sh">
|
|
<!ENTITY m4 SYSTEM "m4.sh">
|
|
<!ENTITY idelete SYSTEM "idelete.sh">
|
|
<!ENTITY matchstring SYSTEM "match-string.sh">
|
|
<!ENTITY bashandperl SYSTEM "bashandperl.sh">
|
|
<!ENTITY cvt SYSTEM "cvt.sh">
|
|
<!ENTITY wf SYSTEM "wf.sh">
|
|
<!ENTITY wf2 SYSTEM "wf2.sh">
|
|
<!ENTITY hypot SYSTEM "hypotenuse.sh">
|
|
<!ENTITY random2 SYSTEM "random2.sh">
|
|
<!ENTITY altbc SYSTEM "alt-bc.sh">
|
|
<!ENTITY substringex SYSTEM "substring-extraction.sh">
|
|
<!ENTITY stupscr SYSTEM "stupid-script-tricks.sh">
|
|
<!ENTITY resistor SYSTEM "resistor-inventory.sh">
|
|
<!ENTITY stackex SYSTEM "stack.sh">
|
|
<!ENTITY gcd SYSTEM "gcd.sh">
|
|
<!ENTITY selfmailer SYSTEM "self-mailer.sh">
|
|
<!ENTITY collatz SYSTEM "collatz.sh">
|
|
<!ENTITY wstrings SYSTEM "wstrings.sh">
|
|
<!ENTITY multiplication SYSTEM "multiplication.sh">
|
|
<!ENTITY sumproduct SYSTEM "sum-product.sh">
|
|
<!ENTITY userlist SYSTEM "userlist.sh">
|
|
<!ENTITY bgloop SYSTEM "background-loop.sh">
|
|
<!ENTITY tout SYSTEM "t-out.sh">
|
|
<!ENTITY csubloop SYSTEM "csubloop.sh">
|
|
<!ENTITY arrfunc SYSTEM "array-function.sh">
|
|
<!ENTITY lifeslow SYSTEM "life.sh">
|
|
<!ENTITY commentblock SYSTEM "commentblock.sh">
|
|
<!ENTITY selfdocument SYSTEM "self-document.sh">
|
|
<!ENTITY hf SYSTEM "here-function.sh">
|
|
<!ENTITY fileintegrity SYSTEM "file-integrity.sh">
|
|
<!ENTITY readnovar SYSTEM "read-novar.sh">
|
|
<!ENTITY setpos SYSTEM "set-pos.sh">
|
|
<!ENTITY revposparams SYSTEM "revposparams.sh">
|
|
<!ENTITY badread SYSTEM "badread.sh">
|
|
<!ENTITY selfexec SYSTEM "self-exec.sh">
|
|
<!ENTITY selfdestruct SYSTEM "self-destruct.sh">
|
|
<!ENTITY reassignstdout SYSTEM "reassign-stdout.sh">
|
|
<!ENTITY upperconv SYSTEM "upperconv.sh">
|
|
<!ENTITY pbook SYSTEM "pb.sh">
|
|
<!ENTITY makedict SYSTEM "makedict.sh">
|
|
<!ENTITY missingkeyword SYSTEM "missing-keyword.sh">
|
|
<!ENTITY blankrename SYSTEM "blank-rename.sh">
|
|
<!ENTITY scriptdetector SYSTEM "script-detector.sh">
|
|
<!ENTITY hexconvert SYSTEM "hexconvert.sh">
|
|
<!ENTITY factr SYSTEM "factr.sh">
|
|
<!ENTITY cannon SYSTEM "cannon.sh">
|
|
<!ENTITY agram SYSTEM "agram.sh">
|
|
<!ENTITY agram2 SYSTEM "agram2.sh">
|
|
<!ENTITY poem SYSTEM "poem.sh">
|
|
<!ENTITY soundex SYSTEM "soundex.sh">
|
|
<!ENTITY tempfilename SYSTEM "tempfile-name.sh">
|
|
<!ENTITY unitconversion SYSTEM "unit-conversion.sh">
|
|
<!ENTITY usagemessage SYSTEM "usage-message.sh">
|
|
<!ENTITY colorecho SYSTEM "color-echo.sh">
|
|
<!ENTITY selfsource SYSTEM "self-source.sh">
|
|
<!ENTITY selfcopy SYSTEM "self-copy.sh">
|
|
<!ENTITY arrowdetect SYSTEM "arrow-detect.sh">
|
|
<!ENTITY paragraphspace SYSTEM "paragraph-space.sh">
|
|
<!ENTITY brokenlink SYSTEM "broken-link.sh">
|
|
<!ENTITY continuenex SYSTEM "continue-n.example">
|
|
<!ENTITY pickcard SYSTEM "pick-card.sh">
|
|
<!ENTITY copyarray SYSTEM "CopyArray.sh">
|
|
<!ENTITY directoryinfo SYSTEM "directory-info.sh">
|
|
<!ENTITY embarr SYSTEM "embedded-arrays.sh">
|
|
<!ENTITY generatescript SYSTEM "generate-script.sh">
|
|
<!ENTITY scriptarray SYSTEM "script-array.sh">
|
|
<!ENTITY randombetween SYSTEM "random-between.sh">
|
|
<!ENTITY arrayops SYSTEM "array-ops.sh">
|
|
<!ENTITY arraystrops SYSTEM "array-strops.sh">
|
|
<!ENTITY arrayappend SYSTEM "array-append.bash">
|
|
<!ENTITY arrayassign SYSTEM "array-assign.bash">
|
|
<!ENTITY lettercount SYSTEM "letter-count.sh">
|
|
<!ENTITY lettercount2 SYSTEM "letter-count2.sh">
|
|
<!ENTITY protectliteral SYSTEM "protect_literal.sh">
|
|
<!ENTITY unprotectliteral SYSTEM "unprotect_literal.sh">
|
|
<!ENTITY usbinst SYSTEM "usb.sh">
|
|
<!ENTITY speech0 SYSTEM "speech.sh">
|
|
<!ENTITY basicsreviewed SYSTEM "basics-reviewed.bash">
|
|
<!ENTITY readpipe SYSTEM "readpipe.sh">
|
|
<!ENTITY usrmnt SYSTEM "usrmnt.sh">
|
|
<!ENTITY stopwatch SYSTEM "sw.sh">
|
|
<!ENTITY dialog SYSTEM "dialog.sh">
|
|
<!ENTITY hellol SYSTEM "hello.sh">
|
|
<!ENTITY hanoi SYSTEM "hanoi.bash">
|
|
<!ENTITY hanoi2 SYSTEM "hanoi2.bash">
|
|
<!ENTITY hanoi2a SYSTEM "hanoi2a.bash">
|
|
<!ENTITY horserace SYSTEM "horserace.sh">
|
|
<!ENTITY remote SYSTEM "remote.bash">
|
|
<!ENTITY musicscr SYSTEM "music.sh">
|
|
<!ENTITY prependex SYSTEM "prepend.sh">
|
|
<!ENTITY setnewpw SYSTEM "setnew-passwd.sh">
|
|
<!ENTITY badop SYSTEM "bad-op.sh">
|
|
<!ENTITY dereferencecl SYSTEM "dereference.sh">
|
|
<!ENTITY archiveweblogs SYSTEM "archiveweblogs.sh">
|
|
<!ENTITY devtcp SYSTEM "dev-tcp.sh">
|
|
<!ENTITY multipleproc SYSTEM "multiple-processes.sh">
|
|
<!ENTITY funccmdlinearg SYSTEM "func-cmdlinearg.sh">
|
|
<!ENTITY isspammer SYSTEM "is-spammer.sh">
|
|
<!ENTITY isspammer2 SYSTEM "is_spammer.bash">
|
|
<!ENTITY wgetter2 SYSTEM "wgetter2.bash">
|
|
<!ENTITY exercisingdd SYSTEM "exercising-dd.sh">
|
|
<!ENTITY quotefetch SYSTEM "quote-fetch.sh">
|
|
<!ENTITY avoidsubshell SYSTEM "avoid-subshell.sh">
|
|
<!ENTITY loggingwrapper SYSTEM "logging-wrapper.sh">
|
|
<!ENTITY dictlookup SYSTEM "dict-lookup.sh">
|
|
<!ENTITY bashpodder SYSTEM "bashpodder.sh">
|
|
<!ENTITY drawbox SYSTEM "Draw-box.sh">
|
|
<!ENTITY testcgi SYSTEM "test-cgi.sh">
|
|
<!ENTITY spawnscr SYSTEM "spawn.sh">
|
|
<!ENTITY iscan SYSTEM "iscan.sh">
|
|
<!ENTITY ra2ogg SYSTEM "ra2ogg.sh">
|
|
<!ENTITY namesdata SYSTEM "names.data">
|
|
<!ENTITY hashlib SYSTEM "Hash.lib">
|
|
<!ENTITY hashexample SYSTEM "hash-example.sh">
|
|
<!ENTITY hashex2 SYSTEM "ha.sh">
|
|
<!ENTITY getoptsimple SYSTEM "getopt-simple.sh">
|
|
<!ENTITY usegetopt SYSTEM "UseGetOpt.sh">
|
|
<!ENTITY usegetopt2 SYSTEM "UseGetOpt-2.sh">
|
|
<!ENTITY usegetoptex SYSTEM "UseGetOpt-2">
|
|
<!ENTITY insertionsort SYSTEM "insertion-sort.bash">
|
|
<!ENTITY findsplit SYSTEM "find-splitpara.sh">
|
|
<!ENTITY prasc SYSTEM "pr-asc.sh">
|
|
<!ENTITY whx SYSTEM "whx.sh">
|
|
<!ENTITY fifteen SYSTEM "fifteen.sh">
|
|
<!ENTITY spamlookup SYSTEM "spam-lookup.sh">
|
|
<!ENTITY testsuite SYSTEM "test-suite.sh">
|
|
<!ENTITY mailboxgrep SYSTEM "mailbox_grep.sh">
|
|
<!ENTITY fc4upd SYSTEM "fc4upd.sh">
|
|
<!ENTITY ipscript SYSTEM "ip.sh">
|
|
<!ENTITY nightlybackup SYSTEM "nightly-backup.sh">
|
|
<!ENTITY echoparams SYSTEM "echo-params.sh">
|
|
<!ENTITY randstring SYSTEM "rand-string.sh">
|
|
<!ENTITY splitcopy SYSTEM "splitcopy.sh">
|
|
<!ENTITY padsw SYSTEM "pad.sh">
|
|
<!ENTITY soundcardon SYSTEM "soundcard-on.sh">
|
|
<!ENTITY recursiondemo SYSTEM "recursion-demo.sh">
|
|
<!ENTITY recursiondemo2 SYSTEM "recursion-def.sh">
|
|
<!ENTITY cwsolver SYSTEM "cw-solver.sh">
|
|
<!ENTITY progressbar SYSTEM "progress-bar.sh">
|
|
<!ENTITY progressbar2 SYSTEM "progress-bar2.sh">
|
|
<!ENTITY tohtml SYSTEM "tohtml.sh">
|
|
<!ENTITY datecalc SYSTEM "date-calc.sh">
|
|
<!ENTITY brownian SYSTEM "brownian.sh">
|
|
<!ENTITY fromsh SYSTEM "from.sh">
|
|
<!ENTITY fibo SYSTEM "fibo.sh">
|
|
<!ENTITY homework SYSTEM "homework.sh">
|
|
<!ENTITY arrchoice SYSTEM "arr-choice.sh">
|
|
<!ENTITY bashek SYSTEM "BashExtraKeys.sh">
|
|
<!ENTITY fetchaddress SYSTEM "fetch_address.sh">
|
|
<!ENTITY fetchaddress2 SYSTEM "fetch_address-2.sh">
|
|
<!ENTITY case4 SYSTEM "case4.sh">
|
|
<!ENTITY asciish SYSTEM "ascii.sh">
|
|
<!ENTITY ascii2sh SYSTEM "ascii2.sh">
|
|
<!ENTITY ascii3sh SYSTEM "ascii3.sh">
|
|
<!ENTITY petals SYSTEM "petals.sh">
|
|
<!ENTITY qky SYSTEM "qky.sh">
|
|
<!ENTITY maned SYSTEM "maned.sh">
|
|
<!ENTITY ktour SYSTEM "ktour.sh">
|
|
<!ENTITY msquare SYSTEM "msquare.sh">
|
|
<!ENTITY readn SYSTEM "read-N.sh">
|
|
<!ENTITY herecommsub SYSTEM "here-commsub.sh">
|
|
<!ENTITY negarray SYSTEM "neg-array.sh">
|
|
<!ENTITY negoffset SYSTEM "neg-offset.sh">
|
|
<!ENTITY lastpipeopt SYSTEM "lastpipe-option.sh">
|
|
<!ENTITY nim SYSTEM "nim.sh">
|
|
<!ENTITY psubp SYSTEM "psub.bash">
|
|
<!ENTITY base64 SYSTEM "base64.sh">
|
|
<!ENTITY bingo SYSTEM "bingo.sh">
|
|
<!ENTITY wrps SYSTEM "wr-ps.bash">
|
|
<!ENTITY ipaddresses SYSTEM "ip-addresses.sh">
|
|
<!ENTITY assocarrtest SYSTEM "assoc-arr-test.sh">
|
|
<!ENTITY stddev SYSTEM "sd.sh">
|
|
<!ENTITY samorse SYSTEM "sam.sh">
|
|
<!ENTITY backlight SYSTEM "backlight.sh">
|
|
<!ENTITY showallc SYSTEM "show-all-colors.sh">
|
|
<!ENTITY sedappend SYSTEM "sedappend.sh">
|
|
<!ENTITY gronsfeld SYSTEM "gronsfeld.bash">
|
|
<!ENTITY rpsdcard SYSTEM "rp.sdcard.sh">
|
|
<!ENTITY testexectime SYSTEM "test-execution-time.sh">
|
|
<!ENTITY gen0data SYSTEM "gen0">
|
|
<!ENTITY cdll SYSTEM "cdll">
|
|
<!ENTITY bashrc SYSTEM "bashrc">
|
|
<!ENTITY bashprof SYSTEM "bash-profile.snippet">
|
|
<!ENTITY opprectable SYSTEM "opprec-table.xml">
|
|
]>
|
|
|
|
<book id="abs-guide">
|
|
<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.abs@gmail.com</email></address>
|
|
</affiliation>
|
|
</author>
|
|
|
|
|
|
<releaseinfo>10</releaseinfo>
|
|
<pubdate>10 Mar 2014</pubdate>
|
|
<isbn>978-1-4357-5219-1</isbn>
|
|
|
|
|
|
|
|
<revhistory id="revhistory">
|
|
|
|
<revision>
|
|
<revnumber>6.5</revnumber>
|
|
<date>05 Apr 2012</date>
|
|
<authorinitials>mc</authorinitials>
|
|
<revremark>'TUNGSTENBERRY' release</revremark>
|
|
</revision>
|
|
|
|
<revision>
|
|
<revnumber>6.6</revnumber>
|
|
<date>27 Nov 2012</date>
|
|
<authorinitials>mc</authorinitials>
|
|
<revremark>'YTTERBIUMBERRY' release</revremark>
|
|
</revision>
|
|
|
|
<revision>
|
|
<revnumber>10</revnumber>
|
|
<date>10 Mar 2014</date>
|
|
<authorinitials>mc</authorinitials>
|
|
<revremark>'PUBLICDOMAIN' release</revremark>
|
|
</revision>
|
|
|
|
</revhistory>
|
|
|
|
|
|
<abstract>
|
|
|
|
<para>This tutorial assumes no previous knowledge of
|
|
scripting or programming, yet progresses rapidly toward an
|
|
intermediate/advanced level of instruction <emphasis>. . . all
|
|
the while sneaking in little nuggets of <trademark
|
|
class="registered">UNIX</trademark> wisdom and lore</emphasis>. It
|
|
serves as a textbook, a manual for self-study, and as 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>This document is herewith granted to the Public Domain.
|
|
<userinput>No copyright!</userinput></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>
|
|
|
|
<epigraph>
|
|
<para>Script: <emphasis>A writing; a written
|
|
document. [Obs.]</emphasis></para>
|
|
<para>--<emphasis>Webster's Dictionary</emphasis>, 1913 ed.</para>
|
|
</epigraph>
|
|
|
|
<para><anchor id="whatsascript"/></para>
|
|
|
|
<para>The shell is a command interpreter. More than just the
|
|
insulating layer between the operating system kernel and the user,
|
|
it's also a fairly powerful programming language. A shell program,
|
|
called a <firstterm>script</firstterm>, is an easy-to-use tool for
|
|
building applications by <quote>gluing together</quote> system
|
|
calls, tools, utilities, and compiled binaries. Virtually the
|
|
entire repertoire of UNIX commands, utilities, and tools is
|
|
available for invocation by a shell script. If that were
|
|
not enough, internal shell commands, such as testing and loop
|
|
constructs, lend additional power and flexibility to scripts.
|
|
Shell scripts are especially well suited for administrative
|
|
system tasks and other routine repetitive tasks not requiring the
|
|
bells and whistles of a full-blown tightly structured programming
|
|
language.</para>
|
|
|
|
</partintro>
|
|
|
|
<chapter id="why-shell">
|
|
<title>Shell Programming!</title>
|
|
|
|
<epigraph>
|
|
<para>No programming language is perfect. There is not even a single
|
|
best language; there are only languages well suited or perhaps
|
|
poorly suited for particular purposes.</para>
|
|
<para>--Herbert Mayer</para>
|
|
</epigraph>
|
|
|
|
|
|
<para>A working knowledge of shell scripting is essential to anyone
|
|
wishing to become reasonably proficient at system administration,
|
|
even if they do not anticipate ever having to actually write a
|
|
script. Consider that as a Linux machine boots up, it executes the
|
|
shell scripts in <filename class="directory">/etc/rc.d</filename>
|
|
to restore the system configuration and set up services. A detailed
|
|
understanding of these startup scripts is important for analyzing
|
|
the behavior of a system, and possibly modifying it.</para>
|
|
|
|
<para>The craft of scripting is not hard to master,
|
|
since 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 -- even austere -- similar to
|
|
that of invoking and chaining together utilities at the command
|
|
line, and there are only a few <quote>rules</quote> governing
|
|
their use. Most short scripts work right the first time, and
|
|
debugging even the longer ones is straightforward.</para>
|
|
|
|
|
|
<para>
|
|
<blockquote>
|
|
<literallayout>
|
|
In the early days of personal computing, the BASIC language enabled
|
|
anyone reasonably computer proficient to write programs on an early
|
|
generation of microcomputers. Decades later, the Bash scripting
|
|
language enables anyone with a rudimentary knowledge of Linux or
|
|
UNIX to do the same on modern machines.
|
|
|
|
We now have miniaturized single-board computers with amazing
|
|
capabilities, such as the <ulink url="http://www.raspberrypi.org/">Raspberry Pi</ulink>.
|
|
Bash scripting provides a way to explore the capabilities of these
|
|
fascinating devices.
|
|
</literallayout>
|
|
</blockquote>
|
|
</para>
|
|
|
|
|
|
<para>A shell script is a quick-and-dirty method of prototyping
|
|
a complex application. Getting even a limited subset of
|
|
the functionality to work in a script is often a useful
|
|
first stage in project development. In this way, the structure
|
|
of the application can be tested and tinkered with, and the
|
|
major pitfalls found before proceeding to the final coding
|
|
in <firstterm>C</firstterm>, <firstterm>C++</firstterm>,
|
|
<firstterm>Java</firstterm>, <link linkend="perlref">Perl</link>,
|
|
or <firstterm>Python</firstterm>.</para>
|
|
|
|
<para>Shell scripting hearkens back to the classic UNIX philosophy
|
|
of breaking complex projects into simpler subtasks, of chaining
|
|
together components and utilities. Many consider this a better,
|
|
or at least more aesthetically pleasing approach to problem solving
|
|
than using one of the new generation of high-powered all-in-one
|
|
languages, such as <firstterm>Perl</firstterm>, which attempt to
|
|
be all things to all people, but at the cost of forcing you to
|
|
alter your thinking processes to fit the tool.</para>
|
|
|
|
<para>According to <link linkend="mayerref">Herbert Mayer</link>,
|
|
<quote>a useful language needs arrays, pointers,
|
|
and a generic mechanism for building data structures.</quote>
|
|
By these criteria, shell scripting falls somewhat short of being
|
|
<quote>useful.</quote> Or, perhaps not. . . .</para>
|
|
|
|
|
|
<sidebar>
|
|
|
|
<para>When not to use shell scripts
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>Resource-intensive tasks, especially where speed is
|
|
a factor (sorting, hashing, recursion
|
|
|
|
<footnote><para>Although <link linkend="recursionref0">recursion
|
|
<emphasis>is</emphasis> possible in a shell script</link>,
|
|
it tends to be slow and its implementation is often
|
|
an <link linkend="fiboref">ugly kludge</link>.
|
|
</para></footnote>
|
|
|
|
...)</para>
|
|
|
|
</listitem> <listitem>
|
|
<para>Procedures involving heavy-duty math operations,
|
|
especially floating point arithmetic, arbitrary
|
|
precision calculations, or complex numbers (use
|
|
<firstterm>C++</firstterm> or <firstterm>FORTRAN</firstterm>
|
|
instead)</para>
|
|
</listitem> <listitem>
|
|
<para>Cross-platform portability required (use
|
|
<firstterm>C</firstterm> or <firstterm>Java</firstterm>
|
|
instead)</para>
|
|
</listitem> <listitem>
|
|
<para>Complex applications, where structured programming is
|
|
a necessity (type-checking of variables, function
|
|
prototypes, etc.)</para>
|
|
</listitem> <listitem>
|
|
<para>Mission-critical applications upon which you are betting the
|
|
future of the company</para>
|
|
</listitem> <listitem>
|
|
<para>Situations where <emphasis>security</emphasis> is
|
|
important, where you need to guarantee the integrity of
|
|
your system and protect against intrusion, cracking, and
|
|
vandalism</para>
|
|
</listitem> <listitem>
|
|
<para>Project consists of subcomponents with interlocking
|
|
dependencies</para>
|
|
</listitem> <listitem>
|
|
<para>Extensive file operations required
|
|
(<firstterm>Bash</firstterm> is limited to serial file access,
|
|
and that only in a particularly clumsy and inefficient
|
|
line-by-line fashion.)</para>
|
|
</listitem> <listitem>
|
|
<para>Need native support for multi-dimensional arrays</para>
|
|
</listitem> <listitem>
|
|
<para>Need data structures, such as linked lists or trees</para>
|
|
</listitem> <listitem>
|
|
<para>Need to generate / manipulate graphics or GUIs</para>
|
|
</listitem> <listitem>
|
|
<para>Need direct access to system hardware or
|
|
external peripherals</para>
|
|
</listitem> <listitem>
|
|
<para>Need port or <link linkend="socketref">socket</link>
|
|
I/O</para>
|
|
</listitem> <listitem>
|
|
<para>Need to use libraries or interface with legacy code</para>
|
|
</listitem> <listitem>
|
|
<para>Proprietary, closed-source applications (Shell scripts
|
|
put the source code right out in the open for all the world
|
|
to see.)</para>
|
|
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>If any of the above applies, consider a more powerful scripting
|
|
language -- perhaps <firstterm>Perl</firstterm>,
|
|
<firstterm>Tcl</firstterm>, <firstterm>Python</firstterm>,
|
|
<firstterm>Ruby</firstterm> -- or possibly a
|
|
compiled language such as <firstterm>C</firstterm>,
|
|
<firstterm>C++</firstterm>, or <firstterm>Java</firstterm>. Even
|
|
then, prototyping the application as a shell script might still
|
|
be a useful development step.</para>
|
|
|
|
</sidebar>
|
|
|
|
|
|
<para><anchor id="bashdef"/></para>
|
|
<para>We will be using <acronym>Bash</acronym>, an acronym
|
|
|
|
<footnote><para>An <firstterm>acronym</firstterm>
|
|
is an <emphasis>ersatz</emphasis> word formed by pasting
|
|
together the initial letters of the words into a tongue-tripping
|
|
phrase. This morally corrupt and pernicious practice
|
|
deserves appropriately severe punishment. Public
|
|
flogging suggests itself.</para></footnote>
|
|
|
|
for <quote>Bourne-Again shell</quote> and a pun on Stephen Bourne's
|
|
now classic <firstterm>Bourne</firstterm> shell. Bash has become
|
|
a <foreignphrase>de facto</foreignphrase> standard for shell
|
|
scripting on most flavors of UNIX. Most of the principles this
|
|
book covers apply equally well to scripting with other shells,
|
|
such as the <firstterm>Korn Shell</firstterm>, from which Bash
|
|
derives some of its features,
|
|
|
|
<footnote><para>Many of the features of <firstterm>ksh88</firstterm>,
|
|
and even a few from the updated <firstterm>ksh93</firstterm>
|
|
have been merged into Bash.</para></footnote>
|
|
|
|
and the <firstterm>C Shell</firstterm> and its variants. (Note that
|
|
<firstterm>C Shell</firstterm> programming is not recommended due to
|
|
certain inherent problems, as pointed out in an October, 1993 <ulink
|
|
url="http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/">Usenet
|
|
post</ulink> by Tom Christiansen.) </para>
|
|
|
|
<para>What follows is a tutorial on shell scripting. It relies
|
|
heavily on examples to illustrate various features of the shell.
|
|
The example scripts work -- they've been tested, insofar as
|
|
possible -- and some of them are even useful in real life. The
|
|
reader can play with the actual working code of the examples
|
|
in the source archive (<filename>scriptname.sh</filename> or
|
|
<filename>scriptname.bash</filename>),
|
|
|
|
<footnote><para>By convention, user-written shell scripts
|
|
that are Bourne shell compliant generally take a name with a
|
|
<filename>.sh</filename> extension. System scripts, such as
|
|
those found in <filename class="directory">/etc/rc.d</filename>,
|
|
do not necessarily conform to this nomenclature.</para></footnote>
|
|
|
|
give them <firstterm>execute</firstterm> permission
|
|
(<userinput>chmod u+rx scriptname</userinput>),
|
|
then run them to see what happens. Should the <ulink
|
|
url="http://bash.deta.in/abs-guide-latest.tar.bz2">source
|
|
archive</ulink> not be available, then cut-and-paste from the <ulink
|
|
url="http://www.tldp.org/LDP/abs/abs-guide.html.tar.gz">HTML</ulink> or
|
|
<ulink url="http://bash.deta.in/abs-guide.pdf">pdf</ulink>
|
|
rendered versions. Be aware that some of the scripts presented here
|
|
introduce features before they are explained, and this may require
|
|
the reader to temporarily skip ahead for enlightenment.</para>
|
|
|
|
<para>Unless otherwise noted, <ulink
|
|
url="mailto:thegrendel.abs@gmail.com">the author</ulink> of this
|
|
book wrote the example scripts that follow.</para>
|
|
|
|
<epigraph>
|
|
<para>His countenance was bold and bashed not.</para>
|
|
<para>--Edmund Spenser</para>
|
|
</epigraph>
|
|
|
|
</chapter> <!-- Why Shell Programming? -->
|
|
|
|
|
|
<chapter id="sha-bang">
|
|
<title>Starting Off With a Sha-Bang</title>
|
|
|
|
<epigraph>
|
|
<para>Shell programming is a 1950s juke box . . .</para>
|
|
<para>--Larry Wall</para>
|
|
</epigraph>
|
|
|
|
<para>In the simplest case, a script is nothing more than a list
|
|
of system commands stored in a file. At the very least, this saves
|
|
the effort of retyping that particular sequence of commands each
|
|
time it is invoked.</para>
|
|
|
|
<example id="ex1">
|
|
<title><firstterm>cleanup</firstterm>: A script to clean up log
|
|
files in /var/log </title> <programlisting>&ex1;</programlisting>
|
|
</example>
|
|
|
|
<para>There is nothing unusual here, only a set of commands that
|
|
could just as easily have been invoked one by one from the
|
|
command-line on the console or in a terminal window.
|
|
The advantages of placing the commands in a script go far beyond
|
|
not having to retype them time and again. The script becomes a
|
|
<firstterm>program</firstterm> -- a <emphasis>tool</emphasis> --
|
|
and it can easily be modified or customized for a particular
|
|
application.</para>
|
|
|
|
<example id="ex1a">
|
|
<title><firstterm>cleanup</firstterm>: An improved clean-up
|
|
script</title> <programlisting>&ex1a;</programlisting>
|
|
</example>
|
|
|
|
<para>Now <emphasis>that's</emphasis> beginning to look like a real
|
|
script. But we can go even farther . . .</para>
|
|
|
|
<example id="ex2">
|
|
<title><firstterm>cleanup</firstterm>: An enhanced
|
|
and generalized version of above scripts.</title>
|
|
<programlisting>&ex2;</programlisting>
|
|
</example>
|
|
|
|
<para>Since you may not wish to wipe out the entire system log,
|
|
this version of the script keeps the last section of the message
|
|
log intact. You will constantly discover ways of fine-tuning
|
|
previously written scripts for increased effectiveness.</para>
|
|
|
|
<para><anchor id="shabangref"/>* * *</para>
|
|
|
|
<para><anchor id="magnumref"/>The
|
|
<firstterm><indexterm>
|
|
<primary>sha-bang</primary>
|
|
</indexterm> sha-bang</firstterm>
|
|
(<token>
|
|
<indexterm>
|
|
<primary>#!</primary>
|
|
</indexterm> #!</token>)
|
|
|
|
<footnote><para>More commonly seen in the literature as
|
|
<firstterm>she-bang</firstterm> or <firstterm>sh-bang</firstterm>.
|
|
This derives from the concatenation of the tokens
|
|
<firstterm>sharp</firstterm> (<token>#</token>) and
|
|
<firstterm>bang</firstterm> (<token>!</token>).</para></footnote>
|
|
|
|
at the head of a script tells your system that this file is a set
|
|
of commands to be fed to the command interpreter indicated. The
|
|
<token>#!</token> is actually a two-byte
|
|
|
|
<footnote>
|
|
<para>Some flavors of UNIX (those based on 4.2 BSD)
|
|
allegedly take a four-byte magic number, requiring
|
|
a blank after the <token>!</token> --
|
|
<userinput>#! /bin/sh</userinput>. <ulink
|
|
url="http://www.in-ulm.de/~mascheck/various/shebang/#details">
|
|
According to Sven Mascheck</ulink> this is probably a myth.</para>
|
|
</footnote>
|
|
|
|
<indexterm>
|
|
<primary>magic number</primary>
|
|
</indexterm>
|
|
<firstterm>magic number</firstterm>, a special marker that
|
|
designates a file type, or in this case an executable shell
|
|
script (type <userinput>man magic</userinput> for more
|
|
details on this fascinating topic). Immediately following
|
|
the <firstterm>sha-bang</firstterm> is a <firstterm>path
|
|
name</firstterm>. This is the path to the program that interprets
|
|
the commands in the script, whether it be a shell, a programming
|
|
language, or a utility. This command interpreter then executes
|
|
the commands in the script, starting at the top (the line
|
|
following the <firstterm>sha-bang</firstterm> line), and 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
|
|
#!/bin/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=85
|
|
|
|
echo "This line will never print (betcha!)."
|
|
|
|
exit $WHATEVER # Doesn't matter. The script will not exit here.
|
|
# Try an echo $? after script termination.
|
|
# You'll get a 0, not a 85.</programlisting></para>
|
|
<para>Also, try starting a <filename>README</filename> file with a
|
|
<userinput>#!/bin/more</userinput>, and making it executable.
|
|
The result is a self-listing documentation file. (A <link
|
|
linkend="heredocref">here document</link> using
|
|
<link linkend="catref">cat</link> is possibly a better alternative
|
|
-- see <xref linkend="ex71"/>).</para>
|
|
</footnote>
|
|
|
|
Using <userinput>#!/bin/sh</userinput>, the default Bourne shell
|
|
in most commercial variants of UNIX, makes the script <link
|
|
linkend="portabilityissues">portable</link> to non-Linux machines,
|
|
though you <link linkend="binsh">sacrifice Bash-specific
|
|
features</link>. The script will, however, conform to the
|
|
<acronym>POSIX</acronym>
|
|
|
|
<footnote>
|
|
<para><anchor id="posix2ref"/><emphasis role="strong">P</emphasis>ortable
|
|
<emphasis role="strong">O</emphasis>perating
|
|
<emphasis role="strong">S</emphasis>ystem <emphasis
|
|
role="bold">I</emphasis>nterface, an attempt to
|
|
standardize UNI<emphasis role="strong">X</emphasis>-like
|
|
OSes. The POSIX specifications are listed on the <ulink
|
|
url="http://www.opengroup.org/onlinepubs/007904975/toc.htm">Open
|
|
Group site</ulink>.</para>
|
|
</footnote>
|
|
|
|
<command>sh</command> standard.</para>
|
|
|
|
<para>Note that the path given at the <quote>sha-bang</quote> must
|
|
be correct, otherwise an error message -- usually <quote>Command
|
|
not found.</quote> -- will be the only result of running the
|
|
script.
|
|
<footnote><para>To avoid this possibility, a script may begin
|
|
with a <link linkend="envv2ref">#!/bin/env bash</link>
|
|
<firstterm>sha-bang</firstterm> line. This may be
|
|
useful on UNIX machines where <firstterm>bash</firstterm>
|
|
is not located in <filename
|
|
class="directory">/bin</filename></para></footnote>
|
|
|
|
</para>
|
|
|
|
<para><token>#!</token> can be omitted if the script consists only
|
|
of a set of generic system commands, using no internal
|
|
shell directives. The second example, above, requires the
|
|
initial <token>#!</token>, since the variable assignment line,
|
|
<userinput>lines=50</userinput>, uses a shell-specific construct.
|
|
<footnote><para>If <firstterm>Bash</firstterm> is your default
|
|
shell, then the <token>#!</token> isn't necessary at the
|
|
beginning of a script. However, if launching a script from
|
|
a different shell, such as <firstterm>tcsh</firstterm>,
|
|
then you <emphasis>will</emphasis> need the
|
|
<token>#!</token>.</para></footnote>
|
|
Note again that <userinput>#!/bin/sh</userinput> invokes the default
|
|
shell interpreter, which defaults to <filename>/bin/bash</filename>
|
|
on a Linux machine.</para>
|
|
|
|
|
|
<tip>
|
|
<para>This tutorial encourages a modular approach
|
|
to constructing a script. Make note of and collect
|
|
<quote>boilerplate</quote> code snippets that might be useful
|
|
in future scripts. Eventually you will build quite an extensive
|
|
library of nifty routines. As an example, the following script
|
|
prolog tests whether the script has been invoked with the correct
|
|
number of parameters.</para>
|
|
|
|
<para><programlisting>E_WRONG_ARGS=85
|
|
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. Later, it might occur to you to generalize
|
|
the script to do other, similar tasks. Replacing the literal
|
|
(<quote>hard-wired</quote>) constants by variables is a step in
|
|
that direction, as is replacing repetitive code blocks by <link
|
|
linkend="functionref">functions</link>.</para>
|
|
|
|
</tip>
|
|
|
|
|
|
|
|
<sect1 id="invoking">
|
|
<title>Invoking the script</title>
|
|
|
|
<para>Having written the script, you can invoke it by <userinput>sh
|
|
scriptname</userinput>,
|
|
|
|
<footnote><para>Caution: invoking a <firstterm>Bash</firstterm>
|
|
script by <userinput>sh scriptname</userinput> turns off
|
|
Bash-specific extensions, and the script may therefore fail
|
|
to execute.</para></footnote>
|
|
|
|
or alternatively <userinput>bash scriptname</userinput>. (Not
|
|
recommended is using <userinput>sh <scriptname</userinput>,
|
|
since this effectively disables reading from
|
|
<link linkend="stdinoutdef"><filename>stdin</filename></link>
|
|
within the script.) Much more convenient is to make
|
|
the script itself directly executable with a <link
|
|
linkend="chmodref">chmod</link>.
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term>Either:</term> <listitem>
|
|
<para><userinput>chmod 555 scriptname</userinput> (gives
|
|
everyone read/execute permission)
|
|
<footnote><para>A script needs <firstterm>read</firstterm>, as
|
|
well as execute permission for it to run, since the shell
|
|
needs to be able to read it.</para></footnote>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry> <varlistentry>
|
|
<term>or</term> <listitem>
|
|
<para><userinput>chmod +rx scriptname</userinput> (gives
|
|
everyone read/execute permission)</para> <para><userinput>chmod
|
|
u+rx scriptname</userinput> (gives only the
|
|
script owner read/execute permission)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</para>
|
|
|
|
<para>Having made the script executable, you may now test it by
|
|
<userinput>./scriptname</userinput>.
|
|
|
|
<footnote><para>Why not simply invoke the script with
|
|
<userinput>scriptname</userinput>? If the directory you
|
|
are in (<link linkend="pwdref">$PWD</link>) is where
|
|
<filename>scriptname</filename> is located, why doesn't
|
|
this work? This fails because, for security reasons, the
|
|
current directory (<filename class="directory">./</filename>)
|
|
is not by default included in a user's <link
|
|
linkend="pathref">$PATH</link>. It is therefore necessary to
|
|
explicitly invoke the script in the current directory with
|
|
a <userinput>./scriptname</userinput>.</para></footnote>
|
|
|
|
If it begins with a <quote>sha-bang</quote> line, invoking the
|
|
script calls the correct command interpreter to run it.</para>
|
|
|
|
<para>As a final step, after testing and debugging,
|
|
you would likely want to move it to <filename
|
|
class="directory">/usr/local/bin</filename> (as
|
|
<firstterm>root</firstterm>, of course), to make the script
|
|
available to yourself and all other users as a systemwide
|
|
executable. The script could then be invoked by simply typing
|
|
<command>scriptname</command> <keycap>[ENTER]</keycap> from the
|
|
command-line.</para>
|
|
|
|
</sect1> <!-- Invoking the script -->
|
|
|
|
|
|
<sect1 id="prelimexer">
|
|
<title>Preliminary Exercises</title>
|
|
|
|
<orderedlist>
|
|
|
|
<listitem>
|
|
<para>System administrators often write scripts to automate common
|
|
tasks. Give several instances where such scripts would be
|
|
useful.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Write a script that upon invocation shows the
|
|
<link linkend="dateref">time and date</link>, <link
|
|
linkend="whoref">lists all logged-in users</link>, and gives
|
|
the system <link linkend="uptimeref">uptime</link>. The script
|
|
then <link linkend="ioredirref">saves this information</link>
|
|
to a logfile.</para>
|
|
</listitem>
|
|
|
|
</orderedlist>
|
|
|
|
</sect1> <!-- Preliminary Exercises -->
|
|
|
|
</chapter> <!-- Starting Off With a Sha-Bang -->
|
|
|
|
|
|
</part> <!-- Part 1 (Introduction) -->
|
|
|
|
|
|
|
|
<part label="Part 2" id="part2">
|
|
<title>Basics</title>
|
|
|
|
|
|
<chapter id="special-chars">
|
|
<title>Special Characters</title>
|
|
|
|
<para>What makes a character <firstterm>special</firstterm>?
|
|
If it has a meaning beyond its
|
|
<firstterm>literal meaning</firstterm>, a <link
|
|
linkend="metameaningref">meta-meaning</link>, then we refer
|
|
to it as a <firstterm>special character</firstterm>. Along
|
|
with commands and <link linkend="keywordref">keywords</link>,
|
|
<firstterm>special characters</firstterm> are building blocks
|
|
of Bash scripts.</para>
|
|
|
|
<variablelist id="scharlist">
|
|
<title><anchor id="scharlist1"/>Special Characters Found In
|
|
Scripts and Elsewhere</title>
|
|
|
|
<varlistentry><term><anchor id="hashmarkref"/><token>#</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>#</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>#</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>comment</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title>Comments</title>
|
|
<para>Lines beginning with a <token>#</token>
|
|
(with the exception of <link linkend="magnumref">
|
|
<token>#!</token></link>) are comments and will
|
|
<emphasis>not</emphasis> be executed.</para>
|
|
</formalpara>
|
|
|
|
<para><programlisting># This line is a comment.</programlisting></para>
|
|
|
|
<para>Comments may also occur following the end of a command.</para>
|
|
|
|
<para><programlisting>echo "A comment will follow." # Comment here.
|
|
# ^ Note whitespace before #</programlisting></para>
|
|
|
|
<para><anchor id="wsbcomm"/> 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>
|
|
|
|
<para><anchor id="comminpipe"/>Comments may even be embedded
|
|
within a <link linkend="piperef">pipe</link>.</para>
|
|
<para>
|
|
<programlisting>initial=( `cat "$startfile" | sed -e '/#/d' | tr -d '\n' |\
|
|
# Delete lines containing '#' comment character.
|
|
sed -e 's/\./\. /g' -e 's/_/_ /g'` )
|
|
# Excerpted from life.sh script</programlisting>
|
|
</para>
|
|
|
|
|
|
|
|
<caution><para>A command may not follow a comment on the
|
|
same line. There is no method of terminating the comment,
|
|
in order for <quote>live code</quote> to begin on the same
|
|
line. Use a new line for the next command.</para></caution>
|
|
|
|
<note><para>Of course, a <link linkend="quotingref">quoted</link>
|
|
or an <link linkend="escp">escaped</link> <token>#</token>
|
|
in an <link linkend="echoref">echo</link> statement does
|
|
<emphasis>not</emphasis> begin a comment. Likewise, a
|
|
<token>#</token> appears in <link linkend="psub2">certain
|
|
parameter-substitution constructs</link> and in <link
|
|
linkend="numconstants"> numerical constant expressions</link>.
|
|
|
|
<programlisting>echo "The # here does not begin a comment."
|
|
echo 'The # here does not begin a comment.'
|
|
echo The \# here does not begin a comment.
|
|
echo The # here begins a comment.
|
|
|
|
echo ${PATH#*:} # Parameter substitution, not a comment.
|
|
echo $(( 2#101011 )) # Base conversion, not a comment.
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
|
|
The standard <link linkend="quotingref">quoting and
|
|
escape</link> characters (" ' \) escape the #.
|
|
</para></note>
|
|
|
|
<para>Certain <link linkend="psorex1">pattern matching
|
|
operations</link> also use the <token>#</token>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><anchor id="semicolonref"/><token>;</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>;</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>;</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>separator</primary>
|
|
</indexterm>
|
|
|
|
<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 the space after the semicolon.
|
|
#+ ^^
|
|
echo "File $filename exists."; cp $filename $filename.bak
|
|
else # ^^
|
|
echo "File $filename not found."; touch $filename
|
|
fi; echo "File test complete."</programlisting>
|
|
</para>
|
|
|
|
<para>Note that the <quote><token>;</token></quote>
|
|
<link linkend="findref0">sometimes needs to be
|
|
<firstterm>escaped</firstterm></link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>;;</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>;;</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>case</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>;;</primary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<term><token>;&</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>;;&</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>;;&</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>;&</primary>
|
|
<secondary>case statement</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>;&</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title><link
|
|
linkend="ncterm">Terminators</link>
|
|
in a <firstterm>case</firstterm> option (<link
|
|
linkend="bash4ref">version 4+</link> of Bash).</title>
|
|
<para></para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry><term><token>.</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>.</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>.</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>dot command</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>source</primary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<listitem>
|
|
<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>
|
|
|
|
<formalpara><title><quote>dot</quote>, as a component of a filename</title>
|
|
<para>When working with filenames, a leading dot is the prefix
|
|
of a <quote>hidden</quote> file, a file that an
|
|
<link linkend="lsref">ls</link> will not normally show.
|
|
<screen><prompt>bash$ </prompt><userinput>touch .hidden-file</userinput>
|
|
<prompt>bash$ </prompt><userinput>ls -l</userinput>
|
|
<computeroutput>total 10
|
|
-rw-r--r-- 1 bozo 4034 Jul 18 22:04 data1.addressbook
|
|
-rw-r--r-- 1 bozo 4602 May 25 13:58 data1.addressbook.bak
|
|
-rw-r--r-- 1 bozo 877 Dec 17 2000 employment.addressbook</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -al</userinput>
|
|
<computeroutput>total 14
|
|
drwxrwxr-x 2 bozo bozo 1024 Aug 29 20:54 ./
|
|
drwx------ 52 bozo bozo 3072 Aug 29 20:51 ../
|
|
-rw-r--r-- 1 bozo bozo 4034 Jul 18 22:04 data1.addressbook
|
|
-rw-r--r-- 1 bozo bozo 4602 May 25 13:58 data1.addressbook.bak
|
|
-rw-r--r-- 1 bozo bozo 877 Dec 17 2000 employment.addressbook
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 29 20:54 .hidden-file</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</formalpara>
|
|
|
|
<para><anchor id="dotdirectory"/></para>
|
|
<para>When considering directory names, <firstterm>a single
|
|
dot</firstterm> represents the current working directory,
|
|
and <firstterm>two dots</firstterm> denote the parent
|
|
directory.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>pwd</userinput>
|
|
<computeroutput>/home/bozo/projects</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>cd .</userinput>
|
|
<prompt>bash$ </prompt><userinput>pwd</userinput>
|
|
<computeroutput>/home/bozo/projects</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>cd ..</userinput>
|
|
<prompt>bash$ </prompt><userinput>pwd</userinput>
|
|
<computeroutput>/home/bozo/</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <firstterm>dot</firstterm> often appears as the
|
|
destination (directory) of a file movement command,
|
|
in this context meaning <firstterm>current
|
|
directory</firstterm>.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>cp /home/bozo/current_work/junk/* .</userinput>
|
|
</screen>
|
|
Copy all the <quote>junk</quote> files to
|
|
<link linkend="pwdref">$PWD</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry><term><token>.</token></term>
|
|
<listitem>
|
|
|
|
<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>
|
|
|
|
<formalpara><title><quote>dot</quote> character match</title>
|
|
<para>When <link linkend="regexdot">matching
|
|
characters</link>, as part of a <link
|
|
linkend="regexref">regular expression</link>, a
|
|
<quote>dot</quote> <link linkend="regexdot">matches a
|
|
single character</link>.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><token>"</token></term>
|
|
<listitem><formalpara><title><link linkend="dblquo">partial
|
|
quoting</link> [double quote]</title>
|
|
<para><emphasis>"STRING"</emphasis> preserves (from
|
|
interpretation) most of the special characters within
|
|
<emphasis>STRING</emphasis>. See <xref
|
|
linkend="quoting"/>.</para>
|
|
</formalpara> </listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>'</token></term>
|
|
<listitem><formalpara><title><link linkend="snglquo">full
|
|
quoting</link> [single quote]</title>
|
|
<para><emphasis>'STRING'</emphasis> preserves all special
|
|
characters within <emphasis>STRING</emphasis>. This is a
|
|
stronger form of quoting than <emphasis>"STRING"</emphasis>.
|
|
See <xref linkend="quoting"/>.</para>
|
|
</formalpara> </listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>,</token></term>
|
|
<listitem><formalpara><title><link linkend="commaop">comma
|
|
operator</link></title>
|
|
<para>The <firstterm>comma operator</firstterm>
|
|
|
|
<footnote><para><anchor id="operatordef"/>An
|
|
<firstterm>operator</firstterm> is an agent that carries
|
|
out an <firstterm>operation</firstterm>. Some examples
|
|
are the common <link linkend="arops1">arithmetic
|
|
operators</link>, <command>+ - * /</command>. In
|
|
Bash, there is some overlap between the concepts
|
|
of <firstterm>operator</firstterm> and <link
|
|
linkend="keywordref">keyword</link>.</para></footnote>
|
|
|
|
links together a
|
|
series of arithmetic operations. All are evaluated,
|
|
but only the last one is returned.
|
|
<programlisting>let "t2 = ((a = 9, 15 / 3))"
|
|
# Set "a = 9" and "t2 = 15 / 3"</programlisting>
|
|
</para>
|
|
</formalpara>
|
|
|
|
<para><anchor id="commaop2"/>The <firstterm>comma</firstterm>
|
|
operator can also concatenate strings.
|
|
<programlisting>for file in /{,usr/}bin/*calc
|
|
# ^ Find all executable files ending in "calc"
|
|
#+ in /bin and /usr/bin directories.
|
|
do
|
|
if [ -x "$file" ]
|
|
then
|
|
echo $file
|
|
fi
|
|
done
|
|
|
|
# /bin/ipcalc
|
|
# /usr/bin/kcalc
|
|
# /usr/bin/oidcalc
|
|
# /usr/bin/oocalc
|
|
|
|
|
|
# Thank you, Rory Winston, for pointing this out.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>,</token></term>
|
|
<term><token>,</token></term>
|
|
<listitem>
|
|
<formalpara><title><link linkend="casemodparamsub">Lowercase
|
|
conversion</link> in <firstterm>parameter substitution</firstterm>
|
|
(added in <link
|
|
linkend="bash4ref">version 4</link> of Bash)</title>
|
|
<para></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>
|
|
<firstterm>escapes</firstterm> the character
|
|
<emphasis>X</emphasis>. This has the effect of
|
|
<quote>quoting</quote> <emphasis>X</emphasis>, equivalent
|
|
to <emphasis>'X'</emphasis>. The <token>\</token> may
|
|
be used to quote <token>"</token> and <token>'</token>,
|
|
so they are expressed literally.</para>
|
|
<para>See <xref linkend="quoting"/> for an in-depth explanation
|
|
of escaped characters.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>/</token></term>
|
|
<listitem><formalpara><title>Filename path separator [forward slash]</title>
|
|
<para>Separates the components of a filename (as in
|
|
<filename>/home/bozo/projects/Makefile</filename>).</para>
|
|
</formalpara>
|
|
<para>This is also the division <link
|
|
linkend="arops1">arithmetic operator</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="backticksref"/><token>`</token></term>
|
|
<listitem><formalpara><title><link
|
|
linkend="commandsubref">command substitution</link></title>
|
|
<para>The <command>`command`</command> construct makes
|
|
available the output of <command>command</command>
|
|
for assignment to a variable. This is also known as
|
|
<link linkend="backquotesref">backquotes</link> or
|
|
backticks.</para></formalpara> </listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><anchor id="colon0ref"/><token>:</token></term>
|
|
<listitem>
|
|
|
|
<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>
|
|
|
|
<para><anchor id="nullref"/></para>
|
|
<formalpara><title>null command [colon]</title>
|
|
<para>This is the shell equivalent of a
|
|
<quote>NOP</quote> (<replaceable>no op</replaceable>, a
|
|
do-nothing operation). It may be considered a synonym for
|
|
the shell builtin <link linkend="trueref">true</link>. The
|
|
<quote><token>:</token></quote> command is itself a
|
|
<firstterm>Bash</firstterm> <link
|
|
linkend="builtinref">builtin</link>, and its <link
|
|
linkend="exitstatusref">exit status</link> is
|
|
<firstterm>true</firstterm>
|
|
(<returnvalue>0</returnvalue>).</para>
|
|
</formalpara>
|
|
|
|
<para><programlisting>:
|
|
echo $? # 0</programlisting></para>
|
|
|
|
|
|
<para>Endless loop:</para>
|
|
|
|
<para><programlisting>
|
|
while :
|
|
do
|
|
operation-1
|
|
operation-2
|
|
...
|
|
operation-n
|
|
done
|
|
|
|
# Same as:
|
|
# while true
|
|
# do
|
|
# ...
|
|
# done</programlisting>
|
|
</para>
|
|
|
|
<para>Placeholder in if/then test:</para>
|
|
|
|
<para><programlisting>
|
|
if condition
|
|
then : # Do nothing and branch ahead
|
|
else # Or else ...
|
|
take-some-action
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
<para>Provide a placeholder where a binary operation is
|
|
expected, see <xref linkend="arithops"/> and <link
|
|
linkend="defparam">default parameters</link>.</para>
|
|
|
|
<para><programlisting>: ${username=`whoami`}
|
|
# ${username=`whoami`} Gives an error without the leading :
|
|
# unless "username" is a command or builtin...
|
|
|
|
: ${1?"Usage: $0 ARGUMENT"} # From "usage-message.sh example script.</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><anchor id="regfileref"/>This applies to regular files,
|
|
not pipes, symlinks, and certain special files.</para></note>
|
|
|
|
|
|
<para>May be used to begin a comment line, although this is not
|
|
recommended. Using <token>#</token> for a comment turns
|
|
off error checking for the remainder of that line, so
|
|
almost anything may appear in a comment. However,
|
|
this is not the case with
|
|
<token>:</token>.
|
|
<programlisting>: This is a comment that generates an error, ( if [ $x -eq 3] ).</programlisting>
|
|
</para>
|
|
|
|
<para>The <quote><token>:</token></quote> serves as a <link
|
|
linkend="fieldref">field</link>
|
|
separator, in <link
|
|
linkend="datafilesref1"><filename>/etc/passwd</filename></link>,
|
|
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>
|
|
|
|
<para><anchor id="colonfname"/></para>
|
|
<para>A <firstterm>colon</firstterm> is <link
|
|
linkend="fstrangeref">acceptable as a function name</link>.
|
|
<programlisting>:()
|
|
{
|
|
echo "The name of this function is "$FUNCNAME" "
|
|
# Why use a colon as a function name?
|
|
# It's a way of obfuscating your code.
|
|
}
|
|
|
|
:
|
|
|
|
# The name of this function is :</programlisting>
|
|
|
|
This is not <link linkend="portabilityissues">portable</link>
|
|
behavior, and therefore not a recommended practice.
|
|
In fact, more recent releases of Bash do not permit
|
|
this usage. An underscore <command>_</command> works,
|
|
though.</para>
|
|
|
|
|
|
<para><anchor id="coloninfunction"/></para>
|
|
<para>A <firstterm>colon</firstterm> can serve
|
|
as a placeholder in an otherwise empty
|
|
function.</para>
|
|
<para><programlisting>not_empty ()
|
|
{
|
|
:
|
|
} # Contains a : (null command), and so is not empty.</programlisting></para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><anchor id="notref"/><token>!</token></term>
|
|
<listitem>
|
|
|
|
<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>
|
|
|
|
<formalpara><title>reverse (or negate) the sense of
|
|
a test or exit status [bang]</title>
|
|
|
|
<para>The <token>!</token> operator inverts the <link
|
|
linkend="exitstatusref">exit status</link>
|
|
of the command to which it is applied (see
|
|
<xref linkend="negcond"/>). It also inverts
|
|
the meaning of a test operator. This can, for
|
|
example, change the sense of <firstterm>equal</firstterm>
|
|
( <link linkend="equalsignref">=</link>
|
|
) to <firstterm>not-equal</firstterm> ( != ). The
|
|
<token>!</token> operator is a Bash <link
|
|
linkend="keywordref">keyword</link>.</para>
|
|
|
|
</formalpara>
|
|
<para>In a different context, the <token>!</token>
|
|
also appears in <link linkend="ivrref">indirect variable
|
|
references</link>.</para>
|
|
|
|
<para>In yet another context, from the <firstterm>command
|
|
line</firstterm>, the <token>!</token> invokes the
|
|
Bash <firstterm>history mechanism</firstterm> (see <xref
|
|
linkend="histcommands"/>). Note that within a script,
|
|
the history mechanism is disabled.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="asteriskref"/><token>*</token></term>
|
|
<listitem>
|
|
|
|
<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>
|
|
|
|
<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.xml add-drive.sh agram.sh alias.sh</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="asteriskref2"/></para>
|
|
<para>The <token>*</token> also represents <link
|
|
linkend="asteriskreg">any number
|
|
(or zero) characters</link> in a <link
|
|
linkend="regexref">regular expression</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>*</token></term>
|
|
<listitem>
|
|
|
|
<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>
|
|
|
|
<formalpara><title><link linkend="arops1">arithmetic operator</link></title>
|
|
|
|
<para>In the context of arithmetic operations, the
|
|
<token>*</token> denotes multiplication.</para>
|
|
|
|
</formalpara>
|
|
|
|
<para><token>**</token> A double asterisk can represent the
|
|
<link linkend="exponentiationref">exponentiation</link>
|
|
operator or <link linkend="globstarref">extended
|
|
file-match</link> <firstterm>globbing</firstterm>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>?</token></term>
|
|
<listitem>
|
|
|
|
<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>
|
|
|
|
<formalpara><title>test operator</title>
|
|
<para>Within certain expressions, the <token>?</token> indicates
|
|
a test for a condition.</para>
|
|
</formalpara>
|
|
|
|
<para><anchor id="cstrinary"/></para>
|
|
<para>In a <link linkend="dblparens">double-parentheses
|
|
construct</link>, the <token>?</token>
|
|
can serve as an element of a C-style
|
|
<firstterm>trinary</firstterm> operator.
|
|
<footnote><para>This is more commonly known
|
|
as the <firstterm>ternary</firstterm>
|
|
operator. Unfortunately, <firstterm>ternary</firstterm>
|
|
is an ugly word. It doesn't roll off
|
|
the tongue, and it doesn't elucidate. It
|
|
obfuscates. <firstterm>Trinary</firstterm> is by far
|
|
the more elegant usage.</para></footnote>
|
|
</para>
|
|
|
|
<para><varname>condition</varname><command>?</command><varname>result-if-true</varname><command>:</command><varname>result-if-false</varname></para>
|
|
|
|
<para><programlisting>(( var0 = var1<98?9:21 ))
|
|
# ^ ^
|
|
|
|
# if [ "$var1" -lt 98 ]
|
|
# then
|
|
# var0=9
|
|
# else
|
|
# var0=21
|
|
# fi</programlisting></para>
|
|
|
|
|
|
<para>In a <link linkend="paramsubref">parameter
|
|
substitution</link> expression, the <token>?</token>
|
|
<link linkend="qerrmsg">tests whether a variable has been
|
|
set</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="wildcardqu"/><token>?</token></term>
|
|
<listitem>
|
|
|
|
<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>
|
|
|
|
<formalpara><title>wild card</title>
|
|
|
|
<para><anchor id="quexwc"/>The <token>?</token> character
|
|
serves as a single-character <quote>wild card</quote>
|
|
for filename expansion in <link
|
|
linkend="globbingref">globbing</link>, as well as <link
|
|
linkend="quexregex">representing one character</link>
|
|
in an <link linkend="extregex">extended regular
|
|
expression</link>.</para>
|
|
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>$</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>$</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable substitution</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title><link linkend="varsubn">Variable
|
|
substitution</link> (contents of a variable)</title>
|
|
<para>
|
|
<programlisting>var1=5
|
|
var2=23skidoo
|
|
|
|
echo $var1 # 5
|
|
echo $var2 # 23skidoo</programlisting>
|
|
</para>
|
|
</formalpara>
|
|
|
|
<para><anchor id="varprefixref"/></para>
|
|
<para>A <token>$</token> prefixing a variable name
|
|
indicates the <firstterm>value</firstterm> the variable
|
|
holds.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>$</token></term>
|
|
<listitem>
|
|
|
|
<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>
|
|
|
|
<formalpara><title>end-of-line</title>
|
|
<para>In a <link linkend="regexref">regular expression</link>, a
|
|
<quote>$</quote> addresses the <link
|
|
linkend="dollarsignref">end of a line</link> of
|
|
text.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>${}</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>${}</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>${}</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>parameter substitution</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title><link linkend="paramsubref">Parameter
|
|
substitution</link></title>
|
|
<para></para></formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>$' ... '</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>$' ... '</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>$</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>string expansion</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>string expansion</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title><link linkend="strq">Quoted string
|
|
expansion</link></title>
|
|
<para>This construct expands single or multiple
|
|
escaped octal or hex values into ASCII
|
|
|
|
<footnote>
|
|
<para><anchor id="asciidef"/></para>
|
|
<para><command>A</command>merican
|
|
<command>S</command>tandard
|
|
<command>C</command>ode
|
|
for
|
|
<command>I</command>nformation
|
|
<command>I</command>nterchange.
|
|
This is a system for encoding text characters
|
|
(alphabetic, numeric, and a limited set of symbols)
|
|
as 7-bit numbers that can be stored and manipulated by
|
|
computers. Many of the ASCII characters are
|
|
represented on a standard keyboard.</para></footnote>
|
|
|
|
or <link linkend="unicoderef">Unicode</link>
|
|
characters.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>$*</token></term>
|
|
<term><token>$@</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>$*</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>$*</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>$@</primary>
|
|
<secondary>positional parameters</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>$@</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title><link linkend="appref">positional
|
|
parameters</link></title>
|
|
<para></para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>$?</token></term>
|
|
<listitem>
|
|
|
|
<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>
|
|
|
|
<formalpara><title>exit status variable</title>
|
|
<para>The <link linkend="exsref">$? variable</link>
|
|
holds the <link linkend="exitstatusref">exit status</link>
|
|
of a command, a <link linkend="functionref">function</link>,
|
|
or of the script itself.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="processidref"/><token>$$</token></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<formalpara><title>process ID variable</title>
|
|
<para>The <link linkend="proccid">$$ variable</link>
|
|
holds the <firstterm>process ID</firstterm>
|
|
<footnote>
|
|
<para><anchor id="processiddef"/></para>
|
|
<para>A <firstterm>PID</firstterm>, or
|
|
<firstterm>process ID</firstterm>, is a number assigned
|
|
to a running process. The <firstterm>PID</firstterm>s
|
|
of running processes may be viewed with a <link
|
|
linkend="ppssref">ps</link> command.
|
|
</para>
|
|
<para><anchor id="processref"/></para>
|
|
<para>
|
|
<userinput>Definition:</userinput> A
|
|
<firstterm>process</firstterm> is a currently
|
|
executing command (or program), sometimes referred
|
|
to as a <firstterm>job</firstterm>. </para>
|
|
</footnote>
|
|
of the script in which it appears.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="parensref"/><token>()</token></term>
|
|
|
|
<listitem>
|
|
<formalpara><title>command group</title>
|
|
<para><programlisting>(a=hello; echo $a)</programlisting></para>
|
|
</formalpara>
|
|
|
|
<important>
|
|
|
|
<para>A listing of commands within
|
|
<replaceable>parentheses</replaceable> starts a <link
|
|
linkend="subshellsref">subshell</link>.</para>
|
|
|
|
<para>Variables inside parentheses, within the subshell, are not
|
|
visible to the rest of the script. The parent process,
|
|
the script, <link linkend="parvis">cannot read variables
|
|
created in the child process</link>, the subshell.
|
|
<programlisting>a=123
|
|
( a=321; )
|
|
|
|
echo "a = $a" # a = 123
|
|
# "a" within parentheses acts like a local variable.</programlisting></para>
|
|
</important>
|
|
|
|
|
|
<formalpara><title>array initialization</title>
|
|
<para>
|
|
<anchor id="arrayinit1"/>
|
|
<programlisting>Array=(element1 element2 element3)</programlisting>
|
|
</para>
|
|
</formalpara>
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>{xxx,yyy,zzz,...}</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>{xxx,yyy,zzz..}</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>{}</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>brace expansion</primary>
|
|
</indexterm>
|
|
<formalpara><title>Brace expansion</title>
|
|
<para><anchor id="braceexpref"/>
|
|
<programlisting>echo \"{These,words,are,quoted}\" # " prefix and suffix
|
|
# "These" "words" "are" "quoted"
|
|
|
|
|
|
cat {file1,file2,file3} > combined_file
|
|
# Concatenates the files file1, file2, and file3 into combined_file.
|
|
|
|
cp file22.{txt,backup}
|
|
# Copies "file22.txt" to "file22.backup"</programlisting></para>
|
|
</formalpara>
|
|
|
|
<para>A command may act upon a comma-separated list of file specs within
|
|
<replaceable>braces</replaceable>.
|
|
|
|
<footnote><para>The shell does the <firstterm>brace
|
|
expansion</firstterm>. The command itself acts upon the
|
|
<emphasis>result</emphasis> of the expansion.</para></footnote>
|
|
|
|
Filename expansion (<link linkend="globbingref">globbing</link>)
|
|
applies to the file specs between the braces.</para>
|
|
|
|
<caution>
|
|
<para>No spaces allowed within the braces
|
|
<emphasis>unless</emphasis> the spaces are quoted or escaped.</para>
|
|
|
|
<para><userinput>echo {file1,file2}\ :{\ A," B",' C'}</userinput></para>
|
|
<para><computeroutput>file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C</computeroutput></para>
|
|
|
|
</caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="braceexpref33"/><token>{a..z}</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>{a..z}</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>{}</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>extended brace expansion</primary>
|
|
</indexterm>
|
|
|
|
<formalpara>
|
|
<title>Extended Brace expansion</title>
|
|
<para>
|
|
<programlisting>echo {a..z} # a b c d e f g h i j k l m n o p q r s t u v w x y z
|
|
# Echoes characters between a and z.
|
|
|
|
echo {0..3} # 0 1 2 3
|
|
# Echoes characters between 0 and 3.
|
|
|
|
|
|
base64_charset=( {A..Z} {a..z} {0..9} + / = )
|
|
# Initializing an array, using extended brace expansion.
|
|
# From vladz's "base64.sh" example script.</programlisting>
|
|
</para>
|
|
</formalpara>
|
|
|
|
<para>The <firstterm>{a..z}</firstterm>
|
|
<link linkend="braceexpref3">extended brace
|
|
expansion</link> construction is a feature introduced
|
|
in <link linkend="bash3ref">version 3</link> of
|
|
<firstterm>Bash</firstterm>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="codeblockref"/><token>{}</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>{}</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>{}</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>block of code</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title>Block of code [curly brackets]</title>
|
|
<para>Also referred to as an <firstterm>inline group</firstterm>,
|
|
this construct, in effect, creates an <firstterm>anonymous
|
|
function</firstterm> (a function without a
|
|
name). However, unlike in a <quote>standard</quote> <link
|
|
linkend="functionref">function</link>, the variables
|
|
inside a code block remain visible to the remainder of the
|
|
script.</para></formalpara>
|
|
|
|
<para> <screen><prompt>bash$ </prompt><userinput>{ local a;
|
|
a=123; }</userinput>
|
|
<computeroutput>bash: local: can only be used in a
|
|
function</computeroutput>
|
|
</screen> </para>
|
|
|
|
<para><programlisting>a=123
|
|
{ a=321; }
|
|
echo "a = $a" # a = 321 (value inside code block)
|
|
|
|
# Thanks, S.C.</programlisting></para>
|
|
|
|
|
|
<para><anchor id="blockio"/></para>
|
|
<para>The code block enclosed in braces may have <link
|
|
linkend="ioredirref">I/O redirected</link> to and from
|
|
it.</para>
|
|
|
|
<example id="ex8">
|
|
<title>Code blocks and I/O redirection</title>
|
|
<programlisting>&ex8;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="blockio2"/></para>
|
|
<example id="rpmcheck">
|
|
<title>Saving the output of a code block to a file</title>
|
|
<programlisting>&rpmcheck;</programlisting>
|
|
</example>
|
|
|
|
<note><para>Unlike a command group within (parentheses),
|
|
as above, a code block enclosed by {braces} will
|
|
<emphasis>not</emphasis> normally launch a <link
|
|
linkend="subshellsref">subshell</link>.
|
|
|
|
<footnote>
|
|
<para>Exception: a code block in braces as
|
|
part of a pipe <emphasis>may</emphasis> run as a
|
|
<link linkend="subshellsref">subshell</link>.</para>
|
|
|
|
<para><programlisting>ls | { read firstline; read secondline; }
|
|
# Error. The code block in braces runs as a subshell,
|
|
#+ so the output of "ls" cannot be passed to variables within the block.
|
|
echo "First line is $firstline; second line is $secondline" # Won't work.
|
|
|
|
# Thanks, S.C.</programlisting></para>
|
|
</footnote>
|
|
|
|
</para>
|
|
|
|
<para>It is possible to <link
|
|
linkend="iterationref">iterate</link> a code block
|
|
using a <link linkend="nododone">non-standard
|
|
<firstterm>for-loop</firstterm></link>.</para>
|
|
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>{}</token></term>
|
|
<listitem>
|
|
|
|
<formalpara><title>placeholder for text</title>
|
|
<para>Used after <link linkend="xargscurlyref">xargs
|
|
<option>-i</option></link> (<firstterm>replace
|
|
strings</firstterm> option). The <token>{}</token> double
|
|
curly brackets are a placeholder for output text.</para>
|
|
</formalpara>
|
|
|
|
<para><programlisting>ls . | xargs -i -t cp ./{} $1
|
|
# ^^ ^^
|
|
|
|
# From "ex42.sh" (copydir.sh) example.</programlisting></para>
|
|
<para><anchor id="semicolonesc"/></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><token>{} \;</token></term>
|
|
<listitem>
|
|
|
|
<formalpara><title>pathname</title>
|
|
<para>Mostly used in <link linkend="findref">find</link>
|
|
constructs. This is <emphasis>not</emphasis> a shell
|
|
<link linkend="builtinref">builtin</link>.</para>
|
|
</formalpara>
|
|
|
|
<sidebar><para><anchor id="pathnameref"/></para>
|
|
<para>Definition: A <firstterm>pathname</firstterm>
|
|
is a <firstterm>filename</firstterm> that includes the
|
|
complete <link linkend="pathref">path</link>. As an example,
|
|
<filename>/home/bozo/Notes/Thursday/schedule.txt</filename>.
|
|
This is sometimes referred to as the <firstterm>absolute
|
|
path</firstterm>.</para></sidebar>
|
|
|
|
<note><para>The <quote><token>;</token></quote> ends
|
|
the <option>-exec</option> option of a
|
|
<command>find</command> command sequence. It needs
|
|
to be escaped to protect it from interpretation by the
|
|
shell.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry><term><anchor id="leftbracket"/><token>[ ]</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>[]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>[ ]</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title>test</title>
|
|
<para><anchor id="bracktest"/></para></formalpara>
|
|
<para><link linkend="ifthen">Test</link> expression between
|
|
<command>[ ]</command>. Note that <command>[</command>
|
|
is part of the shell <firstterm>builtin</firstterm> <link
|
|
linkend="ttestref">test</link> (and a synonym for it),
|
|
<emphasis>not</emphasis> a link to the external command
|
|
<filename>/usr/bin/test</filename>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>[[ ]]</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>[[]]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>[[ ]]</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title>test</title>
|
|
<para></para></formalpara>
|
|
<para>Test expression between <token>[[ ]]</token>. More
|
|
flexible than the single-bracket <token>[ ]</token> test,
|
|
this is a shell <link
|
|
linkend="keywordref">keyword</link>.</para> <para>See the
|
|
discussion on the <link linkend="dblbrackets">[[ ... ]]
|
|
construct</link>.</para>
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>[ ]</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>[ ]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>array_element[ ]</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>array element</primary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>[ ]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>character range</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>regular expression</primary>
|
|
</indexterm>
|
|
|
|
<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><anchor id="bracketarith"/><token>$[ ... ]</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>$[ ]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>integer expansion</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>integer arithmetic (obsolete)</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title>integer expansion</title>
|
|
<para></para></formalpara>
|
|
<para>Evaluate integer expression between
|
|
<token>$[ ]</token>.
|
|
<programlisting>a=3
|
|
b=7
|
|
|
|
echo $[$a+$b] # 10
|
|
echo $[$a*$b] # 21</programlisting></para>
|
|
|
|
<para>Note that this usage is <emphasis>deprecated</emphasis>,
|
|
and has been replaced by the
|
|
<link linkend="dblparens">(( ... ))</link> construct.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry><term><token>(( ))</token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>(( ))</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>(( ))</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>integer comparison</primary>
|
|
</indexterm>
|
|
|
|
<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> <token><></token></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<formalpara><title><link linkend="ioredirref">redirection</link></title>
|
|
<para></para>
|
|
</formalpara>
|
|
|
|
<para><userinput>scriptname >filename</userinput> redirects the output of
|
|
<filename>scriptname</filename> to file
|
|
<filename>filename</filename>. Overwrite
|
|
<filename>filename</filename> if it already exists.</para>
|
|
|
|
<para><anchor id="redirouterror"/></para>
|
|
<para><userinput>command &>filename</userinput> redirects
|
|
both the <link
|
|
linkend="stdinoutdef"><filename>stdout</filename></link>
|
|
and the
|
|
<filename>stderr</filename> of <filename>command</filename>
|
|
to <filename>filename</filename>.</para>
|
|
|
|
|
|
<note>
|
|
|
|
<para>
|
|
<anchor id="devnullredirect"/>
|
|
This is useful for suppressing output when
|
|
testing for a condition. For example, let us
|
|
test whether a certain command exists.
|
|
</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>type bogus_command &>/dev/null</userinput>
|
|
<computeroutput></computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $?</userinput>
|
|
<computeroutput>1</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Or in a script:</para>
|
|
|
|
<para><programlisting>command_test () { type "$1" &>/dev/null; }
|
|
# ^
|
|
|
|
cmd=rmdir # Legitimate command.
|
|
command_test $cmd; echo $? # 0
|
|
|
|
|
|
cmd=bogus_command # Illegitimate command
|
|
command_test $cmd; echo $? # 1</programlisting></para>
|
|
|
|
</note>
|
|
|
|
|
|
<para><anchor id="redirouterror2"/></para>
|
|
<para><userinput>command >&2</userinput> redirects
|
|
<filename>stdout</filename> of <filename>command</filename>
|
|
to <filename>stderr</filename>.</para>
|
|
|
|
<para><userinput>scriptname >>filename</userinput> appends
|
|
the output of <filename>scriptname</filename>
|
|
to file <filename>filename</filename>. If
|
|
<filename>filename</filename> does not already exist,
|
|
it is created.</para>
|
|
|
|
<para><anchor id="redirrw"/></para>
|
|
<para><userinput>[i]<>filename</userinput>
|
|
opens file <filename>filename</filename> for reading
|
|
and writing, and assigns <link linkend="fdref">file
|
|
descriptor</link> <token>i</token> to it. If
|
|
<filename>filename</filename> does not exist, it is
|
|
created.</para>
|
|
|
|
|
|
<formalpara><title><link linkend="processsubref">process substitution</link></title>
|
|
<para></para>
|
|
</formalpara>
|
|
|
|
<para><userinput>(command)></userinput></para>
|
|
<para><userinput><(command)</userinput></para>
|
|
|
|
|
|
<para><link linkend="ltref">In a different context</link>,
|
|
the <quote><token><</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><anchor id="heredocrrref"/><token><<</token></term>
|
|
<listitem><formalpara><title>redirection used in a <link
|
|
linkend="heredocref">here document</link></title>
|
|
<para></para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="herestringref"/><token><<<</token></term>
|
|
<listitem><formalpara><title>redirection used in a <link
|
|
linkend="herestringsref">here string</link></title>
|
|
<para></para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token><</token></term>
|
|
<term><token>></token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary><</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary><</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>></primary>
|
|
<secondary>ASCII comparison</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>></primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title><link linkend="ltref">ASCII
|
|
comparison</link></title>
|
|
<para><programlisting>veg1=carrots
|
|
veg2=tomatoes
|
|
|
|
if [[ "$veg1" < "$veg2" ]]
|
|
then
|
|
echo "Although $veg1 precede $veg2 in the dictionary,"
|
|
echo -n "this does not necessarily imply anything "
|
|
echo "about my culinary preferences."
|
|
else
|
|
echo "What kind of dictionary are you using, anyhow?"
|
|
fi</programlisting></para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>\<</token></term>
|
|
<term><token>\></token></term>
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>\<</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>regular expression</primary>
|
|
<secondary>\<</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>></primary>
|
|
<secondary>word boundary</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>></primary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>|</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>|</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>pipe</primary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="piperef"/></para>
|
|
<formalpara><title>pipe</title>
|
|
<para>Passes the output (<filename>stdout</filename>)
|
|
of a previous command to the input
|
|
(<filename>stdin</filename>) of the next one, or
|
|
to the shell. This is a method of chaining commands
|
|
together.</para>
|
|
</formalpara>
|
|
|
|
<para>
|
|
<programlisting>echo ls -l | sh
|
|
# Passes the output of "echo ls -l" to the shell,
|
|
#+ with the same result as a simple "ls -l".
|
|
|
|
|
|
cat *.lst | sort | uniq
|
|
# Merges and sorts all ".lst" files, then deletes duplicate lines.</programlisting>
|
|
</para>
|
|
|
|
<sidebar>
|
|
|
|
<para>
|
|
A pipe, as a classic method of interprocess
|
|
communication, sends the <filename>stdout</filename>
|
|
of one <link linkend="processref">process</link> to the
|
|
<filename>stdin</filename> of another. In a typical case,
|
|
a command, such as <link linkend="catref">cat</link> or
|
|
<link linkend="echoref">echo</link>, pipes a stream of
|
|
data to a
|
|
<anchor id="filterdef"/>
|
|
<firstterm>filter</firstterm>, a command that
|
|
transforms its input for processing.
|
|
<footnote><para> Even as in olden times a
|
|
<firstterm>philtre</firstterm> denoted a potion alleged
|
|
to have magical transformative powers, so does a UNIX
|
|
<firstterm>filter</firstterm> transform its target in
|
|
(roughly) analogous fashion. (The coder who comes up with a
|
|
<quote>love philtre</quote> that runs on a Linux machine
|
|
will likely win accolades and honors.)</para></footnote>
|
|
</para>
|
|
|
|
<para>
|
|
<userinput>cat $filename1 $filename2 | grep $search_word</userinput>
|
|
</para>
|
|
|
|
<para>For an interesting note on the complexity of using UNIX
|
|
pipes, see <ulink
|
|
url="http://www.faqs.org/faqs/unix-faq/faq/part3/">the UNIX FAQ,
|
|
Part 3</ulink>.</para>
|
|
|
|
</sidebar>
|
|
|
|
|
|
<para><anchor id="ucref"/>The output of a command or commands
|
|
may be piped to a script.
|
|
|
|
<programlisting>#!/bin/bash
|
|
# uppercase.sh : Changes input to uppercase.
|
|
|
|
tr 'a-z' 'A-Z'
|
|
# Letter ranges must be quoted
|
|
#+ to prevent filename generation from single-letter filenames.
|
|
|
|
exit 0</programlisting>
|
|
Now, let us pipe the output of <command>ls -l</command> to this
|
|
script.
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>ls -l | ./uppercase.sh</userinput>
|
|
<computeroutput>-RW-RW-R-- 1 BOZO BOZO 109 APR 7 19:49 1.TXT
|
|
-RW-RW-R-- 1 BOZO BOZO 109 APR 14 16:48 2.TXT
|
|
-RW-R--R-- 1 BOZO BOZO 725 APR 20 20:56 DATA-FILE</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note>
|
|
|
|
<para>The <filename>stdout</filename> of each process in
|
|
a pipe must be read as the <filename>stdin</filename>
|
|
of the next. If this is not the case, the data stream
|
|
will <firstterm>block</firstterm>, and the pipe will not
|
|
behave as expected.
|
|
<programlisting>cat file1 file2 | ls -l | sort
|
|
# The output from "cat file1 file2" disappears.</programlisting>
|
|
</para>
|
|
|
|
<para>A pipe runs as a <link linkend="childref">child
|
|
process</link>, and therefore cannot alter script
|
|
variables.
|
|
<programlisting>variable="initial_value"
|
|
echo "new_value" | read variable
|
|
echo "variable = $variable" # variable = initial_value</programlisting>
|
|
</para>
|
|
|
|
<para>If one of the commands in the pipe
|
|
aborts, this prematurely terminates execution of the
|
|
pipe. Called a <firstterm>broken pipe</firstterm>, this
|
|
condition sends a <replaceable>SIGPIPE</replaceable> <link
|
|
linkend="signald">signal</link>.</para>
|
|
|
|
</note>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>>|</token></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>||</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>||</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>or</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>logical operator</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title><link linkend="orref">OR logical operator</link></title>
|
|
<para>In a <link linkend="testconstructs1">test
|
|
construct</link>, the <token>||</token> operator causes
|
|
a return of <returnvalue>0</returnvalue> (success) if
|
|
<emphasis>either</emphasis> of the linked test conditions
|
|
is true.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="bgjob"/><token>&</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>
|
|
|
|
<para><anchor id="bgloop0"/></para>
|
|
<example id="bgloop">
|
|
<title>Running a loop in the background</title>
|
|
<programlisting>&bgloop;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>A command run in the background within a
|
|
script may cause the script to hang, waiting
|
|
for a keystroke. Fortunately, there is a <link
|
|
linkend="waithang">remedy</link> for this.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><anchor
|
|
id="logicaland"/><token>&&</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>&&</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>&&</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>and</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>logical operator</primary>
|
|
</indexterm>
|
|
|
|
<formalpara><title><link linkend="logops1">AND logical
|
|
operator</link></title>
|
|
|
|
<para>In a <link linkend="testconstructs1">test
|
|
construct</link>, the <token>&&</token> operator causes
|
|
a return of <returnvalue>0</returnvalue> (success) only if
|
|
<emphasis>both</emphasis> the linked test conditions
|
|
are true.</para>
|
|
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dashref"/><token>-</token></term>
|
|
<listitem><formalpara><title>option, prefix</title>
|
|
<para>Option flag for a command or filter. Prefix for
|
|
an operator. Prefix for a <link
|
|
linkend="defparam1">default parameter</link>
|
|
in <link linkend="paramsubref">parameter
|
|
substitution</link>.</para>
|
|
</formalpara>
|
|
<para><userinput>COMMAND -[Option1][Option2][...]</userinput></para>
|
|
<para><userinput>ls -al</userinput></para>
|
|
<para><userinput>sort -dfu $filename</userinput></para>
|
|
|
|
|
|
|
|
<para>
|
|
<programlisting>if [ $file1 -ot $file2 ]
|
|
then # ^
|
|
echo "File $file1 is older than $file2."
|
|
fi
|
|
|
|
if [ "$a" -eq "$b" ]
|
|
then # ^
|
|
echo "$a is equal to $b."
|
|
fi
|
|
|
|
if [ "$c" -eq 24 -a "$d" -eq 47 ]
|
|
then # ^ ^
|
|
echo "$c equals 24 and $d equals 47."
|
|
fi
|
|
|
|
|
|
param2=${param1:-$DEFAULTVAL}
|
|
# ^</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="doubledashref"/></para>
|
|
<para><command>--</command></para>
|
|
|
|
<para>The <firstterm>double-dash</firstterm>
|
|
<option>--</option> prefixes <firstterm>long</firstterm>
|
|
(verbatim) options to commands.</para>
|
|
|
|
<para><userinput>sort --ignore-leading-blanks</userinput></para>
|
|
|
|
<para>Used with a <link linkend="builtinref">Bash
|
|
builtin</link>, it means the <firstterm>end of
|
|
options</firstterm> to that particular command.</para>
|
|
|
|
<tip><para>This provides a handy means of removing
|
|
files whose <emphasis>names begin with a dash</emphasis>.
|
|
<screen><prompt>bash$ </prompt><userinput>ls -l</userinput>
|
|
<computeroutput>-rw-r--r-- 1 bozo bozo 0 Nov 25 12:29 -badname</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>rm -- -badname</userinput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l</userinput>
|
|
<computeroutput>total 0</computeroutput></screen>
|
|
</para></tip>
|
|
|
|
<para>The <firstterm>double-dash</firstterm> is also used in
|
|
conjunction with <link linkend="setref">set</link>.</para>
|
|
|
|
<para><userinput>set -- $variable</userinput> (as in <xref
|
|
linkend="setpos"/>)</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dashref2"/><token>-</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>-</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>-</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>redirection</primary>
|
|
<secondary>from/to stdin/stdout</secondary>
|
|
</indexterm>
|
|
<formalpara><title>redirection from/to <filename>stdin</filename> or <filename>stdout</filename> [dash]</title>
|
|
<para><anchor id="coxex"/></para>
|
|
</formalpara>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>cat -</userinput>
|
|
<userinput>abc</userinput>
|
|
<computeroutput>abc</computeroutput>
|
|
|
|
<computeroutput>...</computeroutput>
|
|
|
|
<userinput>Ctl-D</userinput></screen>
|
|
</para>
|
|
|
|
<para>As expected, <userinput>cat -</userinput> echoes
|
|
<filename>stdin</filename>, in this case keyboarded user input,
|
|
to <filename>stdout</filename>. But, does I/O redirection using
|
|
<command>-</command> have real-world applications?</para>
|
|
|
|
<para><programlisting>(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)
|
|
# Move entire file tree from one directory to another
|
|
# [courtesy Alan Cox <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 -)
|
|
#
|
|
# Also having same effect:
|
|
# cp -a /source/directory/* /dest/directory
|
|
# Or:
|
|
# cp -a /source/directory/* /source/directory/.[^.]* /dest/directory
|
|
# If there are hidden files in /source/directory.
|
|
</programlisting></para>
|
|
|
|
<para><programlisting>bunzip2 -c linux-2.6.16.tar.bz2 | tar xvf -
|
|
# --uncompress tar file-- | --then pass it to "tar"--
|
|
# If "tar" has not been patched to handle "bunzip2",
|
|
#+ this needs to be done in two discrete steps, using a pipe.
|
|
# The purpose of the exercise is to unarchive "bzipped" kernel source.
|
|
</programlisting></para>
|
|
|
|
<para>Note that in this context the <quote>-</quote> is not
|
|
itself a Bash operator, but rather an option recognized by
|
|
certain UNIX utilities that write to
|
|
<filename>stdout</filename>, such as <command>tar</command>,
|
|
<command>cat</command>, etc.</para>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo "whatever" | cat -</userinput>
|
|
<computeroutput>whatever</computeroutput> </screen>
|
|
</para>
|
|
|
|
|
|
<para>Where a filename is expected,
|
|
<replaceable>-</replaceable> redirects output to
|
|
<filename>stdout</filename> (sometimes seen with
|
|
<userinput>tar cf</userinput>), or accepts input from
|
|
<filename>stdin</filename>, rather than from a file.
|
|
<anchor id="filterdash"/>
|
|
This is a method of using a file-oriented utility as a
|
|
filter in a pipe.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>file</userinput>
|
|
<computeroutput>Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...</computeroutput>
|
|
</screen>
|
|
|
|
By itself on the command-line, <link
|
|
linkend="fileref">file</link> fails with an error message.
|
|
</para>
|
|
|
|
<para>
|
|
Add a <quote>-</quote> for a more useful result. This causes the
|
|
shell to await user input.
|
|
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>file -</userinput>
|
|
<userinput>abc</userinput>
|
|
<computeroutput>standard input: ASCII text</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>file -</userinput>
|
|
<userinput>#!/bin/bash</userinput>
|
|
<computeroutput>standard input: Bourne-Again shell script text executable</computeroutput>
|
|
</screen>
|
|
|
|
Now the command accepts input from <filename>stdin</filename>
|
|
and analyzes it.
|
|
</para>
|
|
|
|
<para>The <quote>-</quote> can be used to pipe
|
|
<filename>stdout</filename> to other commands. This permits
|
|
such stunts as <link linkend="prependref">prepending lines
|
|
to a file</link>.</para>
|
|
|
|
<para>Using <link linkend="diffref">diff</link> to
|
|
compare a file with a <emphasis>section</emphasis>
|
|
of another:</para>
|
|
|
|
<para><userinput>grep Linux file1 | diff file2 -</userinput></para>
|
|
|
|
|
|
<para>Finally, a real-world example using
|
|
<replaceable>-</replaceable> with <link
|
|
linkend="tarref">tar</link>.</para>
|
|
|
|
<example id="ex58">
|
|
<title>Backup of all files changed in last day</title>
|
|
<programlisting>&ex58;</programlisting>
|
|
</example>
|
|
|
|
<caution>
|
|
|
|
<para>Filenames beginning with
|
|
<quote>-</quote> may cause problems when coupled with the
|
|
<quote>-</quote> redirection operator. A script should
|
|
check for this and add an appropriate prefix to such
|
|
filenames, for example <filename>./-FILENAME</filename>,
|
|
<filename>$PWD/-FILENAME</filename>, or
|
|
<filename>$PATHNAME/-FILENAME</filename>.</para>
|
|
|
|
<para>If the value of a variable begins with a
|
|
<replaceable>-</replaceable>, this may likewise create
|
|
problems.
|
|
<programlisting>var="-n"
|
|
echo $var
|
|
# Has the effect of "echo -n", and outputs nothing.</programlisting>
|
|
</para>
|
|
</caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><token>-</token></term>
|
|
<listitem><formalpara><title>previous working directory</title>
|
|
<para>A <command>cd -</command> command changes to the
|
|
previous working directory. This uses the
|
|
<link linkend="oldpwd">$OLDPWD</link> <link
|
|
linkend="envref">environmental variable</link>.</para>
|
|
</formalpara>
|
|
<caution><para>Do not confuse the <quote>-</quote> used in this
|
|
sense with the <quote>-</quote> redirection
|
|
operator just discussed. The interpretation of the
|
|
<quote>-</quote> depends on the context in which it
|
|
appears.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-</token></term>
|
|
<listitem><formalpara><title>Minus</title>
|
|
<para>Minus sign in an <link linkend="arops1">arithmetic
|
|
operation</link>.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>=</token></term>
|
|
<listitem><formalpara><title>Equals</title>
|
|
<para><link linkend="eqref">Assignment operator</link>
|
|
<programlisting>a=28
|
|
echo $a # 28</programlisting></para>
|
|
</formalpara>
|
|
<para>In a <link linkend="equalsignref">different context</link>,
|
|
the <quote><token>=</token></quote> is a <link
|
|
linkend="scomparison1">string comparison</link>
|
|
operator.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>+</token></term>
|
|
<listitem><formalpara><title>Plus</title>
|
|
<para>Addition <link linkend="arops1">arithmetic
|
|
operator</link>.</para>
|
|
</formalpara>
|
|
<para>In a <link linkend="plusref">different context</link>,
|
|
the <token>+</token> is a <link linkend="regexp">Regular
|
|
Expression</link> operator.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>+</token></term>
|
|
<listitem><formalpara><title>Option</title>
|
|
<para>Option flag for a command or filter.</para>
|
|
</formalpara>
|
|
<para>Certain commands and <link
|
|
linkend="builtinref">builtins</link> use the
|
|
<option>+</option> to enable certain options and the
|
|
<option>-</option> to disable them. In <link
|
|
linkend="paramsubref">parameter substitution</link>,
|
|
the <option>+</option> prefixes an <link linkend="paramaltv">
|
|
alternate value</link> that a variable expands to.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="modulo00"/><token>%</token></term>
|
|
<listitem><formalpara><title><link linkend="moduloref">modulo</link></title>
|
|
<para>Modulo (remainder of a division) <link linkend="arops1">arithmetic
|
|
operation</link>.</para>
|
|
</formalpara>
|
|
<para><programlisting>let "z = 5 % 3"
|
|
echo $z # 2</programlisting></para>
|
|
<para>In a <link linkend="pctpatref">different context</link>,
|
|
the <token>%</token> is a <link linkend="psub2">pattern
|
|
matching</link> operator.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tilderef"/><token>~</token></term>
|
|
<listitem><formalpara><title>home directory [tilde]</title>
|
|
|
|
<para>This corresponds to the <link
|
|
linkend="homedirref">$HOME</link> internal variable.
|
|
|
|
<filename>~bozo</filename> is bozo's home directory,
|
|
and <command>ls ~bozo</command> lists the contents of it.
|
|
<token>~/</token> is the current user's home directory,
|
|
and <command>ls ~/</command> lists the contents of it.
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>echo ~bozo</userinput>
|
|
<computeroutput>/home/bozo</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ~</userinput>
|
|
<computeroutput>/home/bozo</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ~/</userinput>
|
|
<computeroutput>/home/bozo/</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ~:</userinput>
|
|
<computeroutput>/home/bozo:</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ~nonexistent-user</userinput>
|
|
<computeroutput>~nonexistent-user</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="workingdirref"/><token>~+</token></term>
|
|
<listitem><formalpara><title>current working directory</title>
|
|
<para>This corresponds to the <link
|
|
linkend="pwdref">$PWD</link> internal variable.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="prevworkingdir"/><token>~-</token></term>
|
|
<listitem><formalpara><title>previous working directory</title>
|
|
<para>This corresponds to the <link
|
|
linkend="oldpwd">$OLDPWD</link> internal variable.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>=~</token></term>
|
|
<listitem><formalpara><title><link linkend="regexmatchref">regular
|
|
expression match</link></title>
|
|
<para>This operator was introduced with <link
|
|
linkend="bash3ref">version 3</link> of Bash.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><anchor id="beglineref"/><token>^</token></term>
|
|
<listitem>
|
|
<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>
|
|
<indexterm>
|
|
<primary>uppercase modification</primary>
|
|
<secondary>parameter substitution</secondary>
|
|
</indexterm>
|
|
|
|
<formalpara><title>beginning-of-line</title>
|
|
<para>In a <link linkend="regexref">regular expression</link>, a
|
|
<quote>^</quote> addresses the <link
|
|
linkend="caretref">beginning of a line</link> of text.</para>
|
|
</formalpara>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>^</token></term>
|
|
<term><token>^^</token></term>
|
|
<listitem>
|
|
<formalpara><title><link linkend="casemodparamsub">Uppercase
|
|
conversion</link> in <firstterm>parameter substitution</firstterm>
|
|
(added in <link
|
|
linkend="bash4ref">version 4</link> of Bash)</title>
|
|
<para></para></formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="controlcharref"/>Control Characters</term>
|
|
<listitem>
|
|
<formalpara><title> change the behavior of the
|
|
terminal or text display.</title>
|
|
|
|
<para>A control character is a <keycap>CONTROL</keycap>
|
|
+ <keycap>key</keycap> combination (pressed
|
|
simultaneously).
|
|
|
|
A control character may also
|
|
be written in <firstterm>octal</firstterm> or
|
|
<firstterm>hexadecimal</firstterm> notation,
|
|
following an <firstterm>escape</firstterm>.</para>
|
|
</formalpara>
|
|
<para>Control characters are not normally useful inside a
|
|
script.</para>
|
|
|
|
|
|
<itemizedlist id="ctlchar">
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-A</userinput></para>
|
|
<para>Moves cursor to beginning of line of text
|
|
(on the command-line).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-B</userinput></para>
|
|
<para><userinput>Backspace</userinput>
|
|
(nondestructive).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="ctlcref"/></para>
|
|
<para><userinput>Ctl-C</userinput></para>
|
|
<para><userinput>Break</userinput>.
|
|
Terminate a foreground job.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="ctldref"/></para>
|
|
<para><userinput>Ctl-D</userinput></para>
|
|
<para><firstterm>Log out</firstterm> from a shell (similar to
|
|
<link linkend="exitcommandref">exit</link>).</para>
|
|
<para><userinput>EOF</userinput> (end-of-file). This also
|
|
terminates input from <filename>stdin</filename>.</para>
|
|
<para>When typing text on the console or in an
|
|
<firstterm>xterm</firstterm> window,
|
|
<userinput>Ctl-D</userinput> erases the character under the
|
|
cursor. When there are no characters present,
|
|
<userinput>Ctl-D</userinput> logs out of the session, as
|
|
expected. In an <firstterm>xterm</firstterm> window,
|
|
this has the effect of closing the window.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-E</userinput></para>
|
|
<para>Moves cursor to end of line of text
|
|
(on the command-line).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-F</userinput></para>
|
|
<para>Moves cursor forward one character position
|
|
(on the command-line).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="ctlgref"/></para>
|
|
<para><userinput>Ctl-G</userinput></para>
|
|
<para><userinput>BEL</userinput>. On some
|
|
old-time teletype terminals, this would actually ring
|
|
a bell. In an <firstterm>xterm</firstterm> it might
|
|
beep.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="ctlhref"/></para>
|
|
<para><userinput>Ctl-H</userinput></para>
|
|
<para><userinput>Rubout</userinput> (destructive backspace).
|
|
Erases characters the cursor backs over while
|
|
backspacing.</para>
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# Embedding Ctl-H in a string.
|
|
|
|
a="^H^H" # Two Ctl-H's -- backspaces
|
|
# ctl-V ctl-H, using vi/vim
|
|
echo "abcdef" # abcdef
|
|
echo
|
|
echo -n "abcdef$a " # abcd f
|
|
# Space at end ^ ^ Backspaces twice.
|
|
echo
|
|
echo -n "abcdef$a" # abcdef
|
|
# No space at end ^ Doesn't backspace (why?).
|
|
# Results may not be quite as expected.
|
|
echo; echo
|
|
|
|
# Constantin Hagemeier suggests trying:
|
|
# a=$'\010\010'
|
|
# a=$'\b\b'
|
|
# a=$'\x08\x08'
|
|
# But, this does not change the results.
|
|
|
|
########################################
|
|
|
|
# Now, try this.
|
|
|
|
rubout="^H^H^H^H^H" # 5 x Ctl-H.
|
|
|
|
echo -n "12345678"
|
|
sleep 2
|
|
echo -n "$rubout"
|
|
sleep 2</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-I</userinput></para>
|
|
<para><userinput>Horizontal tab</userinput>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="ctljref"/></para>
|
|
<para><userinput>Ctl-J</userinput></para>
|
|
<para><userinput>Newline</userinput> (line feed).
|
|
In a script, may also be expressed in octal notation --
|
|
'\012' or in hexadecimal -- '\x0a'.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-K</userinput></para>
|
|
<para><userinput>Vertical tab</userinput>.</para>
|
|
<para>When typing text on the console or in an
|
|
<firstterm>xterm</firstterm> window,
|
|
<userinput>Ctl-K</userinput> erases from the character
|
|
under the cursor to end of line. Within a script,
|
|
<userinput>Ctl-K</userinput> may behave differently,
|
|
as in Lee Lee Maschmeyer's example, below.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-L</userinput></para>
|
|
<para><userinput>Formfeed</userinput> (clear the terminal
|
|
screen). In a terminal, this has the same effect as the
|
|
<link linkend="clearref">clear</link> command. When sent
|
|
to a printer, a <userinput>Ctl-L</userinput> causes
|
|
an advance to end of the paper sheet.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="ctlmref"/></para>
|
|
<para><userinput>Ctl-M</userinput></para>
|
|
<para><userinput>Carriage return</userinput>.</para>
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# Thank you, Lee Maschmeyer, for this example.
|
|
|
|
read -n 1 -s -p \
|
|
$'Control-M leaves cursor at beginning of this line. Press Enter. \x0d'
|
|
# Of course, '0d' is the hex equivalent of Control-M.
|
|
echo >&2 # The '-s' makes anything typed silent,
|
|
#+ so it is necessary to go to new line explicitly.
|
|
|
|
read -n 1 -s -p $'Control-J leaves cursor on next line. \x0a'
|
|
# '0a' is the hex equivalent of Control-J, linefeed.
|
|
echo >&2
|
|
|
|
###
|
|
|
|
read -n 1 -s -p $'And Control-K\x0bgoes straight down.'
|
|
echo >&2 # Control-K is vertical tab.
|
|
|
|
# A better example of the effect of a vertical tab is:
|
|
|
|
var=$'\x0aThis is the bottom line\x0bThis is the top line\x0a'
|
|
echo "$var"
|
|
# This works the same way as the above example. However:
|
|
echo "$var" | col
|
|
# This causes the right end of the line to be higher than the left end.
|
|
# It also explains why we started and ended with a line feed --
|
|
#+ to avoid a garbled screen.
|
|
|
|
# As Lee Maschmeyer explains:
|
|
# --------------------------
|
|
# In the [first vertical tab example] . . . the vertical tab
|
|
#+ makes the printing go straight down without a carriage return.
|
|
# This is true only on devices, such as the Linux console,
|
|
#+ that can't go "backward."
|
|
# The real purpose of VT is to go straight UP, not down.
|
|
# It can be used to print superscripts on a printer.
|
|
# The col utility can be used to emulate the proper behavior of VT.
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-N</userinput></para>
|
|
<para>Erases a line of text recalled from
|
|
<firstterm>history buffer</firstterm>
|
|
<footnote><para>Bash stores a list of commands
|
|
previously issued from the command-line
|
|
in a <firstterm>buffer</firstterm>, or
|
|
memory space, for recall with the <link
|
|
linkend="builtinref">builtin</link>
|
|
<firstterm>history</firstterm>
|
|
commands.</para></footnote> (on the
|
|
command-line).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-O</userinput></para>
|
|
<para>Issues a <firstterm>newline</firstterm>
|
|
(on the command-line).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-P</userinput></para>
|
|
<para>Recalls last command from <firstterm>history
|
|
buffer</firstterm> (on the command-line).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-Q</userinput></para>
|
|
<para>Resume (<userinput>XON</userinput>).</para>
|
|
<para>This resumes <filename>stdin</filename> in a terminal.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-R</userinput></para>
|
|
<para>Backwards search for text in <firstterm>history
|
|
buffer</firstterm>
|
|
(on the command-line).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-S</userinput></para>
|
|
<para>Suspend (<userinput>XOFF</userinput>).</para>
|
|
<para>This freezes <filename>stdin</filename> in a terminal.
|
|
(Use Ctl-Q to restore input.)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-T</userinput></para>
|
|
<para>Reverses the position of the character the cursor
|
|
is on with the previous character (on the
|
|
command-line).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-U</userinput></para>
|
|
<para>Erase a line of input, from the cursor backward to
|
|
beginning of line. In some settings,
|
|
<userinput>Ctl-U</userinput> erases the entire
|
|
line of input, <emphasis>regardless of cursor
|
|
position</emphasis>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-V</userinput></para>
|
|
<para>When inputting text, <userinput>Ctl-V</userinput>
|
|
permits inserting control characters. For example, the
|
|
following two are equivalent:
|
|
<programlisting>echo -e '\x0a'
|
|
echo <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
|
|
<link linkend="whitespaceref">whitespace</link>. In
|
|
some settings, <userinput>Ctl-W</userinput> erases
|
|
backwards to first non-alphanumeric character.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-X</userinput></para>
|
|
<para>In certain word processing programs,
|
|
<firstterm>Cuts</firstterm> highlighted text
|
|
and copies to <firstterm>clipboard</firstterm>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-Y</userinput></para>
|
|
<para><firstterm>Pastes</firstterm> back text previously
|
|
erased (with <userinput>Ctl-U</userinput> or
|
|
<userinput>Ctl-W</userinput>).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><userinput>Ctl-Z</userinput></para>
|
|
<para><firstterm>Pauses</firstterm> a foreground job.</para>
|
|
<para><firstterm>Substitute</firstterm> operation in certain
|
|
word processing applications.</para>
|
|
<para><userinput>EOF</userinput> (end-of-file) character
|
|
in the MSDOS filesystem.</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whitespaceref"/>Whitespace</term>
|
|
<listitem>
|
|
<formalpara>
|
|
<title>functions as a separator between commands and/or
|
|
variables.</title>
|
|
<para>Whitespace consists of either
|
|
<firstterm>spaces</firstterm>,
|
|
<firstterm>tabs</firstterm>, <firstterm>blank
|
|
lines</firstterm>, or any combination thereof.
|
|
|
|
<footnote><para>A linefeed (<firstterm>newline</firstterm>)
|
|
is also a whitespace character. This explains
|
|
why a <firstterm>blank line</firstterm>,
|
|
consisting only of a linefeed, is considered
|
|
whitespace.</para></footnote>
|
|
|
|
In some contexts, such as <link linkend="wsbad">variable
|
|
assignment</link>, whitespace is not permitted, and
|
|
results in a syntax error.</para>
|
|
</formalpara>
|
|
|
|
<para>Blank lines have no effect on the action of a script,
|
|
and are therefore useful for visually separating functional
|
|
sections.</para>
|
|
|
|
<para><link linkend="ifsref">$IFS</link>, the special variable
|
|
separating <firstterm>fields</firstterm> of input to certain
|
|
commands. It defaults to whitespace.</para>
|
|
|
|
<sidebar><para>
|
|
<anchor id="fieldref"/><userinput>Definition:</userinput>
|
|
A <firstterm>field</firstterm> is a discrete chunk of data
|
|
expressed as a string of consecutive characters.
|
|
Separating each field from adjacent fields is either
|
|
<firstterm>whitespace</firstterm> or some other designated
|
|
character (often determined by the <token>$IFS</token>).
|
|
In some contexts, a field may be called a
|
|
<firstterm>record</firstterm>.
|
|
</para></sidebar>
|
|
|
|
<para><anchor id="quotingws"/></para>
|
|
<para>To preserve <firstterm>whitespace</firstterm>
|
|
within a string or in a variable, use <link
|
|
linkend="quotingref">quoting</link>.</para>
|
|
|
|
<para>UNIX <link linkend="filterdef">filters</link>
|
|
can target and operate on <firstterm>whitespace</firstterm>
|
|
using the <link linkend="posixref">POSIX</link> character class
|
|
<link linkend="wsposix">[:space:]</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
</chapter> <!-- Special characters used in shell scripts -->
|
|
|
|
|
|
|
|
<chapter id="variables">
|
|
<title>Introduction to Variables and Parameters</title>
|
|
|
|
<para><firstterm>Variables</firstterm> are how programming and
|
|
scripting languages represent data. A variable is nothing
|
|
more than a <firstterm>label</firstterm>, a name assigned to a
|
|
location or set of locations in computer memory holding an item
|
|
of data.</para>
|
|
|
|
<para>Variables appear in arithmetic operations and manipulation of
|
|
quantities, and in string parsing.</para>
|
|
|
|
|
|
<sect1 id="varsubn">
|
|
<title>Variable Substitution</title>
|
|
|
|
<para>The <firstterm>name</firstterm> of a variable is a placeholder
|
|
for its <firstterm>value</firstterm>, the data it holds.
|
|
Referencing (retrieving) its value is called
|
|
<firstterm>variable substitution</firstterm>.</para>
|
|
|
|
<variablelist id="dollarsign">
|
|
|
|
<varlistentry>
|
|
<term><token>$</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$</primary>
|
|
</indexterm> <indexterm>
|
|
<primary>variable</primary> <secondary>$</secondary>
|
|
</indexterm> <indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>substitution</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<para><anchor id="varnameval"/></para>
|
|
<para>Let us carefully distinguish between the
|
|
<firstterm>name</firstterm> of a variable
|
|
and its <firstterm>value</firstterm>. If
|
|
<userinput>variable1</userinput> is the name of a
|
|
variable, then <userinput>$variable1</userinput>
|
|
is a reference to its <firstterm>value</firstterm>,
|
|
the data item it contains.
|
|
|
|
<footnote>
|
|
|
|
<para><anchor id="lvalueref"/>Technically, the
|
|
<firstterm>name</firstterm> of a variable is called an
|
|
<firstterm>lvalue</firstterm>, meaning that it appears
|
|
on the <emphasis>left</emphasis> side of an assignment
|
|
statment, as in <userinput>VARIABLE=23</userinput>.
|
|
A variable's <firstterm>value</firstterm> is
|
|
an <firstterm>rvalue</firstterm>, meaning that
|
|
it appears on the <emphasis>right</emphasis>
|
|
side of an assignment statement, as in
|
|
<userinput>VAR2=$VARIABLE</userinput>.</para>
|
|
|
|
<para><anchor id="pointerref"/>A variable's
|
|
<firstterm>name</firstterm> is, in fact,
|
|
a <firstterm>reference</firstterm>, a
|
|
<firstterm>pointer</firstterm> to the memory
|
|
location(s) where the actual data associated with
|
|
that variable is kept.</para>
|
|
|
|
</footnote>
|
|
|
|
|
|
</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>variable1=23</userinput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo variable1</userinput>
|
|
<computeroutput>variable1</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $variable1</userinput>
|
|
<computeroutput>23</computeroutput></screen>
|
|
</para>
|
|
|
|
|
|
<para>The only times a variable appears <quote>naked</quote>
|
|
-- without the <token>$</token> prefix -- is when
|
|
declared or assigned, when <firstterm>unset</firstterm>,
|
|
when <link linkend="exportref">exported</link>,
|
|
in an arithmetic expression within <link
|
|
linkend="dblparens">double parentheses
|
|
(( ... ))</link>, or in the special case of a variable
|
|
representing a <link linkend="signald">signal</link>
|
|
(see <xref linkend="ex76"/>). Assignment may be with an
|
|
<token>=</token> (as in <parameter>var1=27</parameter>),
|
|
in a <link linkend="readref">read</link> statement,
|
|
and at the head of a loop (<parameter>for var2 in 1
|
|
2 3</parameter>).</para>
|
|
|
|
|
|
<para><anchor id="dblquo"/>Enclosing a referenced value in
|
|
<firstterm>double quotes</firstterm> (<token>" ... "</token>)
|
|
does not interfere with variable substitution. This is
|
|
called <firstterm>partial quoting</firstterm>, sometimes
|
|
referred to as <quote>weak quoting.</quote> <anchor
|
|
id="snglquo"/>Using single quotes (<token>' ... '</token>)
|
|
causes the variable name to be used literally, and no
|
|
substitution will take place. This is <firstterm>full
|
|
quoting</firstterm>, sometimes referred to as 'strong
|
|
quoting.' See <xref linkend="quoting"/> for a
|
|
detailed discussion.</para>
|
|
|
|
<para>Note that <userinput>$variable</userinput> is actually a
|
|
simplified form of
|
|
<userinput>${variable}</userinput>. In contexts
|
|
where the <userinput>$variable</userinput> syntax
|
|
causes an error, the longer form may work (see <xref
|
|
linkend="Parameter-Substitution"/>, below).</para>
|
|
|
|
<para><anchor id="varunsetting"/></para>
|
|
<example id="ex9">
|
|
<title>Variable assignment and substitution</title>
|
|
<programlisting>&ex9;</programlisting>
|
|
</example>
|
|
|
|
<caution>
|
|
|
|
<para><anchor id="uninitvar1"/></para>
|
|
<para>An uninitialized variable has a
|
|
<quote>null</quote> value -- no assigned value at all
|
|
(<emphasis>not</emphasis> zero!).
|
|
|
|
<programlisting>if [ -z "$unassigned" ]
|
|
then
|
|
echo "\$unassigned is NULL."
|
|
fi # $unassigned is NULL.</programlisting></para>
|
|
|
|
<para>Using a variable before
|
|
assigning a value to it may cause problems.
|
|
It is nevertheless possible to perform arithmetic operations
|
|
on an uninitialized variable.
|
|
|
|
<programlisting>echo "$uninitialized" # (blank line)
|
|
let "uninitialized += 5" # Add 5 to it.
|
|
echo "$uninitialized" # 5
|
|
|
|
# Conclusion:
|
|
# An uninitialized variable has no value,
|
|
#+ however it evaluates as 0 in an arithmetic operation.</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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>assignment</secondary>
|
|
</indexterm>
|
|
|
|
<para>the assignment operator (<emphasis>no space before
|
|
and after</emphasis>)</para>
|
|
|
|
|
|
<caution>
|
|
<para>Do not confuse this with <link
|
|
linkend="equalsignref">=</link> and
|
|
<link linkend="equalref">-eq</link>, which
|
|
<link linkend="ifthen">test</link>,
|
|
rather than assign!</para>
|
|
|
|
<para>Note that <token>=</token> can be either
|
|
an <firstterm>assignment</firstterm> or a
|
|
<firstterm>test</firstterm> operator, depending on
|
|
context.</para>
|
|
</caution>
|
|
|
|
|
|
<para><anchor id="ex15_0"/></para>
|
|
<example id="ex15">
|
|
<title>Plain Variable Assignment</title>
|
|
<programlisting>&ex15;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="ex16_0"/></para>
|
|
<example id="ex16">
|
|
<title>Variable Assignment, plain and fancy</title>
|
|
<programlisting>&ex16;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="commandsubref0"/></para>
|
|
|
|
<para>Variable assignment using the <firstterm>$(...)</firstterm>
|
|
mechanism (a newer method than <link
|
|
linkend="backquotesref">backquotes</link>). This is
|
|
likewise a form of <link linkend="commandsubref">command
|
|
substitution</link>.</para>
|
|
|
|
<para><programlisting># From /etc/rc.d/rc.local
|
|
R=$(cat /etc/redhat-release)
|
|
arch=$(uname -m)</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Variable Assignment -->
|
|
|
|
<sect1 id="untyped">
|
|
<title>Bash Variables Are Untyped</title>
|
|
|
|
<para><anchor id="bvuntyped"/></para>
|
|
<para>Unlike many other programming languages, Bash does not segregate
|
|
its variables by <quote>type.</quote> Essentially, <emphasis>Bash
|
|
variables are character strings</emphasis>, but, depending on
|
|
context, Bash permits arithmetic operations and comparisons on
|
|
variables. The determining factor is whether the value of a
|
|
variable contains only digits.</para>
|
|
|
|
<example id="intorstring">
|
|
<title>Integer or string?</title>
|
|
<programlisting>&intorstring;</programlisting>
|
|
</example>
|
|
|
|
<para>Untyped variables are both a blessing and a curse. They permit
|
|
more flexibility in scripting and make it easier to grind out
|
|
lines of code (and give you enough rope to hang yourself!).
|
|
However, they likewise permit subtle errors to creep in
|
|
and encourage sloppy programming habits.</para>
|
|
|
|
<para>To lighten the burden of keeping track of variable
|
|
types in a script, Bash <emphasis>does</emphasis> permit
|
|
<link linkend="declareref">declaring</link> variables.</para>
|
|
|
|
</sect1> <!-- Bash Variables Are Untyped-->
|
|
|
|
|
|
<sect1 id="othertypesv">
|
|
<title>Special Variable Types</title>
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
<term><replaceable>Local variables</replaceable></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>local</secondary>
|
|
</indexterm>
|
|
|
|
<para>Variables <link
|
|
linkend="scoperef">visible</link> only within a <link
|
|
linkend="codeblockref">code block</link> or function (see
|
|
also <link linkend="localref">local variables</link> in
|
|
<link linkend="functionref">functions</link>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="envref"/><replaceable>Environmental variables</replaceable></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>environmental</secondary>
|
|
</indexterm>
|
|
|
|
<para>Variables that affect the behavior of the shell and
|
|
user interface</para>
|
|
|
|
<note>
|
|
|
|
<para>In a more general context, each <link
|
|
linkend="processref">process</link> has an
|
|
<quote>environment</quote>, that is, a group of
|
|
variables that the process may reference. In this sense,
|
|
the shell behaves like any other process.</para>
|
|
|
|
<para>Every time a shell starts, it creates shell variables that
|
|
correspond to its own environmental variables. Updating
|
|
or adding new environmental variables causes the
|
|
shell to update its environment, and all the shell's
|
|
<firstterm>child processes</firstterm> (the commands it
|
|
executes) inherit this environment.</para>
|
|
|
|
</note>
|
|
|
|
<caution>
|
|
<para>The space allotted to the environment is limited.
|
|
Creating too many environmental variables or ones that use up
|
|
excessive space may cause problems.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>eval "`seq 10000 | sed -e 's/.*/export var&=ZZZZZZZZZZZZZZ/'`"</userinput>
|
|
|
|
<prompt>bash$ </prompt><userinput>du</userinput>
|
|
<computeroutput>bash: /usr/bin/du: Argument list too long</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Note: this <quote>error</quote> has been fixed, as of
|
|
kernel version 2.6.23.</para>
|
|
<para>(Thank you, Stéphane Chazelas for the clarification,
|
|
and for providing the above example.)</para>
|
|
</caution>
|
|
|
|
<para>If a script sets environmental variables, they need to be
|
|
<quote>exported,</quote> that is, reported to the
|
|
<firstterm>environment</firstterm> local to
|
|
the script. This is the function of the <link
|
|
linkend="exportref">export</link> command.</para>
|
|
|
|
<anchor id="childref"/>
|
|
<note>
|
|
<para>A script can <command>export</command> variables only
|
|
to child <link linkend="processref">processes</link>,
|
|
that is, only to commands or processes which that
|
|
particular script initiates. A script invoked from
|
|
the command-line <replaceable>cannot</replaceable>
|
|
export variables back to the command-line environment.
|
|
<emphasis><link linkend="forkref">Child processes</link>
|
|
cannot export variables back to the parent processes that
|
|
spawned them.</emphasis></para>
|
|
<para><anchor id="childref2"/><userinput>Definition:</userinput>
|
|
A <firstterm>child process</firstterm> is a
|
|
subprocess launched by another process, its <link
|
|
linkend="parentref">parent</link>.</para>
|
|
</note>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="posparamref1"/><replaceable>Positional parameters</replaceable></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>parameter</primary>
|
|
<secondary>positional</secondary>
|
|
</indexterm>
|
|
|
|
<para>Arguments passed to the script from the command
|
|
line
|
|
<footnote><para>Note that <link
|
|
linkend="passedargs"><firstterm>functions</firstterm>
|
|
also take positional parameters</link>.</para></footnote>
|
|
: <varname>$0</varname>, <varname>$1</varname>,
|
|
<varname>$2</varname>, <varname>$3</varname> . . .</para>
|
|
|
|
<para><anchor id="scrnameparam"/><varname>$0</varname> is
|
|
the name of the script itself,
|
|
<varname>$1</varname> is the first argument,
|
|
<varname>$2</varname> the second, <varname>$3</varname>
|
|
the third, and so forth.
|
|
|
|
<footnote>
|
|
<para><anchor id="arg0"/>The process calling the
|
|
script sets the <varname>$0</varname> parameter. By
|
|
convention, this parameter is the name of the script. See
|
|
the <link linkend="manref">manpage</link> (manual page)
|
|
for <command>execv</command>.</para>
|
|
<para>From the <firstterm>command-line</firstterm>, however,
|
|
<varname>$0</varname> is the name of the shell.
|
|
<screen><prompt>bash$ </prompt><userinput>echo $0</userinput>
|
|
<computeroutput>bash</computeroutput>
|
|
|
|
<prompt>tcsh% </prompt><userinput>echo $0</userinput>
|
|
<computeroutput>tcsh</computeroutput></screen></para>
|
|
</footnote>
|
|
|
|
<anchor id="bracketnotation"/>
|
|
After <varname>$9</varname>, the arguments must be enclosed
|
|
in brackets, for example, <varname>${10}</varname>,
|
|
<varname>${11}</varname>, <varname>${12}</varname>.</para>
|
|
|
|
<para>The special variables <link linkend="appref">$* and $@</link>
|
|
denote <emphasis>all</emphasis> the positional parameters.</para>
|
|
|
|
<example id="ex17">
|
|
<title>Positional Parameters</title>
|
|
<programlisting>&ex17;</programlisting>
|
|
</example>
|
|
|
|
<para><firstterm>Bracket notation</firstterm> for positional
|
|
parameters leads to a fairly simple way of referencing
|
|
the <emphasis>last</emphasis> argument passed to a
|
|
script on the command-line. This also requires <link
|
|
linkend="varrefnew">indirect referencing</link>.</para>
|
|
|
|
<para><anchor id="lastargref"/></para>
|
|
<para><programlisting>args=$# # Number of args passed.
|
|
lastarg=${!args}
|
|
# Note: This is an *indirect reference* to $args ...
|
|
|
|
|
|
# Or: lastarg=${!#} (Thanks, Chris Monson.)
|
|
# This is an *indirect reference* to the $# variable.
|
|
# Note that lastarg=${!$#} doesn't work.
|
|
</programlisting></para>
|
|
|
|
|
|
<para>Some scripts can perform different operations,
|
|
depending on which name they are invoked with. For this
|
|
to work, the script needs to check <varname>$0</varname>,
|
|
the name it was invoked by.
|
|
|
|
<footnote><para>If the the script is <link
|
|
linkend="sourceref">sourced</link> or <link
|
|
linkend="symlinkref">symlinked</link>, then
|
|
this will not work. It is safer to check <link
|
|
linkend="bashsourceref">$BASH_Source</link>.</para></footnote>
|
|
|
|
There must also exist symbolic links to all the alternate
|
|
names of the script. See <xref linkend="hellol"/>.</para>
|
|
|
|
<para><anchor id="nullvar"/></para>
|
|
<tip><para>If a script expects a command-line parameter
|
|
but is invoked without one, this may cause a <firstterm>null
|
|
variable assignment</firstterm>, generally an undesirable
|
|
result. One way to prevent this is to append an extra
|
|
character to both sides of the assignment statement using
|
|
the expected positional parameter. </para></tip>
|
|
|
|
<programlisting>variable1_=$1_ # Rather than variable1=$1
|
|
# This will prevent an error, even if positional parameter is absent.
|
|
|
|
critical_argument01=$variable1_
|
|
|
|
# The extra character can be stripped off later, like so.
|
|
variable1=${variable1_/_/}
|
|
# Side effects only if $variable1_ begins with an underscore.
|
|
# This uses one of the parameter substitution templates discussed later.
|
|
# (Leaving out the replacement pattern results in a deletion.)
|
|
|
|
# A more straightforward way of dealing with this is
|
|
#+ to simply test whether expected positional parameters have been passed.
|
|
if [ -z $1 ]
|
|
then
|
|
exit $E_MISSING_POS_PARAM
|
|
fi
|
|
|
|
|
|
# However, as Fabian Kreutz points out,
|
|
#+ the above method may have unexpected side-effects.
|
|
# A better method is parameter substitution:
|
|
# ${1:-$DefaultVal}
|
|
# See the "Parameter Substition" section
|
|
#+ in the "Variables Revisited" chapter.
|
|
</programlisting>
|
|
|
|
<para>---</para>
|
|
|
|
<example id="ex18">
|
|
<title><firstterm>wh</firstterm>, <firstterm>
|
|
whois</firstterm> domain name lookup</title>
|
|
<programlisting>&ex18;</programlisting>
|
|
</example>
|
|
|
|
<para>---</para>
|
|
|
|
<para><anchor id="shiftref"/></para>
|
|
<para>
|
|
<indexterm>
|
|
<primary>shift</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>shift</secondary>
|
|
</indexterm>
|
|
The <command>shift</command> command reassigns the positional
|
|
parameters, in effect shifting them to the left one notch.</para>
|
|
|
|
<para><varname>$1</varname> <--- <varname>$2</varname>, <varname>$2</varname> <--- <varname>$3</varname>, <varname>$3</varname> <--- <varname>$4</varname>, etc.</para>
|
|
|
|
<para>The old <varname>$1</varname> disappears, but
|
|
<emphasis><varname>$0</varname> (the script name)
|
|
does not change</emphasis>. If you use a large number of
|
|
positional parameters to a script, <command>shift</command>
|
|
lets you access those past <literal>10</literal>, although
|
|
<link linkend="bracketnotation">{bracket} notation</link>
|
|
also permits this.</para>
|
|
|
|
<example id="ex19">
|
|
<title>Using <firstterm>shift</firstterm></title>
|
|
<programlisting>&ex19;</programlisting>
|
|
</example>
|
|
|
|
<para>The <command>shift</command> command can take a numerical
|
|
parameter indicating how many positions to shift.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
# shift-past.sh
|
|
|
|
shift 3 # Shift 3 positions.
|
|
# n=3; shift $n
|
|
# Has the same effect.
|
|
|
|
echo "$1"
|
|
|
|
exit 0
|
|
|
|
# ======================== #
|
|
|
|
|
|
$ sh shift-past.sh 1 2 3 4 5
|
|
4
|
|
|
|
# However, as Eleni Fragkiadaki, points out,
|
|
#+ attempting a 'shift' past the number of
|
|
#+ positional parameters ($#) returns an exit status of 1,
|
|
#+ and the positional parameters themselves do not change.
|
|
# This means possibly getting stuck in an endless loop. . . .
|
|
# For example:
|
|
# until [ -z "$1" ]
|
|
# do
|
|
# echo -n "$1 "
|
|
# shift 20 # If less than 20 pos params,
|
|
# done #+ then loop never ends!
|
|
#
|
|
# When in doubt, add a sanity check. . . .
|
|
# shift 20 || break
|
|
# ^^^^^^^^</programlisting></para>
|
|
|
|
<note><para>The <command>shift</command> command works in a similar
|
|
fashion on parameters passed to a <link
|
|
linkend="functionref">function</link>. See <xref
|
|
linkend="multiplication"/>.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Special Variable Types -->
|
|
|
|
|
|
</chapter> <!-- Variables -->
|
|
|
|
|
|
|
|
<chapter id="quoting">
|
|
<title>Quoting</title>
|
|
|
|
<para><anchor id="quotingref"/></para>
|
|
|
|
<indexterm>
|
|
<primary>"</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>"</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>'</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>'</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>quote</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>\</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>\</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escape</primary>
|
|
</indexterm>
|
|
<para>Quoting means just that, bracketing a string in quotes. This
|
|
has the effect of protecting <link linkend="scharlist1">special
|
|
characters</link> in the string from reinterpretation
|
|
or expansion by the shell or shell script. (A character
|
|
is <quote>special</quote> if it has an interpretation
|
|
other than its literal meaning. For example, the <link
|
|
linkend="asteriskref">asterisk *</link> represents
|
|
a <firstterm>wild card</firstterm> character in
|
|
<link linkend="globbingref">globbing</link> and <link
|
|
linkend="regexref">Regular Expressions</link>).</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ls -l [Vv]*</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 324 Apr 2 15:05 VIEWDATA.BAT
|
|
-rw-rw-r-- 1 bozo bozo 507 May 4 14:25 vartrace.sh
|
|
-rw-rw-r-- 1 bozo bozo 539 Apr 14 17:11 viewdata.sh
|
|
</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l '[Vv]*'</userinput>
|
|
<computeroutput>ls: [Vv]*: No such file or directory</computeroutput></screen>
|
|
</para>
|
|
|
|
<para><anchor id="quotingdef"/></para>
|
|
<sidebar><para>In everyday speech or writing, when we
|
|
<quote>quote</quote> a phrase, we set it apart and give it special
|
|
meaning. In a Bash script, when we <firstterm>quote</firstterm> a
|
|
string, we set it apart and protect its <firstterm>literal</firstterm>
|
|
meaning.</para></sidebar>
|
|
|
|
<para>Certain programs and utilities reinterpret or expand
|
|
special characters in a quoted string. An important use of
|
|
quoting is protecting a command-line parameter from the shell,
|
|
but still letting the calling program expand it.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep '[Ff]irst' *.txt</userinput>
|
|
<computeroutput>file1.txt:This is the first line of file1.txt.
|
|
file2.txt:This is the First line of file2.txt.</computeroutput></screen>
|
|
</para>
|
|
|
|
<para>Note that the unquoted <userinput>grep [Ff]irst *.txt</userinput>
|
|
works under the Bash shell.
|
|
<footnote><para>Unless there is a file named
|
|
<filename>first</filename> in the current working directory. Yet
|
|
another reason to <firstterm>quote</firstterm>. (Thank you, Harald
|
|
Koenig, for pointing this out.</para></footnote>
|
|
</para>
|
|
|
|
|
|
<para>Quoting can also suppress <link linkend="echoref">echo's</link>
|
|
<quote>appetite</quote> for newlines.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo $(ls -l)</userinput>
|
|
<computeroutput>total 8 -rw-rw-r-- 1 bo bo 13 Aug 21 12:57 t.sh -rw-rw-r-- 1 bo bo 78 Aug 21 12:57 u.sh</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo "$(ls -l)"</userinput>
|
|
<computeroutput>total 8
|
|
-rw-rw-r-- 1 bo bo 13 Aug 21 12:57 t.sh
|
|
-rw-rw-r-- 1 bo bo 78 Aug 21 12:57 u.sh</computeroutput></screen>
|
|
</para>
|
|
|
|
|
|
<sect1 id="quotingvar">
|
|
<title>Quoting Variables</title>
|
|
|
|
|
|
<para>When referencing a variable, it is generally advisable to
|
|
enclose its name in double quotes.
|
|
This prevents reinterpretation of all special characters within
|
|
the quoted string -- except <token>$</token>, <token>`</token>
|
|
(backquote), and <token>\</token> (escape).
|
|
|
|
<footnote>
|
|
|
|
<para><anchor id="quotingbsl"/></para>
|
|
<para>Encapsulating <quote>!</quote> within double
|
|
quotes gives an error when used <emphasis>from the command
|
|
line</emphasis>. This is interpreted as a <link
|
|
linkend="histcommands">history command</link>. Within a script,
|
|
though, this problem does not occur, since the Bash history
|
|
mechanism is disabled then.</para>
|
|
|
|
<para>Of more concern is the <emphasis>apparently</emphasis>
|
|
inconsistent behavior of <replaceable>\</replaceable>
|
|
within double quotes, and especially following an
|
|
<command>echo -e</command> command.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo hello\!</userinput>
|
|
<computeroutput>hello!</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo "hello\!"</userinput>
|
|
<computeroutput>hello\!</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo \</userinput>
|
|
<computeroutput>></computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo "\"</userinput>
|
|
<computeroutput>></computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo \a</userinput>
|
|
<computeroutput>a</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo "\a"</userinput>
|
|
<computeroutput>\a</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo x\ty</userinput>
|
|
<computeroutput>xty</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo "x\ty"</userinput>
|
|
<computeroutput>x\ty</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -e x\ty</userinput>
|
|
<computeroutput>xty</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo -e "x\ty"</userinput>
|
|
<computeroutput>x y</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Double quotes following an <firstterm>echo</firstterm>
|
|
<emphasis>sometimes</emphasis> escape
|
|
<replaceable>\</replaceable>. Moreover, the
|
|
<option>-e</option> option to <firstterm>echo</firstterm>
|
|
causes the <quote>\t</quote> to be interpreted as a
|
|
<firstterm>tab</firstterm>.</para>
|
|
|
|
<para>(Thank you, Wayne Pollock, for pointing this out, and Geoff
|
|
Lee and Daniel Barclay for explaining it.) </para>
|
|
|
|
</footnote>
|
|
|
|
Keeping <token>$</token> as a special character within
|
|
double quotes permits referencing a quoted variable
|
|
(<replaceable>"$variable"</replaceable>), that is, replacing the
|
|
variable with its value (see <xref linkend="ex9"/>, above).</para>
|
|
|
|
<para><anchor id="wsquo"/></para>
|
|
<para>Use double quotes to prevent word splitting.
|
|
|
|
<footnote><para><anchor id="wsplitref"/><quote>Word
|
|
splitting,</quote> in this context, means dividing
|
|
a character string into separate and discrete
|
|
arguments.</para></footnote>
|
|
|
|
An argument enclosed in double quotes presents
|
|
itself as a single word, even if it contains <link
|
|
linkend="whitespaceref">whitespace</link> separators.</para>
|
|
|
|
|
|
<para><anchor id="varsplitting"/></para>
|
|
<para><programlisting>List="one two three"
|
|
|
|
for a in $List # Splits the variable in parts at whitespace.
|
|
do
|
|
echo "$a"
|
|
done
|
|
# one
|
|
# two
|
|
# three
|
|
|
|
echo "---"
|
|
|
|
for a in "$List" # Preserves whitespace in a single variable.
|
|
do # ^ ^
|
|
echo "$a"
|
|
done
|
|
# one two three</programlisting></para>
|
|
|
|
<para>A more elaborate example:</para>
|
|
|
|
<para><programlisting>variable1="a variable containing five words"
|
|
COMMAND This is $variable1 # Executes COMMAND with 7 arguments:
|
|
# "This" "is" "a" "variable" "containing" "five" "words"
|
|
|
|
COMMAND "This is $variable1" # Executes COMMAND with 1 argument:
|
|
# "This is a variable containing five words"
|
|
|
|
|
|
variable2="" # Empty.
|
|
|
|
COMMAND $variable2 $variable2 $variable2
|
|
# Executes COMMAND with no arguments.
|
|
COMMAND "$variable2" "$variable2" "$variable2"
|
|
# Executes COMMAND with 3 empty arguments.
|
|
COMMAND "$variable2 $variable2 $variable2"
|
|
# Executes COMMAND with 1 argument (2 spaces).
|
|
|
|
# Thanks, Stéphane Chazelas.
|
|
</programlisting></para>
|
|
|
|
|
|
<tip><para>Enclosing the arguments to an <command>echo</command>
|
|
statement in double quotes is necessary only when word splitting
|
|
or preservation of <link linkend="whitespaceref">whitespace</link>
|
|
is an issue.</para></tip>
|
|
|
|
<example id="weirdvars">
|
|
<title>Echoing Weird Variables</title>
|
|
<programlisting>&weirdvars;</programlisting>
|
|
</example>
|
|
|
|
<para>Single quotes (<token>' '</token>) operate similarly to double
|
|
quotes, but do not permit referencing variables, since
|
|
the special meaning of <token>$</token> is turned off.
|
|
Within single quotes, <emphasis>every</emphasis> special
|
|
character except <token>'</token> gets interpreted literally.
|
|
Consider single quotes (<quote>full quoting</quote>) to be a
|
|
stricter method of quoting than double quotes (<quote>partial
|
|
quoting</quote>).</para>
|
|
|
|
<note><para>Since even the escape character (<token>\</token>)
|
|
gets a literal interpretation within single quotes, trying to
|
|
enclose a single quote within single quotes will not yield the
|
|
expected result.
|
|
<programlisting>echo "Why can't I write 's between single quotes"
|
|
|
|
echo
|
|
|
|
# The roundabout method.
|
|
echo 'Why can'\''t I write '"'"'s between single quotes'
|
|
# |-------| |----------| |-----------------------|
|
|
# Three single-quoted strings, with escaped and quoted single quotes between.
|
|
|
|
# This example courtesy of Stéphane Chazelas.</programlisting>
|
|
</para></note>
|
|
|
|
</sect1> <!-- Quoting Variables -->
|
|
|
|
|
|
|
|
<sect1 id="escapingsection">
|
|
<title>Escaping</title>
|
|
|
|
<para><anchor id="escp"/><firstterm>Escaping</firstterm> is a method
|
|
of quoting single characters. The <token>escape</token>
|
|
(<token>\</token>) preceding a character tells the shell to
|
|
interpret that character literally.</para>
|
|
|
|
<caution><para>With certain commands and utilities, such as <link
|
|
linkend="echoref">echo</link> and <link
|
|
linkend="sedref">sed</link>, escaping a character may have the
|
|
opposite effect - it can toggle on a special meaning for that
|
|
character.</para></caution>
|
|
|
|
<variablelist id="specialmeanings">
|
|
<title><anchor id="spm"/>Special meanings of certain
|
|
escaped characters</title>
|
|
|
|
<varlistentry>
|
|
<term>used with <command>echo</command> and
|
|
<command>sed</command></term>
|
|
<listitem><para></para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\n</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\n</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\n</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>newline</primary>
|
|
</indexterm>
|
|
<para>means newline</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\r</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\r</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\r</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>carriage return</primary>
|
|
</indexterm>
|
|
<para>means return</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\t</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\t</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\t</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>tabulation</primary>
|
|
</indexterm>
|
|
<para>means tab</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\v</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\v</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\v</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>vertical tabulation</primary>
|
|
</indexterm>
|
|
<para> means vertical tab</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\b</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\b</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\b</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>backspace</primary>
|
|
</indexterm>
|
|
<para>means backspace</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\a</token></term>
|
|
<listitem>
|
|
<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>
|
|
<para>means <firstterm>alert</firstterm> (beep or flash)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\0xx</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\0xx</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\0nn</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>octal ASCII</primary>
|
|
</indexterm>
|
|
<para><anchor id="octalref"/>translates to the
|
|
octal <link linkend="asciidef">ASCII</link>
|
|
equivalent of <replaceable>0nn</replaceable>, where
|
|
<replaceable>nn</replaceable> is a string of digits</para>
|
|
|
|
<important>
|
|
<para><anchor id="strq"/></para>
|
|
<para>The <userinput>$' ... '</userinput>
|
|
<link linkend="quotingref">quoted</link> string-expansion
|
|
construct is a mechanism that uses escaped octal or hex values
|
|
to assign ASCII characters to variables, e.g.,
|
|
<command>quote=$'\042'</command>.</para>
|
|
</important>
|
|
|
|
<example id="escaped">
|
|
<title>Escaped Characters</title>
|
|
<programlisting>&escaped;</programlisting>
|
|
</example>
|
|
|
|
<para>A more elaborate example:</para>
|
|
<example id="bashek">
|
|
<title>Detecting key-presses</title>
|
|
<programlisting>&bashek;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="ex77"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\"</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\"</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\"</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>quote</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\$</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>dollar</primary>
|
|
</indexterm>
|
|
<para>gives the dollar sign its literal meaning
|
|
(variable name following <token>\$</token> will not be
|
|
referenced)</para>
|
|
<para><programlisting>echo "\$variable01" # $variable01
|
|
echo "The book cost \$7.98." # The book cost $7.98.</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry><term><token>\\</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\\</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>escaped character</primary>
|
|
<secondary>\\</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>double backslash</primary>
|
|
</indexterm>
|
|
<para>gives the backslash its literal meaning</para>
|
|
<para><programlisting>echo "\\" # Results in \
|
|
|
|
# Whereas . . .
|
|
|
|
echo "\" # Invokes secondary prompt from the command-line.
|
|
# In a script, gives an error message.
|
|
|
|
# However . . .
|
|
|
|
echo '\' # Results in \</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<note>
|
|
<para>The behavior of <token>\</token> depends on whether
|
|
it is escaped, <link linkend="snglquo">strong-quoted</link>,
|
|
<link linkend="dblquo">weak-quoted</link>, or appearing within
|
|
<link linkend="commandsubref">command substitution</link> or a
|
|
<link linkend="heredocref">here document</link>.
|
|
|
|
<programlisting> # Simple escaping and quoting
|
|
echo \z # z
|
|
echo \\z # \z
|
|
echo '\z' # \z
|
|
echo '\\z' # \\z
|
|
echo "\z" # \z
|
|
echo "\\z" # \z
|
|
|
|
# Command substitution
|
|
echo `echo \z` # z
|
|
echo `echo \\z` # z
|
|
echo `echo \\\z` # \z
|
|
echo `echo \\\\z` # \z
|
|
echo `echo \\\\\\z` # \z
|
|
echo `echo \\\\\\\z` # \\z
|
|
echo `echo "\z"` # \z
|
|
echo `echo "\\z"` # \z
|
|
|
|
# Here document
|
|
cat <<EOF
|
|
\z
|
|
EOF # \z
|
|
|
|
cat <<EOF
|
|
\\z
|
|
EOF # \z
|
|
|
|
# These examples supplied by Stéphane Chazelas.</programlisting>
|
|
</para>
|
|
|
|
<para>Elements of a string assigned to a variable may be escaped, but
|
|
the escape character alone may not be assigned to a variable.
|
|
<programlisting>variable=\
|
|
echo "$variable"
|
|
# Will not work - gives an error message:
|
|
# test.sh: : command not found
|
|
# A "naked" escape cannot safely be assigned to a variable.
|
|
#
|
|
# What actually happens here is that the "\" escapes the newline and
|
|
#+ the effect is variable=echo "$variable"
|
|
#+ invalid variable assignment
|
|
|
|
variable=\
|
|
23skidoo
|
|
echo "$variable" # 23skidoo
|
|
# This works, since the second line
|
|
#+ is a valid variable assignment.
|
|
|
|
variable=\
|
|
# \^ escape followed by space
|
|
echo "$variable" # space
|
|
|
|
variable=\\
|
|
echo "$variable" # \
|
|
|
|
variable=\\\
|
|
echo "$variable"
|
|
# Will not work - gives an error message:
|
|
# test.sh: \: command not found
|
|
#
|
|
# First escape escapes second one, but the third one is left "naked",
|
|
#+ with same result as first instance, above.
|
|
|
|
variable=\\\\
|
|
echo "$variable" # \\
|
|
# Second and fourth escapes escaped.
|
|
# This is o.k.</programlisting>
|
|
</para>
|
|
|
|
</note>
|
|
|
|
|
|
|
|
<para>Escaping a space can prevent word splitting in a command's argument list.
|
|
<programlisting>file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
|
|
# List of files as argument(s) to a command.
|
|
|
|
# Add two files to the list, and list all.
|
|
ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list
|
|
|
|
echo "-------------------------------------------------------------------------"
|
|
|
|
# What happens if we escape a couple of spaces?
|
|
ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
|
|
# Error: the first three files concatenated into a single argument to 'ls -l'
|
|
# because the two escaped spaces prevent argument (word) splitting.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="escnewline"/></para>
|
|
<para>The <token>escape</token> also provides a means of writing a
|
|
multi-line command. Normally, each separate line constitutes
|
|
a different command, but an <token>escape</token> at the end
|
|
of a line <emphasis>escapes the newline character</emphasis>,
|
|
and the command sequence continues on to the next line.</para>
|
|
<para><programlisting>(cd /source/directory && tar cf - . ) | \
|
|
(cd /dest/directory && tar xpvf -)
|
|
# Repeating Alan Cox's directory tree copy command,
|
|
# but split into two lines for increased legibility.
|
|
|
|
# As an alternative:
|
|
tar cf - -C /source/directory . |
|
|
tar xpvf - -C /dest/directory
|
|
# See note below.
|
|
# (Thanks, Stéphane Chazelas.)</programlisting>
|
|
|
|
<note><para>If a script line ends with a <token>|</token>, a pipe
|
|
character, then a <token>\</token>, an escape, is not strictly
|
|
necessary. It is, however, good programming practice to always
|
|
escape the end of a line of code that continues to the
|
|
following line.</para></note></para>
|
|
|
|
<para><programlisting>echo "foo
|
|
bar"
|
|
#foo
|
|
#bar
|
|
|
|
echo
|
|
|
|
echo 'foo
|
|
bar' # No difference yet.
|
|
#foo
|
|
#bar
|
|
|
|
echo
|
|
|
|
echo foo\
|
|
bar # Newline escaped.
|
|
#foobar
|
|
|
|
echo
|
|
|
|
echo "foo\
|
|
bar" # Same here, as \ still interpreted as escape within weak quotes.
|
|
#foobar
|
|
|
|
echo
|
|
|
|
echo 'foo\
|
|
bar' # Escape character \ taken literally because of strong quoting.
|
|
#foo\
|
|
#bar
|
|
|
|
# Examples suggested by Stéphane Chazelas.</programlisting></para>
|
|
|
|
</sect1> <!-- Escaping -->
|
|
|
|
|
|
</chapter> <!-- Quoting -->
|
|
|
|
|
|
<chapter id="exit-status">
|
|
<title>Exit and Exit Status</title>
|
|
|
|
<epigraph>
|
|
<para>... there are dark corners in the Bourne shell, and people use all
|
|
of them.</para>
|
|
<para>--Chet Ramey</para>
|
|
</epigraph>
|
|
|
|
<para><anchor id="exitcommandref"/>The
|
|
<command>
|
|
<indexterm>
|
|
<primary>exit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>exit</secondary>
|
|
</indexterm>
|
|
exit
|
|
</command>
|
|
command terminates a script, just as in a <command>C</command>
|
|
program. It can also return a value, which is available to the
|
|
script's parent process.</para>
|
|
|
|
|
|
<para><anchor id="exitstatusref"/>Every command returns an
|
|
<firstterm>
|
|
<indexterm>
|
|
<primary>exit status</primary>
|
|
</indexterm>
|
|
exit status
|
|
</firstterm>
|
|
(sometimes referred to as a
|
|
<firstterm>
|
|
<indexterm>
|
|
<primary>return status</primary>
|
|
</indexterm>
|
|
return status
|
|
</firstterm> or <firstterm>exit code</firstterm>).
|
|
<anchor id="exitsuccess"/>
|
|
A successful command returns a <returnvalue>0</returnvalue>, while
|
|
an unsuccessful one returns a <returnvalue>non-zero</returnvalue>
|
|
value that usually can be interpreted as an <firstterm>error
|
|
code</firstterm>. Well-behaved UNIX commands, programs, and
|
|
utilities return a <returnvalue>0</returnvalue> exit code upon
|
|
successful completion, though there are some exceptions.</para>
|
|
|
|
<para><anchor id="functxstr"/></para>
|
|
<para>Likewise, <link linkend="functionref">functions</link>
|
|
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 an integer in the <returnvalue>0</returnvalue> -
|
|
<returnvalue>255</returnvalue> range).</para>
|
|
|
|
<note>
|
|
|
|
<para>When a script ends with an <command>exit</command> that has
|
|
no parameter, the exit status of the script is the exit status
|
|
of the last command executed in the script (previous to the
|
|
<command>exit</command>).</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
COMMAND_1
|
|
|
|
. . .
|
|
|
|
COMMAND_LAST
|
|
|
|
# Will exit with status of last command.
|
|
|
|
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
|
|
|
|
. . .
|
|
|
|
COMMAND_LAST
|
|
|
|
# Will exit with status of last command.
|
|
|
|
exit $?</programlisting></para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
COMMAND1
|
|
|
|
. . .
|
|
|
|
COMMAND_LAST
|
|
|
|
# Will exit with status of last command.</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>
|
|
|
|
<footnote><para>In those instances when there is no <link
|
|
linkend="returnref">return</link>
|
|
terminating the function.</para></footnote>
|
|
</para>
|
|
|
|
<para><anchor id="pipeex"/>Following the execution of a <link
|
|
linkend="piperef">pipe</link>, a <varname>$?</varname>
|
|
gives the exit status of the last command executed.</para>
|
|
|
|
|
|
<para>After a script terminates, a <varname>$?</varname> from the
|
|
command-line gives the exit status of the script, that is, the
|
|
last command executed in the script, which is, by convention,
|
|
<userinput>0</userinput> on success or an integer in the
|
|
range <returnvalue>1 - 255</returnvalue> on error.</para>
|
|
|
|
<example id="ex5">
|
|
<title>exit / exit status</title>
|
|
<programlisting>&ex5;</programlisting>
|
|
</example>
|
|
|
|
<para><link linkend="xstatvarref">$?</link> is especially useful
|
|
for testing the result of a command in a script (see <xref
|
|
linkend="filecomp"/> and <xref linkend="lookup"/>).</para>
|
|
|
|
<note>
|
|
<para>The <link linkend="notref">!</link>, the <firstterm>logical
|
|
not</firstterm> qualifier, reverses the outcome of a test or
|
|
command, and this affects its <link linkend="exitstatusref">exit
|
|
status</link>.
|
|
|
|
<example id="negcond">
|
|
<title>Negating a condition using <token>!</token></title>
|
|
<programlisting>true # The "true" builtin.
|
|
echo "exit status of \"true\" = $?" # 0
|
|
|
|
! true
|
|
echo "exit status of \"! true\" = $?" # 1
|
|
# Note that the "!" needs a space between it and the command.
|
|
# !true leads to a "command not found" error
|
|
#
|
|
# The '!' operator prefixing a command invokes the Bash history mechanism.
|
|
|
|
true
|
|
!true
|
|
# No error this time, but no negation either.
|
|
# It just repeats the previous command (true).
|
|
|
|
|
|
# =========================================================== #
|
|
# Preceding a _pipe_ with ! inverts the exit status returned.
|
|
ls | bogus_command # bash: bogus_command: command not found
|
|
echo $? # 127
|
|
|
|
! ls | bogus_command # bash: bogus_command: command not found
|
|
echo $? # 0
|
|
# Note that the ! does not change the execution of the pipe.
|
|
# Only the exit status changes.
|
|
# =========================================================== #
|
|
|
|
# Thanks, Stéphane Chazelas and Kristopher Newsome.</programlisting>
|
|
</example>
|
|
|
|
</para>
|
|
</note>
|
|
|
|
|
|
<caution><para>Certain exit status codes have <link
|
|
linkend="exitcodesref">reserved meanings</link> and should not
|
|
be user-specified in a script. </para></caution>
|
|
|
|
|
|
</chapter> <!-- Exit and Exit status -->
|
|
|
|
|
|
<chapter id="tests">
|
|
<title>Tests</title>
|
|
|
|
<para><anchor id="ifthen"/></para>
|
|
|
|
<indexterm>
|
|
<primary>if</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
<secondary>if</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>then</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>else</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>else if</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>elif</primary>
|
|
</indexterm>
|
|
|
|
<para>Every reasonably complete programming language can test
|
|
for a condition, then act according to the result of the
|
|
test. Bash has the <link linkend="ttestref">test</link>
|
|
command, various <link linkend="dblbrackets">bracket</link>
|
|
and <link linkend="dblparenstst">parenthesis</link> operators,
|
|
and the <command>if/then</command> construct.</para>
|
|
|
|
<sect1 id="testconstructs">
|
|
<title>Test Constructs</title>
|
|
|
|
<para><anchor id="testconstructs1"/></para>
|
|
|
|
<itemizedlist id="testingref">
|
|
|
|
<listitem>
|
|
<para>An <command>if/then</command> construct tests whether the
|
|
<link linkend="exitstatusref">exit status</link> of a list
|
|
of commands is <returnvalue>0</returnvalue> (since 0 means
|
|
<quote>success</quote> by UNIX convention), and if so, executes
|
|
one or more commands.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>There exists a dedicated command called <command>
|
|
[</command> (<link linkend="leftbracket">left bracket</link>
|
|
special character). It is a synonym for <command>test</command>,
|
|
and a <link linkend="builtinref">builtin</link> for efficiency
|
|
reasons. This command considers its arguments as comparison
|
|
expressions or file tests and returns an exit status corresponding
|
|
to the result of the comparison (0 for true, 1 for false).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>With version 2.02, Bash introduced the <link
|
|
linkend="dblbrackets">[[ ... ]]</link> <firstterm>extended
|
|
test command</firstterm>, which performs comparisons
|
|
in a manner more familiar to programmers from other
|
|
languages. Note that <command>[[</command> is a <link
|
|
linkend="keywordref">keyword</link>, not a command.</para>
|
|
|
|
<para>Bash sees <userinput>[[ $a -lt $b ]]</userinput> as a
|
|
single element, which returns an exit status.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="dblparenstst"/></para>
|
|
<para>The <link linkend="dblparens">(( ... ))</link> and <link
|
|
linkend="letref">let ...</link> constructs return an
|
|
<link linkend="exitstatusref">exit status</link>,
|
|
<emphasis>according to whether the arithmetic expressions they
|
|
evaluate expand to a non-zero value</emphasis>. These
|
|
<link linkend="arithexpref">arithmetic-expansion</link>
|
|
constructs may therefore be used to perform <link
|
|
linkend="icomparison1">arithmetic comparisons</link>.</para>
|
|
|
|
<para>
|
|
<programlisting>(( 0 && 1 )) # Logical AND
|
|
echo $? # 1 ***
|
|
# And so ...
|
|
let "num = (( 0 && 1 ))"
|
|
echo $num # 0
|
|
# But ...
|
|
let "num = (( 0 && 1 ))"
|
|
echo $? # 1 ***
|
|
|
|
|
|
(( 200 || 11 )) # Logical OR
|
|
echo $? # 0 ***
|
|
# ...
|
|
let "num = (( 200 || 11 ))"
|
|
echo $num # 1
|
|
let "num = (( 200 || 11 ))"
|
|
echo $? # 0 ***
|
|
|
|
|
|
(( 200 | 11 )) # Bitwise OR
|
|
echo $? # 0 ***
|
|
# ...
|
|
let "num = (( 200 | 11 ))"
|
|
echo $num # 203
|
|
let "num = (( 200 | 11 ))"
|
|
echo $? # 0 ***
|
|
|
|
# The "let" construct returns the same exit status
|
|
#+ as the double-parentheses arithmetic expansion.</programlisting>
|
|
</para>
|
|
|
|
<caution><para><anchor id="arxs"/>Again, note that the
|
|
<firstterm>exit status</firstterm> of an arithmetic expression
|
|
is <emphasis>not</emphasis> an error value.
|
|
<programlisting>var=-2 && (( var+=2 ))
|
|
echo $? # 1
|
|
|
|
var=-2 && (( var+=2 )) && echo $var
|
|
# Will not echo $var!</programlisting>
|
|
</para></caution>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="ifgrepref"/></para>
|
|
|
|
<para>An <command>if</command> can test any command, not just
|
|
conditions enclosed within brackets.</para>
|
|
|
|
|
|
<para><programlisting>if cmp a b &> /dev/null # Suppress output.
|
|
then echo "Files a and b are identical."
|
|
else echo "Files a and b differ."
|
|
fi
|
|
|
|
# The very useful "if-grep" construct:
|
|
# -----------------------------------
|
|
if grep -q Bash file
|
|
then echo "File contains at least one occurrence of Bash."
|
|
fi
|
|
|
|
word=Linux
|
|
letter_sequence=inu
|
|
if echo "$word" | grep -q "$letter_sequence"
|
|
# The "-q" option to grep suppresses output.
|
|
then
|
|
echo "$letter_sequence found in $word"
|
|
else
|
|
echo "$letter_sequence not found in $word"
|
|
fi
|
|
|
|
|
|
if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED
|
|
then echo "Command succeeded."
|
|
else echo "Command failed."
|
|
fi</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
|
|
<para><emphasis>These last two examples
|
|
courtesy of Stéphane Chazelas.</emphasis></para>
|
|
|
|
</listitem>
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
<example id="ex10">
|
|
<title>What is truth?</title>
|
|
<programlisting>&ex10;</programlisting>
|
|
</example>
|
|
|
|
<formalpara><title>Exercise</title>
|
|
<para>Explain the behavior of <xref linkend="ex10"/>, above.</para>
|
|
</formalpara>
|
|
|
|
<para><anchor id="elseref"/><programlisting>if [ condition-true ]
|
|
then
|
|
command 1
|
|
command 2
|
|
...
|
|
else # Or else ...
|
|
# Adds default code block executing if original condition tests false.
|
|
command 3
|
|
command 4
|
|
...
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
<note>
|
|
<para>When <firstterm>if</firstterm> and <firstterm>then</firstterm>
|
|
are on same line in a condition test, a semicolon must
|
|
terminate the <firstterm>if</firstterm> statement. Both
|
|
<firstterm>if</firstterm> and <firstterm>then</firstterm>
|
|
are <link linkend="keywordref">keywords</link>. Keywords (or
|
|
commands) begin statements, and before a new statement on the
|
|
same line begins, the old one must terminate.</para>
|
|
|
|
<para><programlisting>if [ -x "$filename" ]; then</programlisting></para>
|
|
</note>
|
|
|
|
<variablelist id="elifref">
|
|
<title><anchor id="elifref1"/>Else if and elif</title>
|
|
<varlistentry>
|
|
<term><token>elif</token></term>
|
|
<listitem>
|
|
<para><userinput>elif</userinput> is a contraction
|
|
for <firstterm>else if</firstterm>. The effect is to nest an
|
|
inner <token>if/then</token> construct within an outer
|
|
one.</para>
|
|
|
|
<para><programlisting>if [ condition1 ]
|
|
then
|
|
command1
|
|
command2
|
|
command3
|
|
elif [ condition2 ]
|
|
# Same as else if
|
|
then
|
|
command4
|
|
command5
|
|
else
|
|
default-command
|
|
fi</programlisting>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<para>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
<secondary>test</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>[</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>[</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>]</secondary>
|
|
</indexterm>
|
|
<anchor id="ifref2"/>
|
|
The <userinput>if test condition-true</userinput> construct is the
|
|
exact equivalent of <userinput>if [ condition-true ]</userinput>.
|
|
As it happens, the left bracket, <command>[</command> , is a
|
|
<firstterm>token</firstterm>
|
|
|
|
<footnote><para><anchor id="tokenref"/>A
|
|
<firstterm>token</firstterm> is a symbol or short
|
|
string with a special meaning attached to it (a <link
|
|
linkend="metameaningref">meta-meaning</link>). In Bash,
|
|
certain tokens, such as <command>[</command> and <link
|
|
linkend="dotref">. (dot-command)</link>, may expand to
|
|
<firstterm>keywords</firstterm> and commands.</para></footnote>
|
|
|
|
which invokes the <command>test</command> command. The closing
|
|
right bracket, <command>]</command> , in an if/test should not
|
|
therefore be strictly necessary, however newer versions of Bash
|
|
require it.</para>
|
|
|
|
<para><anchor id="ttestref"/></para>
|
|
<note><para>The <command>test</command> command is a Bash <link
|
|
linkend="builtinref">builtin</link> which tests file
|
|
types and compares strings. Therefore, in a Bash script,
|
|
<command>test</command> does <emphasis>not</emphasis> call
|
|
the external <filename>/usr/bin/test</filename> binary,
|
|
which is part of the <firstterm>sh-utils</firstterm>
|
|
package. Likewise, <command>[</command> does not call
|
|
<filename>/usr/bin/[</filename>, which is linked to
|
|
<filename>/usr/bin/test</filename>.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>type test</userinput>
|
|
<computeroutput>test is a shell builtin</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type '['</userinput>
|
|
<computeroutput>[ is a shell builtin</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type '[['</userinput>
|
|
<computeroutput>[[ is a shell keyword</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type ']]'</userinput>
|
|
<computeroutput>]] is a shell keyword</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type ']'</userinput>
|
|
<computeroutput>bash: type: ]: not found</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="usrbintest"/></para>
|
|
<para>If, for some reason, you wish to use
|
|
<filename>/usr/bin/test</filename> in a Bash script,
|
|
then specify it by full pathname.</para>
|
|
|
|
</note>
|
|
|
|
|
|
<example id="ex11">
|
|
<title>Equivalence of <firstterm>test</firstterm>,
|
|
<filename>/usr/bin/test</filename>, <token>[ ]</token>,
|
|
and <filename>/usr/bin/[</filename></title>
|
|
<programlisting>&ex11;</programlisting>
|
|
</example>
|
|
|
|
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>test</primary>
|
|
<secondary>test</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>[[</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>[[</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>]]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>]]</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<sidebar>
|
|
|
|
<para><anchor id="dblbrackets"/>The <token>[[ ]]</token> construct
|
|
is the more versatile Bash version of <token>[ ]</token>. This
|
|
is the <firstterm>extended test command</firstterm>, adopted from
|
|
<firstterm>ksh88</firstterm>.</para>
|
|
|
|
<para>* * *</para>
|
|
|
|
<para>No filename expansion or word splitting takes place
|
|
between <token>[[</token> and <token>]]</token>, but there is
|
|
parameter expansion and command substitution.
|
|
|
|
<programlisting>file=/etc/passwd
|
|
|
|
if [[ -e $file ]]
|
|
then
|
|
echo "Password file exists."
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>Using the <command>[[ ... ]]</command> test construct,
|
|
rather than <command>[ ... ]</command> can prevent many
|
|
logic errors in scripts. For example, the <token>&&</token>,
|
|
<token>||</token>, <token><</token>, and <token>></token>
|
|
operators work within a <token>[[ ]]</token> test, despite
|
|
giving an error within a <token>[ ]</token> construct.</para>
|
|
|
|
|
|
<para><anchor id="dblbraev"/></para>
|
|
<para><firstterm>Arithmetic evaluation</firstterm> of octal /
|
|
hexadecimal constants takes place automatically within a
|
|
<token>[[ ... ]]</token> construct.
|
|
<programlisting># [[ Octal and hexadecimal evaluation ]]
|
|
# Thank you, Moritz Gronbach, for pointing this out.
|
|
|
|
|
|
decimal=15
|
|
octal=017 # = 15 (decimal)
|
|
hex=0x0f # = 15 (decimal)
|
|
|
|
if [ "$decimal" -eq "$octal" ]
|
|
then
|
|
echo "$decimal equals $octal"
|
|
else
|
|
echo "$decimal is not equal to $octal" # 15 is not equal to 017
|
|
fi # Doesn't evaluate within [ single brackets ]!
|
|
|
|
|
|
if [[ "$decimal" -eq "$octal" ]]
|
|
then
|
|
echo "$decimal equals $octal" # 15 equals 017
|
|
else
|
|
echo "$decimal is not equal to $octal"
|
|
fi # Evaluates within [[ double brackets ]]!
|
|
|
|
if [[ "$decimal" -eq "$hex" ]]
|
|
then
|
|
echo "$decimal equals $hex" # 15 equals 0x0f
|
|
else
|
|
echo "$decimal is not equal to $hex"
|
|
fi # [[ $hexadecimal ]] also evaluates!</programlisting>
|
|
</para>
|
|
|
|
</sidebar>
|
|
|
|
|
|
<note>
|
|
<para>Following an <command>if</command>, neither the
|
|
<command>test</command> command nor the test brackets ( [ ] or [[ ]] )
|
|
are strictly necessary.
|
|
|
|
<programlisting>dir=/home/bozo
|
|
|
|
if cd "$dir" 2>/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><anchor id="dblprx"/>The <link linkend="dblparens">(( ))
|
|
construct</link> expands and evaluates an arithmetic
|
|
expression. If the expression evaluates as zero, it returns
|
|
an <link linkend="exitstatusref">exit status</link> of
|
|
<returnvalue>1</returnvalue>, or <quote>false</quote>. A non-zero
|
|
expression returns an exit status of <returnvalue>0</returnvalue>,
|
|
or <quote>true</quote>. This is in marked contrast to using
|
|
the <command>test</command> and <token>[ ]</token> constructs
|
|
previously discussed.</para>
|
|
|
|
<example id="arithtests">
|
|
<title>Arithmetic Tests using <token>(( ))</token></title>
|
|
<programlisting>&arithtests;</programlisting>
|
|
</example>
|
|
|
|
</sect1> <!-- Test Constructs -->
|
|
|
|
|
|
<sect1 id="fto">
|
|
<title>File test operators</title>
|
|
|
|
<variablelist>
|
|
<title><anchor id="rtif"/>Returns true if...</title>
|
|
<varlistentry>
|
|
<term><token>-e</token></term>
|
|
<listitem><para>file exists</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-a</token></term>
|
|
<listitem><para>file exists</para>
|
|
<para>This is identical in effect to <token>-e</token>.
|
|
It has been <quote>deprecated,</quote>
|
|
|
|
<footnote><para>
|
|
Per the 1913 edition of <emphasis>Webster's
|
|
Dictionary</emphasis>:
|
|
<programlisting>Deprecate
|
|
...
|
|
|
|
To pray against, as an evil;
|
|
to seek to avert by prayer;
|
|
to desire the removal of;
|
|
to seek deliverance from;
|
|
to express deep regret for;
|
|
to disapprove of strongly.</programlisting>
|
|
</para></footnote>
|
|
|
|
and its use is
|
|
discouraged.</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><anchor id="regularfile"/><token>-f</token></term>
|
|
<listitem><para>file is a <replaceable>regular</replaceable>
|
|
file (not a directory or <link linkend="devfileref">device
|
|
file</link>)</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-s</token></term>
|
|
<listitem><para>file is not zero size</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-d</token></term>
|
|
<listitem><para>file is a directory</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-b</token></term>
|
|
<listitem>
|
|
<para>file is a <link linkend="blockdevref">block
|
|
device</link></para>
|
|
<para><anchor id="blockdevtest"/></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-c</token></term>
|
|
<listitem><para><anchor id="chardevtest"/>file is a <link
|
|
linkend="chardevref">character device</link></para>
|
|
<para><programlisting>device0="/dev/sda2" # / (root directory)
|
|
if [ -b "$device0" ]
|
|
then
|
|
echo "$device0 is a block device."
|
|
fi
|
|
|
|
# /dev/sda2 is a block device.
|
|
|
|
|
|
|
|
device1="/dev/ttyS1" # PCMCIA modem card.
|
|
if [ -c "$device1" ]
|
|
then
|
|
echo "$device1 is a character device."
|
|
fi
|
|
|
|
# /dev/ttyS1 is a character device.</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-p</token></term>
|
|
<listitem>
|
|
<para>file is a <link linkend="piperef">pipe</link></para>
|
|
<para><programlisting>function show_input_type()
|
|
{
|
|
[ -p /dev/fd/0 ] && echo PIPE || echo STDIN
|
|
}
|
|
|
|
show_input_type "Input" # STDIN
|
|
echo "Input" | show_input_type # PIPE
|
|
|
|
# This example courtesy of Carl Anderson.</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-h</token></term>
|
|
<listitem><para>file is a <link linkend="symlinkref">symbolic
|
|
link</link></para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-L</token></term>
|
|
<listitem><para>file is a symbolic link</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-S</token></term>
|
|
<listitem><para>file is a <link linkend="socketref">socket</link></para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-t</token></term>
|
|
<listitem>
|
|
|
|
<para><anchor id="termtest"/>file (<link
|
|
linkend="fdref">descriptor</link>) is
|
|
associated with a terminal device</para>
|
|
|
|
<para>This test option <link linkend="ii2test"> may be used
|
|
to check</link> whether the <filename>stdin</filename>
|
|
<userinput>[ -t 0 ]</userinput> or
|
|
<filename>stdout</filename> <userinput>[ -t 1 ]</userinput>
|
|
in a given script is a terminal.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-r</token></term>
|
|
<listitem><para>file has read permission (<emphasis>for the
|
|
user running the test</emphasis>)</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-w</token></term>
|
|
<listitem><para>file has write permission (for the user running
|
|
the test)</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-x</token></term>
|
|
<listitem><para>file has execute permission (for the user running
|
|
the test)</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-g</token></term>
|
|
<listitem>
|
|
<para>set-group-id (sgid) flag set on file or directory</para>
|
|
<para>If a directory has the <replaceable>sgid</replaceable>
|
|
flag set, then a file created within that directory belongs
|
|
to the group that owns the directory, not necessarily to
|
|
the group of the user who created the file. This may be
|
|
useful for a directory shared by a workgroup.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-u</token></term>
|
|
<listitem>
|
|
<para><anchor id="suidref"/></para>
|
|
<para>set-user-id (suid) flag set on file</para>
|
|
<para>A binary owned by <firstterm>root</firstterm>
|
|
with <replaceable>set-user-id</replaceable> flag set
|
|
runs with <firstterm>root</firstterm> privileges, even
|
|
when an ordinary user invokes it.
|
|
|
|
<footnote><para>Be aware that <firstterm>suid</firstterm>
|
|
binaries may open security holes. The
|
|
<firstterm>suid</firstterm> flag has no effect on
|
|
shell scripts.</para></footnote>
|
|
|
|
This is useful for executables (such as
|
|
<command>pppd</command> and <command>cdrecord</command>)
|
|
that need to access system hardware. Lacking the
|
|
<firstterm>suid</firstterm> flag, these binaries could not
|
|
be invoked by a <firstterm>non-root</firstterm> user.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<computeroutput>-rwsr-xr-t 1 root 178236 Oct 2 2000 /usr/sbin/pppd</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>A file with the <replaceable>suid</replaceable>
|
|
flag set shows an <firstterm>s</firstterm> in its
|
|
permissions.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-k</token></term>
|
|
<listitem>
|
|
|
|
<para><replaceable>sticky bit</replaceable> set</para>
|
|
|
|
<para>Commonly known as the <firstterm>sticky bit,</firstterm>
|
|
the <firstterm>save-text-mode</firstterm> flag is a special
|
|
type of file permission. If a file has this flag set,
|
|
that file will be kept in cache memory, for quicker access.
|
|
<footnote><para>On Linux systems, the sticky
|
|
bit is no longer used for files, only on
|
|
directories.</para></footnote>
|
|
If set on a directory, it restricts write permission.
|
|
Setting the sticky bit adds a <firstterm>t</firstterm>
|
|
to the permissions on the file or directory listing.
|
|
This restricts altering or deleting specific files
|
|
in that directory to the owner of those files.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<computeroutput>drwxrwxrwt 7 root 1024 May 19 21:26 tmp/</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>If a user does not own a directory that has the sticky
|
|
bit set, but has write permission in that directory, she
|
|
can only delete those files that she owns in it. This
|
|
keeps users from inadvertently overwriting or deleting
|
|
each other's files in a publicly accessible directory,
|
|
such as <filename class="directory">/tmp</filename>.
|
|
(The <firstterm>owner</firstterm> of the directory or
|
|
<firstterm>root</firstterm> can, of course, delete or
|
|
rename files there.)</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-O</token></term>
|
|
<listitem><para>you are owner of file</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-G</token></term>
|
|
<listitem><para>group-id of file same as yours</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>-N</token></term>
|
|
<listitem><para>file modified since it was last read</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>f1 -nt f2</token></term>
|
|
<listitem><para>file <replaceable>f1</replaceable> is newer than
|
|
<replaceable>f2</replaceable></para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>f1 -ot f2</token></term>
|
|
<listitem><para>file <replaceable>f1</replaceable> is older than
|
|
<replaceable>f2</replaceable></para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>f1 -ef f2</token></term>
|
|
<listitem><para>files <replaceable>f1</replaceable> and
|
|
<replaceable>f2</replaceable> are hard links to the same
|
|
file</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><token>!</token></term>
|
|
<listitem><para><quote>not</quote> -- reverses the sense of the
|
|
tests above (returns true if condition absent).</para></listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<example id="brokenlink">
|
|
<title>Testing for broken links</title>
|
|
<programlisting>&brokenlink;</programlisting>
|
|
</example>
|
|
|
|
<para><xref linkend="cookies"/>, <xref linkend="bingrep"/>,
|
|
<xref linkend="fileinfo"/>, <xref linkend="ramdisk"/>, and <xref
|
|
linkend="mailformat"/> also illustrate uses of the file test
|
|
operators.</para>
|
|
|
|
|
|
</sect1> <!-- File test operators -->
|
|
|
|
<sect1 id="comparison-ops">
|
|
<title>Other Comparison Operators</title>
|
|
|
|
<para>A <firstterm>binary</firstterm> comparison operator
|
|
compares two variables or quantities. <emphasis>Note
|
|
that integer and string comparison use a different set of
|
|
operators.</emphasis></para>
|
|
|
|
<variablelist id="icomparison">
|
|
<title><anchor id="icomparison1"/>integer comparison</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="equalref"/><token>-eq</token></term>
|
|
<listitem>
|
|
<para>is equal to</para>
|
|
<para><userinput>if [ "$a" -eq "$b" ]</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="nequalref"/><token>-ne</token></term>
|
|
<listitem>
|
|
<para>is not equal to</para>
|
|
<para><userinput>if [ "$a" -ne "$b" ]</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="gt0ref"/><token>-gt</token></term>
|
|
<listitem>
|
|
<para>is greater than</para>
|
|
<para><userinput>if [ "$a" -gt "$b" ]</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ge0ref"/><token>-ge</token></term>
|
|
<listitem>
|
|
<para>is greater than or equal to</para>
|
|
<para><userinput>if [ "$a" -ge "$b" ]</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lt0ref"/><token>-lt</token></term>
|
|
<listitem>
|
|
<para>is less than</para>
|
|
<para><userinput>if [ "$a" -lt "$b" ]</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="le0ref"/><token>-le</token></term>
|
|
<listitem>
|
|
<para>is less than or equal to</para>
|
|
<para><userinput>if [ "$a" -le "$b" ]</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="intlt"/><token><</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><anchor id="lteq"/><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><anchor id="intgt"/><token>></token></term>
|
|
<listitem>
|
|
<para>is greater than (within double parentheses)</para>
|
|
<para><userinput>(("$a" > "$b"))</userinput></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="gteq"/><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>
|
|
|
|
<caution><para>Note the <link
|
|
linkend="whitespaceref">whitespace</link>
|
|
framing the <command>=</command>.</para>
|
|
<para><userinput>if [ "$a"="$b" ]</userinput> is
|
|
<emphasis>not</emphasis> equivalent to the
|
|
above.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="scomparison2"/><token>==</token></term>
|
|
<listitem>
|
|
<para>is equal to</para>
|
|
<para><userinput>if [ "$a" == "$b" ]</userinput></para>
|
|
<para>This is a synonym for <token>=</token>.</para>
|
|
|
|
<note><para>
|
|
The <token>==</token> comparison operator behaves differently
|
|
within a <link linkend="dblbrackets">double-brackets</link>
|
|
test than within single brackets.
|
|
<programlisting>[[ $a == z* ]] # True if $a starts with an "z" (pattern matching).
|
|
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
|
|
|
|
[ $a == z* ] # File globbing and word splitting take place.
|
|
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).
|
|
|
|
# Thanks, Stéphane Chazelas</programlisting>
|
|
</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><anchor id="notequal"/><token>!=</token></term>
|
|
<listitem>
|
|
<para>is not equal to</para>
|
|
<para><userinput>if [ "$a" != "$b" ]</userinput></para>
|
|
<para>This operator uses pattern matching within a <link
|
|
linkend="dblbrackets">[[ ... ]]</link> construct.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ltref"/><token><</token></term>
|
|
<listitem>
|
|
<para>is less than, in <link
|
|
linkend="asciidef">ASCII</link> 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
|
|
<link linkend="escp">escaped</link> 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><anchor id="stringnull"/><token>-z</token></term>
|
|
<listitem>
|
|
<para>string is <firstterm>null</firstterm>,
|
|
that is, has zero length</para>
|
|
<para><programlisting> String='' # Zero-length ("null") string variable.
|
|
|
|
if [ -z "$String" ]
|
|
then
|
|
echo "\$String is null."
|
|
else
|
|
echo "\$String is NOT null."
|
|
fi # $String is null.</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="stringnotnull"/><token>-n</token></term>
|
|
<listitem>
|
|
<para>string is not <firstterm>null.</firstterm></para>
|
|
|
|
<caution><para>The <userinput>-n</userinput> test
|
|
requires that the string be quoted within the
|
|
test brackets. Using an unquoted string with
|
|
<firstterm>! -z</firstterm>, or even just the
|
|
unquoted string alone within test brackets (see <xref
|
|
linkend="strtest"/>) normally works, however, this is
|
|
an unsafe practice. <emphasis>Always</emphasis> quote
|
|
a tested string.
|
|
<footnote><para>As S.C. points out, in a compound test,
|
|
even quoting the string variable might not
|
|
suffice. <userinput>[ -n "$string" -o "$a" = "$b" ]</userinput>
|
|
may cause an error with some versions of Bash if
|
|
<varname>$string</varname> is empty. The safe way
|
|
is to append an extra character to possibly empty variables,
|
|
<userinput>[ "x$string" != x -o "x$a" = "x$b" ]</userinput>
|
|
(the <quote>x's</quote> cancel out).</para></footnote>
|
|
</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
</variablelist>
|
|
|
|
<example id="ex13">
|
|
<title>Arithmetic and string comparisons</title>
|
|
<programlisting>&ex13;</programlisting>
|
|
</example>
|
|
|
|
<example id="strtest">
|
|
<title>Testing whether a string is <firstterm>null</firstterm></title>
|
|
<programlisting>&strtest;</programlisting>
|
|
</example>
|
|
|
|
<example id="ex14">
|
|
<title><firstterm>zmore</firstterm></title>
|
|
<programlisting>&ex14;</programlisting>
|
|
</example>
|
|
|
|
<variablelist id="ccomparison">
|
|
<title><anchor id="ccomparison1"/>compound comparison</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="compoundand"/><token>-a</token></term>
|
|
<listitem>
|
|
<para>logical and</para>
|
|
<para><replaceable>exp1 -a exp2</replaceable> returns true if
|
|
<emphasis>both</emphasis> exp1 and exp2 are true.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="compoundor"/><token>-o</token></term>
|
|
<listitem>
|
|
<para>logical or </para>
|
|
<para><replaceable>exp1 -o exp2</replaceable> returns
|
|
true if either exp1 <emphasis>or</emphasis> exp2 is
|
|
true.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<para>
|
|
These are similar to the Bash comparison operators
|
|
<command>&&</command> and <command>||</command>, used
|
|
within <link linkend="dblbrackets">double brackets</link>.
|
|
<programlisting>[[ condition1 && condition2 ]]</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
The <command>-o</command> and <command>-a</command> operators
|
|
work with the <link linkend="ttestref">test</link> command or
|
|
occur within single test brackets.
|
|
<programlisting>if [ "$expr1" -a "$expr2" ]
|
|
then
|
|
echo "Both expr1 and expr2 are true."
|
|
else
|
|
echo "Either expr1 or expr2 is false."
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
<caution>
|
|
<para>But, as <emphasis>rihad</emphasis> points out:
|
|
<programlisting>[ 1 -eq 1 ] && [ -n "`echo true 1>&2`" ] # true
|
|
[ 1 -eq 2 ] && [ -n "`echo true 1>&2`" ] # (no output)
|
|
# ^^^^^^^ False condition. So far, everything as expected.
|
|
|
|
# However ...
|
|
[ 1 -eq 2 -a -n "`echo true 1>&2`" ] # true
|
|
# ^^^^^^^ False condition. So, why "true" output?
|
|
|
|
# Is it because both condition clauses within brackets evaluate?
|
|
[[ 1 -eq 2 && -n "`echo true 1>&2`" ]] # (no output)
|
|
# No, that's not it.
|
|
|
|
# Apparently && and || "short-circuit" while -a and -o do not.</programlisting>
|
|
</para>
|
|
</caution>
|
|
|
|
<para>Refer to <xref linkend="andor"/>, <xref linkend="twodim"/>,
|
|
and <xref linkend="whx"/> to see compound comparison operators
|
|
in action.</para>
|
|
|
|
</sect1> <!-- Comparison operators (binary) -->
|
|
|
|
<sect1 id="nestedifthen">
|
|
<title>Nested <replaceable>if/then</replaceable> Condition Tests</title>
|
|
|
|
<para>Condition tests using the <replaceable>if/then</replaceable>
|
|
construct may be nested. The net result is equivalent to using the
|
|
<link linkend="logops1"><firstterm>&&</firstterm></link> compound
|
|
comparison operator.</para>
|
|
|
|
<para><programlisting>a=3
|
|
|
|
if [ "$a" -gt 0 ]
|
|
then
|
|
if [ "$a" -lt 5 ]
|
|
then
|
|
echo "The value of \"a\" lies somewhere between 0 and 5."
|
|
fi
|
|
fi
|
|
|
|
# Same result as:
|
|
|
|
if [ "$a" -gt 0 ] && [ "$a" -lt 5 ]
|
|
then
|
|
echo "The value of \"a\" lies somewhere between 0 and 5."
|
|
fi</programlisting></para>
|
|
|
|
<para><xref linkend="cards"/> and <xref linkend="backlight"/>
|
|
demonstrate 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 <firstterm>if/then</firstterm> tests. The following
|
|
is excerpted from an <quote>ancient</quote> version of
|
|
<filename>xinitrc</filename> (<firstterm>Red Hat 7.1</firstterm>,
|
|
or thereabouts).</para>
|
|
|
|
<para><programlisting>if [ -f $HOME/.Xclients ]; then
|
|
exec $HOME/.Xclients
|
|
elif [ -f /etc/X11/xinit/Xclients ]; then
|
|
exec /etc/X11/xinit/Xclients
|
|
else
|
|
# failsafe settings. Although we should never get here
|
|
# (we provide fallbacks in Xclients as well) it can't hurt.
|
|
xclock -geometry 100x100-5+5 &
|
|
xterm -geometry 80x50-50+150 &
|
|
if [ -f /usr/bin/netscape -a -f /usr/share/doc/HTML/index.html ]; then
|
|
netscape /usr/share/doc/HTML/index.html &
|
|
fi
|
|
fi</programlisting></para>
|
|
|
|
<para>Explain the <firstterm>test</firstterm> constructs in the
|
|
above snippet, then examine an updated version of the
|
|
file, <filename>/etc/X11/xinit/xinitrc</filename>, and
|
|
analyze the <firstterm>if/then</firstterm> test constructs
|
|
there. You may need to refer ahead to the discussions of <link
|
|
linkend="grepref">grep</link>, <link linkend="sedref">sed</link>,
|
|
and <link linkend="regexref">regular expressions</link>.</para>
|
|
|
|
|
|
</sect1> <!-- Testing Your Knowledge of Tests -->
|
|
|
|
</chapter> <!-- Tests -->
|
|
|
|
|
|
|
|
<chapter id="operations">
|
|
<title>Operations and Related Topics</title>
|
|
|
|
|
|
<sect1 id="ops">
|
|
<title>Operators</title>
|
|
|
|
<variablelist id="asnop">
|
|
<title><anchor id="asnop1"/>assignment</title>
|
|
|
|
<varlistentry>
|
|
<term><replaceable>variable assignment</replaceable></term>
|
|
<listitem><para>Initializing or changing the value of a variable</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>=</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>=</secondary>
|
|
</indexterm>
|
|
<para>All-purpose assignment operator, which works for both
|
|
arithmetic and string assignments.</para>
|
|
|
|
<para>
|
|
<programlisting>var=27
|
|
category=minerals # No spaces allowed after the "=".</programlisting>
|
|
</para>
|
|
|
|
<caution>
|
|
<para>Do not confuse the <quote>=</quote> assignment
|
|
operator with the <link linkend="equalsignref">= test
|
|
operator</link>.</para>
|
|
|
|
<para>
|
|
<programlisting># = as a test operator
|
|
|
|
if [ "$string1" = "$string2" ]
|
|
then
|
|
command
|
|
fi
|
|
|
|
# if [ "X$string1" = "X$string2" ] is safer,
|
|
#+ to prevent an error message should one of the variables be empty.
|
|
# (The prepended "X" characters cancel out.)</programlisting>
|
|
</para>
|
|
</caution>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<indexterm>
|
|
<primary>expr</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>let</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>let</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<variablelist id="arops">
|
|
<title><anchor id="arops1"/>arithmetic operators</title>
|
|
|
|
<varlistentry>
|
|
<term><token>+</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>+</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>+</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>addition</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>plus</primary>
|
|
</indexterm>
|
|
<para>plus</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>-</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>-</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>subtraction</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>minus</primary>
|
|
</indexterm>
|
|
<para>minus</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>*</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>*</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>*</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>multiplication</primary>
|
|
</indexterm>
|
|
<para>multiplication</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>/</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>/</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>/</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>division</primary>
|
|
</indexterm>
|
|
<para>division</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="exponentiationref"/><token>**</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>**</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>**</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>exponentiation</primary>
|
|
</indexterm>
|
|
|
|
<para>exponentiation</para>
|
|
|
|
<para>
|
|
<programlisting># Bash, version 2.02, introduced the "**" exponentiation operator.
|
|
|
|
let "z=5**3" # 5 * 5 * 5
|
|
echo "z = $z" # z = 125</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="moduloref"/><token>%</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>%</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>%</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>modulo</primary>
|
|
</indexterm>
|
|
|
|
<para>modulo, or mod (returns the
|
|
<firstterm>remainder</firstterm> of an integer division
|
|
operation)</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>expr 5 % 3</userinput>
|
|
<computeroutput>2</computeroutput>
|
|
</screen>
|
|
<emphasis>5/3 = 1, with remainder 2</emphasis>
|
|
</para>
|
|
|
|
<para>This operator finds use in, among other things,
|
|
generating numbers within a specific range (see <xref
|
|
linkend="ex21"/> and <xref linkend="randomtest"/>) and
|
|
formatting program output (see <xref linkend="qfunction"/> and
|
|
<xref linkend="collatz"/>). It can even be used to generate
|
|
prime numbers, (see <xref linkend="primes"/>). Modulo turns
|
|
up surprisingly often in numerical recipes.</para>
|
|
|
|
<example id="gcd">
|
|
<title>Greatest common divisor</title>
|
|
<programlisting>&gcd;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="arithopscomb"/><token>+=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>+=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>+=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>plus-equal</primary>
|
|
</indexterm>
|
|
<para><firstterm>plus-equal</firstterm> (increment variable
|
|
by a constant)
|
|
|
|
<footnote><para>In a different context, <command>+=</command> can
|
|
serve as a <firstterm>string concatenation</firstterm>
|
|
operator. This can be useful for <link
|
|
linkend="pathappend">modifying <firstterm>environmental
|
|
variables</firstterm></link>.</para></footnote>
|
|
|
|
</para>
|
|
|
|
<para><userinput>let "var += 5"</userinput> results in
|
|
<parameter>var</parameter> being incremented by
|
|
<literal>5</literal>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>-=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>-=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>minus-equal</primary>
|
|
</indexterm>
|
|
<para><firstterm>minus-equal</firstterm> (decrement
|
|
variable by a constant)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>*=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>*=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>*=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>times-equal</primary>
|
|
</indexterm>
|
|
<para><firstterm>times-equal</firstterm> (multiply
|
|
variable by a constant)</para>
|
|
<para><userinput>let "var *= 4"</userinput> results in <parameter>var</parameter>
|
|
being multiplied by <literal>4</literal>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>/=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>/=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>/=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>slash-equal</primary>
|
|
</indexterm>
|
|
<para><firstterm>slash-equal</firstterm> (divide
|
|
variable by a constant)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>%=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>%=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>%=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>mod-equal</primary>
|
|
</indexterm>
|
|
<para><firstterm>mod-equal</firstterm>
|
|
(<firstterm>remainder</firstterm>
|
|
of dividing variable by a constant)</para>
|
|
|
|
<para><emphasis>Arithmetic operators often occur in an
|
|
<link linkend="exprref">expr</link> or <link
|
|
linkend="letref">let</link> expression.</emphasis></para>
|
|
|
|
<example id="arithops">
|
|
<title>Using Arithmetic Operations</title>
|
|
<programlisting>&arithops;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<para><anchor id="intvarref"/></para>
|
|
<note>
|
|
<para>Integer variables in older versions of Bash were signed
|
|
<firstterm>long</firstterm> (32-bit) integers, in the range of
|
|
-2147483648 to 2147483647. An operation that took a variable
|
|
outside these limits gave an erroneous result.</para>
|
|
|
|
<para>
|
|
<programlisting>echo $BASH_VERSION # 1.14
|
|
|
|
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,
|
|
# + and the leftmost bit, the sign bit,
|
|
# + has been set, making the result negative.</programlisting>
|
|
</para>
|
|
|
|
<para>As of version >= 2.05b, Bash supports 64-bit integers.</para>
|
|
</note>
|
|
|
|
<caution>
|
|
|
|
<para><anchor id="nofloatingpoint"/></para>
|
|
<para>Bash does not understand floating point arithmetic. It
|
|
treats numbers containing a decimal point as strings.</para>
|
|
|
|
<para>
|
|
<programlisting>a=1.5
|
|
|
|
let "b = $a + 1.3" # Error.
|
|
# t2.sh: let: b = 1.5 + 1.3: syntax error in expression
|
|
# (error token is ".5 + 1.3")
|
|
|
|
echo "b = $b" # b=1</programlisting>
|
|
</para>
|
|
|
|
<para>Use <link linkend="bcref">bc</link> in scripts that need floating
|
|
point calculations or math library functions.</para></caution>
|
|
|
|
|
|
|
|
<formalpara><title>bitwise operators</title>
|
|
<para>The bitwise operators seldom make an appearance in shell scripts.
|
|
Their chief use seems to be manipulating and testing values read
|
|
from ports or <link linkend="socketref">sockets</link>. <quote>Bit
|
|
flipping</quote> is more relevant to compiled languages, such
|
|
as C and C++, which provide direct access to system
|
|
hardware. However, see <emphasis>vladz's</emphasis>
|
|
ingenious use of bitwise operators in his
|
|
<firstterm>base64.sh</firstterm> (<xref linkend="base64"/>)
|
|
script. </para></formalpara>
|
|
|
|
<variablelist id="bitwsops">
|
|
<title><anchor id="bitwsops1"/>bitwise operators</title>
|
|
|
|
<varlistentry>
|
|
<term><token><<</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary><<</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary><<</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>left shift</primary>
|
|
</indexterm>
|
|
<para>bitwise left shift (multiplies by <literal>2</literal>
|
|
for each shift position)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token><<=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary><<=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary><<=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>left-shift-equal</primary>
|
|
</indexterm>
|
|
|
|
<para><firstterm>left-shift-equal</firstterm></para>
|
|
<para><userinput>let "var <<= 2"</userinput> results in <parameter>var</parameter>
|
|
left-shifted <literal>2</literal> bits (multiplied by <literal>4</literal>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>>></token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>>></primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>>></secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>right shift</primary>
|
|
</indexterm>
|
|
<para>bitwise right shift (divides by <literal>2</literal>
|
|
for each shift position)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>>>=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>>>=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>>>=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>right-shift-equal</primary>
|
|
</indexterm>
|
|
<para><firstterm>right-shift-equal</firstterm>
|
|
(inverse of <token><<=</token>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>&</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>&</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>&</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>AND</primary>
|
|
<secondary>bitwise</secondary>
|
|
</indexterm>
|
|
<para>bitwise AND</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>&=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>&=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>&=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>and-equal</primary>
|
|
</indexterm>
|
|
<para>bitwise <firstterm>AND-equal</firstterm></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>|</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>|</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>|</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>OR</primary>
|
|
<secondary>bitwise</secondary>
|
|
</indexterm>
|
|
<para>bitwise OR</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>|=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>|=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>|=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>OR-equal</primary>
|
|
</indexterm>
|
|
<para>bitwise <firstterm>OR-equal</firstterm></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>~</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>~</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>~</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>negate</primary>
|
|
</indexterm>
|
|
<para>bitwise NOT</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>^</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>^</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>^</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>XOR</primary>
|
|
</indexterm>
|
|
<para>bitwise XOR</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>^=</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>^=</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>^=</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>XOR-equal</primary>
|
|
</indexterm>
|
|
<para>bitwise <firstterm>XOR-equal</firstterm></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="logops">
|
|
<title><anchor id="logops1"/>logical (boolean) operators</title>
|
|
|
|
<varlistentry>
|
|
<term><token>!</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>!</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operator</primary>
|
|
<secondary>!</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>NOT</primary>
|
|
</indexterm>
|
|
<para>NOT</para>
|
|
<para><programlisting>if [ ! -f $FILENAME ]
|
|
then
|
|
...</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>&&</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>&&</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operator</primary>
|
|
<secondary>&&</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>AND</primary>
|
|
<secondary>logical</secondary>
|
|
</indexterm>
|
|
<para>AND</para>
|
|
<para><programlisting>if [ $condition1 ] && [ $condition2 ]
|
|
# Same as: if [ $condition1 -a $condition2 ]
|
|
# Returns true if both condition1 and condition2 hold true...
|
|
|
|
if [[ $condition1 && $condition2 ]] # Also works.
|
|
# Note that && operator not permitted <emphasis>inside brackets</emphasis>
|
|
#+ of [ ... ] construct.</programlisting></para>
|
|
|
|
<note><para><token>&&</token> may also be used, depending on context,
|
|
in an <link linkend="listconsref">and list</link>
|
|
to concatenate commands.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="orref"/><token>||</token></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>||</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operator</primary>
|
|
<secondary>||</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>OR</primary>
|
|
<secondary>logical</secondary>
|
|
</indexterm>
|
|
<para>OR</para>
|
|
<para><programlisting>if [ $condition1 ] || [ $condition2 ]
|
|
# Same as: if [ $condition1 -o $condition2 ]
|
|
# Returns true if either condition1 or condition2 holds true...
|
|
|
|
if [[ $condition1 || $condition2 ]] # Also works.
|
|
# Note that || operator not permitted <emphasis>inside brackets</emphasis>
|
|
#+ of a [ ... ] 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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>,</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>operation</primary>
|
|
<secondary>,</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>linking</primary>
|
|
</indexterm>
|
|
|
|
<para>Comma operator</para>
|
|
<para>The <command>comma operator</command> chains together
|
|
two or more arithmetic operations. All the operations are
|
|
evaluated (with possible <firstterm>side
|
|
effects</firstterm>.
|
|
<footnote><para><firstterm>Side effects</firstterm>
|
|
are, of course, unintended -- and usually undesirable --
|
|
consequences.</para></footnote>
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting>let "t1 = ((5 + 3, 7 - 1, 15 - 4))"
|
|
echo "t1 = $t1" ^^^^^^ # t1 = 11
|
|
# Here t1 is set to the result of the last operation. Why?
|
|
|
|
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 -->
|
|
|
|
<sect1 id="dblparens">
|
|
<title>The Double-Parentheses Construct</title>
|
|
|
|
<para><anchor id="dblparensref"/></para>
|
|
|
|
<para>Similar to the <link linkend="letref">let</link> command,
|
|
the <command>(( ... ))</command> construct permits
|
|
arithmetic expansion and evaluation. In its simplest
|
|
form, <userinput>a=$(( 5 + 3 ))</userinput> would set
|
|
<userinput>a</userinput> to <userinput>5 + 3</userinput>, or
|
|
<userinput>8</userinput>. However, this double-parentheses
|
|
construct is also a mechanism for allowing C-style
|
|
manipulation of variables in Bash, for example,
|
|
<varname>(( var++ ))</varname>.</para>
|
|
|
|
<para><anchor id="plusplusref"/></para>
|
|
|
|
<example id="cvars">
|
|
<title>C-style manipulation of variables</title>
|
|
<programlisting>&cvars;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="forloopc"/> and <xref
|
|
linkend="numbers"/>.</para>
|
|
|
|
</sect1> <!-- The Double-Parentheses Construct -->
|
|
|
|
<sect1 id="opprecedence">
|
|
<title>Operator Precedence</title>
|
|
|
|
<para><anchor id="opprecedence1"/></para>
|
|
|
|
<para>
|
|
In a script, operations execute in order of
|
|
<firstterm>precedence</firstterm>: the higher precedence operations
|
|
execute <emphasis>before</emphasis> the lower precedence ones.
|
|
<footnote><para><firstterm>Precedence</firstterm>, in this context,
|
|
has approximately the same meaning as
|
|
<firstterm>priority</firstterm></para></footnote>
|
|
</para>
|
|
|
|
&opprectable;
|
|
|
|
<para>In practice, all you really need to remember is the
|
|
following:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>The <quote>My Dear Aunt Sally</quote> mantra (<emphasis>multiply,
|
|
divide, add, subtract</emphasis>) for the familiar <link
|
|
linkend="arops1">arithmetic operations</link>.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>The <firstterm>compound</firstterm> logical operators,
|
|
<command>&&</command>, <command>||</command>, <command>-a</command>,
|
|
and <command>-o</command> have low precedence.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>The order of evaluation of equal-precedence operators is
|
|
usually <firstterm>left-to-right</firstterm>.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Now, let's utilize our knowledge of operator precedence to
|
|
analyze a couple of lines from the
|
|
<filename>/etc/init.d/functions file</filename>, as found in
|
|
the <firstterm>Fedora Core</firstterm> Linux distro.</para>
|
|
|
|
<para><programlisting>while [ -n "$remaining" -a "$retry" -gt 0 ]; do
|
|
|
|
# This looks rather daunting at first glance.
|
|
|
|
|
|
# Separate the conditions:
|
|
while [ -n "$remaining" -a "$retry" -gt 0 ]; do
|
|
# --condition 1-- ^^ --condition 2-
|
|
|
|
# If variable "$remaining" is not zero length
|
|
#+ AND (-a)
|
|
#+ variable "$retry" is greater-than zero
|
|
#+ then
|
|
#+ the [ expresion-within-condition-brackets ] returns success (0)
|
|
#+ and the while-loop executes an iteration.
|
|
# ==============================================================
|
|
# Evaluate "condition 1" and "condition 2" ***before***
|
|
#+ ANDing them. Why? Because the AND (-a) has a lower precedence
|
|
#+ than the -n and -gt operators,
|
|
#+ and therefore gets evaluated *last*.
|
|
|
|
#################################################################
|
|
|
|
if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
|
|
|
|
|
|
# Again, separate the conditions:
|
|
if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
|
|
# --condition 1--------- ^^ --condition 2-----
|
|
|
|
# If file "/etc/sysconfig/i18n" exists
|
|
#+ AND (-a)
|
|
#+ variable $NOLOCALE is zero length
|
|
#+ then
|
|
#+ the [ test-expresion-within-condition-brackets ] returns success (0)
|
|
#+ and the commands following execute.
|
|
#
|
|
# As before, the AND (-a) gets evaluated *last*
|
|
#+ because it has the lowest precedence of the operators within
|
|
#+ the test brackets.
|
|
# ==============================================================
|
|
# Note:
|
|
# ${NOLOCALE:-} is a parameter expansion that seems redundant.
|
|
# But, if $NOLOCALE has not been declared, it gets set to *null*,
|
|
#+ in effect declaring it.
|
|
# This makes a difference in some contexts.</programlisting></para>
|
|
|
|
<tip>
|
|
<para>To avoid confusion or error in a complex sequence of test
|
|
operators, break up the sequence into bracketed sections.
|
|
<programlisting>if [ "$v1" -gt "$v2" -o "$v1" -lt "$v2" -a -e "$filename" ]
|
|
# Unclear what's going on here...
|
|
|
|
if [[ "$v1" -gt "$v2" ]] || [[ "$v1" -lt "$v2" ]] && [[ -e "$filename" ]]
|
|
# Much better -- the condition tests are grouped in logical sections.</programlisting>
|
|
</para>
|
|
</tip>
|
|
|
|
</sect1> <!-- Operator Precedence -->
|
|
|
|
</chapter> <!-- Operations -->
|
|
|
|
</part> <!-- Part 2 (Basics) -->
|
|
|
|
|
|
|
|
<part label="Part 3" id="part3">
|
|
<title>Beyond the Basics</title>
|
|
|
|
|
|
<chapter id="variables2">
|
|
<title>Another Look at Variables</title>
|
|
|
|
<para>Used properly, variables can add power and flexibility
|
|
to scripts. This requires learning their subtleties and
|
|
nuances.</para>
|
|
|
|
|
|
<sect1 id="internalvariables">
|
|
<title>Internal Variables</title>
|
|
|
|
<variablelist id="internalvariables1">
|
|
|
|
<varlistentry>
|
|
<term><replaceable><link
|
|
linkend="builtinref">Builtin</link> variables:</replaceable></term>
|
|
<listitem><para>variables affecting bash script behavior</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="bashvarref"/><varname>$BASH</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$BASH</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$BASH</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>path to bash</primary>
|
|
</indexterm>
|
|
|
|
<para>The path to the <firstterm>Bash</firstterm>
|
|
binary itself
|
|
<screen><prompt>bash$ </prompt><userinput>echo $BASH</userinput>
|
|
<computeroutput>/bin/bash</computeroutput></screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="bashenvref"/><varname>$BASH_ENV</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$BASH_ENV</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$BASH_ENV</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$BASH_SUBSHELL</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>subshell</secondary>
|
|
</indexterm>
|
|
<para>A variable indicating the <link
|
|
linkend="subshellsref">subshell</link> level. This is a
|
|
new addition to Bash, <link linkend="bash3ref">version 3</link>.</para>
|
|
<para>See <xref linkend="subshell"/> for usage.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="bashpidref"/><varname>$BASHPID</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$BASHPID</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>process ID</secondary>
|
|
</indexterm>
|
|
<para><firstterm>Process ID</firstterm>
|
|
of the current instance of Bash. This is not the same as the
|
|
<link linkend="proccid">$$</link> variable, but it often
|
|
gives the same result.</para>
|
|
<para>
|
|
<screen>
|
|
<prompt>bash4$ </prompt><userinput>echo $$</userinput>
|
|
<computeroutput>11015</computeroutput>
|
|
|
|
|
|
<prompt>bash4$ </prompt><userinput>echo $BASHPID</userinput>
|
|
<computeroutput>11015</computeroutput>
|
|
|
|
|
|
<prompt>bash4$ </prompt><userinput>ps ax | grep bash4</userinput>
|
|
<computeroutput>11015 pts/2 R 0:00 bash4</computeroutput>
|
|
</screen>
|
|
</para>
|
|
<para><anchor id="bashpidref2"/>But ...</para>
|
|
<para><programlisting>
|
|
#!/bin/bash4
|
|
|
|
echo "\$\$ outside of subshell = $$" # 9602
|
|
echo "\$BASH_SUBSHELL outside of subshell = $BASH_SUBSHELL" # 0
|
|
echo "\$BASHPID outside of subshell = $BASHPID" # 9602
|
|
|
|
echo
|
|
|
|
( echo "\$\$ inside of subshell = $$" # 9602
|
|
echo "\$BASH_SUBSHELL inside of subshell = $BASH_SUBSHELL" # 1
|
|
echo "\$BASHPID inside of subshell = $BASHPID" ) # 9603
|
|
# Note that $$ returns PID of parent process.
|
|
</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><varname>$BASH_VERSINFO[n]</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$BASH_VERSINFO</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>version information</secondary>
|
|
</indexterm>
|
|
<para>A 6-element <link linkend="arrayref">array</link>
|
|
containing version information about the installed release
|
|
of Bash. This is similar to <varname>$BASH_VERSION</varname>,
|
|
below, but a bit more detailed.</para>
|
|
<para>
|
|
<programlisting># Bash version info:
|
|
|
|
for n in 0 1 2 3 4 5
|
|
do
|
|
echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"
|
|
done
|
|
|
|
# BASH_VERSINFO[0] = 3 # Major version no.
|
|
# BASH_VERSINFO[1] = 00 # Minor version no.
|
|
# BASH_VERSINFO[2] = 14 # Patch level.
|
|
# BASH_VERSINFO[3] = 1 # Build version.
|
|
# BASH_VERSINFO[4] = release # Release status.
|
|
# BASH_VERSINFO[5] = i386-redhat-linux-gnu # Architecture
|
|
# (same as $MACHTYPE).</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$BASH_VERSION</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$BASH_VERSION</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$BASH_VERSION</secondary>
|
|
</indexterm>
|
|
<para>The version of Bash installed on the system</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
|
|
<computeroutput>3.2.25(1)-release</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>
|
|
<screen><prompt>tcsh% </prompt><userinput>echo $BASH_VERSION</userinput>
|
|
<computeroutput>BASH_VERSION: Undefined variable.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Checking $BASH_VERSION is a good method of determining which
|
|
shell is running. <link linkend="shellvarref">$SHELL</link>
|
|
does not necessarily give the correct answer.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cdpathref"/><varname>$CDPATH</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$CDPATH</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$CDPATH</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>cd path</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>cd</primary>
|
|
<secondary>path</secondary>
|
|
</indexterm>
|
|
<para>A colon-separated list of search paths
|
|
available to the <link linkend="cdref">cd</link>
|
|
command, similar in function to the <link
|
|
linkend="pathref">$PATH</link> variable for binaries.
|
|
The <varname>$CDPATH</varname> variable may be set in the
|
|
local <link
|
|
linkend="bashrc"><filename>~/.bashrc</filename></link>
|
|
file.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>cd bash-doc</userinput>
|
|
<computeroutput>bash: cd: bash-doc: No such file or directory</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>CDPATH=/usr/share/doc</userinput>
|
|
<prompt>bash$ </prompt><userinput>cd bash-doc</userinput>
|
|
<computeroutput>/usr/share/doc/bash-doc</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $PWD</userinput>
|
|
<computeroutput>/usr/share/doc/bash-doc</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dirstackref"/><varname>$DIRSTACK</varname></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The top value in the directory stack
|
|
|
|
<footnote><para><anchor id="stackdefref"/>
|
|
A <firstterm>stack register</firstterm>
|
|
is a set of consecutive memory locations, such that
|
|
the values stored (<firstterm>pushed</firstterm>)
|
|
are retrieved (<firstterm>popped</firstterm>)
|
|
in <emphasis>reverse</emphasis> order. The last
|
|
value stored is the first retrieved. This is
|
|
sometimes called a <replaceable>LIFO</replaceable>
|
|
(<firstterm>last-in-first-out</firstterm>) or
|
|
<firstterm>pushdown</firstterm> stack.</para></footnote>
|
|
|
|
(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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$EDITOR</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$EDITOR</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>editor</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$EUID</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$EUID</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>effective user ID</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$FUNCNAME</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>function</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>name</primary>
|
|
</indexterm>
|
|
<para>Name of the current function</para>
|
|
<para><programlisting>xyz23 ()
|
|
{
|
|
echo "$FUNCNAME now executing." # xyz23 now executing.
|
|
}
|
|
|
|
xyz23
|
|
|
|
echo "FUNCNAME = $FUNCNAME" # FUNCNAME =
|
|
# Null value outside a function.</programlisting>
|
|
</para>
|
|
|
|
<para>See also <xref linkend="usegetopt"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$GLOBIGNORE</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$GLOBIGNORE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>globbing</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>ignore</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$GROUPS</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$GROUPS</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>groups</primary>
|
|
</indexterm>
|
|
<para>Groups current user belongs to</para>
|
|
<para>This is a listing (array) of the group id numbers for
|
|
current user, as recorded in
|
|
<link
|
|
linkend="datafilesref1"><filename>/etc/passwd</filename></link>
|
|
and <filename>/etc/group</filename>.
|
|
</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>root# </prompt><userinput>echo $GROUPS</userinput>
|
|
<computeroutput>0</computeroutput>
|
|
|
|
|
|
<prompt>root# </prompt><userinput>echo ${GROUPS[1]}</userinput>
|
|
<computeroutput>1</computeroutput>
|
|
|
|
|
|
<prompt>root# </prompt><userinput>echo ${GROUPS[5]}</userinput>
|
|
<computeroutput>6</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="homedirref"/><varname>$HOME</varname></term>
|
|
<listitem>
|
|
<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>
|
|
<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>
|
|
<listitem>
|
|
<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>
|
|
<para>The <link linkend="hnameref">hostname</link> command
|
|
assigns the system host name at bootup in an init script.
|
|
However, the <function>gethostname()</function> function
|
|
sets the Bash internal variable <varname>$HOSTNAME</varname>.
|
|
See also <xref linkend="ex6"/>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$HOSTTYPE</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$HOSTTYPE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$HOSTTYPE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>host type</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$IFS</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$IFS</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>internal field separator</primary>
|
|
</indexterm>
|
|
<para>internal field separator</para>
|
|
|
|
<para>This variable determines how Bash recognizes <link
|
|
linkend="fieldref">fields</link>, or word boundaries,
|
|
when it interprets character strings.</para>
|
|
|
|
<para><anchor id="ifsws"/></para>
|
|
<para>$IFS defaults to <link
|
|
linkend="whitespaceref">whitespace</link> (space,
|
|
tab, and newline), but may be changed, for example,
|
|
to parse a comma-separated data file. Note that
|
|
<link linkend="appref">$*</link> uses the first
|
|
character held in <varname>$IFS</varname>. See <xref
|
|
linkend="weirdvars"/>.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo "$IFS"</userinput>
|
|
<computeroutput>
|
|
|
|
</computeroutput>
|
|
<computeroutput>(With $IFS set to default, a blank line displays.)</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo "$IFS" | cat -vte</userinput>
|
|
<computeroutput> ^I$
|
|
$</computeroutput>
|
|
<computeroutput>(Show whitespace: here a single space, ^I [horizontal tab],
|
|
and newline, and display "$" at end-of-line.)</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>bash -c 'set w x y z; IFS=":-;"; echo "$*"'</userinput>
|
|
<computeroutput>w:x:y:z</computeroutput>
|
|
<computeroutput>(Read commands from string and assign any arguments to pos params.)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Set <varname>$IFS</varname> to eliminate whitespace
|
|
in <link linkend="pathnameref">pathnames</link>.
|
|
<programlisting>IFS="$(printf '\n\t')" # Per David Wheeler.</programlisting>
|
|
</para>
|
|
|
|
<caution><para><varname>$IFS</varname> does not handle whitespace
|
|
the same as it does other characters.
|
|
|
|
<example id="ifsh">
|
|
<title>$IFS and whitespace</title>
|
|
<programlisting>&ifsh;</programlisting>
|
|
</example>
|
|
|
|
</para></caution>
|
|
|
|
<para>(Many thanks, Stéphane Chazelas, for clarification
|
|
and above examples.)</para>
|
|
|
|
<para>See also <xref linkend="isspammer"/>, <xref
|
|
linkend="bingrep"/>, and <xref linkend="mailboxgrep"/>
|
|
for instructive examples of using
|
|
<varname>$IFS</varname>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$IGNOREEOF</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$IGNOREEOF</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$IGNOREEOF</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>Ignore EOF</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$LC_COLLATE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$LC_COLLATE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>lowercase collate</primary>
|
|
</indexterm>
|
|
|
|
<para>Often set in the <link
|
|
linkend="sample-bashrc"><filename>.bashrc</filename></link>
|
|
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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$LC_CTYPE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$LC_CTYPE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>lowercase character type</primary>
|
|
</indexterm>
|
|
|
|
<para>This internal variable controls character interpretation
|
|
in <link linkend="globbingref">globbing</link> and pattern
|
|
matching.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="linenoref"/><varname>$LINENO</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$LINENO</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$LINENO</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>line number</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$MACHTYPE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$MACHTYPE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>machine type</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<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>
|
|
<para>Old working directory
|
|
(<quote>OLD-Print-Working-Directory</quote>,
|
|
previous directory you were in).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$OSTYPE</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$OSTYPE</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$OSTYPE</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>os type</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$PATH</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PATH</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>path to binaries</primary>
|
|
</indexterm>
|
|
<para>Path to binaries, usually
|
|
<filename class="directory">/usr/bin/</filename>,
|
|
<filename class="directory">/usr/X11R6/bin/</filename>,
|
|
<filename class="directory">/usr/local/bin</filename>, etc.</para>
|
|
|
|
<para>When given a command, the shell automatically does
|
|
a hash table search on the directories listed in the
|
|
<firstterm>path</firstterm> for the executable. The path
|
|
is stored in the <link linkend="envref">environmental
|
|
variable</link>, <varname>$PATH</varname>, a list
|
|
of directories, separated by colons. Normally,
|
|
the system stores the <varname>$PATH</varname>
|
|
definition in <filename>/etc/profile</filename>
|
|
and/or <link
|
|
linkend="sample-bashrc"><filename>~/.bashrc</filename></link>
|
|
(see <xref linkend="files"/>).</para>
|
|
|
|
<para><screen><prompt>bash$ </prompt><command>echo $PATH</command>
|
|
<computeroutput>/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin</computeroutput></screen>
|
|
</para>
|
|
|
|
<para><userinput>PATH=${PATH}:/opt/bin</userinput> appends
|
|
the <filename class="directory">/opt/bin</filename>
|
|
directory to the current path. In a script, it may be
|
|
expedient to temporarily add a directory to the path
|
|
in this way. When the script exits, this restores the
|
|
original <varname>$PATH</varname> (a child process, such
|
|
as a script, may not change the environment of the parent
|
|
process, the shell).</para>
|
|
|
|
<para><anchor id="currentwdref"/></para>
|
|
<note><para>The current <quote>working directory</quote>,
|
|
<filename class="directory">./</filename>, is usually
|
|
omitted from the <varname>$PATH</varname> as a security
|
|
measure.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="pipestatusref"/><varname>$PIPESTATUS</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$PIPESTATUS</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>pipe</secondary>
|
|
</indexterm>
|
|
<para><link linkend="arrayref">Array</link> variable holding
|
|
<link linkend="exitstatusref">exit status</link>(es) of
|
|
last executed <firstterm>foreground</firstterm> <link
|
|
linkend="piperef">pipe</link>.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo $PIPESTATUS</userinput>
|
|
<computeroutput>0</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -al | bogus_command</userinput>
|
|
<computeroutput>bash: bogus_command: command not found</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[1]}</userinput>
|
|
<computeroutput>127</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -al | bogus_command</userinput>
|
|
<computeroutput>bash: bogus_command: command not found</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>echo $?</userinput>
|
|
<computeroutput>127</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<para>The members of the <varname>$PIPESTATUS</varname>
|
|
array hold the exit status of each respective command
|
|
executed in a pipe. <varname>$PIPESTATUS[0]</varname>
|
|
holds the exit status of the first command in the pipe,
|
|
<varname>$PIPESTATUS[1]</varname> the exit status of
|
|
the second command, and so on.</para>
|
|
|
|
|
|
<caution>
|
|
<para>
|
|
The <varname>$PIPESTATUS</varname> variable
|
|
may contain an erroneous <errorcode>0</errorcode> value
|
|
in a login shell (in releases prior to 3.0 of Bash).
|
|
</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>tcsh% </prompt><userinput>bash</userinput>
|
|
|
|
<prompt>bash$ </prompt><userinput>who | grep nobody | sort</userinput>
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[*]}</userinput>
|
|
<computeroutput>0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
The above lines contained in a script would produce the expected
|
|
<computeroutput>0 1 0</computeroutput> output.
|
|
</para>
|
|
|
|
<para>
|
|
Thank you, Wayne Pollock for pointing this out and supplying the
|
|
above example.
|
|
</para>
|
|
|
|
</caution>
|
|
|
|
|
|
<note>
|
|
|
|
<para>The <varname>$PIPESTATUS</varname> variable gives
|
|
unexpected results in some contexts.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
|
|
<computeroutput>3.00.14(1)-release</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>$ ls | bogus_command | wc</userinput>
|
|
<computeroutput>bash: bogus_command: command not found
|
|
0 0 0</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
|
|
<computeroutput>141 127 0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Chet Ramey attributes the above output to the behavior of
|
|
<link linkend="lsref">ls</link>. If <firstterm>ls</firstterm>
|
|
writes to a <firstterm>pipe</firstterm> whose output is not
|
|
read, then <replaceable>SIGPIPE</replaceable> kills it,
|
|
and its <link linkend="exitstatusref">exit status</link>
|
|
is <returnvalue>141</returnvalue>. Otherwise
|
|
its exit status is <returnvalue>0</returnvalue>,
|
|
as expected. This likewise is the case for <link
|
|
linkend="trref">tr</link>.</para>
|
|
|
|
</note>
|
|
|
|
<note>
|
|
<para><varname>$PIPESTATUS</varname> is a
|
|
<quote>volatile</quote> variable. It needs to be
|
|
captured immediately after the pipe in question, before
|
|
any other command intervenes.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>$ ls | bogus_command | wc</userinput>
|
|
<computeroutput>bash: bogus_command: command not found
|
|
0 0 0</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
|
|
<computeroutput>0 127 0</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[@]}</userinput>
|
|
<computeroutput>0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
<note>
|
|
<para>The <link linkend="pipefailref">pipefail option</link>
|
|
may be useful in cases where
|
|
<varname>$PIPESTATUS</varname> does not give the desired
|
|
information.</para>
|
|
</note>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ppidref"/><varname>$PPID</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$PPID</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PPID</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>process ID</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$PROMPT_COMMAND</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>prompt</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$PS1</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PS1</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>prompt</primary>
|
|
</indexterm>
|
|
<para>This is the main prompt, seen at the command-line.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="secpromptref"/><varname>$PS2</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$PS2</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PS2</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>prompt</primary>
|
|
<secondary>secondary</secondary>
|
|
</indexterm>
|
|
<para>The secondary prompt, seen when additional input is
|
|
expected. It displays as <quote>></quote>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$PS3</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$PS3</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PS3</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>prompt</primary>
|
|
<secondary>tertiary</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$PS4</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$PS4</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>prompt</primary>
|
|
<secondary>quartenary</secondary>
|
|
</indexterm>
|
|
<para>The quartenary prompt, shown at the beginning of
|
|
each line of output when invoking a script with the
|
|
<token>-x</token> <emphasis>[verbose trace]</emphasis>
|
|
<link linkend="optionsref">option</link>. It displays as
|
|
<quote>+</quote>.</para>
|
|
|
|
<para>As a debugging aid, it may be useful to embed diagnostic
|
|
information in <varname>$PS4</varname>.
|
|
<programlisting>P4='$(read time junk < /proc/$$/schedstat; echo "@@@ $time @@@ " )'
|
|
# Per suggestion by Erik Brandsberg.
|
|
set -x
|
|
# Various commands follow ...</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pwdref"/><varname>$PWD</varname></term>
|
|
<listitem>
|
|
<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>
|
|
<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>
|
|
<listitem>
|
|
<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>
|
|
<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>
|
|
<listitem>
|
|
<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>
|
|
<para>The number of seconds the script has been running.</para>
|
|
<para><programlisting>&seconds;</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>$SHELLOPTS</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$SHELLOPTS</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$SHELLOPTS</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>shell options</primary>
|
|
</indexterm>
|
|
<para>The list of enabled shell <link
|
|
linkend="optionsref">options</link>, a readonly variable.
|
|
<screen><prompt>bash$ </prompt><userinput>echo $SHELLOPTS</userinput>
|
|
<computeroutput>braceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="shlvlref"/><varname>$SHLVL</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$SHLVL</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$SHLVL</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>shell level</primary>
|
|
</indexterm>
|
|
|
|
<para>Shell level, how deeply Bash is nested.
|
|
<footnote><para>
|
|
Somewhat analogous to <link
|
|
linkend="recursionref">recursion</link>, in this context
|
|
<firstterm>nesting</firstterm> refers to a pattern
|
|
embedded within a larger pattern. One of the definitions
|
|
of <firstterm>nest</firstterm>, according to the 1913
|
|
edition of <emphasis>Webster's Dictionary</emphasis>,
|
|
illustrates this beautifully: <quote><emphasis>A collection of
|
|
boxes, cases, or the like, of graduated size, each put
|
|
within the one next larger.</emphasis></quote>
|
|
</para></footnote>
|
|
If, at the command-line, $SHLVL is 1, then in a script it
|
|
will increment to 2.</para>
|
|
|
|
<note><para>This variable is <link linkend = "subshnlevref">
|
|
<emphasis>not</emphasis> affected by
|
|
subshells</link>. Use <link
|
|
linkend="bashsubshellref">$BASH_SUBSHELL</link> when you
|
|
need an indication of subshell nesting.</para></note>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tmoutref"/><varname>$TMOUT</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$TMOUT</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$TMOUT</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>timeout interval</primary>
|
|
</indexterm>
|
|
<para>If the <replaceable>$TMOUT</replaceable>
|
|
environmental variable is set to a non-zero value
|
|
<varname>time</varname>, then the shell prompt will time out
|
|
after <varname>$time</varname> seconds. This will cause a
|
|
logout.</para>
|
|
|
|
|
|
<para>As of version 2.05b of Bash, it is now possible to use
|
|
<replaceable>$TMOUT</replaceable> in a script in combination
|
|
with <link linkend="readref">read</link>.</para>
|
|
|
|
<para>
|
|
<programlisting># Works in scripts for Bash, versions 2.05b and later.
|
|
|
|
TMOUT=3 # Prompt times out at three seconds.
|
|
|
|
echo "What is your favorite song?"
|
|
echo "Quickly now, you only have $TMOUT seconds to answer!"
|
|
read song
|
|
|
|
if [ -z "$song" ]
|
|
then
|
|
song="(no answer)"
|
|
# Default response.
|
|
fi
|
|
|
|
echo "Your favorite song is $song."</programlisting>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="timingloop"/></para>
|
|
<para>There are other, more complex, ways of implementing
|
|
timed input in a script. One alternative is to set up
|
|
a timing loop to signal the script when it times out.
|
|
This also requires a signal handling routine to <link
|
|
linkend="trapref1">trap</link> (see <xref linkend="ex76"/>)
|
|
the interrupt generated by the timing loop (whew!).</para>
|
|
|
|
<example id="tmdin">
|
|
<title>Timed Input</title>
|
|
<programlisting>&tmdin;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="sttyto"/></para>
|
|
<para>An alternative is using <link
|
|
linkend="sttyref">stty</link>.</para>
|
|
|
|
<example id="timeout">
|
|
<title>Once more, timed input</title>
|
|
<programlisting>&timeout;</programlisting>
|
|
</example>
|
|
|
|
<para>Perhaps the simplest method is using the
|
|
<option>-t</option> option to <link
|
|
linkend="readref">read</link>.</para>
|
|
|
|
<example id="tout">
|
|
<title>Timed <firstterm>read</firstterm></title>
|
|
<programlisting>&tout;</programlisting>
|
|
</example>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="uidref"/><varname>$UID</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$UID</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$UID</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>user ID</primary>
|
|
</indexterm>
|
|
<para>User ID number</para>
|
|
|
|
<para>Current user's user identification number, as
|
|
recorded in <link
|
|
linkend="datafilesref1"><filename>/etc/passwd</filename></link></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 <link linkend="filesref1">Bash</link> or
|
|
<firstterm>login</firstterm> startup files. <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>
|
|
<listitem>
|
|
<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>
|
|
<para>Positional parameters, passed from command
|
|
line to script, passed to a function, or <link
|
|
linkend="setref">set</link> to a variable (see <xref
|
|
linkend="ex17"/> and <xref linkend="ex34"/>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="clacountref"/><varname>$#</varname></term>
|
|
<listitem>
|
|
<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>
|
|
<para>Number of command-line arguments
|
|
<footnote><para>The words <quote>argument</quote>
|
|
and <quote>parameter</quote> are often used
|
|
interchangeably. In the context of this document, they
|
|
have the same precise meaning: <emphasis>a variable passed
|
|
to a script or function.</emphasis></para></footnote>
|
|
or positional parameters (see <xref linkend="ex4"/>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="appref"/><varname>$*</varname></term>
|
|
<listitem>
|
|
<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>
|
|
<para>All of the positional parameters, seen as a single word</para>
|
|
<note><para><quote><varname>$*</varname></quote> must be
|
|
quoted.</para></note>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="appref2"/><varname>$@</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$@</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$*</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>positional parameter</primary>
|
|
<secondary>all</secondary>
|
|
</indexterm>
|
|
|
|
<para>Same as <token>$*</token>, but each parameter is a
|
|
quoted string, that is, the parameters are passed on
|
|
intact, without interpretation or expansion. This means,
|
|
among other things, that each parameter in the argument
|
|
list is seen as a separate word.</para>
|
|
|
|
<note><para>Of course, <quote><varname>$@</varname></quote>
|
|
should be quoted.</para></note>
|
|
|
|
<example id="arglist">
|
|
<title><firstterm>arglist</firstterm>: Listing arguments
|
|
with $* and $@</title>
|
|
<programlisting>&arglist;</programlisting>
|
|
</example>
|
|
|
|
<para>Following a <command>shift</command>, the
|
|
<varname>$@</varname> holds the remaining command-line
|
|
parameters, lacking the previous <varname>$1</varname>,
|
|
which was lost.
|
|
<programlisting>#!/bin/bash
|
|
# Invoke with ./scriptname 1 2 3 4 5
|
|
|
|
echo "$@" # 1 2 3 4 5
|
|
shift
|
|
echo "$@" # 2 3 4 5
|
|
shift
|
|
echo "$@" # 3 4 5
|
|
|
|
# Each "shift" loses parameter $1.
|
|
# "$@" then contains the remaining parameters.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>The <varname>$@</varname> special parameter finds
|
|
use as a tool for filtering input into shell scripts. The
|
|
<command>cat "$@"</command> construction accepts input
|
|
to a script either from <filename>stdin</filename> or
|
|
from files given as parameters to the script. See <xref
|
|
linkend="rot13"/> and <xref linkend="cryptoquote"/>.</para>
|
|
|
|
|
|
<caution><para>The <varname>$*</varname> and <varname>$@</varname>
|
|
parameters sometimes display inconsistent and
|
|
puzzling behavior, depending on the setting of <link
|
|
linkend="ifsref">$IFS</link>.</para></caution>
|
|
|
|
<example id="incompat">
|
|
<title>Inconsistent <varname>$*</varname> and <varname>$@</varname> behavior</title>
|
|
<programlisting>&incompat;</programlisting>
|
|
</example>
|
|
|
|
<note><para>The <command>$@</command> and <command>$*</command>
|
|
parameters differ only when between double quotes.</para></note>
|
|
|
|
<example id="ifsempty">
|
|
<title><varname>$*</varname> and <varname>$@</varname> when
|
|
<varname>$IFS</varname> is empty</title>
|
|
<programlisting>&ifsempty;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="otherspecparams">
|
|
<title>Other Special Parameters</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="flpref"/><varname>$-</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$-</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$-</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>flags</primary>
|
|
</indexterm>
|
|
<para>Flags passed to script (using <link
|
|
linkend="setref">set</link>). See <xref linkend="ex34"/>.</para>
|
|
<caution><para>This was originally a <firstterm>ksh</firstterm>
|
|
construct adopted into Bash, and unfortunately it does not
|
|
seem to work reliably in Bash scripts. One possible use
|
|
for it is to have a script <link linkend="iitest">self-test
|
|
whether it is interactive</link>.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pidvarref"/><varname>$!</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$!</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$!</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>PID</primary>
|
|
<secondary>last job background</secondary>
|
|
</indexterm>
|
|
|
|
<para><link linkend="processiddef">PID</link> (process ID) of last
|
|
job run in background</para>
|
|
|
|
<para>
|
|
<programlisting>LOG=$0.log
|
|
|
|
COMMAND1="sleep 100"
|
|
|
|
echo "Logging PIDs background commands for script: $0" >> "$LOG"
|
|
# So they can be monitored, and killed as necessary.
|
|
echo >> "$LOG"
|
|
|
|
# Logging commands.
|
|
|
|
echo -n "PID of \"$COMMAND1\": " >> "$LOG"
|
|
${COMMAND1} &
|
|
echo $! >> "$LOG"
|
|
# PID of "sleep 100": 1506
|
|
|
|
# Thank you, Jacques Lederer, for suggesting this.</programlisting>
|
|
</para>
|
|
|
|
<para>Using <varname>$!</varname> for job control:</para>
|
|
|
|
<para>
|
|
<programlisting>possibly_hanging_job & { sleep ${TIMEOUT}; eval 'kill -9 $!' &> /dev/null; }
|
|
# Forces completion of an ill-behaved program.
|
|
# Useful, for example, in init scripts.
|
|
|
|
# Thank you, Sylvain Fourmanoit, for this creative use of the "!" variable.</programlisting>
|
|
|
|
</para>
|
|
|
|
<para>Or, alternately:</para>
|
|
|
|
<para>
|
|
<programlisting># This example by Matthew Sage.
|
|
# Used with permission.
|
|
|
|
TIMEOUT=30 # Timeout value in seconds
|
|
count=0
|
|
|
|
possibly_hanging_job & {
|
|
while ((count < TIMEOUT )); do
|
|
eval '[ ! -d "/proc/$!" ] && ((count = TIMEOUT))'
|
|
# /proc is where information about running processes is found.
|
|
# "-d" tests whether it exists (whether directory exists).
|
|
# So, we're waiting for the job in question to show up.
|
|
((count++))
|
|
sleep 1
|
|
done
|
|
eval '[ -d "/proc/$!" ] && kill -15 $!'
|
|
# If the hanging job is running, kill it.
|
|
}
|
|
|
|
# -------------------------------------------------------------- #
|
|
|
|
# However, this may not work as specified if another process
|
|
#+ begins to run after the "hanging_job" . . .
|
|
# In such a case, the wrong job may be killed.
|
|
# Ariel Meragelman suggests the following fix.
|
|
|
|
TIMEOUT=30
|
|
count=0
|
|
# Timeout value in seconds
|
|
possibly_hanging_job & {
|
|
|
|
while ((count < TIMEOUT )); do
|
|
eval '[ ! -d "/proc/$lastjob" ] && ((count = TIMEOUT))'
|
|
lastjob=$!
|
|
((count++))
|
|
sleep 1
|
|
done
|
|
eval '[ -d "/proc/$lastjob" ] && kill -15 $lastjob'
|
|
|
|
}
|
|
|
|
exit</programlisting>
|
|
</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="underscoreref"/><varname>$_</varname></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$_</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$_</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>underscore</primary>
|
|
<secondary>last argument</secondary>
|
|
</indexterm>
|
|
<para>Special variable set to final 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.
|
|
# Note that this will vary according to
|
|
#+ how the script is invoked.
|
|
|
|
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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$?</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$?</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>exit status</primary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$$</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>PID</primary>
|
|
<secondary>of script</secondary>
|
|
</indexterm>
|
|
<para>Process ID (<firstterm>PID</firstterm>) of
|
|
the script itself.
|
|
|
|
<footnote><para>Within a script, inside a subshell,
|
|
<varname>$$</varname> <link linkend="bashpidref">returns
|
|
the PID of the script</link>, not the
|
|
subshell.</para></footnote>
|
|
|
|
The <varname>$$</varname> variable often
|
|
finds use in scripts to construct <quote>unique</quote>
|
|
temp file names (see <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="declareref">
|
|
<title>Typing variables: <command>declare</command> or
|
|
<command>typeset</command></title>
|
|
|
|
<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>
|
|
|
|
<para><anchor id="declare1ref"/></para>
|
|
|
|
<para>The <firstterm>declare</firstterm> or
|
|
<firstterm>typeset</firstterm> <link
|
|
linkend="builtinref">builtins</link>, which are exact synonyms,
|
|
permit modifying the properties of variables. This is
|
|
a very weak form of the <firstterm>typing</firstterm>
|
|
|
|
<footnote>
|
|
|
|
<para><anchor id="typingref"/>In this context,
|
|
<firstterm>typing</firstterm>
|
|
a variable means to classify it and restrict its properties.
|
|
For example, a variable <firstterm>declared</firstterm>
|
|
or <firstterm>typed</firstterm> as an integer
|
|
is no longer available for <link linkend="stringopstab">string
|
|
operations</link>.</para>
|
|
|
|
<para><programlisting>declare -i intvar
|
|
|
|
intvar=23
|
|
echo "$intvar" # 23
|
|
intvar=stringval
|
|
echo "$intvar" # 0</programlisting></para>
|
|
|
|
</footnote>
|
|
|
|
available in certain programming languages. The
|
|
<firstterm>declare</firstterm> command is specific to version
|
|
2 or later of Bash. The <firstterm>typeset</firstterm> command
|
|
also works in ksh scripts.</para>
|
|
|
|
<variablelist id="declareopsref">
|
|
<title><anchor id="declareopsref1"/>declare/typeset options</title>
|
|
|
|
<varlistentry>
|
|
<term><token>-r</token>
|
|
<replaceable>readonly</replaceable></term>
|
|
<listitem>
|
|
<para>(<userinput>declare -r var1</userinput> works the same as
|
|
<userinput>readonly var1</userinput>)</para>
|
|
<para>This is the rough equivalent of the <command>C</command>
|
|
<firstterm>const</firstterm> type qualifier. An attempt
|
|
to change the value of a <firstterm>readonly</firstterm>
|
|
variable fails with an error message.</para>
|
|
<para><programlisting>declare -r var1=1
|
|
echo "var1 = $var1" # var1 = 1
|
|
|
|
(( var1++ )) # x.sh: line 4: var1: readonly variable</programlisting>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-i</token> <replaceable>integer</replaceable></term>
|
|
|
|
<listitem>
|
|
|
|
<para><programlisting>declare -i number
|
|
# The script will treat subsequent occurrences of "number" as an integer.
|
|
|
|
number=3
|
|
echo "Number = $number" # Number = 3
|
|
|
|
number=three
|
|
echo "Number = $number" # Number = 0
|
|
# Tries to evaluate the string "three" as an integer.</programlisting></para>
|
|
|
|
<para>Certain arithmetic operations are permitted
|
|
for declared integer variables without the need
|
|
for <link linkend="exprref">expr</link> or <link
|
|
linkend="letref">let</link>.</para>
|
|
|
|
<para><programlisting>n=6/3
|
|
echo "n = $n" # n = 6/3
|
|
|
|
declare -i n
|
|
n=6/3
|
|
echo "n = $n" # n = 2</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="arraydeclare"/><token>-a</token>
|
|
<replaceable>array</replaceable></term>
|
|
<listitem><para><programlisting>declare -a indices</programlisting></para>
|
|
<para>The variable <parameter>indices</parameter> will be treated as
|
|
an <link linkend="arrayref">array</link>.</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-f</token> <replaceable>function(s)</replaceable></term>
|
|
<listitem>
|
|
|
|
<para><programlisting>declare -f</programlisting></para>
|
|
<para>A <userinput>declare -f</userinput> line with no
|
|
arguments in a script causes a listing of all the
|
|
<link linkend="functionref">functions</link> previously
|
|
defined in that script.</para>
|
|
|
|
<para><programlisting>declare -f function_name</programlisting></para>
|
|
<para>A <userinput>declare -f function_name</userinput>
|
|
in a script lists just the function named.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><token>-x</token> <link linkend="exportref">export</link></term>
|
|
<listitem><para><programlisting>declare -x var3</programlisting></para>
|
|
<para>This declares a variable as available for exporting outside the
|
|
environment of the script itself.</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>-x var=$value</term>
|
|
<listitem>
|
|
<para><programlisting>declare -x var3=373</programlisting></para>
|
|
<para>The <command>declare</command> command permits
|
|
assigning a value to a variable in the same statement
|
|
as setting its properties.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
<example id="ex20">
|
|
<title>Using <firstterm>declare</firstterm> to type variables</title>
|
|
<programlisting>&ex20;</programlisting>
|
|
</example>
|
|
|
|
|
|
<caution>
|
|
|
|
<para>Using the <firstterm>declare</firstterm> builtin
|
|
restricts the <link linkend="scoperef">scope</link>
|
|
of a variable.
|
|
|
|
|
|
<programlisting>foo ()
|
|
{
|
|
FOO="bar"
|
|
}
|
|
|
|
bar ()
|
|
{
|
|
foo
|
|
echo $FOO
|
|
}
|
|
|
|
bar # Prints bar.</programlisting></para>
|
|
|
|
<para>However . . .
|
|
|
|
<programlisting>foo (){
|
|
declare FOO="bar"
|
|
}
|
|
|
|
bar ()
|
|
{
|
|
foo
|
|
echo $FOO
|
|
}
|
|
|
|
bar # Prints nothing.
|
|
|
|
|
|
# Thank you, Michael Iatrou, for pointing this out.</programlisting></para>
|
|
|
|
</caution>
|
|
|
|
|
|
<sect2 id="declare2x">
|
|
<title>Another use for <firstterm>declare</firstterm></title>
|
|
|
|
<para>The <firstterm>declare</firstterm> command can be
|
|
helpful in identifying variables, <link
|
|
linkend="envref">environmental</link> or otherwise.
|
|
This can be especially useful with <link
|
|
linkend="arrayref">arrays</link>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>declare | grep HOME</userinput>
|
|
<computeroutput>HOME=/home/bozo</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>zzy=68</userinput>
|
|
<prompt>bash$ </prompt><userinput>declare | grep zzy</userinput>
|
|
<computeroutput>zzy=68</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>Colors=([0]="purple" [1]="reddish-orange" [2]="light green")</userinput>
|
|
<prompt>bash$ </prompt><userinput>echo ${Colors[@]}</userinput>
|
|
<computeroutput>purple reddish-orange light green</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>declare | grep Colors</userinput>
|
|
<computeroutput>Colors=([0]="purple" [1]="reddish-orange" [2]="light green")</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
</sect2> <!-- Another use for declare -->
|
|
|
|
</sect1> <!-- Typing variables: declare or typeset -->
|
|
|
|
|
|
|
|
|
|
|
|
<sect1 id="randomvar">
|
|
<title>$RANDOM: generate random integer</title>
|
|
|
|
<indexterm>
|
|
<primary>$RANDOM</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>$RANDOM</secondary>
|
|
</indexterm>
|
|
|
|
<epigraph>
|
|
<para>Anyone who attempts to generate random numbers by
|
|
deterministic means is, of course, living in a state of
|
|
sin.</para>
|
|
<para>--John von Neumann</para>
|
|
</epigraph>
|
|
|
|
<para><anchor id="randomvar01"/></para>
|
|
<para><varname>$RANDOM</varname> is an internal Bash <link
|
|
linkend="functionref">function</link> (not a constant) that
|
|
returns a <firstterm>pseudorandom</firstterm>
|
|
|
|
<footnote><para>True <quote>randomness,</quote> insofar as
|
|
it exists at all, can only be found in certain incompletely
|
|
understood natural phenomena, such as radioactive
|
|
decay. Computers only <firstterm>simulate</firstterm>
|
|
randomness, and computer-generated sequences of
|
|
<quote>random</quote> numbers are therefore referred to as
|
|
<firstterm>pseudorandom</firstterm>.</para></footnote>
|
|
|
|
integer in the range 0 - 32767. It should
|
|
<replaceable>not</replaceable> be used to generate an encryption
|
|
key.</para>
|
|
|
|
<example id="ex21">
|
|
<title>Generating random numbers</title>
|
|
<programlisting>&ex21;</programlisting>
|
|
</example>
|
|
|
|
<example id="pickcard">
|
|
<title>Picking a random card from a deck</title>
|
|
<programlisting>&pickcard;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="brownianref"/></para>
|
|
<example id="brownian">
|
|
<title>Brownian Motion Simulation</title>
|
|
<programlisting>&brownian;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para>
|
|
<emphasis>Jipe</emphasis> points out a set of techniques for
|
|
generating random numbers within a range.
|
|
|
|
<programlisting># Generate random number between 6 and 30.
|
|
rnumber=$((RANDOM%25+6))
|
|
|
|
# Generate random number in the same 6 - 30 range,
|
|
#+ but the number must be evenly divisible by 3.
|
|
rnumber=$(((RANDOM%30/3+1)*3))
|
|
|
|
# Note that this will not work all the time.
|
|
# It fails if $RANDOM%30 returns 0.
|
|
|
|
# Frank Wang suggests the following alternative:
|
|
rnumber=$(( RANDOM%27/3*3+6 ))</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
<emphasis>Bill Gradwohl</emphasis> came up with an improved
|
|
formula that works for positive numbers.
|
|
<programlisting>rnumber=$(((RANDOM%(max-min+divisibleBy))/divisibleBy*divisibleBy+min))</programlisting>
|
|
</para>
|
|
|
|
<para>Here Bill presents a versatile function that returns
|
|
a random number between two specified values.</para>
|
|
|
|
<example id="randombetween">
|
|
<title>Random between values</title>
|
|
<programlisting>&randombetween;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para>Just how random is <varname>$RANDOM</varname>? The best
|
|
way to test this is to write a script that tracks
|
|
the distribution of <quote>random</quote> numbers
|
|
generated by <varname>$RANDOM</varname>. Let's roll a
|
|
<varname>$RANDOM</varname> die a few times . . .</para>
|
|
|
|
<example id="randomtest">
|
|
<title>Rolling a single die with RANDOM</title>
|
|
<programlisting>&randomtest;</programlisting>
|
|
</example>
|
|
|
|
<para>As we have seen in the last example, it is best to
|
|
<firstterm>reseed</firstterm> the <parameter>RANDOM</parameter>
|
|
generator each time it is invoked. Using the same seed
|
|
for <parameter>RANDOM</parameter> repeats the same series
|
|
of numbers.
|
|
<footnote>
|
|
<para>The <firstterm>seed</firstterm> of a
|
|
computer-generated pseudorandom number series
|
|
can be considered an identification label. For
|
|
example, think of the pseudorandom series with a
|
|
seed of <emphasis>23</emphasis> as <replaceable>Series
|
|
#23</replaceable>.</para>
|
|
<para>A property of a pseurandom number series is the length of
|
|
the cycle before it starts repeating itself. A good pseurandom
|
|
generator will produce series with very long cycles.</para>
|
|
</footnote>
|
|
(This mirrors the behavior of the
|
|
<replaceable>random()</replaceable> function in
|
|
<firstterm>C</firstterm>.)</para>
|
|
|
|
<example id="seedingrandom">
|
|
<title>Reseeding RANDOM</title>
|
|
<programlisting>&seedingrandom;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="urandomref"/></para>
|
|
<note>
|
|
<para>The <filename>/dev/urandom</filename> pseudo-device file
|
|
provides a method of generating much more <quote>random</quote>
|
|
pseudorandom numbers than the <varname>$RANDOM</varname>
|
|
variable. <userinput>dd if=/dev/urandom of=targetfile
|
|
bs=1 count=XX</userinput> creates a file of well-scattered
|
|
pseudorandom numbers. However, assigning these numbers
|
|
to a variable in a script requires a workaround, such
|
|
as filtering through <link linkend="odref">od</link>
|
|
(as in above example, <xref linkend="rnd"/>, and
|
|
<xref linkend="insertionsort"/>), or even piping to
|
|
<link linkend="md5sumref">md5sum</link> (see <xref
|
|
linkend="horserace"/>).</para>
|
|
|
|
<para><anchor id="awkrandomref"/></para>
|
|
|
|
<para>There are also other ways to generate pseudorandom
|
|
numbers in a script. <command>Awk</command> provides a
|
|
convenient means of doing this.</para>
|
|
|
|
<example id="random2">
|
|
<title>Pseudorandom numbers, using <link
|
|
linkend="awkref">awk</link></title>
|
|
<programlisting>&random2;</programlisting>
|
|
</example>
|
|
|
|
<para>The <link linkend="dateref">date</link> command also lends
|
|
itself to <link linkend="daterandref">generating pseudorandom
|
|
integer sequences</link>.</para>
|
|
|
|
</note>
|
|
|
|
|
|
|
|
</sect1> <!-- RANDOM: generate random integer -->
|
|
|
|
|
|
|
|
|
|
</chapter> <!-- Variables Revisited -->
|
|
|
|
|
|
|
|
<chapter id="manipulatingvars">
|
|
<title>Manipulating Variables</title>
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>string length</primary>
|
|
<secondary>parameter substitution</secondary>
|
|
</indexterm>
|
|
|
|
<para></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr length $string</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>string length</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="strlen"/>These are the equivalent of
|
|
<firstterm>strlen()</firstterm> in
|
|
<firstterm>C</firstterm>.</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr "$string" : '.*'</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>string length</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<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><anchor id="exprmatch"/>expr match "$string"
|
|
'$substring'</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring length</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<para><replaceable>$substring</replaceable> is a <link
|
|
linkend="regexref">regular expression</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>expr "$string" : '$substring'</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring length</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<para><replaceable>$substring</replaceable> is a regular
|
|
expression.</para>
|
|
<para>
|
|
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
# |------|
|
|
# 12345678
|
|
|
|
echo `expr match "$stringZ" 'abc[A-Z]*.2'` # 8
|
|
echo `expr "$stringZ" : 'abc[A-Z]*.2'` # 8</programlisting>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="substringindex">
|
|
<title>Index</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="substringindex2"/>expr index $string
|
|
$substring</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring index</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<para>Numerical position in $string of first character in
|
|
$substring that matches.</para>
|
|
|
|
<para><programlisting>stringZ=abcABC123ABCabc
|
|
# 123456 ...
|
|
echo `expr index "$stringZ" C12` # 6
|
|
# C position.
|
|
|
|
echo `expr index "$stringZ" 1c` # 3
|
|
# 'c' (in #3 position) matches before '1'.</programlisting></para>
|
|
|
|
<para>This is the near equivalent of
|
|
<firstterm>strchr()</firstterm> in
|
|
<firstterm>C</firstterm>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="substringextraction">
|
|
<title>Substring Extraction</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="substrextr01"/>${string:position}</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>extraction</secondary>
|
|
</indexterm>
|
|
|
|
<para>Extracts substring from <replaceable>$string</replaceable> at
|
|
<replaceable>$position</replaceable>.</para>
|
|
<para>If the <varname>$string</varname> parameter is
|
|
<quote><token>*</token></quote>
|
|
or <quote><token>@</token></quote>, then this extracts the
|
|
<link linkend="posparamref">positional parameters</link>,
|
|
<footnote><para>This applies to either command-line
|
|
arguments or parameters passed to a <link
|
|
linkend="functionref">function</link>.</para></footnote>
|
|
starting at <varname>$position</varname>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="substrextr02"/>${string:position:length}</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>extraction</secondary>
|
|
</indexterm>
|
|
|
|
<para>Extracts <replaceable>$length</replaceable> characters
|
|
of substring from <replaceable>$string</replaceable> at
|
|
<replaceable>$position</replaceable>.</para>
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
# 0123456789.....
|
|
# 0-based indexing.
|
|
|
|
echo ${stringZ:0} # abcABC123ABCabc
|
|
echo ${stringZ:1} # bcABC123ABCabc
|
|
echo ${stringZ:7} # 23ABCabc
|
|
|
|
echo ${stringZ:7:3} # 23A
|
|
# Three characters of substring.
|
|
|
|
|
|
|
|
# Is it possible to index from the right end of the string?
|
|
|
|
echo ${stringZ:-4} # abcABC123ABCabc
|
|
# Defaults to full string, as in ${parameter:-default}.
|
|
# However . . .
|
|
|
|
echo ${stringZ:(-4)} # Cabc
|
|
echo ${stringZ: -4} # Cabc
|
|
# Now, it works.
|
|
# Parentheses or added space "escape" the position parameter.
|
|
|
|
# Thank you, Dan Jacobson, for pointing this out.</programlisting>
|
|
</para>
|
|
|
|
<para>The <firstterm>position</firstterm> and
|
|
<firstterm>length</firstterm> arguments can be
|
|
<quote>parameterized,</quote> that is, represented as a
|
|
variable, rather than as a numerical constant.</para>
|
|
|
|
<para><anchor id="randstring0"/></para>
|
|
<example id="randstring">
|
|
<title>Generating an 8-character <quote>random</quote>
|
|
string</title>
|
|
<programlisting>&randstring;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="substrextrp"/></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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>extraction expr</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring extraction</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring extraction</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring extraction</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring extraction</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>removal</secondary>
|
|
</indexterm>
|
|
|
|
<para>Deletes shortest match of
|
|
<replaceable>$substring</replaceable> from
|
|
<emphasis>front</emphasis> of
|
|
<replaceable>$string</replaceable>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>${string##substring}</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>removal</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<para>Deletes longest match of
|
|
<replaceable>$substring</replaceable> from
|
|
<emphasis>front</emphasis> of
|
|
<replaceable>$string</replaceable>.</para>
|
|
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
# |----| shortest
|
|
# |----------| longest
|
|
|
|
echo ${stringZ#a*C} # 123ABCabc
|
|
# Strip out shortest match between 'a' and 'C'.
|
|
|
|
echo ${stringZ##a*C} # abc
|
|
# Strip out longest match between 'a' and 'C'.
|
|
|
|
|
|
|
|
# You can parameterize the substrings.
|
|
|
|
X='a*C'
|
|
|
|
echo ${stringZ#$X} # 123ABCabc
|
|
echo ${stringZ##$X} # abc
|
|
# As above.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>${string%substring}</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>removal</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<para>Deletes shortest match of
|
|
<replaceable>$substring</replaceable> from
|
|
<emphasis>back</emphasis> of
|
|
<replaceable>$string</replaceable>.</para>
|
|
|
|
<para>For example:
|
|
<programlisting># Rename all filenames in $PWD with "TXT" suffix to a "txt" suffix.
|
|
# For example, "file1.TXT" becomes "file1.txt" . . .
|
|
|
|
SUFF=TXT
|
|
suff=txt
|
|
|
|
for i in $(ls *.$SUFF)
|
|
do
|
|
mv -f $i ${i%.$SUFF}.$suff
|
|
# Leave unchanged everything *except* the shortest pattern match
|
|
#+ starting from the right-hand-side of the variable $i . . .
|
|
done ### This could be condensed into a "one-liner" if desired.
|
|
|
|
# Thank you, Rory Winston.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>${string%%substring}</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>removal</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<para>Deletes longest match of
|
|
<replaceable>$substring</replaceable> from
|
|
<emphasis>back</emphasis> of
|
|
<replaceable>$string</replaceable>.</para>
|
|
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
# || shortest
|
|
# |------------| longest
|
|
|
|
echo ${stringZ%b*c} # abcABC123ABCa
|
|
# Strip out shortest match between 'b' and 'c', from back of $stringZ.
|
|
|
|
echo ${stringZ%%b*c} # a
|
|
# Strip out longest match between 'b' and 'c', from back of $stringZ.</programlisting>
|
|
</para>
|
|
|
|
<para>This operator is useful for generating filenames.</para>
|
|
|
|
<example id="cvt">
|
|
<title>Converting graphic file formats, with filename change</title>
|
|
<programlisting>&cvt;</programlisting>
|
|
</example>
|
|
|
|
<example id="ra2ogg">
|
|
<title>Converting streaming audio files to
|
|
<firstterm>ogg</firstterm></title>
|
|
<programlisting>&ra2ogg;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="getoptsimple1"/></para>
|
|
<para>A simple emulation of <link linkend="getopty">getopt</link>
|
|
using substring-extraction constructs.</para>
|
|
|
|
<example id="getoptsimple">
|
|
<title>Emulating <firstterm>getopt</firstterm></title>
|
|
<programlisting>&getoptsimple;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="substringreplacement">
|
|
<title>Substring Replacement</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="substrrepl00"/>${string/substring/replacement}</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>replacement</secondary>
|
|
</indexterm>
|
|
|
|
<para>
|
|
Replace first <firstterm>match</firstterm> of
|
|
<replaceable>$substring</replaceable> with
|
|
<replaceable>$replacement</replaceable>.
|
|
<footnote><para>Note that
|
|
<replaceable>$substring</replaceable> and
|
|
<replaceable>$replacement</replaceable> may refer to
|
|
either <firstterm>literal strings</firstterm> or
|
|
<firstterm>variables</firstterm>, depending on
|
|
context. See the first usage example.</para></footnote>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="substrrepl01"/>${string//substring/replacement}</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>replacement</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<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'.
|
|
|
|
echo ---------------
|
|
echo "$stringZ" # abcABC123ABCabc
|
|
echo ---------------
|
|
# The string itself is not altered!
|
|
|
|
# Can the match and replacement strings be parameterized?
|
|
match=abc
|
|
repl=000
|
|
echo ${stringZ/$match/$repl} # 000ABC123ABCabc
|
|
# ^ ^ ^^^
|
|
echo ${stringZ//$match/$repl} # 000ABC123ABC000
|
|
# Yes! ^ ^ ^^^ ^^^
|
|
|
|
echo
|
|
|
|
# What happens if no $replacement string is supplied?
|
|
echo ${stringZ/abc} # ABC123ABCabc
|
|
echo ${stringZ//abc} # ABC123ABC
|
|
# A simple deletion takes place.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="substrrepl02"/>${string/#substring/replacement}</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>replacement</secondary>
|
|
</indexterm>
|
|
|
|
<para>If <replaceable>$substring</replaceable> matches
|
|
<emphasis>front</emphasis> end of
|
|
<replaceable>$string</replaceable>, substitute
|
|
<replaceable>$replacement</replaceable> for
|
|
<replaceable>$substring</replaceable>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="substrrepl03"/>${string/%substring/replacement}</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>substring</primary>
|
|
<secondary>replacement</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<para>If <replaceable>$substring</replaceable> matches
|
|
<emphasis>back</emphasis> end of
|
|
<replaceable>$string</replaceable>, substitute
|
|
<replaceable>$replacement</replaceable> for
|
|
<replaceable>$substring</replaceable>.</para>
|
|
|
|
<para>
|
|
<programlisting>stringZ=abcABC123ABCabc
|
|
|
|
echo ${stringZ/#abc/XYZ} # XYZABC123ABCabc
|
|
# Replaces front-end match of 'abc' with 'XYZ'.
|
|
|
|
echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ
|
|
# Replaces back-end match of 'abc' with 'XYZ'.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<sect2 id="awkstringmanip">
|
|
<title>Manipulating strings using awk</title>
|
|
|
|
<para><anchor id="awkstringmanip2"/></para>
|
|
<para>A Bash script may invoke the string manipulation facilities of
|
|
<link linkend="awkref">awk</link> as an alternative to using its
|
|
built-in operations.</para>
|
|
|
|
<example id="substringex">
|
|
<title>Alternate ways of extracting and locating substrings</title>
|
|
<programlisting>&substringex;</programlisting>
|
|
</example>
|
|
|
|
</sect2> <!-- Manipulating strings using awk -->
|
|
|
|
|
|
|
|
<sect2 id="strfdisc">
|
|
<title>Further Reference</title>
|
|
|
|
<para>For more on string manipulation in scripts, refer to <xref
|
|
linkend="Parameter-Substitution"/> and the
|
|
<link linkend="expextrsub">relevant section</link> of the <link
|
|
linkend="exprref">expr</link> command listing.</para>
|
|
|
|
<para>Script examples:
|
|
<orderedlist>
|
|
<listitem><para><xref linkend="ex45"/></para></listitem>
|
|
<listitem><para><xref linkend="length"/></para></listitem>
|
|
<listitem><para><xref linkend="pattmatching"/></para></listitem>
|
|
<listitem><para><xref linkend="rfe"/></para></listitem>
|
|
<listitem><para><xref linkend="varmatch"/></para></listitem>
|
|
<listitem><para><xref linkend="insertionsort"/></para></listitem>
|
|
<listitem><para><xref linkend="qky"/></para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
</sect2> <!-- Further Reference-->
|
|
|
|
|
|
</sect1> <!-- Manipulating Strings -->
|
|
|
|
|
|
|
|
<sect1 id="Parameter-Substitution">
|
|
<title>Parameter Substitution</title>
|
|
|
|
<para><anchor id="paramsubref"/></para>
|
|
|
|
<variablelist id="pssub">
|
|
<title><anchor id="pssub1"/>Manipulating and/or expanding variables</title>
|
|
<varlistentry>
|
|
<term>
|
|
<userinput>${parameter}</userinput></term>
|
|
<listitem>
|
|
|
|
<para>Same as <replaceable>$parameter</replaceable>, i.e.,
|
|
value of the variable
|
|
<replaceable>parameter</replaceable>.
|
|
In certain contexts, only the less ambiguous
|
|
<replaceable>${parameter}</replaceable> form
|
|
works.</para>
|
|
|
|
<para>May be used for concatenating variables with strings.</para>
|
|
|
|
<para><programlisting>
|
|
your_id=${USER}-on-${HOSTNAME}
|
|
echo "$your_id"
|
|
#
|
|
echo "Old \$PATH = $PATH"
|
|
PATH=${PATH}:/opt/bin # Add /opt/bin to $PATH for duration of script.
|
|
echo "New \$PATH = $PATH"
|
|
</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="defparam1"/><userinput>${parameter-default}</userinput></term>
|
|
<term><userinput>${parameter:-default}</userinput></term>
|
|
<listitem>
|
|
<para>If parameter not set, use default.</para>
|
|
<para><programlisting>var1=1
|
|
var2=2
|
|
# var3 is unset.
|
|
|
|
echo ${var1-$var2} # 1
|
|
echo ${var3-$var2} # 2
|
|
# ^ Note the $ prefix.
|
|
|
|
|
|
|
|
echo ${username-`whoami`}
|
|
# Echoes the result of `whoami`, if variable $username is still unset.</programlisting></para>
|
|
|
|
<note><para><anchor
|
|
id="unddr"/><replaceable>${parameter-default}</replaceable>
|
|
and <replaceable>${parameter:-default}</replaceable>
|
|
are almost equivalent. The extra <token>:</token> makes
|
|
a difference only when <parameter>parameter</parameter>
|
|
has been declared, but is null. </para></note>
|
|
|
|
<para><programlisting>¶msub;</programlisting></para>
|
|
|
|
<para>The <firstterm>default parameter</firstterm> construct
|
|
finds use in providing <quote>missing</quote> command-line
|
|
arguments in scripts.</para>
|
|
|
|
<para>
|
|
<programlisting>DEFAULT_FILENAME=generic.data
|
|
filename=${1:-$DEFAULT_FILENAME}
|
|
# If not otherwise specified, the following command block operates
|
|
#+ on the file "generic.data".
|
|
# Begin-Command-Block
|
|
# ...
|
|
# ...
|
|
# ...
|
|
# End-Command-Block
|
|
|
|
|
|
|
|
# From "hanoi2.bash" example:
|
|
DISKS=${1:-E_NOPARAM} # Must specify how many disks.
|
|
# Set $DISKS to $1 command-line-parameter,
|
|
#+ or to $E_NOPARAM if that is unset.</programlisting>
|
|
</para>
|
|
|
|
<para>See also <xref linkend="ex58"/>, <xref
|
|
linkend="ex73"/>, and <xref linkend="collatz"/>.</para>
|
|
|
|
<para>Compare this method with <link
|
|
linkend="anddefault">using an <firstterm>and
|
|
list</firstterm> to supply a default command-line
|
|
argument</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${parameter=default}</userinput></term>
|
|
<term><userinput>${parameter:=default}</userinput></term>
|
|
<listitem>
|
|
<para><anchor id="defparam"/></para>
|
|
<para>If parameter not set, set it to
|
|
<firstterm>default</firstterm>.</para>
|
|
|
|
<para>Both forms nearly equivalent. The <token>:</token>
|
|
makes a difference only when <varname>$parameter</varname>
|
|
has been declared and is null,
|
|
<footnote>
|
|
<para>If $parameter is null in a
|
|
non-interactive script, it will terminate with a <link
|
|
linkend="exitcodesref"><returnvalue>127</returnvalue>
|
|
exit status</link> (the Bash error code for
|
|
<quote>command not found</quote>).</para>
|
|
</footnote>
|
|
as above.
|
|
</para>
|
|
|
|
<para><programlisting>echo ${var=abc} # abc
|
|
echo ${var=xyz} # abc
|
|
# $var had already been set to abc, so it did not change.</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="paramaltv"/><userinput>${parameter+alt_value}</userinput></term>
|
|
<term><userinput>${parameter:+alt_value}</userinput></term>
|
|
<listitem>
|
|
<para>If parameter set, use
|
|
<userinput>alt_value</userinput>, else use null
|
|
string.</para>
|
|
|
|
<para>Both forms nearly equivalent. The <token>:</token>
|
|
makes a difference only when
|
|
<parameter>parameter</parameter>
|
|
has been declared and is null, see below.</para>
|
|
|
|
<para><programlisting>echo "###### \${parameter+alt_value} ########"
|
|
echo
|
|
|
|
a=${param1+xyz}
|
|
echo "a = $a" # a =
|
|
|
|
param2=
|
|
a=${param2+xyz}
|
|
echo "a = $a" # a = xyz
|
|
|
|
param3=123
|
|
a=${param3+xyz}
|
|
echo "a = $a" # a = xyz
|
|
|
|
echo
|
|
echo "###### \${parameter:+alt_value} ########"
|
|
echo
|
|
|
|
a=${param4:+xyz}
|
|
echo "a = $a" # a =
|
|
|
|
param5=
|
|
a=${param5:+xyz}
|
|
echo "a = $a" # a =
|
|
# Different result from a=${param5+xyz}
|
|
|
|
param6=123
|
|
a=${param6:+xyz}
|
|
echo "a = $a" # a = xyz</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><anchor id="qerrmsg"/><userinput>${parameter?err_msg}</userinput></term>
|
|
<term><userinput>${parameter:?err_msg}</userinput></term>
|
|
<listitem><para>If parameter set, use it, else print
|
|
<firstterm>err_msg</firstterm> and <emphasis>abort
|
|
the script</emphasis> with an <link
|
|
linkend="exitstatusref">exit status</link> of
|
|
<errorcode>1</errorcode>.</para>
|
|
|
|
<para>Both forms nearly equivalent. The <token>:</token>
|
|
makes a difference only when <parameter>parameter</parameter>
|
|
has been declared and is null, as above.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<example id="ex6">
|
|
<title>Using parameter substitution and error messages</title>
|
|
<programlisting>&ex6;</programlisting>
|
|
</example>
|
|
|
|
<example id="usagemessage">
|
|
<title>Parameter substitution and <quote>usage</quote> messages</title>
|
|
<programlisting>&usagemessage;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<formalpara><title>Parameter substitution and/or expansion</title>
|
|
|
|
<para><anchor id="psub2"/>The following expressions are
|
|
the complement to the <command>match</command>
|
|
<replaceable>in</replaceable> <command>expr</command>
|
|
string operations (see <xref linkend="ex45"/>).
|
|
These particular ones are used mostly in parsing file
|
|
path names.</para></formalpara>
|
|
|
|
<variablelist id="psorex">
|
|
<title><anchor id="psorex1"/>Variable length / Substring removal</title>
|
|
|
|
<varlistentry>
|
|
|
|
<term><userinput>${#var}</userinput></term>
|
|
<listitem>
|
|
<para><userinput>String length</userinput> (number
|
|
of characters in <varname>$var</varname>). For
|
|
an <link linkend="arrayref">array</link>,
|
|
<command>${#array}</command> is the length of the
|
|
first element in the array.</para>
|
|
|
|
<note><para>
|
|
Exceptions:
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><anchor id="numposparam"/></para>
|
|
<para>
|
|
<command>${#*}</command> and
|
|
<command>${#@}</command> give the <emphasis>number
|
|
of positional parameters</emphasis>.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
For an array, <command>${#array[*]}</command> and
|
|
<command>${#array[@]}</command> give the number
|
|
of elements in the array.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para></note>
|
|
|
|
<example id="length">
|
|
<title>Length of a variable</title>
|
|
<programlisting>&length;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="psorex2"/><userinput>${var#Pattern}</userinput></term>
|
|
<term><userinput>${var##Pattern}</userinput></term>
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="psorexsh"/></para>
|
|
<para><command>${var#Pattern} </command>
|
|
Remove from <varname>$var</varname>
|
|
the <emphasis>shortest</emphasis> part of
|
|
<varname>$Pattern</varname> that matches
|
|
the <replaceable>front end</replaceable> of
|
|
<varname>$var</varname>.
|
|
</para>
|
|
|
|
<para><anchor id="psorexlo"/></para>
|
|
<para><command>${var##Pattern} </command>
|
|
Remove from <varname>$var</varname>
|
|
the <emphasis>longest</emphasis> part of
|
|
<varname>$Pattern</varname> that matches
|
|
the <replaceable>front end</replaceable> of
|
|
<varname>$var</varname>.
|
|
</para>
|
|
|
|
<para>A usage illustration from <xref
|
|
linkend="daysbetween"/>:
|
|
<programlisting># Function from "days-between.sh" example.
|
|
# Strips leading zero(s) from argument passed.
|
|
|
|
strip_leading_zero () # Strip possible leading zero(s)
|
|
{ #+ from argument passed.
|
|
return=${1#0} # The "1" refers to "$1" -- passed arg.
|
|
} # The "0" is what to remove from "$1" -- strips zeros.</programlisting>
|
|
</para>
|
|
|
|
<para>Manfred Schwarb's more elaborate variation of the
|
|
above:</para>
|
|
|
|
<para>
|
|
<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:</para>
|
|
<para>
|
|
<programlisting>echo `basename $PWD` # Basename of current working directory.
|
|
echo "${PWD##*/}" # Basename of current working directory.
|
|
echo
|
|
echo `basename $0` # Name of script.
|
|
echo $0 # Name of script.
|
|
echo "${0##*/}" # Name of script.
|
|
echo
|
|
filename=test.data
|
|
echo "${filename##*.}" # data
|
|
# Extension of filename.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pctpatref"/><userinput>${var%Pattern}</userinput></term>
|
|
<term><userinput>${var%%Pattern}</userinput></term>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="pctrep1"/></para>
|
|
<para><command>${var%Pattern}</command>
|
|
Remove from <varname>$var</varname>
|
|
the <emphasis>shortest</emphasis> part of
|
|
<varname>$Pattern</varname> that matches
|
|
the <replaceable>back end</replaceable> of
|
|
<varname>$var</varname>. </para>
|
|
|
|
<para><anchor id="pctrep2"/></para>
|
|
<para><command>${var%%Pattern}</command>
|
|
Remove from <varname>$var</varname>
|
|
the <emphasis>longest</emphasis> part of
|
|
<varname>$Pattern</varname> that matches
|
|
the <replaceable>back end</replaceable> of
|
|
<varname>$var</varname>. </para>
|
|
|
|
</listitem>
|
|
|
|
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<para><link linkend="bash2ref">Version 2</link> of Bash added
|
|
additional options.</para>
|
|
|
|
<example id="pattmatching">
|
|
<title>Pattern matching in parameter substitution</title>
|
|
<programlisting>&pattmatching;</programlisting>
|
|
</example>
|
|
|
|
|
|
<example id="rfe">
|
|
<title>Renaming file extensions<token>:</token></title>
|
|
<programlisting>&rfe;</programlisting>
|
|
</example>
|
|
|
|
|
|
<variablelist id="exprepl">
|
|
<title><anchor id="exprepl1"/>Variable expansion / Substring
|
|
replacement</title>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>These constructs have been adopted from
|
|
<firstterm>ksh</firstterm>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var:pos}</userinput></term>
|
|
<listitem>
|
|
<para>Variable <replaceable>var</replaceable> expanded,
|
|
starting from offset <replaceable>pos</replaceable>.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var:pos:len}</userinput></term>
|
|
<listitem>
|
|
<para>Expansion to a max of <replaceable>len</replaceable>
|
|
characters of variable <replaceable>var</replaceable>, from offset
|
|
<replaceable>pos</replaceable>. See <xref linkend="pw"/>
|
|
for an example of the creative use of this operator.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var/Pattern/Replacement}</userinput></term>
|
|
<listitem>
|
|
<para>First match of <replaceable>Pattern</replaceable>,
|
|
within <replaceable>var</replaceable> replaced with
|
|
<replaceable>Replacement</replaceable>.</para>
|
|
<para>If <replaceable>Replacement</replaceable> is
|
|
omitted, then the first match of
|
|
<replaceable>Pattern</replaceable> is replaced by
|
|
<emphasis>nothing</emphasis>, that is, deleted.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var//Pattern/Replacement}</userinput></term>
|
|
<listitem>
|
|
|
|
<formalpara><title>Global replacement</title>
|
|
<para><anchor id="psglob"/>
|
|
All matches of <replaceable>Pattern</replaceable>,
|
|
within <replaceable>var</replaceable> replaced with
|
|
<replaceable>Replacement</replaceable>.</para>
|
|
</formalpara>
|
|
|
|
<para>As above, if <replaceable>Replacement</replaceable>
|
|
is omitted, then all occurrences of
|
|
<replaceable>Pattern</replaceable> are replaced by
|
|
<emphasis>nothing</emphasis>, that is, deleted.</para>
|
|
|
|
<example id="ex7">
|
|
<title>Using pattern matching to parse arbitrary strings</title>
|
|
<programlisting>&ex7;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var/#Pattern/Replacement}</userinput></term>
|
|
<listitem>
|
|
<para>If <firstterm>prefix</firstterm> of
|
|
<replaceable>var</replaceable> matches
|
|
<replaceable>Pattern</replaceable>, then substitute
|
|
<replaceable>Replacement</replaceable> for
|
|
<replaceable>Pattern</replaceable>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>${var/%Pattern/Replacement}</userinput></term>
|
|
<listitem>
|
|
<para>If <firstterm>suffix</firstterm> of
|
|
<replaceable>var</replaceable> matches
|
|
<replaceable>Pattern</replaceable>, then substitute
|
|
<replaceable>Replacement</replaceable> for
|
|
<replaceable>Pattern</replaceable>.</para>
|
|
|
|
<example id="varmatch">
|
|
<title>Matching patterns at prefix or suffix of string</title>
|
|
<programlisting>&varmatch;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="varprefixm"/><userinput>${!varprefix*}</userinput></term>
|
|
<term><userinput>${!varprefix@}</userinput></term>
|
|
<listitem>
|
|
<para>Matches <emphasis>names</emphasis> of all
|
|
previously declared variables beginning
|
|
with <parameter>varprefix</parameter>.
|
|
<programlisting># This is a variation on indirect reference, but with a * or @.
|
|
# Bash, version 2.04, adds this feature.
|
|
|
|
xyz23=whatever
|
|
xyz24=
|
|
|
|
a=${!xyz*} # Expands to *names* of declared variables
|
|
# ^ ^ ^ + beginning with "xyz".
|
|
echo "a = $a" # a = xyz23 xyz24
|
|
a=${!xyz@} # Same as above.
|
|
echo "a = $a" # a = xyz23 xyz24
|
|
|
|
echo "---"
|
|
|
|
abc23=something_else
|
|
b=${!abc*}
|
|
echo "b = $b" # b = abc23
|
|
c=${!b} # Now, the more familiar type of indirect reference.
|
|
echo $c # something_else</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Parameter Substitution -->
|
|
|
|
</chapter> <!-- Manipulating Variables -->
|
|
|
|
|
|
|
|
<chapter id="loops">
|
|
<title>Loops and Branches</title>
|
|
|
|
<epigraph>
|
|
<para>What needs this iteration, woman?</para>
|
|
<para>--Shakespeare, <replaceable>Othello</replaceable></para>
|
|
</epigraph>
|
|
|
|
|
|
<para><anchor id="loopref00"/></para>
|
|
<para>Operations on code blocks are the key to structured and organized
|
|
shell scripts. Looping and branching constructs provide the tools for
|
|
accomplishing this.</para>
|
|
|
|
<sect1 id="loops1">
|
|
<title>Loops</title>
|
|
|
|
<para>A <firstterm>loop</firstterm> is a block of code that
|
|
<firstterm>iterates</firstterm>
|
|
|
|
<footnote><para><anchor
|
|
id="iterationref"/><firstterm>Iteration</firstterm>:
|
|
Repeated execution of a command or group of commands, usually --
|
|
but not always, <firstterm>while</firstterm> a given condition
|
|
holds, or <firstterm>until</firstterm> a given condition is
|
|
met.</para></footnote>
|
|
|
|
a list of commands
|
|
as long as the <firstterm>loop control condition</firstterm>
|
|
is true.</para>
|
|
|
|
|
|
<variablelist id="forloopref">
|
|
<title><anchor id="forloopref1"/>for loops</title>
|
|
|
|
<varlistentry>
|
|
<term><command>for <parameter>arg</parameter> in
|
|
<replaceable>[list]</replaceable></command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>This is the basic looping construct. It differs significantly
|
|
from its <firstterm>C</firstterm> counterpart.</para>
|
|
|
|
<para><anchor id="doinref"/></para>
|
|
|
|
<para><cmdsynopsis>
|
|
<command>for</command>
|
|
<arg choice="plain"><replaceable>arg</replaceable></arg>
|
|
<arg choice="plain">in</arg>
|
|
<arg choice="opt"><replaceable>list</replaceable></arg><sbr/>
|
|
<arg choice="plain">do</arg><sbr/>
|
|
<arg rep="repeat" choice="plain"><replaceable> command(s)</replaceable></arg><sbr/>
|
|
<arg choice="plain">done</arg>
|
|
</cmdsynopsis></para>
|
|
|
|
<note><para>During each pass through the loop,
|
|
<replaceable>arg</replaceable> takes on the
|
|
value of each successive variable in the
|
|
<replaceable>list</replaceable>.</para></note>
|
|
|
|
<para><programlisting>for arg in "$var1" "$var2" "$var3" ... "$varN"
|
|
# In pass 1 of the loop, arg = $var1
|
|
# In pass 2 of the loop, arg = $var2
|
|
# In pass 3 of the loop, arg = $var3
|
|
# ...
|
|
# In pass N of the loop, arg = $varN
|
|
|
|
# Arguments in [list] quoted to prevent possible word splitting.</programlisting></para>
|
|
|
|
|
|
<para>The argument <replaceable>list</replaceable> may
|
|
contain <link linkend="asteriskref">wild cards</link>.</para>
|
|
|
|
<para><anchor id="needsemicolon"/></para>
|
|
<para>If <firstterm>do</firstterm> is on same line as
|
|
<firstterm>for</firstterm>, there needs to be a semicolon
|
|
after list.</para>
|
|
|
|
<para><cmdsynopsis>
|
|
<command>for</command>
|
|
<arg choice="plain"><replaceable>arg</replaceable></arg>
|
|
<arg choice="plain">in</arg>
|
|
<arg choice="opt"><replaceable>list</replaceable></arg>
|
|
<arg choice="plain">;</arg>
|
|
<arg choice="plain">do</arg><sbr/>
|
|
</cmdsynopsis></para>
|
|
|
|
<example id="ex22">
|
|
<title>Simple <firstterm>for</firstterm> loops</title>
|
|
<programlisting>&ex22;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="multparaml"/></para>
|
|
<para>Each <userinput>[list]</userinput> element
|
|
may contain multiple parameters. This is useful when
|
|
processing parameters in groups. In such cases,
|
|
use the <link linkend="setref">set</link> command
|
|
(see <xref linkend="ex34"/>) to force parsing of each
|
|
<userinput>[list]</userinput> element and assignment of
|
|
each component to the positional parameters.</para>
|
|
|
|
<example id="ex22a">
|
|
<title><firstterm>for</firstterm> loop with two parameters in each
|
|
[list] element</title>
|
|
<programlisting>&ex22a;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="paramli"/></para>
|
|
<para>A variable may supply the <userinput>[list]</userinput> in a
|
|
<firstterm>for loop</firstterm>.</para>
|
|
|
|
<example id="fileinfo">
|
|
<title><emphasis>Fileinfo:</emphasis> operating on a file list
|
|
contained in a variable</title>
|
|
<programlisting>&fileinfo;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="paramli2"/></para>
|
|
<para>The <userinput>[list]</userinput> in a
|
|
<firstterm>for loop</firstterm> may be parameterized.</para>
|
|
|
|
<example id="fileinfo01">
|
|
<title>Operating on a parameterized file list</title>
|
|
<programlisting>&fileinfo01;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="liglob"/></para>
|
|
<para>If the <userinput>[list]</userinput> in a
|
|
<firstterm>for loop</firstterm> contains wild cards
|
|
(<token>*</token> and <token>?</token>) used in filename
|
|
expansion, then <link linkend="globbingref">globbing</link>
|
|
takes place.</para>
|
|
|
|
<example id="listglob">
|
|
<title>Operating on files with a <firstterm>for</firstterm> loop</title>
|
|
<programlisting>&listglob;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="omitlist"/></para>
|
|
<para>Omitting the <userinput>in [list]</userinput> part of a
|
|
<firstterm>for loop</firstterm> causes the loop to operate
|
|
on <token>$@</token> -- the <link linkend="posparamref">
|
|
positional parameters</link>. A particularly clever
|
|
illustration of this is <xref linkend="primes"/>. See also <xref
|
|
linkend="revposparams"/>.</para>
|
|
|
|
<example id="ex23">
|
|
<title>Missing <userinput>in [list]</userinput> in a
|
|
<firstterm>for</firstterm> loop</title>
|
|
<programlisting>&ex23;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="loopcs"/></para>
|
|
<para>It is possible to use <link
|
|
linkend="commandsubref">command substitution</link>
|
|
to generate the <userinput>[list]</userinput> in a
|
|
<firstterm>for loop</firstterm>. See also <xref linkend="ex53"/>,
|
|
<xref linkend="symlinks"/> and <xref linkend="base"/>.</para>
|
|
|
|
<example id="forloopcmd">
|
|
<title>Generating the <userinput>[list]</userinput> in
|
|
a <firstterm>for</firstterm> loop with command substitution</title>
|
|
<programlisting>&forloopcmd;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>Here is a somewhat more complex example of using command
|
|
substitution to create the <userinput>[list]</userinput>.</para>
|
|
|
|
<example id="bingrep">
|
|
<title>A <firstterm>grep</firstterm> replacement
|
|
for binary files</title>
|
|
<programlisting>&bingrep;</programlisting>
|
|
</example>
|
|
|
|
<para>More of the same.</para>
|
|
|
|
<example id="userlist">
|
|
<title>Listing all users on the system</title>
|
|
<programlisting>&userlist;</programlisting>
|
|
</example>
|
|
|
|
<para>Yet another example of the <userinput>[list]</userinput>
|
|
resulting from command substitution.</para>
|
|
|
|
<example id="findstring">
|
|
<title>Checking all the binaries in a directory for
|
|
authorship</title>
|
|
<programlisting>&findstring;</programlisting>
|
|
</example>
|
|
|
|
<para>A final example of <userinput>[list]</userinput>
|
|
/ command substitution, but this time
|
|
the <quote>command</quote> is a <link
|
|
linkend="functionref">function</link>.</para>
|
|
|
|
<para><programlisting>generate_list ()
|
|
{
|
|
echo "one two three"
|
|
}
|
|
|
|
for word in $(generate_list) # Let "word" grab output of function.
|
|
do
|
|
echo "$word"
|
|
done
|
|
|
|
# one
|
|
# two
|
|
# three</programlisting></para>
|
|
|
|
|
|
<para><anchor id="loopredir"/></para>
|
|
<para>The output of a <firstterm>for loop</firstterm> may
|
|
be piped to a command or commands.</para>
|
|
|
|
<example id="symlinks">
|
|
<title>Listing the <firstterm>symbolic
|
|
links</firstterm> in a directory</title>
|
|
<programlisting>&symlinks;</programlisting>
|
|
</example>
|
|
|
|
<para>The <filename>stdout</filename> of a loop may be <link
|
|
linkend="ioredirref">redirected</link> to a file, as this slight
|
|
modification to the previous example shows.</para>
|
|
|
|
<example id="symlinks2">
|
|
<title>Symbolic links in a directory, saved to a file</title>
|
|
<programlisting>&symlinks2;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="loopcstyle"/></para>
|
|
<para>There is an alternative syntax to a <firstterm>for
|
|
loop</firstterm> that will look very familiar to C
|
|
programmers. This requires <link
|
|
linkend="dblparensref">double parentheses</link>.</para>
|
|
|
|
<example id="forloopc">
|
|
<title>A C-style <firstterm>for</firstterm> loop</title>
|
|
<programlisting>&forloopc;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="qfunction"/>, <xref
|
|
linkend="twodim"/>, and <xref linkend="collatz"/>.</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para>Now, a <firstterm>for loop</firstterm> used in a
|
|
<quote>real-life</quote> context.</para>
|
|
|
|
<example id="ex24">
|
|
<title>Using <firstterm>efax</firstterm> in batch mode</title>
|
|
<programlisting>&ex24;</programlisting>
|
|
</example>
|
|
|
|
<note><para><anchor id="nododone"/>The
|
|
<link linkend="keywordref">keywords</link>
|
|
<command>do</command> and <command>done</command> delineate
|
|
the <firstterm>for-loop</firstterm> command block. However,
|
|
these may, in certain contexts, be omitted by framing the
|
|
command block within <link linkend="codeblockref">curly
|
|
brackets</link>
|
|
|
|
<programlisting>for((n=1; n<=10; n++))
|
|
# No do!
|
|
{
|
|
echo -n "* $n *"
|
|
}
|
|
# No done!
|
|
|
|
|
|
# Outputs:
|
|
# * 1 ** 2 ** 3 ** 4 ** 5 ** 6 ** 7 ** 8 ** 9 ** 10 *
|
|
# And, echo $? returns 0, so Bash does not register an error.
|
|
|
|
|
|
echo
|
|
|
|
|
|
# But, note that in a classic for-loop: for n in [list] ...
|
|
#+ a terminal semicolon is required.
|
|
|
|
for n in 1 2 3
|
|
{ echo -n "$n "; }
|
|
# ^
|
|
|
|
|
|
# Thank you, YongYe, for pointing this out.</programlisting>
|
|
</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whileloopref"/><command>while</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>while</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>do</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>done</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>loop</primary>
|
|
<secondary>while</secondary>
|
|
</indexterm>
|
|
<para>This construct tests for a condition at the top of a
|
|
loop, and keeps looping as long as that condition
|
|
is true (returns a <returnvalue>0</returnvalue> <link
|
|
linkend="exitstatusref">exit status</link>). In contrast
|
|
to a <link linkend="forloopref1">for loop</link>, a
|
|
<firstterm>while loop</firstterm> finds use in situations
|
|
where the number of loop repetitions is not known
|
|
beforehand.</para>
|
|
|
|
<para><cmdsynopsis>
|
|
<command>while</command>
|
|
<arg choice="opt"><replaceable> condition </replaceable></arg><sbr/>
|
|
<arg choice="plain">do</arg><sbr/>
|
|
<arg choice="plain" rep="repeat"><replaceable> command(s)</replaceable></arg><sbr/>
|
|
<arg choice="plain">done</arg>
|
|
</cmdsynopsis></para>
|
|
|
|
|
|
<para>The bracket construct in a <firstterm>while
|
|
loop</firstterm> is nothing more than our old friend,
|
|
the <link linkend="testconstructs1">test brackets</link>
|
|
used in an <firstterm>if/then</firstterm> test. In fact,
|
|
a <firstterm>while loop</firstterm> can legally use the
|
|
more versatile <link linkend="dblbrackets">double-brackets
|
|
construct</link> (while [[ condition ]]).</para>
|
|
|
|
<para><anchor id="whileneedsemi"/></para>
|
|
<para><link linkend="needsemicolon">As is the case with
|
|
<firstterm>for loops</firstterm></link>, placing the
|
|
<firstterm>do</firstterm> on the same line as the condition
|
|
test requires a semicolon.</para>
|
|
|
|
<para><cmdsynopsis>
|
|
<command>while</command>
|
|
<arg choice="opt"><replaceable> condition </replaceable></arg>
|
|
<arg choice="plain">;</arg>
|
|
<arg choice="plain">do</arg>
|
|
</cmdsynopsis></para>
|
|
|
|
<para>Note that the <firstterm>test brackets</firstterm>
|
|
<link linkend="whilenobrackets">are <emphasis>not</emphasis>
|
|
mandatory</link> in a <firstterm>while</firstterm> loop.
|
|
See, for example, the <link linkend="getoptsx">getopts
|
|
construct</link>.</para>
|
|
|
|
<example id="ex25">
|
|
<title>Simple <firstterm>while</firstterm> loop</title>
|
|
<programlisting>&ex25;</programlisting>
|
|
</example>
|
|
|
|
<example id="ex26">
|
|
<title>Another <firstterm>while</firstterm> loop</title>
|
|
<programlisting>&ex26;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="whmultcond"/></para>
|
|
<para>A <firstterm>while loop</firstterm> may have multiple
|
|
conditions. Only the final condition determines when the loop
|
|
terminates. This necessitates a slightly different loop syntax,
|
|
however.</para>
|
|
|
|
<example id="ex26a">
|
|
<title><firstterm>while</firstterm> loop with multiple conditions</title>
|
|
<programlisting>&ex26a;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="wloopcstyle"/></para>
|
|
<para>As with a <firstterm>for loop</firstterm>, a
|
|
<firstterm>while loop</firstterm> may employ C-style syntax
|
|
by using the double-parentheses construct (see also <xref
|
|
linkend="cvars"/>).</para>
|
|
|
|
<example id="whloopc">
|
|
<title>C-style syntax in a <firstterm>while</firstterm> loop</title>
|
|
<programlisting>&whloopc;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="whilefunc"/></para>
|
|
<para>
|
|
Inside its test brackets, a <firstterm>while loop</firstterm>
|
|
can call a <link linkend="functionref">function</link>.
|
|
|
|
<programlisting>t=0
|
|
|
|
condition ()
|
|
{
|
|
((t++))
|
|
|
|
if [ $t -lt 5 ]
|
|
then
|
|
return 0 # true
|
|
else
|
|
return 1 # false
|
|
fi
|
|
}
|
|
|
|
while condition
|
|
# ^^^^^^^^^
|
|
# Function call -- four loop iterations.
|
|
do
|
|
echo "Still going: t = $t"
|
|
done
|
|
|
|
# Still going: t = 1
|
|
# Still going: t = 2
|
|
# Still going: t = 3
|
|
# Still going: t = 4</programlisting>
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
<sidebar><para><anchor id="whilenobrackets"/></para>
|
|
<para>Similar to the <link linkend="ifgrepref">if-test</link>
|
|
construct, a <firstterm>while</firstterm> loop can omit the test
|
|
brackets.
|
|
<programlisting>while condition
|
|
do
|
|
command(s) ...
|
|
done</programlisting></para></sidebar>
|
|
|
|
<para><anchor id="whilereadref2"/></para>
|
|
<para>By coupling the power of the <link
|
|
linkend="readref">read</link> command with a
|
|
<firstterm>while loop</firstterm>, we get the handy <link
|
|
linkend="whilereadref">while read</link> construct, useful
|
|
for reading and parsing files.</para>
|
|
|
|
<para><programlisting>cat $filename | # Supply input from a file.
|
|
while read line # As long as there is another line to read ...
|
|
do
|
|
...
|
|
done
|
|
|
|
# =========== Snippet from "sd.sh" example script ========== #
|
|
|
|
while read value # Read one data point at a time.
|
|
do
|
|
rt=$(echo "scale=$SC; $rt + $value" | bc)
|
|
(( ct++ ))
|
|
done
|
|
|
|
am=$(echo "scale=$SC; $rt / $ct" | bc)
|
|
|
|
echo $am; return $ct # This function "returns" TWO values!
|
|
# Caution: This little trick will not work if $ct > 255!
|
|
# To handle a larger number of data points,
|
|
#+ simply comment out the "return $ct" above.
|
|
} <"$datafile" # Feed in data file.</programlisting></para>
|
|
|
|
<para><anchor id="whredir"/></para>
|
|
<note>
|
|
<para>A <firstterm>while loop</firstterm> may have its
|
|
<filename>stdin</filename> <link
|
|
linkend="redirref">redirected to a file</link> by a
|
|
<token><</token> at its end.</para>
|
|
|
|
<para>A <firstterm>while loop</firstterm> may have its
|
|
<filename>stdin</filename> <link linkend="readpiperef">
|
|
supplied by a pipe</link>.</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="untilloopref"/><command>until</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>until</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>do</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>done</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>loop</primary>
|
|
<secondary>until</secondary>
|
|
</indexterm>
|
|
|
|
<para>This construct tests for a condition at the top of a loop, and keeps
|
|
looping as long as that condition is
|
|
<emphasis>false</emphasis> (opposite of <firstterm>while
|
|
loop</firstterm>).</para>
|
|
|
|
<para><cmdsynopsis>
|
|
<command>until</command>
|
|
<arg choice="opt"><replaceable> condition-is-true </replaceable></arg><sbr/>
|
|
<arg choice="plain">do</arg><sbr/>
|
|
<arg choice="plain" rep="repeat"><replaceable> command(s)</replaceable></arg><sbr/>
|
|
<arg choice="plain">done</arg>
|
|
</cmdsynopsis></para>
|
|
|
|
<para>Note that an <firstterm>until loop</firstterm> tests for the
|
|
terminating condition at the <emphasis>top</emphasis>
|
|
of the loop, differing from a similar construct in some
|
|
programming languages.</para>
|
|
|
|
<para>As is the case with <firstterm>for loops</firstterm>,
|
|
placing the <firstterm>do</firstterm> on the same line as
|
|
the condition test requires a semicolon.</para>
|
|
|
|
<para><cmdsynopsis>
|
|
<command>until</command>
|
|
<arg choice="opt"><replaceable> condition-is-true </replaceable></arg>
|
|
<arg choice="plain">;</arg>
|
|
<arg choice="plain">do</arg>
|
|
</cmdsynopsis></para>
|
|
|
|
<example id="ex27">
|
|
<title><firstterm>until</firstterm> loop</title>
|
|
<programlisting>&ex27;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<para><anchor id="chooseloop"/></para>
|
|
<para>How to choose between a <firstterm>for</firstterm> loop or a
|
|
<firstterm>while</firstterm> loop or
|
|
<firstterm>until</firstterm> loop? In <command>C</command>,
|
|
you would typically use a <firstterm>for</firstterm> loop
|
|
when the number of loop iterations is known beforehand. With
|
|
<firstterm>Bash</firstterm>, however, the situation is
|
|
fuzzier. The Bash <firstterm>for</firstterm> loop is more
|
|
loosely structured and more flexible than its equivalent in
|
|
other languages. Therefore, feel free to use whatever type
|
|
of loop gets the job done in the simplest way.</para>
|
|
|
|
</sect1> <!-- Loops -->
|
|
|
|
|
|
|
|
<sect1 id="nestedloops">
|
|
<title>Nested Loops</title>
|
|
|
|
<para>A <firstterm>nested loop</firstterm> is a loop within a
|
|
loop, an inner loop within the body of an outer one. How
|
|
this works is that the first pass of the outer loop triggers
|
|
the inner loop, which executes to completion. Then the
|
|
second pass of the outer loop triggers the inner loop
|
|
again. This repeats until the outer loop finishes. Of course,
|
|
a <firstterm>break</firstterm> within either the inner or outer
|
|
loop would interrupt this process.</para>
|
|
|
|
<example id="nestedloop">
|
|
<title>Nested Loop</title>
|
|
<programlisting>&nestedloop;</programlisting>
|
|
</example>
|
|
|
|
<para>See <xref linkend="bubble"/> for an illustration of nested
|
|
<link linkend="whileloopref">while loops</link>, and <xref
|
|
linkend="ex68"/> to see a while loop nested inside an <link
|
|
linkend="untilloopref">until loop</link>.</para>
|
|
|
|
</sect1> <!-- Nested Loops -->
|
|
|
|
|
|
<sect1 id="loopcontrol">
|
|
<title>Loop Control</title>
|
|
|
|
<epigraph>
|
|
<para>Tournez cent tours, tournez mille tours,</para>
|
|
<para>Tournez souvent et tournez toujours . . .</para>
|
|
<para>--Verlaine, <quote>Chevaux de bois</quote></para>
|
|
</epigraph>
|
|
|
|
<variablelist id="brkcont">
|
|
<title><anchor id="brkcont1"/>Commands affecting loop behavior</title>
|
|
|
|
<varlistentry>
|
|
<term><command>break</command></term>
|
|
<term><command>continue</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>break</command> and <command>continue</command>
|
|
loop control commands
|
|
<footnote><para>These are shell <link
|
|
linkend="builtinref">builtins</link>,
|
|
whereas other loop commands, such as <link
|
|
linkend="whileloopref">while</link> and <link
|
|
linkend="caseesac1">case</link>, are <link
|
|
linkend="keywordref">keywords</link>.</para></footnote>
|
|
correspond exactly to their counterparts in other
|
|
programming languages. The <command>break</command>
|
|
command terminates the loop (<emphasis>breaks</emphasis>
|
|
out of it), while <command>continue</command> causes a jump
|
|
to the next <link linkend="iterationref">iteration</link>
|
|
of the loop, skipping all the remaining commands in that
|
|
particular loop cycle.</para>
|
|
|
|
<example id="ex28">
|
|
<title>Effects of <firstterm>break</firstterm> and
|
|
<command>continue</command> in a loop</title>
|
|
<programlisting>&ex28;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="breakparam"/></para>
|
|
<para>The <command>break</command> command may optionally take a
|
|
parameter. A plain <command>break</command> terminates
|
|
only the innermost loop in which it is embedded,
|
|
but a <command>break N</command> breaks out of
|
|
<parameter>N</parameter> levels of loop.</para>
|
|
|
|
<example id="breaklevels">
|
|
<title>Breaking out of multiple loop levels</title>
|
|
<programlisting>&breaklevels;</programlisting>
|
|
</example>
|
|
|
|
<para>The <command>continue</command> command, similar to
|
|
<command>break</command>, optionally takes a parameter. A
|
|
plain <command>continue</command> cuts short the
|
|
current iteration within its loop and begins the next.
|
|
A <command>continue N</command> terminates all remaining
|
|
iterations at its loop level and continues with the
|
|
next iteration at the loop, <option>N</option> levels
|
|
above.</para>
|
|
|
|
<example id="continuelevels">
|
|
<title>Continuing at a higher loop level</title>
|
|
<programlisting>&continuelevels;</programlisting>
|
|
</example>
|
|
|
|
<example id="continuenex">
|
|
<title>Using <firstterm>continue N</firstterm> in an actual task</title>
|
|
<programlisting>&continuenex;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>The <command>continue N</command> construct is
|
|
difficult to understand and tricky to use in any meaningful
|
|
context. It is probably best avoided.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Loop Control Commands -->
|
|
|
|
|
|
|
|
<sect1 id="testbranch">
|
|
<title>Testing and Branching</title>
|
|
|
|
<para>The <command>case</command> and <command>select</command>
|
|
constructs are technically not loops, since they do not iterate the
|
|
execution of a code block. Like loops, however, they direct
|
|
program flow according to conditions at the top or bottom of
|
|
the block.</para>
|
|
|
|
<variablelist id="caseesac">
|
|
<title><anchor id="caseesac1"/>Controlling program flow in a code
|
|
block</title>
|
|
|
|
<varlistentry>
|
|
<term><command>case (in) / esac</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para>The <command>case</command> construct is the shell
|
|
scripting analog to <replaceable>switch</replaceable>
|
|
in <command>C/C++</command>.
|
|
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/>
|
|
<command>esac</command>
|
|
</cmdsynopsis></para>
|
|
|
|
<note><para>
|
|
<itemizedlist>
|
|
<listitem><para>Quoting the variables is not mandatory,
|
|
since word splitting does not take place.</para>
|
|
</listitem>
|
|
<listitem>
|
|
|
|
<para><anchor id="caseparen"/>Each test line
|
|
ends with a right paren <command>)</command>.
|
|
|
|
<footnote><para>Pattern-match lines may also <emphasis>start</emphasis>
|
|
with a <command>(</command> left paren to give the layout
|
|
a more structured appearance.</para>
|
|
<para><programlisting>case $( arch ) in # $( arch ) returns machine architecture.
|
|
( i386 ) echo "80386-based machine";;
|
|
# ^ ^
|
|
( i486 ) echo "80486-based machine";;
|
|
( i586 ) echo "Pentium-based machine";;
|
|
( i686 ) echo "Pentium2+-based machine";;
|
|
( * ) echo "Other type of machine";;
|
|
esac</programlisting></para></footnote>
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem><para>Each condition block ends
|
|
with a <emphasis>double</emphasis> semicolon
|
|
<token>;;</token>.</para>
|
|
</listitem>
|
|
<listitem><para>If a condition tests
|
|
<firstterm>true</firstterm>, then the associated
|
|
commands execute and the <command>case</command>
|
|
block terminates.</para></listitem>
|
|
<listitem><para>The entire <command>case</command>
|
|
block ends with an <command>esac</command>
|
|
(<wordasword>case</wordasword> spelled backwards).</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para></note>
|
|
|
|
<example id="ex29">
|
|
<title>Using <firstterm>case</firstterm></title>
|
|
<programlisting>&ex29;</programlisting>
|
|
</example>
|
|
|
|
<example id="ex30">
|
|
<title>Creating menus using <firstterm>case</firstterm></title>
|
|
<programlisting>&ex30;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="casecl"/></para>
|
|
<para>An exceptionally clever use of <command>case</command>
|
|
involves testing for command-line parameters.
|
|
<programlisting>#! /bin/bash
|
|
|
|
case "$1" in
|
|
"") echo "Usage: ${0##*/} <filename>"; exit $E_PARAM;;
|
|
# No command-line parameters,
|
|
# or first parameter empty.
|
|
# Note that ${0##*/} is ${var##pattern} param substitution.
|
|
# Net result is $0.
|
|
|
|
-*) FILENAME=./$1;; # If filename passed as argument ($1)
|
|
#+ starts with a dash,
|
|
#+ replace it with ./$1
|
|
#+ so further commands don't interpret it
|
|
#+ as an option.
|
|
|
|
* ) FILENAME=$1;; # Otherwise, $1.
|
|
esac</programlisting></para>
|
|
|
|
<para>Here is a more straightforward example of
|
|
command-line parameter handling:
|
|
<programlisting>#! /bin/bash
|
|
|
|
|
|
while [ $# -gt 0 ]; do # Until you run out of parameters . . .
|
|
case "$1" in
|
|
-d|--debug)
|
|
# "-d" or "--debug" parameter?
|
|
DEBUG=1
|
|
;;
|
|
-c|--conf)
|
|
CONFFILE="$2"
|
|
shift
|
|
if [ ! -f $CONFFILE ]; then
|
|
echo "Error: Supplied file doesn't exist!"
|
|
exit $E_CONFFILE # File not found error.
|
|
fi
|
|
;;
|
|
esac
|
|
shift # Check next set of parameters.
|
|
done
|
|
|
|
# From Stefano Falsetto's "Log2Rot" script,
|
|
#+ part of his "rottlog" package.
|
|
# Used with permission.</programlisting></para>
|
|
|
|
|
|
<example id="casecmd">
|
|
<title>Using <firstterm>command substitution</firstterm>
|
|
to generate the <firstterm>case</firstterm> variable</title>
|
|
<programlisting>&casecmd;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="csglob"/></para>
|
|
<para>A <command>case</command> construct can filter strings for
|
|
<link linkend="globbingref">globbing</link> patterns.</para>
|
|
|
|
<example id="matchstring">
|
|
<title>Simple string matching</title>
|
|
<programlisting>&matchstring;</programlisting>
|
|
</example>
|
|
|
|
<example id="isalpha">
|
|
<title>Checking for alphabetic input</title>
|
|
<programlisting>&isalpha;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="selectref"/><command>select</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>select</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>menus</primary>
|
|
</indexterm>
|
|
<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 this may be changed.</para>
|
|
|
|
<example id="ex31">
|
|
<title>Creating menus using <firstterm>select</firstterm></title>
|
|
<programlisting>&ex31;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="inlistomit"/></para>
|
|
<para>If <userinput>in <replaceable>list</replaceable></userinput> is
|
|
omitted, then <command>select</command> uses the list of command
|
|
line arguments (<varname>$@</varname>) passed to the script or
|
|
the function containing the <command>select</command>
|
|
construct.</para>
|
|
|
|
<para>Compare this to the behavior of a
|
|
<cmdsynopsis>
|
|
<command>for</command>
|
|
<arg choice="plain"><replaceable>variable</replaceable></arg>
|
|
<arg choice="opt">in <replaceable>list</replaceable></arg>
|
|
</cmdsynopsis>
|
|
construct with the
|
|
<userinput>in <replaceable>list</replaceable></userinput>
|
|
omitted.</para>
|
|
|
|
<example id="ex32">
|
|
<title>Creating menus using <firstterm>select</firstterm>
|
|
in a function</title>
|
|
<programlisting>&ex32;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="resistor"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Testing and Branching -->
|
|
|
|
|
|
</chapter> <!-- Loops -->
|
|
|
|
|
|
|
|
<chapter id="commandsub">
|
|
<title>Command Substitution</title>
|
|
|
|
<indexterm>
|
|
<primary>$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>`</secondary>
|
|
</indexterm>
|
|
|
|
<para>
|
|
<anchor id="commandsubref"/><command>Command
|
|
substitution</command> reassigns the output of a command
|
|
<footnote><para>For purposes of <firstterm>command
|
|
substitution</firstterm>, a <command>command</command>
|
|
may be an external system command, an internal scripting
|
|
<link linkend="builtinref">builtin</link>, or even <link
|
|
linkend="rvt">a script function</link>.</para></footnote>
|
|
or even multiple commands; it literally plugs the command
|
|
output into another context.
|
|
|
|
<footnote><para>In a more technically correct sense,
|
|
<firstterm>command substitution</firstterm> extracts the
|
|
<filename>stdout</filename> of a command, then assigns
|
|
it to a variable using the <token>=</token>
|
|
operator.</para></footnote>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="backquotesref"/>The classic form of command
|
|
substitution uses <firstterm>backquotes</firstterm>
|
|
(`...`). Commands within backquotes (backticks) generate
|
|
command-line text.
|
|
|
|
<programlisting>script_name=`basename $0`
|
|
echo "The name of this script is $script_name."</programlisting></para>
|
|
|
|
|
|
<formalpara>
|
|
<title>The output of commands can be used as arguments to
|
|
another command, to set a variable, and even for generating
|
|
the argument list in a <link linkend="forloopref1">for</link>
|
|
loop.</title>
|
|
<para></para>
|
|
</formalpara>
|
|
|
|
<para>
|
|
<programlisting>rm `cat filename` # <quote>filename</quote> contains a list of files to delete.
|
|
#
|
|
# S. C. points out that "arg list too long" error might result.
|
|
# Better is xargs rm -- < filename
|
|
# ( -- covers those cases where <quote>filename</quote> begins with a <quote>-</quote> )
|
|
|
|
textfile_listing=`ls *.txt`
|
|
# Variable contains names of all *.txt files in current working directory.
|
|
echo $textfile_listing
|
|
|
|
textfile_listing2=$(ls *.txt) # The alternative form of command substitution.
|
|
echo $textfile_listing2
|
|
# Same result.
|
|
|
|
# A possible problem with putting a list of files into a single string
|
|
# is that a newline may creep in.
|
|
#
|
|
# A safer way to assign a list of files to a parameter is with an array.
|
|
# shopt -s nullglob # If no match, filename expands to nothing.
|
|
# textfile_listing=( *.txt )
|
|
#
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<note><para><anchor id="cssubsh"/>Command substitution
|
|
invokes a <link
|
|
linkend="subshellsref">subshell</link>.</para></note>
|
|
|
|
|
|
|
|
<caution><para><anchor id="csws"/>Command substitution may
|
|
result in <link linkend="wsplitref">word splitting</link>.
|
|
<programlisting>COMMAND `echo a b` # 2 args: a and b
|
|
|
|
COMMAND "`echo a b`" # 1 arg: "a b"
|
|
|
|
COMMAND `echo` # no arg
|
|
|
|
COMMAND "`echo`" # one empty arg
|
|
|
|
|
|
# Thanks, S.C.</programlisting></para>
|
|
|
|
|
|
<para><anchor id="cstrnl"/></para>
|
|
<para>Even when there is no word splitting, command
|
|
substitution can remove trailing newlines.
|
|
|
|
<programlisting># cd "`pwd`" # This should always work.
|
|
# However...
|
|
|
|
mkdir 'dir with trailing newline
|
|
'
|
|
|
|
cd 'dir with trailing newline
|
|
'
|
|
|
|
cd "`pwd`" # Error message:
|
|
# bash: cd: /tmp/file with trailing newline: No such file or directory
|
|
|
|
cd "$PWD" # Works fine.
|
|
|
|
|
|
|
|
|
|
|
|
old_tty_setting=$(stty -g) # Save old terminal setting.
|
|
echo "Hit a key "
|
|
stty -icanon -echo # Disable "canonical" mode for terminal.
|
|
# Also, disable *local* echo.
|
|
key=$(dd bs=1 count=1 2> /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.
|
|
|
|
#Code snippet by Stéphane Chazelas.</programlisting>
|
|
</para>
|
|
</caution>
|
|
|
|
|
|
<caution>
|
|
<para>Using <command>echo</command> to output an
|
|
<firstterm>unquoted</firstterm> variable set with command
|
|
substitution removes trailing newlines characters from
|
|
the output of the reassigned command(s). This can cause
|
|
unpleasant surprises.
|
|
|
|
<programlisting>dir_listing=`ls -l`
|
|
echo $dir_listing # unquoted
|
|
|
|
# Expecting a nicely ordered directory listing.
|
|
|
|
# However, what you get is:
|
|
# total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
|
|
# bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh
|
|
|
|
# The newlines disappeared.
|
|
|
|
|
|
echo "$dir_listing" # quoted
|
|
# -rw-rw-r-- 1 bozo 30 May 13 17:15 1.txt
|
|
# -rw-rw-r-- 1 bozo 51 May 15 20:57 t2.sh
|
|
# -rwxr-xr-x 1 bozo 217 Mar 5 21:13 wi.sh</programlisting>
|
|
</para>
|
|
</caution>
|
|
|
|
|
|
|
|
<para>Command substitution even permits setting a variable to the
|
|
contents of a file, using either <link
|
|
linkend="ioredirref">redirection</link> or the <link
|
|
linkend="catref">cat</link> command.</para>
|
|
|
|
<para>
|
|
<programlisting>variable1=`<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 that the variables may contain embedded whitespace,
|
|
#+ or even (horrors), control characters.
|
|
|
|
# It is not necessary to explicitly assign a variable.
|
|
echo "` <$0`" # Echoes the script itself to stdout.</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting># Excerpts from system file, /etc/rc.d/rc.sysinit
|
|
#+ (on a Red Hat Linux installation)
|
|
|
|
|
|
if [ -f /fsckoptions ]; then
|
|
fsckoptions=`cat /fsckoptions`
|
|
...
|
|
fi
|
|
#
|
|
#
|
|
if [ -e "/proc/ide/${disk[$device]}/media" ] ; then
|
|
hdmedia=`cat /proc/ide/${disk[$device]}/media`
|
|
...
|
|
fi
|
|
#
|
|
#
|
|
if [ ! -n "`uname -r | grep -- "-"`" ]; then
|
|
ktag="`cat /proc/version`"
|
|
...
|
|
fi
|
|
#
|
|
#
|
|
if [ $usb = "1" ]; then
|
|
sleep 5
|
|
mouseoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=02"`
|
|
kbdoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=01"`
|
|
...
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
<caution>
|
|
<para>Do not set a variable to the contents of a
|
|
<emphasis>long</emphasis> text file unless you have a very good
|
|
reason for doing so. Do not set a variable to the contents of a
|
|
<firstterm>binary</firstterm> file, even as a joke.</para>
|
|
|
|
<example id="stupscr">
|
|
<title>Stupid script tricks</title>
|
|
<programlisting>&stupscr;</programlisting>
|
|
</example>
|
|
|
|
<para>Notice that a <firstterm>buffer overrun</firstterm>
|
|
does not occur. This is one instance where an interpreted
|
|
language, such as Bash, provides more protection from
|
|
programmer mistakes than a compiled language.</para>
|
|
|
|
</caution>
|
|
|
|
|
|
<para><anchor id="csvl"/></para>
|
|
<para>Command substitution permits setting a variable to the
|
|
output of a <link linkend="forloopref1">loop</link>. The
|
|
key to this is grabbing the output of an <link
|
|
linkend="echoref">echo</link> command within the
|
|
loop.</para>
|
|
|
|
<example id="csubloop">
|
|
<title>Generating a variable from a loop</title>
|
|
<programlisting>&csubloop;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para><anchor id="cstoolset"/></para>
|
|
<sidebar>
|
|
<para>Command substitution makes it possible to extend the
|
|
toolset available to Bash. It is simply a matter
|
|
of writing a program or script that outputs to
|
|
<filename>stdout</filename> (like a well-behaved UNIX
|
|
tool should) and assigning that output to a variable.</para>
|
|
|
|
<para>
|
|
<programlisting>#include <stdio.h>
|
|
|
|
/* "Hello, world." C program */
|
|
|
|
int main()
|
|
{
|
|
printf( "Hello, world.\n" );
|
|
return (0);
|
|
}</programlisting>
|
|
<screen><prompt>bash$ </prompt><userinput>gcc -o hello hello.c</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# hello.sh
|
|
|
|
greeting=`./hello`
|
|
echo $greeting</programlisting>
|
|
<screen><prompt>bash$ </prompt><userinput>sh hello.sh</userinput>
|
|
<computeroutput>Hello, world.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</sidebar>
|
|
|
|
<note>
|
|
|
|
<para><anchor id="csparens"/>The <command>$(...)</command>
|
|
form has superseded backticks for command
|
|
substitution.</para>
|
|
|
|
<para><programlisting>output=$(sed -n /"$1"/p $file) # From "grp.sh" example.
|
|
|
|
# Setting a variable to the contents of a text file.
|
|
File_contents1=$(cat $file1)
|
|
File_contents2=$(<$file2) # Bash permits this also.</programlisting></para>
|
|
|
|
<para>The <command>$(...)</command> form of command substitution
|
|
treats a double backslash in a different way than
|
|
<command>`...`</command>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo `echo \\`</userinput>
|
|
<computeroutput></computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $(echo \\)</userinput>
|
|
<computeroutput>\</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="csnest"/></para>
|
|
<para>The <command>$(...)</command> form of command
|
|
substitution permits nesting.
|
|
<footnote>
|
|
<para>
|
|
In fact, nesting with backticks is also possible,
|
|
but only by escaping the inner backticks, as John
|
|
Default points out.
|
|
<programlisting>word_count=` wc -w \`echo * | awk '{print $8}'\` `</programlisting>
|
|
</para>
|
|
</footnote>
|
|
|
|
</para>
|
|
|
|
<para><programlisting>word_count=$( wc -w $(echo * | awk '{print $8}') )</programlisting>
|
|
</para>
|
|
|
|
<para>Or, for something a bit more elaborate . . .</para>
|
|
|
|
<example id="agram2">
|
|
<title>Finding anagrams</title>
|
|
<programlisting>&agram2;</programlisting>
|
|
</example>
|
|
|
|
|
|
</note>
|
|
|
|
|
|
<para>Examples of command substitution in shell scripts:
|
|
<orderedlist>
|
|
<listitem><para><xref linkend="bingrep"/></para></listitem>
|
|
<listitem><para><xref linkend="casecmd"/></para></listitem>
|
|
<listitem><para><xref linkend="seedingrandom"/></para></listitem>
|
|
<listitem><para><xref linkend="ex57"/></para></listitem>
|
|
<listitem><para><xref linkend="lowercase"/></para></listitem>
|
|
<listitem><para><xref linkend="grp"/></para></listitem>
|
|
<listitem><para><xref linkend="ex53"/></para></listitem>
|
|
<listitem><para><xref linkend="ex24"/></para></listitem>
|
|
<listitem><para><xref linkend="symlinks"/></para></listitem>
|
|
<listitem><para><xref linkend="stripc"/></para></listitem>
|
|
<listitem><para><xref linkend="redir4"/></para></listitem>
|
|
<listitem><para><xref linkend="tree"/></para></listitem>
|
|
<listitem><para><xref linkend="pidid"/></para></listitem>
|
|
<listitem><para><xref linkend="monthlypmt"/></para></listitem>
|
|
<listitem><para><xref linkend="base"/></para></listitem>
|
|
<listitem><para><xref linkend="altbc"/></para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
</chapter> <!-- Command Substitution -->
|
|
|
|
|
|
|
|
<chapter id="arithexp">
|
|
<title>Arithmetic Expansion</title>
|
|
|
|
|
|
<para><anchor id="arithexpref"/>Arithmetic expansion provides a
|
|
powerful tool for performing (integer) arithmetic
|
|
operations in scripts. Translating a string into a
|
|
numerical expression is relatively straightforward using
|
|
<firstterm>backticks</firstterm>, <firstterm>double
|
|
parentheses</firstterm>, or <firstterm>let</firstterm>.</para>
|
|
|
|
<variablelist id="arithexpvar">
|
|
<title><anchor id="arithexpvar1"/>Variations</title>
|
|
|
|
<varlistentry>
|
|
<term>Arithmetic expansion with <link linkend="backquotesref">backticks</link> (often used in
|
|
conjunction with <link linkend="exprref">expr</link>)</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>arithmetic</primary> <secondary>expansion</secondary>
|
|
</indexterm> <indexterm>
|
|
<primary>arithmetic</primary> <secondary>expansion</secondary>
|
|
</indexterm>
|
|
<para><programlisting>z=`expr $z + 3` # The 'expr' command performs the expansion.</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term>Arithmetic expansion with <link linkend="dblparens">double
|
|
parentheses</link></term>
|
|
<term>and using <link linkend="letref">let</link></term>
|
|
<listitem>
|
|
<indexterm><primary>double</primary>
|
|
<secondary>parentheses</secondary></indexterm>
|
|
<indexterm><primary>let</primary>
|
|
<secondary>let</secondary></indexterm>
|
|
|
|
|
|
|
|
<para>The use of <firstterm>backticks</firstterm>
|
|
(<firstterm>backquotes</firstterm>) in arithmetic
|
|
expansion has been superseded by <firstterm>double
|
|
parentheses</firstterm> --
|
|
<userinput>((...))</userinput> and
|
|
<userinput>$((...))</userinput> -- and also by the very
|
|
convenient <link linkend="letref">let</link> construction.</para>
|
|
|
|
<para>
|
|
<programlisting>z=$(($z+3))
|
|
z=$((z+3)) # Also correct.
|
|
# Within double parentheses,
|
|
#+ parameter dereferencing
|
|
#+ is optional.
|
|
|
|
# $((EXPRESSION)) is arithmetic expansion. # Not to be confused with
|
|
#+ command substitution.
|
|
|
|
|
|
|
|
# You may also use operations within double parentheses without assignment.
|
|
|
|
n=0
|
|
echo "n = $n" # n = 0
|
|
|
|
(( n += 1 )) # Increment.
|
|
# (( $n += 1 )) is incorrect!
|
|
echo "n = $n" # n = 1
|
|
|
|
|
|
let z=z+3
|
|
let "z += 3" # Quotes permit the use of spaces in variable assignment.
|
|
# The 'let' operator actually performs arithmetic evaluation,
|
|
#+ rather than expansion.</programlisting>
|
|
</para>
|
|
|
|
<para>Examples of arithmetic expansion in scripts:
|
|
<orderedlist>
|
|
<listitem><para><xref linkend="ex45"/></para></listitem>
|
|
<listitem><para><xref linkend="ex25"/></para></listitem>
|
|
<listitem><para><xref linkend="ex66"/></para></listitem>
|
|
<listitem><para><xref linkend="bubble"/></para></listitem>
|
|
<listitem><para><xref linkend="tree"/></para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</chapter> <!-- Arithmetic Expansion -->
|
|
|
|
|
|
|
|
|
|
<chapter id="Recess-Time">
|
|
<title>Recess Time</title>
|
|
|
|
<para><emphasis>
|
|
This bizarre little intermission gives the reader a chance to
|
|
relax and maybe laugh a bit.
|
|
</emphasis></para>
|
|
|
|
<blockquote>
|
|
<literallayout>
|
|
|
|
Fellow Linux user, greetings! You are reading something which
|
|
will bring you luck and good fortune. Just e-mail a copy of
|
|
this document to 10 of your friends. Before making the copies,
|
|
send a 100-line Bash script to the first person on the list
|
|
at the bottom of this letter. Then delete their name and add
|
|
yours to the bottom of the list.
|
|
|
|
Don't break the chain! Make the copies within 48 hours.
|
|
Wilfred P. of Brooklyn failed to send out his ten copies and
|
|
woke the next morning to find his job description changed
|
|
to "COBOL programmer." Howard L. of Newport News sent
|
|
out his ten copies and within a month had enough hardware
|
|
to build a 100-node Beowulf cluster dedicated to playing
|
|
<emphasis>Tuxracer</emphasis>. Amelia V. of Chicago laughed at this letter
|
|
and broke the chain. Shortly thereafter, a fire broke out
|
|
in her terminal and she now spends her days writing
|
|
documentation for MS Windows.
|
|
|
|
Don't break the chain! Send out your ten copies today!
|
|
|
|
</literallayout>
|
|
</blockquote>
|
|
|
|
|
|
<para><emphasis>Courtesy 'NIX "fortune cookies", with some
|
|
alterations and many apologies</emphasis></para>
|
|
|
|
</chapter> <!-- Recess Time -->
|
|
|
|
|
|
</part> <!-- Part 3 (Beyond the Basics) -->
|
|
|
|
|
|
<part label="Part 4" id="part4">
|
|
<title>Commands</title>
|
|
|
|
|
|
<partintro>
|
|
|
|
<para><anchor id="part4A"/></para>
|
|
<para>Mastering the commands on your Linux machine is an indispensable
|
|
prelude to writing effective shell scripts.</para>
|
|
|
|
<para>This section covers the following commands:</para>
|
|
|
|
|
|
<itemizedlist id="Commandlist">
|
|
|
|
<listitem><para><link linkend="dotref">.</link>
|
|
(See also <link linkend="sourceref">source</link>)</para></listitem>
|
|
<listitem><para><link linkend="acref">ac</link></para></listitem>
|
|
<listitem><para><link linkend="useraddref">adduser</link></para></listitem>
|
|
<listitem><para><link linkend="agettyref">agetty</link></para></listitem>
|
|
<listitem><para><link linkend="agrepref">agrep</link></para></listitem>
|
|
<listitem><para><link linkend="arref">ar</link></para></listitem>
|
|
<listitem><para><link linkend="archref">arch</link></para></listitem>
|
|
<listitem><para><link linkend="atref">at</link></para></listitem>
|
|
<listitem><para><link linkend="autoloadref">autoload</link></para></listitem>
|
|
<listitem><para><link linkend="awkref">awk</link>
|
|
(See also <link linkend="awkmath">Using
|
|
<command>awk</command> for
|
|
math operations</link>)</para></listitem>
|
|
<listitem><para><link linkend="badblocksref">badblocks</link></para></listitem>
|
|
<listitem><para><link linkend="bannerref">banner</link></para></listitem>
|
|
<listitem><para><link linkend="basenameref">basename</link></para></listitem>
|
|
<listitem><para><link linkend="batchref">batch</link></para></listitem>
|
|
<listitem><para><link linkend="bcref">bc</link></para></listitem>
|
|
<listitem><para><link linkend="bgref">bg</link></para></listitem>
|
|
<listitem><para><link linkend="bindref">bind</link></para></listitem>
|
|
<listitem><para><link linkend="bisonref">bison</link></para></listitem>
|
|
<listitem><para><link linkend="bltref">builtin</link></para></listitem>
|
|
<listitem><para><link linkend="bzgrepref">bzgrep</link></para></listitem>
|
|
<listitem><para><link linkend="bzipref">bzip2</link></para></listitem>
|
|
<listitem><para><link linkend="calref">cal</link></para></listitem>
|
|
<listitem><para><link linkend="callerref">caller</link></para></listitem>
|
|
<listitem><para><link linkend="catref">cat</link></para></listitem>
|
|
<listitem><para><link linkend="cdref">cd</link></para></listitem>
|
|
<listitem><para><link linkend="chattrref">chattr</link></para></listitem>
|
|
<listitem><para><link linkend="chfnref">chfn</link></para></listitem>
|
|
<listitem><para><link linkend="chgrpref">chgrp</link></para></listitem>
|
|
<listitem><para><link linkend="chkconfigref">chkconfig</link></para></listitem>
|
|
<listitem><para><link linkend="chmodref">chmod</link></para></listitem>
|
|
<listitem><para><link linkend="chownref">chown</link></para></listitem>
|
|
<listitem><para><link linkend="chrootref">chroot</link></para></listitem>
|
|
<listitem><para><link linkend="cksumref">cksum</link></para></listitem>
|
|
<listitem><para><link linkend="clearref">clear</link></para></listitem>
|
|
<listitem><para><link linkend="clockref">clock</link></para></listitem>
|
|
<listitem><para><link linkend="cmpref">cmp</link></para></listitem>
|
|
<listitem><para><link linkend="colref">col</link></para></listitem>
|
|
<listitem><para><link linkend="colrmref">colrm</link></para></listitem>
|
|
<listitem><para><link linkend="columnref">column</link></para></listitem>
|
|
<listitem><para><link linkend="commref">comm</link></para></listitem>
|
|
<listitem><para><link linkend="commandref">command</link></para></listitem>
|
|
<listitem><para><link linkend="compgenref">compgen</link></para></listitem>
|
|
<listitem><para><link linkend="completeref">complete</link></para></listitem>
|
|
<listitem><para><link linkend="compressref">compress</link></para></listitem>
|
|
<listitem><para><link linkend="coprocref">coproc</link></para></listitem>
|
|
<listitem><para><link linkend="cpref">cp</link></para></listitem>
|
|
<listitem><para><link linkend="cpioref">cpio</link></para></listitem>
|
|
<listitem><para><link linkend="cronref">cron</link></para></listitem>
|
|
<listitem><para><link linkend="cryptref">crypt</link></para></listitem>
|
|
<listitem><para><link linkend="csplitref">csplit</link></para></listitem>
|
|
<listitem><para><link linkend="curef">cu</link></para></listitem>
|
|
<listitem><para><link linkend="cutref">cut</link></para></listitem>
|
|
<listitem><para><link linkend="dateref">date</link></para></listitem>
|
|
<listitem><para><link linkend="dcref">dc</link></para></listitem>
|
|
<listitem><para><link linkend="ddref">dd</link></para></listitem>
|
|
<listitem><para><link linkend="debugfsref">debugfs</link></para></listitem>
|
|
<listitem><para><link linkend="declareref">declare</link></para></listitem>
|
|
<listitem><para><link linkend="depmodref">depmod</link></para></listitem>
|
|
<listitem><para><link linkend="dfref">df</link></para></listitem>
|
|
<listitem><para><link linkend="dialogref">dialog</link></para></listitem>
|
|
<listitem><para><link linkend="diffref">diff</link></para></listitem>
|
|
<listitem><para><link linkend="diff3ref">diff3</link></para></listitem>
|
|
<listitem><para><link linkend="diffstatref">diffstat</link></para></listitem>
|
|
<listitem><para><link linkend="digref">dig</link></para></listitem>
|
|
<listitem><para><link linkend="dirnameref">dirname</link></para></listitem>
|
|
<listitem><para><link linkend="dirsd">dirs</link></para></listitem>
|
|
<listitem><para><link linkend="disownref">disown</link></para></listitem>
|
|
<listitem><para><link linkend="dmesgref">dmesg</link></para></listitem>
|
|
<listitem><para><link linkend="doexecref">doexec</link></para></listitem>
|
|
<listitem><para><link linkend="dos2unixref">dos2unix</link></para></listitem>
|
|
<listitem><para><link linkend="duref">du</link></para></listitem>
|
|
<listitem><para><link linkend="dumpref">dump</link></para></listitem>
|
|
<listitem><para><link linkend="dumpe2fsref">dumpe2fs</link></para></listitem>
|
|
<listitem><para><link linkend="e2fsckref">e2fsck</link></para></listitem>
|
|
<listitem><para><link linkend="echoref">echo</link></para></listitem>
|
|
<listitem><para><link linkend="egrepref">egrep</link></para></listitem>
|
|
<listitem><para><link linkend="enableref">enable</link></para></listitem>
|
|
<listitem><para><link linkend="enscriptref">enscript</link></para></listitem>
|
|
<listitem><para><link linkend="envvref">env</link></para></listitem>
|
|
<listitem><para><link linkend="eqnref">eqn</link></para></listitem>
|
|
<listitem><para><link linkend="evalref">eval</link></para></listitem>
|
|
<listitem><para><link linkend="execref">exec</link></para></listitem>
|
|
<listitem><para><link linkend="exitref">exit</link>
|
|
(Related topic: <link linkend="exitstatusref">exit
|
|
status</link>)</para></listitem>
|
|
<listitem><para><link linkend="expandref">expand</link></para></listitem>
|
|
<listitem><para><link linkend="exportref">export</link></para></listitem>
|
|
<listitem><para><link linkend="exprref">expr</link></para></listitem>
|
|
<listitem><para><link linkend="factorref">factor</link></para></listitem>
|
|
<listitem><para><link linkend="falseref">false</link></para></listitem>
|
|
<listitem><para><link linkend="fdformatref">fdformat</link></para></listitem>
|
|
<listitem><para><link linkend="fdiskref">fdisk</link></para></listitem>
|
|
<listitem><para><link linkend="fgref">fg</link></para></listitem>
|
|
<listitem><para><link linkend="fgrepref">fgrep</link></para></listitem>
|
|
<listitem><para><link linkend="fileref">file</link></para></listitem>
|
|
<listitem><para><link linkend="findref">find</link></para></listitem>
|
|
<listitem><para><link linkend="fingerref">finger</link></para></listitem>
|
|
<listitem><para><link linkend="flexref">flex</link></para></listitem>
|
|
<listitem><para><link linkend="flockref">flock</link></para></listitem>
|
|
<listitem><para><link linkend="fmtref">fmt</link></para></listitem>
|
|
<listitem><para><link linkend="foldref">fold</link></para></listitem>
|
|
<listitem><para><link linkend="freeref">free</link></para></listitem>
|
|
<listitem><para><link linkend="fsckref">fsck</link></para></listitem>
|
|
<listitem><para><link linkend="ftpref">ftp</link></para></listitem>
|
|
<listitem><para><link linkend="fuserref">fuser</link></para></listitem>
|
|
<listitem><para><link linkend="getfaclref">getfacl</link></para></listitem>
|
|
<listitem><para><link linkend="getopty">getopt</link></para></listitem>
|
|
<listitem><para><link linkend="getoptsx">getopts</link></para></listitem>
|
|
<listitem><para><link linkend="gettextref">gettext</link></para></listitem>
|
|
<listitem><para><link linkend="gettyref">getty</link></para></listitem>
|
|
<listitem><para><link linkend="gnomemountref">gnome-mount</link></para></listitem>
|
|
<listitem><para><link linkend="grepref">grep</link></para></listitem>
|
|
<listitem><para><link linkend="groffref">groff</link></para></listitem>
|
|
<listitem><para><link linkend="groupmodref">groupmod</link></para></listitem>
|
|
<listitem><para><link linkend="groupscmdref">groups</link>
|
|
(Related topic: the <link linkend="groupsref">$GROUPS</link>
|
|
variable)</para></listitem>
|
|
<listitem><para><link linkend="gsref">gs</link></para></listitem>
|
|
<listitem><para><link linkend="gzipref">gzip</link></para></listitem>
|
|
<listitem><para><link linkend="haltref">halt</link></para></listitem>
|
|
<listitem><para><link linkend="hashcmdref">hash</link></para></listitem>
|
|
<listitem><para><link linkend="hdparmref">hdparm</link></para></listitem>
|
|
<listitem><para><link linkend="headref">head</link></para></listitem>
|
|
<listitem><para><link linkend="helpref">help</link></para></listitem>
|
|
<listitem><para><link linkend="hexdumpref">hexdump</link></para></listitem>
|
|
<listitem><para><link linkend="hostref">host</link></para></listitem>
|
|
<listitem><para><link linkend="hostidref">hostid</link></para></listitem>
|
|
<listitem><para><link linkend="hnameref">hostname</link>
|
|
(Related topic: the <link linkend="hostnameref">$HOSTNAME</link>
|
|
variable)</para></listitem>
|
|
<listitem><para><link linkend="hwclockref">hwclock</link></para></listitem>
|
|
<listitem><para><link linkend="iconvref">iconv</link></para></listitem>
|
|
<listitem><para><link linkend="idref">id</link>
|
|
(Related topic: the <link linkend="uidref">$UID</link>
|
|
variable)</para></listitem>
|
|
<listitem><para><link linkend="ifconfigref">ifconfig</link></para></listitem>
|
|
<listitem><para><link linkend="inforef">info</link></para></listitem>
|
|
<listitem><para><link linkend="infocmpref">infocmp</link></para></listitem>
|
|
<listitem><para><link linkend="initref">init</link></para></listitem>
|
|
<listitem><para><link linkend="insmodref">insmod</link></para></listitem>
|
|
<listitem><para><link linkend="installref">install</link></para></listitem>
|
|
<listitem><para><link linkend="ipref">ip</link></para></listitem>
|
|
<listitem><para><link linkend="ipcalcref">ipcalc</link></para></listitem>
|
|
<listitem><para><link linkend="iptablesref">iptables</link></para></listitem>
|
|
<listitem><para><link linkend="iwconfigref">iwconfig</link></para></listitem>
|
|
<listitem><para><link linkend="jobsref">jobs</link></para></listitem>
|
|
<listitem><para><link linkend="joinref">join</link></para></listitem>
|
|
<listitem><para><link linkend="jotref">jot</link></para></listitem>
|
|
<listitem><para><link linkend="killref">kill</link></para></listitem>
|
|
<listitem><para><link linkend="killallref">killall</link></para></listitem>
|
|
<listitem><para><link linkend="lastref">last</link></para></listitem>
|
|
<listitem><para><link linkend="lastcommref">lastcomm</link></para></listitem>
|
|
<listitem><para><link linkend="lastlogref">lastlog</link></para></listitem>
|
|
<listitem><para><link linkend="lddref">ldd</link></para></listitem>
|
|
<listitem><para><link linkend="lessref">less</link></para></listitem>
|
|
<listitem><para><link linkend="letref">let</link></para></listitem>
|
|
<listitem><para><link linkend="lexref">lex</link></para></listitem>
|
|
<listitem><para><link linkend="lidref">lid</link></para></listitem>
|
|
<listitem><para><link linkend="linkref">ln</link></para></listitem>
|
|
<listitem><para><link linkend="locateref">locate</link></para></listitem>
|
|
<listitem><para><link linkend="lockfileref">lockfile</link></para></listitem>
|
|
<listitem><para><link linkend="loggerref">logger</link></para></listitem>
|
|
<listitem><para><link linkend="lognameref">logname</link></para></listitem>
|
|
<listitem><para><link linkend="logoutref">logout</link></para></listitem>
|
|
<listitem><para><link linkend="logrotateref">logrotate</link></para></listitem>
|
|
<listitem><para><link linkend="lookref">look</link></para></listitem>
|
|
<listitem><para><link linkend="losetupref">losetup</link></para></listitem>
|
|
<listitem><para><link linkend="lpref">lp</link></para></listitem>
|
|
<listitem><para><link linkend="lsref">ls</link></para></listitem>
|
|
<listitem><para><link linkend="lsdevref">lsdev</link></para></listitem>
|
|
<listitem><para><link linkend="lsmodref">lsmod</link></para></listitem>
|
|
<listitem><para><link linkend="lsofref">lsof</link></para></listitem>
|
|
<listitem><para><link linkend="lspciref">lspci</link></para></listitem>
|
|
<listitem><para><link linkend="lsusbref">lsusb</link></para></listitem>
|
|
<listitem><para><link linkend="ltraceref">ltrace</link></para></listitem>
|
|
<listitem><para><link linkend="lynxref">lynx</link></para></listitem>
|
|
<listitem><para><link linkend="lzmaref">lzcat</link></para></listitem>
|
|
<listitem><para><link linkend="lzmaref">lzma</link></para></listitem>
|
|
<listitem><para><link linkend="m4ref">m4</link></para></listitem>
|
|
<listitem><para><link linkend="commmail1">mail</link></para></listitem>
|
|
<listitem><para><link linkend="mailstatsref">mailstats</link></para></listitem>
|
|
<listitem><para><link linkend="mailtoref">mailto</link></para></listitem>
|
|
<listitem><para><link linkend="makeref">make</link></para></listitem>
|
|
<listitem><para><link linkend="MAKEDEVref">MAKEDEV</link></para></listitem>
|
|
<listitem><para><link linkend="manref">man</link></para></listitem>
|
|
<listitem><para><link linkend="mapfileref">mapfile</link></para></listitem>
|
|
<listitem><para><link linkend="mcookieref">mcookie</link></para></listitem>
|
|
<listitem><para><link linkend="md5sumref">md5sum</link></para></listitem>
|
|
<listitem><para><link linkend="mergeref">merge</link></para></listitem>
|
|
<listitem><para><link linkend="mesgref">mesg</link></para></listitem>
|
|
<listitem><para><link linkend="mimencoderef">mimencode</link></para></listitem>
|
|
<listitem><para><link linkend="mkbootdiskref">mkbootdisk</link></para></listitem>
|
|
<listitem><para><link linkend="mkdirref">mkdir</link></para></listitem>
|
|
<listitem><para><link linkend="mkdosfsref">mkdosfs</link></para></listitem>
|
|
<listitem><para><link linkend="mke2fsref">mke2fs</link></para></listitem>
|
|
<listitem><para><link linkend="mkfiforef">mkfifo</link></para></listitem>
|
|
<listitem><para><link linkend="mkisofsref">mkisofs</link></para></listitem>
|
|
<listitem><para><link linkend="mknodref">mknod</link></para></listitem>
|
|
<listitem><para><link linkend="mkswapref">mkswap</link></para></listitem>
|
|
<listitem><para><link linkend="mktempref">mktemp</link></para></listitem>
|
|
<listitem><para><link linkend="mmencoderef">mmencode</link></para></listitem>
|
|
<listitem><para><link linkend="modinforef">modinfo</link></para></listitem>
|
|
<listitem><para><link linkend="modproberef">modprobe</link></para></listitem>
|
|
<listitem><para><link linkend="moreref">more</link></para></listitem>
|
|
<listitem><para><link linkend="mountref">mount</link></para></listitem>
|
|
<listitem><para><link linkend="msgfmtref">msgfmt</link></para></listitem>
|
|
<listitem><para><link linkend="mvref">mv</link></para></listitem>
|
|
<listitem><para><link linkend="ncref">nc</link></para></listitem>
|
|
<listitem><para><link linkend="netconfigref">netconfig</link></para></listitem>
|
|
<listitem><para><link linkend="netstatref">netstat</link></para></listitem>
|
|
<listitem><para><link linkend="newgrpref">newgrp</link></para></listitem>
|
|
<listitem><para><link linkend="niceref">nice</link></para></listitem>
|
|
<listitem><para><link linkend="nlref">nl</link></para></listitem>
|
|
<listitem><para><link linkend="nmref">nm</link></para></listitem>
|
|
<listitem><para><link linkend="nmapref">nmap</link></para></listitem>
|
|
<listitem><para><link linkend="nohupref">nohup</link></para></listitem>
|
|
<listitem><para><link linkend="nslookupref">nslookup</link></para></listitem>
|
|
<listitem><para><link linkend="objdumpref">objdump</link></para></listitem>
|
|
<listitem><para><link linkend="odref">od</link></para></listitem>
|
|
<listitem><para><link linkend="opensslref">openssl</link></para></listitem>
|
|
<listitem><para><link linkend="passwdref">passwd</link></para></listitem>
|
|
<listitem><para><link linkend="pasteref">paste</link></para></listitem>
|
|
<listitem><para><link linkend="patchref">patch</link>
|
|
(Related topic: <link linkend="diffref">diff</link>)</para></listitem>
|
|
<listitem><para><link linkend="pathchkref">pathchk</link></para></listitem>
|
|
<listitem><para><link linkend="paxref">pax</link></para></listitem>
|
|
<listitem><para><link linkend="pgrepref">pgrep</link></para></listitem>
|
|
<listitem><para><link linkend="pidofref">pidof</link></para></listitem>
|
|
<listitem><para><link linkend="pingref">ping</link></para></listitem>
|
|
<listitem><para><link linkend="pkillref">pkill</link></para></listitem>
|
|
<listitem><para><link linkend="dirsd">popd</link></para></listitem>
|
|
<listitem><para><link linkend="prref">pr</link></para></listitem>
|
|
<listitem><para><link linkend="printenvref">printenv</link></para></listitem>
|
|
<listitem><para><link linkend="printfref">printf</link></para></listitem>
|
|
<listitem><para><link linkend="procinforef">procinfo</link></para></listitem>
|
|
<listitem><para><link linkend="ppssref">ps</link></para></listitem>
|
|
<listitem><para><link linkend="pstreeref">pstree</link></para></listitem>
|
|
<listitem><para><link linkend="ptxref">ptx</link></para></listitem>
|
|
<listitem><para><link linkend="dirsd">pushd</link></para></listitem>
|
|
<listitem><para><link linkend="pwd2ref">pwd</link>
|
|
(Related topic: the <link linkend="pwdref">$PWD</link>
|
|
variable)</para></listitem>
|
|
<listitem><para><link linkend="quotaref">quota</link></para></listitem>
|
|
<listitem><para><link linkend="rcpref">rcp</link></para></listitem>
|
|
<listitem><para><link linkend="rdevref">rdev</link></para></listitem>
|
|
<listitem><para><link linkend="rdistref">rdist</link></para></listitem>
|
|
<listitem><para><link linkend="readref">read</link></para></listitem>
|
|
<listitem><para><link linkend="readelfref">readelf</link></para></listitem>
|
|
<listitem><para><link linkend="readlinkref">readlink</link></para></listitem>
|
|
<listitem><para><link linkend="readonlyref">readonly</link></para></listitem>
|
|
<listitem><para><link linkend="rebootref">reboot</link></para></listitem>
|
|
<listitem><para><link linkend="recoderef">recode</link></para></listitem>
|
|
<listitem><para><link linkend="nice2ref">renice</link></para></listitem>
|
|
<listitem><para><link linkend="resetref">reset</link></para></listitem>
|
|
<listitem><para><link linkend="resizeref">resize</link></para></listitem>
|
|
<listitem><para><link linkend="restoreref">restore</link></para></listitem>
|
|
<listitem><para><link linkend="revref">rev</link></para></listitem>
|
|
<listitem><para><link linkend="rloginref">rlogin</link></para></listitem>
|
|
<listitem><para><link linkend="rmref">rm</link></para></listitem>
|
|
<listitem><para><link linkend="rmdirref">rmdir</link></para></listitem>
|
|
<listitem><para><link linkend="rmmodref">rmmod</link></para></listitem>
|
|
<listitem><para><link linkend="routeref">route</link></para></listitem>
|
|
<listitem><para><link linkend="rpmref">rpm</link></para></listitem>
|
|
<listitem><para><link linkend="rpm2cpioref">rpm2cpio</link></para></listitem>
|
|
<listitem><para><link linkend="rshref">rsh</link></para></listitem>
|
|
<listitem><para><link linkend="rsyncref">rsync</link></para></listitem>
|
|
<listitem><para><link linkend="runlevelref">runlevel</link></para></listitem>
|
|
<listitem><para><link linkend="runpartsref">run-parts</link></para></listitem>
|
|
<listitem><para><link linkend="rxref">rx</link></para></listitem>
|
|
<listitem><para><link linkend="rzref">rz</link></para></listitem>
|
|
<listitem><para><link linkend="sarref">sar</link></para></listitem>
|
|
<listitem><para><link linkend="scpref">scp</link></para></listitem>
|
|
<listitem><para><link linkend="scriptref">script</link></para></listitem>
|
|
<listitem><para><link linkend="sdiffref">sdiff</link></para></listitem>
|
|
<listitem><para><link linkend="sedref">sed</link></para></listitem>
|
|
<listitem><para><link linkend="seqref">seq</link></para></listitem>
|
|
<listitem><para><link linkend="serviceref">service</link></para></listitem>
|
|
<listitem><para><link linkend="setref">set</link></para></listitem>
|
|
<listitem><para><link linkend="setfaclref">setfacl</link></para></listitem>
|
|
<listitem><para><link linkend="setquotaref">setquota</link></para></listitem>
|
|
<listitem><para><link linkend="setserialref">setserial</link></para></listitem>
|
|
<listitem><para><link linkend="settermref">setterm</link></para></listitem>
|
|
<listitem><para><link linkend="sha1sumref">sha1sum</link></para></listitem>
|
|
<listitem><para><link linkend="sharref">shar</link></para></listitem>
|
|
<listitem><para><link linkend="shoptref">shopt</link></para></listitem>
|
|
<listitem><para><link linkend="shredref">shred</link></para></listitem>
|
|
<listitem><para><link linkend="shutdownref">shutdown</link></para></listitem>
|
|
<listitem><para><link linkend="sizeref">size</link></para></listitem>
|
|
<listitem><para><link linkend="nice2ref">skill</link></para></listitem>
|
|
<listitem><para><link linkend="sleepref">sleep</link></para></listitem>
|
|
<listitem><para><link linkend="slocateref">slocate</link></para></listitem>
|
|
<listitem><para><link linkend="nice2ref">snice</link></para></listitem>
|
|
<listitem><para><link linkend="sortref">sort</link></para></listitem>
|
|
<listitem><para><link linkend="sourceref">source</link></para></listitem>
|
|
<listitem><para><link linkend="soxref">sox</link></para></listitem>
|
|
<listitem><para><link linkend="splitref">split</link></para></listitem>
|
|
<listitem><para><link linkend="sqref">sq</link></para></listitem>
|
|
<listitem><para><link linkend="sshref">ssh</link></para></listitem>
|
|
<listitem><para><link linkend="statref">stat</link></para></listitem>
|
|
<listitem><para><link linkend="straceref">strace</link></para></listitem>
|
|
<listitem><para><link linkend="stringsref">strings</link></para></listitem>
|
|
<listitem><para><link linkend="stripref">strip</link></para></listitem>
|
|
<listitem><para><link linkend="sttyref">stty</link></para></listitem>
|
|
<listitem><para><link linkend="suref">su</link></para></listitem>
|
|
<listitem><para><link linkend="sudoref">sudo</link></para></listitem>
|
|
<listitem><para><link linkend="sumref">sum</link></para></listitem>
|
|
<listitem><para><link linkend="suspendref">suspend</link></para></listitem>
|
|
<listitem><para><link linkend="swaponref">swapoff</link></para></listitem>
|
|
<listitem><para><link linkend="swaponref">swapon</link></para></listitem>
|
|
<listitem><para><link linkend="rxref">sx</link></para></listitem>
|
|
<listitem><para><link linkend="syncref">sync</link></para></listitem>
|
|
<listitem><para><link linkend="rzref">sz</link></para></listitem>
|
|
<listitem><para><link linkend="catref">tac</link></para></listitem>
|
|
<listitem><para><link linkend="tailref">tail</link></para></listitem>
|
|
<listitem><para><link linkend="tarref">tar</link></para></listitem>
|
|
<listitem><para><link linkend="tblref">tbl</link></para></listitem>
|
|
<listitem><para><link linkend="tcpdumpref">tcpdump</link></para></listitem>
|
|
<listitem><para><link linkend="teeref">tee</link></para></listitem>
|
|
<listitem><para><link linkend="telinitref">telinit</link></para></listitem>
|
|
<listitem><para><link linkend="telnetref">telnet</link></para></listitem>
|
|
<listitem><para><link linkend="texref">Tex</link></para></listitem>
|
|
<listitem><para><link linkend="texexecref">texexec</link></para></listitem>
|
|
<listitem><para><link linkend="timref">time</link></para></listitem>
|
|
<listitem><para><link linkend="timesref">times</link></para></listitem>
|
|
<listitem><para><link linkend="tmpwatchref">tmpwatch</link></para></listitem>
|
|
<listitem><para><link linkend="topref">top</link></para></listitem>
|
|
<listitem><para><link linkend="touchref">touch</link></para></listitem>
|
|
<listitem><para><link linkend="tputref">tput</link></para></listitem>
|
|
<listitem><para><link linkend="trref">tr</link></para></listitem>
|
|
<listitem><para><link linkend="tracerouteref">traceroute</link></para></listitem>
|
|
<listitem><para><link linkend="trueref">true</link></para></listitem>
|
|
<listitem><para><link linkend="tsetref">tset</link></para></listitem>
|
|
<listitem><para><link linkend="tsortref">tsort</link></para></listitem>
|
|
<listitem><para><link linkend="ttyref">tty</link></para></listitem>
|
|
<listitem><para><link linkend="tune2fsref">tune2fs</link></para></listitem>
|
|
<listitem><para><link linkend="typeref">type</link></para></listitem>
|
|
<listitem><para><link linkend="declareref">typeset</link></para></listitem>
|
|
<listitem><para><link linkend="ulimitref">ulimit</link></para></listitem>
|
|
<listitem><para><link linkend="umaskref">umask</link></para></listitem>
|
|
<listitem><para><link linkend="umountref">umount</link></para></listitem>
|
|
<listitem><para><link linkend="unameref">uname</link></para></listitem>
|
|
<listitem><para><link linkend="unarcref">unarc</link></para></listitem>
|
|
<listitem><para><link linkend="unarcref">unarj</link></para></listitem>
|
|
<listitem><para><link linkend="uncompressref">uncompress</link></para></listitem>
|
|
<listitem><para><link linkend="expandref">unexpand</link></para></listitem>
|
|
<listitem><para><link linkend="uniqref">uniq</link></para></listitem>
|
|
<listitem><para><link linkend="unitsref">units</link></para></listitem>
|
|
<listitem><para><link linkend="lzmaref">unlzma</link></para></listitem>
|
|
<listitem><para><link linkend="unarcref">unrar</link></para></listitem>
|
|
<listitem><para><link linkend="unsetref">unset</link></para></listitem>
|
|
<listitem><para><link linkend="sqref">unsq</link></para></listitem>
|
|
<listitem><para><link linkend="zipref">unzip</link></para></listitem>
|
|
<listitem><para><link linkend="uptimeref">uptime</link></para></listitem>
|
|
<listitem><para><link linkend="lsusbref">usbmodules</link></para></listitem>
|
|
<listitem><para><link linkend="useraddref">useradd</link></para></listitem>
|
|
<listitem><para><link linkend="useraddref">userdel</link></para></listitem>
|
|
<listitem><para><link linkend="usermodref">usermod</link></para></listitem>
|
|
<listitem><para><link linkend="usersref">users</link></para></listitem>
|
|
<listitem><para><link linkend="usleepref">usleep</link></para></listitem>
|
|
<listitem><para><link linkend="uucpref">uucp</link></para></listitem>
|
|
<listitem><para><link linkend="uudecoderef">uudecode</link></para></listitem>
|
|
<listitem><para><link linkend="uuencoderef">uuencode</link></para></listitem>
|
|
<listitem><para><link linkend="uuxref">uux</link></para></listitem>
|
|
<listitem><para><link linkend="vacationref">vacation</link></para></listitem>
|
|
<listitem><para><link linkend="vdirref">vdir</link></para></listitem>
|
|
<listitem><para><link linkend="vmstatref">vmstat</link></para></listitem>
|
|
<listitem><para><link linkend="vrfyref">vrfy</link></para></listitem>
|
|
<listitem><para><link linkend="wref">w</link></para></listitem>
|
|
<listitem><para><link linkend="waitref">wait</link></para></listitem>
|
|
<listitem><para><link linkend="wallref">wall</link></para></listitem>
|
|
<listitem><para><link linkend="watchref">watch</link></para></listitem>
|
|
<listitem><para><link linkend="wcref">wc</link></para></listitem>
|
|
<listitem><para><link linkend="wgetref">wget</link></para></listitem>
|
|
<listitem><para><link linkend="whatisref">whatis</link></para></listitem>
|
|
<listitem><para><link linkend="whereisref">whereis</link></para></listitem>
|
|
<listitem><para><link linkend="whichref">which</link></para></listitem>
|
|
<listitem><para><link linkend="whoref">who</link></para></listitem>
|
|
<listitem><para><link linkend="whoamiref">whoami</link></para></listitem>
|
|
<listitem><para><link linkend="whoisref">whois</link></para></listitem>
|
|
<listitem><para><link linkend="writeref">write</link></para></listitem>
|
|
<listitem><para><link linkend="xargsref">xargs</link></para></listitem>
|
|
<listitem><para><link linkend="xrandrref">xrandr</link></para></listitem>
|
|
<listitem><para><link linkend="xzref">xz</link></para></listitem>
|
|
<listitem><para><link linkend="yaccref">yacc</link></para></listitem>
|
|
<listitem><para><link linkend="yesref">yes</link></para></listitem>
|
|
<listitem><para><link linkend="zcatref">zcat</link></para></listitem>
|
|
<listitem><para><link linkend="zdiffref">zdiff</link></para></listitem>
|
|
<listitem><para><link linkend="zdumpref">zdump</link></para></listitem>
|
|
<listitem><para><link linkend="zegrepref">zegrep</link></para></listitem>
|
|
<listitem><para><link linkend="zegrepref">zfgrep</link></para></listitem>
|
|
<listitem><para><link linkend="zegrepref">zgrep</link></para></listitem>
|
|
<listitem><para><link linkend="zipref">zip</link></para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
</partintro>
|
|
|
|
<chapter id="internal">
|
|
<title>Internal Commands and Builtins</title>
|
|
|
|
|
|
<indexterm>
|
|
<primary>builtin</primary>
|
|
</indexterm>
|
|
|
|
|
|
<para><anchor id="builtinref"/>A <firstterm>builtin</firstterm>
|
|
is a <command>command</command> contained within the Bash tool
|
|
set, literally <firstterm>built in</firstterm>. This is either
|
|
for performance reasons -- builtins execute faster than external
|
|
commands, which usually require <firstterm>forking off</firstterm>
|
|
<footnote><para>As Nathan Coulter points out, "while forking a
|
|
process is a low-cost operation, executing a new program in
|
|
the newly-forked child process adds more
|
|
overhead."</para></footnote>
|
|
a separate process -- or because a particular builtin needs
|
|
direct access to the shell internals.</para>
|
|
|
|
<para><anchor id="forkref"/></para>
|
|
|
|
<sidebar>
|
|
|
|
<para><anchor id="parentref"/>When a command or
|
|
the shell itself initiates (or
|
|
<firstterm>spawns</firstterm>) a new
|
|
subprocess to carry out a task, this is called
|
|
<firstterm>forking</firstterm>. This new process
|
|
is the <firstterm>child</firstterm>, and the process
|
|
that <firstterm>forked</firstterm> it off is the
|
|
<firstterm>parent</firstterm>. While the <firstterm>child
|
|
process</firstterm> is doing its work, the
|
|
<firstterm>parent process</firstterm> is still
|
|
executing.</para>
|
|
|
|
<para>Note that while a <firstterm>parent
|
|
process</firstterm> gets the <firstterm>process
|
|
ID</firstterm> of the <firstterm>child
|
|
process</firstterm>, and can thus pass arguments to it,
|
|
<emphasis>the reverse is not true</emphasis>. <link
|
|
linkend="parchildprobref">This can create problems
|
|
that are subtle and hard to track down.</link></para>
|
|
|
|
<example id="spawnscr">
|
|
<title>A script that spawns multiple instances of itself</title>
|
|
<programlisting>&spawnscr;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="bltinfrk"/></para>
|
|
<para>Generally, a Bash <firstterm>builtin</firstterm>
|
|
does not fork a subprocess when it executes within
|
|
a script. An external system command or filter in
|
|
a script usually <emphasis>will</emphasis> fork a
|
|
subprocess.</para>
|
|
|
|
</sidebar>
|
|
|
|
|
|
<para>A builtin may be a synonym to a system command of the same
|
|
name, but Bash reimplements it internally. For example,
|
|
the Bash <command>echo</command> command is not the same as
|
|
<filename>/bin/echo</filename>, although their behavior is
|
|
almost identical.
|
|
<programlisting>#!/bin/bash
|
|
|
|
echo "This line uses the \"echo\" builtin."
|
|
/bin/echo "This line uses the /bin/echo system command."</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="keywordref"/>A <firstterm>keyword</firstterm>
|
|
is a <firstterm>reserved</firstterm> word, token or
|
|
operator. Keywords have a special meaning to the shell,
|
|
and indeed are the building blocks of the shell's
|
|
syntax. As examples, <firstterm>for</firstterm>,
|
|
<firstterm>while</firstterm>, <firstterm>do</firstterm>,
|
|
and <firstterm>!</firstterm> are keywords. Similar to a <link
|
|
linkend="builtinref">builtin</link>, a keyword is hard-coded into
|
|
Bash, but unlike a <firstterm>builtin</firstterm>, a keyword is
|
|
not in itself a command, but <emphasis>a subunit of a command
|
|
construct</emphasis>.
|
|
|
|
<footnote><para>An exception to this is the <link
|
|
linkend="timref">time</link> command, listed in the
|
|
official Bash documentation as a keyword (<quote>reserved
|
|
word</quote>).</para></footnote>
|
|
|
|
</para>
|
|
|
|
|
|
<variablelist id="intio">
|
|
<title><anchor id="intio1"/>I/O</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="echoref"/><command>echo</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>echo</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>echo</secondary>
|
|
</indexterm>
|
|
<para>prints (to <filename>stdout</filename>) an expression
|
|
or variable (see <xref linkend="ex9"/>).
|
|
<programlisting>echo Hello
|
|
echo $a</programlisting></para>
|
|
|
|
<para>An <command>echo</command> requires the
|
|
<option>-e</option> option to print escaped characters. See
|
|
<xref linkend="escaped"/>.</para>
|
|
|
|
<para>Normally, each <command>echo</command> command prints
|
|
a terminal newline, but the <option>-n</option> option
|
|
suppresses this.</para>
|
|
|
|
<para><anchor id="echogrepref"/></para>
|
|
<note>
|
|
<para>An <command>echo</command> can be used to feed a
|
|
sequence of commands down a pipe.</para>
|
|
<para><programlisting>if echo "$VAR" | grep -q txt # if [[ $VAR = *txt* ]]
|
|
then
|
|
echo "$VAR contains the substring sequence \"txt\""
|
|
fi</programlisting></para>
|
|
</note>
|
|
|
|
<para><anchor id="echocs"/></para>
|
|
<note><para>An <command>echo</command>, in combination with
|
|
<link linkend="commandsubref">command substitution</link>
|
|
can set a variable.</para> <para><userinput>a=`echo
|
|
"HELLO" | tr A-Z a-z`</userinput></para>
|
|
<para>See also <xref linkend="lowercase"/>, <xref
|
|
linkend="ex57"/>, <xref linkend="monthlypmt"/>, and <xref
|
|
linkend="base"/>.</para></note>
|
|
|
|
|
|
<para>Be aware that <command>echo `command`</command>
|
|
deletes any linefeeds that the output
|
|
of <replaceable>command</replaceable>
|
|
generates.</para>
|
|
|
|
<para>The <link linkend="ifsref">$IFS</link> (internal field
|
|
separator) variable normally contains
|
|
<token>\n</token> (linefeed) as one of its set of
|
|
<link linkend="whitespaceref">whitespace</link>
|
|
characters. Bash therefore splits the output of
|
|
<replaceable>command</replaceable> at linefeeds
|
|
into arguments to <command>echo</command>. Then
|
|
<command>echo</command> outputs these arguments,
|
|
separated by spaces.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>ls -l /usr/share/apps/kjezz/sounds</userinput>
|
|
<computeroutput>-rw-r--r-- 1 root root 1407 Nov 7 2000 reflect.au
|
|
-rw-r--r-- 1 root root 362 Nov 7 2000 seconds.au</computeroutput>
|
|
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo `ls -l /usr/share/apps/kjezz/sounds`</userinput>
|
|
<computeroutput>total 40 -rw-r--r-- 1 root root 716 Nov 7 2000 reflect.au -rw-r--r-- 1 root root ...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>
|
|
So, how can we embed a linefeed within an
|
|
<link linkend="echoref">echoed</link> character string?
|
|
|
|
<programlisting># Embedding a linefeed?
|
|
echo "Why doesn't this string \n split on two lines?"
|
|
# Doesn't split.
|
|
|
|
# Let's try something else.
|
|
|
|
echo
|
|
|
|
echo $"A line of text containing
|
|
a linefeed."
|
|
# Prints as two distinct lines (embedded linefeed).
|
|
# But, is the "$" variable prefix really necessary?
|
|
|
|
echo
|
|
|
|
echo "This string splits
|
|
on two lines."
|
|
# No, the "$" is not needed.
|
|
|
|
echo
|
|
echo "---------------"
|
|
echo
|
|
|
|
echo -n $"Another line of text containing
|
|
a linefeed."
|
|
# Prints as two distinct lines (embedded linefeed).
|
|
# Even the -n option fails to suppress the linefeed here.
|
|
|
|
echo
|
|
echo
|
|
echo "---------------"
|
|
echo
|
|
echo
|
|
|
|
# However, the following doesn't work as expected.
|
|
# Why not? Hint: Assignment to a variable.
|
|
string1=$"Yet another line of text containing
|
|
a linefeed (maybe)."
|
|
|
|
echo $string1
|
|
# Yet another line of text containing a linefeed (maybe).
|
|
# ^
|
|
# Linefeed becomes a space.
|
|
|
|
# Thanks, Steve Parker, for pointing this out.</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="binecho"/></para>
|
|
<note>
|
|
<para>This command is a shell builtin, and not the same as
|
|
<filename>/bin/echo</filename>, although its behavior is
|
|
similar.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>type -a echo</userinput>
|
|
<computeroutput>echo is a shell builtin
|
|
echo is /bin/echo</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="printfref"/><command>printf</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>printf</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>printf</secondary>
|
|
</indexterm>
|
|
<para>The <command>printf</command>, formatted print, command is an
|
|
enhanced <command>echo</command>. It is a limited variant
|
|
of the <firstterm>C</firstterm> language
|
|
<function>printf()</function> library function, and its
|
|
syntax is somewhat different.</para>
|
|
<cmdsynopsis>
|
|
<command>printf</command>
|
|
<arg choice="plain" rep="repeat"><replaceable>format-string</replaceable></arg>
|
|
<arg choice="plain" rep="repeat"><replaceable>parameter</replaceable></arg>
|
|
</cmdsynopsis>
|
|
|
|
<para>This is the Bash <firstterm>builtin</firstterm> version
|
|
of the <filename>/bin/printf</filename> or
|
|
<filename>/usr/bin/printf</filename> command. See the
|
|
<command>printf</command> <link
|
|
linkend="manref">manpage</link> (of the system command)
|
|
for in-depth coverage.</para>
|
|
|
|
<caution><para>Older versions of Bash may not support
|
|
<command>printf</command>.</para></caution>
|
|
|
|
<example id="ex47">
|
|
<title><firstterm>printf</firstterm> in action</title>
|
|
<programlisting>&ex47;</programlisting>
|
|
</example>
|
|
|
|
<para>Formatting error messages is a useful application of
|
|
<command>printf</command></para>
|
|
|
|
<para>
|
|
<programlisting>E_BADDIR=85
|
|
|
|
var=nonexistent_directory
|
|
|
|
error()
|
|
{
|
|
printf "$@" >&2
|
|
# Formats positional params passed, and sends them to stderr.
|
|
echo
|
|
exit $E_BADDIR
|
|
}
|
|
|
|
cd $var || error $"Can't cd to %s." "$var"
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<para>See also <xref linkend="progressbar"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="readref"/><command>read</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>read</primary>
|
|
</indexterm> <indexterm>
|
|
<primary>command</primary> <secondary>read</secondary>
|
|
</indexterm>
|
|
<para><quote>Reads</quote> the value
|
|
of a variable from <filename>stdin</filename>, that
|
|
is, interactively fetches input from the keyboard. The
|
|
<option>-a</option> option lets <command>read</command>
|
|
get array variables (see <xref linkend="ex67"/>).</para>
|
|
|
|
<example id="ex36">
|
|
<title>Variable assignment, using <firstterm>read</firstterm></title>
|
|
<programlisting>&ex36;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>A <command>read</command> without an associated variable
|
|
assigns its input to the dedicated variable <link
|
|
linkend="replyref">$REPLY</link>.</para>
|
|
|
|
<example id="readnovar">
|
|
<title>What happens when <firstterm>read</firstterm> has no
|
|
variable</title>
|
|
<programlisting>&readnovar;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>Normally, inputting a <userinput>\</userinput>
|
|
suppresses a newline during input to
|
|
a <command>read</command>. The <option>-r</option>
|
|
option causes an inputted <userinput>\</userinput> to be
|
|
interpreted literally.</para>
|
|
|
|
<example id="readr">
|
|
<title>Multi-line input to <firstterm>read</firstterm></title>
|
|
<programlisting>&readr;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="readoptions"/></para>
|
|
<para>The <command>read</command> command has some interesting
|
|
options that permit echoing a prompt and even reading keystrokes
|
|
without hitting <keycap>ENTER</keycap>.</para>
|
|
|
|
<para><programlisting># Read a keypress without hitting ENTER.
|
|
|
|
read -s -n1 -p "Hit a key " keypress
|
|
echo; echo "Keypress was "\"$keypress\""."
|
|
|
|
# -s option means do not echo input.
|
|
# -n N option means accept only N characters of input.
|
|
# -p option means echo the following prompt before reading input.
|
|
|
|
# Using these options is tricky, since they need to be in the correct order.</programlisting></para>
|
|
|
|
|
|
<para><anchor id="readarrow"/></para>
|
|
<para>The <option>-n</option> option to <command>read</command>
|
|
also allows detection of the <keycap>arrow keys</keycap>
|
|
and certain of the other unusual keys.</para>
|
|
|
|
<example id="arrowdetect">
|
|
<title>Detecting the arrow keys</title>
|
|
<programlisting>&arrowdetect;</programlisting>
|
|
</example>
|
|
|
|
<note><para>The <option>-n</option> option to <command>read</command>
|
|
will not detect the <keycap>ENTER</keycap> (newline)
|
|
key.</para></note>
|
|
|
|
|
|
<para><anchor id="readtimed"/></para>
|
|
<para>The <option>-t</option> option to <command>read</command>
|
|
permits timed input (see <xref linkend="tout"/> and <xref
|
|
linkend="qky"/>).</para>
|
|
|
|
<para><anchor id="readfd"/>The <option>-u</option> option
|
|
takes the <link linkend="fdref">file descriptor</link>
|
|
of the target file.</para>
|
|
|
|
<para><anchor id="readredir0"/></para>
|
|
<para>The <command>read</command> command may also
|
|
<quote>read</quote> its variable value from a file
|
|
<link linkend="ioredirref">redirected</link> to
|
|
<filename>stdin</filename>. If the file contains
|
|
more than one line, only the first line is assigned
|
|
to the variable. If <command>read</command>
|
|
has more than one parameter, then each of
|
|
these variables gets assigned a successive <link
|
|
linkend="whitespaceref">whitespace-delineated</link>
|
|
string. Caution!</para>
|
|
|
|
<example id="readredir">
|
|
<title>Using <firstterm>read</firstterm> with
|
|
<link linkend="ioredirref">file redirection</link></title>
|
|
<programlisting>&readredir;</programlisting>
|
|
</example>
|
|
|
|
<note>
|
|
|
|
<para><anchor id="pipereadref0"/></para>
|
|
<para><link linkend="piperef">Piping</link> output
|
|
to a <firstterm>read</firstterm>, using <link
|
|
linkend="echoref">echo</link> to set variables <link
|
|
linkend="badread0">will fail</link>.</para>
|
|
|
|
<para><anchor id="readpiperef"/>Yet, piping the output of <link
|
|
linkend="catref">cat</link> <emphasis>seems</emphasis> to
|
|
work.</para>
|
|
|
|
<para><anchor id="whilereadref"/></para>
|
|
|
|
<para><programlisting>cat file1 file2 |
|
|
while read line
|
|
do
|
|
echo $line
|
|
done</programlisting></para>
|
|
|
|
|
|
<para>However, as Bjön Eriksson shows:</para>
|
|
|
|
<example id="readpipe">
|
|
<title>Problems reading from a pipe</title>
|
|
<programlisting>&readpipe;</programlisting>
|
|
</example>
|
|
|
|
<para>The <firstterm>gendiff</firstterm> script, usually
|
|
found in <filename>/usr/bin</filename> on
|
|
many Linux distros, pipes the output of <link
|
|
linkend="findref">find</link> to a <firstterm>while
|
|
read</firstterm> construct.
|
|
|
|
<programlisting>find $1 \( -name "*$2" -o -name ".*$2" \) -print |
|
|
while read f; do
|
|
. . .</programlisting>
|
|
</para>
|
|
|
|
</note>
|
|
|
|
<tip>
|
|
<para>It is possible to <firstterm>paste</firstterm> text into
|
|
the input field of a <firstterm>read</firstterm> (but
|
|
<emphasis>not</emphasis> multiple lines!). See <xref
|
|
linkend="padsw"/>.</para>
|
|
</tip>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="intfilesystem">
|
|
<title><anchor id="intfilesystem1"/>Filesystem</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cdref"/><command>cd</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>cd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cd</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<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>
|
|
<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>
|
|
<listitem>
|
|
<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>
|
|
<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 <link
|
|
linkend="stackdefref">stack</link> 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 (to the <firstterm>top</firstterm> of the 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 the directory now at the <firstterm>top</firstterm> of
|
|
the stack.</para>
|
|
|
|
<para><anchor id="dirsref"/><command>dirs</command> lists
|
|
the contents of the directory stack (compare this
|
|
with the <link linkend="dirstackref">$DIRSTACK</link>
|
|
variable). A successful <command>pushd</command>
|
|
or <command>popd</command> will automatically invoke
|
|
<command>dirs</command>.</para>
|
|
|
|
|
|
<para>Scripts that require various changes to the current
|
|
working directory without hard-coding the directory name
|
|
changes can make good use of these commands. Note that
|
|
the implicit <varname>$DIRSTACK</varname> array variable,
|
|
accessible from within a script, holds the contents of
|
|
the directory stack.
|
|
</para>
|
|
|
|
<example id="ex37">
|
|
<title>Changing the current working directory</title>
|
|
<programlisting>&ex37;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="intvar">
|
|
<title><anchor id="intvar1"/>Variables</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="letref"/><command>let</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>let</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>let</secondary>
|
|
</indexterm>
|
|
<para>The <command>let</command> command carries out
|
|
<firstterm>arithmetic</firstterm> operations on variables.
|
|
|
|
<footnote><para>Note that <firstterm>let</firstterm>
|
|
<link linkend="letbad">cannot be used
|
|
for setting <firstterm>string</firstterm>
|
|
variables.</link></para></footnote>
|
|
|
|
In many cases, it functions as a less complex version
|
|
of <link linkend="exprref">expr</link>.</para>
|
|
|
|
<example id="ex46">
|
|
<title>Letting <firstterm>let</firstterm> do arithmetic.</title>
|
|
<programlisting>&ex46;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="exitvalanomaly02"/></para>
|
|
|
|
<caution>
|
|
<para>The <firstterm>let</firstterm> command can,
|
|
in certain contexts, return a surprising <link
|
|
linkend="exitstatusref">exit status</link>.</para>
|
|
<para><programlisting># Evgeniy Ivanov points out:
|
|
|
|
var=0
|
|
echo $? # 0
|
|
# As expected.
|
|
|
|
let var++
|
|
echo $? # 1
|
|
# The command was successful, so why isn't $?=0 ???
|
|
# Anomaly!
|
|
|
|
let var++
|
|
echo $? # 0
|
|
# As expected.
|
|
|
|
|
|
# Likewise . . .
|
|
|
|
let var=0
|
|
echo $? # 1
|
|
# The command was successful, so why isn't $?=0 ???
|
|
|
|
# However, as Jeff Gorak points out,
|
|
#+ this is part of the design spec for 'let' . . .
|
|
# "If the last ARG evaluates to 0, let returns 1;
|
|
# let returns 0 otherwise." ['help let']</programlisting></para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="evalref"/><command>eval</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>eval</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>eval</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>eval arg1 [arg2] ... [argN]</userinput></para>
|
|
|
|
<para>Combines the arguments in an expression or list of
|
|
expressions and <replaceable>evaluates</replaceable> them.
|
|
Any variables within the expression are expanded. The
|
|
net result is to <command>convert a string into a
|
|
command</command>.</para>
|
|
|
|
<tip><para>The <command>eval</command> command can be used for
|
|
code generation from the command-line or within a script.
|
|
</para></tip>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>command_string="ps ax"</userinput>
|
|
<prompt>bash$ </prompt><userinput>process="ps ax"</userinput>
|
|
<prompt>bash$ </prompt><userinput>eval "$command_string" | grep "$process"</userinput>
|
|
<computeroutput>26973 pts/3 R+ 0:00 grep --color ps ax
|
|
26974 pts/3 R+ 0:00 ps ax</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="evalforced"/></para>
|
|
<para>Each invocation of <firstterm>eval</firstterm> forces
|
|
a re-<emphasis>evaluation</emphasis> of its arguments.
|
|
<programlisting>a='$b'
|
|
b='$c'
|
|
c=d
|
|
|
|
echo $a # $b
|
|
# First level.
|
|
eval echo $a # $c
|
|
# Second level.
|
|
eval eval echo $a # d
|
|
# Third level.
|
|
|
|
# Thank you, E. Choroba.</programlisting></para>
|
|
|
|
|
|
<para><anchor id="evaleff"/></para>
|
|
<example id="ex43">
|
|
<title>Showing the effect of <firstterm>eval</firstterm></title>
|
|
<programlisting>&ex43;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="arrchoice0"/></para>
|
|
<example id="arrchoice">
|
|
<title>Using <firstterm>eval</firstterm> to select
|
|
among variables</title>
|
|
<programlisting>&arrchoice;</programlisting>
|
|
</example>
|
|
|
|
<example id="echoparams">
|
|
<title><firstterm>Echoing</firstterm> the
|
|
<firstterm>command-line parameters</firstterm></title>
|
|
<programlisting>&echoparams;</programlisting>
|
|
</example>
|
|
|
|
<example id="ex44">
|
|
<title>Forcing a log-off</title>
|
|
<programlisting>&ex44;</programlisting>
|
|
</example>
|
|
|
|
<example id="rot14">
|
|
<title>A version of <firstterm>rot13</firstterm></title>
|
|
<programlisting>&rot14;</programlisting>
|
|
</example>
|
|
|
|
<para>Here is another example of using
|
|
<firstterm>eval</firstterm> to
|
|
<emphasis>evaluate</emphasis> a complex expression,
|
|
this one from an earlier version of YongYe's <ulink
|
|
url="https://github.com/yongye/shell/blob/master/Tetris_Game.sh">Tetris
|
|
game script</ulink>.</para>
|
|
|
|
<para>
|
|
<programlisting>eval ${1}+=\"${x} ${y} \"</programlisting>
|
|
</para>
|
|
|
|
<para><xref linkend="samorse"/> uses
|
|
<firstterm>eval</firstterm> to convert <link
|
|
linkend="arrayref">array</link> elements into a command
|
|
list.</para>
|
|
|
|
<para>The <firstterm>eval</firstterm> command occurs
|
|
in the older version of <link linkend="ivrref">indirect
|
|
referencing</link>.
|
|
<programlisting>eval var=\$$var</programlisting>
|
|
</para>
|
|
|
|
<tip><para>The <firstterm>eval</firstterm> command can
|
|
be used to <link linkend="braceexpref3">parameterize
|
|
<firstterm>brace expansion</firstterm></link>.</para></tip>
|
|
|
|
|
|
<para><anchor id="evalrisk"/></para>
|
|
<caution><para>The <command>eval</command> command can be
|
|
risky, and normally should be avoided when there
|
|
exists a reasonable alternative. An <userinput>eval
|
|
$COMMANDS</userinput> executes the contents of
|
|
<replaceable>COMMANDS</replaceable>, which may
|
|
contain such unpleasant surprises as <command>rm -rf
|
|
*</command>. Running an <command>eval</command> on
|
|
unfamiliar code written by persons unknown is living
|
|
dangerously.</para></caution>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="setref"/><command>set</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>set</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>set</secondary>
|
|
</indexterm>
|
|
<para>The <command>set</command> command changes
|
|
the value of internal script variables/options. One use for
|
|
this is to toggle <link linkend="optionsref">option
|
|
flags</link> which help determine the behavior of the
|
|
script. Another application for it is to reset the <link
|
|
linkend="posparamref">positional parameters</link> that
|
|
a script sees as the result of a command (<userinput>set
|
|
`command`</userinput>). The script can then parse the
|
|
<link linkend="fieldref">fields</link> of the command
|
|
output.</para>
|
|
|
|
<example id="ex34">
|
|
<title>Using <firstterm>set</firstterm> with positional
|
|
parameters</title>
|
|
<programlisting>&ex34;</programlisting>
|
|
</example>
|
|
|
|
<para>More fun with positional parameters.</para>
|
|
|
|
<example id="revposparams">
|
|
<title>Reversing the positional parameters</title>
|
|
<programlisting>&revposparams;</programlisting>
|
|
</example>
|
|
|
|
<para>Invoking <command>set</command> without any options or
|
|
arguments simply lists all the <link
|
|
linkend="envref">environmental</link> and other variables
|
|
that have been initialized.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>set</userinput>
|
|
<computeroutput>AUTHORCOPY=/home/bozo/posts
|
|
BASH=/bin/bash
|
|
BASH_VERSION=$'2.05.8(1)-release'
|
|
...
|
|
XAUTHORITY=/home/bozo/.Xauthority
|
|
_=/etc/bashrc
|
|
variable22=abc
|
|
variable23=xzy</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<para>Using <command>set</command> with the <option>--</option>
|
|
option explicitly assigns the contents of a variable to
|
|
the positional parameters. If no variable follows the
|
|
<option>--</option> it <firstterm>unsets</firstterm>
|
|
the positional parameters.</para>
|
|
|
|
<example id="setpos">
|
|
<title>Reassigning the positional parameters</title>
|
|
<programlisting>&setpos;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="ex22a"/> and <xref linkend="ex33a"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="unsetref"/><command>unset</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>unset</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>unset</secondary>
|
|
</indexterm>
|
|
<para>The <command>unset</command> command deletes a
|
|
shell variable, effectively setting it to
|
|
<firstterm>null</firstterm>. Note that this command does
|
|
not affect positional parameters.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>unset PATH</userinput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $PATH</userinput>
|
|
<computeroutput>
|
|
|
|
|
|
</computeroutput>
|
|
<prompt>bash$ </prompt></screen>
|
|
</para>
|
|
|
|
<example id="uns">
|
|
<title><quote>Unsetting</quote> a variable</title>
|
|
<programlisting>&uns;</programlisting>
|
|
</example>
|
|
|
|
<note><para>In most contexts, an <firstterm>undeclared</firstterm>
|
|
variable and one that has been <firstterm>unset</firstterm>
|
|
are equivalent. However, the <link linkend="unddr">
|
|
${parameter:-default}</link> parameter substitution
|
|
construct can distinguish between the two.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="exportref"/><command>export</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>export</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>export</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="exportref2"/></para>
|
|
<para>The <command>export</command>
|
|
|
|
<footnote><para>To <firstterm>Export</firstterm>
|
|
information is to make it available in a more general context.
|
|
See also <link
|
|
linkend="scoperef">scope</link>.</para></footnote>
|
|
|
|
command makes available variables to all child processes
|
|
of the running script or shell. One important use
|
|
of the <command>export</command> command is in <link
|
|
linkend="filesref1">startup files</link>, to initialize
|
|
and make accessible <link linkend="envref">environmental
|
|
variables</link> to subsequent user processes.</para>
|
|
|
|
<caution><para>Unfortunately, <link linkend="parchildprobref">
|
|
there is no way to export variables back to the parent
|
|
process</link>, to the process that called or invoked the
|
|
script or shell.</para></caution>
|
|
|
|
|
|
<para><anchor id="exportawk"/></para>
|
|
<example id="coltotaler3">
|
|
<title>Using <firstterm>export</firstterm> to pass a variable to an
|
|
embedded <firstterm>awk</firstterm> script</title>
|
|
<programlisting>&coltotaler3;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<tip>
|
|
|
|
<para>It is possible to initialize and export
|
|
variables in the same operation, as in <command>export
|
|
var1=xxx</command>.</para>
|
|
|
|
<para>However, as Greg Keraunen points out, in certain
|
|
situations this may have a different effect than
|
|
setting a variable, then exporting it.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>export var=(a b); echo ${var[0]}</userinput>
|
|
<computeroutput>(a b)</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>var=(a b); export var; echo ${var[0]}</userinput>
|
|
<computeroutput>a</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
</tip>
|
|
|
|
<note>
|
|
<para>A variable to be exported may require special
|
|
treatment. See <xref linkend="bashprof"/>.</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="declare2ref"/><command>declare</command></term>
|
|
<term><command>typeset</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <link linkend="declareref">declare</link> and
|
|
<link linkend="declareref">typeset</link> commands specify
|
|
and/or restrict properties of variables.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="readonlyref"/><command>readonly</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>readonly</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>readonly</secondary>
|
|
</indexterm>
|
|
<para>Same as <link linkend="declareref">declare -r</link>,
|
|
sets a variable as read-only, or, in effect, as a
|
|
constant. Attempts to change the variable fail with
|
|
an error message. This is the shell analog of the
|
|
<firstterm>C</firstterm> language <command>const</command>
|
|
type qualifier.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="getoptsx"/><command>getopts</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>This powerful tool parses command-line arguments passed
|
|
to the script. This is the Bash analog of the <link
|
|
linkend="getopty">getopt</link> external command and the
|
|
<firstterm>getopt</firstterm> library function familiar to
|
|
<firstterm>C</firstterm> programmers. It permits passing
|
|
and concatenating multiple options
|
|
|
|
<footnote><para>An <firstterm>option</firstterm> is an
|
|
argument that acts as a flag, switching script behaviors
|
|
on or off. The argument associated with a particular
|
|
option indicates the behavior that the option (flag)
|
|
switches on or off.</para></footnote>
|
|
|
|
and associated arguments to a script (for
|
|
example <userinput>scriptname -abc -e
|
|
/usr/local</userinput>).</para>
|
|
|
|
<para><anchor id="getoptsopt"/></para>
|
|
<para>The <command>getopts</command> construct uses two implicit
|
|
variables. <varname>$OPTIND</varname> is the argument
|
|
pointer (<wordasword>OPTion INDex</wordasword>)
|
|
and <varname>$OPTARG</varname> (<wordasword>OPTion
|
|
ARGument</wordasword>) the (optional) argument attached
|
|
to an option. A colon following the option name in the
|
|
declaration tags that option as having an associated
|
|
argument.</para>
|
|
|
|
<para>A <command>getopts</command> construct usually comes
|
|
packaged in a <link linkend="whileloopref">while
|
|
loop</link>, which processes the options and
|
|
arguments one at a time, then increments the implicit
|
|
<varname>$OPTIND</varname> variable to point to the
|
|
next.</para>
|
|
|
|
<note>
|
|
<para>
|
|
<orderedlist>
|
|
<listitem>
|
|
|
|
<para>The arguments passed from the command-line to
|
|
the script must be preceded by a
|
|
dash (<option>-</option>). It is the
|
|
prefixed <option>-</option> that lets
|
|
<command>getopts</command> recognize command-line
|
|
arguments as <firstterm>options</firstterm>.
|
|
In fact, <command>getopts</command> will not process
|
|
arguments without the prefixed <option>-</option>,
|
|
and will terminate option processing at the first
|
|
argument encountered lacking them.</para>
|
|
|
|
</listitem>
|
|
<listitem><para>The <command>getopts</command> template
|
|
differs slightly from the standard <link
|
|
linkend="whileloopref">while loop</link>, in that
|
|
it lacks condition brackets.</para>
|
|
</listitem>
|
|
<listitem>
|
|
|
|
<para>The <command>getopts</command> construct is a highly
|
|
functional replacement for the traditional
|
|
<link linkend="getopty">getopt</link> external
|
|
command.</para>
|
|
|
|
</listitem>
|
|
</orderedlist>
|
|
</para>
|
|
</note>
|
|
|
|
<para><programlisting>
|
|
while getopts ":abcde:fg" Option
|
|
# Initial declaration.
|
|
# a, b, c, d, e, f, and g are the options (flags) expected.
|
|
# The : after option 'e' shows it will have an argument passed with it.
|
|
do
|
|
case $Option in
|
|
a ) # Do something with variable 'a'.
|
|
b ) # Do something with variable 'b'.
|
|
...
|
|
e) # Do something with 'e', and also with $OPTARG,
|
|
# which is the associated argument passed with option 'e'.
|
|
...
|
|
g ) # Do something with variable 'g'.
|
|
esac
|
|
done
|
|
shift $(($OPTIND - 1))
|
|
# Move argument pointer to next.
|
|
|
|
# All this is not nearly as complicated as it looks <grin>.</programlisting></para>
|
|
|
|
<example id="ex33">
|
|
<title>Using <firstterm>getopts</firstterm> to read the
|
|
options/arguments passed to a script</title>
|
|
<programlisting>&ex33;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="intscrbeh">
|
|
<title><anchor id="intscrbeh1"/>Script Behavior</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sourceref"/><command>source</command></term>
|
|
<term><token>.</token> (<link linkend="dotref">dot</link> command)</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>source</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>source</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>.</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>.</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<para>This command, when invoked from the command-line,
|
|
executes a script. Within a script, a
|
|
<userinput>source file-name</userinput>
|
|
loads the file <filename>file-name</filename>.
|
|
<firstterm>Sourcing</firstterm> a file (dot-command)
|
|
<firstterm>imports</firstterm>
|
|
code into the script, appending to the script (same effect
|
|
as the <userinput>#include</userinput> directive in a
|
|
<firstterm>C</firstterm> program). The net result is the
|
|
same as if the <quote>sourced</quote> lines of code were
|
|
physically present in the body of the script. This is useful
|
|
in situations when multiple scripts use a common data file
|
|
or function library.</para>
|
|
|
|
<example id="ex38">
|
|
<title><quote>Including</quote> a data file</title>
|
|
<programlisting>&ex38;</programlisting>
|
|
|
|
<para>File <filename>data-file</filename> for <xref
|
|
linkend="ex38"/>, above. Must be present in same
|
|
directory.</para>
|
|
|
|
<programlisting>&ex38bis;</programlisting>
|
|
</example>
|
|
|
|
<para>If the <firstterm>sourced</firstterm> file is itself
|
|
an executable script, then it will run, then return
|
|
control to the script that called it. A
|
|
<firstterm>sourced</firstterm> executable script may use a
|
|
<link linkend="returnref">return</link> for this
|
|
purpose.</para>
|
|
|
|
<para><anchor id="sourceparams"/></para>
|
|
<para>
|
|
Arguments may be (optionally) passed to the
|
|
<firstterm>sourced</firstterm> file as <link
|
|
linkend="posparamref1">positional parameters</link>.
|
|
<programlisting>source $filename $arg1 arg2</programlisting>
|
|
</para>
|
|
|
|
|
|
|
|
<para>It is even possible for a script to
|
|
<firstterm>source</firstterm> itself, though this does not
|
|
seem to have any practical applications.</para>
|
|
|
|
<example id="selfsource">
|
|
<title>A (useless) script that sources itself</title>
|
|
<programlisting>&selfsource;</programlisting>
|
|
</example>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="exitref"/><command>exit</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>exit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>exit</secondary>
|
|
</indexterm>
|
|
<para>Unconditionally terminates a script.
|
|
<footnote><para>Technically, an
|
|
<command>exit</command> only terminates the
|
|
process (or shell) in which it is running,
|
|
<emphasis>not</emphasis> the <firstterm>parent
|
|
process</firstterm>.</para></footnote>
|
|
The <command>exit</command> command may optionally take an
|
|
integer argument, which is returned to the shell as
|
|
the <link linkend="exitstatusref">exit status</link>
|
|
of the script. It is good practice to end all but the
|
|
simplest scripts with an <userinput>exit 0</userinput>,
|
|
indicating a successful run.</para>
|
|
|
|
<note><para>If a script terminates with an <command>exit</command>
|
|
lacking an argument, the exit status of the script is the exit
|
|
status of the last command executed in the script, not counting
|
|
the <command>exit</command>. This is equivalent to an
|
|
<command>exit $?</command>.</para></note>
|
|
|
|
<note><para>An <command>exit</command> command may also be used to
|
|
terminate a <link
|
|
linkend="subshellsref">subshell</link>.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="execref"/><command>exec</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>exec</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>exec</secondary>
|
|
</indexterm>
|
|
|
|
<para>
|
|
This shell builtin replaces the current process with
|
|
a specified command. Normally, when the shell encounters
|
|
a command, it <link linkend="forkref">forks off</link> a
|
|
child process to actually execute the command. Using the
|
|
<command>exec</command> builtin, the shell does not fork,
|
|
and the command <firstterm>exec</firstterm>'ed replaces
|
|
the shell. When used in a script, therefore, it forces an
|
|
exit from the script when the <command>exec</command>'ed
|
|
command terminates.
|
|
<footnote><para>Unless the <command>exec</command> is used
|
|
to <link linkend="usingexecref">reassign file
|
|
descriptors</link>.</para></footnote>
|
|
</para>
|
|
|
|
<example id="ex54">
|
|
<title>Effects of <firstterm>exec</firstterm></title>
|
|
<programlisting>&ex54;</programlisting>
|
|
</example>
|
|
|
|
<example id="selfexec">
|
|
<title>A script that <firstterm>exec's</firstterm> itself</title>
|
|
<programlisting>&selfexec;</programlisting>
|
|
</example>
|
|
|
|
<para>An <command>exec</command> also serves to <link
|
|
linkend="usingexecref">reassign
|
|
file descriptors</link>. For example, <userinput>exec
|
|
<zzz-file</userinput> replaces <filename>stdin</filename>
|
|
with the file <filename>zzz-file</filename>.</para>
|
|
|
|
<note><para>The <option>-exec</option> option to
|
|
<link linkend="findref">find</link> is
|
|
<replaceable>not</replaceable> the same as the
|
|
<command>exec</command> shell builtin.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="shoptref"/><command>shopt</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>shopt</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>shopt</secondary>
|
|
</indexterm>
|
|
<para>This command permits changing <firstterm>shell
|
|
options</firstterm> on the fly (see <xref linkend="al"/>
|
|
and <xref linkend="unal"/>). It often appears in the Bash
|
|
<link linkend="filesref1">startup files</link>, but also has
|
|
its uses in scripts. Needs <link linkend="bash2ref">version
|
|
2</link> or later of Bash.</para>
|
|
|
|
<para><programlisting>shopt -s cdspell
|
|
# Allows minor misspelling of directory names with 'cd'
|
|
# Option -s sets, -u unsets.
|
|
|
|
cd /hpme # Oops! Mistyped '/home'.
|
|
pwd # /home
|
|
# The shell corrected the misspelling.</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>caller</command><anchor id="callerref"/></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>caller</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>caller</secondary>
|
|
</indexterm>
|
|
<para>Putting a <command>caller</command> command
|
|
inside a <link linkend="functionref">function</link>
|
|
echoes to <filename>stdout</filename> information about
|
|
the <firstterm>caller</firstterm> of that function.</para>
|
|
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
function1 ()
|
|
{
|
|
# Inside function1 ().
|
|
caller 0 # Tell me about it.
|
|
}
|
|
|
|
function1 # Line 9 of script.
|
|
|
|
# 9 main test.sh
|
|
# ^ Line number that the function was called from.
|
|
# ^^^^ Invoked from "main" part of script.
|
|
# ^^^^^^^ Name of calling script.
|
|
|
|
caller 0 # Has no effect because it's not inside a function.</programlisting></para>
|
|
|
|
<para>A <command>caller</command> command can also return
|
|
<firstterm>caller</firstterm> information from a script <link
|
|
linkend="sourceref">sourced</link> within another
|
|
script. Analogous to a function, this is a <quote>subroutine
|
|
call.</quote></para>
|
|
|
|
<para>You may find this command useful in debugging.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="intcommand">
|
|
<title><anchor id="intcommand1"/>Commands</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="trueref"/><command>true</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>true</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>true</secondary>
|
|
</indexterm>
|
|
|
|
<para>A command that returns a successful
|
|
(<returnvalue>zero</returnvalue>) <link
|
|
linkend="exitstatusref">exit status</link>, but does
|
|
nothing else.
|
|
</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>true</userinput>
|
|
<prompt>bash$ </prompt><userinput>echo $?</userinput>
|
|
<computeroutput>0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><programlisting># Endless loop
|
|
while true # alias for ":"
|
|
do
|
|
operation-1
|
|
operation-2
|
|
...
|
|
operation-n
|
|
# Need a way to break out of loop or script will hang.
|
|
done</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="falseref"/><command>false</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>false</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>false</secondary>
|
|
</indexterm>
|
|
<para>A command that returns an unsuccessful <link
|
|
linkend="exitstatusref">exit status</link>,
|
|
but does nothing else.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>false</userinput>
|
|
<prompt>bash$ </prompt><userinput>echo $?</userinput>
|
|
<computeroutput>1</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><programlisting># Testing "false"
|
|
if false
|
|
then
|
|
echo "false evaluates \"true\""
|
|
else
|
|
echo "false evaluates \"false\""
|
|
fi
|
|
# false evaluates "false"
|
|
|
|
|
|
# Looping while "false" (null loop)
|
|
while false
|
|
do
|
|
# The following code will not execute.
|
|
operation-1
|
|
operation-2
|
|
...
|
|
operation-n
|
|
# Nothing happens!
|
|
done
|
|
</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="typeref"/><command>type [cmd]</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>type</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>type</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>which</secondary>
|
|
</indexterm>
|
|
<para>Similar to the <link
|
|
linkend="whichref">which</link> external command,
|
|
<command>type cmd</command> identifies
|
|
<quote>cmd.</quote> Unlike <command>which</command>,
|
|
<command>type</command> is a Bash builtin. The useful
|
|
<option>-a</option> option to <command>type</command>
|
|
identifies <replaceable>keywords</replaceable>
|
|
and <replaceable>builtins</replaceable>, and also locates
|
|
system commands with identical names.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>type '['</userinput>
|
|
<computeroutput>[ is a shell builtin</computeroutput>
|
|
<prompt>bash$ </prompt><userinput>type -a '['</userinput>
|
|
<computeroutput>[ is a shell builtin
|
|
[ is /usr/bin/[</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>type type</userinput>
|
|
<computeroutput>type is a shell builtin</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <command>type</command> command can be useful
|
|
for <link linkend="devnullredirect">testing whether a
|
|
certain command exists</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="hashcmdref"/><command>hash [cmds]</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>Records the <firstterm>path</firstterm>
|
|
name of specified commands -- in the shell <firstterm>hash
|
|
table</firstterm>
|
|
|
|
<footnote>
|
|
<para><anchor id="hashref"/></para>
|
|
<para><firstterm>Hashing</firstterm> is a method of
|
|
creating lookup keys for data stored in a table. The
|
|
<emphasis>data items themselves</emphasis> are
|
|
<quote>scrambled</quote> to create keys, using one of
|
|
a number of simple mathematical
|
|
<firstterm>algorithms</firstterm> (methods, or
|
|
recipes).</para>
|
|
|
|
<para>An advantage of <firstterm>hashing</firstterm> is that
|
|
it is fast. A disadvantage is that
|
|
<firstterm>collisions</firstterm> -- where a single key
|
|
maps to more than one data item -- are possible.</para>
|
|
|
|
<para>For examples of hashing see <xref linkend="hashlib"/> and
|
|
<xref linkend="hashexample"/>.</para>
|
|
</footnote>
|
|
|
|
-- so the shell or script will not need to search the
|
|
<link linkend="pathref">$PATH</link> on subsequent calls to those
|
|
commands. When <command>hash</command> is called with no
|
|
arguments, it simply lists the commands that have been hashed.
|
|
The <option>-r</option> option resets the hash table.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="bindref"/><command>bind</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>bind</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>bind</primary>
|
|
<secondary>key bindings </secondary>
|
|
</indexterm>
|
|
|
|
<para>The <command>bind</command> builtin displays or modifies
|
|
<firstterm>readline</firstterm>
|
|
<footnote><para><anchor id="readlineref"/>The
|
|
<firstterm>readline</firstterm> library is what
|
|
Bash uses for reading input in an
|
|
interactive shell.</para></footnote>
|
|
key bindings.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="helpref"/><command>help</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>help</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary></secondary>
|
|
</indexterm>
|
|
|
|
<para>Gets a short usage summary of a shell builtin. This is
|
|
the counterpart to <link linkend="whatisref">whatis</link>,
|
|
but for builtins. The display of <firstterm>help</firstterm>
|
|
information got a much-needed update in the <link
|
|
linkend="bash4ref">version 4 release</link> of Bash.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>help exit</userinput>
|
|
<computeroutput>exit: exit [n]
|
|
Exit the shell with a status of N. If N is omitted, the exit status
|
|
is that of the last command executed.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<sect1>
|
|
<title>Job Control Commands</title>
|
|
|
|
|
|
<para>Certain of the following job control commands take a
|
|
<firstterm>job identifier</firstterm> as an argument. See
|
|
the <link linkend="jobidtable">table</link> at end of the
|
|
chapter.</para>
|
|
|
|
<variablelist id="jccommandlist">
|
|
|
|
<varlistentry>
|
|
<term><anchor id="jobsref"/><command>jobs</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para>Lists the jobs running in the background, giving
|
|
the <firstterm>job number</firstterm>.
|
|
Not as useful as <link linkend="ppssref">ps</link>.</para>
|
|
|
|
<note>
|
|
<para>It is all too easy to confuse
|
|
<firstterm>jobs</firstterm> and
|
|
<firstterm>processes</firstterm>. Certain <link
|
|
linkend="builtinref">builtins</link>, such as
|
|
<command>kill</command>, <command>disown</command>, and
|
|
<command>wait</command> accept either a job number or a
|
|
process number as an argument. The <link linkend="fgref">fg</link>,
|
|
<link linkend="bgref">bg</link> and <command>jobs</command>
|
|
commands accept only a job number.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>sleep 100 &</userinput>
|
|
<computeroutput>[1] 1384</computeroutput>
|
|
|
|
<prompt>bash $ </prompt><userinput>jobs</userinput>
|
|
<computeroutput>[1]+ Running sleep 100 &</computeroutput></screen>
|
|
</para>
|
|
|
|
<para><quote>1</quote> is the job number (jobs are
|
|
maintained by the current shell). <quote>1384</quote>
|
|
is the <link linkend="ppidref">PID</link> or <firstterm>process ID
|
|
number</firstterm> (processes are maintained by the system). To kill
|
|
this job/process, either a <command>kill %1</command>
|
|
or a <command>kill 1384</command> works.</para>
|
|
|
|
<para><emphasis>Thanks, S.C.</emphasis></para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="disownref"/><command>disown</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>disown</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>disown</secondary>
|
|
</indexterm>
|
|
<para>Remove job(s) from the shell's table of active jobs.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="fgref"/><command>fg</command></term>
|
|
<term><anchor id="bgref"/><command>bg</command></term>
|
|
<listitem>
|
|
<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>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>wait</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>wait</secondary>
|
|
</indexterm>
|
|
|
|
<para>Suspend script execution until all jobs running in
|
|
background have terminated, or until the job number or
|
|
process ID specified as an option terminates. Returns the <link
|
|
linkend="exitstatusref">exit status</link> of waited-for
|
|
command.</para>
|
|
|
|
<para>You may use the <command>wait</command> command
|
|
to prevent a script from exiting before a background
|
|
job finishes executing (this would create a dreaded
|
|
<link linkend="zombieref">orphan process</link>).</para>
|
|
|
|
<example id="ex39">
|
|
<title>Waiting for a process to finish before proceeding</title>
|
|
<programlisting>&ex39;</programlisting>
|
|
</example>
|
|
|
|
<para>Optionally, <command>wait</command> can take a <firstterm>job
|
|
identifier</firstterm> as an argument, for example,
|
|
<replaceable>wait%1</replaceable> or <replaceable>wait
|
|
$PPID</replaceable>.
|
|
|
|
<footnote><para>This only applies to <firstterm>child
|
|
processes</firstterm>, of course.</para></footnote>
|
|
|
|
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>
|
|
|
|
<blockquote>
|
|
<literallayout>
|
|
As Walter Brameld IV explains it:
|
|
|
|
As far as I can tell, such scripts don't actually hang. It just
|
|
seems that they do because the background command writes text to
|
|
the console after the prompt. The user gets the impression that
|
|
the prompt was never displayed. Here's the sequence of events:
|
|
|
|
1. Script launches background command.
|
|
2. Script exits.
|
|
3. Shell displays the prompt.
|
|
4. Background command continues running and writing text to the
|
|
console.
|
|
5. Background command finishes.
|
|
6. User doesn't see a prompt at the bottom of the output, thinks script
|
|
is hanging.
|
|
</literallayout>
|
|
</blockquote>
|
|
|
|
<para>Placing a <command>wait</command> after the background
|
|
command seems to remedy this.
|
|
<programlisting>#!/bin/bash
|
|
# test.sh
|
|
|
|
ls -l &
|
|
echo "Done."
|
|
wait</programlisting>
|
|
<screen><prompt>bash$ </prompt><userinput>./test.sh</userinput>
|
|
<computeroutput>Done.
|
|
[bozo@localhost test-scripts]$ total 1
|
|
-rwxr-xr-x 1 bozo bozo 34 Oct 11 15:09 test.sh</computeroutput>
|
|
</screen>
|
|
<link linkend="ioredirref">Redirecting</link> the
|
|
output of the command to a file or even to
|
|
<filename>/dev/null</filename> also takes care of this
|
|
problem.
|
|
</para>
|
|
</tip>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="suspendref"/><command>suspend</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>suspend</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>suspend</secondary>
|
|
</indexterm>
|
|
<para>This has a similar effect to
|
|
<keycombo><keycap>Control</keycap><keycap>Z</keycap></keycombo>,
|
|
but it suspends the shell (the shell's parent process should
|
|
resume it at an appropriate time).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="logoutref"/><command>logout</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>logout</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>log out</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>times</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>times</secondary>
|
|
</indexterm>
|
|
<para>Gives statistics on the system time elapsed when
|
|
executing commands, in the following form:
|
|
<screen><computeroutput>0m0.020s 0m0.020s</computeroutput></screen></para>
|
|
|
|
<para>This capability is of relatively limited value, since it is not common to
|
|
profile and benchmark shell scripts.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="killref"/><command>kill</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>kill</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>kill</secondary>
|
|
</indexterm>
|
|
<para>Forcibly terminate a process by sending it an
|
|
appropriate <firstterm>terminate</firstterm> signal
|
|
(see <xref linkend="killprocess"/>).</para>
|
|
|
|
<example id="selfdestruct">
|
|
<title>A script that kills itself</title>
|
|
<programlisting>&selfdestruct;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="zombieref"/></para>
|
|
<note><para><userinput>kill -l</userinput> lists all the
|
|
<link linkend="signald">signals</link> (as does the
|
|
file <filename>/usr/include/asm/signal.h</filename>).
|
|
A <userinput>kill -9</userinput> is a <firstterm>sure
|
|
kill</firstterm>, which will usually terminate a
|
|
process that stubbornly refuses to die with a plain
|
|
<command>kill</command>. Sometimes, a <userinput>kill
|
|
-15</userinput> works. A <firstterm>zombie</firstterm> process,
|
|
that is, a child process that has terminated, but that
|
|
the <link linkend="forkref">parent process</link>
|
|
has not (yet) killed, cannot be killed by a logged-on
|
|
user -- you can't kill something that is already dead --
|
|
but <command>init</command> will generally clean it up
|
|
sooner or later.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="killallref"/><command>killall</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>killall</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>kill</secondary>
|
|
</indexterm>
|
|
<para>The <command>killall</command> command
|
|
kills a running process by <firstterm>name</firstterm>,
|
|
rather than by <link linkend="processidref">process ID</link>.
|
|
If there are multiple instances of a particular command running,
|
|
then doing a <firstterm>killall</firstterm> on that command will
|
|
terminate them <emphasis>all</emphasis>.</para>
|
|
|
|
<note><para>This refers to the <command>killall</command>
|
|
command in <filename class="directory">/usr/bin</filename>,
|
|
<emphasis>not</emphasis> the <link
|
|
linkend="killall2ref">killall script</link> in <filename
|
|
class="directory">/etc/rc.d/init.d</filename>.</para></note>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="commandref"/><command>command</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>command</secondary>
|
|
</indexterm>
|
|
<para>The <command>command</command> directive
|
|
disables aliases and functions for the command immediately
|
|
following it.</para>
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>command ls</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>This is one of three shell directives that
|
|
effect script command processing. The others are
|
|
<link linkend="bltref">builtin</link> and <link
|
|
linkend="enableref">enable</link>.</para></note>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="bltref"/><command>builtin</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>builtin</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>builtin</secondary>
|
|
</indexterm>
|
|
<para>Invoking <command>builtin
|
|
BUILTIN_COMMAND</command> runs the command
|
|
<replaceable>BUILTIN_COMMAND</replaceable> as a shell <link
|
|
linkend="builtinref">builtin</link>, temporarily disabling
|
|
both functions and external system commands with the
|
|
same name.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="enableref"/><command>enable</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>enable</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>enable</secondary>
|
|
</indexterm>
|
|
|
|
<para>This either enables or disables a shell
|
|
builtin command. As an example, <replaceable>enable -n
|
|
kill</replaceable> disables the shell builtin <link
|
|
linkend="killref">kill</link>, so that when Bash
|
|
subsequently encounters <firstterm>kill</firstterm>, it invokes
|
|
the external command <filename>/bin/kill</filename>.</para>
|
|
|
|
<para><anchor id="enableref1"/>The <option>-a</option>
|
|
option to <firstterm>enable</firstterm> lists all the
|
|
shell builtins, indicating whether or not they
|
|
are enabled. The <option>-f filename</option>
|
|
option lets <firstterm>enable</firstterm> load a <link
|
|
linkend="builtinref">builtin</link> as a shared library
|
|
(DLL) module from a properly compiled object file.
|
|
<footnote>
|
|
<para>The C source for a number of loadable builtins is
|
|
typically found in the <filename
|
|
class="directory">/usr/share/doc/bash-?.??/functions</filename>
|
|
directory.</para>
|
|
<para>Note that the <option>-f</option> option to
|
|
<command>enable</command> is not <link
|
|
linkend="portabilityissues">portable</link> to all
|
|
systems.</para>
|
|
</footnote>.
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="autoloadref"/><command>autoload</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>autoload</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>autoloader</secondary>
|
|
</indexterm>
|
|
|
|
<para>This is a port to Bash of the
|
|
<firstterm>ksh</firstterm> autoloader. With
|
|
<command>autoload</command> in place, a function with
|
|
an <firstterm>autoload</firstterm> declaration will load from an
|
|
external file at its first invocation.
|
|
<footnote><para>The same effect as
|
|
<command>autoload</command> can be achieved with <link
|
|
linkend="declareref">typeset -fu</link>.</para></footnote>
|
|
This saves system resources.</para>
|
|
|
|
<para>Note that <firstterm>autoload</firstterm> is not a part of the
|
|
core Bash installation. It needs to be loaded in with
|
|
<replaceable>enable -f</replaceable> (see above).</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<para><anchor id="jobidtable0"/></para>
|
|
<table id="jobidtable">
|
|
<title>Job identifiers</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Notation</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>%N</option></entry>
|
|
<entry>Job number [N]</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%S</option></entry>
|
|
<entry>Invocation (command-line) of job begins with string <emphasis>S</emphasis></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%?S</option></entry>
|
|
<entry>Invocation (command-line) of job contains within it string <emphasis>S</emphasis></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%%</option></entry>
|
|
<entry><quote>current</quote> job (last job stopped in
|
|
foreground or started in background)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%+</option></entry>
|
|
<entry><quote>current</quote> job (last job stopped in
|
|
foreground or started in background)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>%-</option></entry>
|
|
<entry>Last job</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$!</option></entry>
|
|
<entry>Last background process</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
</sect1> <!-- Job Control Commands -->
|
|
|
|
</chapter> <!-- Internal Commands and Builtins -->
|
|
|
|
|
|
|
|
<chapter id="external">
|
|
<title>External Filters, Programs and Commands</title>
|
|
|
|
<para><anchor id="externalref"/></para>
|
|
|
|
<para>Standard UNIX commands make shell scripts more versatile. The
|
|
power of scripts comes from coupling system commands and shell
|
|
directives with simple programming constructs.</para>
|
|
|
|
<sect1 id="basic">
|
|
<title>Basic Commands</title>
|
|
|
|
<variablelist id="basiccommands">
|
|
<title><anchor id="basiccommands1"/>The first commands a novice learns</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lsref"/><command>ls</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ls</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ls</secondary>
|
|
</indexterm>
|
|
<para>The basic file <quote>list</quote> command. It is all too easy
|
|
to underestimate the power of this humble command. For
|
|
example, using the <option>-R</option>, recursive option,
|
|
<command>ls</command> provides a tree-like listing of
|
|
a directory structure. Other useful options are
|
|
<option>-S</option>, sort listing by file size,
|
|
<option>-t</option>, sort by file modification time,
|
|
<option>-v</option>, sort by (numerical) version numbers
|
|
embedded in the filenames,
|
|
<footnote><para>The <option>-v</option> option also orders the
|
|
sort by <emphasis>upper- and lowercase prefixed</emphasis>
|
|
filenames.</para></footnote>
|
|
<option>-b</option>, show escape characters, and
|
|
<option>-i</option>, show file inodes (see <xref
|
|
linkend="idelete"/>).</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ls -l</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter10.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter11.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter12.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter1.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter2.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter3.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:49 Chapter_headings.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:49 Preface.txt</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -lv</userinput>
|
|
<computeroutput> total 0
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:49 Chapter_headings.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:49 Preface.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter1.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter2.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter3.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter10.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter11.txt
|
|
-rw-rw-r-- 1 bozo bozo 0 Sep 14 18:44 chapter12.txt</computeroutput></screen>
|
|
</para>
|
|
|
|
|
|
<tip><para>
|
|
The <firstterm>ls</firstterm> command returns a
|
|
non-zero <link linkend="exitstatusref">exit status</link> when
|
|
attempting to list a non-existent file.
|
|
<screen><prompt>bash$ </prompt><userinput>ls abc</userinput>
|
|
<computeroutput>ls: abc: No such file or directory</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $?</userinput>
|
|
<computeroutput>2</computeroutput></screen>
|
|
</para></tip>
|
|
|
|
<example id="ex40">
|
|
<title>Using <firstterm>ls</firstterm> to create a table of contents
|
|
for burning a <abbrev>CDR</abbrev> disk</title>
|
|
<programlisting>&ex40;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="catref"/><command>cat</command></term>
|
|
<term><command>tac</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para><command>cat</command>, an acronym for
|
|
<wordasword>concatenate</wordasword>,
|
|
lists a file to <filename>stdout</filename>. When
|
|
combined with redirection (<token>></token> or
|
|
<token>>></token>), it is commonly used to concatenate
|
|
files.
|
|
|
|
<anchor id="catuses"/>
|
|
<programlisting># Uses of 'cat'
|
|
cat filename # Lists the file.
|
|
|
|
cat file.1 file.2 file.3 > file.123 # Combines three files into one.</programlisting>
|
|
|
|
The <option>-n</option> option to <command>cat</command>
|
|
inserts consecutive numbers before all lines of the
|
|
target file(s). The <option>-b</option> option numbers
|
|
only the non-blank lines. The <option>-v</option> option
|
|
echoes nonprintable characters, using <token>^</token>
|
|
notation. The <option>-s</option> option squeezes multiple
|
|
consecutive blank lines into a single blank line.</para>
|
|
|
|
<para>See also <xref linkend="lnum"/> and <xref linkend="rot13"/>.</para>
|
|
|
|
<note>
|
|
<para><anchor id="catlesseff"/>
|
|
In a <link linkend="piperef">pipe</link>, it may be
|
|
more efficient to <link linkend="ioredirref">redirect</link>
|
|
the <filename>stdin</filename> to a file, rather than to
|
|
<command>cat</command> the file.
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting>cat filename | tr a-z A-Z
|
|
|
|
tr a-z A-Z < filename # Same effect, but starts one less process,
|
|
#+ and also dispenses with the pipe.</programlisting>
|
|
</para>
|
|
</note>
|
|
|
|
|
|
<para><command>tac</command>, is the inverse of
|
|
<wordasword>cat</wordasword>, listing a file backwards from its end.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="revref"/><command>rev</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rev</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>rev</secondary>
|
|
</indexterm>
|
|
<para>reverses each line of a file, and outputs to
|
|
<filename>stdout</filename>. This does not have the same effect
|
|
as <command>tac</command>, as it preserves the order of
|
|
the lines, but flips each one around (mirror image).</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>cat file1.txt</userinput>
|
|
<computeroutput>This is line 1.
|
|
This is line 2.</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>tac file1.txt</userinput>
|
|
<computeroutput>This is line 2.
|
|
This is line 1.</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>rev file1.txt</userinput>
|
|
<computeroutput>.1 enil si sihT
|
|
.2 enil si sihT</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cpref"/><command>cp</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>cp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cp</secondary>
|
|
</indexterm>
|
|
|
|
<para>This is the file copy command. <userinput>cp file1
|
|
file2</userinput> copies <filename>file1</filename>
|
|
to <filename>file2</filename>, overwriting
|
|
<filename>file2</filename> if it already exists (see <xref
|
|
linkend="ex42"/>).</para>
|
|
|
|
<tip>
|
|
<para>Particularly useful are the <option>-a</option>
|
|
archive flag (for copying an entire directory tree),
|
|
the <option>-u</option> update flag (which prevents
|
|
overwriting identically-named newer files), and the
|
|
<option>-r</option> and <option>-R</option> recursive
|
|
flags.</para>
|
|
<para><programlisting>cp -u source_dir/* dest_dir
|
|
# "Synchronize" dest_dir to source_dir
|
|
#+ by copying over all newer and not previously existing files.</programlisting></para>
|
|
</tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mvref"/><command>mv</command></term>
|
|
<listitem>
|
|
<para>This is the file <firstterm>move</firstterm> command.
|
|
It is equivalent to a combination of <command>cp</command>
|
|
and <command>rm</command>. It may be used to move multiple
|
|
files to a directory, or even to rename a directory. For
|
|
some examples of using <command>mv</command> in a script,
|
|
see <xref linkend="rfe"/> and <xref linkend="rn"/>.</para>
|
|
|
|
<note>
|
|
<para>When used in a non-interactive script,
|
|
<command>mv</command> takes the <option>-f</option>
|
|
(<firstterm>force</firstterm>) option to bypass user
|
|
input.</para>
|
|
|
|
<para>When a directory is moved to a preexisting directory,
|
|
it becomes a subdirectory of the destination directory.</para>
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>mv source_directory target_directory</userinput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -lF target_directory</userinput>
|
|
<computeroutput>total 1
|
|
drwxrwxr-x 2 bozo bozo 1024 May 28 19:20 source_directory/</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rmref"/><command>rm</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>rm</secondary>
|
|
</indexterm>
|
|
<para>Delete (remove) a file or files. The <option>-f</option>
|
|
option forces removal of even readonly files, and is useful
|
|
for bypassing user input in a script.</para>
|
|
|
|
<note>
|
|
<para><anchor id="dashrem"/></para>
|
|
<para>The <firstterm>rm</firstterm> command will, by
|
|
itself, fail to remove filenames beginning with
|
|
a dash. Why? Because <firstterm>rm</firstterm>
|
|
sees a dash-prefixed filename as an
|
|
<firstterm>option</firstterm>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>rm -badname</userinput>
|
|
<computeroutput>rm: invalid option -- b
|
|
Try `rm --help' for more information.</computeroutput></screen>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
One clever workaround is to precede
|
|
the filename with a <quote> -- </quote> (the
|
|
<firstterm>end-of-options</firstterm> flag).
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>rm -- -badname</userinput></screen>
|
|
</para>
|
|
|
|
<para>
|
|
Another method to is to preface the filename to be removed
|
|
with a <filename>dot-slash</filename> .
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>rm ./-badname</userinput></screen>
|
|
</para>
|
|
</note>
|
|
|
|
|
|
<warning><para><anchor id="rmrecurs"/>When used with the
|
|
recursive flag <option>-r</option>, this command removes
|
|
files all the way down the directory tree from the current
|
|
directory. A careless <command>rm -rf *</command> can wipe
|
|
out a big chunk of a directory structure.</para></warning>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rmdirref"/><command>rmdir</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rmdir</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>rmdir</secondary>
|
|
</indexterm>
|
|
<para>Remove directory. The directory must be empty of
|
|
all files -- including <quote>invisible</quote>
|
|
<firstterm>dotfiles</firstterm>
|
|
|
|
<footnote>
|
|
<para><anchor id="dotfilesref"/></para>
|
|
<para><firstterm>Dotfiles</firstterm> are files whose
|
|
names begin with a <firstterm>dot</firstterm>, such as
|
|
<filename>~/.Xdefaults</filename>. Such filenames do
|
|
not appear in a normal <command>ls</command> listing
|
|
(although an <command>ls -a</command> will show
|
|
them), and they cannot be deleted by an accidental
|
|
<command>rm -rf *</command>. Dotfiles are generally
|
|
used as setup and configuration files in a user's
|
|
home directory.</para>
|
|
</footnote>
|
|
|
|
-- for this command to succeed.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mkdirref"/><command>mkdir</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mkdir</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mkdir</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>chmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>chmod</secondary>
|
|
</indexterm>
|
|
|
|
<para>Changes the attributes of an existing file or directory
|
|
(see <xref linkend="ex44"/>).</para>
|
|
|
|
<para><programlisting>chmod +x filename
|
|
# Makes "filename" executable for all users.
|
|
|
|
chmod u+s filename
|
|
# Sets "suid" bit on "filename" permissions.
|
|
# An ordinary user may execute "filename" with same privileges as the file's owner.
|
|
# (This does not apply to shell scripts.)</programlisting></para>
|
|
|
|
<para><programlisting>chmod 644 filename
|
|
# Makes "filename" readable/writable to owner, readable to others
|
|
#+ (octal mode).
|
|
|
|
chmod 444 filename
|
|
# Makes "filename" read-only for all.
|
|
# Modifying the file (for example, with a text editor)
|
|
#+ not allowed for a user who does not own the file (except for root),
|
|
#+ and even the file owner must force a file-save
|
|
#+ if she modifies the file.
|
|
# Same restrictions apply for deleting the file.</programlisting></para>
|
|
|
|
<para><programlisting>chmod 1777 directory-name
|
|
# Gives everyone read, write, and execute permission in directory,
|
|
#+ however also sets the "sticky bit".
|
|
# This means that only the owner of the directory,
|
|
#+ owner of the file, and, of course, root
|
|
#+ can delete any particular file in that directory.
|
|
|
|
chmod 111 directory-name
|
|
# Gives everyone execute-only permission in a directory.
|
|
# This means that you can execute and READ the files in that directory
|
|
#+ (execute permission necessarily includes read permission
|
|
#+ because you can't execute a file without being able to read it).
|
|
# But you can't list the files or search for them with the "find" command.
|
|
# These restrictions do not apply to root.
|
|
|
|
chmod 000 directory-name
|
|
# No permissions at all for that directory.
|
|
# Can't read, write, or execute files in it.
|
|
# Can't even list files in it or "cd" to it.
|
|
# But, you can rename (mv) the directory
|
|
#+ or delete it (rmdir) if it is empty.
|
|
# You can even symlink to files in the directory,
|
|
#+ but you can't read, write, or execute the symlinks.
|
|
# These restrictions do not apply to root.</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="chattrref"/><command>chattr</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>chattr</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>chattr</secondary>
|
|
</indexterm>
|
|
|
|
<para><command>Ch</command>ange file
|
|
<command>attr</command>ibutes. This is analogous to
|
|
<command>chmod</command> above, but with different options
|
|
and a different invocation syntax, and it works only on
|
|
<firstterm>ext2/ext3</firstterm> filesystems.</para>
|
|
|
|
<para>One particularly interesting <command>chattr</command>
|
|
option is <option>i</option>. A <command>chattr +i
|
|
<filename>filename</filename></command> marks the file
|
|
as immutable. The file cannot be modified, linked to, or
|
|
deleted, <emphasis>not even by root</emphasis>. This
|
|
file attribute can be set or removed only by
|
|
<firstterm>root</firstterm>. In a similar fashion,
|
|
the <option>a</option> option marks the file as append
|
|
only.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>root# </prompt><userinput>chattr +i file1.txt</userinput>
|
|
|
|
|
|
<prompt>root# </prompt><userinput>rm file1.txt</userinput>
|
|
|
|
<computeroutput>rm: remove write-protected regular file `file1.txt'? y
|
|
rm: cannot remove `file1.txt': Operation not permitted</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>If a file has the <option>s</option> (secure)
|
|
attribute set, then when it is deleted its block is
|
|
overwritten with binary zeroes.
|
|
<footnote><para>This particular feature may not yet be
|
|
implemented in the version of the ext2/ext3 filesystem
|
|
installed on your system. Check the documentation for
|
|
your Linux distro.</para></footnote>
|
|
</para>
|
|
|
|
<para>If a file has the <option>u</option> (undelete)
|
|
attribute set, then when it is deleted, its contents can still
|
|
be retrieved (undeleted).</para>
|
|
|
|
<para>If a file has the <option>c</option> (compress)
|
|
attribute set, then it will automatically be compressed
|
|
on writes to disk, and uncompressed on reads.</para>
|
|
|
|
<note><para>The file attributes set with
|
|
<command>chattr</command> do not show in a file listing
|
|
(<command>ls -l</command>).</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="linkref"/><command>ln</command></term>
|
|
<listitem>
|
|
|
|
<para>Creates links to pre-existings files. A <quote>link</quote>
|
|
is a reference to a file, an alternate name for it.
|
|
The <command>ln</command> command permits referencing
|
|
the linked file by more than one name and is a superior
|
|
alternative to aliasing (see <xref linkend="ex18"/>).</para>
|
|
|
|
<para>The <command>ln</command> creates only a reference, a
|
|
pointer to the file only a few bytes in size.</para>
|
|
|
|
<para><anchor id="symlinkref"/></para>
|
|
|
|
<para>The <command>ln</command> command is most often used
|
|
with the <option>-s</option>, symbolic or
|
|
<quote>soft</quote> link flag. Advantages of using the
|
|
<option>-s</option> flag are that it permits linking across
|
|
file systems or to directories.</para>
|
|
|
|
<para>The syntax of the command is a bit tricky. For example:
|
|
<userinput>ln -s oldfile newfile</userinput> links the
|
|
previously existing <filename>oldfile</filename> to the
|
|
newly created link, <filename>newfile</filename>.</para>
|
|
|
|
<caution><para>If a file named <filename>newfile</filename> has
|
|
previously existed, an error message will
|
|
result.</para></caution>
|
|
|
|
|
|
<sidebar><title>Which type of link to use?</title>
|
|
|
|
<para>As John Macdonald explains it:</para>
|
|
|
|
<para>Both of these [types of links] provide a certain measure of dual reference
|
|
-- if you edit the contents of the file using any name,
|
|
your changes will affect both the original name and either
|
|
a hard or soft new name. The differences between them
|
|
occurs when you work at a higher level. The advantage of
|
|
a hard link is that the new name is totally independent
|
|
of the old name -- if you remove or rename the old name,
|
|
that does not affect the hard link, which continues
|
|
to point to the data while it would leave a soft link
|
|
hanging pointing to the old name which is no longer
|
|
there. The advantage of a soft link is that it can refer
|
|
to a different file system (since it is just a reference
|
|
to a file name, not to actual data). And, unlike a hard
|
|
link, a symbolic link can refer to a directory.</para>
|
|
|
|
</sidebar>
|
|
|
|
<para><anchor id="linkminvok"/></para>
|
|
<para>Links give the ability to invoke a script (or any other type
|
|
of executable) with multiple names, and having that script
|
|
behave according to how it was invoked.</para>
|
|
|
|
<example id="hellol">
|
|
<title>Hello or Good-bye</title>
|
|
<programlisting>&hellol;</programlisting>
|
|
</example>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="manref"/><command>man</command></term>
|
|
<term><anchor id="inforef"/><command>info</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para>These commands access the manual and information pages on
|
|
system commands and installed utilities. When available, the
|
|
<firstterm>info</firstterm> pages usually contain more detailed
|
|
descriptions than do the <firstterm>man</firstterm> pages.</para>
|
|
|
|
<para>There have been various attempts at
|
|
<quote>automating</quote> the writing of <firstterm>man
|
|
pages</firstterm>. For a script that makes a tentative first
|
|
step in that direction, see <xref linkend="maned"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
|
|
</sect1> <!-- End Basic Commands -->
|
|
|
|
|
|
<sect1 id="moreadv">
|
|
<title>Complex Commands</title>
|
|
|
|
<variablelist id="cclisting">
|
|
<title><anchor id="cclisting1"/>Commands for more advanced users</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="findref"/><command>find</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para><anchor id="findref0"/></para>
|
|
<para>-exec <replaceable>COMMAND</replaceable> \;</para>
|
|
<para>Carries out <replaceable>COMMAND</replaceable> on
|
|
each file that <command>find</command> matches. The
|
|
command sequence terminates with <token>;</token> (the
|
|
<quote>;</quote> is <link linkend="escp">escaped</link> to
|
|
make certain the shell passes it to <command>find</command>
|
|
literally, without interpreting it as a special character).</para>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>find ~/ -name '*.txt'</userinput>
|
|
<computeroutput>/home/bozo/.kde/share/apps/karm/karmdata.txt
|
|
/home/bozo/misc/irmeyc.txt
|
|
/home/bozo/test-scripts/1.txt</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="curlybracketsref"/></para>
|
|
|
|
<para>If <replaceable>COMMAND</replaceable> contains
|
|
<token>{}</token>, then <command>find</command>
|
|
substitutes the full path name of the selected file for
|
|
<quote>{}</quote>.</para>
|
|
|
|
<para>
|
|
<programlisting>find ~/ -name 'core*' -exec rm {} \;
|
|
# Removes all core dump files from user's home directory.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
<programlisting>find /home/bozo/projects -mtime -1
|
|
# ^ Note minus sign!
|
|
# Lists all files in /home/bozo/projects directory tree
|
|
#+ that were modified within the last day (current_day - 1).
|
|
#
|
|
find /home/bozo/projects -mtime 1
|
|
# Same as above, but modified *exactly* one day ago.
|
|
#
|
|
# mtime = last modification time of the target file
|
|
# ctime = last status change time (via 'chmod' or otherwise)
|
|
# atime = last access time
|
|
|
|
DIR=/home/bozo/junk_files
|
|
find "$DIR" -type f -atime +5 -exec rm {} \;
|
|
# ^ ^^
|
|
# Curly brackets are placeholder for the path name output by "find."
|
|
#
|
|
# Deletes all files in "/home/bozo/junk_files"
|
|
#+ that have not been accessed in *at least* 5 days (plus sign ... +5).
|
|
#
|
|
# "-type filetype", where
|
|
# f = regular file
|
|
# d = directory
|
|
# l = symbolic link, etc.
|
|
#
|
|
# (The 'find' manpage and info page have complete option listings.)</programlisting>
|
|
</para>
|
|
|
|
|
|
|
|
<para><programlisting>find /etc -exec grep '[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*' {} \;
|
|
|
|
# Finds all IP addresses (xxx.xxx.xxx.xxx) in /etc directory files.
|
|
# There a few extraneous hits. Can they be filtered out?
|
|
|
|
# Possibly by:
|
|
|
|
find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
|
|
| grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'
|
|
#
|
|
# [:digit:] is one of the character classes
|
|
#+ introduced with the POSIX 1003.2 standard.
|
|
|
|
# Thanks, Stéphane Chazelas.
|
|
</programlisting></para>
|
|
|
|
|
|
<note><para>The <option>-exec</option> option to
|
|
<command>find</command> should not be confused with the <link
|
|
linkend="execref">exec</link> shell builtin.</para></note>
|
|
|
|
<example id="ex57">
|
|
<title><firstterm>Badname</firstterm>, eliminate file names
|
|
in current directory containing bad characters and <link
|
|
linkend="whitespaceref">whitespace</link>.</title>
|
|
<programlisting>&ex57;</programlisting>
|
|
</example>
|
|
|
|
<example id="idelete">
|
|
<title>Deleting a file by its <firstterm>inode</firstterm>
|
|
number</title>
|
|
<programlisting>&idelete;</programlisting>
|
|
</example>
|
|
|
|
<para>The <command>find</command> command also works
|
|
without the <option>-exec</option> option.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# Find suid root files.
|
|
# A strange suid file might indicate a security hole,
|
|
#+ or even a system intrusion.
|
|
|
|
directory="/usr/sbin"
|
|
# Might also try /sbin, /bin, /usr/bin, /usr/local/bin, etc.
|
|
permissions="+4000" # suid root (dangerous!)
|
|
|
|
|
|
for file in $( find "$directory" -perm "$permissions" )
|
|
do
|
|
ls -ltF --author "$file"
|
|
done</programlisting>
|
|
</para>
|
|
|
|
<para>See <xref linkend="ex48"/>, <xref linkend="ex58"/>,
|
|
and <xref linkend="findstring"/> for scripts using
|
|
<command>find</command>. Its <link
|
|
linkend="manref">manpage</link> provides more detail
|
|
on this complex and powerful command.</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="xargsref"/><command>xargs</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>xargs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>xargs</secondary>
|
|
</indexterm>
|
|
<para>A filter for feeding arguments to a command, and also
|
|
a tool for assembling the commands themselves. It breaks
|
|
a data stream into small enough chunks for filters and
|
|
commands to process. Consider it as a powerful replacement
|
|
for <link linkend="backquotesref">backquotes</link>.
|
|
In situations where <link linkend="commandsubref">command
|
|
substitution</link> fails with a <errorname>too
|
|
many arguments</errorname> error,
|
|
substituting <command>xargs</command> often
|
|
works.
|
|
<footnote><para>And even when <firstterm>xargs</firstterm> is
|
|
not strictly necessary, it can speed up execution of a command
|
|
involving <link
|
|
linkend="batchprocref">batch-processing</link> of multiple
|
|
files.</para></footnote>
|
|
Normally, <command>xargs</command> reads from
|
|
<filename>stdin</filename> or from a pipe, but it can also
|
|
be given the output of a file.</para>
|
|
|
|
<para>The default command for <command>xargs</command> is
|
|
<link linkend="echoref">echo</link>. This means that input
|
|
piped to <command>xargs</command> may have linefeeds and
|
|
other whitespace characters stripped out.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>ls -l</userinput>
|
|
<computeroutput>total 0
|
|
-rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file1
|
|
-rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file2</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l | xargs</userinput>
|
|
<computeroutput>total 0 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file1 -rw-rw-r-- 1 bozo bozo 0 Jan...</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>find ~/mail -type f | xargs grep "Linux"</userinput>
|
|
<computeroutput>./misc:User-Agent: slrn/0.9.8.1 (Linux)
|
|
./sent-mail-jul-2005: hosted by the Linux Documentation Project.
|
|
./sent-mail-jul-2005: (Linux Documentation Project Site, rtf version)
|
|
./sent-mail-jul-2005: Subject: Criticism of Bozo's Windows/Linux article
|
|
./sent-mail-jul-2005: while mentioning that the Linux ext2/ext3 filesystem
|
|
. . .</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><userinput>ls | xargs -p -l gzip</userinput> <link
|
|
linkend="gzipref">gzips</link> every file in current
|
|
directory, one at a time, prompting before each
|
|
operation.</para>
|
|
|
|
<para><anchor id="xargsoneatatime"/></para>
|
|
<note>
|
|
<para>Note that <firstterm>xargs</firstterm> processes the
|
|
arguments passed to it sequentially, <emphasis>one at
|
|
a time</emphasis>.</para>
|
|
|
|
<para><screen>
|
|
<prompt>bash$ </prompt><userinput>find /usr/bin | xargs file</userinput>
|
|
<computeroutput>/usr/bin: directory
|
|
/usr/bin/foomatic-ppd-options: perl script text executable
|
|
. . .</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
<para><anchor id="xargslimargs"/></para>
|
|
<tip>
|
|
<para>An interesting <firstterm>xargs</firstterm>
|
|
option is <option>-n <replaceable>NN</replaceable></option>,
|
|
which limits to <replaceable>NN</replaceable> the number
|
|
of arguments passed.</para>
|
|
<para><userinput>ls | xargs -n 8 echo</userinput> lists the files in the
|
|
current directory in <literal>8</literal> columns.</para>
|
|
</tip>
|
|
|
|
|
|
<para><anchor id="xargsws"/></para>
|
|
<tip>
|
|
<para>Another useful option is
|
|
<option>-0</option>, in combination with <userinput>find
|
|
-print0</userinput> or <userinput>grep -lZ</userinput>. This
|
|
allows handling arguments containing whitespace or
|
|
quotes.</para>
|
|
|
|
<para>
|
|
<userinput>find / -type f -print0 | xargs -0 grep -liwZ GUI | xargs -0 rm -f</userinput>
|
|
</para>
|
|
|
|
<para>
|
|
<userinput>grep -rliwZ GUI / | xargs -0 rm -f</userinput>
|
|
</para>
|
|
|
|
<para>Either of the above will remove any file containing <quote>GUI</quote>.
|
|
<emphasis>(Thanks, S.C.)</emphasis></para>
|
|
|
|
<para>Or:
|
|
<programlisting>cat /proc/"$pid"/"$OPTION" | xargs -0 echo
|
|
# Formats output: ^^^^^^^^^^^^^^^
|
|
# From Han Holl's fixup of "get-commandline.sh"
|
|
#+ script in "/dev and /proc" chapter.</programlisting></para>
|
|
</tip>
|
|
|
|
<tip>
|
|
<para><anchor id="xargsmultiprocess"/></para>
|
|
<para>The <option>-P</option> option to
|
|
<firstterm>xargs</firstterm> permits running
|
|
processes in parallel. This speeds up execution
|
|
in a machine with a multicore CPU.</para>
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
ls *gif | xargs -t -n1 -P2 gif2png
|
|
# Converts all the gif images in current directory to png.
|
|
|
|
# Options:
|
|
# =======
|
|
# -t Print command to stderr.
|
|
# -n1 At most 1 argument per command line.
|
|
# -P2 Run up to 2 processes simultaneously.
|
|
|
|
# Thank you, Roberto Polli, for the inspiration.</programlisting></para>
|
|
</tip>
|
|
|
|
|
|
<example id="ex41">
|
|
<title>Logfile: Using <firstterm>xargs</firstterm> to monitor system log</title>
|
|
<programlisting>&ex41;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="xargscurlyref"/></para>
|
|
<para><link linkend="curlybracketsref">As in
|
|
<command>find</command></link>, a curly bracket
|
|
pair serves as a placeholder for replacement text.</para>
|
|
|
|
<example id="ex42">
|
|
<title>Copying files in current directory to another</title>
|
|
<programlisting>&ex42;</programlisting>
|
|
</example>
|
|
|
|
<example id="killbyname">
|
|
<title>Killing processes by name</title>
|
|
<programlisting>&killbyname;</programlisting>
|
|
</example>
|
|
|
|
<example id="wf2">
|
|
<title>Word frequency analysis using
|
|
<firstterm>xargs</firstterm></title>
|
|
<programlisting>&wf2;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="exprref"/><userinput>expr</userinput></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>expr</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>expr</secondary>
|
|
</indexterm>
|
|
<para>All-purpose expression evaluator:
|
|
Concatenates and evaluates the arguments according
|
|
to the operation given (arguments must be separated
|
|
by spaces). Operations may be arithmetic, comparison,
|
|
string, or logical.</para>
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term><userinput>expr 3 + 5</userinput></term>
|
|
<listitem>
|
|
<para>returns <literal>8</literal></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>expr 5 % 3</userinput></term>
|
|
<listitem>
|
|
<para>returns 2</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>expr 1 / 0</userinput></term>
|
|
<listitem>
|
|
<para>returns the error message, <errorcode>expr: division by
|
|
zero</errorcode></para>
|
|
<para>Illegal arithmetic operations not allowed.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>expr 5 \* 3</userinput></term>
|
|
<listitem>
|
|
<para>returns 15</para>
|
|
<para>The multiplication operator
|
|
must be escaped when used in an arithmetic expression
|
|
with <command>expr</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><userinput>y=`expr $y + 1`</userinput></term>
|
|
<listitem>
|
|
<para>Increment a variable, with the same effect
|
|
as <userinput>let y=y+1</userinput> and
|
|
<userinput>y=$(($y+1))</userinput>. This is an
|
|
example of <link linkend="arithexpref">arithmetic
|
|
expansion</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="expextrsub"/><userinput>z=`expr substr
|
|
$string $position $length`</userinput></term>
|
|
<listitem>
|
|
<para>Extract substring of $length characters, starting
|
|
at $position.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<example id="ex45">
|
|
<title>Using <firstterm>expr</firstterm></title>
|
|
<programlisting>&ex45;</programlisting>
|
|
</example>
|
|
|
|
<important>
|
|
<para>The <link linkend="nullref">:
|
|
(<firstterm>null</firstterm>)</link> operator
|
|
can substitute for <command>match</command>. For example,
|
|
<userinput>b=`expr $a : [0-9]*`</userinput> is the
|
|
exact equivalent of <userinput>b=`expr match $a
|
|
[0-9]*`</userinput> in the above listing.</para>
|
|
|
|
<para><programlisting>&ex45a;</programlisting></para>
|
|
</important>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<para>The above script illustrates how
|
|
<command>expr</command> uses the <firstterm>escaped
|
|
parentheses -- \( ... \) --</firstterm> grouping operator
|
|
in tandem with <link linkend="regexref">regular
|
|
expression</link> parsing to match a substring.
|
|
Here is a another example, this time from <quote>real
|
|
life.</quote>
|
|
|
|
<programlisting># Strip the whitespace from the beginning and end.
|
|
LRFDATE=`expr "$LRFDATE" : '[[:space:]]*\(.*\)[[:space:]]*$'`
|
|
|
|
# From Peter Knowles' "booklistgen.sh" script
|
|
#+ for converting files to Sony Librie/PRS-50X format.
|
|
# (http://booklistgensh.peterknowles.com)</programlisting>
|
|
|
|
</para>
|
|
|
|
|
|
<para><link linkend="perlref">Perl</link>,
|
|
<link linkend="sedref">sed</link>, and <link
|
|
linkend="awkref">awk</link> have far superior string
|
|
parsing facilities. A short <command>sed</command> or
|
|
<command>awk</command> <quote>subroutine</quote> within
|
|
a script (see <xref linkend="wrapper"/>) is an attractive
|
|
alternative to <command>expr</command>.</para>
|
|
|
|
|
|
<para>See <xref linkend="String-Manipulation"/> for more on
|
|
using <command>expr</command> in string operations.</para>
|
|
|
|
|
|
</sect1> <!-- End Complex Commands -->
|
|
|
|
|
|
|
|
<sect1 id="timedate">
|
|
<title>Time / Date Commands</title>
|
|
|
|
<variablelist id="tdlisting">
|
|
<title><anchor id="tdlisting1"/>Time/date and timing</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dateref"/><command>date</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>date</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>date</secondary>
|
|
</indexterm>
|
|
<para>Simply invoked, <command>date</command> prints the date and
|
|
time to <filename>stdout</filename>. Where this command gets
|
|
interesting is in its formatting and parsing options.</para>
|
|
|
|
<example id="ex51">
|
|
<title>Using <firstterm>date</firstterm></title>
|
|
<programlisting>&ex51;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>The <option>-u</option> option gives the UTC (Universal
|
|
Coordinated Time).</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>date</userinput>
|
|
<computeroutput>Fri Mar 29 21:07:39 MST 2002</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>date -u</userinput>
|
|
<computeroutput>Sat Mar 30 04:07:42 UTC 2002</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>This option facilitates calculating the time between
|
|
different dates.</para>
|
|
|
|
<example id="datecalc">
|
|
<title><firstterm>Date</firstterm> calculations</title>
|
|
<programlisting>&datecalc;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="daterandref"/></para>
|
|
<para>The <firstterm>date</firstterm> command has quite a
|
|
number of <firstterm>output</firstterm> options. For
|
|
example <option>%N</option> gives the nanosecond portion
|
|
of the current time. One interesting use for this is to
|
|
generate random integers.
|
|
|
|
<programlisting>date +%N | sed -e 's/000$//' -e 's/^0//'
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
# Strip off leading and trailing zeroes, if present.
|
|
# Length of generated integer depends on
|
|
#+ how many zeroes stripped off.
|
|
|
|
# 115281032
|
|
# 63408725
|
|
# 394504284</programlisting>
|
|
</para>
|
|
|
|
<para>There are many more options (try <command>man
|
|
date</command>).</para>
|
|
|
|
<para><programlisting>date +%j
|
|
# Echoes day of the year (days elapsed since January 1).
|
|
|
|
date +%k%M
|
|
# Echoes hour and minute in 24-hour format, as a single digit string.
|
|
|
|
|
|
|
|
# The 'TZ' parameter permits overriding the default time zone.
|
|
date # Mon Mar 28 21:42:16 MST 2005
|
|
TZ=EST date # Mon Mar 28 23:42:16 EST 2005
|
|
# Thanks, Frank Kannemann and Pete Sjoberg, for the tip.
|
|
|
|
|
|
SixDaysAgo=$(date --date='6 days ago')
|
|
OneMonthAgo=$(date --date='1 month ago') # Four weeks back (not a month!)
|
|
OneYearAgo=$(date --date='1 year ago')</programlisting></para>
|
|
|
|
<para>See also <xref linkend="ex58"/> and <xref
|
|
linkend="stopwatch"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="zdumpref"/><command>zdump</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>zdump</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>time zone dump</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>time</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>time</secondary>
|
|
</indexterm>
|
|
|
|
<para>Outputs verbose timing statistics for executing a command.</para>
|
|
|
|
<para><userinput>time ls -l /</userinput> gives something
|
|
like this:</para>
|
|
|
|
<para>
|
|
<screen><computeroutput>real 0m0.067s
|
|
user 0m0.004s
|
|
sys 0m0.005s</computeroutput></screen>
|
|
</para>
|
|
|
|
<para>See also the very similar <link
|
|
linkend="timesref">times</link> command in the previous
|
|
section.</para>
|
|
|
|
<note><para>As of <link linkend="bash2ref">version 2.0</link>
|
|
of Bash, <command>time</command> became a shell reserved word,
|
|
with slightly altered behavior in a pipeline.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="touchref"/><command>touch</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>touch</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>touch</secondary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
|
|
<tip>
|
|
<para>Before doing a <link linkend="cpref">cp -u</link>
|
|
(<firstterm>copy/update</firstterm>), use
|
|
<command>touch</command> to update the time stamp of files
|
|
you don't wish overwritten.</para>
|
|
<para>As an example, if the directory <filename
|
|
class="directory">/home/bozo/tax_audit</filename> contains the
|
|
files <filename>spreadsheet-051606.data</filename>,
|
|
<filename>spreadsheet-051706.data</filename>, and
|
|
<filename>spreadsheet-051806.data</filename>, then
|
|
doing a <command>touch spreadsheet*.data</command>
|
|
will protect these files from being overwritten
|
|
by files with the same names during a
|
|
<command>cp -u /home/bozo/financial_info/spreadsheet*data
|
|
/home/bozo/tax_audit</command>.</para>
|
|
</tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="atref"/><command>at</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>at</command> job control command executes
|
|
a given set of commands at a specified time. Superficially,
|
|
it resembles <link linkend="cronref">cron</link>, however,
|
|
<command>at</command> is chiefly useful for one-time execution
|
|
of a command set.</para>
|
|
|
|
<para><userinput>at 2pm January 15</userinput> prompts for a set of
|
|
commands to execute at that time. These commands should be
|
|
shell-script compatible, since, for all practical
|
|
purposes, the user is typing in an executable shell
|
|
script a line at a time. Input terminates with a <link
|
|
linkend="ctldref">Ctl-D</link>.</para>
|
|
|
|
<para>Using either the <option>-f</option> option or input
|
|
redirection (<token><</token>), <command>at</command>
|
|
reads a command list from a file. This file is an
|
|
executable shell script, though it should, of course,
|
|
be non-interactive. Particularly clever is including the
|
|
<link linkend="runpartsref">run-parts</link> command in
|
|
the file to execute a different set of scripts.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>at 2:30 am Friday < at-jobs.list</userinput>
|
|
<computeroutput>job 2 at 2000-10-27 02:30</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="batchref"/><command>batch</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para>The <command>batch</command> job control command is similar to
|
|
<command>at</command>, but it runs a command list when the system
|
|
load drops below <literal>.8</literal>. Like
|
|
<command>at</command>, it can read commands from a file with the
|
|
<option>-f</option> option.</para>
|
|
|
|
<para><anchor id="batchprocref"/></para>
|
|
|
|
<sidebar>
|
|
<para>The concept of <firstterm>batch processing</firstterm>
|
|
dates back to the era of mainframe computers. It means
|
|
running a set of commands without user intervention.</para>
|
|
</sidebar>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="calref"/><command>cal</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>cal</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cal</secondary>
|
|
</indexterm>
|
|
<para>Prints a neatly formatted monthly calendar to
|
|
<filename>stdout</filename>. Will do current year or a large
|
|
range of past and future years.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sleepref"/><command>sleep</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>sleep</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sleep</secondary>
|
|
</indexterm>
|
|
<para>This is the shell equivalent of a <firstterm>wait
|
|
loop</firstterm>. It pauses for a specified number of
|
|
seconds, doing nothing. It can be useful for timing or
|
|
in processes running in the background, checking for
|
|
a specific event every so often (polling), as in <xref
|
|
linkend="online"/>. <programlisting>sleep 3 # Pauses 3 seconds.</programlisting>
|
|
</para>
|
|
|
|
<note><para>The <command>sleep</command> command defaults to
|
|
seconds, but minute, hours, or days may also be specified.
|
|
<programlisting>sleep 3 h # Pauses 3 hours!</programlisting>
|
|
</para></note>
|
|
|
|
<note><para>The <link linkend="watchref">watch</link> command may
|
|
be a better choice than <command>sleep</command> for running
|
|
commands at timed intervals.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="usleepref"/><command>usleep</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>usleep</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>usleep</secondary>
|
|
</indexterm>
|
|
<para><firstterm>Microsleep</firstterm> (the
|
|
<firstterm>u</firstterm> may be read as the Greek
|
|
<firstterm>mu</firstterm>, or <firstterm>micro-</firstterm>
|
|
prefix). This is the same as <command>sleep</command>,
|
|
above, but <quote>sleeps</quote> in microsecond
|
|
intervals. It can be used for fine-grained timing,
|
|
or for polling an ongoing process at very frequent
|
|
intervals.</para>
|
|
|
|
<para>
|
|
<programlisting>usleep 30 # Pauses 30 microseconds.</programlisting>
|
|
</para>
|
|
|
|
<para>This command is part of the Red Hat
|
|
<firstterm>initscripts / rc-scripts</firstterm> package.</para>
|
|
|
|
<caution><para>The <command>usleep</command> command does not
|
|
provide particularly accurate timing, and is therefore
|
|
unsuitable for critical timing loops.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="hwclockref"/><command>hwclock</command></term>
|
|
<term><anchor id="clockref"/><command>clock</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>hwclock</command> command accesses or
|
|
adjusts the machine's hardware clock. Some options
|
|
require <firstterm>root</firstterm> privileges. The
|
|
<filename>/etc/rc.d/rc.sysinit</filename> startup file
|
|
uses <command>hwclock</command> to set the system time
|
|
from the hardware clock at bootup.</para>
|
|
|
|
<para>The <command>clock</command> command is a synonym for
|
|
<command>hwclock</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Time / Date Commands -->
|
|
|
|
|
|
|
|
|
|
<sect1 id="textproc">
|
|
<title>Text Processing Commands</title>
|
|
|
|
<variablelist id="tpcommandlisting">
|
|
<title><anchor id="tpcommandlisting1"/>Commands affecting text and
|
|
text files</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sortref"/><command>sort</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>sort</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sort</secondary>
|
|
</indexterm>
|
|
<para>File sort utility, often used as a filter in a pipe. This
|
|
command sorts a <firstterm>text stream</firstterm>
|
|
or file forwards or backwards, or according to various
|
|
keys or character positions. Using the <option>-m</option>
|
|
option, it merges presorted input files. The <firstterm>info
|
|
page</firstterm> lists its many capabilities and options. See
|
|
<xref linkend="findstring"/>, <xref linkend="symlinks"/>,
|
|
and <xref linkend="makedict"/>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tsortref"/><command>tsort</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tsort</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>topological sort</secondary>
|
|
</indexterm>
|
|
|
|
<para><firstterm>Topological sort</firstterm>, reading in
|
|
pairs of whitespace-separated strings and sorting
|
|
according to input patterns. The original purpose of
|
|
<command>tsort</command> was to sort a list of dependencies
|
|
for an obsolete version of the <firstterm>ld</firstterm>
|
|
linker in an <quote>ancient</quote> version of UNIX.</para>
|
|
|
|
<para>The results of a <firstterm>tsort</firstterm> will usually
|
|
differ markedly from those of the standard
|
|
<command>sort</command> command, above.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="uniqref"/><command>uniq</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>uniq</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>uniq</secondary>
|
|
</indexterm>
|
|
<para>This filter removes duplicate lines from a sorted
|
|
file. It is often seen in a pipe coupled with
|
|
<link linkend="sortref">sort</link>.</para>
|
|
|
|
<para><programlisting>cat list-1 list-2 list-3 | sort | uniq > final.list
|
|
# Concatenates the list files,
|
|
# sorts them,
|
|
# removes duplicate lines,
|
|
# and finally writes the result to an output file.</programlisting></para>
|
|
|
|
<para>The useful <option>-c</option> option prefixes each line of
|
|
the input file with its number of occurrences.</para>
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>cat testfile</userinput>
|
|
<computeroutput>This line occurs only once.
|
|
This line occurs twice.
|
|
This line occurs twice.
|
|
This line occurs three times.
|
|
This line occurs three times.
|
|
This line occurs three times.</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>uniq -c testfile</userinput>
|
|
<computeroutput> 1 This line occurs only once.
|
|
2 This line occurs twice.
|
|
3 This line occurs three times.</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>sort testfile | uniq -c | sort -nr</userinput>
|
|
<computeroutput> 3 This line occurs three times.
|
|
2 This line occurs twice.
|
|
1 This line occurs only once.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <userinput>sort INPUTFILE | uniq -c | sort -nr</userinput>
|
|
command string produces a <firstterm>frequency
|
|
of occurrence</firstterm> listing on the
|
|
<filename>INPUTFILE</filename> file (the
|
|
<option>-nr</option> options to <command>sort</command>
|
|
cause a reverse numerical sort). This template finds
|
|
use in analysis of log files and dictionary lists, and
|
|
wherever the lexical structure of a document needs to
|
|
be examined.</para>
|
|
|
|
<example id="wf">
|
|
<title>Word Frequency Analysis</title>
|
|
<programlisting>&wf;</programlisting>
|
|
</example>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>cat testfile</userinput>
|
|
<computeroutput>This line occurs only once.
|
|
This line occurs twice.
|
|
This line occurs twice.
|
|
This line occurs three times.
|
|
This line occurs three times.
|
|
This line occurs three times.</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>./wf.sh testfile</userinput>
|
|
<computeroutput> 6 this
|
|
6 occurs
|
|
6 line
|
|
3 times
|
|
3 three
|
|
2 twice
|
|
1 only
|
|
1 once</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="expandref"/><command>expand</command></term>
|
|
<term><command>unexpand</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>expand</command> filter converts tabs to
|
|
spaces. It is often used in a <link
|
|
linkend="piperef">pipe</link>.</para>
|
|
<para>The <command>unexpand</command> filter
|
|
converts spaces to tabs. This reverses the effect of
|
|
<command>expand</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cutref"/><command>cut</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>A tool for extracting <link
|
|
linkend="fieldref">fields</link> from files. It is similar
|
|
to the <userinput>print $N</userinput> command set in <link
|
|
linkend="awkref">awk</link>, but more limited. It may be
|
|
simpler to use <firstterm>cut</firstterm> in a script than
|
|
<firstterm>awk</firstterm>. Particularly important are the
|
|
<option>-d</option> (delimiter) and <option>-f</option>
|
|
(field specifier) options.</para>
|
|
|
|
<para>Using <command>cut</command> to obtain a listing of the
|
|
mounted filesystems:
|
|
<programlisting>cut -d ' ' -f1,2 /etc/mtab</programlisting></para>
|
|
|
|
<para>Using <command>cut</command> to list the OS and kernel version:
|
|
<programlisting>uname -a | cut -d" " -f1,3,11,12</programlisting></para>
|
|
|
|
<para>Using <command>cut</command> to extract message headers from
|
|
an e-mail folder:
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>grep '^Subject:' read-messages | cut -c10-80</userinput>
|
|
<computeroutput>Re: Linux suitable for mission-critical apps?
|
|
MAKE MILLIONS WORKING AT HOME!!!
|
|
Spam complaint
|
|
Re: Spam complaint</computeroutput></screen>
|
|
</para>
|
|
|
|
<para>Using <command>cut</command> to parse a file:
|
|
<programlisting># List all the users in /etc/passwd.
|
|
|
|
FILENAME=/etc/passwd
|
|
|
|
for user in $(cut -d: -f1 $FILENAME)
|
|
do
|
|
echo $user
|
|
done
|
|
|
|
# Thanks, Oleg Philon for suggesting this.</programlisting></para>
|
|
|
|
<para><userinput>cut -d ' ' -f2,3 filename</userinput> is equivalent to
|
|
<userinput>awk -F'[ ]' '{ print $2, $3 }' filename</userinput></para>
|
|
|
|
<note>
|
|
<para>It is even possible to specify a linefeed as a
|
|
delimiter. The trick is to actually embed a linefeed
|
|
(<keycap>RETURN</keycap>) in the command sequence.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>cut -d'
|
|
' -f3,7,19 testfile</userinput>
|
|
<computeroutput>This is line 3 of testfile.
|
|
This is line 7 of testfile.
|
|
This is line 19 of testfile.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Thank you, Jaka Kranjc, for pointing this out.</para>
|
|
</note>
|
|
|
|
<para>See also <xref linkend="base"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pasteref"/><command>paste</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>Tool for merging together different files into a single,
|
|
multi-column file. In combination with
|
|
<link linkend="cutref">cut</link>, useful for creating system log
|
|
files.
|
|
</para>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>cat items</userinput>
|
|
<computeroutput>alphabet blocks
|
|
building blocks
|
|
cables</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>cat prices</userinput>
|
|
<computeroutput>$1.00/dozen
|
|
$2.50 ea.
|
|
$3.75</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>paste items prices</userinput>
|
|
<computeroutput>alphabet blocks $1.00/dozen
|
|
building blocks $2.50 ea.
|
|
cables $3.75</computeroutput></screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="joinref"/><command>join</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>join</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>join</secondary>
|
|
</indexterm>
|
|
<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 <link linkend="fieldref">field</link>
|
|
(usually a numerical label), and writes the result to
|
|
<filename>stdout</filename>. The files to be joined should
|
|
be sorted according to the tagged field for the matchups
|
|
to work properly.</para>
|
|
|
|
<para><programlisting>File: 1.data
|
|
|
|
100 Shoes
|
|
200 Laces
|
|
300 Socks</programlisting></para>
|
|
|
|
<para><programlisting>File: 2.data
|
|
|
|
100 $40.00
|
|
200 $1.00
|
|
300 $2.00</programlisting></para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>join 1.data 2.data</userinput>
|
|
<computeroutput>File: 1.data 2.data
|
|
|
|
100 Shoes $40.00
|
|
200 Laces $1.00
|
|
300 Socks $2.00</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>The tagged field appears only once in the
|
|
output.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="headref"/><command>head</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>head</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>head</secondary>
|
|
</indexterm>
|
|
<para>lists the beginning of a file to <filename>stdout</filename>.
|
|
The default is <literal>10</literal> lines, but a different
|
|
number can be specified. The command has a number of
|
|
interesting options.
|
|
|
|
<example id="scriptdetector">
|
|
<title>Which files are scripts?</title>
|
|
<programlisting>&scriptdetector;</programlisting>
|
|
</example>
|
|
|
|
<example id="rnd">
|
|
<title>Generating 10-digit random numbers</title>
|
|
<programlisting>&rnd;</programlisting>
|
|
</example>
|
|
|
|
See also <xref linkend="ex52"/>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tailref"/><command>tail</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tail</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tail</secondary>
|
|
</indexterm>
|
|
<para>lists the (tail) end of a file to <filename>stdout</filename>.
|
|
The default is <literal>10</literal> lines, but this can
|
|
be changed with the <option>-n</option> option.
|
|
Commonly used to keep track of
|
|
changes to a system logfile, using the <option>-f</option>
|
|
option, which outputs lines appended to the file.</para>
|
|
|
|
<example id="ex12">
|
|
<title>Using <firstterm>tail</firstterm> to monitor the system log</title>
|
|
<programlisting>&ex12;</programlisting>
|
|
</example>
|
|
|
|
<tip>
|
|
<para>To list a specific line of a text file,
|
|
<link linkend="piperef">pipe</link> the output of
|
|
<command>head</command> to <command>tail -n 1</command>.
|
|
For example <userinput>head -n 8 database.txt | tail
|
|
-n 1</userinput> lists the 8th line of the file
|
|
<filename>database.txt</filename>.</para>
|
|
<para>To set a variable to a given block of a text file:
|
|
<programlisting>var=$(head -n $m $filename | tail -n $n)
|
|
|
|
# filename = name of file
|
|
# m = from beginning of file, number of lines to end of block
|
|
# n = number of lines to set variable to (trim from end of block)</programlisting></para>
|
|
</tip>
|
|
|
|
<note>
|
|
<para>Newer implementations of <command>tail</command>
|
|
deprecate the older <command>tail -$LINES
|
|
filename</command> usage. The standard <command>tail -n $LINES
|
|
filename</command> is correct.</para>
|
|
</note>
|
|
|
|
<para>See also <xref linkend="ex41"/>, <xref linkend="ex52"/> and
|
|
<xref linkend="online"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="grepref"/><command>grep</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>grep</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>grep</secondary>
|
|
</indexterm>
|
|
<para>A multi-purpose file search tool that uses
|
|
<link linkend="regexref">Regular Expressions</link>.
|
|
It was originally a command/filter in the
|
|
venerable <command>ed</command> line editor:
|
|
<userinput>g/re/p</userinput> -- <firstterm>global -
|
|
regular expression - print</firstterm>.</para>
|
|
|
|
<para><cmdsynopsis>
|
|
<command>grep</command> <arg
|
|
choice="plain"><replaceable>pattern</replaceable></arg>
|
|
<arg choice="opt"
|
|
rep="repeat"><replaceable>file</replaceable></arg>
|
|
</cmdsynopsis>Search the target file(s) for
|
|
occurrences of <replaceable>pattern</replaceable>, where
|
|
<replaceable>pattern</replaceable> may be literal text
|
|
or a Regular Expression.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep '[rst]ystem.$' osinfo.txt</userinput>
|
|
<computeroutput>The GPL governs the distribution of the Linux operating system.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>If no target file(s) specified, <command>grep</command>
|
|
works as a filter on <filename>stdout</filename>, as in
|
|
a <link linkend="piperef">pipe</link>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ps ax | grep clock</userinput>
|
|
<computeroutput>765 tty1 S 0:00 xclock
|
|
901 pts/1 S 0:00 grep clock</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <option>-i</option> option causes a case-insensitive
|
|
search.</para>
|
|
|
|
<para>The <option>-w</option> option matches only whole
|
|
words.</para>
|
|
|
|
<para>The <option>-l</option> option lists only the files in which
|
|
matches were found, but not the matching lines.</para>
|
|
|
|
<para>The <option>-r</option> (recursive) option searches files in
|
|
the current working directory and all subdirectories below
|
|
it.</para>
|
|
|
|
<para>The <option>-n</option> option lists the matching lines,
|
|
together with line numbers.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep -n Linux osinfo.txt</userinput>
|
|
<computeroutput>2:This is a file containing information about Linux.
|
|
6:The GPL governs the distribution of the Linux operating system.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <option>-v</option> (or <option>--invert-match</option>)
|
|
option <firstterm>filters out</firstterm> matches.
|
|
<programlisting>grep pattern1 *.txt | grep -v pattern2
|
|
|
|
# Matches all lines in "*.txt" files containing "pattern1",
|
|
# but ***not*** "pattern2".
|
|
</programlisting></para>
|
|
|
|
<para>The <option>-c</option> (<option>--count</option>)
|
|
option gives a numerical count of matches, rather than
|
|
actually listing the matches.
|
|
|
|
<programlisting>grep -c txt *.xml # (number of occurrences of "txt" in "*.xml" files)
|
|
|
|
|
|
# grep -cz .
|
|
# ^ dot
|
|
# means count (-c) zero-separated (-z) items matching "."
|
|
# that is, non-empty ones (containing at least 1 character).
|
|
#
|
|
printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz . # 3
|
|
printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '$' # 5
|
|
printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '^' # 5
|
|
#
|
|
printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -c '$' # 9
|
|
# By default, newline chars (\n) separate items to match.
|
|
|
|
# Note that the -z option is GNU "grep" specific.
|
|
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<para>The <option>--color</option> (or <option>--colour</option>)
|
|
option marks the matching string in color (on the console
|
|
or in an <firstterm>xterm</firstterm> window). Since
|
|
<firstterm>grep</firstterm> prints out each entire line
|
|
containing the matching pattern, this lets you see exactly
|
|
<emphasis>what</emphasis> is being matched. See also
|
|
the <option>-o</option> option, which shows only the
|
|
matching portion of the line(s).</para>
|
|
|
|
|
|
<example id="fromsh">
|
|
<title>Printing out the <firstterm>From</firstterm> lines in
|
|
stored e-mail messages</title>
|
|
<programlisting>&fromsh;</programlisting>
|
|
</example>
|
|
|
|
<para>When invoked with more than one target file given,
|
|
<command>grep</command> specifies which file contains
|
|
matches.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep Linux osinfo.txt misc.txt</userinput>
|
|
<computeroutput>osinfo.txt:This is a file containing information about Linux.
|
|
osinfo.txt:The GPL governs the distribution of the Linux operating system.
|
|
misc.txt:The Linux operating system is steadily gaining in popularity.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<tip>
|
|
<para>To force <command>grep</command> to show the filename
|
|
when searching only one target file, simply give
|
|
<filename>/dev/null</filename> as the second file.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep Linux osinfo.txt /dev/null</userinput>
|
|
<computeroutput>osinfo.txt:This is a file containing information about Linux.
|
|
osinfo.txt:The GPL governs the distribution of the Linux operating system.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</tip>
|
|
|
|
|
|
<para>If there is a successful match, <command>grep</command>
|
|
returns an <link linkend="exitstatusref">exit status</link>
|
|
of 0, which makes it useful in a condition test in a
|
|
script, especially in combination with the <option>-q</option>
|
|
option to suppress output.
|
|
<programlisting>SUCCESS=0 # if grep lookup succeeds
|
|
word=Linux
|
|
filename=data.file
|
|
|
|
grep -q "$word" "$filename" # The "-q" option
|
|
#+ causes nothing to echo to stdout.
|
|
if [ $? -eq $SUCCESS ]
|
|
# if grep -q "$word" "$filename" can replace lines 5 - 7.
|
|
then
|
|
echo "$word found in $filename"
|
|
else
|
|
echo "$word not found in $filename"
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
|
|
<para><xref linkend="online"/> demonstrates how to use
|
|
<command>grep</command> to search for a word pattern in
|
|
a system logfile.</para>
|
|
|
|
|
|
<example id="grp">
|
|
<title>Emulating <firstterm>grep</firstterm> in a script</title>
|
|
<programlisting>&grp;</programlisting>
|
|
</example>
|
|
|
|
<para>How can <command>grep</command> search for two (or
|
|
more) separate patterns? What if you want
|
|
<command>grep</command> to display all lines in a file
|
|
or files that contain both <quote>pattern1</quote>
|
|
<emphasis>and</emphasis> <quote>pattern2</quote>?</para>
|
|
|
|
<para>One method is to <link
|
|
linkend="piperef">pipe</link> the result of <command>grep
|
|
pattern1</command> to <command>grep pattern2</command>.</para>
|
|
|
|
<para>For example, given the following file:</para>
|
|
|
|
<para>
|
|
<programlisting># Filename: tstfile
|
|
|
|
This is a sample file.
|
|
This is an ordinary text file.
|
|
This file does not contain any unusual text.
|
|
This file is not unusual.
|
|
Here is some text.</programlisting>
|
|
</para>
|
|
|
|
<para>Now, let's search this file for lines containing
|
|
<emphasis>both</emphasis> <quote>file</quote> and
|
|
<quote>text</quote> . . . </para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>grep file tstfile</userinput>
|
|
<computeroutput># Filename: tstfile
|
|
This is a sample file.
|
|
This is an ordinary text file.
|
|
This file does not contain any unusual text.
|
|
This file is not unusual.</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>grep file tstfile | grep text</userinput>
|
|
<computeroutput>This is an ordinary text file.
|
|
This file does not contain any unusual text.</computeroutput></screen>
|
|
|
|
<para>Now, for an interesting recreational use
|
|
of <firstterm>grep</firstterm> . . .</para>
|
|
|
|
|
|
<example id="cwsolver">
|
|
<title>Crossword puzzle solver</title>
|
|
<programlisting>&cwsolver;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para><anchor id="egrepref"/><command>egrep</command>
|
|
-- <firstterm>extended grep</firstterm> -- is the same
|
|
as <command>grep -E</command>. This uses a somewhat
|
|
different, extended set of <link linkend="regexref">Regular
|
|
Expressions</link>, which can make the search a bit more
|
|
flexible. It also allows the boolean |
|
|
(<firstterm>or</firstterm>) operator.
|
|
<screen><prompt>bash $ </prompt><userinput>egrep 'matches|Matches' file.txt</userinput>
|
|
<computeroutput>Line 1 matches.
|
|
Line 3 Matches.
|
|
Line 4 contains matches, but also Matches</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="fgrepref"/><command>fgrep</command> --
|
|
<firstterm>fast grep</firstterm> -- is the same as
|
|
<command>grep -F</command>. It does a literal string search
|
|
(no <link linkend="regexref">Regular Expressions</link>),
|
|
which generally speeds things up a bit.</para>
|
|
|
|
<note><para>On some Linux distros, <command>egrep</command> and
|
|
<command>fgrep</command> are symbolic links to, or aliases for
|
|
<command>grep</command>, but invoked with the
|
|
<option>-E</option> and <option>-F</option> options,
|
|
respectively.</para></note>
|
|
|
|
<example id="dictlookup">
|
|
<title>Looking up definitions in <citetitle
|
|
pubwork="book">Webster's 1913 Dictionary</citetitle></title>
|
|
<programlisting>&dictlookup;</programlisting>
|
|
</example>
|
|
|
|
<note><para>See also <xref linkend="qky"/> for an example
|
|
of speedy <firstterm>fgrep</firstterm> lookup on a large
|
|
text file.</para></note>
|
|
|
|
<para><anchor id="agrepref"/></para>
|
|
<para><command>agrep</command> (<firstterm>approximate
|
|
grep</firstterm>) extends the capabilities of
|
|
<command>grep</command> to approximate matching. The search
|
|
string may differ by a specified number of characters
|
|
from the resulting matches. This utility is not part of
|
|
the core Linux distribution.</para>
|
|
|
|
|
|
<para><anchor id="zegrepref"/></para>
|
|
<tip> <para>To search compressed files, use
|
|
<command>zgrep</command>, <command>zegrep</command>, or
|
|
<command>zfgrep</command>. These also work on non-compressed
|
|
files, though slower than plain <command>grep</command>,
|
|
<command>egrep</command>, <command>fgrep</command>.
|
|
They are handy for searching through a mixed set of files,
|
|
some compressed, some not.</para>
|
|
<para><anchor id="bzgrepref"/></para>
|
|
<para>To search <link linkend="bzipref">bzipped</link>
|
|
files, use <command>bzgrep</command>.</para> </tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lookref"/><command>look</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>look</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>look</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<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>
|
|
<para>Scripting languages especially suited for parsing text
|
|
files and command output. May be embedded singly or in
|
|
combination in pipes and shell scripts.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command><link linkend="sedref">sed</link></command></term>
|
|
<listitem>
|
|
<para>Non-interactive <quote>stream editor</quote>, permits using
|
|
many <command>ex</command> commands in <link
|
|
linkend="batchprocref">batch</link> mode. It finds many
|
|
uses in shell scripts.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command><link linkend="awkref">awk</link></command></term>
|
|
<listitem>
|
|
<para>Programmable file extractor and formatter, good for
|
|
manipulating and/or extracting <link
|
|
linkend="fieldref">fields</link> (columns) in structured
|
|
text files. Its syntax is similar to C.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="wcref"/><command>wc</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>wc</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>wc</secondary>
|
|
</indexterm>
|
|
|
|
<para><firstterm>wc</firstterm> gives a <quote>word
|
|
count</quote> on a file or I/O stream:
|
|
|
|
<screen><prompt>bash $ </prompt><userinput>wc /usr/share/doc/sed-4.1.2/README</userinput>
|
|
<computeroutput>13 70 447 README</computeroutput>
|
|
[13 lines 70 words 447 characters]</screen></para>
|
|
|
|
<para><userinput>wc -w</userinput> gives only the word count.</para>
|
|
<para><userinput>wc -l</userinput> gives only the line count.</para>
|
|
<para><userinput>wc -c</userinput> gives only the byte count.</para>
|
|
<para><userinput>wc -m</userinput> gives only the character count.</para>
|
|
<para><userinput>wc -L</userinput> gives only the length of the longest line.</para>
|
|
|
|
<para>Using <command>wc</command> to count how many
|
|
<filename>.txt</filename> files are in current working directory:
|
|
<programlisting>$ ls *.txt | wc -l
|
|
# Will work as long as none of the "*.txt" files
|
|
#+ have a linefeed embedded in their name.
|
|
|
|
# Alternative ways of doing this are:
|
|
# find . -maxdepth 1 -name \*.txt -print0 | grep -cz .
|
|
# (shopt -s nullglob; set -- *.txt; echo $#)
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<para>Using <command>wc</command> to total up the size of all the
|
|
files whose names begin with letters in the range d - h
|
|
<screen><prompt>bash$ </prompt><userinput>wc [d-h]* | grep total | awk '{print $3}'</userinput>
|
|
<computeroutput>71832</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Using <command>wc</command> to count the instances of the
|
|
word <quote>Linux</quote> in the main source file for
|
|
this book.
|
|
<screen><prompt>bash$ </prompt><userinput>grep Linux abs-book.xml | wc -l</userinput>
|
|
<computeroutput>138</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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tr</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tr</secondary>
|
|
</indexterm>
|
|
<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><anchor id="troptions"/></para>
|
|
<para>The <option>-d</option> option deletes a range of
|
|
characters.
|
|
<programlisting>echo "abcdef" # abcdef
|
|
echo "abcdef" | tr -d b-d # aef
|
|
|
|
|
|
tr -d 0-9 <filename
|
|
# Deletes all digits from the file "filename".</programlisting></para>
|
|
|
|
<para>The <option>--squeeze-repeats</option> (or
|
|
<option>-s</option>) option deletes all but the
|
|
first instance of a string of consecutive characters.
|
|
This option is useful for removing excess <link
|
|
linkend="whitespaceref">whitespace</link>.
|
|
|
|
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>echo "XXXXX" | tr --squeeze-repeats 'X'</userinput>
|
|
<computeroutput>X</computeroutput></screen></para>
|
|
|
|
<para>The <option>-c</option> <quote>complement</quote>
|
|
option <firstterm>inverts</firstterm> the character set to
|
|
match. With this option, <command>tr</command> acts only
|
|
upon those characters <emphasis>not</emphasis> matching
|
|
the specified set.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo "acfdeb123" | tr -c b-d +</userinput>
|
|
<computeroutput>+c+d+b++++</computeroutput></screen>
|
|
</para>
|
|
|
|
|
|
|
|
<para>Note that <command>tr</command> recognizes <link
|
|
linkend="posixref">POSIX character classes</link>.
|
|
<footnote><para>This is only true of the GNU version of
|
|
<command>tr</command>, not the generic version often found on
|
|
commercial UNIX systems.</para></footnote>
|
|
</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo "abcd2ef1" | tr '[:alpha:]' -</userinput>
|
|
<computeroutput>----2--1</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<example id="ex49">
|
|
<title><firstterm>toupper</firstterm>: Transforms a file
|
|
to all uppercase.</title>
|
|
<programlisting>&ex49;</programlisting>
|
|
</example>
|
|
|
|
|
|
<example id="lowercase">
|
|
<title><firstterm>lowercase</firstterm>: Changes all
|
|
filenames in working directory to lowercase.</title>
|
|
<programlisting>&lowercase;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="trd2u"/></para>
|
|
<example id="du">
|
|
<title><firstterm>du</firstterm>: DOS to UNIX text file conversion.</title>
|
|
<programlisting>&du;</programlisting>
|
|
</example>
|
|
|
|
<example id="rot13">
|
|
<title><firstterm>rot13</firstterm>: ultra-weak encryption.</title>
|
|
<programlisting>&rot13;</programlisting>
|
|
</example>
|
|
|
|
<example id="cryptoquote">
|
|
<title>Generating <quote>Crypto-Quote</quote> Puzzles</title>
|
|
<programlisting>&cryptoquote;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="jabh"/>Of course, <firstterm>tr</firstterm>
|
|
lends itself to <firstterm>code
|
|
obfuscation</firstterm>.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
# jabh.sh
|
|
|
|
x="wftedskaebjgdBstbdbsmnjgz"
|
|
echo $x | tr "a-z" 'oh, turtleneck Phrase Jar!'
|
|
|
|
# Based on the Wikipedia "Just another Perl hacker" article.</programlisting></para>
|
|
|
|
|
|
<para><anchor id="trvariants"/></para>
|
|
<sidebar><title><firstterm>tr</firstterm> variants</title>
|
|
<para>
|
|
The <command>tr</command> utility has two historic
|
|
variants. The BSD version does not use brackets
|
|
(<userinput>tr a-z A-Z</userinput>), but the SysV one does
|
|
(<userinput>tr '[a-z]' '[A-Z]'</userinput>). The GNU version
|
|
of <command>tr</command> resembles the BSD one.
|
|
</para>
|
|
</sidebar>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="foldref"/><command>fold</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>fold</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>fold</secondary>
|
|
</indexterm>
|
|
<para>A filter that wraps lines of input to a specified width.
|
|
This is especially useful with the <option>-s</option>
|
|
option, which breaks lines at word spaces (see <xref
|
|
linkend="ex50"/> and <xref linkend="mailformat"/>).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="fmtref"/><command>fmt</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>fmt</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>fmt</secondary>
|
|
</indexterm>
|
|
<para>Simple-minded file formatter, used as a filter in a
|
|
pipe to <quote>wrap</quote> long lines of text
|
|
output.</para>
|
|
|
|
<example id="ex50">
|
|
<title>Formatted file listing.</title>
|
|
<programlisting>&ex50;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="ex41"/>.</para>
|
|
|
|
<tip><para>A powerful alternative to <command>fmt</command> is
|
|
Kamil Toman's <command>par</command>
|
|
utility, available from <ulink
|
|
url="http://www.cs.berkeley.edu/~amc/Par/">http://www.cs.berkeley.edu/~amc/Par/</ulink>.
|
|
</para></tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="colref"/><command>col</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>col</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>reverse line feed</secondary>
|
|
</indexterm>
|
|
<para>This deceptively named filter removes reverse line feeds
|
|
from an input stream. It also attempts to replace
|
|
whitespace with equivalent tabs. The chief use of
|
|
<command>col</command> is in filtering the output
|
|
from certain text processing utilities, such as
|
|
<command>groff</command> and <command>tbl</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="columnref"/><command>column</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>column</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>column</secondary>
|
|
</indexterm>
|
|
<para>Column formatter. This filter transforms list-type
|
|
text output into a <quote>pretty-printed</quote> table
|
|
by inserting tabs at appropriate places.</para>
|
|
|
|
<example id="col">
|
|
<title>Using <firstterm>column</firstterm> to format a directory
|
|
listing</title>
|
|
<programlisting>&colm;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="colrmref"/><command>colrm</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>colrm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>colrm</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<caution><para>If the file contains tabs or nonprintable
|
|
characters, this may cause unpredictable
|
|
behavior. In such cases, consider using
|
|
<link linkend="expandref">expand</link> and
|
|
<command>unexpand</command> in a pipe preceding
|
|
<command>colrm</command>.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="nlref"/><command>nl</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>nl</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>fmt</secondary>
|
|
</indexterm>
|
|
<para>Line numbering filter: <userinput>nl filename</userinput>
|
|
lists <filename>filename</filename> to
|
|
<filename>stdout</filename>, but inserts consecutive
|
|
numbers at the beginning of each non-blank line. If
|
|
<filename>filename</filename> omitted, operates on
|
|
<filename>stdin.</filename></para>
|
|
|
|
<para>The output of <command>nl</command> is very similar to
|
|
<userinput>cat -b</userinput>, since, by default
|
|
<command>nl</command> does not list blank lines.</para>
|
|
|
|
<example id="lnum">
|
|
<title><firstterm>nl</firstterm>: A self-numbering script.</title>
|
|
<programlisting>&lnum;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="prref"/><command>pr</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>pr</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>pr</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>gettext</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>localization</secondary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>msgfmt</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>localization</secondary>
|
|
</indexterm>
|
|
<para>A program for generating binary
|
|
message catalogs. It is used for <link
|
|
linkend="localization">localization</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="iconvref"/><command>iconv</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>iconv</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>encoding</secondary>
|
|
</indexterm>
|
|
|
|
<para>A utility for converting file(s) to a different encoding
|
|
(character set). Its chief use is for <link
|
|
linkend="localization">localization</link>.</para>
|
|
|
|
<para>
|
|
<programlisting># Convert a string from UTF-8 to UTF-16 and print to the BookList
|
|
function write_utf8_string {
|
|
STRING=$1
|
|
BOOKLIST=$2
|
|
echo -n "$STRING" | iconv -f UTF8 -t UTF16 | \
|
|
cut -b 3- | tr -d \\n >> "$BOOKLIST"
|
|
}
|
|
|
|
# From Peter Knowles' "booklistgen.sh" script
|
|
#+ for converting files to Sony Librie/PRS-50X format.
|
|
# (http://booklistgensh.peterknowles.com)</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="recoderef"/><command>recode</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>recode</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>encoding</secondary>
|
|
</indexterm>
|
|
<para>Consider this a fancier version of
|
|
<command>iconv</command>, above. This very versatile utility
|
|
for converting a file to a different encoding scheme.
|
|
Note that <firstterm>recode</firstterm> is not part of the
|
|
standard Linux installation.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="texref"/><command>TeX</command></term>
|
|
<term><anchor id="gsref"/><command>gs</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para><command>TeX</command> and <command>Postscript</command>
|
|
are text markup languages used for preparing copy for
|
|
printing or formatted video display.</para>
|
|
|
|
<para><command>TeX</command> is Donald Knuth's elaborate
|
|
typsetting system. It is often convenient to write a
|
|
shell script encapsulating all the options and arguments
|
|
passed to one of these markup languages.</para>
|
|
|
|
<para><firstterm>Ghostscript</firstterm>
|
|
(<command>gs</command>) is a GPL-ed Postscript
|
|
interpreter.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="texexecref"/><command>texexec</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>texexec</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>pdf</secondary>
|
|
</indexterm>
|
|
|
|
<para>Utility for processing <firstterm>TeX</firstterm> and
|
|
<firstterm>pdf</firstterm> files. Found in
|
|
<filename class="directory">/usr/bin</filename>
|
|
on many Linux distros, it is actually a <link
|
|
linkend="shwrapper">shell wrapper</link> that
|
|
calls <link linkend="perlref">Perl</link> to invoke
|
|
<firstterm>Tex</firstterm>.</para>
|
|
|
|
<para>
|
|
<programlisting>texexec --pdfarrange --result=Concatenated.pdf *pdf
|
|
|
|
# Concatenates all the pdf files in the current working directory
|
|
#+ into the merged file, Concatenated.pdf . . .
|
|
# (The --pdfarrange option repaginates a pdf file. See also --pdfcombine.)
|
|
# The above command-line could be parameterized and put into a shell script.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="enscriptref"/><command>enscript</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>enscript</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>PostScript</secondary>
|
|
</indexterm>
|
|
<para>Utility for converting plain text file to PostScript</para>
|
|
<para>For example, <command>enscript filename.txt -p filename.ps</command>
|
|
produces the PostScript output file
|
|
<filename>filename.ps</filename>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="groffref"/><command>groff</command></term>
|
|
<term><anchor id="tblref"/><command>tbl</command></term>
|
|
<term><anchor id="eqnref"/><command>eqn</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para>Yet another text markup and display formatting language
|
|
is <command>groff</command>. This is the enhanced GNU version
|
|
of the venerable UNIX <command>roff/troff</command> display
|
|
and typesetting package. <link linkend="manref">Manpages</link>
|
|
use <command>groff</command>.</para>
|
|
|
|
<para>The <command>tbl</command> table processing utility
|
|
is considered part of <command>groff</command>, as its
|
|
function is to convert table markup into
|
|
<command>groff</command> commands.</para>
|
|
|
|
<para>The <command>eqn</command> equation processing utility
|
|
is likewise part of <command>groff</command>, and
|
|
its function is to convert equation markup into
|
|
<command>groff</command> commands.</para>
|
|
|
|
<example id="manview">
|
|
<title><firstterm>manview</firstterm>: Viewing formatted manpages</title>
|
|
<programlisting>&manview;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="maned"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lexref"/><command>lex</command></term>
|
|
<term><anchor id="yaccref"/><command>yacc</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para><anchor id="flexref"/></para>
|
|
<para>The <command>lex</command> lexical analyzer produces
|
|
programs for pattern matching. This has been replaced
|
|
by the nonproprietary <command>flex</command> on Linux
|
|
systems.</para>
|
|
<para><anchor id="bisonref"/></para>
|
|
<para>The <command>yacc</command> utility creates a
|
|
parser based on a set of specifications. This has been
|
|
replaced by the nonproprietary <command>bison</command>
|
|
on Linux systems.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Text Processing Commands -->
|
|
|
|
|
|
<sect1 id="filearchiv">
|
|
<title>File and Archiving Commands</title>
|
|
|
|
<variablelist id="faarchiving">
|
|
<title><anchor id="faarchiving1"/>Archiving</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tarref"/><command>tar</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tar</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tar</secondary>
|
|
</indexterm>
|
|
|
|
<para>The standard UNIX archiving utility.
|
|
|
|
<footnote><para>An <firstterm>archive</firstterm>,
|
|
in the sense discussed here, is simply a set of related
|
|
files stored in a single location.</para></footnote>
|
|
|
|
Originally a
|
|
<wordasword>Tape ARchiving</wordasword> program, it has
|
|
developed into a general purpose package that can handle
|
|
all manner of archiving with all types of destination
|
|
devices, ranging from tape drives to regular files to even
|
|
<filename>stdout</filename> (see <xref linkend="ex58"/>). GNU
|
|
<firstterm>tar</firstterm> has been patched to accept
|
|
various compression filters, for example: <command>tar
|
|
czvf archive_name.tar.gz *</command>, which recursively
|
|
archives and <link linkend="gzipref">gzips</link>
|
|
all files in a directory tree except <link
|
|
linkend="dotfilesref">dotfiles</link> in the current
|
|
working directory (<link linkend="pwdref">$PWD</link>).
|
|
|
|
<footnote>
|
|
<para>
|
|
A <replaceable>tar czvf ArchiveName.tar.gz *</replaceable>
|
|
<emphasis>will</emphasis> include dotfiles in
|
|
subdirectories <emphasis>below</emphasis> the current
|
|
working directory. This is an undocumented GNU
|
|
<command>tar</command> <quote>feature.</quote>
|
|
</para>
|
|
</footnote>
|
|
</para>
|
|
|
|
|
|
<para>Some useful <command>tar</command> options:
|
|
<orderedlist>
|
|
|
|
<listitem><para><option>-c</option> create (a new
|
|
archive)</para></listitem>
|
|
|
|
<listitem><para><option>-x</option> extract (files from
|
|
existing archive)</para></listitem>
|
|
|
|
<listitem>
|
|
<para><option>--delete</option> delete (files
|
|
from existing archive)</para>
|
|
<caution><para>This option will not work on magnetic tape
|
|
devices.</para></caution>
|
|
</listitem>
|
|
|
|
<listitem><para><option>-r</option> append (files to
|
|
existing archive)</para></listitem>
|
|
|
|
<listitem><para><option>-A</option> append
|
|
(<firstterm>tar</firstterm> files to
|
|
existing archive)</para></listitem>
|
|
|
|
<listitem><para><option>-t</option> list (contents of
|
|
existing archive)</para></listitem>
|
|
|
|
<listitem><para><option>-u</option> update archive</para></listitem>
|
|
|
|
<listitem><para><option>-d</option> compare archive with
|
|
specified filesystem</para></listitem>
|
|
|
|
<listitem><para><option>--after-date</option> only process
|
|
files with a date stamp <emphasis>after</emphasis>
|
|
specified date</para></listitem>
|
|
|
|
<listitem>
|
|
<para><option>-z</option> <link
|
|
linkend="gzipref">gzip</link> the archive</para>
|
|
<para>(compress or uncompress, depending on whether
|
|
combined with the <option>-c</option> or
|
|
<option>-x</option>) option</para>
|
|
</listitem>
|
|
|
|
<listitem><para><option>-j</option>
|
|
<link linkend="bzipref">bzip2</link> the
|
|
archive</para></listitem>
|
|
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<caution><para>It may be difficult to recover data from a
|
|
corrupted <firstterm>gzipped</firstterm> tar
|
|
archive. When archiving important files, make multiple
|
|
backups.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sharref"/><command>shar</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>shar</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>archive</secondary>
|
|
</indexterm>
|
|
|
|
<para><firstterm>Shell archiving</firstterm> utility.
|
|
The text and/or binary files in a shell archive are
|
|
concatenated without compression, and the resultant
|
|
archive is essentially a shell script, complete with
|
|
<token>#!/bin/sh</token> header, containing all the
|
|
necessary unarchiving commands, as well as the files
|
|
themselves. Unprintable binary characters in the target
|
|
file(s) are converted to printable ASCII characters in the
|
|
output <firstterm>shar</firstterm> file. <firstterm>Shar
|
|
archives</firstterm> still show up in Usenet newsgroups,
|
|
but otherwise <command>shar</command> has been replaced
|
|
by <command>tar</command>/<command>gzip</command>.
|
|
The <command>unshar</command> command unpacks
|
|
<firstterm>shar</firstterm> archives.</para> <para>The
|
|
<command>mailshar</command> command is a Bash script that
|
|
uses <command>shar</command> to concatenate multiple files
|
|
into a single one for e-mailing.
|
|
This script supports compression and <link
|
|
linkend="uuencoderef">uuencoding</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="arref"/><command>ar</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ar</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>archive</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rpm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>package manager</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <firstterm>Red Hat Package Manager</firstterm>, or
|
|
<command>rpm</command> utility provides a wrapper for
|
|
source or binary archives. It includes commands for
|
|
installing and checking the integrity of packages, among
|
|
other things.</para>
|
|
|
|
<para>A simple <command>rpm -i package_name.rpm</command>
|
|
usually suffices to install a package, though there are many
|
|
more options available.</para>
|
|
|
|
|
|
<tip>
|
|
<para><userinput>rpm -qf</userinput> identifies which package a
|
|
file originates from.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>rpm -qf /bin/ls</userinput>
|
|
<computeroutput>coreutils-5.2.1-31</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</tip>
|
|
|
|
<tip>
|
|
<para><userinput>rpm -qa</userinput> gives a
|
|
complete list of all installed <firstterm>rpm</firstterm> packages
|
|
on a given system. An <userinput>rpm -qa package_name</userinput>
|
|
lists only the package(s) corresponding to
|
|
<filename>package_name</filename>.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>rpm -qa</userinput>
|
|
<computeroutput>redhat-logos-1.1.3-1
|
|
glibc-2.2.4-13
|
|
cracklib-2.7-12
|
|
dosfstools-2.7-1
|
|
gdbm-1.8.0-10
|
|
ksymoops-2.4.1-1
|
|
mktemp-1.5-11
|
|
perl-5.6.0-17
|
|
reiserfs-utils-3.x.0j-2
|
|
...</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>rpm -qa docbook-utils</userinput>
|
|
<computeroutput>docbook-utils-0.6.9-2</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>rpm -qa docbook | grep docbook</userinput>
|
|
<computeroutput>docbook-dtd31-sgml-1.0-10
|
|
docbook-style-dsssl-1.64-3
|
|
docbook-dtd30-sgml-1.0-10
|
|
docbook-dtd40-sgml-1.0-11
|
|
docbook-utils-pdf-0.6.9-2
|
|
docbook-dtd41-sgml-1.0-10
|
|
docbook-utils-0.6.9-2</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cpioref"/><command>cpio</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>cpio</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cpio</secondary>
|
|
</indexterm>
|
|
<para>This specialized archiving copy command
|
|
(<command>c</command>o<command>p</command>y
|
|
<command>i</command>nput and <command>o</command>utput)
|
|
is rarely seen any more, having been supplanted by
|
|
<command>tar</command>/<command>gzip</command>. It still
|
|
has its uses, such as moving a directory tree. With an
|
|
appropriate block size (for copying) specified, it
|
|
can be appreciably faster than <command>tar</command>.</para>
|
|
|
|
<example id="ex48">
|
|
<title>Using <firstterm>cpio</firstterm> to move a directory tree</title>
|
|
<programlisting>&ex48;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rpm2cpioref"/><command>rpm2cpio</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rpm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cpio</secondary>
|
|
</indexterm>
|
|
<para>This command extracts a
|
|
<command>cpio</command> archive from an <link
|
|
linkend="rpmref">rpm</link> one.</para>
|
|
|
|
<example id="derpm">
|
|
<title>Unpacking an <firstterm>rpm</firstterm> archive</title>
|
|
<programlisting>&derpm;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="paxref"/><command>pax</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>pax</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>archive</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <firstterm>pax</firstterm>
|
|
<command>p</command>ortable <command>a</command>rchive
|
|
e<command>x</command>change toolkit facilitates periodic
|
|
file backups and is designed to be cross-compatible
|
|
between various flavors of UNIX. It was designed
|
|
to replace <link linkend="tarref">tar</link> and <link
|
|
linkend="cpioref">cpio</link>.</para>
|
|
|
|
<para>
|
|
<programlisting>pax -wf daily_backup.pax ~/linux-server/files
|
|
# Creates a tar archive of all files in the target directory.
|
|
# Note that the options to pax must be in the correct order --
|
|
#+ pax -fw has an entirely different effect.
|
|
|
|
pax -f daily_backup.pax
|
|
# Lists the files in the archive.
|
|
|
|
pax -rf daily_backup.pax ~/bsd-server/files
|
|
# Restores the backed-up files from the Linux machine
|
|
#+ onto a BSD one.</programlisting>
|
|
</para>
|
|
|
|
<para>Note that <firstterm>pax</firstterm> handles many of
|
|
the standard archiving and compression commands.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="facompression">
|
|
<title><anchor id="facompression1"/>Compression</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="gzipref"/><command>gzip</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>gzip</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>gzip</secondary>
|
|
</indexterm>
|
|
|
|
<para>The standard GNU/UNIX compression utility, replacing
|
|
the inferior and proprietary
|
|
<command>compress</command>. The corresponding decompression
|
|
command is <command>gunzip</command>, which is the equivalent of
|
|
<command>gzip -d</command>.</para>
|
|
|
|
<note><para>The <option>-c</option> option sends the output of
|
|
<command>gzip</command> to <filename>stdout</filename>. This
|
|
is useful when <link linkend="piperef">piping</link> to other
|
|
commands.</para></note>
|
|
|
|
<para><anchor id="zcatref"/></para>
|
|
<para>The <command>zcat</command> filter decompresses a
|
|
<firstterm>gzipped</firstterm> file to
|
|
<filename>stdout</filename>, as possible input to a pipe or
|
|
redirection. This is, in effect, a <command>cat</command>
|
|
command that works on compressed files (including files
|
|
processed with the older <link
|
|
linkend="compressref">compress</link>
|
|
utility). The <command>zcat</command> command is equivalent to
|
|
<command>gzip -dc</command>.</para>
|
|
|
|
|
|
<caution><para>On some commercial UNIX systems, <command>zcat</command>
|
|
is a synonym for <command>uncompress -c</command>,
|
|
and will not work on <firstterm>gzipped</firstterm>
|
|
files.</para></caution>
|
|
|
|
<para>See also <xref linkend="ex14"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="bzipref"/><command>bzip2</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>bzip2</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>bzip2</secondary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
|
|
<para>Similar to the <command>zcat</command> command,
|
|
<command>bzcat</command> decompresses a
|
|
<firstterm>bzipped2-ed</firstterm> file to
|
|
<filename>stdout</filename>.</para>
|
|
|
|
<note><para>Newer versions of <link
|
|
linkend="tarref">tar</link> have been patched with
|
|
<command>bzip2</command> support.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="compressref"/><command>compress</command></term>
|
|
<term><anchor id="uncompressref"/><command>uncompress</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>This is an older, proprietary compression
|
|
utility found in commercial UNIX distributions. The
|
|
more efficient <command>gzip</command> has largely
|
|
replaced it. Linux distributions generally include a
|
|
<command>compress</command> workalike for compatibility,
|
|
although <command>gunzip</command> can unarchive files
|
|
treated with <command>compress</command>.</para>
|
|
|
|
<tip><para>The <command>znew</command> command transforms
|
|
<firstterm>compressed</firstterm> files into
|
|
<firstterm>gzipped</firstterm> ones.</para></tip>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sqref"/><command>sq</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>sq</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sq</secondary>
|
|
</indexterm>
|
|
|
|
<para>Yet another compression (<command>sq</command>ueeze)
|
|
utility, a filter that works only on sorted
|
|
<link linkend="asciidef">ASCII</link> word lists. It
|
|
uses the standard invocation syntax for a filter,
|
|
<command>sq < input-file > output-file</command>.
|
|
Fast, but not nearly as efficient as <link
|
|
linkend="gzipref">gzip</link>. The corresponding
|
|
uncompression filter is <command>unsq</command>, invoked
|
|
like <command>sq</command>.</para>
|
|
|
|
<tip><para>The output of <command>sq</command> may be
|
|
piped to <command>gzip</command> for further
|
|
compression.</para></tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="zipref"/><command>zip</command></term>
|
|
<term><command>unzip</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>Cross-platform file archiving and compression utility
|
|
compatible with DOS <firstterm>pkzip.exe</firstterm>.
|
|
<quote>Zipped</quote> archives seem to be a more
|
|
common medium of file exchange on the Internet than
|
|
<quote>tarballs.</quote></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="unarcref"/><command>unarc</command></term>
|
|
<term><command>unarj</command></term>
|
|
<term><command>unrar</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>These Linux utilities permit unpacking archives
|
|
compressed with the DOS <firstterm>arc.exe</firstterm>,
|
|
<firstterm>arj.exe</firstterm>, and
|
|
<firstterm>rar.exe</firstterm> programs.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lzmaref"/><command>lzma</command></term>
|
|
<term><command>unlzma</command></term>
|
|
<term><command>lzcat</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lzma</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>lzma</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>unlzma</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>unlzma</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>lzcat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>lzcat</secondary>
|
|
</indexterm>
|
|
<para>Highly efficient Lempel-Ziv-Markov compression.
|
|
The syntax of <firstterm>lzma</firstterm> is similar to
|
|
that of <firstterm>gzip</firstterm>. The <ulink
|
|
url="http://www.7-zip.org/sdk.html">7-zip Website</ulink>
|
|
has more information.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="xzref"/><command>xz</command></term>
|
|
<term><command>unxz</command></term>
|
|
<term><command>xzcat</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>xz</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>xz</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>unxz</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>unxz</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>xzcat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>xzcat</secondary>
|
|
</indexterm>
|
|
<para>A new high-efficiency compression tool, backward compatible
|
|
with <firstterm>lzma</firstterm>, and with an invocation
|
|
syntax similar to <firstterm>gzip</firstterm>. For
|
|
more information, see the <ulink
|
|
url="http://en.wikipedia.org/wiki/Xz">Wikipedia
|
|
entry</ulink>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="fainformation">
|
|
<title><anchor id="fainformation1"/>File Information</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="fileref"/><command>file</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>file</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>file</secondary>
|
|
</indexterm>
|
|
|
|
<para>A utility for identifying file types. The command
|
|
<userinput>file file-name</userinput> will return a
|
|
file specification for <filename>file-name</filename>,
|
|
such as <computeroutput>ascii text</computeroutput> or
|
|
<computeroutput>data</computeroutput>. It references
|
|
the <link linkend="magnumref">magic numbers</link>
|
|
found in <filename>/usr/share/magic</filename>,
|
|
<filename>/etc/magic</filename>, or
|
|
<filename>/usr/lib/magic</filename>, depending on the
|
|
Linux/UNIX distribution.</para>
|
|
|
|
<para>The <option>-f</option> option causes
|
|
<command>file</command> to run in <link
|
|
linkend="batchprocref">batch</link> mode, to read from
|
|
a designated file a list of filenames to analyze. The
|
|
<option>-z</option> option, when used on a compressed
|
|
target file, forces an attempt to analyze the uncompressed
|
|
file type.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>file test.tar.gz</userinput>
|
|
<computeroutput>test.tar.gz: gzip compressed data, deflated,
|
|
last modified: Sun Sep 16 13:34:51 2001, os: Unix</computeroutput>
|
|
|
|
<prompt>bash </prompt><userinput>file -z test.tar.gz</userinput>
|
|
<computeroutput>test.tar.gz: GNU tar archive (gzip compressed data, deflated,
|
|
last modified: Sun Sep 16 13:34:51 2001, os: Unix)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting># Find sh and Bash scripts in a given directory:
|
|
|
|
DIRECTORY=/usr/local/bin
|
|
KEYWORD=Bourne
|
|
# Bourne and Bourne-Again shell scripts
|
|
|
|
file $DIRECTORY/* | fgrep $KEYWORD
|
|
|
|
# Output:
|
|
|
|
# /usr/local/bin/burn-cd: Bourne-Again shell script text executable
|
|
# /usr/local/bin/burnit: Bourne-Again shell script text executable
|
|
# /usr/local/bin/cassette.sh: Bourne shell script text executable
|
|
# /usr/local/bin/copy-cd: Bourne-Again shell script text executable
|
|
# . . .</programlisting>
|
|
</para>
|
|
|
|
<example id="stripc">
|
|
<title>Stripping comments from C program files</title>
|
|
<programlisting>&stripc;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whichref"/><command>which</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>which</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>which</secondary>
|
|
</indexterm>
|
|
<para><command>which command</command> gives the full path
|
|
to <quote>command.</quote> This is useful for finding
|
|
out whether a particular command or utility is installed
|
|
on the system.</para>
|
|
<para><userinput>$bash which rm</userinput>
|
|
<screen><computeroutput>/usr/bin/rm</computeroutput></screen>
|
|
</para>
|
|
<para>For an interesting use of this command, see <xref
|
|
linkend="horserace"/>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whereisref"/><command>whereis</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>whereis</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>whereis</secondary>
|
|
</indexterm>
|
|
<para>Similar to <command>which</command>, above,
|
|
<command>whereis command</command> gives the
|
|
full path to <quote>command,</quote> but also to its
|
|
<link linkend="manref">manpage</link>.</para>
|
|
<para><userinput>$bash whereis rm</userinput>
|
|
<screen><computeroutput>rm: /bin/rm /usr/share/man/man1/rm.1.bz2</computeroutput></screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whatisref"/><command>whatis</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>whatis</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>whatis</secondary>
|
|
</indexterm>
|
|
<para><command>whatis command</command> looks up
|
|
<quote>command</quote> in the
|
|
<replaceable>whatis</replaceable> database. This is useful
|
|
for identifying system commands and important configuration
|
|
files. Consider it a simplified <command>man</command>
|
|
command.</para>
|
|
<para><userinput>$bash whatis whatis</userinput>
|
|
<screen><computeroutput>whatis (1) - search the whatis database for complete words</computeroutput></screen>
|
|
</para>
|
|
|
|
<example id="what">
|
|
<title>Exploring <filename
|
|
class="directory">/usr/X11R6/bin</filename></title>
|
|
<programlisting>&what;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="fileinfo"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="vdirref"/><command>vdir</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>vdir</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ls</secondary>
|
|
</indexterm>
|
|
<para>Show a detailed directory listing. The effect is similar to
|
|
<link linkend="lsref">ls -lb</link>.</para>
|
|
<para>This is one of the GNU
|
|
<firstterm>fileutils</firstterm>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>vdir</userinput>
|
|
<computeroutput>total 10
|
|
-rw-r--r-- 1 bozo bozo 4034 Jul 18 22:04 data1.xrolo
|
|
-rw-r--r-- 1 bozo bozo 4602 May 25 13:58 data1.xrolo.bak
|
|
-rw-r--r-- 1 bozo bozo 877 Dec 17 2000 employment.xrolo</computeroutput>
|
|
|
|
<prompt>bash </prompt><userinput>ls -l</userinput>
|
|
<computeroutput>total 10
|
|
-rw-r--r-- 1 bozo bozo 4034 Jul 18 22:04 data1.xrolo
|
|
-rw-r--r-- 1 bozo bozo 4602 May 25 13:58 data1.xrolo.bak
|
|
-rw-r--r-- 1 bozo bozo 877 Dec 17 2000 employment.xrolo</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="locateref"/><command>locate</command></term>
|
|
<term><anchor id="slocateref"/><command>slocate</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>locate</command> command searches for
|
|
files using a database stored for just that purpose. The
|
|
<command>slocate</command> command is the secure version of
|
|
<command>locate</command> (which may be aliased to
|
|
<command>slocate</command>).</para>
|
|
<para><userinput>$bash locate hickson</userinput>
|
|
<screen><computeroutput>/usr/lib/xephem/catalogs/hickson.edb</computeroutput></screen></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="getfaclref"/><command>getfacl</command></term>
|
|
<term><anchor id="setfaclref"/><command>setfacl</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>getfacl</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>getfacl</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>setfacl</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>setfacl</secondary>
|
|
</indexterm>
|
|
<para>These commands <firstterm>retrieve</firstterm> or
|
|
<firstterm>set</firstterm> the <command>f</command>ile
|
|
<command>a</command>ccess <command>c</command>ontrol
|
|
<command>l</command>ist -- the <firstterm>owner</firstterm>,
|
|
<firstterm>group</firstterm>, and file permissions.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>getfacl *</userinput>
|
|
<computeroutput># file: test1.txt
|
|
# owner: bozo
|
|
# group: bozgrp
|
|
user::rw-
|
|
group::rw-
|
|
other::r--
|
|
|
|
# file: test2.txt
|
|
# owner: bozo
|
|
# group: bozgrp
|
|
user::rw-
|
|
group::rw-
|
|
other::r--</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>setfacl -m u:bozo:rw yearly_budget.csv</userinput>
|
|
<prompt>bash$ </prompt><userinput>getfacl yearly_budget.csv</userinput>
|
|
<computeroutput># file: yearly_budget.csv
|
|
# owner: accountant
|
|
# group: budgetgrp
|
|
user::rw-
|
|
user:bozo:rw-
|
|
user:accountant:rw-
|
|
group::rw-
|
|
mask::rw-
|
|
other::r--</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="readlinkref"/><command>readlink</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>readlink</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>link</secondary>
|
|
</indexterm>
|
|
<para>Disclose the file that a symbolic link points to.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>readlink /usr/bin/awk</userinput>
|
|
<computeroutput>../../bin/gawk</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="stringsref"/><command>strings</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>strings</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>strings</secondary>
|
|
</indexterm>
|
|
<para>Use the <command>strings</command> command to find
|
|
printable strings in a binary or data file. It will list
|
|
sequences of printable characters found in the target
|
|
file. This might be handy for a quick 'n dirty examination
|
|
of a core dump or for looking at an unknown graphic image
|
|
file (<userinput>strings image-file | more</userinput> might
|
|
show something like <firstterm>JFIF</firstterm>,
|
|
which would identify the file as a <firstterm>jpeg</firstterm>
|
|
graphic). In a script, you would probably
|
|
parse the output of <command>strings</command>
|
|
with <link linkend="grepref">grep</link> or <link
|
|
linkend="sedref">sed</link>. See <xref linkend="bingrep"/>
|
|
and <xref linkend="findstring"/>.</para>
|
|
|
|
<example id="wstrings">
|
|
<title>An <quote>improved</quote>
|
|
<firstterm>strings</firstterm> command</title>
|
|
<programlisting>&wstrings;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="comparisonn">
|
|
<title><anchor id="comparisonn1"/>Comparison</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="diffref"/><command>diff</command></term>
|
|
<term><command>patch</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para><command>diff</command>: flexible file comparison
|
|
utility. It compares the target files line-by-line
|
|
sequentially. In some applications, such as comparing
|
|
word dictionaries, it may be helpful to filter the
|
|
files through <link linkend="sortref">sort</link>
|
|
and <command>uniq</command> before piping them
|
|
to <command>diff</command>. <userinput>diff file-1
|
|
file-2</userinput> outputs the lines in the files that
|
|
differ, with carets showing which file each particular
|
|
line belongs to.</para>
|
|
|
|
<para>The <option>--side-by-side</option> option to
|
|
<command>diff</command> outputs each compared file, line by
|
|
line, in separate columns, with non-matching lines marked. The
|
|
<option>-c</option> and <option>-u</option> options likewise
|
|
make the output of the command easier to interpret.</para>
|
|
|
|
<para>There are available various fancy frontends for
|
|
<command>diff</command>, such as <command>sdiff</command>,
|
|
<command>wdiff</command>, <command>xdiff</command>, and
|
|
<command>mgdiff</command>. </para>
|
|
|
|
<tip><para><anchor id="differr2"/>The <command>diff</command>
|
|
command returns an exit status of <errorcode>0</errorcode>
|
|
if the compared files are identical, and
|
|
<errorcode>1</errorcode> if they differ (or
|
|
<errorcode>2</errorcode> when <firstterm>binary</firstterm>
|
|
files are being compared). This permits use of
|
|
<command>diff</command> in a test construct within a shell
|
|
script (see below).</para></tip>
|
|
|
|
|
|
<para>A common use for <command>diff</command> is generating
|
|
difference files to be used with <command>patch</command>
|
|
The <option>-e</option> option outputs files suitable
|
|
for <command>ed</command> or <command>ex</command>
|
|
scripts.</para>
|
|
|
|
|
|
<para><anchor id="patchref"/></para>
|
|
<para><command>patch</command>: flexible versioning
|
|
utility. Given a difference file generated by
|
|
<command>diff</command>, <command>patch</command> can
|
|
upgrade a previous version of a package to a newer version.
|
|
It is much more convenient to distribute a relatively
|
|
small <quote>diff</quote> file than the entire body of a
|
|
newly revised package. Kernel <quote>patches</quote> have
|
|
become the preferred method of distributing the frequent
|
|
releases of the Linux kernel.</para>
|
|
|
|
<para><programlisting>patch -p1 <patch-file
|
|
# Takes all the changes listed in 'patch-file'
|
|
# and applies them to the files referenced therein.
|
|
# This upgrades to a newer version of the package.</programlisting></para>
|
|
|
|
<para>Patching the kernel:</para>
|
|
<para><programlisting>cd /usr/src
|
|
gzip -cd patchXX.gz | patch -p0
|
|
# Upgrading kernel source using 'patch'.
|
|
# From the Linux kernel docs "README",
|
|
# by anonymous author (Alan Cox?).</programlisting></para>
|
|
|
|
|
|
|
|
<note>
|
|
<para>The <command>diff</command> command can also
|
|
recursively compare directories (for the filenames
|
|
present).</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>diff -r ~/notes1 ~/notes2</userinput>
|
|
<computeroutput>Only in /home/bozo/notes1: file02
|
|
Only in /home/bozo/notes1: file03
|
|
Only in /home/bozo/notes2: file04</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
<tip>
|
|
<para><anchor id="zdiffref"/></para>
|
|
<para>Use <command>zdiff</command> to compare
|
|
<firstterm>gzipped</firstterm> files.</para>
|
|
</tip>
|
|
|
|
<tip>
|
|
<para><anchor id="diffstatref"/></para>
|
|
<para>Use <command>diffstat</command> to create
|
|
a histogram (point-distribution graph) of output from
|
|
<command>diff</command>.</para>
|
|
</tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="diff3ref"/><command>diff3</command></term>
|
|
<term><command>merge</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>diff3</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>diff3</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>merge</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>merge</secondary>
|
|
</indexterm>
|
|
|
|
<para>An extended version of <command>diff</command> that compares
|
|
three files at a time. This command returns an exit value
|
|
of 0 upon successful execution, but unfortunately this gives
|
|
no information about the results of the comparison.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>diff3 file-1 file-2 file-3</userinput>
|
|
<computeroutput>====
|
|
1:1c
|
|
This is line 1 of "file-1".
|
|
2:1c
|
|
This is line 1 of "file-2".
|
|
3:1c
|
|
This is line 1 of "file-3"</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="mergeref"/>The <command>merge</command>
|
|
(3-way file merge) command is an interesting adjunct to
|
|
<firstterm>diff3</firstterm>. Its syntax is
|
|
<userinput>merge Mergefile file1 file2</userinput>.
|
|
The result is to output to <filename>Mergefile</filename>
|
|
the changes that lead from <filename>file1</filename>
|
|
to <filename>file2</filename>. Consider this command
|
|
a stripped-down version of <firstterm>patch</firstterm>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sdiffref"/><command>sdiff</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>sdiff</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sdiff</secondary>
|
|
</indexterm>
|
|
<para>Compare and/or edit two files in order to merge
|
|
them into an output file. Because of its interactive nature,
|
|
this command would find little use in a script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cmpref"/><command>cmp</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>cmp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cmp</secondary>
|
|
</indexterm>
|
|
<para>The <command>cmp</command> command is a simpler version of
|
|
<command>diff</command>, above. Whereas <command>diff</command>
|
|
reports the differences between two files,
|
|
<command>cmp</command> merely shows at what point they
|
|
differ.</para>
|
|
|
|
<note><para>Like <command>diff</command>, <command>cmp</command>
|
|
returns an exit status of 0 if the compared files are
|
|
identical, and 1 if they differ. This permits use in a test
|
|
construct within a shell script.</para></note>
|
|
|
|
<example id="filecomp">
|
|
<title>Using <firstterm>cmp</firstterm> to compare two files
|
|
within a script.</title>
|
|
<programlisting>&filecomp;</programlisting>
|
|
</example>
|
|
|
|
<tip><para>Use <command>zcmp</command> on
|
|
<firstterm>gzipped</firstterm> files.</para></tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="commref"/><command>comm</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>comm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>comm</secondary>
|
|
</indexterm>
|
|
<para>Versatile file comparison utility. The files must be
|
|
sorted for this to be useful.</para>
|
|
|
|
<para><command>comm
|
|
<replaceable>-options</replaceable>
|
|
<replaceable>first-file</replaceable>
|
|
<replaceable>second-file</replaceable></command></para>
|
|
|
|
<para><userinput>comm file-1 file-2</userinput> outputs three columns:
|
|
<itemizedlist>
|
|
<listitem><para>column 1 = lines unique to <filename>file-1</filename></para>
|
|
</listitem>
|
|
|
|
<listitem><para>column 2 = lines unique to <filename>file-2</filename></para>
|
|
</listitem>
|
|
|
|
<listitem><para>column 3 = lines common to both.</para>
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>The options allow suppressing output of one or more columns.
|
|
<itemizedlist>
|
|
<listitem><para><option>-1</option> suppresses column
|
|
<literal>1</literal></para>
|
|
</listitem>
|
|
<listitem><para><option>-2</option> suppresses column
|
|
<literal>2</literal></para>
|
|
</listitem>
|
|
<listitem><para><option>-3</option> suppresses column
|
|
<literal>3</literal></para>
|
|
</listitem>
|
|
<listitem><para><option>-12</option> suppresses both columns
|
|
<literal>1</literal> and <literal>2</literal>, etc.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>This command is useful for comparing
|
|
<quote>dictionaries</quote> or <firstterm>word
|
|
lists</firstterm> -- sorted text files with one word per
|
|
line.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="fautils">
|
|
<title><anchor id="fautils1"/>Utilities</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="basenameref"/><command>basename</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>basename</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>basename</secondary>
|
|
</indexterm>
|
|
<para>Strips the path information from a file name, printing
|
|
only the file name. The construction <userinput>basename
|
|
$0</userinput> lets the script know its name, that is, the name it
|
|
was invoked by. This can be used for <quote>usage</quote> messages if,
|
|
for example a script is called with missing arguments:
|
|
<programlisting>echo "Usage: `basename $0` arg1 arg2 ... argn"</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dirnameref"/><command>dirname</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>dirname</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dirname</secondary>
|
|
</indexterm>
|
|
<para>Strips the <command>basename</command> from
|
|
a filename, printing only the path information.</para>
|
|
<note>
|
|
<para><command>basename</command> and <command>dirname</command>
|
|
can operate on any arbitrary string. The argument
|
|
does not need to refer to an existing file, or
|
|
even be a filename for that matter (see <xref
|
|
linkend="daysbetween"/>).</para>
|
|
</note>
|
|
|
|
<example id="ex35">
|
|
<title><firstterm>basename</firstterm> and
|
|
<firstterm>dirname</firstterm></title>
|
|
<programlisting>&ex35;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="splitref"/><command>split</command></term>
|
|
<term><anchor id="csplitref"/><command>csplit</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para>These are utilities for splitting a file into smaller
|
|
chunks. Their usual use is for splitting up large files
|
|
in order to back them up on floppies or preparatory to
|
|
e-mailing or uploading them.</para>
|
|
|
|
<para>The <command>csplit</command> command splits a file
|
|
according to <firstterm>context</firstterm>, the split occuring
|
|
where patterns are matched.</para>
|
|
|
|
<example id="splitcopy">
|
|
<title>A script that copies itself in sections</title>
|
|
<programlisting>&splitcopy;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
|
|
<variablelist id="faencencr">
|
|
<title><anchor id="faencencr1"/>Encoding and Encryption</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sumref"/><command>sum</command></term>
|
|
<term><anchor id="cksumref"/><command>cksum</command></term>
|
|
<term><anchor id="md5sumref"/><command>md5sum</command></term>
|
|
<term><anchor id="sha1sumref"/><command>sha1sum</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>sum</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sum</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>cksum</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cksum</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>md5sum</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>md5sum</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sha1sum</secondary>
|
|
</indexterm>
|
|
<para><anchor id="checksumref"/>These are utilities for
|
|
generating <firstterm>checksums</firstterm>. A
|
|
<firstterm>checksum</firstterm> is a number
|
|
|
|
<footnote><para>The checksum may be expressed as a
|
|
<firstterm>hexadecimal</firstterm> number, or to some
|
|
other base.</para></footnote>
|
|
|
|
mathematically calculated from the contents of a file,
|
|
for the purpose of checking its integrity. A script might
|
|
refer to a list of checksums for security purposes, such
|
|
as ensuring that the contents of key system files have not
|
|
been altered or corrupted. For security applications, use
|
|
the <command>md5sum</command> (<command>m</command>essage
|
|
<command>d</command>igest <command>5</command>
|
|
check<command>sum</command>) command, or better yet, the
|
|
newer <command>sha1sum</command> (Secure Hash Algorithm).
|
|
|
|
<footnote><para>For even <emphasis>better</emphasis>
|
|
security, use the <firstterm>sha256sum</firstterm>,
|
|
<firstterm>sha512</firstterm>, and
|
|
<firstterm>sha1pass</firstterm>
|
|
commands.</para></footnote>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>cksum /boot/vmlinuz</userinput>
|
|
<computeroutput>1670054224 804083 /boot/vmlinuz</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -n "Top Secret" | cksum</userinput>
|
|
<computeroutput>3391003827 10</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>md5sum /boot/vmlinuz</userinput>
|
|
<computeroutput>0f43eccea8f09e0a0b2b5cf1dcf333ba /boot/vmlinuz</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -n "Top Secret" | md5sum</userinput>
|
|
<computeroutput>8babc97a6f62a4649716f4df8d61728f -</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<note>
|
|
<para>The <command>cksum</command> command shows the size,
|
|
in bytes, of its target, whether file or
|
|
<filename>stdout</filename>.</para>
|
|
<para>The <command>md5sum</command> and
|
|
<command>sha1sum</command> commands display a
|
|
<link linkend="dashref2">dash</link> when they receive their input from
|
|
<filename>stdout</filename>.</para>
|
|
</note>
|
|
|
|
<example id="fileintegrity">
|
|
<title>Checking file integrity</title>
|
|
<programlisting>&fileintegrity;</programlisting>
|
|
</example>
|
|
|
|
<para>Also see <xref linkend="directoryinfo"/>, <xref
|
|
linkend="horserace"/>, and <xref linkend="randstring"/> for
|
|
creative uses of the <command>md5sum</command> command.</para>
|
|
|
|
<note>
|
|
|
|
<para>
|
|
There have been reports that the 128-bit
|
|
<command>md5sum</command> can be cracked, so the more secure
|
|
160-bit <command>sha1sum</command> is a welcome new addition
|
|
to the checksum toolkit.
|
|
</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>md5sum testfile</userinput>
|
|
<computeroutput>e181e2c8720c60522c4c4c981108e367 testfile</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>sha1sum testfile</userinput>
|
|
<computeroutput>5d7425a9c08a66c3177f1e31286fa40986ffc996 testfile</computeroutput>
|
|
</screen></note>
|
|
|
|
<para>Security consultants have demonstrated that even
|
|
<command>sha1sum</command> can be compromised. Fortunately,
|
|
newer Linux distros include longer bit-length
|
|
<command>sha224sum</command>,
|
|
<command>sha256sum</command>,
|
|
<command>sha384sum</command>, and
|
|
<command>sha512sum</command> commands.</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="uuencoderef"/><command>uuencode</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>uuencode</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>uuencode</secondary>
|
|
</indexterm>
|
|
<para>This utility encodes binary files (images, sound files,
|
|
compressed files, etc.) into <link
|
|
linkend="asciidef">ASCII</link> characters, making
|
|
them suitable for transmission in the body of an
|
|
e-mail message or in a newsgroup posting. This is
|
|
especially useful where MIME (multimedia) encoding
|
|
is not available.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="uudecoderef"/><command>uudecode</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>uudecode</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>uudecode</secondary>
|
|
</indexterm>
|
|
<para>This reverses the encoding, decoding
|
|
<firstterm>uuencoded</firstterm> files back into the
|
|
original binaries.</para>
|
|
|
|
<example id="ex52">
|
|
<title>Uudecoding encoded files</title>
|
|
<programlisting>&ex52;</programlisting>
|
|
</example>
|
|
|
|
<tip><para>The <link linkend="foldref">fold -s</link> command
|
|
may be useful (possibly in a pipe) to process long uudecoded
|
|
text messages downloaded from Usenet newsgroups.</para></tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mimencoderef"/><command>mimencode</command></term>
|
|
<term><anchor id="mmencoderef"/><command>mmencode</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>mimencode</command> and
|
|
<command>mmencode</command> commands process
|
|
multimedia-encoded e-mail attachments. Although
|
|
<firstterm>mail user agents</firstterm> (such as
|
|
<firstterm>pine</firstterm> or <firstterm>kmail</firstterm>)
|
|
normally handle this automatically, these particular
|
|
utilities permit manipulating such attachments manually from
|
|
the command-line or in <link linkend="batchprocref">batch
|
|
processing mode</link> by means of a shell script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cryptref"/><command>crypt</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>crypt</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>crypt</secondary>
|
|
</indexterm>
|
|
<para>At one time, this was the standard UNIX file encryption
|
|
utility.
|
|
|
|
<footnote><para>This is a symmetric block cipher, used to
|
|
encrypt files on a single system or local network,
|
|
as opposed to the <firstterm>public key</firstterm>
|
|
cipher class, of which <firstterm>pgp</firstterm> is a
|
|
well-known example.</para></footnote>
|
|
|
|
Politically-motivated government regulations
|
|
prohibiting the export of encryption software resulted
|
|
in the disappearance of <command>crypt</command>
|
|
from much of the UNIX world, and it is still
|
|
missing from most Linux distributions. Fortunately,
|
|
programmers have come up with a number of decent
|
|
alternatives to it, among them the author's very own <ulink
|
|
url="ftp://metalab.unc.edu/pub/Linux/utils/file/cruft-0.2.tar.gz">cruft</ulink>
|
|
(see <xref linkend="encryptedpw"/>). </para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="opensslref"/><command>openssl</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>openssl</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>SSL</secondary>
|
|
</indexterm>
|
|
<para>This is an Open Source implementation of
|
|
<firstterm>Secure Sockets Layer</firstterm> encryption.
|
|
|
|
<programlisting># To encrypt a file:
|
|
openssl aes-128-ecb -salt -in file.txt -out file.encrypted \
|
|
-pass pass:my_password
|
|
# ^^^^^^^^^^^ User-selected password.
|
|
# aes-128-ecb is the encryption method chosen.
|
|
|
|
# To decrypt an openssl-encrypted file:
|
|
openssl aes-128-ecb -d -salt -in file.encrypted -out file.txt \
|
|
-pass pass:my_password
|
|
# ^^^^^^^^^^^ User-selected password.</programlisting></para>
|
|
|
|
<para><link linkend="piperef">Piping</link>
|
|
<firstterm>openssl</firstterm> to/from <link
|
|
linkend="tarref">tar</link> makes it possible to encrypt
|
|
an entire directory tree.
|
|
|
|
<programlisting># To encrypt a directory:
|
|
|
|
sourcedir="/home/bozo/testfiles"
|
|
encrfile="encr-dir.tar.gz"
|
|
password=my_secret_password
|
|
|
|
tar czvf - "$sourcedir" |
|
|
openssl des3 -salt -out "$encrfile" -pass pass:"$password"
|
|
# ^^^^ Uses des3 encryption.
|
|
# Writes encrypted file "encr-dir.tar.gz" in current working directory.
|
|
|
|
# To decrypt the resulting tarball:
|
|
openssl des3 -d -salt -in "$encrfile" -pass pass:"$password" |
|
|
tar -xzv
|
|
# Decrypts and unpacks into current working directory.</programlisting>
|
|
|
|
</para>
|
|
|
|
<para>Of course, <firstterm>openssl</firstterm> has many other uses,
|
|
such as obtaining signed <firstterm>certificates</firstterm>
|
|
for Web sites. See the <link linkend="inforef">info</link>
|
|
page.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="shredref"/><command>shred</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>shred</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>secure delete</secondary>
|
|
</indexterm>
|
|
|
|
<para>Securely erase a file by overwriting it multiple times with
|
|
random bit patterns before deleting it. This command has
|
|
the same effect as <xref linkend="blotout"/>, but does it
|
|
in a more thorough and elegant manner.</para>
|
|
|
|
<para>This is one of the GNU
|
|
<firstterm>fileutils</firstterm>.</para>
|
|
|
|
<caution><para>Advanced forensic technology may still be able to
|
|
recover the contents of a file, even after application of
|
|
<command>shred</command>.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="famisc">
|
|
<title><anchor id="famisc1"/>Miscellaneous</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mktempref"/><command>mktemp</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>temporary</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>filename</secondary>
|
|
</indexterm>
|
|
<para>Create a <firstterm>temporary file</firstterm>
|
|
|
|
<footnote><para>Creates a temporary
|
|
<firstterm>directory</firstterm> when invoked with the
|
|
<option>-d</option> option.</para></footnote>
|
|
|
|
with a <quote>unique</quote> filename. When invoked
|
|
from the command-line without additional arguments,
|
|
it creates a zero-length file in the <filename
|
|
class="directory">/tmp</filename> directory.</para>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>mktemp</userinput>
|
|
<computeroutput>/tmp/tmp.zzsvql3154</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><programlisting>PREFIX=filename
|
|
tempfile=`mktemp $PREFIX.XXXXXX`
|
|
# ^^^^^^ Need at least 6 placeholders
|
|
#+ in the filename template.
|
|
# If no filename template supplied,
|
|
#+ "tmp.XXXXXXXXXX" is the default.
|
|
|
|
echo "tempfile name = $tempfile"
|
|
# tempfile name = filename.QA2ZpY
|
|
# or something similar...
|
|
|
|
# Creates a file of that name in the current working directory
|
|
#+ with 600 file permissions.
|
|
# A "umask 177" is therefore unnecessary,
|
|
#+ but it's good programming practice nevertheless.</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="makeref"/><command>make</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>make</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>Makefile</secondary>
|
|
</indexterm>
|
|
<para><anchor id="makefileref"/></para>
|
|
<para>Utility for building and compiling binary packages.
|
|
This can also be used for any set of operations triggered
|
|
by incremental changes in source files.</para>
|
|
<para>The <firstterm>make</firstterm> command checks a
|
|
<filename>Makefile</filename>, a list of file dependencies and
|
|
operations to be carried out.</para>
|
|
<para>The <firstterm>make</firstterm> utility is, in effect,
|
|
a powerful scripting language similar in many ways to
|
|
<firstterm>Bash</firstterm>, but with the capability of
|
|
recognizing <firstterm>dependencies</firstterm>. For in-depth
|
|
coverage of this useful tool set, see the <ulink
|
|
url="http://www.gnu.org/manual/manual.html">GNU software
|
|
documentation site</ulink>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="installref"/><command>install</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>install</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>install</secondary>
|
|
</indexterm>
|
|
<para>Special purpose file copying command, similar to
|
|
<link linkend="cpref">cp</link>, but capable of
|
|
setting permissions and attributes of the copied
|
|
files. This command seems tailormade for installing
|
|
software packages, and as such it shows up frequently in
|
|
<filename>Makefiles</filename> (in the <replaceable>make
|
|
install :</replaceable> section). It could likewise prove
|
|
useful in installation scripts.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dos2unixref"/><command>dos2unix</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>dos2unix</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>file converter</secondary>
|
|
</indexterm>
|
|
<para>This utility, written by Benjamin Lin and collaborators,
|
|
converts DOS-formatted text files (lines terminated by
|
|
CR-LF) to UNIX format (lines terminated by LF only),
|
|
and <link linkend="dosnewlines">vice-versa</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ptxref"/><command>ptx</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ptx</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>index</secondary>
|
|
</indexterm>
|
|
<para>The <command>ptx [targetfile]</command> command
|
|
outputs a permuted index (cross-reference list) of the
|
|
targetfile. This may be further filtered and formatted in a
|
|
pipe, if necessary.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="moreref"/><command>more</command></term>
|
|
<term><anchor id="lessref"/><command>less</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para>Pagers that display a text file or stream to
|
|
<filename>stdout</filename>, one screenful at a time.
|
|
These may be used to filter the output of
|
|
<filename>stdout</filename> . . . or of a script.</para>
|
|
|
|
<para>
|
|
An interesting application of <firstterm>more</firstterm>
|
|
is to <quote>test drive</quote> a command sequence,
|
|
to forestall potentially unpleasant consequences.
|
|
<programlisting>ls /home/bozo | awk '{print "rm -rf " $1}' | more
|
|
# ^^^^
|
|
|
|
# Testing the effect of the following (disastrous) command-line:
|
|
# ls /home/bozo | awk '{print "rm -rf " $1}' | sh
|
|
# Hand off to the shell to execute . . . ^^</programlisting>
|
|
</para>
|
|
|
|
<para>The <firstterm>less</firstterm> pager has the
|
|
interesting property of doing a formatted display of
|
|
<firstterm>man page</firstterm> source. See <xref
|
|
linkend="maned"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End File and Archiving Commands -->
|
|
|
|
|
|
|
|
<sect1 id="communications">
|
|
<title>Communications Commands</title>
|
|
|
|
<para>Certain of the following commands find use in
|
|
network data transfer and analysis, as well as in
|
|
<link linkend="cspammers">chasing spammers</link>.</para>
|
|
|
|
<variablelist id="communinfo">
|
|
<title><anchor id="communinfo1"/>Information and Statistics</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="hostref"/><command>host</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>host</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>host</secondary>
|
|
</indexterm>
|
|
<para>Searches for information about an Internet host by name or
|
|
IP address, using DNS.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>host surfacemail.com</userinput>
|
|
<computeroutput>surfacemail.com. has address 202.92.42.236</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ipcalcref"/><command>ipcalc</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ipcalc</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ipcalc</secondary>
|
|
</indexterm>
|
|
<para>Displays IP information for a host.
|
|
With the <option>-h</option> option,
|
|
<command>ipcalc</command> does a reverse DNS lookup, finding
|
|
the name of the host (server) from the IP address.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ipcalc -h 202.92.42.236</userinput>
|
|
<computeroutput>HOSTNAME=surfacemail.com</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="nslookupref"/><command>nslookup</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>nslookup</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>name server lookup</secondary>
|
|
</indexterm>
|
|
|
|
<para>Do an Internet <quote>name server lookup</quote>
|
|
on a host by IP address. This is essentially equivalent
|
|
to <command>ipcalc -h</command> or <command>dig -x
|
|
</command>. The command may be run either interactively
|
|
or noninteractively, i.e., from within a script.</para>
|
|
|
|
<para>The <command>nslookup</command> command has allegedly
|
|
been <quote>deprecated,</quote> but it is still useful.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>nslookup -sil 66.97.104.180</userinput>
|
|
<computeroutput>nslookup kuhleersparnis.ch
|
|
Server: 135.116.137.2
|
|
Address: 135.116.137.2#53
|
|
|
|
Non-authoritative answer:
|
|
Name: kuhleersparnis.ch</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="digref"/><command>dig</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>dig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>domain information groper</secondary>
|
|
</indexterm>
|
|
|
|
<para><command>D</command>omain <command>I</command>nformation
|
|
<command>G</command>roper. Similar to
|
|
<command>nslookup</command>, <firstterm>dig</firstterm> does
|
|
an Internet <firstterm>name server lookup</firstterm> on a host.
|
|
May be run from the command-line or from within a script.</para>
|
|
|
|
<para>Some interesting options to <firstterm>dig</firstterm> are
|
|
<option>+time=N</option> for setting a query timeout to
|
|
<parameter>N</parameter> seconds, <option>+nofail</option> for
|
|
continuing to query servers until a reply is received, and
|
|
<option>-x</option> for doing a reverse address lookup.</para>
|
|
|
|
<para>Compare the output of <command>dig -x</command> with
|
|
<command>ipcalc -h</command> and
|
|
<command>nslookup</command>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>dig -x 81.9.6.2</userinput>
|
|
<computeroutput>;; Got answer:
|
|
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 11649
|
|
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
|
|
|
|
;; QUESTION SECTION:
|
|
;2.6.9.81.in-addr.arpa. IN PTR
|
|
|
|
;; AUTHORITY SECTION:
|
|
6.9.81.in-addr.arpa. 3600 IN SOA ns.eltel.net. noc.eltel.net.
|
|
2002031705 900 600 86400 3600
|
|
|
|
;; Query time: 537 msec
|
|
;; SERVER: 135.116.137.2#53(135.116.137.2)
|
|
;; WHEN: Wed Jun 26 08:35:24 2002
|
|
;; MSG SIZE rcvd: 91</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="spamlookup_0"/></para>
|
|
<example id="spamlookup">
|
|
<title>Finding out where to report a spammer</title>
|
|
<programlisting>&spamlookup;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="isspammer_0"/></para>
|
|
<example id="isspammer">
|
|
<title>Analyzing a spam domain</title>
|
|
<programlisting>&isspammer;</programlisting>
|
|
</example>
|
|
|
|
<para>For a much more elaborate version of the above script, see
|
|
<xref linkend="isspammer2"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tracerouteref"/><command>traceroute</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>traceroute</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>traceroute</secondary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ping</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ping</secondary>
|
|
</indexterm>
|
|
|
|
<para>Broadcast an <replaceable>ICMP
|
|
ECHO_REQUEST</replaceable> packet to another machine,
|
|
either on a local or remote network. This is a
|
|
diagnostic tool for testing network connections,
|
|
and it should be used with caution.</para>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ping localhost</userinput>
|
|
<computeroutput>PING localhost.localdomain (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data.
|
|
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=255 time=709 usec
|
|
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=255 time=286 usec
|
|
|
|
--- localhost.localdomain ping statistics ---
|
|
2 packets transmitted, 2 packets received, 0% packet loss
|
|
round-trip min/avg/max/mdev = 0.286/0.497/0.709/0.212 ms</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>A successful <firstterm>ping</firstterm> returns
|
|
an <link linkend="exitstatusref">exit status</link> of
|
|
<errorcode>0</errorcode>. This can be tested for in a
|
|
script.</para>
|
|
<para><anchor id="ping0"/></para>
|
|
|
|
<para><programlisting> HNAME=news-15.net # Notorious spammer.
|
|
# HNAME=$HOST # Debug: test for localhost.
|
|
count=2 # Send only two pings.
|
|
|
|
if [[ `ping -c $count "$HNAME"` ]]
|
|
then
|
|
echo ""$HNAME" still up and broadcasting spam your way."
|
|
else
|
|
echo ""$HNAME" seems to be down. Pity."
|
|
fi</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whoisref"/><command>whois</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>whois</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>domain name server</secondary>
|
|
</indexterm>
|
|
<para>Perform a DNS (Domain Name System) lookup.
|
|
The <option>-h</option> option permits specifying which
|
|
particular <firstterm>whois</firstterm> server to query. See
|
|
<xref linkend="ex18"/> and <xref linkend="spamlookup"/>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="fingerref"/><command>finger</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>finger</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>finger</secondary>
|
|
</indexterm>
|
|
|
|
<para>Retrieve information about users on a
|
|
network. Optionally, this command can display
|
|
a user's <filename>~/.plan</filename>,
|
|
<filename>~/.project</filename>, and
|
|
<filename>~/.forward</filename> files, if present.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>finger</userinput>
|
|
<computeroutput>Login Name Tty Idle Login Time Office Office Phone
|
|
bozo Bozo Bozeman tty1 8 Jun 25 16:59 (:0)
|
|
bozo Bozo Bozeman ttyp0 Jun 25 16:59 (:0.0)
|
|
bozo Bozo Bozeman ttyp1 Jun 25 17:07 (:0.0)</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>finger bozo</userinput>
|
|
<computeroutput>Login: bozo Name: Bozo Bozeman
|
|
Directory: /home/bozo Shell: /bin/bash
|
|
Office: 2355 Clown St., 543-1234
|
|
On since Fri Aug 31 20:13 (MST) on tty1 1 hour 38 minutes idle
|
|
On since Fri Aug 31 20:13 (MST) on pts/0 12 seconds idle
|
|
On since Fri Aug 31 20:13 (MST) on pts/1
|
|
On since Fri Aug 31 20:31 (MST) on pts/2 1 hour 16 minutes idle
|
|
Mail last read Tue Jul 3 10:08 2007 (MST)
|
|
No Plan.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Out of security considerations, many networks disable
|
|
<command>finger</command> and its associated daemon.
|
|
<footnote>
|
|
<para><anchor id="daemonref"/></para>
|
|
<para>A <firstterm>daemon</firstterm> is a background
|
|
process not attached to a terminal session. Daemons
|
|
perform designated services either at specified times
|
|
or explicitly triggered by certain events.</para>
|
|
<para>The word <quote>daemon</quote> means ghost in
|
|
Greek, and there is certainly something mysterious,
|
|
almost supernatural, about the way UNIX daemons
|
|
wander about behind the scenes, silently carrying
|
|
out their appointed tasks.</para>
|
|
</footnote>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="chfnref"/><command>chfn</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>chfn</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>finger</secondary>
|
|
</indexterm>
|
|
<para>Change information disclosed by the
|
|
<command>finger</command> command.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="vrfyref"/><command>vrfy</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>vrfy</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>vrfy</secondary>
|
|
</indexterm>
|
|
<para>Verify an Internet e-mail address.</para>
|
|
|
|
<para>This command seems to be missing from newer Linux
|
|
distros.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="commremote">
|
|
<title><anchor id="commremote1"/>Remote Host Access</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rxref"/><command>sx</command></term>
|
|
<term><command>rx</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>sx</command> and <command>rx</command>
|
|
command set serves to transfer files to and from a remote
|
|
host using the <firstterm>xmodem</firstterm> protocol. These
|
|
are generally part of a communications package, such as
|
|
<command>minicom</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rzref"/><command>sz</command></term>
|
|
<term><command>rz</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>sz</command> and <command>rz</command>
|
|
command set serves to transfer files to and from a remote
|
|
host using the <firstterm>zmodem</firstterm> protocol.
|
|
<firstterm>Zmodem</firstterm> has certain advantages over
|
|
<firstterm>xmodem</firstterm>, such as faster transmission
|
|
rate and resumption of interrupted file transfers.
|
|
Like <command>sx</command> and <command>rx</command>,
|
|
these are generally part of a communications package.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ftpref"/><command>ftp</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ftp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>file transfer</secondary>
|
|
</indexterm>
|
|
<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"/> and <xref
|
|
linkend="encryptedpw"/>).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="uucpref"/><command>uucp</command></term>
|
|
<term><anchor id="uuxref"/><command>uux</command></term>
|
|
<term><anchor id="curef"/><command>cu</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>uucp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>uucp</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>uux</primary>
|
|
<secondary>unix to unix execute</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>cu</primary>
|
|
<secondary>call up</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>uucp</secondary>
|
|
</indexterm>
|
|
|
|
<para><command>uucp</command>: <firstterm>UNIX to UNIX
|
|
copy</firstterm>. This is a communications package for
|
|
transferring files between UNIX servers. A shell script
|
|
is an effective way to handle a <command>uucp</command>
|
|
command sequence.</para>
|
|
|
|
<para>Since the advent of the Internet and e-mail,
|
|
<command>uucp</command> seems to have faded into obscurity,
|
|
but it still exists and remains perfectly workable in
|
|
situations where an Internet connection is not available
|
|
or appropriate. The advantage of <command>uucp</command>
|
|
is that it is fault-tolerant, so even if there is a service
|
|
interruption the copy operation will resume where it left
|
|
off when the connection is restored.</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para><command>uux</command>: <firstterm>UNIX to UNIX
|
|
execute</firstterm>. Execute a command on a remote system.
|
|
This command is part of the <command>uucp</command>
|
|
package.</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para><command>cu</command>: <command>C</command>all
|
|
<command>U</command>p a remote system and connect as a
|
|
simple terminal. It is a sort of dumbed-down version of
|
|
<link linkend="telnetref">telnet</link>. This command is
|
|
part of the <command>uucp</command> package.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="telnetref"/><command>telnet</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>telnet</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>telnet</secondary>
|
|
</indexterm>
|
|
<para>Utility and protocol for connecting to a remote host.</para>
|
|
<caution><para>The <firstterm>telnet</firstterm> protocol
|
|
contains security holes and should therefore probably be
|
|
avoided. Its use within a shell script is
|
|
<emphasis>not</emphasis> recommended.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="wgetref"/><command>wget</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>wget</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>download</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <command>wget</command> utility
|
|
<firstterm>noninteractively</firstterm> retrieves or
|
|
downloads files from a Web or ftp site. It works well in a
|
|
script.</para>
|
|
|
|
<para><programlisting>wget -p http://www.xyz23.com/file01.html
|
|
# The -p or --page-requisite option causes wget to fetch all files
|
|
#+ required to display the specified page.
|
|
|
|
wget -r ftp://ftp.xyz24.net/~bozo/project_files/ -O $SAVEFILE
|
|
# The -r option recursively follows and retrieves all links
|
|
#+ on the specified site.
|
|
|
|
wget -c ftp://ftp.xyz25.net/bozofiles/filename.tar.bz2
|
|
# The -c option lets wget resume an interrupted download.
|
|
# This works with ftp servers and many HTTP sites.</programlisting></para>
|
|
|
|
<example id="quotefetch">
|
|
<title>Getting a stock quote</title>
|
|
<programlisting>"efetch;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>See also <xref linkend="wgetter2"/> and <xref
|
|
linkend="bashpodder"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lynxref"/><command>lynx</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lynx</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>browser</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <command>lynx</command> Web and file browser
|
|
can be used inside a script (with the
|
|
<option>-dump</option> option) to retrieve a file from a Web or
|
|
ftp site noninteractively.</para>
|
|
|
|
<para>
|
|
<programlisting>lynx -dump http://www.xyz23.com/file01.html >$SAVEFILE</programlisting>
|
|
</para>
|
|
|
|
<para>With the <option>-traversal</option> option,
|
|
<command>lynx</command> starts at the HTTP URL specified
|
|
as an argument, then <quote>crawls</quote> through all
|
|
links located on that particular server. Used together
|
|
with the <option>-crawl</option> option, outputs page text
|
|
to a log file.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rloginref"/><command>rlogin</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rlogin</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>remote login</secondary>
|
|
</indexterm>
|
|
<para><replaceable>Remote login</replaceable>, initates a
|
|
session on a remote host. This command has security issues,
|
|
so use <link linkend="sshref">ssh</link> instead.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rshref"/><command>rsh</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rsh</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>remote shell</secondary>
|
|
</indexterm>
|
|
<para><replaceable>Remote shell</replaceable>, executes
|
|
command(s) on a remote host. This has security issues,
|
|
so use <command>ssh</command> instead.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rcpref"/><command>rcp</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rcp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>remote copy</secondary>
|
|
</indexterm>
|
|
<para><replaceable>Remote copy</replaceable>, copies files
|
|
between two different networked machines.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rsyncref"/><command>rsync</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rsync</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>remote update</secondary>
|
|
</indexterm>
|
|
|
|
<para><replaceable>Remote synchronize</replaceable>, updates
|
|
(synchronizes) files
|
|
between two different networked machines.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>rsync -a ~/sourcedir/*txt /node1/subdirectory/</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<example id="fc4upd">
|
|
<title>Updating FC4</title>
|
|
<programlisting>&fc4upd;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="nightlybackup"/>.</para>
|
|
|
|
<note><para>Using <link linkend="rcpref">rcp</link>, <link
|
|
linkend="rsyncref">rsync</link>, and similar
|
|
utilities with security implications in a shell
|
|
script may not be advisable. Consider, instead, using
|
|
<command>ssh</command>, <link linkend="scpref">scp</link>,
|
|
or an <command>expect</command> script.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sshref"/><command>ssh</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ssh</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>secure shell</secondary>
|
|
</indexterm>
|
|
<para><replaceable>Secure shell</replaceable>, logs onto
|
|
a remote host and executes commands there. This
|
|
secure replacement for <command>telnet</command>,
|
|
<command>rlogin</command>, <command>rcp</command>, and
|
|
<command>rsh</command> uses identity authentication
|
|
and encryption. See its <link linkend="manref">manpage</link>
|
|
for details.</para>
|
|
|
|
<example id="remote">
|
|
<title>Using <firstterm>ssh</firstterm></title>
|
|
<programlisting>&remote;</programlisting>
|
|
</example>
|
|
|
|
<caution>
|
|
<para>Within a loop, <command>ssh</command> may cause
|
|
unexpected behavior. According to a <ulink
|
|
url="http://groups-beta.google.com/group/comp.unix.shell/msg/dcb446b5fff7d230">
|
|
Usenet post</ulink> in the comp.unix shell archives,
|
|
<command>ssh</command> inherits the loop's
|
|
<filename>stdin</filename>. To remedy this, pass
|
|
<command>ssh</command> either the <option>-n</option>
|
|
or <option>-f</option> option.</para>
|
|
<para>Thanks, Jason Bechtel, for pointing this out.</para>
|
|
</caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="scpref"/><command>scp</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>scp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>secure copy</secondary>
|
|
</indexterm>
|
|
<para><replaceable>Secure copy</replaceable>, similar in
|
|
function to <command>rcp</command>, copies files between
|
|
two different networked machines, but does so using
|
|
authentication, and with a security level similar to
|
|
<command>ssh</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="commlocal">
|
|
<title><anchor id="commlocal1"/>Local Network</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="writeref"/><command>write</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>write</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>write</secondary>
|
|
</indexterm>
|
|
<para>This is a utility for terminal-to-terminal communication.
|
|
It allows sending lines from your terminal (console or
|
|
<firstterm>xterm</firstterm>) to that of another user. The
|
|
<link linkend="mesgref">mesg</link> command may, of course,
|
|
be used to disable write access to a terminal</para>
|
|
|
|
<para>Since <command>write</command> is interactive, it
|
|
would not normally find use in a script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="netconfigref"/><command>netconfig</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>netconfig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>network</secondary>
|
|
</indexterm>
|
|
<para>A command-line utility for configuring a network adapter
|
|
(using <firstterm>DHCP</firstterm>). This command is native
|
|
to Red Hat centric Linux distros.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="commmail">
|
|
<title><anchor id="commmail1"/>Mail</title>
|
|
|
|
<varlistentry>
|
|
<term><command>mail</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mail</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mail</secondary>
|
|
</indexterm>
|
|
|
|
<para>Send or read e-mail messages.</para>
|
|
|
|
<para>This stripped-down command-line mail client
|
|
works fine as a command embedded in a script.</para>
|
|
|
|
<example id="selfmailer">
|
|
<title>A script that mails itself</title>
|
|
<programlisting>&selfmailer;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mailtoref"/><command>mailto</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mailto</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>MIME mail</secondary>
|
|
</indexterm>
|
|
<para>Similar to the <command>mail</command> command,
|
|
<command>mailto</command> sends e-mail messages
|
|
from the command-line or in a script. However,
|
|
<command>mailto</command> also permits sending MIME
|
|
(multimedia) messages.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mailstatsref"/><command>mailstats</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mailstats</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>statistics</secondary>
|
|
</indexterm>
|
|
<para>Show <firstterm>mail statistics</firstterm>. This command
|
|
may be invoked only by <firstterm>root</firstterm>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>root# </prompt><userinput>mailstats</userinput>
|
|
<computeroutput>Statistics from Tue Jan 1 20:32:08 2008
|
|
M msgsfr bytes_from msgsto bytes_to msgsrej msgsdis msgsqur Mailer
|
|
4 1682 24118K 0 0K 0 0 0 esmtp
|
|
9 212 640K 1894 25131K 0 0 0 local
|
|
=====================================================================
|
|
T 1894 24758K 1894 25131K 0 0 0
|
|
C 414 0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="vacationref"/><command>vacation</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>vacation</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mail</secondary>
|
|
</indexterm>
|
|
<para>This utility automatically replies to e-mails that
|
|
the intended recipient is on vacation and temporarily
|
|
unavailable. It runs on a network, in conjunction with
|
|
<command>sendmail</command>, and is not applicable to a
|
|
dial-up POPmail account.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Communications Commands -->
|
|
|
|
|
|
|
|
<sect1 id="terminalccmds">
|
|
<title>Terminal Control Commands</title>
|
|
|
|
<variablelist id="termcommandlisting">
|
|
<title><anchor id="termcommandlisting1"/>Command affecting the console
|
|
or terminal</title>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tputref"/><command>tput</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tput</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>terminal</secondary>
|
|
</indexterm>
|
|
|
|
<para>Initialize terminal and/or fetch information about it from
|
|
<database>terminfo</database> data. Various options permit
|
|
certain terminal operations: <command>tput clear</command>
|
|
is the equivalent of <link linkend="clearref">clear</link>;
|
|
<command>tput reset</command> is the equivalent
|
|
of <link linkend="resetref">reset</link>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>tput longname</userinput>
|
|
<computeroutput>xterm terminal emulator (X Window System)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Issuing a <command>tput cup X Y</command> moves
|
|
the cursor to the (X,Y) coordinates in the current
|
|
terminal. A <command>clear</command> to erase the terminal
|
|
screen would normally precede this.</para>
|
|
|
|
|
|
<para>
|
|
|
|
Some interesting options to <firstterm>tput</firstterm> are:
|
|
|
|
<itemizedlist>
|
|
<listitem><para><option>bold</option>, for high-intensity
|
|
text</para></listitem>
|
|
<listitem><para><option>smul</option>, to underline text
|
|
in the terminal</para></listitem>
|
|
<listitem><para><option>smso</option>, to render text in
|
|
reverse</para></listitem>
|
|
<listitem><para><option>sgr0</option>, to reset the terminal
|
|
parameters (to normal), without clearing the
|
|
screen</para></listitem>
|
|
</itemizedlist>
|
|
|
|
</para>
|
|
|
|
|
|
<para>Example scripts using <firstterm>tput</firstterm>:
|
|
<orderedlist id="tputexamples">
|
|
<listitem><para><xref linkend="colorecho"/></para></listitem>
|
|
<listitem><para><xref linkend="ex30a"/></para></listitem>
|
|
<listitem><para><xref linkend="homework"/></para></listitem>
|
|
<listitem><para><xref linkend="nim"/></para></listitem>
|
|
<listitem><para><xref linkend="poem"/></para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<para>Note that <link linkend="sttyref">stty</link> offers
|
|
a more powerful command set for controlling a terminal.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="infocmpref"/><command>infocmp</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>infocmp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>terminal</secondary>
|
|
</indexterm>
|
|
|
|
<para>This command prints out extensive information about the
|
|
current terminal. It references the
|
|
<firstterm>terminfo</firstterm> database.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>infocmp</userinput>
|
|
<computeroutput># Reconstructed via infocmp from file:
|
|
/usr/share/terminfo/r/rxvt
|
|
rxvt|rxvt terminal emulator (X Window System),
|
|
am, bce, eo, km, mir, msgr, xenl, xon,
|
|
colors#8, cols#80, it#8, lines#24, pairs#64,
|
|
acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
|
|
bel=^G, blink=\E[5m, bold=\E[1m,
|
|
civis=\E[?25l,
|
|
clear=\E[H\E[2J, cnorm=\E[?25h, cr=^M,
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="resetref"/><command>reset</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>reset</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>reset</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>clear</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>clear</secondary>
|
|
</indexterm>
|
|
<para>The <command>clear</command> command simply clears
|
|
the text screen at the console or in an
|
|
<firstterm>xterm</firstterm>. The prompt and cursor
|
|
reappear at the upper lefthand corner of the screen or
|
|
xterm window. This command may be used either at the command
|
|
line or in a script. See <xref linkend="ex30"/>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="resizeref"/><command>resize</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>resize</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>resize</secondary>
|
|
</indexterm>
|
|
<para>Echoes commands necessary to set <varname>$TERM</varname>
|
|
and <varname>$TERMCAP</varname> to duplicate the
|
|
<firstterm>size</firstterm> (dimensions) of the current
|
|
terminal.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>resize</userinput>
|
|
<computeroutput>set noglob;
|
|
setenv COLUMNS '80';
|
|
setenv LINES '24';
|
|
unset noglob;</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="scriptref"/><command>script</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>script</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>script</secondary>
|
|
</indexterm>
|
|
<para>This utility records (saves to a file) all the user keystrokes at
|
|
the command-line in a console or an xterm window. This, in effect,
|
|
creates a record of a session.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Terminal Control Commands -->
|
|
|
|
|
|
<sect1 id="mathc">
|
|
<title>Math Commands</title>
|
|
|
|
<variablelist id="mathcommandlisting">
|
|
<title><anchor id="mathcommandlisting1"/><quote>Doing the
|
|
numbers</quote></title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="factorref"/><command>factor</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>factor</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>factor</secondary>
|
|
</indexterm>
|
|
<para>Decompose an integer into prime factors.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>factor 27417</userinput>
|
|
<computeroutput>27417: 3 13 19 37</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<example id="primes2">
|
|
<title>Generating prime numbers</title>
|
|
<programlisting>&primes2;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="bcref"/><command>bc</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>bc</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>bc</secondary>
|
|
</indexterm>
|
|
|
|
<para>Bash can't handle floating point calculations, and
|
|
it lacks operators for certain important mathematical
|
|
functions. Fortunately, <command>bc</command> gallops 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. It has a syntax vaguely resembling
|
|
<command>C</command>.</para>
|
|
|
|
<para>Since it is a fairly well-behaved UNIX utility, and may
|
|
therefore be used in a <link linkend="piperef">pipe</link>,
|
|
<command>bc</command> comes in handy in scripts.</para>
|
|
|
|
<para><anchor id="bctemplate"/></para>
|
|
<para>Here is a simple template for using
|
|
<command>bc</command> to calculate a script
|
|
variable. This uses <link linkend="commandsubref">command
|
|
substitution</link>.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<userinput>variable=$(echo "OPTIONS; OPERATIONS" | bc)</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="monthlypmt0"/></para>
|
|
<example id="monthlypmt">
|
|
<title>Monthly Payment on a Mortgage</title>
|
|
<programlisting>&monthlypmt;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="base0"/></para>
|
|
<example id="base">
|
|
<title>Base Conversion</title>
|
|
<programlisting>&base;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="bcheredoc"/></para>
|
|
<para>An alternate method of invoking <command>bc</command>
|
|
involves using a <link linkend="heredocref">here
|
|
document</link> embedded within a <link
|
|
linkend="commandsubref">command substitution</link>
|
|
block. This is especially appropriate when a script
|
|
needs to pass a list of options and commands to
|
|
<command>bc</command>.</para>
|
|
|
|
<para>
|
|
<programlisting>variable=`bc << LIMIT_STRING
|
|
options
|
|
statements
|
|
operations
|
|
LIMIT_STRING
|
|
`
|
|
|
|
...or...
|
|
|
|
|
|
variable=$(bc << LIMIT_STRING
|
|
options
|
|
statements
|
|
operations
|
|
LIMIT_STRING
|
|
)</programlisting>
|
|
</para>
|
|
|
|
|
|
<example id="altbc">
|
|
<title>Invoking <firstterm>bc</firstterm> using a <firstterm>here
|
|
document</firstterm></title>
|
|
<programlisting>&altbc;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="cannonref"/></para>
|
|
<example id="cannon">
|
|
<title>Calculating PI</title>
|
|
<programlisting>&cannon;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="stddev"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dcref"/><command>dc</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>dc</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dc</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <command>dc</command> (<command>d</command>esk
|
|
<command>c</command>alculator) utility is <link
|
|
linkend="stackdefref">stack-oriented</link>
|
|
and uses RPN (<firstterm>Reverse Polish Notation</firstterm>).
|
|
Like <command>bc</command>, it has much of the power of
|
|
a programming language.</para>
|
|
|
|
<para>Similar to the procedure with <command>bc</command>,
|
|
<link linkend="echoref">echo</link> a command-string
|
|
to <command>dc</command>.</para>
|
|
|
|
<para>
|
|
<programlisting>echo "[Printing a string ... ]P" | dc
|
|
# The P command prints the string between the preceding brackets.
|
|
|
|
# And now for some simple arithmetic.
|
|
echo "7 8 * p" | dc # 56
|
|
# Pushes 7, then 8 onto the stack,
|
|
#+ multiplies ("*" operator), then prints the result ("p" operator).</programlisting>
|
|
</para>
|
|
|
|
<para>Most persons avoid <command>dc</command>, because
|
|
of its non-intuitive input and rather cryptic
|
|
operators. Yet, it has its uses.</para>
|
|
|
|
<example id="hexconvert">
|
|
<title>Converting a decimal number to hexadecimal</title>
|
|
<programlisting>&hexconvert;</programlisting>
|
|
</example>
|
|
|
|
<para>Studying the <link linkend="inforef">info</link> page for
|
|
<command>dc</command> is a painful path to understanding its
|
|
intricacies. There seems to be a small, select group of
|
|
<emphasis>dc wizards</emphasis> who delight in showing off
|
|
their mastery of this powerful, but arcane utility.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo "16i[q]sa[ln0=aln100%Pln100/snlbx]sbA0D68736142snlbxq" | dc</userinput>
|
|
<computeroutput>Bash</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="goldenratio"/>
|
|
<programlisting>dc <<< 10k5v1+2/p # 1.6180339887
|
|
# ^^^ Feed operations to dc using a Here String.
|
|
# ^^^ Pushes 10 and sets that as the precision (10k).
|
|
# ^^ Pushes 5 and takes its square root
|
|
# (5v, v = square root).
|
|
# ^^ Pushes 1 and adds it to the running total (1+).
|
|
# ^^ Pushes 2 and divides the running total by that (2/).
|
|
# ^ Pops and prints the result (p)
|
|
# The result is 1.6180339887 ...
|
|
# ... which happens to be the Pythagorean Golden Ratio, to 10 places.</programlisting>
|
|
</para>
|
|
|
|
<example id="factr">
|
|
<title>Factoring</title>
|
|
<programlisting>&factr;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="awkmath"/><command>awk</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>awk</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>math</secondary>
|
|
</indexterm>
|
|
<para>Yet another way of doing floating point math in
|
|
a script is using <link linkend="awkref">awk's</link>
|
|
built-in math functions in a <link linkend="shwrapper">shell
|
|
wrapper</link>.</para>
|
|
|
|
<example id="hypot">
|
|
<title>Calculating the hypotenuse of a triangle</title>
|
|
<programlisting>&hypot;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- End Math Commands -->
|
|
|
|
|
|
<sect1 id="extmisc">
|
|
<title>Miscellaneous Commands</title>
|
|
|
|
<variablelist id="misccommandlisting">
|
|
<title><anchor id="misccommandlisting1"/>Command that fit in no
|
|
special category</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="jotref"/><command>jot</command></term>
|
|
<term><anchor id="seqref"/><command>seq</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>These utilities emit a sequence of integers, with a
|
|
user-selectable increment.</para>
|
|
|
|
<para>The default separator character between each integer is a
|
|
newline, but this can be changed with the <option>-s</option>
|
|
option.</para>
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>seq 5</userinput>
|
|
<computeroutput>1
|
|
2
|
|
3
|
|
4
|
|
5</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>seq -s : 5</userinput>
|
|
<computeroutput>1:2:3:4:5</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<para>Both <command>jot</command> and <command>seq</command>
|
|
come in handy in a <link linkend="forloopref1">for
|
|
loop</link>.</para>
|
|
|
|
<example id="ex53">
|
|
<title>Using <firstterm>seq</firstterm> to generate loop
|
|
arguments</title>
|
|
<programlisting>&ex53;</programlisting>
|
|
</example>
|
|
|
|
<para>A simpler example:</para>
|
|
|
|
<para><programlisting># Create a set of 10 files,
|
|
#+ named file.1, file.2 . . . file.10.
|
|
COUNT=10
|
|
PREFIX=file
|
|
|
|
for filename in `seq $COUNT`
|
|
do
|
|
touch $PREFIX.$filename
|
|
# Or, can do other operations,
|
|
#+ such as rm, grep, etc.
|
|
done</programlisting></para>
|
|
|
|
<example id="lettercount">
|
|
<title>Letter Count"</title>
|
|
<programlisting>&lettercount;</programlisting>
|
|
</example>
|
|
|
|
<note>
|
|
<para>Somewhat more capable than <firstterm>seq</firstterm>,
|
|
<command>jot</command> is a classic UNIX
|
|
utility that is not normally included in a standard Linux
|
|
distro. However, the source <firstterm>rpm</firstterm>
|
|
is available for download from the <ulink
|
|
url="http://www.mit.edu/afs/athena/system/rhlinux/athena-9.0/free/SRPMS/athena-jot-9.0-3.src.rpm">
|
|
MIT repository</ulink>.</para>
|
|
|
|
<para><anchor id="jotrandom"/></para>
|
|
<para>Unlike <firstterm>seq</firstterm>, <command>jot</command> can
|
|
generate a sequence of random numbers, using the <option>-r</option>
|
|
option.</para>
|
|
<para><screen><prompt>bash$ </prompt><userinput>jot -r 3 999</userinput>
|
|
<computeroutput>1069
|
|
1272
|
|
1428</computeroutput></screen></para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="getopty"/><command>getopt</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>getopt</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>option</secondary>
|
|
</indexterm>
|
|
<para>The <command>getopt</command> command
|
|
parses command-line options preceded by a <link
|
|
linkend="dashref">dash</link>. This external command
|
|
corresponds to the <link linkend="getoptsx">getopts</link>
|
|
Bash builtin. Using <command>getopt</command> permits
|
|
handling long options by means of the <option>-l</option>
|
|
flag, and this also allows parameter reshuffling.</para>
|
|
|
|
<example id="ex33a">
|
|
<title>Using <firstterm>getopt</firstterm> to parse command-line
|
|
options</title>
|
|
<programlisting>&ex33a;</programlisting>
|
|
</example>
|
|
|
|
<note>
|
|
<para>As <emphasis>Peggy Russell</emphasis> points out:</para>
|
|
<para>It is often necessary to include an <link
|
|
linkend="evalref">eval</link> to correctly process
|
|
<link linkend="whitespaceref">whitespace</link> and
|
|
<firstterm>quotes</firstterm>.
|
|
<programlisting>args=$(getopt -o a:bc:d -- "$@")
|
|
eval set -- "$args"</programlisting></para>
|
|
</note>
|
|
|
|
<para>See <xref linkend="getoptsimple"/> for a simplified emulation
|
|
of <command>getopt</command>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="runpartsref"/><command>run-parts</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>run-parts</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>run-parts</secondary>
|
|
</indexterm>
|
|
<para>The <command>run-parts</command> command
|
|
|
|
<footnote><para>This is actually a script adapted from
|
|
the Debian Linux distribution.</para></footnote>
|
|
|
|
executes all the scripts in a target directory, sequentially
|
|
in ASCII-sorted filename order. Of course, the scripts
|
|
need to have execute permission.</para>
|
|
|
|
<para>The <link linkend="cronref">cron</link> <link
|
|
linkend="daemonref">daemon</link> invokes
|
|
<command>run-parts</command> to run the scripts in
|
|
the <filename class="directory">/etc/cron.*</filename>
|
|
directories.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="yesref"/><command>yes</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>yes</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>yes</secondary>
|
|
</indexterm>
|
|
|
|
<para>In its default behavior the <command>yes</command>
|
|
command feeds a continuous string of the character
|
|
<computeroutput>y</computeroutput> followed
|
|
by a line feed to <filename>stdout</filename>. A
|
|
<keycombo><keycap>control</keycap><keycap>C</keycap></keycombo>
|
|
terminates the run. A different output string
|
|
may be specified, as in <userinput>yes different
|
|
string</userinput>, which would continually output
|
|
<computeroutput>different string</computeroutput> to
|
|
<filename>stdout</filename>.</para>
|
|
|
|
<para>One might well ask the purpose of this. From the
|
|
command-line or in a script, the output of
|
|
<command>yes</command> can be redirected or piped into a
|
|
program expecting user input. In effect, this becomes a sort
|
|
of poor man's version of <firstterm>expect</firstterm>.</para>
|
|
|
|
<para><userinput>yes | fsck /dev/hda1</userinput> runs
|
|
<command>fsck</command> non-interactively (careful!).</para>
|
|
|
|
<para><userinput>yes | rm -r dirname</userinput> has same effect as
|
|
<userinput>rm -rf dirname</userinput> (careful!).</para>
|
|
|
|
<warning><para>Caution advised when piping
|
|
<firstterm>yes</firstterm> to a potentially dangerous
|
|
system command, such as <link linkend="fsckref">fsck</link>
|
|
or <link linkend="fdiskref">fdisk</link>. It might have
|
|
unintended consequences.</para></warning>
|
|
|
|
<note>
|
|
<para>The <firstterm>yes</firstterm> command parses variables,
|
|
or more accurately, it echoes parsed variables.
|
|
For example:</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>yes $BASH_VERSION</userinput>
|
|
<computeroutput>3.1.17(1)-release
|
|
3.1.17(1)-release
|
|
3.1.17(1)-release
|
|
3.1.17(1)-release
|
|
3.1.17(1)-release
|
|
. . .</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>
|
|
This particular <quote>feature</quote> may be used
|
|
to create a <emphasis>very large</emphasis> ASCII file on the fly:
|
|
<screen><prompt>bash$ </prompt><userinput>yes $PATH > huge_file.txt</userinput>
|
|
<userinput>Ctl-C</userinput>
|
|
</screen>
|
|
Hit <userinput>Ctl-C</userinput> <emphasis>very
|
|
quickly</emphasis>, or you just might get more than you
|
|
bargained for. . . .
|
|
</para>
|
|
</note>
|
|
|
|
<para><anchor id="yesemu"/>The <firstterm>yes</firstterm>
|
|
command may be emulated in a very simple script <link
|
|
linkend="functionref">function</link>.</para>
|
|
|
|
<para><programlisting>yes ()
|
|
{ # Trivial emulation of "yes" ...
|
|
local DEFAULT_TEXT="y"
|
|
while [ true ] # Endless loop.
|
|
do
|
|
if [ -z "$1" ]
|
|
then
|
|
echo "$DEFAULT_TEXT"
|
|
else # If argument ...
|
|
echo "$1" # ... expand and echo it.
|
|
fi
|
|
done # The only things missing are the
|
|
} #+ --help and --version options.</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="bannerref"/><command>banner</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>banner</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>banner</secondary>
|
|
</indexterm>
|
|
<para>Prints arguments as a large vertical banner to
|
|
<filename>stdout</filename>, using an <link
|
|
linkend="asciidef">ASCII</link> character (default
|
|
'#'). This may be redirected to a printer for
|
|
hardcopy.</para>
|
|
|
|
<para>Note that <firstterm>banner</firstterm> has been
|
|
dropped from many Linux distros, presumably because it
|
|
is no longer considered useful.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="printenvref"/><command>printenv</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>printenv</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>environment</secondary>
|
|
</indexterm>
|
|
<para>Show all the <link linkend="envref">environmental
|
|
variables</link> set for a particular user.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>printenv | grep HOME</userinput>
|
|
<computeroutput>HOME=/home/bozo</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lpref"/><command>lp</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>lpr</secondary>
|
|
</indexterm>
|
|
<para>The <command>lp</command> and <command>lpr</command>
|
|
commands send file(s) to the print queue, to be printed as
|
|
hard copy.
|
|
|
|
<footnote><para>The <firstterm>print queue</firstterm> is
|
|
the group of jobs <quote>waiting in line</quote> to be
|
|
printed.</para></footnote>
|
|
|
|
These commands trace the origin of their names to the
|
|
line printers of another era.
|
|
<footnote><para>Large mechanical <firstterm>line
|
|
printers</firstterm> printed a single
|
|
line of type at a time onto joined
|
|
sheets of <firstterm>greenbar</firstterm>
|
|
paper, to the accompaniment of <ulink
|
|
url="http://www.columbia.edu/cu/computinghistory/1403.html">a
|
|
great deal of noise</ulink>. The hardcopy
|
|
thusly printed was referred to as a
|
|
<firstterm>printout</firstterm>.</para></footnote>
|
|
|
|
</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 <link
|
|
linkend="groffref">groff</link> and
|
|
<firstterm>Ghostscript</firstterm> may send their output
|
|
directly to <command>lp</command>.</para>
|
|
|
|
<para><prompt>bash$ </prompt><userinput>groff -Tascii file.tr | lp</userinput>
|
|
</para>
|
|
|
|
<para><prompt>bash$ </prompt><userinput>gs -options | lp file.ps</userinput>
|
|
</para>
|
|
|
|
<para>Related commands are <command>lpq</command>, for viewing
|
|
the print queue, and <command>lprm</command>, for removing
|
|
jobs from the print queue.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="teeref"/><command>tee</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tee</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tee</secondary>
|
|
</indexterm>
|
|
<para>[UNIX borrows an idea from the plumbing trade.]</para>
|
|
<para>This is a redirection operator, but with a difference. Like the
|
|
plumber's <firstterm>tee,</firstterm> it permits <quote>siphoning
|
|
off</quote> <emphasis>to a file </emphasis>the output of a command
|
|
or commands within a pipe, but without affecting the result. This is
|
|
useful for printing an ongoing process to a file or paper, perhaps to
|
|
keep track of it for debugging purposes.</para>
|
|
|
|
<screen>
|
|
(redirection)
|
|
|----> to file
|
|
|
|
|
==========================|====================
|
|
command ---> command ---> |tee ---> command ---> ---> output of pipe
|
|
===============================================
|
|
</screen>
|
|
|
|
|
|
<para><programlisting>cat listfile* | sort | tee check.file | uniq > result.file
|
|
# ^^^^^^^^^^^^^^ ^^^^
|
|
|
|
# The file "check.file" contains the concatenated sorted "listfiles,"
|
|
#+ before the duplicate lines are removed by 'uniq.'</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mkfiforef"/><command>mkfifo</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mkfifo</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mkfifo</secondary>
|
|
</indexterm>
|
|
<para><anchor id="namedpiperef"/>This obscure command
|
|
creates a <firstterm>named pipe</firstterm>, a temporary
|
|
<firstterm>first-in-first-out buffer</firstterm> for
|
|
transferring data between processes.
|
|
|
|
<footnote><para>For an excellent overview of this
|
|
topic, see Andy Vaught's article, <ulink
|
|
url="http://www2.linuxjournal.com/lj-issues/issue41/2156.html">Introduction
|
|
to Named Pipes</ulink>, in the September, 1997 issue of
|
|
<ulink url="http://www.linuxjournal.com"><citetitle
|
|
pubwork="journal">Linux
|
|
Journal</citetitle></ulink>.</para></footnote>
|
|
|
|
Typically, one process writes to the FIFO, and the other
|
|
reads from it. See <xref linkend="fifo"/>.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# This short script by Omair Eshkenazi.
|
|
# Used in ABS Guide with permission (thanks!).
|
|
|
|
mkfifo pipe1 # Yes, pipes can be given names.
|
|
mkfifo pipe2 # Hence the designation "named pipe."
|
|
|
|
(cut -d' ' -f1 | tr "a-z" "A-Z") >pipe2 <pipe1 &
|
|
ls -l | tr -s ' ' | cut -d' ' -f3,9- | tee pipe1 |
|
|
cut -d' ' -f2 | paste - pipe2
|
|
|
|
rm -f pipe1
|
|
rm -f pipe2
|
|
|
|
# No need to kill background processes when script terminates (why not?).
|
|
|
|
exit $?
|
|
|
|
Now, invoke the script and explain the output:
|
|
sh mkfifo-example.sh
|
|
|
|
4830.tar.gz BOZO
|
|
pipe1 BOZO
|
|
pipe2 BOZO
|
|
mkfifo-example.sh BOZO
|
|
Mixed.msg BOZO</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pathchkref"/><command>pathchk</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>pathchk</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>pathchk</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>dd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dd</secondary>
|
|
</indexterm>
|
|
<para>Though this somewhat obscure and much feared
|
|
<command>d</command>ata <command>d</command>uplicator
|
|
command originated as a utility for exchanging
|
|
data on magnetic tapes between UNIX minicomputers
|
|
and IBM mainframes, it still has its uses.
|
|
The <command>dd</command> command simply copies a
|
|
file (or <filename>stdin/stdout</filename>), but with
|
|
conversions. <anchor id="ddconversions"/>Possible conversions
|
|
include ASCII/EBCDIC,
|
|
|
|
<footnote><para><acronym>EBCDIC</acronym> (pronounced
|
|
<quote>ebb-sid-ick</quote>) is an acronym for Extended
|
|
Binary Coded Decimal Interchange Code, an obsolete
|
|
IBM data format. A bizarre application of
|
|
the <option>conv=ebcdic</option> option of
|
|
<command>dd</command> is as a quick 'n easy, but not
|
|
very secure text file encoder.
|
|
<programlisting>cat $file | dd conv=swab,ebcdic > $file_encrypted
|
|
# Encode (looks like gibberish).
|
|
# Might as well switch bytes (swab), too, for a little extra obscurity.
|
|
|
|
cat $file_encrypted | dd conv=swab,ascii > $file_plaintext
|
|
# Decode.</programlisting>
|
|
</para></footnote>
|
|
|
|
upper/lower case, swapping of byte pairs between input
|
|
and output, and skipping and/or truncating the head or
|
|
tail of the input file.</para>
|
|
|
|
<para>
|
|
<programlisting># Converting a file to all uppercase:
|
|
|
|
dd if=$filename conv=ucase > $filename.uppercase
|
|
# lcase # For lower case conversion</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="ddoptions"/></para>
|
|
<para>Some basic options to <command>dd</command> are:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>if=INFILE</para>
|
|
<para>INFILE is the <firstterm>source</firstterm>
|
|
file.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>of=OUTFILE</para>
|
|
<para>OUTFILE is the <firstterm>target</firstterm>
|
|
file, the file that will have the data written to it.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>bs=BLOCKSIZE</para>
|
|
<para>This is the size of each block of data being read
|
|
and written, usually a power of 2.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>skip=BLOCKS</para>
|
|
<para>How many blocks of data to skip in INFILE before
|
|
starting to copy. This is useful when the INFILE has
|
|
<quote>garbage</quote> or garbled data in its
|
|
header or when it is desirable to copy only a portion
|
|
of the INFILE.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>seek=BLOCKS</para>
|
|
<para>How many blocks of data to skip in OUTFILE before
|
|
starting to copy, leaving blank data at beginning
|
|
of OUTFILE.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>count=BLOCKS</para>
|
|
<para>Copy only this many blocks of data, rather than the
|
|
entire INFILE.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>conv=CONVERSION</para>
|
|
<para>Type of conversion to be applied to INFILE data
|
|
before copying operation.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>A <userinput>dd --help</userinput> lists all the
|
|
options this powerful utility takes.</para>
|
|
|
|
|
|
<example id="selfcopy">
|
|
<title>A script that copies itself</title>
|
|
<programlisting>&selfcopy;</programlisting>
|
|
</example>
|
|
|
|
<example id="exercisingdd">
|
|
<title>Exercising <firstterm>dd</firstterm></title>
|
|
<programlisting>&exercisingdd;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="ddkeystrokes"/></para>
|
|
<para>To demonstrate just how versatile <command>dd</command> is,
|
|
let's use it to capture keystrokes.</para>
|
|
|
|
<example id="ddkeypress">
|
|
<title>Capturing Keystrokes</title>
|
|
<programlisting>&ddkeypress;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="ddrandom"/></para>
|
|
<para>The <command>dd</command> command can do random access on a
|
|
data stream.
|
|
|
|
<programlisting>echo -n . | dd bs=1 seek=4 of=file conv=notrunc
|
|
# The "conv=notrunc" option means that the output file
|
|
#+ will not be truncated.
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="ddcopy"/></para>
|
|
<para>The <command>dd</command> command can copy raw data
|
|
and disk images to and from devices, such as floppies and
|
|
tape drives (<xref linkend="copycd"/>). A common use is
|
|
creating boot floppies.</para>
|
|
<para>
|
|
<userinput>dd if=kernel-image of=/dev/fd0H1440</userinput>
|
|
</para>
|
|
|
|
<para>Similarly, <command>dd</command> can copy the entire
|
|
contents of a floppy, even one formatted with a
|
|
<quote>foreign</quote> OS, to the hard drive as an
|
|
image file.</para>
|
|
<para>
|
|
<userinput>dd if=/dev/fd0 of=/home/bozo/projects/floppy.img</userinput>
|
|
</para>
|
|
|
|
<para><anchor id="bfs"/>Likewise, <command>dd</command>
|
|
can create bootable flash drives and SD cards.</para>
|
|
|
|
<para><userinput>dd if=image.iso of=/dev/sdb</userinput></para>
|
|
|
|
<para><anchor id="rpsdcard01"/></para>
|
|
<example id="rpsdcard">
|
|
<title>Preparing a bootable SD card for the
|
|
<emphasis>Raspberry Pi</emphasis></title>
|
|
<programlisting>&rpsdcard;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="ddswap"/></para>
|
|
<para>
|
|
Other applications of <command>dd</command> include
|
|
initializing temporary swap files (<xref linkend="ex73"/>)
|
|
and ramdisks (<xref linkend="ramdisk"/>). It can even do a
|
|
low-level copy of an entire hard drive partition, although
|
|
this is not necessarily recommended.</para>
|
|
|
|
<para>People (with presumably nothing better to do with
|
|
their time) are constantly thinking of interesting
|
|
applications of <command>dd</command>.</para>
|
|
|
|
<para><anchor id="ddfdel"/></para>
|
|
<example id="blotout">
|
|
<title>Securely deleting a file</title>
|
|
<programlisting>&blotout;</programlisting>
|
|
</example>
|
|
|
|
<para>See also the <link linkend="ddlink">dd
|
|
thread</link> entry in the <link
|
|
linkend="biblioref">bibliography</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="odref"/><command>od</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>od</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>od</secondary>
|
|
</indexterm>
|
|
<para>The <command>od</command>, or <firstterm>octal
|
|
dump</firstterm> filter converts input (or files) to octal
|
|
(base-8) or other bases. This is useful for viewing or
|
|
processing binary data files or otherwise unreadable system
|
|
<link linkend="devfileref">device files</link>, such as
|
|
<filename>/dev/urandom</filename>, and as a filter for
|
|
binary data.</para>
|
|
|
|
<para>
|
|
<programlisting>head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p'
|
|
# Sample output: 1324725719, 3918166450, 2989231420, etc.
|
|
|
|
# From rnd.sh example script, by Stéphane Chazelas</programlisting>
|
|
</para>
|
|
|
|
<para>See also <xref linkend="seedingrandom"/> and <xref
|
|
linkend="insertionsort"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="hexdumpref"/><command>hexdump</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>hexdump</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>hexadecimal</secondary>
|
|
</indexterm>
|
|
<para>Performs a hexadecimal, octal, decimal, or ASCII
|
|
dump of a binary file. This command is the rough equivalent
|
|
of <command>od</command>, above, but not nearly as
|
|
useful. May be used to view the contents of a binary file,
|
|
in combination with <link linkend="ddref">dd</link> and <link
|
|
linkend="lessref">less</link>.</para>
|
|
|
|
<para>
|
|
<programlisting>dd if=/bin/ls | hexdump -C | less
|
|
# The -C option nicely formats the output in tabular form.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="objdumpref"/><command>objdump</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>objdump</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>object binary dump</secondary>
|
|
</indexterm>
|
|
<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><anchor id="mcookieref"/><command>mcookie</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>magic</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>cookie</secondary>
|
|
</indexterm>
|
|
|
|
<para>This command generates a <quote>magic cookie,</quote> a
|
|
128-bit (32-character) pseudorandom hexadecimal number,
|
|
normally used as an authorization <quote>signature</quote>
|
|
by the X server. This also available for use in a script
|
|
as a <quote>quick 'n dirty</quote> random number.</para>
|
|
|
|
<para><programlisting>random000=$(mcookie)</programlisting></para>
|
|
|
|
<para>Of course, a script could use <link
|
|
linkend="md5sumref">md5sum</link> for the same purpose.</para>
|
|
|
|
<para><programlisting># Generate md5 checksum on the script itself.
|
|
random001=`md5sum $0 | awk '{print $1}'`
|
|
# Uses 'awk' to strip off the filename.</programlisting></para>
|
|
|
|
<para>The <command>mcookie</command> command gives yet another way
|
|
to generate a <quote>unique</quote> filename.</para>
|
|
|
|
<example id="tempfilename">
|
|
<title>Filename generator</title>
|
|
<programlisting>&tempfilename;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="unitsref"/><command>units</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>units</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>conversion</secondary>
|
|
</indexterm>
|
|
<para>This utility converts between different <firstterm>units
|
|
of measure</firstterm>. While normally invoked in interactive
|
|
mode, <command>units</command> may find use in a
|
|
script.</para>
|
|
<example id="unitconversion">
|
|
<title>Converting meters to miles</title>
|
|
<programlisting>&unitconversion;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="m4ref"/><command>m4</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>m4</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>macro</secondary>
|
|
</indexterm>
|
|
<para>A hidden treasure, <command>m4</command> is a
|
|
powerful macro
|
|
<footnote><para>A <firstterm>macro</firstterm> is a
|
|
symbolic constant that expands into a command string
|
|
or a set of operations on parameters. Simply put,
|
|
it's a shortcut or abbreviation.</para></footnote>
|
|
processing filter, virtually a complete language.
|
|
Although originally written as a pre-processor
|
|
for <firstterm>RatFor</firstterm>, <command>m4</command>
|
|
turned out to be useful as a stand-alone utility. In
|
|
fact, <command>m4</command> combines some of the
|
|
functionality of <link linkend="evalref">eval</link>,
|
|
<link linkend="trref">tr</link>, and <link
|
|
linkend="awkref">awk</link>, in addition to its extensive
|
|
macro expansion facilities.</para>
|
|
|
|
<para>The April, 2002 issue of <ulink
|
|
url="http://www.linuxjournal.com"><citetitle
|
|
pubwork="journal">Linux Journal</citetitle></ulink>
|
|
has a very nice article on <command>m4</command> and
|
|
its uses.</para>
|
|
|
|
<example id="m4">
|
|
<title>Using <firstterm>m4</firstterm></title>
|
|
<programlisting>&m4;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="xmessageref"/><command>xmessage</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>xmessage</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>macro</secondary>
|
|
</indexterm>
|
|
<para>This X-based variant of
|
|
<link linkend="echoref">echo</link> pops up a message/query
|
|
window on the desktop.</para>
|
|
<para>
|
|
<programlisting>xmessage Left click to continue -button okay</programlisting>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="zenityref"/><command>zenity</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>zenity</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>macro</secondary>
|
|
</indexterm>
|
|
<para>The
|
|
<ulink url="http://freshmeat.net/projects/zenity">zenity</ulink>
|
|
utility is adept at displaying
|
|
<firstterm>GTK+</firstterm> dialog <link
|
|
linkend="widgetref">widgets</link> and <link
|
|
linkend="zenityref2">very suitable for scripting
|
|
purposes</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="doexecref"/><command>doexec</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>doexec</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>executable arg list</secondary>
|
|
</indexterm>
|
|
<para>The <command>doexec</command> command enables passing
|
|
an arbitrary list of arguments to a <firstterm>binary
|
|
executable</firstterm>. In particular, passing
|
|
<parameter>argv[0]</parameter> (which corresponds to <link
|
|
linkend="posparamref1">$0</link> in a script) lets the
|
|
executable be invoked by various names, and it can then
|
|
carry out different sets of actions, according to the name
|
|
by which it was called. What this amounts to is roundabout
|
|
way of passing options to an executable.</para>
|
|
|
|
<para>For example, the <filename
|
|
class="directory">/usr/local/bin</filename> directory might
|
|
contain a binary called <quote>aaa</quote>. Invoking
|
|
<command>doexec /usr/local/bin/aaa list</command>
|
|
would <emphasis>list</emphasis> all those files
|
|
in the current working directory beginning with an
|
|
<quote>a</quote>, while invoking (the same executable
|
|
with) <command>doexec /usr/local/bin/aaa delete </command>
|
|
would <emphasis>delete</emphasis> those files.</para>
|
|
|
|
<note><para>The various behaviors of the executable
|
|
must be defined within the code of the executable itself,
|
|
analogous to something like the following in a shell script:
|
|
<programlisting>case `basename $0` in
|
|
"name1" ) do_something;;
|
|
"name2" ) do_something_else;;
|
|
"name3" ) do_yet_another_thing;;
|
|
* ) bail_out;;
|
|
esac</programlisting></para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>dialog</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>dialog</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dialog</secondary>
|
|
</indexterm>
|
|
<para>The <link linkend="dialogref">dialog</link> family of tools
|
|
provide a method of calling interactive
|
|
<quote>dialog</quote> boxes from a script. The more
|
|
elaborate variations of <command>dialog</command> --
|
|
<command>gdialog</command>, <command>Xdialog</command>,
|
|
and <command>kdialog</command> -- actually invoke X-Windows
|
|
<link linkend="widgetref">widgets</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="soxref"/><command>sox</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>sox</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sound</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <command>sox</command>, or
|
|
<quote><command>so</command>und
|
|
e<command>x</command>change</quote> command plays and
|
|
performs transformations on sound files. In fact,
|
|
the <filename>/usr/bin/play</filename> executable
|
|
(now deprecated) is nothing but a shell wrapper for
|
|
<firstterm>sox</firstterm>.</para>
|
|
|
|
<para>For example, <command>sox soundfile.wav
|
|
soundfile.au</command> changes a WAV sound file into a
|
|
(Sun audio format) AU sound file.</para>
|
|
|
|
<para>Shell scripts are ideally suited for batch-processing
|
|
<command>sox</command> operations on
|
|
sound files. For examples, see the <ulink
|
|
url="http://osl.iu.edu/~tveldhui/radio/"> Linux Radio
|
|
Timeshift HOWTO</ulink> and the <ulink
|
|
url="http://savannah.nongnu.org/projects/audiodo">MP3do
|
|
Project</ulink>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
</sect1> <!-- End Miscellaneous Commands -->
|
|
|
|
</chapter> <!-- External Filters, Programs and Commands -->
|
|
|
|
|
|
|
|
<chapter id="system">
|
|
<title>System and Administrative Commands</title>
|
|
|
|
|
|
<para>The startup and shutdown scripts in
|
|
<filename class="directory">/etc/rc.d</filename> illustrate the uses
|
|
(and usefulness) of many of these comands. These are usually
|
|
invoked by <firstterm>root</firstterm> and used for system
|
|
maintenance or emergency filesystem repairs. Use with caution, as
|
|
some of these commands may damage your system if misused.</para>
|
|
|
|
<variablelist id="usersgroups">
|
|
<title><anchor id="usersgroups1"/>Users and Groups</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="usersref"/><command>users</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>users</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>users</secondary>
|
|
</indexterm>
|
|
<para>Show all logged on users. This is the approximate
|
|
equivalent of <command>who -q</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="groupscmdref"/><command>groups</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>groups</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>groups</secondary>
|
|
</indexterm>
|
|
<para>Lists the current user and the groups she belongs to.
|
|
This corresponds to the <link
|
|
linkend="groupsref">$GROUPS</link> internal variable,
|
|
but gives the group names, rather than the numbers.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>groups</userinput>
|
|
<computeroutput>bozita cdrom cdwriter audio xgrp</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $GROUPS</userinput>
|
|
<computeroutput>501</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="chownref"/><command>chown</command></term>
|
|
<term><anchor id="chgrpref"/><command>chgrp</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>chown</command> command changes the
|
|
ownership of a file or files. This command is a useful
|
|
method that <firstterm>root</firstterm> can use to
|
|
shift file ownership from one user to another. An ordinary
|
|
user may not change the ownership of files, not even her
|
|
own files.
|
|
<footnote><para>This is the case on a Linux machine or a UNIX
|
|
system with disk quotas.</para></footnote>
|
|
</para>
|
|
|
|
<para>
|
|
<screen><prompt>root# </prompt><userinput>chown bozo *.txt</userinput>
|
|
<computeroutput></computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <command>chgrp</command> command changes the
|
|
<replaceable>group</replaceable> ownership of a file or
|
|
files. You must be owner of the file(s) as well as a member
|
|
of the destination group (or <firstterm>root</firstterm>)
|
|
to use this operation.
|
|
<programlisting>chgrp --recursive dunderheads *.data
|
|
# The "dunderheads" group will now own all the "*.data" files
|
|
#+ all the way down the $PWD directory tree (that's what "recursive" means).
|
|
</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="useraddref"/><command>useradd</command></term>
|
|
<term><command>userdel</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>useradd</command> administrative command
|
|
adds a user account to the system and creates a home
|
|
directory for that particular user, if so specified. The
|
|
corresponding <command>userdel</command> command removes
|
|
a user account from the system
|
|
<footnote><para>The <command>userdel</command> command
|
|
will fail if the particular user being deleted is
|
|
still logged on.</para></footnote>
|
|
and deletes associated files.</para>
|
|
|
|
<note><para>The <command>adduser</command> command is a synonym
|
|
for <command>useradd</command> and is usually a symbolic link to
|
|
it.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="usermodref"/><command>usermod</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>usermod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>usermod</secondary>
|
|
</indexterm>
|
|
<para>Modify a user account. Changes may be made to the password,
|
|
group membership, expiration date, and other attributes of
|
|
a given user's account. With this command, a user's password
|
|
may be locked, which has the effect of disabling the
|
|
account.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="groupmodref"/><command>groupmod</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>groupmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>group</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>id</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>id</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <command>id</command> command lists the real and
|
|
effective user IDs and the group IDs of the user
|
|
associated with the current process. This is the
|
|
counterpart to the <link linkend="uidref">$UID</link>,
|
|
<link linkend="euidref">$EUID</link>, and <link
|
|
linkend="groupsref">$GROUPS</link> internal Bash
|
|
variables.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>id</userinput>
|
|
<computeroutput>uid=501(bozo) gid=501(bozo) groups=501(bozo),22(cdrom),80(cdwriter),81(audio)</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $UID</userinput>
|
|
<computeroutput>501</computeroutput></screen>
|
|
|
|
<note><para>The <command>id</command> command shows the
|
|
<emphasis>effective</emphasis> IDs only when they differ
|
|
from the <emphasis>real</emphasis> ones.</para></note>
|
|
|
|
<para>Also see <xref linkend="amiroot"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lidref"/><command>lid</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lid</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>group</secondary>
|
|
</indexterm>
|
|
<para>The <firstterm>lid</firstterm> (list ID) command
|
|
shows the group(s) that a given user belongs to, or alternately,
|
|
the users belonging to a given group. May be invoked only by
|
|
root.</para>
|
|
<para>
|
|
<screen><prompt>root# </prompt><userinput>lid bozo</userinput>
|
|
<computeroutput> bozo(gid=500)</computeroutput>
|
|
|
|
|
|
<prompt>root# </prompt><userinput>lid daemon</userinput>
|
|
<computeroutput> bin(gid=1)
|
|
daemon(gid=2)
|
|
adm(gid=4)
|
|
lp(gid=7)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="whoref"/><command>who</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>who</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>whoami</secondary>
|
|
</indexterm>
|
|
|
|
<para>Show all users logged on to the system.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>who</userinput>
|
|
<computeroutput>bozo tty1 Apr 27 17:45
|
|
bozo pts/0 Apr 27 17:46
|
|
bozo pts/1 Apr 27 17:47
|
|
bozo pts/2 Apr 27 17:49
|
|
</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <option>-m</option> gives detailed information about
|
|
only the current user. Passing any two arguments to
|
|
<command>who</command> is the equivalent of <command>who
|
|
-m</command>, as in <command>who am i</command> or <command>who
|
|
The Man</command>.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>who -m</userinput>
|
|
<computeroutput>localhost.localdomain!bozo pts/2 Apr 27 17:49</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="whoamiref"/><command>whoami</command> is similar to <command>who
|
|
-m</command>, but only lists the user name.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>whoami</userinput>
|
|
<computeroutput>bozo</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="wref"/><command>w</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>w</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>w</secondary>
|
|
</indexterm>
|
|
<para>Show all logged on users and the processes belonging to them. This is
|
|
an extended version of <command>who</command>. The output of <command>w</command>
|
|
may be piped to <link linkend="grepref">grep</link> to find
|
|
a specific user and/or process.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>w | grep startx</userinput>
|
|
<computeroutput>bozo tty1 - 4:22pm 6:41 4.47s 0.45s startx</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lognameref"/><command>logname</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>logname</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>logname</secondary>
|
|
</indexterm>
|
|
|
|
<para>Show current user's login name (as found in
|
|
<filename>/var/run/utmp</filename>). This is a
|
|
near-equivalent to <link linkend="whoamiref">whoami</link>,
|
|
above.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>logname</userinput>
|
|
<computeroutput>bozo</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>whoami</userinput>
|
|
<computeroutput>bozo</computeroutput></screen>
|
|
|
|
<para>However . . .</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>su</userinput>
|
|
<computeroutput>Password: ......</computeroutput>
|
|
|
|
<prompt>bash# </prompt><userinput>whoami</userinput>
|
|
<computeroutput>root</computeroutput>
|
|
<prompt>bash# </prompt><userinput>logname</userinput>
|
|
<computeroutput>bozo</computeroutput></screen>
|
|
</para>
|
|
|
|
|
|
<note><para>While <command>logname</command> prints the name
|
|
of the logged in user, <command>whoami</command> gives the
|
|
name of the user attached to the current process. As we have
|
|
just seen, sometimes these are not the same.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="suref"/><command>su</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>su</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>su</secondary>
|
|
</indexterm>
|
|
<para>Runs a program or script as a
|
|
<command>s</command>ubstitute <command>u</command>ser.
|
|
<command>su rjones</command> starts a shell as user
|
|
<emphasis>rjones</emphasis>. A naked <command>su</command>
|
|
defaults to <firstterm>root</firstterm>. See <xref
|
|
linkend="fifo"/>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sudoref"/><command>sudo</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>sudo</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sudo</secondary>
|
|
</indexterm>
|
|
<para>Runs a command as <firstterm>root</firstterm> (or
|
|
another user). This may be used in a script, thus permitting
|
|
a <firstterm>regular user</firstterm> to run the script.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
# Some commands.
|
|
sudo cp /root/secretfile /home/bozo/secret
|
|
# Some more commands.</programlisting></para>
|
|
|
|
<para>The file <filename>/etc/sudoers</filename> holds
|
|
the names of users permitted to invoke
|
|
<command>sudo</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="passwdref"/><command>passwd</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>passwd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>password</secondary>
|
|
</indexterm>
|
|
|
|
<para>Sets, changes, or manages a user's password.</para>
|
|
|
|
<para>The <command>passwd</command> command can be used in
|
|
a script, but probably <emphasis>should not</emphasis> be.</para>
|
|
|
|
<example id="setnewpw">
|
|
<title>Setting a new password</title>
|
|
<programlisting>&setnewpw;</programlisting>
|
|
</example>
|
|
|
|
<para>The <command>passwd</command> command's <option>-l</option>,
|
|
<option>-u</option>, and <option>-d</option> options permit
|
|
locking, unlocking, and deleting a user's password. Only
|
|
<firstterm>root</firstterm> may use these options.</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="acref"/><command>ac</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ac</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>accounting</secondary>
|
|
</indexterm>
|
|
<para>Show users' logged in time, as read from
|
|
<filename>/var/log/wtmp</filename>. This is one of the GNU
|
|
accounting utilities.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>ac</userinput>
|
|
<computeroutput> total 68.08</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lastref"/><command>last</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>last</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>logged in</secondary>
|
|
</indexterm>
|
|
|
|
<para>List <emphasis>last</emphasis> logged in users, as read from
|
|
<filename>/var/log/wtmp</filename>. This command can also
|
|
show remote logins.</para>
|
|
|
|
<para>For example, to show the last few times the system
|
|
rebooted:</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>last reboot</userinput>
|
|
<computeroutput>reboot system boot 2.6.9-1.667 Fri Feb 4 18:18 (00:02)
|
|
reboot system boot 2.6.9-1.667 Fri Feb 4 15:20 (01:27)
|
|
reboot system boot 2.6.9-1.667 Fri Feb 4 12:56 (00:49)
|
|
reboot system boot 2.6.9-1.667 Thu Feb 3 21:08 (02:17)
|
|
. . .
|
|
|
|
wtmp begins Tue Feb 1 12:50:09 2005</computeroutput></screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="newgrpref"/><command>newgrp</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>newgrp</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>group</secondary>
|
|
</indexterm>
|
|
<para>Change user's <firstterm>group ID</firstterm> without
|
|
logging out. This permits access to the new group's
|
|
files. Since users may be members of multiple groups
|
|
simultaneously, this command finds only limited use.</para>
|
|
|
|
<note><para>Kurt Glaesemann points out that the
|
|
<firstterm>newgrp</firstterm> command could prove helpful
|
|
in setting the default group permissions for files a user
|
|
writes. However, the <link linkend="chgrpref">chgrp</link>
|
|
command might be more convenient for this purpose.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="terminalssys">
|
|
<title><anchor id="terminalssys1"/>Terminals</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ttyref"/><command>tty</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tty</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tty</secondary>
|
|
</indexterm>
|
|
<para>Echoes the name (filename) of the current user's terminal.
|
|
Note that each separate <firstterm>xterm</firstterm>
|
|
window counts as a different terminal.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>tty</userinput>
|
|
<computeroutput>/dev/pts/1</computeroutput></screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sttyref"/><command>stty</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>stty</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>stty</secondary>
|
|
</indexterm>
|
|
<para>Shows and/or changes terminal settings. This complex
|
|
command, used in a script, can control terminal behavior
|
|
and the way output displays. See the info page, and study
|
|
it carefully.</para>
|
|
|
|
<example id="erase">
|
|
<title>Setting an <firstterm>erase</firstterm> character</title>
|
|
<programlisting>&erase;</programlisting>
|
|
</example>
|
|
|
|
<example id="secretpw">
|
|
<title><firstterm>secret password</firstterm>:
|
|
Turning off terminal echoing </title>
|
|
<programlisting>&secretpw;</programlisting>
|
|
</example>
|
|
|
|
<para>A creative use of <command>stty</command> is detecting a
|
|
user keypress (without hitting
|
|
<keycap>ENTER</keycap>).</para>
|
|
|
|
<example id="keypress">
|
|
<title>Keypress detection</title>
|
|
<programlisting>&keypress;</programlisting>
|
|
</example>
|
|
|
|
<para>Also see <xref linkend="timeout"/> and <xref
|
|
linkend="stopwatch"/>.</para>
|
|
|
|
|
|
<para><anchor id="terminalsref"/></para>
|
|
<sidebar><title>terminals and modes</title>
|
|
|
|
<para>Normally, a terminal works in the
|
|
<firstterm>canonical</firstterm> mode. When a user hits a
|
|
key, the resulting character does not immediately go to
|
|
the program actually running in this terminal. A buffer
|
|
local to the terminal stores keystrokes. When the user
|
|
hits the <keycap>ENTER</keycap> key, this sends all the
|
|
stored keystrokes to the program running. There is even
|
|
a basic line editor inside the terminal.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>stty -a</userinput>
|
|
<computeroutput>speed 9600 baud; rows 36; columns 96; line = 0;
|
|
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = <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>wc -c < filexxx</userinput>
|
|
<computeroutput>12</computeroutput>
|
|
</screen>
|
|
|
|
The process controlling the terminal receives only 12
|
|
characters (11 alphabetic ones, plus a newline), although
|
|
the user hit 26 keys.
|
|
</para>
|
|
|
|
<para>In non-canonical (<quote>raw</quote>) mode, every
|
|
key hit (including special editing keys such as
|
|
<keycap>ctl-H</keycap>) sends a character immediately to
|
|
the controlling process.</para>
|
|
|
|
|
|
<para>The Bash prompt disables both <option>icanon</option>
|
|
and <option>echo</option>, since it replaces the basic
|
|
terminal line editor with its own more elaborate one. For
|
|
example, when you hit <keycap>ctl-A</keycap> at the Bash
|
|
prompt, there's no <keycap>^A</keycap> echoed by the
|
|
terminal, but Bash gets a <keycap>\1</keycap> character,
|
|
interprets it, and moves the cursor to the begining of
|
|
the line.</para>
|
|
|
|
<para><emphasis>Stéphane Chazelas</emphasis></para>
|
|
|
|
</sidebar>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="settermref"/><command>setterm</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>setterm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>terminal</secondary>
|
|
</indexterm>
|
|
|
|
<para>Set certain terminal attributes. This command writes
|
|
to its terminal's <filename>stdout</filename> a string that
|
|
changes the behavior of that terminal.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>setterm -cursor off</userinput>
|
|
<computeroutput>bash$</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <command>setterm</command> command can be used within a
|
|
script to change the appearance of text written to
|
|
<filename>stdout</filename>, although there are certainly
|
|
<link linkend="colorizingref">better tools</link> available
|
|
for this purpose.</para>
|
|
|
|
<para><programlisting>setterm -bold on
|
|
echo bold hello
|
|
|
|
setterm -bold off
|
|
echo normal hello</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tsetref"/><command>tset</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tset</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tset</secondary>
|
|
</indexterm>
|
|
<para>Show or initialize terminal settings.
|
|
This is a less capable version of
|
|
<command>stty</command>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>tset -r</userinput>
|
|
<computeroutput>Terminal type is xterm-xfree86.
|
|
Kill is control-U (^U).
|
|
Interrupt is control-C (^C).</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="setserialref"/><command>setserial</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>setserial</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>serial</secondary>
|
|
</indexterm>
|
|
|
|
<para>Set or display serial port parameters. This command must be
|
|
run by <firstterm>root</firstterm> and is usually found in a
|
|
system setup script.</para>
|
|
|
|
<para><programlisting># From /etc/pcmcia/serial script:
|
|
|
|
IRQ=`setserial /dev/$DEVICE | sed -e 's/.*IRQ: //'`
|
|
setserial /dev/$DEVICE irq 0 ; setserial /dev/$DEVICE irq $IRQ</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="gettyref"/><command>getty</command></term>
|
|
<term><anchor id="agettyref"/><command>agetty</command></term>
|
|
<listitem>
|
|
<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>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mesg</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mesg</secondary>
|
|
</indexterm>
|
|
<para>Enables or disables write access to the current user's
|
|
terminal. Disabling access would prevent another user
|
|
on the network to <link linkend="writeref">write</link>
|
|
to the terminal.</para>
|
|
|
|
<tip><para>It can be quite annoying to have a message
|
|
about ordering pizza suddenly appear in the middle of
|
|
the text file you are editing. On a multi-user network,
|
|
you might therefore wish to disable write access to your
|
|
terminal when you need to avoid interruptions.</para></tip>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="wallref"/><command>wall</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>wall</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>wall</secondary>
|
|
</indexterm>
|
|
<para>This is an acronym for <quote><link
|
|
linkend="writeref">write</link> all,</quote> i.e., sending
|
|
a message to all users at every terminal logged into the
|
|
network. It is primarily a system administrator's tool,
|
|
useful, for example, when warning everyone that the
|
|
system will shortly go down due to a problem (see <xref
|
|
linkend="ex70"/>).</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>wall System going down for maintenance in 5 minutes!</userinput>
|
|
<computeroutput>Broadcast message from bozo (pts/1) Sun Jul 8 13:53:27 2001...
|
|
|
|
System going down for maintenance in 5 minutes!</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>If write access to a particular terminal has been
|
|
disabled with <command>mesg</command>, then
|
|
<command>wall</command> cannot send a message to
|
|
that terminal.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="statisticssys">
|
|
<title><anchor id="statisticssys1"/>Information and Statistics</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="unameref"/><command>uname</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>uname</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>uname</secondary>
|
|
</indexterm>
|
|
<para>Output system specifications (OS, kernel version,
|
|
etc.) to <filename>stdout</filename>. Invoked with the
|
|
<option>-a</option> option, gives verbose system info
|
|
(see <xref linkend="ex41"/>). The <option>-s</option>
|
|
option shows only the OS type.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>uname</userinput>
|
|
<computeroutput>Linux</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>uname -s</userinput>
|
|
<computeroutput>Linux</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>uname -a</userinput>
|
|
<computeroutput>Linux iron.bozo 2.6.15-1.2054_FC5 #1 Tue Mar 14 15:48:33 EST 2006
|
|
i686 i686 i386 GNU/Linux</computeroutput></screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="archref"/><command>arch</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>arch</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>arch</secondary>
|
|
</indexterm>
|
|
<para>Show system architecture.
|
|
Equivalent to <command>uname -m</command>. See <xref
|
|
linkend="casecmd"/>.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>arch</userinput>
|
|
<computeroutput>i686</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>uname -m</userinput>
|
|
<computeroutput>i686</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lastcommref"/><command>lastcomm</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lastcomm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>last</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lastlog</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>last</secondary>
|
|
</indexterm>
|
|
<para>List the last login time of all system users. This
|
|
references the <filename>/var/log/lastlog</filename>
|
|
file.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lastlog</userinput>
|
|
<computeroutput>root tty1 Fri Dec 7 18:43:21 -0700 2001
|
|
bin **Never logged in**
|
|
daemon **Never logged in**
|
|
...
|
|
bozo tty1 Sat Dec 8 21:14:29 -0700 2001</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>lastlog | grep root</userinput>
|
|
<computeroutput>root tty1 Fri Dec 7 18:43:21 -0700 2001</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<caution><para>This command will fail if the user invoking
|
|
it does not have read permission for the
|
|
<filename>/var/log/lastlog</filename> file.</para></caution>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lsofref"/><command>lsof</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lsof</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>lsof</secondary>
|
|
</indexterm>
|
|
<para>List open files. This command outputs a detailed
|
|
table of all currently open files and gives information
|
|
about their owner, size, the processes associated with
|
|
them, and more. Of course, <command>lsof</command> may
|
|
be piped to <link linkend="grepref">grep</link> and/or
|
|
<link linkend="awkref">awk</link> to parse and analyze
|
|
its results.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lsof</userinput>
|
|
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
|
|
init 1 root mem REG 3,5 30748 30303 /sbin/init
|
|
init 1 root mem REG 3,5 73120 8069 /lib/ld-2.1.3.so
|
|
init 1 root mem REG 3,5 931668 8075 /lib/libc-2.1.3.so
|
|
cardmgr 213 root mem REG 3,5 36956 30357 /sbin/cardmgr
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <command>lsof</command> command is a useful,
|
|
if complex administrative tool. If you are unable to
|
|
dismount a filesystem and get an error message that it is
|
|
still in use, then running <firstterm>lsof</firstterm> helps
|
|
determine which files are still open on that filesystem. The
|
|
<option>-i</option> option lists open network socket files,
|
|
and this can help trace intrusion or hack attempts.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lsof -an -i tcp</userinput>
|
|
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
|
|
firefox 2330 bozo 32u IPv4 9956 TCP 66.0.118.137:57596->67.112.7.104:http ...
|
|
firefox 2330 bozo 38u IPv4 10535 TCP 66.0.118.137:57708->216.79.48.24:http ...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>See <xref linkend="ipaddresses"/> for an effective use
|
|
of <command>lsof</command>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="straceref"/><command>strace</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>strace</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>trace</secondary>
|
|
</indexterm>
|
|
<para><command>S</command>ystem <command>trace</command>:
|
|
diagnostic and debugging tool for tracing <firstterm>system
|
|
calls</firstterm> and signals. This command and
|
|
<command>ltrace</command>, following, are useful for
|
|
diagnosing why a given program or package fails to
|
|
run . . . perhaps due to missing libraries or related
|
|
causes.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>strace df</userinput>
|
|
<computeroutput>execve("/bin/df", ["df"], [/* 45 vars */]) = 0
|
|
uname({sys="Linux", node="bozo.localdomain", ...}) = 0
|
|
brk(0) = 0x804f5e4
|
|
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>This is the Linux equivalent of
|
|
the Solaris <command>truss</command> command.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ltraceref"/><command>ltrace</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ltrace</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>trace</secondary>
|
|
</indexterm>
|
|
<para><command>L</command>ibrary <command>trace</command>:
|
|
diagnostic and debugging tool that traces <firstterm>library calls</firstterm>
|
|
invoked by a given command.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ltrace df</userinput>
|
|
<computeroutput>__libc_start_main(0x804a910, 1, 0xbfb589a4, 0x804fb70, 0x804fb68 <unfinished ...>
|
|
setlocale(6, "") = "en_US.UTF-8"
|
|
bindtextdomain("coreutils", "/usr/share/locale") = "/usr/share/locale"
|
|
textdomain("coreutils") = "coreutils"
|
|
__cxa_atexit(0x804b650, 0, 0, 0x8052bf0, 0xbfb58908) = 0
|
|
getenv("DF_BLOCK_SIZE") = NULL
|
|
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ncref"/><command>nc</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>nc</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>nc</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <command>nc</command> (<firstterm>netcat</firstterm>)
|
|
utility is a complete toolkit for connecting to and
|
|
listening to TCP and UDP ports. It is useful as a diagnostic
|
|
and testing tool and as a component in simple script-based HTTP
|
|
clients and servers.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>nc localhost.localdomain 25</userinput>
|
|
<computeroutput>220 localhost.localdomain ESMTP Sendmail 8.13.1/8.13.1;
|
|
Thu, 31 Mar 2005 15:41:35 -0700</computeroutput></screen>
|
|
</para>
|
|
|
|
<para>A real-life <link linkend="netcatexample">usage
|
|
example</link>.</para>
|
|
|
|
<example id="iscan">
|
|
<title>Checking a remote server for
|
|
<firstterm>identd</firstterm></title>
|
|
<programlisting>&iscan;</programlisting>
|
|
</example>
|
|
|
|
<para>
|
|
And, of course, there's Dr. Andrew Tridgell's notorious
|
|
one-line script in the BitKeeper Affair:
|
|
<programlisting>echo clone | nc thunk.org 5000 > e2fsprogs.dat</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="freeref"/><command>free</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>free</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>free</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>procinfo</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>procinfo</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lsdev</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>device</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>du</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>du</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>df</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>df</secondary>
|
|
</indexterm>
|
|
<para>Shows filesystem usage in tabular form.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><command>df</command>
|
|
<computeroutput>Filesystem 1k-blocks Used Available Use% Mounted on
|
|
/dev/hda5 273262 92607 166547 36% /
|
|
/dev/hda8 222525 123951 87085 59% /home
|
|
/dev/hda7 1408796 1075744 261488 80% /usr</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dmesgref"/><command>dmesg</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>dmesg</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dmesg</secondary>
|
|
</indexterm>
|
|
<para>Lists all system bootup messages to
|
|
<filename>stdout</filename>. Handy for debugging and
|
|
ascertaining which device drivers were installed
|
|
and which system interrupts in use. The output
|
|
of <command>dmesg</command> may, of course, be
|
|
parsed with <link linkend="grepref">grep</link>,
|
|
<link linkend="sedref">sed</link>, or <link
|
|
linkend="awkref">awk</link> from within a script.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>dmesg | grep hda</userinput>
|
|
<computeroutput>Kernel command line: ro root=/dev/hda2
|
|
hda: IBM-DLGA-23080, ATA DISK drive
|
|
hda: 6015744 sectors (3080 MB) w/96KiB Cache, CHS=746/128/63
|
|
hda: hda1 hda2 hda3 < hda5 hda6 hda7 > hda4</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="statref"/><command>stat</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>stat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>stat</secondary>
|
|
</indexterm>
|
|
<para>Gives detailed and verbose <emphasis>stat</emphasis>istics
|
|
on a given file (even a directory or device file) or set
|
|
of files.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>stat test.cru</userinput>
|
|
<computeroutput> File: "test.cru"
|
|
Size: 49970 Allocated Blocks: 100 Filetype: Regular File
|
|
Mode: (0664/-rw-rw-r--) Uid: ( 501/ bozo) Gid: ( 501/ bozo)
|
|
Device: 3,8 Inode: 18185 Links: 1
|
|
Access: Sat Jun 2 16:40:24 2001
|
|
Modify: Sat Jun 2 16:40:24 2001
|
|
Change: Sat Jun 2 16:40:24 2001</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>If the target file does not exist, <command>stat</command>
|
|
returns an error message.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>stat nonexistent-file</userinput>
|
|
<computeroutput>nonexistent-file: No such file or directory</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>In a script, you can use <command>stat</command> to extract
|
|
information about files (and filesystems) and set variables
|
|
accordingly.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# fileinfo2.sh
|
|
|
|
# Per suggestion of Joël Bourquard and . . .
|
|
# http://www.linuxquestions.org/questions/showthread.php?t=410766
|
|
|
|
|
|
FILENAME=testfile.txt
|
|
file_name=$(stat -c%n "$FILENAME") # Same as "$FILENAME" of course.
|
|
file_owner=$(stat -c%U "$FILENAME")
|
|
file_size=$(stat -c%s "$FILENAME")
|
|
# Certainly easier than using "ls -l $FILENAME"
|
|
#+ and then parsing with sed.
|
|
file_inode=$(stat -c%i "$FILENAME")
|
|
file_type=$(stat -c%F "$FILENAME")
|
|
file_access_rights=$(stat -c%A "$FILENAME")
|
|
|
|
echo "File name: $file_name"
|
|
echo "File owner: $file_owner"
|
|
echo "File size: $file_size"
|
|
echo "File inode: $file_inode"
|
|
echo "File type: $file_type"
|
|
echo "File access rights: $file_access_rights"
|
|
|
|
exit 0
|
|
|
|
sh fileinfo2.sh
|
|
|
|
File name: testfile.txt
|
|
File owner: bozo
|
|
File size: 418
|
|
File inode: 1730378
|
|
File type: regular file
|
|
File access rights: -rw-rw-r--</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="vmstatref"/><command>vmstat</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>vmstat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>virtual memory</secondary>
|
|
</indexterm>
|
|
<para>Display virtual memory statistics.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>vmstat</userinput>
|
|
<computeroutput> procs memory swap io system cpu
|
|
r b w swpd free buff cache si so bi bo in cs us sy id
|
|
0 0 0 0 11040 2636 38952 0 0 33 7 271 88 8 3 89</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="uptimeref"/><command>uptime</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>uptime</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>uptime</secondary>
|
|
</indexterm>
|
|
|
|
<para>Shows how long the system has been running, along with
|
|
associated statistics.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>uptime</userinput>
|
|
<computeroutput>10:28pm up 1:57, 3 users, load average: 0.17, 0.34, 0.27</computeroutput></screen>
|
|
</para>
|
|
|
|
<note><para>A <firstterm>load average</firstterm> of 1 or less
|
|
indicates that the system handles processes immediately. A load
|
|
average greater than 1 means that processes are being queued. When
|
|
the load average gets above 3 (on a single-core processor),
|
|
then system performance is significantly degraded.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="hnameref"/><command>hostname</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>hostname</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>hostname</secondary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>hostid</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>host id</secondary>
|
|
</indexterm>
|
|
|
|
<para>Echo a 32-bit hexadecimal numerical identifier for the
|
|
host machine.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>hostid</userinput>
|
|
<computeroutput>7f0100</computeroutput></screen>
|
|
</para>
|
|
|
|
<note>
|
|
<para>This command allegedly fetches a <quote>unique</quote>
|
|
serial number for a particular system. Certain
|
|
product registration procedures use this number
|
|
to brand a particular user license. Unfortunately,
|
|
<command>hostid</command> only returns the machine
|
|
network address in hexadecimal, with pairs of bytes
|
|
transposed.</para>
|
|
|
|
<para>The network address of a typical non-networked Linux
|
|
machine, is found in <filename>/etc/hosts</filename>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>cat /etc/hosts</userinput>
|
|
<computeroutput>127.0.0.1 localhost.localdomain localhost</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>As it happens, transposing the bytes of
|
|
<userinput>127.0.0.1</userinput>, we get
|
|
<userinput>0.127.1.0</userinput>, which translates in
|
|
hex to <userinput>007f0100</userinput>, the exact equivalent
|
|
of what <command>hostid</command> returns, above. There
|
|
exist only a few million other Linux machines with this
|
|
identical <firstterm>hostid</firstterm>.</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sarref"/><command>sar</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>sar</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>system activity report</secondary>
|
|
</indexterm>
|
|
<para>Invoking <command>sar</command> (System Activity Reporter)
|
|
gives a very detailed rundown on system statistics. The
|
|
Santa Cruz Operation (<quote>Old</quote> SCO) released
|
|
<command>sar</command> as Open Source in June, 1999.</para>
|
|
|
|
<para>This command is not part of the base Linux distribution,
|
|
but may be obtained as part of the<ulink
|
|
url="http://perso.wanadoo.fr/sebastien.godard/">
|
|
sysstat utilities</ulink> package, written by <ulink
|
|
url="mailto:sebastien.godard@wanadoo.fr">Sebastien
|
|
Godard</ulink>.</para>
|
|
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>sar</userinput>
|
|
<computeroutput>Linux 2.4.9 (brooks.seringas.fr) 09/26/03
|
|
|
|
10:30:00 CPU %user %nice %system %iowait %idle
|
|
10:40:00 all 2.21 10.90 65.48 0.00 21.41
|
|
10:50:00 all 3.36 0.00 72.36 0.00 24.28
|
|
11:00:00 all 1.12 0.00 80.77 0.00 18.11
|
|
Average: all 2.23 3.63 72.87 0.00 21.27
|
|
|
|
14:32:30 LINUX RESTART
|
|
|
|
15:00:00 CPU %user %nice %system %iowait %idle
|
|
15:10:00 all 8.59 2.40 17.47 0.00 71.54
|
|
15:20:00 all 4.07 1.00 11.95 0.00 82.98
|
|
15:30:00 all 0.79 2.94 7.56 0.00 88.71
|
|
Average: all 6.33 1.70 14.71 0.00 77.26</computeroutput>
|
|
</screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="readelfref"/><command>readelf</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>elf</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>statistics</secondary>
|
|
</indexterm>
|
|
<para>Show information and statistics about a designated
|
|
<firstterm>elf</firstterm> binary. This is part of the
|
|
<firstterm>binutils</firstterm> package.</para>
|
|
<screen><prompt>bash$ </prompt><userinput>readelf -h /bin/bash</userinput>
|
|
<computeroutput>ELF Header:
|
|
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
|
|
Class: ELF32
|
|
Data: 2's complement, little endian
|
|
Version: 1 (current)
|
|
OS/ABI: UNIX - System V
|
|
ABI Version: 0
|
|
Type: EXEC (Executable file)
|
|
. . .</computeroutput></screen>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="sizeref"/><command>size</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>size</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>segment</secondary>
|
|
</indexterm>
|
|
<para>The <command>size [/path/to/binary]</command> command
|
|
gives the segment sizes of a binary executable or archive file.
|
|
This is mainly of use to programmers.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>size /bin/bash</userinput>
|
|
<computeroutput> text data bss dec hex filename
|
|
495971 22496 17392 535859 82d33 /bin/bash</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="syslog">
|
|
<title><anchor id="syslog1"/>System Logs</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="loggerref"/><command>logger</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>logger</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>logger</secondary>
|
|
</indexterm>
|
|
|
|
<para>Appends a user-generated message to the system log
|
|
(<filename>/var/log/messages</filename>). You do not have
|
|
to be <firstterm>root</firstterm> to invoke
|
|
<command>logger</command>.</para>
|
|
|
|
<para>
|
|
<programlisting>logger Experiencing instability in network connection at 23:10, 05/21.
|
|
# Now, do a 'tail /var/log/messages'.</programlisting></para>
|
|
|
|
<para>By embedding a <command>logger</command> command in a script,
|
|
it is possible to write debugging information to
|
|
<filename>/var/log/messages</filename>.</para>
|
|
|
|
<para><programlisting>logger -t $0 -i Logging at line "$LINENO".
|
|
# The "-t" option specifies the tag for the logger entry.
|
|
# The "-i" option records the process ID.
|
|
|
|
# tail /var/log/message
|
|
# ...
|
|
# Jul 7 20:48:58 localhost ./test.sh[1712]: Logging at line 3.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="logrotateref"/><command>logrotate</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>logrotate</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>logrotate</secondary>
|
|
</indexterm>
|
|
|
|
<para>This utility manages the system log files, rotating,
|
|
compressing, deleting, and/or e-mailing them, as appropriate.
|
|
This keeps the <filename class="directory">/var/log</filename>
|
|
from getting cluttered with old log files.
|
|
Usually <link linkend="cronref">cron</link> runs
|
|
<command>logrotate</command> on a daily basis.</para>
|
|
|
|
<para>Adding an appropriate entry to
|
|
<filename>/etc/logrotate.conf</filename> makes it possible
|
|
to manage personal log files, as well as system-wide
|
|
ones.</para>
|
|
|
|
<note><para>Stefano Falsetto has created <ulink
|
|
url="http://www.gnu.org/software/rottlog/">rottlog</ulink>,
|
|
which he considers to be an improved version of
|
|
<command>logrotate</command>.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="jobcontrolsys">
|
|
<title><anchor id="jobcontrolsys1"/>Job Control</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ppssref"/><command>ps</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ps</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ps</secondary>
|
|
</indexterm>
|
|
|
|
<para><replaceable>P</replaceable>rocess
|
|
<replaceable>S</replaceable>tatistics: lists currently
|
|
executing processes by owner and PID (process ID). This
|
|
is usually invoked with <option>ax</option> or
|
|
<option>aux</option> options,
|
|
and may be piped to <link linkend="grepref">grep</link>
|
|
or <link linkend="sedref">sed</link> to search for a
|
|
specific process (see <xref linkend="ex44"/> and <xref
|
|
linkend="pidid"/>).</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput> ps ax | grep sendmail</userinput>
|
|
<computeroutput>295 ? S 0:00 sendmail: accepting connections on port 25</computeroutput></screen>
|
|
|
|
<para>To display system processes in graphical <quote>tree</quote>
|
|
format: <command>ps afjx</command> or
|
|
<command>ps ax --forest</command>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pgrepref"/><command>pgrep</command></term>
|
|
<term><anchor id="pkillref"/><command>pkill</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>pgrep</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>process grep</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>pkill</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>process kill</secondary>
|
|
</indexterm>
|
|
|
|
<para>Combining the <command>ps</command> command
|
|
with <link linkend="grepref">grep</link> or
|
|
<link linkend="killref">kill</link>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ps a | grep mingetty</userinput>
|
|
<computeroutput>2212 tty2 Ss+ 0:00 /sbin/mingetty tty2
|
|
2213 tty3 Ss+ 0:00 /sbin/mingetty tty3
|
|
2214 tty4 Ss+ 0:00 /sbin/mingetty tty4
|
|
2215 tty5 Ss+ 0:00 /sbin/mingetty tty5
|
|
2216 tty6 Ss+ 0:00 /sbin/mingetty tty6
|
|
4849 pts/2 S+ 0:00 grep mingetty</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>pgrep mingetty</userinput>
|
|
<computeroutput>2212 mingetty
|
|
2213 mingetty
|
|
2214 mingetty
|
|
2215 mingetty
|
|
2216 mingetty</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Compare the action of <command>pkill</command> with <link
|
|
linkend="killallref">killall</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pstreeref"/><command>pstree</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>pstree</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>pstree</secondary>
|
|
</indexterm>
|
|
<para>Lists currently executing processes in
|
|
<quote>tree</quote> format. The <option>-p</option> option
|
|
shows the PIDs, as well as the process names.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="topref"/><command>top</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>top</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>processes</secondary>
|
|
</indexterm>
|
|
|
|
<para>Continuously updated display of most cpu-intensive
|
|
processes. The <option>-b</option> option displays in text
|
|
mode, so that the output may be parsed or accessed from
|
|
a script.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>top -b</userinput>
|
|
<computeroutput> 8:30pm up 3 min, 3 users, load average: 0.49, 0.32, 0.13
|
|
45 processes: 44 sleeping, 1 running, 0 zombie, 0 stopped
|
|
CPU states: 13.6% user, 7.3% system, 0.0% nice, 78.9% idle
|
|
Mem: 78396K av, 65468K used, 12928K free, 0K shrd, 2352K buff
|
|
Swap: 157208K av, 0K used, 157208K free 37244K cached
|
|
|
|
PID USER PRI NI SIZE RSS SHARE STAT %CPU %MEM TIME COMMAND
|
|
848 bozo 17 0 996 996 800 R 5.6 1.2 0:00 top
|
|
1 root 8 0 512 512 444 S 0.0 0.6 0:04 init
|
|
2 root 9 0 0 0 0 SW 0.0 0.0 0:00 keventd
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="niceref"/><command>nice</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>nice</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>nice</secondary>
|
|
</indexterm>
|
|
<para><anchor id="nice2ref"/></para>
|
|
<para>Run a background job with an altered
|
|
priority. Priorities run from 19 (lowest) to -20
|
|
(highest). Only <firstterm>root</firstterm> may set the
|
|
negative (higher) priorities. Related commands are
|
|
<command>renice</command> and <command>snice</command>,
|
|
which change the priority of a running process or
|
|
processes, and <command>skill</command>, which sends a
|
|
<link linkend="killref">kill</link> signal to a process
|
|
or processes.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="nohupref"/><command>nohup</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>nohup</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>nohup</secondary>
|
|
</indexterm>
|
|
<para>Keeps a command running even after user logs off.
|
|
The command will run as a foreground process unless followed
|
|
by <token>&</token>. If you use <command>nohup</command>
|
|
within a script, consider coupling it with a <link
|
|
linkend="waitref">wait</link> to avoid creating an
|
|
<firstterm>orphan</firstterm> or
|
|
<link linkend="zombieref">zombie</link> process.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="pidofref"/><command>pidof</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>pidof</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>process ID</secondary>
|
|
</indexterm>
|
|
<para>Identifies <firstterm>process ID (PID)</firstterm> of a
|
|
running job. Since job control commands, such as <link
|
|
linkend="killref">kill</link> and <link
|
|
linkend="nice2ref">renice</link> act on the
|
|
<firstterm>PID</firstterm> of a process (not its
|
|
name), it is sometimes necessary to identify that
|
|
<firstterm>PID</firstterm>. The <command>pidof</command>
|
|
command is the approximate counterpart to the <link
|
|
linkend="ppidref">$PPID</link> internal variable.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>pidof xclock</userinput>
|
|
<computeroutput>880</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<example id="killprocess">
|
|
<title><firstterm>pidof</firstterm> helps kill a process</title>
|
|
<programlisting>&killprocess;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="fuserref"/><command>fuser</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>fuser</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>fuser</secondary>
|
|
</indexterm>
|
|
<para>Identifies the processes (by PID) that are accessing
|
|
a given file, set of files, or directory. May also be
|
|
invoked with the <option>-k</option> option, which kills
|
|
those processes. This has interesting implications for
|
|
system security, especially in scripts preventing
|
|
unauthorized users from accessing system services.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>fuser -u /usr/bin/vim</userinput>
|
|
<computeroutput>/usr/bin/vim: 3207e(bozo)</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>fuser -u /dev/null</userinput>
|
|
<computeroutput>/dev/null: 3009(bozo) 3010(bozo) 3197(bozo) 3199(bozo)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>One important application for <command>fuser</command> is
|
|
when physically inserting or removing storage media, such
|
|
as CD ROM disks or USB flash drives. Sometimes trying
|
|
a <link linkend="umountref">umount</link> fails with a
|
|
<errorname>device is busy</errorname> error message. This
|
|
means that some user(s) and/or process(es) are accessing
|
|
the device. An <command>fuser -um /dev/device_name</command>
|
|
will clear up the mystery, so you can kill any relevant
|
|
processes.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>umount /mnt/usbdrive</userinput>
|
|
<computeroutput>umount: /mnt/usbdrive: device is busy</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>fuser -um /dev/usbdrive</userinput>
|
|
<computeroutput>/mnt/usbdrive: 1772c(bozo)</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>kill -9 1772</userinput>
|
|
<prompt>bash$ </prompt><userinput>umount /mnt/usbdrive</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para> The <command>fuser</command> command, invoked with the
|
|
<option>-n</option> option identifies the processes
|
|
accessing a <firstterm>port</firstterm>. This
|
|
is especially useful in combination with <link
|
|
linkend="nmapref">nmap</link>.</para>
|
|
|
|
<para>
|
|
<screen><prompt>root# </prompt><userinput>nmap localhost.localdomain</userinput>
|
|
<computeroutput>PORT STATE SERVICE
|
|
25/tcp open smtp</computeroutput>
|
|
|
|
|
|
|
|
<prompt>root# </prompt><userinput>fuser -un tcp 25</userinput>
|
|
<computeroutput>25/tcp: 2095(root)</computeroutput>
|
|
|
|
<prompt>root# </prompt><userinput>ps ax | grep 2095 | grep -v grep</userinput>
|
|
<computeroutput>2095 ? Ss 0:00 sendmail: accepting connections</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cronref"/><command>cron</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>cron</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>crond</secondary>
|
|
</indexterm>
|
|
|
|
<para>Administrative program scheduler, performing such
|
|
duties as cleaning up and deleting system log files and
|
|
updating the <database>slocate</database> database. This
|
|
is the <firstterm>superuser</firstterm> version of <link
|
|
linkend="atref">at</link> (although each user may have
|
|
their own <filename>crontab</filename> file which can be
|
|
changed with the <command>crontab</command> command).
|
|
It runs as a <link linkend="daemonref">daemon</link>
|
|
and executes scheduled entries from
|
|
<filename>/etc/crontab</filename>.</para>
|
|
|
|
<note><para>Some flavors of Linux run
|
|
<command>crond</command>, Matthew Dillon's version of
|
|
<command>cron</command>.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<variablelist id="runcontrolsys">
|
|
<title><anchor id="runcontrolsys1"/>Process Control and Booting</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="initref"/><command>init</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>init</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>init</secondary>
|
|
</indexterm>
|
|
<para><anchor id="inittabref"/></para>
|
|
<para>The <command>init</command> command is the <link
|
|
linkend="forkref">parent</link> of all processes. Called
|
|
in the final step of a bootup, <command>init</command>
|
|
determines the runlevel of the system from
|
|
<filename>/etc/inittab</filename>. Invoked by its alias
|
|
<command>telinit</command>, and by
|
|
<firstterm>root</firstterm> only.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="telinitref"/><command>telinit</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>telinit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>telinit</secondary>
|
|
</indexterm>
|
|
<para>Symlinked to <command>init</command>, this is a means of changing the system runlevel,
|
|
usually done for system maintenance or emergency filesystem
|
|
repairs. Invoked only by <firstterm>root</firstterm>. This
|
|
command can be dangerous -- be certain you understand it
|
|
well before using!</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="runlevelref"/><command>runlevel</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>runlevel</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>runlevel</secondary>
|
|
</indexterm>
|
|
<para>Shows the current and last runlevel, that is, whether the system
|
|
is halted (runlevel <literal>0</literal>), in single-user mode
|
|
(<literal>1</literal>), in multi-user mode (<literal>2</literal>
|
|
or <literal>3</literal>), in X Windows (<literal>5</literal>), or
|
|
rebooting (<literal>6</literal>). This command accesses the
|
|
<filename>/var/run/utmp</filename> file.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="haltref"/><command>halt</command></term>
|
|
<term><anchor id="shutdownref"/><command>shutdown</command></term>
|
|
<term><anchor id="rebootref"/><command>reboot</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>Command set to shut the system down, usually just prior to a power down.</para>
|
|
<warning><para>On some Linux distros, the <command>halt</command> command
|
|
has 755 permissions, so it can be invoked by a non-root user.
|
|
A careless <firstterm>halt</firstterm> in a terminal or a script
|
|
may shut down the system!</para></warning>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="serviceref"/><command>service</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>service</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>service</secondary>
|
|
</indexterm>
|
|
<para>Starts or stops a system <firstterm>service</firstterm>.
|
|
The startup scripts in <filename class="directory">/etc/init.d</filename>
|
|
and <filename class="directory">/etc/rc.d</filename> use this
|
|
command to start services at bootup.</para>
|
|
|
|
<para><anchor id="iptables01"/></para>
|
|
|
|
<para>
|
|
<screen><prompt>root# </prompt><userinput>/sbin/service iptables stop</userinput>
|
|
<computeroutput>Flushing firewall rules: [ OK ]
|
|
Setting chains to policy ACCEPT: filter [ OK ]
|
|
Unloading iptables modules: [ OK ]</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="networksys">
|
|
<title><anchor id="networksys1"/>Network</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="nmapref"/><command>nmap</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>nmap</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>port scan</secondary>
|
|
</indexterm>
|
|
<para><command>N</command>etwork <command>map</command>per
|
|
and port scanner. This command scans a server to
|
|
locate open ports and the services associated with those
|
|
ports. It can also report information about packet filters and
|
|
firewalls. This is an important security tool for locking down
|
|
a network against hacking attempts.</para>
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
SERVER=$HOST # localhost.localdomain (127.0.0.1).
|
|
PORT_NUMBER=25 # SMTP port.
|
|
|
|
nmap $SERVER | grep -w "$PORT_NUMBER" # Is that particular port open?
|
|
# grep -w matches whole words only,
|
|
#+ so this wouldn't match port 1025, for example.
|
|
|
|
exit 0
|
|
|
|
# 25/tcp open smtp</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ifconfigref"/><command>ifconfig</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ifconfig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ifconfig</secondary>
|
|
</indexterm>
|
|
<para>Network <firstterm>interface configuration</firstterm>
|
|
and tuning utility.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>ifconfig -a</userinput>
|
|
<computeroutput>lo Link encap:Local Loopback
|
|
inet addr:127.0.0.1 Mask:255.0.0.0
|
|
UP LOOPBACK RUNNING MTU:16436 Metric:1
|
|
RX packets:10 errors:0 dropped:0 overruns:0 frame:0
|
|
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
|
|
collisions:0 txqueuelen:0
|
|
RX bytes:700 (700.0 b) TX bytes:700 (700.0 b)</computeroutput></screen>
|
|
|
|
<para>The <command>ifconfig</command> command is most often used
|
|
at bootup to set up the interfaces, or to shut them down
|
|
when rebooting.</para>
|
|
|
|
<para><programlisting># Code snippets from /etc/rc.d/init.d/network
|
|
|
|
# ...
|
|
|
|
# Check that networking is up.
|
|
[ ${NETWORKING} = "no" ] && exit 0
|
|
|
|
[ -x /sbin/ifconfig ] || exit 0
|
|
|
|
# ...
|
|
|
|
for i in $interfaces ; do
|
|
if ifconfig $i 2>/dev/null | grep -q "UP" >/dev/null 2>&1 ; then
|
|
action "Shutting down interface $i: " ./ifdown $i boot
|
|
fi
|
|
# The GNU-specific "-q" option to "grep" means "quiet", i.e.,
|
|
#+ producing no output.
|
|
# Redirecting output to /dev/null is therefore not strictly necessary.
|
|
|
|
# ...
|
|
|
|
echo "Currently active devices:"
|
|
echo `/sbin/ifconfig | grep ^[a-z] | awk '{print $1}'`
|
|
# ^^^^^ should be quoted to prevent globbing.
|
|
# The following also work.
|
|
# echo $(/sbin/ifconfig | awk '/^[a-z]/ { print $1 })'
|
|
# echo $(/sbin/ifconfig | sed -e 's/ .*//')
|
|
# Thanks, S.C., for additional comments.</programlisting></para>
|
|
|
|
<para>See also <xref linkend="online"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="netstatref"/><command>netstat</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>netstat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>netstat</secondary>
|
|
</indexterm>
|
|
|
|
<para>Show current network statistics and information,
|
|
such as routing tables and active connections. This utility
|
|
accesses information in <filename>/proc/net</filename>
|
|
(<xref linkend="devproc"/>). See <xref
|
|
linkend="constat"/>.</para>
|
|
<para><command>netstat -r</command> is equivalent to <link
|
|
linkend="routeref">route</link>.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>netstat</userinput>
|
|
<computeroutput>Active Internet connections (w/o servers)
|
|
Proto Recv-Q Send-Q Local Address Foreign Address State
|
|
Active UNIX domain sockets (w/o servers)
|
|
Proto RefCnt Flags Type State I-Node Path
|
|
unix 11 [ ] DGRAM 906 /dev/log
|
|
unix 3 [ ] STREAM CONNECTED 4514 /tmp/.X11-unix/X0
|
|
unix 3 [ ] STREAM CONNECTED 4513
|
|
. . .</computeroutput></screen>
|
|
|
|
<note><para>A <command>netstat -lptu</command> shows <link
|
|
linkend="socketref">sockets</link> that are listening
|
|
to ports, and the associated processes. This can be useful
|
|
for determining whether a computer has been hacked or
|
|
compromised.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="iwconfigref"/><command>iwconfig</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>iwconfig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>wireless</secondary>
|
|
</indexterm>
|
|
<para>This is the command set for configuring a wireless network.
|
|
It is the wireless equivalent of <command>ifconfig</command>,
|
|
above.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ipref"/><command>ip</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ip</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>routing</secondary>
|
|
</indexterm>
|
|
|
|
<para>General purpose utility for setting up, changing, and
|
|
analyzing <firstterm>IP</firstterm> (Internet Protocol)
|
|
networks and attached devices. This command is part of
|
|
the <firstterm>iproute2</firstterm> package.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>ip link show</userinput>
|
|
<computeroutput>1: lo: <LOOPBACK,UP> mtu 16436 qdisc noqueue
|
|
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
|
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast qlen 1000
|
|
link/ether 00:d0:59:ce:af:da brd ff:ff:ff:ff:ff:ff
|
|
3: sit0: <NOARP> mtu 1480 qdisc noop
|
|
link/sit 0.0.0.0 brd 0.0.0.0</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>ip route list</userinput>
|
|
<computeroutput>169.254.0.0/16 dev lo scope link</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Or, in a script:</para>
|
|
|
|
<para><anchor id="ipscript0"/>
|
|
<programlisting>&ipscript;</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="routeref"/><command>route</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>route</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>route</secondary>
|
|
</indexterm>
|
|
|
|
<para>Show info about or make changes to the kernel routing table.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>route</userinput>
|
|
<computeroutput>Destination Gateway Genmask Flags MSS Window irtt Iface
|
|
pm3-67.bozosisp * 255.255.255.255 UH 40 0 0 ppp0
|
|
127.0.0.0 * 255.0.0.0 U 40 0 0 lo
|
|
default pm3-67.bozosisp 0.0.0.0 UG 40 0 0 ppp0</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor
|
|
id="iptablesref"/><command>iptables</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>iptables</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>firewall</secondary>
|
|
</indexterm>
|
|
|
|
|
|
<para> The <command>iptables</command> command set is
|
|
a packet filtering tool used mainly for such security
|
|
purposes as setting up network firewalls. This
|
|
is a complex tool, and a detailed explanation of
|
|
its use is beyond the scope of this document. <ulink
|
|
url="http://www.frozentux.net/iptables-tutorial/iptables-tutorial.html">Oskar
|
|
Andreasson's tutorial</ulink> is a reasonable starting
|
|
point.</para>
|
|
|
|
<para>See also <link linkend="iptables01">shutting down
|
|
<firstterm>iptables</firstterm></link> and <xref
|
|
linkend="ipaddresses"/>.</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="chkconfigref"/><command>chkconfig</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>chkconfig</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>network configuration</secondary>
|
|
</indexterm>
|
|
|
|
<para>Check network and system configuration. This command
|
|
lists and
|
|
manages the network and system services started at bootup in
|
|
the <filename class="directory">/etc/rc?.d</filename>
|
|
directory.</para>
|
|
|
|
<para>Originally a port from IRIX to Red Hat Linux,
|
|
<command>chkconfig</command> may not be part of the core
|
|
installation of some Linux flavors.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>chkconfig --list</userinput>
|
|
<computeroutput>atd 0:off 1:off 2:off 3:on 4:on 5:on 6:off
|
|
rwhod 0:off 1:off 2:off 3:off 4:off 5:off 6:off
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tcpdumpref"/><command>tcpdump</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tcpdump</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tcp</secondary>
|
|
</indexterm>
|
|
<para>Network packet <quote>sniffer.</quote> This is a tool for
|
|
analyzing and troubleshooting traffic on a network by dumping
|
|
packet headers that match specified criteria.</para>
|
|
|
|
<para>Dump ip packet traffic between hosts
|
|
<emphasis>bozoville</emphasis> and
|
|
<emphasis>caduceus</emphasis>:</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>tcpdump ip host bozoville and caduceus</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Of course, the output of <command>tcpdump</command> can be
|
|
parsed with certain of the previously discussed <link
|
|
linkend="tpcommandlisting1">text processing
|
|
utilities</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
|
|
<variablelist id="filesystemsys">
|
|
<title><anchor id="filesystemsys1"/>Filesystem</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mountref"/><command>mount</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mount</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mount</secondary>
|
|
</indexterm>
|
|
<para>Mount a filesystem, usually on an external device,
|
|
such as a floppy or CDROM. <anchor id="fstabref"/>The file
|
|
<filename>/etc/fstab</filename> provides a handy listing
|
|
of available filesystems, partitions, and devices,
|
|
including options, that may be automatically or manually
|
|
mounted. The file <filename>/etc/mtab</filename> shows
|
|
the currently mounted filesystems and partitions
|
|
(including the virtual ones, such as <filename
|
|
class="directory">/proc</filename>).</para>
|
|
|
|
<para><command>mount -a</command> mounts all filesystems and
|
|
partitions listed in <filename>/etc/fstab</filename>,
|
|
except those with a <option>noauto</option>
|
|
option. At bootup, a startup script in
|
|
<filename class="directory">/etc/rc.d</filename>
|
|
(<filename>rc.sysinit</filename> or something similar)
|
|
invokes this to get everything mounted.</para>
|
|
|
|
|
|
<para><programlisting>mount -t iso9660 /dev/cdrom /mnt/cdrom
|
|
# Mounts CD ROM. ISO 9660 is a standard CD ROM filesystem.
|
|
mount /mnt/cdrom
|
|
# Shortcut, if /mnt/cdrom listed in /etc/fstab</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="isomountref0"/></para>
|
|
<para>The versatile <firstterm>mount</firstterm> command can even
|
|
mount an ordinary file on a block device, and the file will
|
|
act as if it were a filesystem. <firstterm>Mount</firstterm>
|
|
accomplishes that by associating the file with a <link
|
|
linkend="loopbackref">loopback device</link>. One application of
|
|
this is to mount and examine an ISO9660 filesystem image before
|
|
burning it onto a CDR.
|
|
|
|
<footnote><para>For more detail on burning CDRs, see Alex
|
|
Withers' article, <ulink
|
|
url="http://www2.linuxjournal.com/lj-issues/issue66/3335.html">Creating
|
|
CDs</ulink>, in the October, 1999 issue of <ulink
|
|
url="http://www.linuxjournal.com"><citetitle
|
|
pubwork="journal">Linux
|
|
Journal</citetitle></ulink>.</para></footnote>
|
|
|
|
</para>
|
|
|
|
<example id="isomountref">
|
|
<title>Checking a CD image</title>
|
|
<programlisting># As root...
|
|
|
|
mkdir /mnt/cdtest # Prepare a mount point, if not already there.
|
|
|
|
mount -r -t iso9660 -o loop cd-image.iso /mnt/cdtest # Mount the image.
|
|
# "-o loop" option equivalent to "losetup /dev/loop0"
|
|
cd /mnt/cdtest # Now, check the image.
|
|
ls -alR # List the files in the directory tree there.
|
|
# And so forth.</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="umountref"/><command>umount</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>umount</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>umount</secondary>
|
|
</indexterm>
|
|
<para>Unmount a currently mounted filesystem. Before physically removing a
|
|
previously mounted floppy or CDROM disk, the device must be
|
|
<command>umount</command>ed, else filesystem corruption may result.
|
|
<programlisting>umount /mnt/cdrom
|
|
# You may now press the eject button and safely remove the disk.</programlisting></para>
|
|
|
|
<note><para>The <command>automount</command> utility, if
|
|
properly installed, can mount and unmount floppies or
|
|
CDROM disks as they are accessed or removed. On
|
|
<quote>multispindle</quote> laptops with swappable
|
|
floppy and optical drives, this can cause problems,
|
|
however.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="gnomemountref"/><command>gnome-mount</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>gnome-mount</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mount</secondary>
|
|
</indexterm>
|
|
<para>The newer Linux distros have deprecated
|
|
<command>mount</command> and <command>umount</command>.
|
|
The successor, for command-line mounting of removable storage
|
|
devices, is <command>gnome-mount</command>. It can take the
|
|
<option>-d</option> option to mount a <link
|
|
linkend="devfileref">device file</link> by its listing in
|
|
<filename class="directory">/dev</filename>.</para>
|
|
|
|
<para>For example, to mount a USB flash drive:</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>gnome-mount -d /dev/sda1</userinput>
|
|
<computeroutput>gnome-mount 0.4</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>df</userinput>
|
|
<computeroutput>. . .
|
|
/dev/sda1 63584 12034 51550 19% /media/disk</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="syncref"/><command>sync</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>sync</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>sync</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>losetup</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>losetup</secondary>
|
|
</indexterm>
|
|
<para>Sets up and configures <link linkend="loopbackref">
|
|
loopback devices</link>.</para>
|
|
|
|
<example id="createfs">
|
|
<title>Creating a filesystem in a file</title>
|
|
<programlisting>SIZE=1000000 # 1 meg
|
|
|
|
head -c $SIZE < /dev/zero > file # Set up file of designated size.
|
|
losetup /dev/loop0 file # Set it up as loopback device.
|
|
mke2fs /dev/loop0 # Create filesystem.
|
|
mount -o loop /dev/loop0 /mnt # Mount it.
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mkswapref"/><command>mkswap</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mkswap</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mkswap</secondary>
|
|
</indexterm>
|
|
<para>Creates a swap partition or file. The swap area must
|
|
subsequently be enabled with
|
|
<command>swapon</command>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="swaponref"/><command>swapon</command></term>
|
|
<term><anchor id="swapoffref"/><command>swapoff</command></term>
|
|
<listitem>
|
|
<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>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mke2fs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mke2fs</secondary>
|
|
</indexterm>
|
|
<para>Create a Linux <firstterm>ext2</firstterm>
|
|
filesystem. This command must be invoked as
|
|
<firstterm>root</firstterm>.</para>
|
|
|
|
|
|
<example id="adddrv">
|
|
<title>Adding a new hard drive</title>
|
|
<programlisting>&adddrv;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="createfs"/> and <xref
|
|
linkend="ramdisk"/>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mkdosfsref"/><command>mkdosfs</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mkdosfs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mkdosfs</secondary>
|
|
</indexterm>
|
|
<para>Create a DOS <firstterm>FAT</firstterm>
|
|
filesystem.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tune2fsref"/><command>tune2fs</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tune2fs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tune2fs</secondary>
|
|
</indexterm>
|
|
<para>Tune <firstterm>ext2</firstterm> filesystem. May be
|
|
used to change filesystem parameters, such as maximum
|
|
mount count. This must be invoked as
|
|
<firstterm>root</firstterm>.</para>
|
|
|
|
<warning><para>This is an extremely dangerous command. Use it at
|
|
your own risk, as you may inadvertently destroy your filesystem.
|
|
</para></warning>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dumpe2fsref"/><command>dumpe2fs</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>dumpe2fs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>dumpe2fs</secondary>
|
|
</indexterm>
|
|
<para>Dump (list to <filename>stdout</filename>) very verbose
|
|
filesystem info. This must be invoked as
|
|
<firstterm>root</firstterm>.</para>
|
|
|
|
<screen><prompt>root# </prompt><command>dumpe2fs /dev/hda7 | grep 'ount count'</command>
|
|
<computeroutput>dumpe2fs 1.19, 13-Jul-2000 for EXT2 FS 0.5b, 95/08/09
|
|
Mount count: 6
|
|
Maximum mount count: 20</computeroutput></screen>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="hdparmref"/><command>hdparm</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>hdparm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>hard disk parameters</secondary>
|
|
</indexterm>
|
|
<para>List or change hard disk parameters. This command must be
|
|
invoked as <firstterm>root</firstterm>, and it may be
|
|
dangerous if misused.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="fdiskref"/><command>fdisk</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>fdisk</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>fdisk</secondary>
|
|
</indexterm>
|
|
<para>Create or change a partition table on a storage device,
|
|
usually a hard drive. This command must be invoked as
|
|
<firstterm>root</firstterm>.</para>
|
|
<warning><para>Use this command with extreme caution. If something
|
|
goes wrong, you may destroy an existing
|
|
filesystem.</para></warning>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="fsckref"/><command>fsck</command></term>
|
|
<term><anchor id="e2fsckref"/><command>e2fsck</command></term>
|
|
<term><anchor id="debugfsref"/><command>debugfs</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para>Filesystem check, repair, and debug command set.</para>
|
|
|
|
<para><command>fsck</command>: a front end for checking a UNIX
|
|
filesystem (may invoke other utilities). The actual
|
|
filesystem type generally defaults to
|
|
<firstterm>ext2</firstterm>.</para>
|
|
|
|
<para><command>e2fsck</command>: ext2 filesystem checker.</para>
|
|
|
|
<para><command>debugfs</command>: ext2 filesystem debugger.
|
|
One of the uses of this versatile, but dangerous command
|
|
is to (attempt to) recover deleted files. For advanced users
|
|
only!</para>
|
|
|
|
<caution><para>All of these should be invoked as
|
|
<firstterm>root</firstterm>, and they can damage or destroy
|
|
a filesystem if misused.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="badblocksref"/><command>badblocks</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>badblocks</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>badblocks</secondary>
|
|
</indexterm>
|
|
<para>Checks for bad blocks (physical media flaws) on a
|
|
storage device. This command finds use when formatting
|
|
a newly installed hard drive or testing the integrity
|
|
of backup media.
|
|
<footnote><para>The <option>-c</option> option to <link
|
|
linkend="mke2fsref">mke2fs</link> also invokes a check for bad
|
|
blocks.</para></footnote>
|
|
As an example, <command>badblocks /dev/fd0</command>
|
|
tests a floppy disk.</para>
|
|
|
|
<para>The <command>badblocks</command> command
|
|
may be invoked destructively (overwrite all data) or
|
|
in non-destructive read-only mode. If <firstterm>root
|
|
user</firstterm> owns the device to be tested, as is
|
|
generally the case, then <firstterm>root</firstterm>
|
|
must invoke this command.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lsusbref"/><command>lsusb</command></term>
|
|
<term><command>usbmodules</command></term>
|
|
<listitem>
|
|
<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>
|
|
|
|
<para>The <command>lsusb</command> command lists all USB
|
|
(Universal Serial Bus) buses and the devices hooked up to
|
|
them.</para>
|
|
|
|
<para>The <command>usbmodules</command> command outputs
|
|
information about the driver modules for connected USB
|
|
devices.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lsusb</userinput>
|
|
<computeroutput>Bus 001 Device 001: ID 0000:0000
|
|
Device Descriptor:
|
|
bLength 18
|
|
bDescriptorType 1
|
|
bcdUSB 1.00
|
|
bDeviceClass 9 Hub
|
|
bDeviceSubClass 0
|
|
bDeviceProtocol 0
|
|
bMaxPacketSize0 8
|
|
idVendor 0x0000
|
|
idProduct 0x0000
|
|
|
|
. . .</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lspciref"/><command>lspci</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lspci</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>pci</secondary>
|
|
</indexterm>
|
|
<para>Lists <firstterm>pci</firstterm> busses present.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lspci</userinput>
|
|
<computeroutput>00:00.0 Host bridge: Intel Corporation 82845 845
|
|
(Brookdale) Chipset Host Bridge (rev 04)
|
|
00:01.0 PCI bridge: Intel Corporation 82845 845
|
|
(Brookdale) Chipset AGP Bridge (rev 04)
|
|
00:1d.0 USB Controller: Intel Corporation 82801CA/CAM USB (Hub #1) (rev 02)
|
|
00:1d.1 USB Controller: Intel Corporation 82801CA/CAM USB (Hub #2) (rev 02)
|
|
00:1d.2 USB Controller: Intel Corporation 82801CA/CAM USB (Hub #3) (rev 02)
|
|
00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 42)
|
|
|
|
. . .</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mkbootdiskref"/><command>mkbootdisk</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mkbootdisk</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>bootdisk</secondary>
|
|
</indexterm>
|
|
<para>Creates a boot floppy which can be used to bring up the
|
|
system if, for example, the MBR (master boot record) becomes
|
|
corrupted. Of special interest is the <option>--iso</option>
|
|
option, which uses <command>mkisofs</command> to create a
|
|
bootable <firstterm>ISO9660</firstterm> filesystem image
|
|
suitable for burning a bootable CDR.</para>
|
|
<para>The <command>mkbootdisk</command> command is actually
|
|
a Bash script, written by Erik Troan, in the <filename
|
|
class="directory">/sbin</filename> directory.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mkisofsref"/><command>mkisofs</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mkisofs</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ISO9660</secondary>
|
|
</indexterm>
|
|
<para>Creates an <firstterm>ISO9660</firstterm> filesystem
|
|
suitable for a CDR image.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="chrootref"/><command>chroot</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>chroot</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>chroot</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>directory</primary>
|
|
<secondary>root</secondary>
|
|
<tertiary>change</tertiary>
|
|
</indexterm>
|
|
<para>CHange ROOT directory. Normally commands are fetched
|
|
from <link linkend="pathref">$PATH</link>, relative to
|
|
<filename class="directory">/</filename>, the default
|
|
<firstterm>root
|
|
directory</firstterm>. This changes the
|
|
<firstterm>root</firstterm> directory to a different one
|
|
(and also changes the working directory to there). This is
|
|
useful for security purposes, for instance when the system
|
|
administrator wishes to restrict certain users, such as
|
|
those <link linkend="telnetref">telnetting</link> in,
|
|
to a secured portion of the filesystem (this is sometimes
|
|
referred to as confining a guest user to a <quote>chroot
|
|
jail</quote>). Note that after a <command>chroot</command>,
|
|
the execution path for system binaries is no longer
|
|
valid.</para>
|
|
|
|
<para>A <userinput>chroot /opt</userinput> would cause
|
|
references to <filename
|
|
class="directory">/usr/bin</filename>
|
|
to be translated to <filename
|
|
class="directory">/opt/usr/bin</filename>. Likewise,
|
|
<userinput>chroot /aaa/bbb /bin/ls</userinput> would
|
|
redirect future instances of <command>ls</command>
|
|
to <filename>/aaa/bbb</filename> as the base directory,
|
|
rather than <filename class="directory">/</filename> as is
|
|
normally the case. An <command>alias XX 'chroot /aaa/bbb
|
|
ls'</command> in a user's <link
|
|
linkend="sample-bashrc"><filename>~/.bashrc</filename></link>
|
|
effectively restricts which portion of the filesystem
|
|
she may run command <quote>XX</quote> on.</para>
|
|
|
|
|
|
<para>The <command>chroot</command> command is also handy
|
|
when running from an emergency boot floppy
|
|
(<command>chroot</command> to <filename>/dev/fd0</filename>),
|
|
or as an option to <command>lilo</command> when recovering
|
|
from a system crash. Other uses include installation from a
|
|
different filesystem (an <link linkend="rpmref">rpm</link>
|
|
option) or running a readonly filesystem from a CD ROM.
|
|
Invoke only as <firstterm>root</firstterm>, and use with
|
|
care.</para>
|
|
|
|
<caution><para>It might be necessary to copy certain system
|
|
files to a <firstterm>chrooted</firstterm> directory,
|
|
since the normal <varname>$PATH</varname> can no longer
|
|
be relied upon.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lockfileref"/><command>lockfile</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lockfile</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>lockfile</secondary>
|
|
</indexterm>
|
|
<para>This utility is part of the <command>procmail</command>
|
|
package (<ulink url="http://www.procmail.org">www.procmail.org</ulink>).
|
|
It creates a <firstterm>lock file</firstterm>, a
|
|
<firstterm>semaphore</firstterm> that controls access to
|
|
a file, device, or resource.</para>
|
|
|
|
<sidebar><para><anchor id="semaphoreref"/>
|
|
<userinput>Definition:</userinput>
|
|
A <firstterm>semaphore</firstterm> is a flag or
|
|
signal. (The usage originated in railroading, where a
|
|
colored flag, lantern, or striped movable arm
|
|
<firstterm>semaphore</firstterm> indicated whether a
|
|
particular track was in use and therefore unavailable
|
|
for another train.) A UNIX process can check the
|
|
appropriate semaphore to determine whether a particular
|
|
resource is available/accessible.</para></sidebar>
|
|
|
|
<para>The lock file serves as a flag that this particular
|
|
file, device, or resource is in use by a process (and
|
|
is therefore <quote>busy</quote>). The presence of a
|
|
lock file permits only restricted access (or no access)
|
|
to other processes.</para>
|
|
|
|
<para><programlisting>lockfile /home/bozo/lockfiles/$0.lock
|
|
# Creates a write-protected lockfile prefixed with the name of the script.
|
|
|
|
lockfile /home/bozo/lockfiles/${0##*/}.lock
|
|
# A safer version of the above, as pointed out by E. Choroba.</programlisting></para>
|
|
|
|
<para>Lock files are used in such applications as protecting
|
|
system mail folders from simultaneously being changed
|
|
by multiple users, indicating that a modem port
|
|
is being accessed, and showing that an instance of
|
|
<application>Firefox</application> is using its cache.
|
|
Scripts may check for the existence of a lock file created
|
|
by a certain process to check if that process is running.
|
|
Note that if a script attempts to create a lock file that
|
|
already exists, the script will likely hang.</para>
|
|
|
|
<para>Normally, applications create and check for lock files
|
|
in the <filename class="directory">/var/lock</filename>
|
|
directory.
|
|
<footnote><para>Since only <firstterm>root</firstterm>
|
|
has write permission in the <filename
|
|
class="directory">/var/lock</filename> directory,
|
|
a user script cannot set a lock file there.</para></footnote>
|
|
A script can test for the presence of a lock file by
|
|
something like the following.
|
|
<programlisting>appname=xyzip
|
|
# Application "xyzip" created lock file "/var/lock/xyzip.lock".
|
|
|
|
if [ -e "/var/lock/$appname.lock" ]
|
|
then #+ Prevent other programs & scripts
|
|
# from accessing files/resources used by xyzip.
|
|
...</programlisting></para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="flockref"/><command>flock</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>flock</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>lock file</secondary>
|
|
</indexterm>
|
|
|
|
<para>Much less useful than the <command>lockfile</command>
|
|
command is <command>flock</command>. It sets an
|
|
<quote>advisory</quote> lock on a file and then executes
|
|
a command while the lock is on. This is to prevent
|
|
any other process from setting a lock on that file until
|
|
completion of the specified command.</para>
|
|
|
|
<para><programlisting>flock $0 cat $0 > lockfile__$0
|
|
# Set a lock on the script the above line appears in,
|
|
#+ while listing the script to stdout.</programlisting></para>
|
|
|
|
<note><para>Unlike <command>lockfile</command>,
|
|
<command>flock</command> does <emphasis>not</emphasis>
|
|
automatically create a lock file.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="mknodref"/><command>mknod</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>mknod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>mknod</secondary>
|
|
</indexterm>
|
|
<para>Creates block or character <link
|
|
linkend="devfileref">device files</link> (may be
|
|
necessary when installing new hardware on the system). The
|
|
<command>MAKEDEV</command> utility has virtually
|
|
all of the functionality of <command>mknod</command>,
|
|
and is easier to use.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="MAKEDEVref"/><command>MAKEDEV</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>MAKEDEV</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>make device file</secondary>
|
|
</indexterm>
|
|
|
|
<para>Utility for creating device files. It must be run as
|
|
<firstterm>root</firstterm>, and in the <filename
|
|
class="directory">/dev</filename> directory. It is a sort
|
|
of advanced version of <command>mknod</command>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="tmpwatchref"/><command>tmpwatch</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>tmpwatch</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>tmpwatch</secondary>
|
|
</indexterm>
|
|
<para>Automatically deletes files which have not been accessed
|
|
within a specified period of time. Usually invoked by
|
|
<link linkend="cronref">cron</link> to remove stale log
|
|
files.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="periphsys">
|
|
<title><anchor id="periphsys1"/>Backup</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="dumpref"/><command>dump</command></term>
|
|
<term><anchor id="restoreref"/><command>restore</command></term>
|
|
<listitem>
|
|
<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>
|
|
<para>The <command>dump</command> command is an elaborate
|
|
filesystem backup utility, generally used on larger
|
|
installations and networks.
|
|
<footnote><para>Operators of single-user Linux systems
|
|
generally prefer something simpler for backups, such
|
|
as <command>tar</command>.</para></footnote>
|
|
It reads raw disk partitions and writes a backup file
|
|
in a binary format. Files to be backed up may be saved
|
|
to a variety of storage media, including disks and tape
|
|
drives. The <command>restore</command> command restores
|
|
backups made with <command>dump</command>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="fdformatref"/><command>fdformat</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>fdformat</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>floppy</secondary>
|
|
</indexterm>
|
|
<para>Perform a low-level format on a floppy disk
|
|
(<filename>/dev/fd0*</filename>).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="sysresources">
|
|
<title><anchor id="sysresources1"/>System Resources</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="ulimitref"/><command>ulimit</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ulimit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ulimit</secondary>
|
|
</indexterm>
|
|
|
|
<para>Sets an <firstterm>upper limit</firstterm> on use
|
|
of system resources. Usually invoked with the
|
|
<option>-f</option> option, which sets a limit on file size
|
|
(<command>ulimit -f 1000</command> limits files to 1 meg
|
|
maximum).
|
|
<footnote><para>As of the <link linkend="bash4ref">version
|
|
4 update</link> of Bash, the <option>-f</option>
|
|
and <option>-c</option> options take a block size
|
|
of 512 when in <link linkend="posix2ref">POSIX</link>
|
|
mode. Additionally, there are two new options:
|
|
<option>-b</option> for <link
|
|
linkend="socketref">socket</link> buffer size, and
|
|
<option>-T</option> for the limit on the number of
|
|
<firstterm>threads</firstterm>.</para></footnote>
|
|
The <option>-t</option> option limits the coredump
|
|
size (<command>ulimit -c 0</command> eliminates coredumps).
|
|
Normally, the value of <command>ulimit</command>
|
|
would be set in <filename>/etc/profile</filename>
|
|
and/or <filename>~/.bash_profile</filename> (see <xref
|
|
linkend="files"/>).</para>
|
|
|
|
<important>
|
|
|
|
<para>Judicious use of <command>ulimit</command> can
|
|
protect a system against the dreaded <firstterm>fork
|
|
bomb</firstterm>.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# This script is for illustrative purposes only.
|
|
# Run it at your own peril -- it WILL freeze your system.
|
|
|
|
while true # Endless loop.
|
|
do
|
|
$0 & # This script invokes itself . . .
|
|
#+ forks an infinite number of times . . .
|
|
#+ until the system freezes up because all resources exhausted.
|
|
done # This is the notorious <quote>sorcerer's appentice</quote> scenario.
|
|
|
|
exit 0 # Will not exit here, because this script will never terminate.</programlisting>
|
|
</para>
|
|
|
|
<para>A <command>ulimit -Hu XX</command> (where
|
|
<emphasis>XX</emphasis> is the user process limit) in
|
|
<filename>/etc/profile</filename> would abort
|
|
this script when it exceeded the preset limit.
|
|
</para>
|
|
|
|
</important>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="quotaref"/><command>quota</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>quota</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>quota</secondary>
|
|
</indexterm>
|
|
<para>Display user or group disk quotas.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="setquotaref"/><command>setquota</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>setquota</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>quota</secondary>
|
|
</indexterm>
|
|
<para>Set user or group disk quotas from the command-line.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="umaskref"/><command>umask</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>umask</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>umask</secondary>
|
|
</indexterm>
|
|
<para>User file creation permissions
|
|
<firstterm>mask</firstterm>. Limit the default file
|
|
attributes for a particular user. All files created
|
|
by that user take on the attributes specified by
|
|
<command>umask</command>. The (octal) value passed to
|
|
<command>umask</command> defines the file permissions
|
|
<firstterm>disabled</firstterm>. For example, <command>umask
|
|
022</command> ensures that new files will have at most
|
|
755 permissions (777 NAND 022).
|
|
|
|
<footnote><para>NAND is the logical
|
|
<firstterm>not-and</firstterm> operator. Its effect
|
|
is somewhat similar to subtraction.</para></footnote>
|
|
|
|
Of course, the user may later change the
|
|
attributes of particular files with <link
|
|
linkend="chmodref">chmod</link>. The usual practice
|
|
is to set the value of <command>umask</command>
|
|
in <filename>/etc/profile</filename> and/or
|
|
<filename>~/.bash_profile</filename> (see <xref
|
|
linkend="files"/>).</para>
|
|
|
|
<example id="rot13a">
|
|
<title>Using <firstterm>umask</firstterm> to hide an output file
|
|
from prying eyes</title>
|
|
<programlisting>&rot13a;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rdevref"/><command>rdev</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rdev</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>rdev</secondary>
|
|
</indexterm>
|
|
<para>Get info about or make changes to root device, swap space, or video
|
|
mode. The functionality of <command>rdev</command> has generally been taken over by
|
|
<command>lilo</command>, but <command>rdev</command> remains
|
|
useful for setting up a ram disk. This is a dangerous command, if misused.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="modulessys">
|
|
<title><anchor id="modulessys1"/>Modules</title>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lsmodref"/><command>lsmod</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>lsmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<para>List installed kernel modules.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>lsmod</userinput>
|
|
<computeroutput>Module Size Used by
|
|
autofs 9456 2 (autoclean)
|
|
opl3 11376 0
|
|
serial_cs 5456 0 (unused)
|
|
sb 34752 0
|
|
uart401 6384 0 [sb]
|
|
sound 58368 0 [opl3 sb uart401]
|
|
soundlow 464 0 [sound]
|
|
soundcore 2800 6 [sb sound]
|
|
ds 6448 2 [serial_cs]
|
|
i82365 22928 2
|
|
pcmcia_core 45984 0 [serial_cs ds i82365]</computeroutput>
|
|
</screen>
|
|
</para>
|
|
<note><para>Doing a <command>cat /proc/modules</command> gives the
|
|
same information.</para></note>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="insmodref"/><command>insmod</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>insmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<para>Force installation of a kernel module (use
|
|
<command>modprobe</command> instead, when possible). Must
|
|
be invoked as <firstterm>root</firstterm>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rmmodref"/><command>rmmod</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rmmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<para>Force unloading of a kernel module. Must be invoked
|
|
as <firstterm>root</firstterm>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="modproberef"/><command>modprobe</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>modprobe</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<para>Module loader that is normally invoked automatically
|
|
in a startup script. Must be invoked as
|
|
<firstterm>root</firstterm>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="depmodref"/><command>depmod</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>depmod</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
<para>Creates module dependency file. Usually invoked from a
|
|
startup script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="modinforef"/><command>modinfo</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>modinfo</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>loadable modules</secondary>
|
|
</indexterm>
|
|
|
|
<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><anchor id="envvref"/><command>env</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>env</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>env</secondary>
|
|
</indexterm>
|
|
<para>
|
|
Runs a program or script with certain <link
|
|
linkend="envref">environmental variables</link>
|
|
set or changed (without changing the overall system
|
|
environment). The <option>[varname=xxx]</option>
|
|
permits changing the environmental variable
|
|
<varname>varname</varname> for the duration of the
|
|
script. With no options specified, this command lists all
|
|
the environmental variable settings.
|
|
|
|
<footnote><para>In Bash and other Bourne shell derivatives, it is
|
|
possible to set variables in a single command's environment.
|
|
<programlisting>var1=value1 var2=value2 commandXXX
|
|
# $var1 and $var2 set in the environment of 'commandXXX' only.</programlisting>
|
|
</para></footnote>
|
|
</para>
|
|
|
|
<note>
|
|
<para><anchor id="envv2ref"/>The first line of a script (the
|
|
<quote>sha-bang</quote> line) may use <command>env</command>
|
|
when the path to the shell or interpreter is unknown.</para>
|
|
|
|
<para><programlisting>#! /usr/bin/env perl
|
|
|
|
print "This Perl script will run,\n";
|
|
print "even when I don't know where to find Perl.\n";
|
|
|
|
# Good for portable cross-platform scripts,
|
|
# where the Perl binaries may not be in the expected place.
|
|
# Thanks, S.C.</programlisting></para>
|
|
|
|
<para>Or even ... </para>
|
|
<para><programlisting>#!/bin/env bash
|
|
# Queries the $PATH enviromental variable for the location of bash.
|
|
# Therefore ...
|
|
# This script will run where Bash is not in its usual place, in /bin.
|
|
...</programlisting></para>
|
|
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="lddref"/><command>ldd</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>ldd</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>ldd</secondary>
|
|
</indexterm>
|
|
<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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>watch</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>periodic</secondary>
|
|
</indexterm>
|
|
<para>Run a command repeatedly, at specified time intervals.</para>
|
|
<para>The default is two-second intervals, but this may be changed
|
|
with the <option>-n</option> option.</para>
|
|
<para><programlisting>watch -n 5 tail /var/log/messages
|
|
# Shows tail end of system log, /var/log/messages, every five seconds.</programlisting></para>
|
|
|
|
<note><para>Unfortunately, <link linkend="piperef">piping</link>
|
|
the output of <command>watch command</command> to <link
|
|
linkend="grepref">grep</link> does not work.</para></note>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="stripref"/><command>strip</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>strip</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>symbol</secondary>
|
|
</indexterm>
|
|
<para>Remove the debugging symbolic references from an executable
|
|
binary. This decreases its size, but makes debugging it
|
|
impossible.</para>
|
|
<para>This command often occurs in a <link
|
|
linkend="makefileref">Makefile</link>,
|
|
but rarely in a shell script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="nmref"/><command>nm</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>nm</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>symbol</secondary>
|
|
</indexterm>
|
|
<para>List symbols in an unstripped compiled binary.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="xrandrref"/><command>xrandr</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>xrandr</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>xrandr</secondary>
|
|
</indexterm>
|
|
<para>Command-line tool for manipulating the root window
|
|
of the screen.</para>
|
|
|
|
<example id="backlight">
|
|
<title><firstterm>Backlight</firstterm>: changes
|
|
the brightness of the (laptop) screen backlight</title>
|
|
<programlisting>&backlight;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="rdistref"/><command>rdist</command></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>rdist</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>rdist</secondary>
|
|
</indexterm>
|
|
<para>Remote distribution client: synchronizes, clones,
|
|
or backs up a file system on a remote server.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
|
|
<sect1 id="sysscripts">
|
|
<title>Analyzing a System Script</title>
|
|
|
|
<para><anchor id="killall2ref"/></para>
|
|
|
|
<para>Using our knowledge of administrative commands, let us examine a system
|
|
script. One of the shortest and simplest to understand scripts is
|
|
<quote>killall,</quote>
|
|
<footnote><para>The <firstterm>killall</firstterm> system
|
|
script should not be confused with the <link
|
|
linkend="killallref">killall</link> command in <filename
|
|
class="directory">/usr/bin</filename>.</para></footnote>
|
|
used to suspend running processes at system shutdown.</para>
|
|
|
|
<example id="ex55">
|
|
<title><firstterm>killall</firstterm>, from <filename
|
|
class="directory">/etc/rc.d/init.d</filename></title>
|
|
<programlisting>&ex55;</programlisting>
|
|
</example>
|
|
|
|
<para>That wasn't so bad. Aside from a little fancy footwork with variable
|
|
matching, there is no new material there.</para>
|
|
|
|
<formalpara><title>Exercise 1</title>
|
|
<para>In <filename class="directory">/etc/rc.d/init.d</filename>,
|
|
analyze the <command>halt</command> script. It is a bit longer
|
|
than <command>killall</command>, but similar in concept. Make
|
|
a copy of this script somewhere in your home directory and
|
|
experiment with it (do <emphasis>not</emphasis> run it as
|
|
<firstterm>root</firstterm>). Do a simulated run
|
|
with the <option>-vn</option> flags (<userinput>sh
|
|
-vn scriptname</userinput>). Add extensive
|
|
comments. Change the commands to <link
|
|
linkend="echoref">echos</link>.</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>.
|
|
Try to understand at least portions of them. Follow
|
|
the above procedure to analyze them. For some
|
|
additional insight, you might also examine the
|
|
file <filename>sysvinitfiles</filename> in <filename
|
|
class="directory">/usr/share/doc/initscripts-?.??</filename>,
|
|
which is part of the <quote>initscripts</quote>
|
|
documentation.</para></formalpara>
|
|
|
|
</sect1> <!-- Analyzing a System Script -->
|
|
|
|
</chapter> <!-- System and Administrative Commands -->
|
|
|
|
</part> <!-- Part 4 (Beyond the Basics) -->
|
|
|
|
|
|
|
|
|
|
<part label="Part 5" id="part5">
|
|
<title>Advanced Topics</title>
|
|
|
|
<partintro>
|
|
<para>At this point, we are ready to delve into certain of the
|
|
difficult and unusual aspects of scripting. Along the way, we
|
|
will attempt to <quote>push the envelope</quote> in various
|
|
ways and examine <firstterm>boundary conditions</firstterm>
|
|
(what happens when we move into uncharted territory?).</para>
|
|
</partintro>
|
|
|
|
<chapter id="regexp">
|
|
<title>Regular Expressions</title>
|
|
|
|
<epigraph>
|
|
<para>. . . the intellectual activity associated with software
|
|
development is largely one of gaining insight.</para>
|
|
<para>--Stowe Boyd</para>
|
|
</epigraph>
|
|
|
|
<para><anchor id="regexref"/></para>
|
|
|
|
<para>To fully utilize the power of shell scripting, you need to
|
|
master Regular Expressions. Certain commands
|
|
and utilities commonly used in scripts, such
|
|
as <link linkend="grepref">grep</link>, <link
|
|
linkend="exprref">expr</link>, <link linkend="sedref">sed</link>
|
|
and <link linkend="awkref">awk</link>, interpret and use REs. As of
|
|
<link linkend="bash3ref">version 3</link>, Bash has acquired its
|
|
own <link linkend="regexmatchref">RE-match operator</link>:
|
|
<command>=~</command>.</para>
|
|
|
|
|
|
|
|
<sect1><title>A Brief Introduction to Regular Expressions</title>
|
|
|
|
<para>An expression is a string of characters. Those characters
|
|
having an interpretation above and beyond their literal
|
|
meaning are called <firstterm>metacharacters</firstterm>.
|
|
A quote symbol, for example, may denote speech by a person,
|
|
<firstterm>ditto</firstterm>, or a meta-meaning
|
|
|
|
<footnote><para><anchor id="metameaningref"/>A
|
|
<firstterm>meta-meaning</firstterm> is the meaning of a
|
|
term or expression on a higher level of abstraction. For
|
|
example, the <firstterm>literal</firstterm> meaning
|
|
of <firstterm>regular expression</firstterm> is an
|
|
ordinary expression that conforms to accepted usage. The
|
|
<firstterm>meta-meaning</firstterm> is drastically different,
|
|
as discussed at length in this chapter.</para></footnote>
|
|
|
|
for the symbols that follow. Regular Expressions are sets
|
|
of characters and/or metacharacters that match (or specify)
|
|
patterns.</para>
|
|
|
|
<para>A Regular Expression contains one or more of the
|
|
following:</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para><firstterm>A character set</firstterm>. These are the
|
|
characters retaining their literal meaning. The
|
|
simplest type of Regular Expression consists
|
|
<emphasis>only</emphasis> of a character set, with no
|
|
metacharacters.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="anchorref"/></para>
|
|
<para><firstterm>An anchor</firstterm>. These designate
|
|
(<firstterm>anchor</firstterm>) the position in the line of
|
|
text that the RE is to match. For example, <token>^</token>,
|
|
and <token>$</token> are anchors.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><firstterm>Modifiers</firstterm>. These expand or narrow
|
|
(<firstterm>modify</firstterm>) the range of text the RE is
|
|
to match. Modifiers include the asterisk, brackets, and
|
|
the backslash.</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<para>The main uses for Regular Expressions
|
|
(<firstterm>RE</firstterm>s) are text searches and string
|
|
manipulation. An RE <firstterm>matches</firstterm> a single
|
|
character or a set of characters -- a string or a part of
|
|
a string.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>*</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>*</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="asteriskreg"/>The asterisk --
|
|
<token>*</token> -- matches any number of
|
|
repeats of the character string or RE preceding it,
|
|
including <emphasis>zero</emphasis> instances.</para>
|
|
|
|
<para><quote>1133*</quote> matches <replaceable>11 +
|
|
one or more 3's</replaceable>:
|
|
<replaceable>113</replaceable>, <replaceable>1133</replaceable>,
|
|
<replaceable>1133333</replaceable>, and so forth.</para>
|
|
|
|
</listitem>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>.</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>.</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="regexdot"/>The <firstterm>dot</firstterm>
|
|
-- <token>.</token> -- matches
|
|
any one character, except a newline.
|
|
<footnote><para>Since <link linkend="sedref">sed</link>, <link
|
|
linkend="awkref">awk</link>, and <link
|
|
linkend="grepref">grep</link> process single lines, there
|
|
will usually not be a newline to match. In those cases where
|
|
there is a newline in a multiple line expression, the dot
|
|
will match the newline.
|
|
<programlisting>#!/bin/bash
|
|
|
|
sed -e 'N;s/.*/[&]/' << 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>
|
|
|
|
<para>See <xref linkend="cwsolver"/> for a demonstration
|
|
of <firstterm>dot single-character</firstterm>
|
|
matching.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>^</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>^</secondary>
|
|
</indexterm>
|
|
<para><anchor id="caretref"/>The caret -- <token>^</token>
|
|
-- matches the beginning of a line, but sometimes, depending
|
|
on context, negates the meaning of a set of characters in
|
|
an RE.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>$</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>$</secondary>
|
|
</indexterm>
|
|
<para><anchor id="dollarsignref"/></para>
|
|
<para>The dollar sign -- <token>$</token> -- at the end of an
|
|
RE matches the end of a line.</para>
|
|
<para><quote>XXX$</quote> matches <token>XXX</token> at the
|
|
end of a line.</para>
|
|
<para><quote>^$</quote> matches blank lines.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>[...]</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>[...]</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="bracketsref"/></para>
|
|
<para>Brackets -- <token>[...]</token> -- enclose a set of characters
|
|
to match in a single RE.</para>
|
|
|
|
<para><quote>[xyz]</quote> matches any one of the characters
|
|
<replaceable>x</replaceable>, <replaceable>y</replaceable>,
|
|
or <replaceable>z</replaceable>.</para>
|
|
|
|
<para><quote>[c-n]</quote> matches any one of the
|
|
characters in the range <replaceable>c</replaceable>
|
|
to <replaceable>n</replaceable>.</para>
|
|
|
|
<para><quote>[B-Pk-y]</quote> matches any one of the
|
|
characters in the ranges <replaceable>B</replaceable>
|
|
to <replaceable>P</replaceable>
|
|
and <replaceable>k</replaceable> to
|
|
<replaceable>y</replaceable>.</para>
|
|
|
|
<para><quote>[a-z0-9]</quote> matches any single lowercase
|
|
letter or any digit.</para>
|
|
|
|
<para><quote>[^b-d]</quote> matches any character
|
|
<emphasis>except</emphasis> those in
|
|
the range <replaceable>b</replaceable> to
|
|
<replaceable>d</replaceable>. This is an instance of
|
|
<token>^</token> negating or inverting the meaning
|
|
of the following RE (taking on a role similar to
|
|
<token>!</token> in a different context).</para>
|
|
|
|
<para>Combined sequences of bracketed characters match
|
|
common word patterns. <quote>[Yy][Ee][Ss]</quote> matches
|
|
<replaceable>yes</replaceable>, <replaceable>Yes</replaceable>,
|
|
<replaceable>YES</replaceable>, <replaceable>yEs</replaceable>,
|
|
and so forth.
|
|
<quote>[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]</quote>
|
|
matches any Social Security number.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>\</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="regexbs"/></para>
|
|
<para>The backslash -- <token>\</token> -- <link
|
|
linkend="escp">escapes</link> a special character, which
|
|
means that character gets interpreted literally (and is
|
|
therefore no longer <firstterm>special</firstterm>).</para>
|
|
|
|
<para>A <quote>\$</quote> reverts back to its
|
|
literal meaning of <quote>$</quote>, rather than its
|
|
RE meaning of end-of-line. Likewise a <quote>\\</quote>
|
|
has the literal meaning of <quote>\</quote>.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\< \></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>
|
|
|
|
<para><anchor id="escpcb"/></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>\{ \}</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>\{ \}</secondary>
|
|
</indexterm>
|
|
|
|
<para><link linkend="escp">Escaped</link> <quote>curly
|
|
brackets</quote> -- <token>\{ \}</token> -- indicate the number
|
|
of occurrences of a preceding RE to match.</para>
|
|
|
|
|
|
<para>It is necessary to escape the curly brackets since
|
|
they have only their literal character meaning
|
|
otherwise. This usage is technically not part of the basic
|
|
RE set.</para>
|
|
|
|
<para><quote>[0-9]\{5\}</quote> matches exactly five digits
|
|
(characters in the range of 0 to 9).</para>
|
|
|
|
<note>
|
|
<para>Curly brackets are not available as an RE in the
|
|
<quote>classic</quote> (non-POSIX compliant) version
|
|
of <link linkend="awkref">awk</link>.
|
|
<anchor id="gnugawk"/>However, the GNU extended version
|
|
of <firstterm>awk</firstterm>, <command>gawk</command>,
|
|
has the <option>--re-interval</option> option that permits
|
|
them (without being escaped).</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo 2222 | gawk --re-interval '/2{3}/'</userinput>
|
|
<computeroutput>2222</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><command>Perl</command> and some
|
|
<command>egrep</command> versions do not require escaping
|
|
the curly brackets.</para>
|
|
|
|
</note>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>()</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>()</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="parengrps"/></para>
|
|
<para>Parentheses -- <command>( )</command> -- enclose a group of
|
|
REs. They are useful with the following
|
|
<quote><token>|</token></quote> operator and in <link
|
|
linkend="exprparen">substring extraction</link> using <link
|
|
linkend="exprref">expr</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>|</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>|</secondary>
|
|
</indexterm>
|
|
|
|
<para>The -- <command>|</command> -- <quote>or</quote> RE operator
|
|
matches any of a set of alternate characters.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>egrep 're(a|e)d' misc.txt</userinput>
|
|
<computeroutput>People who read seem to be better informed than those who do not.
|
|
The clarinet produces sound by the vibration of its reed.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<note><para>Some versions of <command>sed</command>,
|
|
<command>ed</command>, and <command>ex</command> support
|
|
escaped versions of the extended Regular Expressions
|
|
described above, as do the GNU utilities.</para></note>
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem override="square">
|
|
|
|
<formalpara><title><anchor id="posixref"/>POSIX Character Classes</title>
|
|
<para><userinput>[:class:]</userinput></para></formalpara>
|
|
|
|
<indexterm>
|
|
<primary>[:</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>:]</secondary>
|
|
</indexterm>
|
|
|
|
<para>This is an alternate method of specifying a range of
|
|
characters to match.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>alnum</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>alphabetic numeric</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:alnum:]</userinput> matches alphabetic or
|
|
numeric characters. This is equivalent to
|
|
<userinput>A-Za-z0-9</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>alpha</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>alphabetic</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:alpha:]</userinput> matches alphabetic
|
|
characters. This is equivalent to
|
|
<userinput>A-Za-z</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>blank</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>space tab</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:blank:]</userinput> matches a space or a
|
|
tab.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>cntrl</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>control</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:cntrl:]</userinput> matches control
|
|
characters.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>digit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>decimal digit</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:digit:]</userinput> matches (decimal)
|
|
digits. This is equivalent to
|
|
<userinput>0-9</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>graph</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>graph</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:graph:]</userinput> (graphic printable
|
|
characters). Matches characters in the range of <link
|
|
linkend="asciidef">ASCII</link> 33 - 126. This is
|
|
the same as <userinput>[:print:]</userinput>, below,
|
|
but excluding the space character.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>lower</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>lowercase</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:lower:]</userinput> matches lowercase
|
|
alphabetic characters. This is equivalent to
|
|
<userinput>a-z</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>print</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>printable</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:print:]</userinput> (printable
|
|
characters). Matches characters in the range of ASCII 32 -
|
|
126. This is the same as <userinput>[:graph:]</userinput>,
|
|
above, but adding the space character.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>space</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>whitespace</secondary>
|
|
</indexterm>
|
|
|
|
<para><anchor id="wsposix"/><userinput>[:space:]</userinput>
|
|
matches whitespace characters (space and horizontal
|
|
tab).</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>upper</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>uppercase</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:upper:]</userinput> matches uppercase
|
|
alphabetic characters. This is equivalent to
|
|
<userinput>A-Z</userinput>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<indexterm>
|
|
<primary>xdigit</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>character range</primary>
|
|
<secondary>hexadecimal</secondary>
|
|
</indexterm>
|
|
|
|
<para><userinput>[:xdigit:]</userinput> matches hexadecimal
|
|
digits. This is equivalent to
|
|
<userinput>0-9A-Fa-f</userinput>.</para>
|
|
|
|
<important>
|
|
<para>POSIX character classes generally require quoting
|
|
or <link linkend="dblbrackets">double brackets</link>
|
|
([[ ]]).</para>
|
|
</important>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>grep [[:digit:]] test.file</userinput>
|
|
<computeroutput>abc=723</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><programlisting># ...
|
|
if [[ $arow =~ [[:digit:]] ]] # Numerical input?
|
|
then # POSIX char class
|
|
if [[ $acol =~ [[:alpha:]] ]] # Number followed by a letter? Illegal!
|
|
# ...
|
|
# From ktour.sh example script.</programlisting>
|
|
</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>POSIX character classes are used in
|
|
<xref linkend="ex49"/> and <xref linkend="lowercase"/>.</para>
|
|
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<para><link linkend="sedref">Sed</link>, <link
|
|
linkend="awkref">awk</link>, and <link
|
|
linkend="perlref">Perl</link>, used as filters in scripts, take
|
|
REs as arguments when "sifting" or transforming files or I/O
|
|
streams. See <xref linkend="behead"/> and <xref linkend="tree"/>
|
|
for illustrations of this.</para>
|
|
|
|
<para>The standard reference on this complex topic is Friedl's
|
|
<citetitle pubwork="book">Mastering Regular
|
|
Expressions</citetitle>. <citetitle pubwork="book">Sed &
|
|
Awk</citetitle>, by Dougherty and Robbins, also gives a very
|
|
lucid treatment of REs. See the <xref linkend="biblio"/> for
|
|
more information on these books.</para>
|
|
|
|
</sect1> <!-- A Brief Introduction to Regular Expressions -->
|
|
|
|
|
|
|
|
|
|
<sect1 id="globbingref">
|
|
<title>Globbing</title>
|
|
|
|
<para><anchor id="globbingref2"/></para>
|
|
<para>Bash itself cannot recognize Regular Expressions. Inside
|
|
scripts, it is commands and utilities -- such as
|
|
<link linkend="sedref">sed</link> and <link
|
|
linkend="awkref">awk</link> -- that interpret RE's.</para>
|
|
|
|
|
|
<para>Bash <emphasis>does</emphasis> carry out <firstterm>filename
|
|
expansion</firstterm>
|
|
|
|
<footnote><para><firstterm>Filename expansion</firstterm>
|
|
means expanding filename patterns or templates
|
|
containing special characters. For example,
|
|
<filename>example.???</filename> might expand
|
|
to <filename>example.001</filename> and/or
|
|
<filename>example.txt</filename>.</para></footnote>
|
|
|
|
-- a process known as <firstterm>globbing</firstterm> -- but
|
|
this does <emphasis>not</emphasis> use the standard RE set.
|
|
Instead, globbing recognizes and expands <firstterm>wild
|
|
cards</firstterm>. Globbing interprets the standard wild
|
|
card characters
|
|
<footnote><para><anchor id="wildcarddef"/>A <firstterm>wild
|
|
card</firstterm> character, analogous to a wild card in poker,
|
|
can represent (almost) any other character.</para></footnote>
|
|
-- <link linkend="asteriskref">*</link> and
|
|
<link linkend="wildcardqu">?</link>, character lists in
|
|
square brackets, and certain other special characters (such
|
|
as <token>^</token> for negating the sense of a match).
|
|
<anchor id="wdotfilewc"/>There are important limitations on wild
|
|
card characters in globbing, however. Strings containing
|
|
<replaceable>*</replaceable> will not match filenames that
|
|
start with a dot, as, for example, <link
|
|
linkend="sample-bashrc"><filename>.bashrc</filename></link>.
|
|
|
|
<footnote>
|
|
<para>
|
|
Filename expansion <emphasis>can</emphasis>
|
|
match dotfiles, but only if the pattern explicitly includes the dot
|
|
as a literal character.
|
|
<programlisting>~/[.]bashrc # Will not expand to ~/.bashrc
|
|
~/?bashrc # Neither will this.
|
|
# Wild cards and metacharacters will NOT
|
|
#+ expand to a dot in globbing.
|
|
|
|
~/.[b]ashrc # Will expand to ~/.bashrc
|
|
~/.ba?hrc # Likewise.
|
|
~/.bashr* # Likewise.
|
|
|
|
# Setting the "dotglob" option turns this off.
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
</footnote>
|
|
|
|
Likewise, the <replaceable>?</replaceable> has a different
|
|
meaning in globbing than as part of an RE.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>ls -l</userinput>
|
|
<computeroutput>total 2
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 a.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1
|
|
-rw-rw-r-- 1 bozo bozo 466 Aug 6 17:48 t2.sh
|
|
-rw-rw-r-- 1 bozo bozo 758 Jul 30 09:02 test1.txt</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l t?.sh</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 466 Aug 6 17:48 t2.sh</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l [ab]*</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 a.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l [a-c]*</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 a.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l [^ab]*</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1
|
|
-rw-rw-r-- 1 bozo bozo 466 Aug 6 17:48 t2.sh
|
|
-rw-rw-r-- 1 bozo bozo 758 Jul 30 09:02 test1.txt</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>ls -l {b*,c*,*est*}</userinput>
|
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 b.1
|
|
-rw-rw-r-- 1 bozo bozo 0 Aug 6 18:42 c.1
|
|
-rw-rw-r-- 1 bozo bozo 758 Jul 30 09:02 test1.txt</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
|
|
|
|
<para>Bash performs filename expansion on unquoted command-line
|
|
arguments. The <link linkend="echoref">echo</link> command
|
|
demonstrates this.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo *</userinput>
|
|
<computeroutput>a.1 b.1 c.1 t2.sh test1.txt</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo t*</userinput>
|
|
<computeroutput>t2.sh test1.txt</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo t?.sh</userinput>
|
|
<computeroutput>t2.sh</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>It is possible to modify the way Bash interprets
|
|
special characters in globbing. A <command>set -f</command>
|
|
command disables globbing, and the
|
|
<option>nocaseglob</option> and <option>nullglob</option>
|
|
options to <link linkend="shoptref">shopt</link> change
|
|
globbing behavior.</para></note>
|
|
|
|
<para>See also <xref linkend="listglob"/>.</para>
|
|
|
|
<caution><para><anchor id="handlingfnames"/>Filenames with
|
|
embedded <link linkend="whitespaceref">whitespace</link>
|
|
can cause <firstterm>globbing</firstterm> to choke.
|
|
<ulink
|
|
url="http://www.dwheeler.com/essays/filenames-in-shell.html">David
|
|
Wheeler</ulink> shows how to avoid many such pitfalls.</para>
|
|
|
|
<para><programlisting>IFS="$(printf '\n\t')" # Remove space.
|
|
|
|
# Correct glob use:
|
|
# Always use for-loop, prefix glob, check if exists file.
|
|
for file in ./* ; do # Use ./* ... NEVER bare *
|
|
if [ -e "$file" ] ; then # Check whether file exists.
|
|
COMMAND ... "$file" ...
|
|
fi
|
|
done
|
|
|
|
# This example taken from David Wheeler's site, with permission.</programlisting></para>
|
|
|
|
</caution>
|
|
|
|
</sect1> <!-- Globbing -->
|
|
|
|
|
|
</chapter> <!-- Regular Expressions -->
|
|
|
|
|
|
|
|
<chapter id="here-docs">
|
|
<title>Here Documents</title>
|
|
|
|
<epigraph>
|
|
<para>Here and now, boys.</para>
|
|
<para>--Aldous Huxley, <firstterm>Island</firstterm></para>
|
|
</epigraph>
|
|
|
|
<para><anchor id="heredocref"/></para>
|
|
|
|
<indexterm>
|
|
<primary><<</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary><<</secondary>
|
|
</indexterm>
|
|
|
|
<para>A <firstterm>here document</firstterm> is a special-purpose
|
|
code block. It uses a form of <link linkend="ioredirref">I/O
|
|
redirection</link> to feed a command list to
|
|
an interactive program or a command, such as <link
|
|
linkend="ftpref">ftp</link>, <link linkend="catref">cat</link>,
|
|
or the <firstterm>ex</firstterm> text editor.</para>
|
|
|
|
<para><programlisting>COMMAND <<InputComesFromHERE
|
|
...
|
|
...
|
|
...
|
|
InputComesFromHERE</programlisting></para>
|
|
|
|
|
|
<para><anchor id="limitstringref"/></para>
|
|
<para>A <firstterm>limit string</firstterm> delineates (frames)
|
|
the command list. The special symbol <token><<</token> precedes
|
|
the limit string. This has the effect of redirecting the output
|
|
of a command block into the <filename>stdin</filename> of the program
|
|
or command. It is similar to <userinput>interactive-program <
|
|
command-file</userinput>, where <filename>command-file</filename>
|
|
contains
|
|
|
|
<programlisting>command #1
|
|
command #2
|
|
...</programlisting></para>
|
|
|
|
<para>The <firstterm>here document</firstterm> equivalent looks
|
|
like this:
|
|
|
|
<programlisting>interactive-program <<LimitString
|
|
command #1
|
|
command #2
|
|
...
|
|
LimitString</programlisting></para>
|
|
|
|
<para>Choose a <firstterm>limit string</firstterm> sufficiently
|
|
unusual that it will not occur anywhere in the command list and
|
|
confuse matters.</para>
|
|
|
|
<para>Note that <firstterm>here documents</firstterm> may sometimes
|
|
be used to good effect with non-interactive utilities and commands,
|
|
such as, for example, <link linkend="wallref">wall</link>.</para>
|
|
|
|
|
|
<example id="ex70">
|
|
<title><firstterm>broadcast</firstterm>: Sends message to everyone
|
|
logged in</title>
|
|
<programlisting>&ex70;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="vihere"/></para>
|
|
<para>Even such unlikely candidates as the <firstterm>vi</firstterm>
|
|
text editor lend themselves to <firstterm>here
|
|
documents</firstterm>.</para>
|
|
|
|
<example id="ex69">
|
|
<title><firstterm>dummyfile</firstterm>: Creates a 2-line dummy
|
|
file</title>
|
|
<programlisting>&ex69;</programlisting>
|
|
</example>
|
|
|
|
<para>
|
|
The above script could just as effectively have been implemented with
|
|
<command>ex</command>, rather than
|
|
<command>vi</command>. <anchor id="exscriptref"/><firstterm>Here
|
|
documents</firstterm> containing a list of <command>ex</command>
|
|
commands are common enough to form their own category, known as
|
|
<firstterm>ex scripts</firstterm>.
|
|
|
|
<programlisting>#!/bin/bash
|
|
# Replace all instances of "Smith" with "Jones"
|
|
#+ in files with a ".txt" filename suffix.
|
|
|
|
ORIGINAL=Smith
|
|
REPLACEMENT=Jones
|
|
|
|
for word in $(fgrep -l $ORIGINAL *.txt)
|
|
do
|
|
# -------------------------------------
|
|
ex $word <<EOF
|
|
:%s/$ORIGINAL/$REPLACEMENT/g
|
|
:wq
|
|
EOF
|
|
# :%s is the "ex" substitution command.
|
|
# :wq is write-and-quit.
|
|
# -------------------------------------
|
|
done</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="catscriptref"/></para>
|
|
<para>Analogous to <quote>ex scripts</quote> are <firstterm>cat
|
|
scripts</firstterm>.</para>
|
|
|
|
<example id="ex71">
|
|
<title>Multi-line message using <firstterm>cat</firstterm></title>
|
|
<programlisting>&ex71;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="limitstrdash"/></para>
|
|
<para>The <option>-</option> option to mark a here document limit string
|
|
(<userinput><<-LimitString</userinput>) suppresses leading
|
|
tabs (but not spaces) in the output. This may be useful in making
|
|
a script more readable.</para>
|
|
|
|
<example id="ex71a">
|
|
<title>Multi-line message, with tabs suppressed</title>
|
|
<programlisting>&ex71a;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="herepassp"/></para>
|
|
<para>A <firstterm>here document</firstterm> supports parameter and
|
|
command substitution. It is therefore possible to pass different
|
|
parameters to the body of the here document, changing its output
|
|
accordingly.</para>
|
|
|
|
<example id="ex71b">
|
|
<title>Here document with replaceable parameters</title>
|
|
<programlisting>&ex71b;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="hereparamsub"/></para>
|
|
<para>This is a useful script containing a <firstterm>here
|
|
document</firstterm> with parameter substitution.</para>
|
|
|
|
<example id="ex72">
|
|
<title>Upload a file pair to <firstterm>Sunsite</firstterm> incoming
|
|
directory</title>
|
|
<programlisting>&ex72;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="hereesc"/></para>
|
|
<para>Quoting or escaping the <quote>limit string</quote> at the
|
|
head of a here document disables parameter substitution within its
|
|
body. The reason for this is that <firstterm>quoting/escaping the
|
|
limit string</firstterm> effectively <link
|
|
linkend="escp">escapes</link> the <token>$</token>,
|
|
<token>`</token>, and <token>\</token> <link
|
|
linkend="scharlist">special characters</link>, and causes them to
|
|
be interpreted literally. (Thank you, Allen Halsey, for pointing
|
|
this out.)</para>
|
|
|
|
<example id="ex71c">
|
|
<title>Parameter substitution turned off</title>
|
|
<programlisting>&ex71c;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="herelit"/></para>
|
|
<para>Disabling parameter substitution permits outputting literal text.
|
|
Generating scripts or even program code is one use for this.</para>
|
|
|
|
<example id="generatescript">
|
|
<title>A script that generates another script</title>
|
|
<programlisting>&generatescript;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para><anchor id="herecs"/></para>
|
|
<para>
|
|
It is possible to set a variable from the output of a here document.
|
|
This is actually a devious form of <link
|
|
linkend="commandsubref">command substitution</link>.
|
|
<programlisting>variable=$(cat <<SETVAR
|
|
This variable
|
|
runs over multiple lines.
|
|
SETVAR
|
|
)
|
|
|
|
echo "$variable"</programlisting>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="herefunc"/></para>
|
|
<para>A here document can supply input to a function in the same
|
|
script.</para>
|
|
|
|
<example id="hf">
|
|
<title>Here documents and functions</title>
|
|
<programlisting>&hf;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="anonheredoc0"/></para>
|
|
<para>It is possible to use <token>:</token> as a dummy command
|
|
accepting output from a here document. This, in effect, creates an
|
|
<quote>anonymous</quote> here document.</para>
|
|
|
|
<example id="anonheredoc">
|
|
<title><quote>Anonymous</quote> Here Document</title>
|
|
<programlisting>#!/bin/bash
|
|
|
|
: <<TESTVARIABLES
|
|
${HOSTNAME?}${USER?}${MAIL?} # Print error message if one of the variables not set.
|
|
TESTVARIABLES
|
|
|
|
exit $?</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="cblock1"/></para>
|
|
<tip><para>A variation of the above technique permits <quote>commenting
|
|
out</quote> blocks of code.</para></tip>
|
|
|
|
<example id="commentblock">
|
|
<title>Commenting out a block of code</title>
|
|
<programlisting>&commentblock;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="hselfdoc"/></para>
|
|
<tip><para>Yet another twist of this nifty trick makes
|
|
<quote>self-documenting</quote> scripts possible.</para></tip>
|
|
|
|
<example id="selfdocument">
|
|
<title>A self-documenting script</title>
|
|
<programlisting>&selfdocument;</programlisting>
|
|
</example>
|
|
|
|
<para>Using a <link linkend="catscriptref">cat script</link> is an
|
|
alternate way of accomplishing this.</para>
|
|
|
|
<para>
|
|
<programlisting>DOC_REQUEST=70
|
|
|
|
if [ "$1" = "-h" -o "$1" = "--help" ] # Request help.
|
|
then # Use a "cat script" . . .
|
|
cat <<DOCUMENTATIONXX
|
|
List the statistics of a specified directory in tabular format.
|
|
---------------------------------------------------------------
|
|
The command-line parameter gives the directory to be listed.
|
|
If no directory specified or directory specified cannot be read,
|
|
then list the current working directory.
|
|
|
|
DOCUMENTATIONXX
|
|
exit $DOC_REQUEST
|
|
fi</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>See also <xref linkend="isspammer2"/>, <xref linkend="petals"/>,
|
|
<xref linkend="qky"/>, and <xref linkend="nim"/> for more examples
|
|
of self-documenting scripts.</para>
|
|
|
|
<para><anchor id="heretemp"/></para>
|
|
<note>
|
|
<para>Here documents create temporary files, but these
|
|
files are deleted after opening and are not accessible to
|
|
any other process.</para>
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>bash -c 'lsof -a -p $$ -d0' << EOF</userinput>
|
|
<prompt>> </prompt><userinput>EOF</userinput>
|
|
<computeroutput>lsof 1213 bozo 0r REG 3,5 0 30386 /tmp/t1213-0-sh (deleted)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</note>
|
|
|
|
<caution><para>Some utilities will not work inside a
|
|
<firstterm>here document</firstterm>.</para></caution>
|
|
|
|
<para><anchor id="indentedls"/></para>
|
|
|
|
<warning>
|
|
|
|
<para>The closing <firstterm>limit string</firstterm>,
|
|
on the final line of a here document, must start in the
|
|
<emphasis>first</emphasis> character position. There can
|
|
be <emphasis>no leading whitespace</emphasis>. Trailing
|
|
whitespace after the limit string likewise causes unexpected
|
|
behavior. The whitespace prevents the limit string from being
|
|
recognized.
|
|
|
|
<footnote><para>Except, as Dennis Benzinger points out,
|
|
if <link linkend="limitstrdash">using
|
|
<command><<-</command> to suppress
|
|
tabs</link>.</para></footnote>
|
|
|
|
</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>
|
|
|
|
<caution>
|
|
<para><anchor id="exclls"/>Some people very cleverly use a
|
|
single <token>!</token> as a limit string. But, that's not
|
|
necessarily a good idea.</para>
|
|
<para><programlisting># This works.
|
|
cat <<!
|
|
Hello!
|
|
! Three more exclamations !!!
|
|
!
|
|
|
|
|
|
# But . . .
|
|
cat <<!
|
|
Hello!
|
|
Single exclamation point follows!
|
|
!
|
|
!
|
|
# Crashes with an error message.
|
|
|
|
|
|
# However, the following will work.
|
|
cat <<EOF
|
|
Hello!
|
|
Single exclamation point follows!
|
|
!
|
|
EOF
|
|
# It's safer to use a multi-character limit string.</programlisting></para>
|
|
</caution>
|
|
|
|
|
|
|
|
<para>For those tasks too complex for a <firstterm>here
|
|
document</firstterm>, consider using the
|
|
<replaceable>expect</replaceable> scripting language, which
|
|
was specifically designed for feeding input into interactive
|
|
programs.</para>
|
|
|
|
|
|
|
|
<sect1><title>Here Strings</title>
|
|
|
|
<para><anchor id="herestringsref"/></para>
|
|
|
|
<blockquote>
|
|
<literallayout>
|
|
A <firstterm>here string</firstterm> can be considered as a stripped-down form of a <firstterm>here document</firstterm>.
|
|
It consists of nothing more than <command>COMMAND <<< $WORD</command>,
|
|
where <varname>$WORD</varname> is expanded and fed to the <filename>stdin</filename> of <command>COMMAND</command>.
|
|
</literallayout>
|
|
</blockquote>
|
|
|
|
<para>As a simple example, consider this alternative to the <link
|
|
linkend="echogrepref">echo-grep</link> construction.</para>
|
|
|
|
<para>
|
|
<programlisting># Instead of:
|
|
if echo "$VAR" | grep -q txt # if [[ $VAR = *txt* ]]
|
|
# etc.
|
|
|
|
# Try:
|
|
if grep -q "txt" <<< "$VAR"
|
|
then # ^^^
|
|
echo "$VAR contains the substring sequence \"txt\""
|
|
fi
|
|
# Thank you, Sebastian Kaminski, for the suggestion.</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="hsread"/></para>
|
|
<para>Or, in combination with <link linkend="readref">read</link>:</para>
|
|
|
|
<para>
|
|
<programlisting>String="This is a string of words."
|
|
|
|
read -r -a Words <<< "$String"
|
|
# The -a option to "read"
|
|
#+ assigns the resulting values to successive members of an array.
|
|
|
|
echo "First word in String is: ${Words[0]}" # This
|
|
echo "Second word in String is: ${Words[1]}" # is
|
|
echo "Third word in String is: ${Words[2]}" # a
|
|
echo "Fourth word in String is: ${Words[3]}" # string
|
|
echo "Fifth word in String is: ${Words[4]}" # of
|
|
echo "Sixth word in String is: ${Words[5]}" # words.
|
|
echo "Seventh word in String is: ${Words[6]}" # (null)
|
|
# Past end of $String.
|
|
|
|
# Thank you, Francisco Lobo, for the suggestion.</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="hsloop"/>It is, of course, possible to feed
|
|
the output of a <firstterm>here string</firstterm>
|
|
into the <filename>stdin</filename> of a <link
|
|
linkend="loopref00">loop</link>.</para>
|
|
|
|
<para><programlisting># As Seamus points out . . .
|
|
|
|
ArrayVar=( element0 element1 element2 {A..D} )
|
|
|
|
while read element ; do
|
|
echo "$element" 1>&2
|
|
done <<< $(echo ${ArrayVar[*]})
|
|
|
|
# element0 element1 element2 A B C D</programlisting></para>
|
|
|
|
<para><anchor id="hspre"/></para>
|
|
<example id="prependex">
|
|
<title>Prepending a line to a file</title>
|
|
<programlisting>&prependex;</programlisting>
|
|
</example>
|
|
|
|
<example id="mailboxgrep">
|
|
<title>Parsing a mailbox</title>
|
|
<programlisting>&mailboxgrep;</programlisting>
|
|
</example>
|
|
|
|
<para>Exercise: Find other uses for <firstterm>here
|
|
strings</firstterm>, such as, for example, <link
|
|
linkend="goldenratio">feeding input to
|
|
<firstterm>dc</firstterm></link>.</para>
|
|
|
|
</sect1><!-- Here Strings -->
|
|
|
|
|
|
</chapter> <!-- Here Documents -->
|
|
|
|
|
|
|
|
<chapter id="io-redirection">
|
|
<title>I/O Redirection</title>
|
|
|
|
<para><anchor id="ioredirref"/></para>
|
|
|
|
<para>There are always three default <firstterm>files</firstterm>
|
|
<footnote><para>By convention in UNIX and Linux, data streams
|
|
and peripherals (<link linkend="devfileref">device files</link>)
|
|
are treated as files, in a fashion analogous to ordinary
|
|
files.</para></footnote>
|
|
open, <filename>stdin</filename> (the keyboard),
|
|
<filename>stdout</filename> (the screen), and
|
|
<filename>stderr</filename> (error messages output to the
|
|
screen). These, and any other open files, can be redirected.
|
|
Redirection simply means capturing output from a file, command,
|
|
program, script, or even code block within a script (see <xref
|
|
linkend="ex8"/> and <xref linkend="rpmcheck"/>) and sending it as
|
|
input to another file, command, program, or script.</para>
|
|
|
|
<para><anchor id="fdref"/>Each open file gets assigned a file descriptor.
|
|
|
|
<footnote><para><anchor id="fdref1"/>A <firstterm>file
|
|
descriptor</firstterm> is simply a number that
|
|
the operating system assigns to an open file
|
|
to keep track of it. Consider it a simplified
|
|
type of file pointer. It is analogous
|
|
to a <firstterm>file handle</firstterm> in
|
|
<command>C</command>.</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://groups.google.com/group/gnu.bash.bug/browse_thread/thread/13955daafded3b5c/18c17050087f9f37">
|
|
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."
|
|
# This operator is now functional, as of Bash 4, final release.
|
|
|
|
M>N
|
|
# "M" is a file descriptor, which defaults to 1, if not explicitly set.
|
|
# "N" is a filename.
|
|
# File descriptor "M" is redirect to file "N."
|
|
M>&N
|
|
# "M" is a file descriptor, which defaults to 1, if not set.
|
|
# "N" is another file descriptor.
|
|
|
|
#==============================================================================
|
|
|
|
# Redirecting stdout, one line at a time.
|
|
LOGFILE=script.log
|
|
|
|
echo "This statement is sent to the log file, \"$LOGFILE\"." 1>$LOGFILE
|
|
echo "This statement is appended to \"$LOGFILE\"." 1>>$LOGFILE
|
|
echo "This statement is also appended to \"$LOGFILE\"." 1>>$LOGFILE
|
|
echo "This statement is echoed to stdout, and will not appear in \"$LOGFILE\"."
|
|
# These redirection commands automatically "reset" after each line.
|
|
|
|
|
|
|
|
# Redirecting stderr, one line at a time.
|
|
ERRORFILE=script.errors
|
|
|
|
bad_command1 2>$ERRORFILE # Error message sent to $ERRORFILE.
|
|
bad_command2 2>>$ERRORFILE # Error message appended to $ERRORFILE.
|
|
bad_command3 # Error message echoed to stderr,
|
|
#+ and does not appear in $ERRORFILE.
|
|
# These redirection commands also automatically "reset" after each line.
|
|
#=======================================================================</programlisting>
|
|
|
|
|
|
<para><anchor id="ioredirectionref1"/></para>
|
|
|
|
<programlisting>
|
|
2>&1
|
|
# Redirects stderr to stdout.
|
|
# Error messages get sent to same place as standard output.
|
|
>>filename 2>&1
|
|
bad_command >>filename 2>&1
|
|
# Appends both stdout and stderr to the file "filename" ...
|
|
2>&1 | [command(s)]
|
|
bad_command 2>&1 | awk '{print $5}' # found
|
|
# Sends stderr through a pipe.
|
|
# |& was added to Bash 4 as an abbreviation for 2>&1 |.
|
|
|
|
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>.</programlisting>
|
|
|
|
<para><anchor id="ioredirectionref2"/></para>
|
|
|
|
<programlisting>
|
|
0< FILENAME
|
|
< FILENAME
|
|
# Accept input from a file.
|
|
# Companion command to <quote>></quote>, and often used in combination with it.
|
|
#
|
|
# grep search-word <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
|
|
# Or the equivalent:
|
|
< input-file command > output-file # Although this is non-standard.
|
|
|
|
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, but does not write to file.
|
|
# More precisely, the command output (in this case, null)
|
|
#+ writes to the file, but the error message goes only to stdout.
|
|
|
|
# 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><anchor id="fdref2"/></para>
|
|
<para>Child processes inherit open file descriptors. This is
|
|
why pipes work. To prevent an fd from being inherited, close it.
|
|
<programlisting># Redirecting only stderr to a pipe.
|
|
|
|
exec 3>&1 # Save current "value" of stdout.
|
|
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls').
|
|
# ^^^^ ^^^^
|
|
exec 3>&- # Now close it for the remainder of the script.
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<para>For a more detailed introduction to I/O redirection see
|
|
<xref linkend="ioredirintro"/>.</para>
|
|
|
|
|
|
|
|
|
|
<sect1><title>Using <firstterm>exec</firstterm></title>
|
|
|
|
|
|
<para><anchor id="usingexecref"/></para>
|
|
|
|
<para>An <command>exec <filename</command> command redirects
|
|
<filename>stdin</filename> to a file. From that point on, all
|
|
<filename>stdin</filename> comes from that file, rather than
|
|
its normal source (usually keyboard input). This provides a
|
|
method of reading a file line by line and possibly parsing
|
|
each line of input using <link linkend="sedref">sed</link>
|
|
and/or <link linkend="awkref">awk</link>.</para>
|
|
|
|
<example id="redir1">
|
|
<title>Redirecting <filename>stdin</filename> using
|
|
<firstterm>exec</firstterm></title>
|
|
<programlisting>&redir1;</programlisting>
|
|
</example>
|
|
|
|
<para>Similarly, an <command>exec >filename</command>
|
|
command redirects <filename>stdout</filename> to a designated
|
|
file. This sends all command output that would normally go
|
|
to <filename>stdout</filename> to that file.</para>
|
|
|
|
<important>
|
|
<para>
|
|
<command>exec N > filename</command> affects the entire
|
|
script or <firstterm>current shell</firstterm>. Redirection in
|
|
the <link linkend="processidref">PID</link> of the script or shell
|
|
from that point on has changed. However . . .
|
|
</para>
|
|
<para>
|
|
<command>N > filename</command> affects only the newly-forked process,
|
|
not the entire script or shell.
|
|
</para>
|
|
<para>Thank you, Ahmed Darwish, for pointing this out.</para>
|
|
</important>
|
|
|
|
|
|
|
|
<example id="reassignstdout">
|
|
<title>Redirecting <filename>stdout</filename> using
|
|
<firstterm>exec</firstterm></title>
|
|
<programlisting>&reassignstdout;</programlisting>
|
|
</example>
|
|
|
|
<example id="upperconv">
|
|
<title>Redirecting both <filename>stdin</filename> and
|
|
<filename>stdout</filename> in the same script with
|
|
<firstterm>exec</firstterm></title>
|
|
<programlisting>&upperconv;</programlisting>
|
|
</example>
|
|
|
|
<para>I/O redirection is a clever way of avoiding the dreaded <link
|
|
linkend="parvis">inaccessible variables within a subshell</link>
|
|
problem.</para>
|
|
|
|
<example id="avoidsubshell">
|
|
<title>Avoiding a subshell</title>
|
|
<programlisting>&avoidsubshell;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
</sect1><!-- Using exec For Redirection -->
|
|
|
|
|
|
|
|
<sect1 id="redircb"><title>Redirecting Code Blocks</title>
|
|
|
|
<para><anchor id="redirref"/>Blocks of code, such as <link
|
|
linkend="whileloopref">while</link>, <link
|
|
linkend="untilloopref">until</link>, and <link
|
|
linkend="forloopref1">for</link> loops, even <link
|
|
linkend="ifthen">if/then</link> test blocks can also incorporate
|
|
redirection of <filename>stdin</filename>. Even a function may
|
|
use this form of redirection (see <xref linkend="realname"/>).
|
|
The <token><</token> operator at the end of the code block
|
|
accomplishes this.</para>
|
|
|
|
<example id="redir2">
|
|
<title>Redirected <firstterm>while</firstterm> loop</title>
|
|
<programlisting>&redir2;</programlisting>
|
|
</example>
|
|
|
|
<example id="redir2a">
|
|
<title>Alternate form of redirected <firstterm>while</firstterm> loop</title>
|
|
<programlisting>&redir2a;</programlisting>
|
|
</example>
|
|
|
|
<example id="redir3">
|
|
<title>Redirected <firstterm>until</firstterm> loop</title>
|
|
<programlisting>&redir3;</programlisting>
|
|
</example>
|
|
|
|
<example id="redir4">
|
|
<title>Redirected <firstterm>for</firstterm> loop</title>
|
|
<programlisting>&redir4;</programlisting>
|
|
</example>
|
|
|
|
<para>We can modify the previous example to also redirect the output of
|
|
the loop.</para>
|
|
|
|
<example id="redir4a">
|
|
<title>Redirected <firstterm>for</firstterm> loop (both
|
|
<filename>stdin</filename> and <filename>stdout</filename>
|
|
redirected)</title>
|
|
<programlisting>&redir4a;</programlisting>
|
|
</example>
|
|
|
|
<example id="redir5">
|
|
<title>Redirected <firstterm>if/then</firstterm> test</title>
|
|
<programlisting>&redir5;</programlisting>
|
|
</example>
|
|
|
|
<example id="namesdata">
|
|
<title>Data file <firstterm>names.data</firstterm> for above
|
|
examples</title>
|
|
<programlisting>&namesdata;</programlisting>
|
|
</example>
|
|
|
|
<para>Redirecting the <filename>stdout</filename> of a code
|
|
block has the effect of saving its output to a file. See <xref
|
|
linkend="rpmcheck"/>.</para>
|
|
|
|
<para><link linkend="heredocref">Here documents</link>
|
|
are a special case of redirected code blocks. That being the case,
|
|
it should be possible to feed the output of a <firstterm>here
|
|
document</firstterm> into the <filename>stdin</filename> for a
|
|
<firstterm>while loop</firstterm>.</para>
|
|
|
|
<para>
|
|
<programlisting># This example by Albert Siersema
|
|
# Used with permission (thanks!).
|
|
|
|
function doesOutput()
|
|
# Could be an external command too, of course.
|
|
# Here we show you can use a function as well.
|
|
{
|
|
ls -al *.jpg | awk '{print $5,$9}'
|
|
}
|
|
|
|
|
|
nr=0 # We want the while loop to be able to manipulate these and
|
|
totalSize=0 #+ to be able to see the changes after the 'while' finished.
|
|
|
|
while read fileSize fileName ; do
|
|
echo "$fileName is $fileSize bytes"
|
|
let nr++
|
|
totalSize=$((totalSize+fileSize)) # Or: "let totalSize+=fileSize"
|
|
done<<EOF
|
|
$(doesOutput)
|
|
EOF
|
|
|
|
echo "$nr files totaling $totalSize bytes"</programlisting>
|
|
</para>
|
|
|
|
</sect1><!-- Redirecting Code Blocks -->
|
|
|
|
|
|
|
|
<sect1 id="redirapps"><title>Applications</title>
|
|
|
|
<para>Clever use of I/O redirection permits parsing and stitching
|
|
together snippets of command output (see <xref
|
|
linkend="readredir"/>). This permits
|
|
generating report and log files.</para>
|
|
|
|
<example id="logevents">
|
|
<title>Logging events</title>
|
|
<programlisting>&logevents;</programlisting>
|
|
</example>
|
|
|
|
|
|
</sect1><!-- Applications -->
|
|
|
|
|
|
</chapter> <!-- I/O Redirection -->
|
|
|
|
|
|
|
|
|
|
<chapter id="subshells">
|
|
<title>Subshells</title>
|
|
|
|
<para><anchor id="subshellsref"/></para>
|
|
|
|
<para>Running a shell script launches a new process, a
|
|
<firstterm>subshell</firstterm>.</para>
|
|
|
|
<sidebar>
|
|
<para><userinput>Definition:</userinput>
|
|
A <firstterm>subshell</firstterm> is a
|
|
<link linkend="childref2">child process</link> launched by a
|
|
shell (or <firstterm>shell script</firstterm>).</para>
|
|
</sidebar>
|
|
|
|
<para>A subshell is a separate instance of the command processor
|
|
-- the <firstterm>shell</firstterm> that gives you the prompt at
|
|
the console or in an <firstterm>xterm</firstterm> window. Just
|
|
as your commands are interpreted at the command-line prompt,
|
|
similarly does a script <link
|
|
linkend="batchprocref">batch-process</link> a list of
|
|
commands. Each shell script running is, in effect, a subprocess
|
|
(<firstterm>child process</firstterm>) of the <link
|
|
linkend="forkref">parent</link> shell.</para>
|
|
|
|
|
|
<para>A shell script can itself launch subprocesses. These
|
|
<firstterm>subshells</firstterm> let the script do
|
|
parallel processing, in effect executing multiple subtasks
|
|
simultaneously.</para>
|
|
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# subshell-test.sh
|
|
|
|
(
|
|
# Inside parentheses, and therefore a subshell . . .
|
|
while [ 1 ] # Endless loop.
|
|
do
|
|
echo "Subshell running . . ."
|
|
done
|
|
)
|
|
|
|
# Script will run forever,
|
|
#+ or at least until terminated by a Ctl-C.
|
|
|
|
exit $? # End of script (but will never get here).
|
|
|
|
|
|
|
|
Now, run the script:
|
|
sh subshell-test.sh
|
|
|
|
And, while the script is running, from a different xterm:
|
|
ps -ef | grep subshell-test.sh
|
|
|
|
UID PID PPID C STIME TTY TIME CMD
|
|
500 2698 2502 0 14:26 pts/4 00:00:00 sh subshell-test.sh
|
|
500 2699 2698 21 14:26 pts/4 00:00:24 sh subshell-test.sh
|
|
|
|
^^^^
|
|
|
|
Analysis:
|
|
PID 2698, the script, launched PID 2699, the subshell.
|
|
|
|
Note: The "UID ..." line would be filtered out by the "grep" command,
|
|
but is shown here for illustrative purposes.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>In general, an <link linkend="externalref">external
|
|
command</link> in a script <link linkend="forkref">forks
|
|
off</link> a subprocess,
|
|
<footnote><para>An external command invoked with an <link
|
|
linkend="execref">exec</link> does <emphasis>not</emphasis>
|
|
(usually) fork off a subprocess / subshell.</para></footnote>
|
|
whereas a Bash <link linkend="builtinref">builtin</link>
|
|
does not. For this reason, builtins execute more quickly
|
|
and use fewer system resources than their external command
|
|
equivalents.</para>
|
|
|
|
|
|
<variablelist id="subshellparens">
|
|
<title><anchor id="subshellparens1"/>Command List within
|
|
Parentheses</title>
|
|
|
|
<varlistentry>
|
|
<term>( command1; command2; command3; ... )</term>
|
|
<listitem>
|
|
<para>A command list embedded between
|
|
<replaceable>parentheses</replaceable> runs as a
|
|
subshell.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<para><anchor id="parvis"/>Variables in a subshell are
|
|
<emphasis>not</emphasis> visible outside the block of code
|
|
in the subshell. They are not accessible to the <link
|
|
linkend="forkref">parent process</link>, to the shell
|
|
that launched the subshell. These are, in effect,
|
|
variables <link linkend="localref">local</link> to the
|
|
<firstterm>child process</firstterm>.</para>
|
|
|
|
<example id="subshell">
|
|
<title>Variable scope in a subshell</title>
|
|
<programlisting>&subshell;</programlisting>
|
|
</example>
|
|
<para>See also <link linkend="bashpidref">$BASHPID</link> and
|
|
<xref linkend="subpit"/>.</para>
|
|
|
|
<sidebar>
|
|
<para><anchor id="scoperef"/></para>
|
|
<para><userinput>Definition:</userinput> The
|
|
<firstterm>scope</firstterm> of a variable is the
|
|
context in which it has meaning, in which it has a
|
|
<firstterm>value</firstterm> that can be referenced. For
|
|
example, the scope of a <link linkend="localref1">local
|
|
variable</link> lies only within the function,
|
|
block of code, or subshell within which it is defined,
|
|
while the scope of a <firstterm>global</firstterm> variable
|
|
is the entire script in which it appears.</para>
|
|
</sidebar>
|
|
|
|
|
|
|
|
|
|
<para><anchor id="subshnlevref"/></para>
|
|
<note>
|
|
<para>While the <link linkend="bashsubshellref">$BASH_SUBSHELL</link>
|
|
internal variable indicates the nesting level of a
|
|
subshell, the <link linkend="shlvlref">$SHLVL</link>
|
|
variable <emphasis>shows no change</emphasis> within
|
|
a subshell.</para>
|
|
|
|
<para>
|
|
<programlisting>echo " \$BASH_SUBSHELL outside subshell = $BASH_SUBSHELL" # 0
|
|
( echo " \$BASH_SUBSHELL inside subshell = $BASH_SUBSHELL" ) # 1
|
|
( ( echo " \$BASH_SUBSHELL inside nested subshell = $BASH_SUBSHELL" ) ) # 2
|
|
# ^ ^ *** nested *** ^ ^
|
|
|
|
echo
|
|
|
|
echo " \$SHLVL outside subshell = $SHLVL" # 3
|
|
( echo " \$SHLVL inside subshell = $SHLVL" ) # 3 (No change!)</programlisting>
|
|
</para>
|
|
</note>
|
|
|
|
|
|
|
|
<para>Directory changes made in a subshell do not carry over to the
|
|
parent shell.</para>
|
|
|
|
<example id="allprofs">
|
|
<title>List User Profiles</title>
|
|
<programlisting>&allprofs;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>A subshell may be used to set up a <quote>dedicated
|
|
environment</quote> for a command group.
|
|
<programlisting>COMMAND1
|
|
COMMAND2
|
|
COMMAND3
|
|
(
|
|
IFS=:
|
|
PATH=/bin
|
|
unset TERMINFO
|
|
set -C
|
|
shift 5
|
|
COMMAND4
|
|
COMMAND5
|
|
exit 3 # Only exits the subshell!
|
|
)
|
|
# The parent shell has not been affected, and the environment is preserved.
|
|
COMMAND6
|
|
COMMAND7</programlisting>
|
|
|
|
As seen here, the <link linkend="exitref">exit</link>
|
|
command only terminates the subshell in which it is running,
|
|
<emphasis>not</emphasis> the parent shell or script.</para>
|
|
|
|
<para>One application of such a <quote>dedicated environment</quote>
|
|
is testing whether a variable is defined.
|
|
<programlisting>if (set -u; : $variable) 2> /dev/null
|
|
then
|
|
echo "Variable is set."
|
|
fi # Variable has been set in current script,
|
|
#+ or is an internal Bash variable,
|
|
#+ or is present in environment (has been exported).
|
|
|
|
# Could also be written [[ ${variable-x} != x || ${variable-y} != y ]]
|
|
# or [[ ${variable-x} != x$variable ]]
|
|
# or [[ ${variable+x} = x ]]
|
|
# or [[ ${variable-x} != x ]]</programlisting></para>
|
|
|
|
<para>Another application is checking for a lock file:
|
|
<programlisting>if (set -C; : > 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 Stéphane Chazelas,
|
|
#+ with modifications by Paulo Marcel Coelho Aragao.</programlisting>
|
|
</para>
|
|
|
|
<para>+</para>
|
|
|
|
<para>Processes may execute in parallel within different
|
|
subshells. This permits breaking a complex task into subcomponents
|
|
processed concurrently.</para>
|
|
|
|
<example id="parallel-processes">
|
|
<title>Running parallel processes in subshells</title>
|
|
<programlisting>
|
|
(cat list1 list2 list3 | sort | uniq > list123) &
|
|
(cat list4 list5 list6 | sort | uniq > list456) &
|
|
# Merges and sorts both sets of lists simultaneously.
|
|
# Running in background ensures parallel execution.
|
|
#
|
|
# Same effect as
|
|
# cat list1 list2 list3 | sort | uniq > list123 &
|
|
# cat list4 list5 list6 | sort | uniq > list456 &
|
|
|
|
wait # Don't execute the next command until subshells finish.
|
|
|
|
diff list123 list456</programlisting>
|
|
</example>
|
|
|
|
<para>Redirecting I/O to a subshell uses the <quote>|</quote> pipe
|
|
operator, as in <userinput>ls -al | (command)</userinput>.</para>
|
|
|
|
|
|
<note>
|
|
<para>A code block between <link
|
|
linkend="codeblockref">curly brackets</link> does
|
|
<emphasis>not</emphasis> launch a subshell.</para>
|
|
<para>{ command1; command2; command3; . . . commandN; }</para>
|
|
<para><programlisting>var1=23
|
|
echo "$var1" # 23
|
|
|
|
{ var1=76; }
|
|
echo "$var1" # 76</programlisting></para>
|
|
</note>
|
|
|
|
|
|
|
|
</chapter> <!-- Subshells -->
|
|
|
|
|
|
|
|
<chapter id="restricted-sh">
|
|
<title>Restricted Shells</title>
|
|
|
|
<para><anchor id="restrictedshref"/></para>
|
|
|
|
<variablelist id="disabledcommref0">
|
|
<title><anchor id="disabledcommref"/>Disabled commands in restricted
|
|
shells</title>
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<formalpara><title> </title>
|
|
<para>Running a script or portion of a script in
|
|
<firstterm>restricted mode</firstterm> disables certain commands
|
|
that would otherwise be available. This is a security measure
|
|
intended to limit the privileges of the script user and to
|
|
minimize possible damage from running the script.</para>
|
|
</formalpara>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<para>The following commands and actions are disabled:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Using <replaceable>cd</replaceable> to change the working
|
|
directory.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Changing the values of the
|
|
<replaceable>$PATH</replaceable>,
|
|
<replaceable>$SHELL</replaceable>,
|
|
<replaceable>$BASH_ENV</replaceable>,
|
|
or <replaceable>$ENV</replaceable> <link
|
|
linkend="envref">environmental variables</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Reading or changing the <replaceable>$SHELLOPTS</replaceable>,
|
|
shell environmental options.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Output redirection.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Invoking commands containing one or more
|
|
<token>/</token>'s.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para>Invoking <link linkend="execref">exec</link> to substitute
|
|
a different process for the shell.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Various other commands that would enable monkeying
|
|
with or attempting to subvert the script for an unintended
|
|
purpose.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para>Getting out of restricted mode within the script.</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<example id="restricted">
|
|
<title>Running a script in restricted mode</title>
|
|
<programlisting>&restricted;</programlisting>
|
|
</example>
|
|
|
|
</chapter> <!-- Restricted Shells -->
|
|
|
|
|
|
|
|
|
|
<chapter id="process-sub">
|
|
<title>Process Substitution</title>
|
|
|
|
<para><anchor id="processsubref"/><link
|
|
linkend="piperef">Piping</link> the <filename>stdout</filename>
|
|
of a command into the <filename>stdin</filename> of another
|
|
is a powerful technique. But, what if you need to pipe the
|
|
<filename>stdout</filename> of <emphasis>multiple</emphasis>
|
|
commands? This is where <replaceable>process
|
|
substitution</replaceable> comes in.</para>
|
|
|
|
<para><firstterm>Process substitution</firstterm> feeds the
|
|
output of a <link linkend="processref">process</link> (or
|
|
processes) into the <filename>stdin</filename> of another
|
|
process.</para>
|
|
|
|
<variablelist id="commandsparens">
|
|
<title><anchor id="commandsparens1"/>Template</title>
|
|
|
|
<varlistentry>
|
|
<term>Command list enclosed within parentheses</term>
|
|
|
|
<listitem>
|
|
<para><command>>(command_list)</command></para>
|
|
<para><command><(command_list)</command></para>
|
|
<para>Process substitution uses
|
|
<filename>/dev/fd/<n></filename> files to send the
|
|
results of the process(es) within parentheses to another process.
|
|
<footnote><para>This has the same effect as a
|
|
<link linkend="namedpiperef">named pipe</link> (temp
|
|
file), and, in fact, named pipes were at one time used
|
|
in process substitution.</para></footnote>
|
|
</para>
|
|
|
|
<caution><para>There is <emphasis>no</emphasis> space between the
|
|
the <quote><</quote> or <quote>></quote> and the parentheses.
|
|
Space there would give an error message.</para></caution>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>echo >(true)</userinput>
|
|
<computeroutput>/dev/fd/63</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo <(true)</userinput>
|
|
<computeroutput>/dev/fd/63</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo >(true) <(true)</userinput>
|
|
<computeroutput>/dev/fd/63 /dev/fd/62</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>wc <(cat /usr/share/dict/linux.words)</userinput>
|
|
<computeroutput> 483523 483523 4992010 /dev/fd/63</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>grep script /usr/share/dict/linux.words | wc</userinput>
|
|
<computeroutput> 262 262 3601</computeroutput>
|
|
|
|
<prompt>bash$ </prompt><userinput>wc <(grep script /usr/share/dict/linux.words)</userinput>
|
|
<computeroutput> 262 262 3601 /dev/fd/63</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>
|
|
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></note>
|
|
|
|
|
|
<para>Process substitution can compare the output of two
|
|
different commands, or even the output of different options
|
|
to the same command.</para>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>comm <(ls -l) <(ls -al)</userinput>
|
|
<computeroutput>total 12
|
|
-rw-rw-r-- 1 bozo bozo 78 Mar 10 12:58 File0
|
|
-rw-rw-r-- 1 bozo bozo 42 Mar 10 12:58 File2
|
|
-rw-rw-r-- 1 bozo bozo 103 Mar 10 12:58 t2.sh
|
|
total 20
|
|
drwxrwxrwx 2 bozo bozo 4096 Mar 10 18:10 .
|
|
drwx------ 72 bozo bozo 4096 Mar 10 17:58 ..
|
|
-rw-rw-r-- 1 bozo bozo 78 Mar 10 12:58 File0
|
|
-rw-rw-r-- 1 bozo bozo 42 Mar 10 12:58 File2
|
|
-rw-rw-r-- 1 bozo bozo 103 Mar 10 12:58 t2.sh</computeroutput></screen>
|
|
|
|
<para><anchor id="pcc2dir"/></para>
|
|
<para>
|
|
Process substitution can compare the contents
|
|
of two directories -- to see which filenames are in one,
|
|
but not the other.</para>
|
|
<para>
|
|
<programlisting>diff <(ls $first_directory) <(ls $second_directory)</programlisting>
|
|
</para>
|
|
|
|
<para>Some other usages and uses of process substitution:</para>
|
|
<para><anchor id="psfdstdin"/></para>
|
|
<para><programlisting>read -a list < <( od -Ad -w24 -t u2 /dev/urandom )
|
|
# Read a list of random numbers from /dev/urandom,
|
|
#+ process with "od"
|
|
#+ and feed into stdin of "read" . . .
|
|
|
|
# From "insertion-sort.bash" example script.
|
|
# Courtesy of JuanJo Ciarlante.</programlisting></para>
|
|
|
|
|
|
<para><anchor id="netcatexample"/></para>
|
|
<para><programlisting>PORT=6881 # bittorrent
|
|
|
|
# Scan the port to make sure nothing nefarious is going on.
|
|
netcat -l $PORT | tee>(md5sum ->mydata-orig.md5) |
|
|
gzip | tee>(md5sum - | sed 's/-$/mydata.lz2/'>mydata-gz.md5)>mydata.gz
|
|
|
|
# Check the decompression:
|
|
gzip -d<mydata.gz | md5sum -c mydata-orig.md5)
|
|
# The MD5sum of the original checks stdin and detects compression issues.
|
|
|
|
# Bill Davidsen contributed this example
|
|
#+ (with light edits by the ABS Guide author).</programlisting></para>
|
|
|
|
|
|
|
|
<para><programlisting>cat <(ls -l)
|
|
# Same as ls -l | cat
|
|
|
|
sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) <(ls -l /usr/X11R6/bin)
|
|
# Lists all the files in the 3 main 'bin' directories, and sorts by filename.
|
|
# Note that three (count 'em) distinct commands are fed to 'sort'.
|
|
|
|
|
|
diff <(command1) <(command2) # Gives difference in command output.
|
|
|
|
tar cf >(bzip2 -c > file.tar.bz2) $directory_name
|
|
# Calls "tar cf /dev/fd/?? $directory_name", and "bzip2 -c > file.tar.bz2".
|
|
#
|
|
# Because of the /dev/fd/<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, Stéphane Chazelas</programlisting></para>
|
|
|
|
<para><anchor id="goodread0"/>Here is a method of circumventing the
|
|
problem of an <link linkend="badread0"><firstterm>echo</firstterm>
|
|
piped to a <firstterm>while-read loop</firstterm></link> running
|
|
in a subshell.</para>
|
|
|
|
<example id="wrps">
|
|
<title>Code block redirection without forking</title>
|
|
<programlisting>&wrps;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="psubpiping"/>This is a similar example.</para>
|
|
|
|
<example id="psubp">
|
|
<title>Redirecting the output of <firstterm>process
|
|
substitution</firstterm> into a loop.</title>
|
|
<programlisting>&psubp;</programlisting>
|
|
</example>
|
|
|
|
<para>A reader sent in the following interesting example of process
|
|
substitution.</para>
|
|
|
|
<para><programlisting># Script fragment taken from SuSE distribution:
|
|
|
|
# --------------------------------------------------------------#
|
|
while read des what mask iface; do
|
|
# Some commands ...
|
|
done < <(route -n)
|
|
# ^ ^ First < is redirection, second is process substitution.
|
|
|
|
# To test it, let's make it do something.
|
|
while read des what mask iface; do
|
|
echo $des $what $mask $iface
|
|
done < <(route -n)
|
|
|
|
# Output:
|
|
# Kernel IP routing table
|
|
# Destination Gateway Genmask Flags Metric Ref Use Iface
|
|
# 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
|
|
# --------------------------------------------------------------#
|
|
|
|
# As Stéphane Chazelas points out,
|
|
#+ an easier-to-understand equivalent is:
|
|
route -n |
|
|
while read des what mask iface; do # Variables set from output of pipe.
|
|
echo $des $what $mask $iface
|
|
done # This yields the same output as above.
|
|
# However, as Ulrich Gayer points out . . .
|
|
#+ this simplified equivalent uses a subshell for the while loop,
|
|
#+ and therefore the variables disappear when the pipe terminates.
|
|
|
|
# --------------------------------------------------------------#
|
|
|
|
# However, Filip Moritz comments that there is a subtle difference
|
|
#+ between the above two examples, as the following shows.
|
|
|
|
(
|
|
route -n | while read x; do ((y++)); done
|
|
echo $y # $y is still unset
|
|
|
|
while read x; do ((y++)); done < <(route -n)
|
|
echo $y # $y has the number of lines of output of route -n
|
|
)
|
|
|
|
More generally spoken
|
|
(
|
|
: | x=x
|
|
# seems to start a subshell like
|
|
: | ( x=x )
|
|
# while
|
|
x=x < <(:)
|
|
# does not
|
|
)
|
|
|
|
# This is useful, when parsing csv and the like.
|
|
# That is, in effect, what the original SuSE code fragment does.</programlisting></para>
|
|
|
|
</chapter> <!-- Process Substitution -->
|
|
|
|
|
|
|
|
|
|
<chapter id="functions">
|
|
<title>Functions</title>
|
|
|
|
<para><anchor id="functionref"/></para>
|
|
|
|
<para>Like <quote>real</quote> programming languages,
|
|
Bash has functions, though in a somewhat limited implementation.
|
|
A function is a subroutine, a <link linkend="codeblockref">code
|
|
block</link> that implements a set of operations, a <quote>black
|
|
box</quote> that performs a specified task. Wherever there is
|
|
repetitive code, when a task repeats with only slight variations in
|
|
procedure, then consider using a function.</para>
|
|
|
|
<para><cmdsynopsis>
|
|
<command>function</command>
|
|
<arg choice="plain"><replaceable>function_name</replaceable></arg>
|
|
<arg choice="plain">{</arg><sbr/>
|
|
<arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr/>
|
|
<arg choice="plain">}</arg><sbr/>
|
|
</cmdsynopsis>
|
|
or
|
|
<cmdsynopsis>
|
|
<arg choice="plain"><replaceable>function_name</replaceable></arg>
|
|
<arg choice="plain">()</arg>
|
|
<arg choice="plain">{</arg><sbr/>
|
|
<arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr/>
|
|
<arg choice="plain">}</arg><sbr/>
|
|
</cmdsynopsis>
|
|
</para>
|
|
|
|
<para>This second form will cheer the hearts of C programmers
|
|
(and is more <link
|
|
linkend="portabilityissues">portable</link>).</para>
|
|
|
|
<para>As in C, the function's opening bracket may optionally appear
|
|
on the second line.</para>
|
|
|
|
<para><cmdsynopsis>
|
|
<arg choice="plain"><replaceable>function_name</replaceable></arg>
|
|
<arg choice="plain">()</arg><sbr/>
|
|
<arg choice="plain">{</arg><sbr/>
|
|
<arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr/>
|
|
<arg choice="plain">}</arg><sbr/>
|
|
</cmdsynopsis>
|
|
</para>
|
|
|
|
<note>
|
|
<para>A function may be <quote>compacted</quote> into a single
|
|
line.</para>
|
|
|
|
<para><programlisting>fun () { echo "This is a function"; echo; }
|
|
# ^ ^</programlisting></para>
|
|
|
|
<para>In this case, however, a <firstterm>semicolon</firstterm>
|
|
must follow the final command in the function.</para>
|
|
|
|
<para><programlisting>fun () { echo "This is a function"; echo } # Error!
|
|
# ^
|
|
|
|
fun2 () { echo "Even a single-command function? Yes!"; }
|
|
# ^</programlisting></para>
|
|
</note>
|
|
|
|
<para>Functions are called, <firstterm>triggered</firstterm>, simply by
|
|
invoking their names. <emphasis>A function call is equivalent to
|
|
a command.</emphasis></para>
|
|
|
|
<example id="ex59">
|
|
<title>Simple functions</title>
|
|
<programlisting>&ex59;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="functdefmust"/></para>
|
|
<para>The function definition must precede the first call to
|
|
it. There is no method of <quote>declaring</quote> the function,
|
|
as, for example, in C.
|
|
<programlisting>f1
|
|
# Will give an error message, since function "f1" not yet defined.
|
|
|
|
declare -f f1 # This doesn't help either.
|
|
f1 # Still an error message.
|
|
|
|
# However...
|
|
|
|
|
|
f1 ()
|
|
{
|
|
echo "Calling function \"f2\" from within function \"f1\"."
|
|
f2
|
|
}
|
|
|
|
f2 ()
|
|
{
|
|
echo "Function \"f2\"."
|
|
}
|
|
|
|
f1 # Function "f2" is not actually called until this point,
|
|
#+ although it is referenced before its definition.
|
|
# This is permissible.
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<note><para><anchor id="emptyfunc"/>Functions may not be empty!
|
|
<programlisting>#!/bin/bash
|
|
# empty-function.sh
|
|
|
|
empty ()
|
|
{
|
|
}
|
|
|
|
exit 0 # Will not exit here!
|
|
|
|
# $ sh empty-function.sh
|
|
# empty-function.sh: line 6: syntax error near unexpected token `}'
|
|
# empty-function.sh: line 6: `}'
|
|
|
|
# $ echo $?
|
|
# 2
|
|
|
|
|
|
# Note that a function containing only comments is empty.
|
|
|
|
func ()
|
|
{
|
|
# Comment 1.
|
|
# Comment 2.
|
|
# This is still an empty function.
|
|
# Thank you, Mark Bova, for pointing this out.
|
|
}
|
|
# Results in same error message as above.
|
|
|
|
|
|
# However ...
|
|
|
|
not_quite_empty ()
|
|
{
|
|
illegal_command
|
|
} # A script containing this function will *not* bomb
|
|
#+ as long as the function is not called.
|
|
|
|
not_empty ()
|
|
{
|
|
:
|
|
} # Contains a : (null command), and this is okay.
|
|
|
|
|
|
# Thank you, Dominick Geyer and Thiemo Kellner.</programlisting>
|
|
</para></note>
|
|
|
|
|
|
|
|
|
|
<para>It is even possible to nest a function within another function,
|
|
although this is not very useful.
|
|
<programlisting>f1 ()
|
|
{
|
|
|
|
f2 () # nested
|
|
{
|
|
echo "Function \"f2\", inside \"f1\"."
|
|
}
|
|
|
|
}
|
|
|
|
f2 # Gives an error message.
|
|
# Even a preceding "declare -f f2" wouldn't help.
|
|
|
|
echo
|
|
|
|
f1 # Does nothing, since calling "f1" does not automatically call "f2".
|
|
f2 # Now, it's all right to call "f2",
|
|
#+ since its definition has been made visible by calling "f1".
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<para>Function declarations can appear in unlikely places, even where a
|
|
command would otherwise go.
|
|
<programlisting>ls -l | foo() { echo "foo"; } # Permissible, but useless.
|
|
|
|
|
|
|
|
if [ "$USER" = bozo ]
|
|
then
|
|
bozo_greet () # Function definition embedded in an if/then construct.
|
|
{
|
|
echo "Hello, Bozo."
|
|
}
|
|
fi
|
|
|
|
bozo_greet # Works only for Bozo, and other users get an error.
|
|
|
|
|
|
|
|
# Something like this might be useful in some contexts.
|
|
NO_EXIT=1 # Will enable function definition below.
|
|
|
|
[[ $NO_EXIT -eq 1 ]] && exit() { true; } # Function definition in an "and-list".
|
|
# If $NO_EXIT is 1, declares "exit ()".
|
|
# This disables the "exit" builtin by aliasing it to "true".
|
|
|
|
exit # Invokes "exit ()" function, not "exit" builtin.
|
|
|
|
|
|
|
|
# Or, similarly:
|
|
filename=file1
|
|
|
|
[ -f "$filename" ] &&
|
|
foo () { rm -f "$filename"; echo "File "$filename" deleted."; } ||
|
|
foo () { echo "File "$filename" not found."; touch bar; }
|
|
|
|
foo
|
|
|
|
# Thanks, S.C. and Christopher Head</programlisting>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="fstrangeref"/>Function names can take strange
|
|
forms.
|
|
<programlisting> _(){ for i in {1..10}; do echo -n "$FUNCNAME"; done; echo; }
|
|
# ^^^ No space between function name and parentheses.
|
|
# This doesn't always work. Why not?
|
|
|
|
# Now, let's invoke the function.
|
|
_ # __________
|
|
# ^^^^^^^^^^ 10 underscores (10 x function name)!
|
|
# A "naked" underscore is an acceptable function name.
|
|
|
|
|
|
# In fact, a colon is likewise an acceptable function name.
|
|
|
|
:(){ echo ":"; }; :
|
|
|
|
# Of what use is this?
|
|
# It's a devious way to obfuscate the code in a script.</programlisting>
|
|
See also <xref linkend="gronsfeld"/></para>
|
|
|
|
|
|
|
|
<note><para>What happens when different versions of the same function
|
|
appear in a script?
|
|
<programlisting># As Yan Chen points out,
|
|
# when a function is defined multiple times,
|
|
# the final version is what is invoked.
|
|
# This is not, however, particularly useful.
|
|
|
|
func ()
|
|
{
|
|
echo "First version of func ()."
|
|
}
|
|
|
|
func ()
|
|
{
|
|
echo "Second version of func ()."
|
|
}
|
|
|
|
func # Second version of func ().
|
|
|
|
exit $?
|
|
|
|
# It is even possible to use functions to override
|
|
#+ or preempt system commands.
|
|
# Of course, this is *not* advisable.</programlisting></para></note>
|
|
|
|
<!-- End of intro section -->
|
|
|
|
<sect1 id="complexfunct">
|
|
<title>Complex Functions and Function Complexities</title>
|
|
|
|
<para>Functions may process arguments passed to them and return
|
|
an <link linkend="exitstatusref">exit status</link> to the script
|
|
for further processing.</para>
|
|
|
|
<programlisting>function_name $arg1 $arg2</programlisting>
|
|
|
|
<para><anchor id="passedargs"/></para>
|
|
<para>The function refers to the passed arguments by position (as if they were
|
|
<link linkend="posparamref">positional parameters</link>),
|
|
that is, <varname>$1</varname>, <varname>$2</varname>, and
|
|
so forth.</para>
|
|
|
|
<example id="ex60">
|
|
<title>Function Taking Parameters</title>
|
|
<programlisting>&ex60;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="fshiftref"/></para>
|
|
<important><para>The <link linkend="shiftref">shift</link>
|
|
command works on arguments passed to functions (see <xref
|
|
linkend="multiplication"/>).</para></important>
|
|
|
|
<para>But, what about command-line arguments passed to the script?
|
|
Does a function see them? Well, let's clear up the confusion.</para>
|
|
|
|
<example id="funccmdlinearg">
|
|
<title>Functions and command-line args passed to the script</title>
|
|
<programlisting>&funccmdlinearg;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>In contrast to certain other programming languages,
|
|
shell scripts normally pass only value parameters to
|
|
functions. Variable names (which are actually
|
|
<firstterm>pointers</firstterm>), if
|
|
passed as parameters to functions, will be treated as string
|
|
literals. <emphasis>Functions interpret their arguments
|
|
literally.</emphasis></para>
|
|
|
|
<para><anchor id="funcpointers"/></para>
|
|
<para><link linkend="ivrref">Indirect variable
|
|
references</link> (see <xref linkend="ex78"/>) provide a clumsy
|
|
sort of mechanism for passing variable pointers to
|
|
functions.</para>
|
|
|
|
<example id="indfunc">
|
|
<title>Passing an indirect reference to a function</title>
|
|
<programlisting>&indfunc;</programlisting>
|
|
</example>
|
|
|
|
<para>The next logical question is whether parameters can be
|
|
dereferenced <emphasis>after</emphasis> being passed to a
|
|
function.</para>
|
|
|
|
<example id="dereferencecl">
|
|
<title>Dereferencing a parameter passed to a function</title>
|
|
<programlisting>&dereferencecl;</programlisting>
|
|
</example>
|
|
|
|
<example id="refparams">
|
|
<title>Again, dereferencing a parameter passed to a function</title>
|
|
<programlisting>&refparams;</programlisting>
|
|
</example>
|
|
|
|
|
|
<variablelist id="exitreturn">
|
|
<title><anchor id="exitreturn1"/>Exit and Return</title>
|
|
|
|
<varlistentry>
|
|
<term><command>exit status</command></term>
|
|
<listitem>
|
|
<para>Functions return a value, called an <firstterm>exit
|
|
status</firstterm>. This is analogous to the <link
|
|
linkend="exitstatusref">exit status</link> returned by a
|
|
command. 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>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>return</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>command</primary>
|
|
<secondary>return</secondary>
|
|
</indexterm>
|
|
<para><anchor id="returnref"/></para>
|
|
<para>Terminates a function. A <command>return</command> command
|
|
<footnote><para>The <command>return</command> command is a
|
|
Bash <link linkend="builtinref">builtin</link>.</para></footnote>
|
|
optionally takes an <firstterm>integer</firstterm>
|
|
argument, which is returned to the calling script as
|
|
the <quote>exit status</quote> of the function, and
|
|
this exit status is assigned to the variable <link
|
|
linkend="xstatvarref">$?</link>.</para>
|
|
|
|
<example id="max">
|
|
<title>Maximum of two numbers</title>
|
|
<programlisting>&max;</programlisting>
|
|
</example>
|
|
|
|
<tip>
|
|
<para>For a function to return a string or array, use a
|
|
dedicated variable.
|
|
<programlisting>count_lines_in_etc_passwd()
|
|
{
|
|
[[ -r /etc/passwd ]] && REPLY=$(echo $(wc -l < /etc/passwd))
|
|
# If /etc/passwd is readable, set REPLY to line count.
|
|
# Returns both a parameter value and status information.
|
|
# The 'echo' seems unnecessary, but . . .
|
|
#+ it removes excess whitespace from the output.
|
|
}
|
|
|
|
if count_lines_in_etc_passwd
|
|
then
|
|
echo "There are $REPLY lines in /etc/passwd."
|
|
else
|
|
echo "Cannot count lines in /etc/passwd."
|
|
fi
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
</tip>
|
|
|
|
|
|
|
|
|
|
<example id="ex61">
|
|
<title>Converting numbers to Roman numerals</title>
|
|
<programlisting>&ex61;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="isalpha"/>.</para>
|
|
|
|
<important>
|
|
|
|
<para>The largest positive integer a function can return is
|
|
255. The <command>return</command> command is closely tied
|
|
to the concept of <link linkend="exitstatusref">exit
|
|
status</link>, which accounts for this particular
|
|
limitation. Fortunately, there are various <link
|
|
linkend="rvt">workarounds</link> for those situations
|
|
requiring a large integer return value from a
|
|
function.</para>
|
|
|
|
|
|
<example id="returntest">
|
|
<title>Testing large return values in a function</title>
|
|
<programlisting>&returntest;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>A workaround for obtaining large integer <quote>return
|
|
values</quote> is to simply assign the <quote>return
|
|
value</quote> to a global variable.
|
|
|
|
<programlisting>Return_Val= # Global variable to hold oversize return value of function.
|
|
|
|
alt_return_test ()
|
|
{
|
|
fvar=$1
|
|
Return_Val=$fvar
|
|
return # Returns 0 (success).
|
|
}
|
|
|
|
alt_return_test 1
|
|
echo $? # 0
|
|
echo "return value = $Return_Val" # 1
|
|
|
|
alt_return_test 256
|
|
echo "return value = $Return_Val" # 256
|
|
|
|
alt_return_test 257
|
|
echo "return value = $Return_Val" # 257
|
|
|
|
alt_return_test 25701
|
|
echo "return value = $Return_Val" #25701</programlisting>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="captureretval"/></para>
|
|
<para>A more elegant method is to have the function
|
|
<command>echo</command> its <quote>return
|
|
value to <filename>stdout</filename>,</quote> and
|
|
then capture it by <link linkend="commandsubref">command
|
|
substitution</link>. See the <link linkend="rvt">discussion
|
|
of this</link> in <xref linkend="assortedtips"/>.</para>
|
|
|
|
<example id="max2">
|
|
<title>Comparing two large integers</title>
|
|
<programlisting>&max2;</programlisting>
|
|
</example>
|
|
|
|
<para>Here is another example of capturing a function
|
|
<quote>return value.</quote> Understanding it requires some
|
|
knowledge of <link linkend="awkref">awk</link>.
|
|
|
|
<programlisting>month_length () # Takes month number as an argument.
|
|
{ # Returns number of days in month.
|
|
monthD="31 28 31 30 31 30 31 31 30 31 30 31" # Declare as local?
|
|
echo "$monthD" | awk '{ print $'"${1}"' }' # Tricky.
|
|
# ^^^^^^^^^
|
|
# Parameter passed to function ($1 -- month number), then to awk.
|
|
# Awk sees this as "print $1 . . . print $12" (depending on month number)
|
|
# Template for passing a parameter to embedded awk script:
|
|
# $'"${script_parameter}"'
|
|
|
|
# Here's a slightly simpler awk construct:
|
|
# echo $monthD | awk -v month=$1 '{print $(month)}'
|
|
# Uses the -v awk option, which assigns a variable value
|
|
#+ prior to execution of the awk program block.
|
|
# Thank you, Rich.
|
|
|
|
# Needs error checking for correct parameter range (1-12)
|
|
#+ and for February in leap year.
|
|
}
|
|
|
|
# ----------------------------------------------
|
|
# Usage example:
|
|
month=4 # April, for example (4th month).
|
|
days_in=$(month_length $month)
|
|
echo $days_in # 30
|
|
# ----------------------------------------------</programlisting></para>
|
|
|
|
|
|
<para>See also <xref linkend="daysbetween"/>
|
|
and <xref linkend="stddev"/>.</para>
|
|
|
|
<para><userinput>Exercise:</userinput> Using what we have
|
|
just learned, extend the previous <link
|
|
linkend="ex61">Roman numerals example</link> to accept
|
|
arbitrarily large input.</para>
|
|
|
|
</important>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="redstdinfunc">
|
|
<title><anchor id="redstdinfunc1"/>Redirection</title>
|
|
|
|
<varlistentry>
|
|
<term><replaceable>Redirecting the stdin
|
|
of a function</replaceable></term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>redirection</primary>
|
|
<secondary>stdin</secondary>
|
|
</indexterm>
|
|
|
|
<para>A function is essentially a <link
|
|
linkend="codeblockref">code block</link>, which means its
|
|
<filename>stdin</filename> can be redirected (as in <xref
|
|
linkend="ex8"/>).</para>
|
|
|
|
<example id="realname">
|
|
<title>Real name from username</title>
|
|
<programlisting>&realname;</programlisting>
|
|
</example>
|
|
|
|
<para>There is an alternate, and perhaps less confusing
|
|
method of redirecting a function's
|
|
<filename>stdin</filename>. This involves redirecting the
|
|
<filename>stdin</filename> to an embedded bracketed code
|
|
block within the function.
|
|
|
|
<programlisting># Instead of:
|
|
Function ()
|
|
{
|
|
...
|
|
} < file
|
|
|
|
# Try this:
|
|
Function ()
|
|
{
|
|
{
|
|
...
|
|
} < file
|
|
}
|
|
|
|
# Similarly,
|
|
|
|
Function () # This works.
|
|
{
|
|
{
|
|
echo $*
|
|
} | tr a b
|
|
}
|
|
|
|
Function () # This doesn't work.
|
|
{
|
|
echo $*
|
|
} | tr a b # A nested code block is mandatory here.
|
|
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<note><para>Emmanuel Rouat's <link
|
|
linkend="sample-bashrc">sample <filename>bashrc</filename>
|
|
file</link> contains some instructive examples of
|
|
functions.</para></note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect1> <!-- Complex Functions and Function Complexities -->
|
|
|
|
|
|
|
|
<sect1 id="localvar">
|
|
<title>Local Variables</title>
|
|
|
|
<variablelist id="localref">
|
|
<title><anchor id="localref1"/>What makes a variable
|
|
<firstterm>local</firstterm>?</title>
|
|
|
|
<varlistentry>
|
|
<term>local variables</term>
|
|
<listitem>
|
|
<indexterm>
|
|
<primary>variable</primary>
|
|
<secondary>local</secondary>
|
|
</indexterm>
|
|
<para>A variable declared as <firstterm>local</firstterm>
|
|
is one that is visible only within the <link
|
|
linkend="codeblockref">block of code</link> in which it
|
|
appears. It has local <link linkend="scoperef">scope</link>.
|
|
In a function, a <firstterm>local variable</firstterm> has
|
|
meaning only within that function block.
|
|
|
|
<footnote>
|
|
|
|
<para>However, as Thomas Braunberger points out, a local
|
|
variable declared in a function <emphasis>is also visible
|
|
to functions called by the parent
|
|
function.</emphasis></para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
function1 ()
|
|
{
|
|
local func1var=20
|
|
|
|
echo "Within function1, \$func1var = $func1var."
|
|
|
|
function2
|
|
}
|
|
|
|
function2 ()
|
|
{
|
|
echo "Within function2, \$func1var = $func1var."
|
|
}
|
|
|
|
function1
|
|
|
|
exit 0
|
|
|
|
|
|
# Output of the script:
|
|
|
|
# Within function1, $func1var = 20.
|
|
# Within function2, $func1var = 20.</programlisting></para>
|
|
|
|
<para>This is documented in the Bash manual:</para>
|
|
|
|
<para><quote>Local can only be used within a function;
|
|
it makes the variable name have a visible scope
|
|
restricted to that function <emphasis>and its
|
|
children</emphasis>.</quote> [emphasis added]
|
|
<emphasis>The ABS Guide author considers this behavior
|
|
to be a bug.</emphasis></para>
|
|
|
|
</footnote>
|
|
</para>
|
|
|
|
|
|
|
|
<example id="ex62">
|
|
<title>Local variable visibility</title>
|
|
<programlisting>&ex62;</programlisting>
|
|
</example>
|
|
|
|
<caution>
|
|
<para>Before a function is called, <emphasis>all</emphasis>
|
|
variables declared within the function are invisible outside
|
|
the body of the function, not just those explicitly declared
|
|
as <firstterm>local</firstterm>.
|
|
<programlisting>#!/bin/bash
|
|
|
|
func ()
|
|
{
|
|
global_var=37 # Visible only within the function block
|
|
#+ before the function has been called.
|
|
} # END OF FUNCTION
|
|
|
|
echo "global_var = $global_var" # global_var =
|
|
# Function "func" has not yet been called,
|
|
#+ so $global_var is not visible here.
|
|
|
|
func
|
|
echo "global_var = $global_var" # global_var = 37
|
|
# Has been set by function call.</programlisting>
|
|
</para>
|
|
</caution>
|
|
|
|
<note>
|
|
<para><anchor id="exitvalanomaly01"/></para>
|
|
<para>As Evgeniy Ivanov points out, when declaring and
|
|
setting a local variable in a single command, apparently the
|
|
order of operations is to <emphasis>first set the variable,
|
|
and only afterwards restrict it to local scope</emphasis>.
|
|
This is reflected in the <link
|
|
linkend="exitstatusref">return value</link>.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
echo "==OUTSIDE Function (global)=="
|
|
t=$(exit 1)
|
|
echo $? # 1
|
|
# As expected.
|
|
echo
|
|
|
|
function0 ()
|
|
{
|
|
|
|
echo "==INSIDE Function=="
|
|
echo "Global"
|
|
t0=$(exit 1)
|
|
echo $? # 1
|
|
# As expected.
|
|
|
|
echo
|
|
echo "Local declared & assigned in same command."
|
|
local t1=$(exit 1)
|
|
echo $? # 0
|
|
# Unexpected!
|
|
# Apparently, the variable assignment takes place before
|
|
#+ the local declaration.
|
|
#+ The return value is for the latter.
|
|
|
|
echo
|
|
echo "Local declared, then assigned (separate commands)."
|
|
local t2
|
|
t2=$(exit 1)
|
|
echo $? # 1
|
|
# As expected.
|
|
|
|
}
|
|
|
|
function0</programlisting></para>
|
|
</note>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<sect2 id="locvarrecur">
|
|
<title>Local variables and recursion.</title>
|
|
|
|
<para><anchor id="recursionref0"/></para>
|
|
|
|
<sidebar>
|
|
|
|
<para><anchor id="recursionref"/></para>
|
|
<para><firstterm>Recursion</firstterm> is an interesting
|
|
and sometimes useful form of
|
|
<firstterm>self-reference</firstterm>. <link
|
|
linkend="mayerref">Herbert Mayer</link> defines it
|
|
as <quote>. . . expressing an algorithm by using a
|
|
simpler version of that same algorithm . . .</quote></para>
|
|
|
|
<para>Consider a definition defined in terms of itself,
|
|
<footnote><para>Otherwise known as
|
|
<firstterm>redundancy</firstterm>.</para></footnote>
|
|
an expression implicit in its own expression,
|
|
<footnote><para>Otherwise known as
|
|
<firstterm>tautology</firstterm>.</para></footnote>
|
|
<emphasis>a snake swallowing its own
|
|
tail</emphasis>,
|
|
<footnote><para>Otherwise known as a
|
|
<firstterm>metaphor</firstterm>.</para></footnote>
|
|
or . . . a function that calls itself.
|
|
<footnote><para>Otherwise known as a
|
|
<firstterm>recursive function</firstterm>.</para></footnote>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="recursiondemo0"/></para>
|
|
<example id="recursiondemo">
|
|
<title>Demonstration of a simple recursive function</title>
|
|
<programlisting>&recursiondemo;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="recursiondemo02"/></para>
|
|
<example id="recursiondemo2">
|
|
<title>Another simple demonstration</title>
|
|
<programlisting>&recursiondemo2;</programlisting>
|
|
</example>
|
|
|
|
</sidebar>
|
|
|
|
<para>Local variables are a useful tool for writing recursive
|
|
code, but this practice generally involves a great deal of
|
|
computational overhead and is definitely
|
|
<emphasis>not</emphasis> recommended in a shell script.
|
|
|
|
<footnote><para>Too many levels of recursion may crash a
|
|
script with a segfault.
|
|
<programlisting>#!/bin/bash
|
|
|
|
# Warning: Running this script could possibly lock up your system!
|
|
# If you're lucky, it will segfault before using up all available memory.
|
|
|
|
recursive_function ()
|
|
{
|
|
echo "$1" # Makes the function do something, and hastens the segfault.
|
|
(( $1 < $2 )) && recursive_function $(( $1 + 1 )) $2;
|
|
# As long as 1st parameter is less than 2nd,
|
|
#+ increment 1st and recurse.
|
|
}
|
|
|
|
recursive_function 1 50000 # Recurse 50,000 levels!
|
|
# Most likely segfaults (depending on stack size, set by ulimit -m).
|
|
|
|
# Recursion this deep might cause even a C program to segfault,
|
|
#+ by using up all the memory allotted to the stack.
|
|
|
|
|
|
echo "This will probably not print."
|
|
exit 0 # This script will not exit normally.
|
|
|
|
# Thanks, Stéphane Chazelas.</programlisting>
|
|
</para></footnote>
|
|
|
|
</para>
|
|
|
|
<para><anchor id="factorialref"/></para>
|
|
<example id="ex63">
|
|
<title>Recursion, using a local variable</title>
|
|
<programlisting>&ex63;</programlisting>
|
|
</example>
|
|
|
|
<para>Also see <xref linkend="primes"/> for an example of
|
|
recursion in a script. Be aware that recursion is
|
|
resource-intensive and executes slowly, and is therefore
|
|
generally not appropriate in a script.</para>
|
|
|
|
</sect2>
|
|
</sect1> <!-- Local Variables -->
|
|
|
|
|
|
|
|
<sect1 id="recurnolocvar">
|
|
<title>Recursion Without Local Variables</title>
|
|
|
|
<para>A function may recursively call itself even without use of
|
|
local variables.</para>
|
|
|
|
<para><anchor id="fiboref"/></para>
|
|
<example id="fibo">
|
|
<title><firstterm>The Fibonacci Sequence</firstterm></title>
|
|
<programlisting>&fibo;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="hanoiref"/></para>
|
|
<example id="hanoi">
|
|
<title><firstterm>The Towers of Hanoi</firstterm></title>
|
|
<programlisting>&hanoi;</programlisting>
|
|
</example>
|
|
|
|
|
|
</sect1> <!-- Recursion Without Local Variables -->
|
|
|
|
|
|
|
|
</chapter> <!-- Functions -->
|
|
|
|
|
|
|
|
<chapter id="aliases">
|
|
<title>Aliases</title>
|
|
|
|
<para><anchor id="aliasref"/></para>
|
|
|
|
<indexterm>
|
|
<primary>alias</primary>
|
|
</indexterm>
|
|
|
|
<para>A Bash <firstterm>alias</firstterm> is essentially nothing
|
|
more than a keyboard shortcut, an abbreviation, a means of
|
|
avoiding typing a long command sequence. If, for example,
|
|
we include <command>alias lm="ls -l | more"</command> in
|
|
the <link linkend="sample-bashrc"><filename>~/.bashrc</filename>
|
|
file</link>, then each <userinput>lm</userinput>
|
|
<footnote><para> ... as the first word of a command string.
|
|
Obviously, an alias is only meaningful at the
|
|
<emphasis>beginning</emphasis> of a command.</para></footnote>
|
|
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 deleting
|
|
important files.</para>
|
|
|
|
<para>In a script, aliases have very limited usefulness. It would be
|
|
nice if aliases could assume some of the functionality of
|
|
the <command>C</command> preprocessor, such as macro expansion,
|
|
but unfortunately Bash does not expand arguments within the
|
|
alias body.
|
|
<footnote><para>However, aliases do seem to expand positional
|
|
parameters.</para></footnote>
|
|
Moreover, a script fails to expand an alias itself
|
|
within <quote>compound constructs,</quote> such as <link
|
|
linkend="ifthen">if/then</link> statements, loops, and
|
|
functions. An added limitation is that an alias will not expand
|
|
recursively. Almost invariably, whatever we would like an alias
|
|
to do could be accomplished much more effectively with a <link
|
|
linkend="functionref">function</link>.</para>
|
|
|
|
<example id="al">
|
|
<title>Aliases within a script</title>
|
|
<programlisting>&al;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="unaliasref"/></para>
|
|
<para>The <command>unalias</command> command removes a previously
|
|
set <firstterm>alias</firstterm>.</para>
|
|
|
|
<example id="unal">
|
|
<title><firstterm>unalias</firstterm>: Setting and unsetting
|
|
an alias</title>
|
|
<programlisting>&unal;</programlisting>
|
|
</example>
|
|
|
|
<screen><prompt>bash$ </prompt><userinput>./unalias.sh</userinput>
|
|
<computeroutput>
|
|
total 6
|
|
drwxrwxr-x 2 bozo bozo 3072 Feb 6 14:04 .
|
|
drwxr-xr-x 40 bozo bozo 2048 Feb 6 14:04 ..
|
|
-rwxr-xr-x 1 bozo bozo 199 Feb 6 14:04 unalias.sh
|
|
|
|
./unalias.sh: llm: command not found
|
|
</computeroutput></screen>
|
|
|
|
|
|
</chapter> <!-- Aliases -->
|
|
|
|
|
|
|
|
|
|
<chapter id="list-cons">
|
|
<title>List Constructs</title>
|
|
|
|
<para><anchor id="listconsref"/></para>
|
|
|
|
|
|
<indexterm>
|
|
<primary>&&</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>&&</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>AND</primary>
|
|
<secondary>list</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>||</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>special character</primary>
|
|
<secondary>||</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>OR</primary>
|
|
<secondary>list</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <firstterm>and list</firstterm> and <firstterm>or
|
|
list</firstterm> constructs provide a means of processing a
|
|
number of commands consecutively. These can effectively replace
|
|
complex nested <link linkend="testconstructs1">if/then</link>
|
|
or even <link linkend="caseesac1">case</link> statements.</para>
|
|
|
|
|
|
<variablelist id="lcons">
|
|
<title><anchor id="lcons1"/>Chaining together commands</title>
|
|
|
|
<varlistentry>
|
|
<term>and list</term>
|
|
<listitem>
|
|
<para><programlisting>command-1 && command-2 && command-3 && ... command-n</programlisting>
|
|
Each command executes in turn, provided that
|
|
the previous command has given a return value of
|
|
<replaceable>true</replaceable> (zero). At the first
|
|
<replaceable>false</replaceable> (non-zero) return, the
|
|
command chain terminates (the first command returning
|
|
<replaceable>false</replaceable> is the last one to
|
|
execute).</para>
|
|
|
|
<para>An interesting use of a two-condition <firstterm>and
|
|
list</firstterm> from an early version of YongYe's <ulink
|
|
url="http://bash.deta.in/Tetris_Game.sh">Tetris
|
|
game script</ulink>:</para>
|
|
|
|
<para>
|
|
<programlisting>equation()
|
|
|
|
{ # core algorithm used for doubling and halving the coordinates
|
|
[[ ${cdx} ]] && ((y=cy+(ccy-cdy)${2}2))
|
|
eval ${1}+=\"${x} ${y} \"
|
|
}</programlisting>
|
|
</para>
|
|
|
|
|
|
<example id="ex64">
|
|
<title>Using an <firstterm>and list</firstterm> to test
|
|
for command-line arguments</title>
|
|
<programlisting>&ex64;</programlisting>
|
|
</example>
|
|
|
|
<example id="andlist2">
|
|
<title>Another command-line arg test using an <firstterm>and
|
|
list</firstterm></title>
|
|
<programlisting>&andlist2;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="anddefault"/></para>
|
|
<para>
|
|
Of course, an <firstterm>and list</firstterm> can also
|
|
<firstterm>set</firstterm> variables to a default value.
|
|
<programlisting>arg1=$@ && [ -z "$arg1" ] && arg1=DEFAULT
|
|
|
|
# Set $arg1 to command-line arguments, if any.
|
|
# But . . . set to DEFAULT if not specified on command-line.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="orlistref"/>or list</term>
|
|
<listitem>
|
|
<para><programlisting>command-1 || command-2 || command-3 || ... command-n</programlisting>
|
|
Each command executes in turn for as long as the previous
|
|
command returns <returnvalue>false</returnvalue>. At
|
|
the first <returnvalue>true</returnvalue> return, the
|
|
command chain terminates (the first command returning
|
|
<returnvalue>true</returnvalue> is the last one to
|
|
execute). This is obviously the inverse of the <quote>and
|
|
list</quote>.</para>
|
|
|
|
|
|
|
|
<example id="ex65">
|
|
<title>Using <firstterm>or lists</firstterm> in combination
|
|
with an <firstterm>and list</firstterm></title>
|
|
<programlisting>&ex65;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>If the first command in an <firstterm>or
|
|
list</firstterm> returns <returnvalue>true</returnvalue>,
|
|
it <replaceable>will</replaceable> execute.</para></caution>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<para><programlisting># ==> The following snippets from the /etc/rc.d/init.d/single
|
|
#+==> script by Miquel van Smoorenburg
|
|
#+==> illustrate use of "and" and "or" lists.
|
|
# ==> "Arrowed" comments added by document author.
|
|
|
|
[ -x /usr/bin/clear ] && /usr/bin/clear
|
|
# ==> If /usr/bin/clear exists, then invoke it.
|
|
# ==> Checking for the existence of a command before calling it
|
|
#+==> avoids error messages and other awkward consequences.
|
|
|
|
# ==> . . .
|
|
|
|
# If they want to run something in single user mode, might as well run it...
|
|
for i in /etc/rc1.d/S[0-9][0-9]* ; do
|
|
# Check if the script is there.
|
|
[ -x "$i" ] || continue
|
|
# ==> If corresponding file in $PWD *not* found,
|
|
#+==> then "continue" by jumping to the top of the loop.
|
|
|
|
# Reject backup files and files generated by rpm.
|
|
case "$1" in
|
|
*.rpmsave|*.rpmorig|*.rpmnew|*~|*.orig)
|
|
continue;;
|
|
esac
|
|
[ "$i" = "/etc/rc1.d/S00single" ] && continue
|
|
# ==> Set script name, but don't execute it yet.
|
|
$i start
|
|
done
|
|
|
|
# ==> . . .</programlisting></para>
|
|
|
|
|
|
<important><para>The <link linkend="exitstatusref">exit
|
|
status</link> of an <userinput>and list</userinput> or an
|
|
<userinput>or list</userinput> is the exit status of the last
|
|
command executed.</para></important>
|
|
|
|
<para>Clever combinations of <firstterm>and</firstterm> and
|
|
<firstterm>or</firstterm> lists are possible, but the logic may
|
|
easily become convoluted and require close attention to <link
|
|
linkend="opprecedence1">operator precedence rules</link>, and
|
|
possibly extensive debugging.</para>
|
|
|
|
<para><programlisting>false && true || echo false # false
|
|
|
|
# Same result as
|
|
( false && true ) || echo false # false
|
|
# But NOT
|
|
false && ( true || echo false ) # (nothing echoed)
|
|
|
|
# Note left-to-right grouping and evaluation of statements.
|
|
|
|
# It's usually best to avoid such complexities.
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
<para>See <xref linkend="daysbetween"/> and <xref
|
|
linkend="brokenlink"/> for illustrations of using <userinput>and
|
|
/ or list</userinput> constructs to test variables.</para>
|
|
|
|
|
|
</chapter> <!-- List Constructs -->
|
|
|
|
|
|
|
|
|
|
<chapter id="arrays">
|
|
<title>Arrays</title>
|
|
|
|
<para><anchor id="arrayref"/></para>
|
|
|
|
<para>Newer versions of Bash support one-dimensional arrays.
|
|
<anchor id="brackarray"/>
|
|
Array elements may be initialized with the
|
|
<userinput>variable[xx]</userinput> notation. Alternatively,
|
|
a script may introduce the entire array by an explicit
|
|
<userinput>declare -a variable</userinput> statement. To
|
|
dereference (retrieve the contents of) an array element, use
|
|
<firstterm>curly bracket</firstterm> notation, that is,
|
|
<userinput>${element[xx]}</userinput>.</para>
|
|
|
|
<para><anchor id="arraynotation"/></para>
|
|
|
|
<example id="ex66">
|
|
<title>Simple array usage</title>
|
|
<programlisting>&ex66;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="arrayinit0"/></para>
|
|
<para>As we have seen, a convenient way of initializing an entire array
|
|
is the <varname>array=( element1 element2 ... elementN )</varname>
|
|
notation.</para>
|
|
|
|
<para>
|
|
<programlisting>base64_charset=( {A..Z} {a..z} {0..9} + / = )
|
|
# Using extended brace expansion
|
|
#+ to initialize the elements of the array.
|
|
# Excerpted from vladz's "base64.sh" script
|
|
#+ in the "Contributed Scripts" appendix.</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="arrayopsvars"/></para>
|
|
|
|
<sidebar><para>Bash permits array operations on variables, even if
|
|
the variables are not explicitly declared as arrays.</para>
|
|
<para><programlisting>string=abcABC123ABCabc
|
|
echo ${string[@]} # abcABC123ABCabc
|
|
echo ${string[*]} # abcABC123ABCabc
|
|
echo ${string[0]} # abcABC123ABCabc
|
|
echo ${string[1]} # No output!
|
|
# Why?
|
|
echo ${#string[@]} # 1
|
|
# One element in the array.
|
|
# The string itself.
|
|
|
|
# Thank you, Michael Zick, for pointing this out.</programlisting>
|
|
Once again this demonstrates that <link linkend="bvuntyped">Bash
|
|
variables are untyped</link>.
|
|
</para></sidebar>
|
|
|
|
|
|
<example id="poem">
|
|
<title>Formatting a poem</title>
|
|
<programlisting>&poem;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="arraysyntax"/></para>
|
|
<para>Array variables have a syntax all their own, and even
|
|
standard Bash commands and operators have special options adapted
|
|
for array use.</para>
|
|
|
|
<example id="arrayops">
|
|
<title>Various array operations</title>
|
|
<programlisting>&arrayops;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="arraystringops"/></para>
|
|
<para>Many of the standard <link linkend="stringmanip">string
|
|
operations</link> work on arrays.</para>
|
|
|
|
<example id="arraystrops">
|
|
<title>String operations on arrays</title>
|
|
<programlisting>&arraystrops;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><link linkend="commandsubref">Command substitution</link> can
|
|
construct the individual elements of an array.</para>
|
|
|
|
<example id="scriptarray">
|
|
<title>Loading the contents of a script into an array</title>
|
|
<programlisting>&scriptarray;</programlisting>
|
|
</example>
|
|
|
|
<para>In an array context, some Bash <link
|
|
linkend="builtinref">builtins</link> have a slightly
|
|
altered meaning. <anchor id="arrayunset"/>For example, <link
|
|
linkend="unsetref">unset</link> deletes array elements, or even
|
|
an entire array.</para>
|
|
|
|
<para><anchor id="arrayspecialprops"/></para>
|
|
<example id="ex67">
|
|
<title>Some special properties of arrays</title>
|
|
<programlisting>&ex67;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="arraynumelements"/></para>
|
|
<para>As seen in the previous example, either
|
|
<command>${array_name[@]}</command> or
|
|
<command>${array_name[*]}</command> refers to
|
|
<emphasis>all</emphasis> the elements of the array.
|
|
Similarly, to get a count of the number of elements in an
|
|
array, use either <command>${#array_name[@]}</command>
|
|
or <command>${#array_name[*]}</command>.
|
|
<command>${#array_name}</command> is the length (number of
|
|
characters) of <command>${array_name[0]}</command>, the first
|
|
element of the array.</para>
|
|
|
|
<para><anchor id="emptyarray0"/></para>
|
|
<example id="emptyarray">
|
|
<title>Of empty arrays and empty elements</title>
|
|
<programlisting>&emptyarray;</programlisting>
|
|
</example>
|
|
|
|
<para>The relationship of <command>${array_name[@]}</command>
|
|
and <command>${array_name[*]}</command> is analogous to that
|
|
between <link linkend="appref">$@ and $*</link>. This powerful
|
|
array notation has a number of uses.</para>
|
|
|
|
<para><anchor id="copyarray0"/></para>
|
|
<para>
|
|
<programlisting># Copying an array.
|
|
array2=( "${array1[@]}" )
|
|
# or
|
|
array2="${array1[@]}"
|
|
#
|
|
# However, this fails with "sparse" arrays,
|
|
#+ arrays with holes (missing elements) in them,
|
|
#+ as Jochen DeSmet points out.
|
|
# ------------------------------------------
|
|
array1[0]=0
|
|
# array1[1] not assigned
|
|
array1[2]=2
|
|
array2=( "${array1[@]}" ) # Copy it?
|
|
|
|
echo ${array2[0]} # 0
|
|
echo ${array2[2]} # (null), should be 2
|
|
# ------------------------------------------
|
|
|
|
|
|
|
|
# Adding an element to an array.
|
|
array=( "${array[@]}" "new element" )
|
|
# or
|
|
array[${#array[*]}]="new element"
|
|
|
|
# Thanks, S.C.</programlisting>
|
|
</para>
|
|
|
|
|
|
<para><anchor id="arrayinitcs"/></para>
|
|
<tip>
|
|
<para>The <command>array=( element1 element2 ... elementN )</command>
|
|
initialization operation, with the help of <link
|
|
linkend="commandsubref">command substitution</link>, makes it
|
|
possible to load the contents of a text file into an array.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
filename=sample_file
|
|
|
|
# cat sample_file
|
|
#
|
|
# 1 a b c
|
|
# 2 d e fg
|
|
|
|
|
|
declare -a array1
|
|
|
|
array1=( `cat "$filename"`) # Loads contents
|
|
# List file to stdout #+ of $filename into array1.
|
|
#
|
|
# array1=( `cat "$filename" | tr '\n' ' '`)
|
|
# change linefeeds in file to spaces.
|
|
# Not necessary because Bash does word splitting,
|
|
#+ changing linefeeds to spaces.
|
|
|
|
echo ${array1[@]} # List the array.
|
|
# 1 a b c 2 d e fg
|
|
#
|
|
# Each whitespace-separated "word" in the file
|
|
#+ has been assigned to an element of the array.
|
|
|
|
element_count=${#array1[*]}
|
|
echo $element_count # 8</programlisting>
|
|
</para>
|
|
</tip>
|
|
|
|
<para>Clever scripting makes it possible to add array operations.</para>
|
|
|
|
<para><anchor id="arrayassign0"/></para>
|
|
<example id="arrayassign">
|
|
<title>Initializing arrays</title>
|
|
<programlisting>&arrayassign;</programlisting>
|
|
</example>
|
|
|
|
<note><para>Adding a superfluous <command>declare -a</command>
|
|
statement to an array declaration may speed up execution of
|
|
subsequent operations on the array.</para></note>
|
|
|
|
<para><anchor id="arrayappend0"/></para>
|
|
<example id="copyarray">
|
|
<title>Copying and concatenating arrays</title>
|
|
<programlisting>©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 for the reader to
|
|
decide.</para>
|
|
|
|
<para><anchor id="bubblesort"/></para>
|
|
|
|
<example id="bubble">
|
|
<title>The Bubble Sort</title>
|
|
<programlisting>&bubble;</programlisting>
|
|
</example>
|
|
|
|
<para>--</para>
|
|
|
|
<para><anchor id="arraynest"/></para>
|
|
<para>Is it possible to nest arrays within arrays?</para>
|
|
<para><programlisting>#!/bin/bash
|
|
# "Nested" array.
|
|
|
|
# Michael Zick provided this example,
|
|
#+ with corrections and clarifications by William Park.
|
|
|
|
AnArray=( $(ls --inode --ignore-backups --almost-all \
|
|
--directory --full-time --color=none --time=status \
|
|
--sort=time -l ${PWD} ) ) # Commands and options.
|
|
|
|
# Spaces are significant . . . and don't quote anything in the above.
|
|
|
|
SubArray=( ${AnArray[@]:11:1} ${AnArray[@]:6:5} )
|
|
# This array has six elements:
|
|
#+ SubArray=( [0]=${AnArray[11]} [1]=${AnArray[6]} [2]=${AnArray[7]}
|
|
# [3]=${AnArray[8]} [4]=${AnArray[9]} [5]=${AnArray[10]} )
|
|
#
|
|
# Arrays in Bash are (circularly) linked lists
|
|
#+ of type string (char *).
|
|
# So, this isn't actually a nested array,
|
|
#+ but it's functionally similar.
|
|
|
|
echo "Current directory and date of last status change:"
|
|
echo "${SubArray[@]}"
|
|
|
|
exit 0</programlisting></para>
|
|
|
|
<para>--</para>
|
|
|
|
<para>Embedded arrays in combination with <link
|
|
linkend="varrefnew">indirect references</link> create some fascinating
|
|
possibilities</para>
|
|
|
|
<para><anchor id="arrayindir"/></para>
|
|
<example id="embarr">
|
|
<title>Embedded arrays and indirect references</title>
|
|
<programlisting>&embarr;</programlisting>
|
|
</example>
|
|
|
|
<para>--</para>
|
|
|
|
<para><anchor id="primes0"/></para>
|
|
<para>Arrays enable implementing a shell script version of the
|
|
<firstterm>Sieve of Eratosthenes</firstterm>. Of course, a
|
|
resource-intensive application of this nature should really be
|
|
written in a compiled language, such as C. It runs excruciatingly
|
|
slowly as a script.</para>
|
|
|
|
<example id="ex68">
|
|
<title>The Sieve of Eratosthenes</title>
|
|
<programlisting>&ex68;</programlisting>
|
|
</example>
|
|
|
|
<example id="ex68a">
|
|
<title>The Sieve of Eratosthenes, Optimized</title>
|
|
<programlisting>&ex68a;</programlisting>
|
|
</example>
|
|
|
|
<para>Compare these array-based prime number generators with
|
|
alternatives that do not use arrays, <xref linkend="primes"/>,
|
|
and <xref linkend="primes2"/>.</para>
|
|
|
|
<para>--</para>
|
|
|
|
<para>Arrays lend themselves, to some extent, to emulating data
|
|
structures for which Bash has no native support.</para>
|
|
|
|
<para><anchor id="stackex0"/></para>
|
|
<example id="stackex">
|
|
<title>Emulating a push-down stack</title>
|
|
<programlisting>&stackex;</programlisting>
|
|
</example>
|
|
|
|
<para>--</para>
|
|
|
|
<para>Fancy manipulation of array <quote>subscripts</quote> may require
|
|
intermediate variables. For projects involving this, again consider
|
|
using a more powerful programming language, such as Perl or C.</para>
|
|
|
|
<example id="qfunction">
|
|
<title>Complex array application:
|
|
<emphasis>Exploring a weird mathematical series</emphasis></title>
|
|
<programlisting>&qfunction;</programlisting>
|
|
</example>
|
|
|
|
<para>--</para>
|
|
|
|
<para><anchor id="arraymultidim"/></para>
|
|
<para>Bash supports only one-dimensional arrays, though a little
|
|
trickery permits simulating multi-dimensional ones.</para>
|
|
|
|
<example id="twodim">
|
|
<title>Simulating a two-dimensional array, then tilting it</title>
|
|
<programlisting>&twodim;</programlisting>
|
|
</example>
|
|
|
|
<para>A two-dimensional array is essentially equivalent to a
|
|
one-dimensional one, but with additional addressing modes
|
|
for referencing and manipulating the individual elements by
|
|
<firstterm>row</firstterm> and <firstterm>column</firstterm>
|
|
position.</para>
|
|
|
|
<para>For an even more elaborate example of simulating a
|
|
two-dimensional array, see <xref linkend="lifeslow"/>.</para>
|
|
|
|
<para>--</para>
|
|
|
|
<para>For more interesting scripts using arrays, see:
|
|
<itemizedlist>
|
|
<listitem><para><xref linkend="agram2"/></para></listitem>
|
|
<listitem><para><xref linkend="primes2"/></para></listitem>
|
|
<listitem><para><xref linkend="hashex2"/></para></listitem>
|
|
<listitem><para><xref linkend="homework"/></para></listitem>
|
|
<listitem><para><xref linkend="qky"/></para></listitem>
|
|
<listitem><para><xref linkend="nim"/></para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
</chapter> <!-- Arrays -->
|
|
|
|
|
|
<chapter id="ivr">
|
|
<title>Indirect References</title>
|
|
|
|
<para><anchor id="ivrref"/></para>
|
|
|
|
<para>We have seen that <link linkend="varsubn">referencing
|
|
a variable</link>, <varname>$var</varname>, fetches its
|
|
<firstterm>value</firstterm>. <anchor id="evalindref"/>But,
|
|
what about the <emphasis>value of a value</emphasis>? What
|
|
about <varname>$$var</varname>?</para>
|
|
|
|
<para>The actual notation is
|
|
<replaceable>\$$var</replaceable>, usually preceded by
|
|
an <link linkend="evalref">eval</link> (and sometimes an
|
|
<link linkend="echoref">echo</link>). This is called an
|
|
<firstterm>indirect reference</firstterm>.</para>
|
|
|
|
|
|
<example id="indref">
|
|
<title>Indirect Variable References</title>
|
|
<programlisting>&indref;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="irrref"/></para>
|
|
|
|
<sidebar><para>Indirect referencing in Bash
|
|
is a multi-step process. First, take the name of a variable:
|
|
<varname>varname</varname>. Then, reference it:
|
|
<varname>$varname</varname>. Then, reference the reference:
|
|
<varname>$$varname</varname>. Then, <firstterm>escape</firstterm>
|
|
the first <token>$</token>: <varname>\$$varname</varname>.
|
|
Finally, force a reevaluation of the expression and assign it:
|
|
<command>eval newvar=\$$varname</command>.</para></sidebar>
|
|
|
|
|
|
<para>Of what practical use is indirect referencing of
|
|
variables? It gives Bash a little of the functionality
|
|
of <link linkend="pointerref">pointers</link>
|
|
in <firstterm>C</firstterm>, for instance, in <link
|
|
linkend="resistor">table lookup</link>. And, it also has some
|
|
other very interesting applications. . . .</para>
|
|
|
|
<para>Nils Radtke shows how to build <quote>dynamic</quote>
|
|
variable names and evaluate their contents. This can be useful
|
|
when <link linkend="sourceref">sourcing</link> configuration
|
|
files.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
|
|
# ---------------------------------------------
|
|
# This could be "sourced" from a separate file.
|
|
isdnMyProviderRemoteNet=172.16.0.100
|
|
isdnYourProviderRemoteNet=10.0.0.10
|
|
isdnOnlineService="MyProvider"
|
|
# ---------------------------------------------
|
|
|
|
|
|
remoteNet=$(eval "echo \$$(echo isdn${isdnOnlineService}RemoteNet)")
|
|
remoteNet=$(eval "echo \$$(echo isdnMyProviderRemoteNet)")
|
|
remoteNet=$(eval "echo \$isdnMyProviderRemoteNet")
|
|
remoteNet=$(eval "echo $isdnMyProviderRemoteNet")
|
|
|
|
echo "$remoteNet" # 172.16.0.100
|
|
|
|
# ================================================================
|
|
|
|
# And, it gets even better.
|
|
|
|
# Consider the following snippet given a variable named getSparc,
|
|
#+ but no such variable getIa64:
|
|
|
|
chkMirrorArchs () {
|
|
arch="$1";
|
|
if [ "$(eval "echo \${$(echo get$(echo -ne $arch |
|
|
sed 's/^\(.\).*/\1/g' | tr 'a-z' 'A-Z'; echo $arch |
|
|
sed 's/^.\(.*\)/\1/g')):-false}")" = true ]
|
|
then
|
|
return 0;
|
|
else
|
|
return 1;
|
|
fi;
|
|
}
|
|
|
|
getSparc="true"
|
|
unset getIa64
|
|
chkMirrorArchs sparc
|
|
echo $? # 0
|
|
# True
|
|
|
|
chkMirrorArchs Ia64
|
|
echo $? # 1
|
|
# False
|
|
|
|
# Notes:
|
|
# -----
|
|
# Even the to-be-substituted variable name part is built explicitly.
|
|
# The parameters to the chkMirrorArchs calls are all lower case.
|
|
# The variable name is composed of two parts: "get" and "Sparc" . . .</programlisting>
|
|
</para>
|
|
|
|
|
|
|
|
<example id="coltotaler2">
|
|
<title>Passing an indirect reference to <firstterm>awk</firstterm></title>
|
|
<programlisting>&coltotaler2;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>This method of indirect referencing is a bit tricky.
|
|
If the second order variable changes its value, then the first
|
|
order variable must be properly dereferenced (as in the above
|
|
example). <anchor id="ivr2"/>Fortunately, the
|
|
<replaceable>${!variable}</replaceable> notation introduced
|
|
with <link linkend="bash2ref">version 2</link> of Bash
|
|
(see <xref linkend="ex78"/> and <xref linkend="hashex2"/>) makes
|
|
indirect referencing more intuitive.</para></caution>
|
|
|
|
|
|
<sidebar>
|
|
<para>Bash does not support pointer arithmetic, and this severely
|
|
limits the usefulness of indirect referencing. In fact, indirect
|
|
referencing in a scripting language is, at best, something of
|
|
an afterthought.</para>
|
|
</sidebar>
|
|
|
|
</chapter> <!-- Indirect References to Variables -->
|
|
|
|
|
|
|
|
|
|
<chapter id="devproc">
|
|
<title><filename class="directory">/dev</filename> and <filename
|
|
class="directory">/proc</filename></title>
|
|
|
|
<para><anchor id="devprocref"/></para>
|
|
|
|
<para>A Linux or UNIX filesystem typically has the
|
|
<filename class="directory">/dev</filename> and
|
|
<filename class="directory">/proc</filename> special-purpose
|
|
directories.</para>
|
|
|
|
|
|
|
|
<sect1 id="devref1">
|
|
<title><filename class="directory">/dev</filename></title>
|
|
|
|
<para><anchor id="devfileref"/>The <filename
|
|
class="directory">/dev</filename> directory contains entries for
|
|
the <firstterm>physical devices</firstterm> that may or may not
|
|
be present in the hardware.
|
|
|
|
<footnote>
|
|
<para>The entries in <filename class="directory">/dev</filename>
|
|
provide mount points for physical and virtual devices. These
|
|
entries use very little drive space.</para>
|
|
<para>Some devices, such as <filename>/dev/null</filename>,
|
|
<filename>/dev/zero</filename>,
|
|
and <filename>/dev/urandom</filename> are virtual. They
|
|
are not actual physical devices and exist only in
|
|
software.</para>
|
|
</footnote>
|
|
|
|
Appropriately enough, these are called <firstterm>device
|
|
files</firstterm>.
|
|
As an example, the hard drive partitions containing
|
|
the mounted filesystem(s) have entries in <filename
|
|
class="directory">/dev</filename>, as <link
|
|
linkend="dfref">df</link> shows.</para>
|
|
|
|
<para><screen><prompt>bash$ </prompt><userinput>df</userinput>
|
|
<computeroutput>Filesystem 1k-blocks Used Available Use%
|
|
Mounted on
|
|
/dev/hda6 495876 222748 247527 48% /
|
|
/dev/hda1 50755 3887 44248 9% /boot
|
|
/dev/hda8 367013 13262 334803 4% /home
|
|
/dev/hda5 1714416 1123624 503704 70% /usr</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para><anchor id="loopbackref"/>Among other things, the <filename
|
|
class="directory">/dev</filename> directory
|
|
contains <firstterm>loopback</firstterm> devices, such as
|
|
<filename>/dev/loop0</filename>. A loopback device is a gimmick
|
|
that allows an ordinary file to be accessed as if it were a
|
|
block device.
|
|
|
|
<footnote><para><anchor id="blockdevref"/>A <firstterm>block
|
|
device</firstterm> reads and/or writes data in chunks,
|
|
or <firstterm>blocks</firstterm>, in contrast to a <anchor
|
|
id="chardevref"/><firstterm>character device</firstterm>,
|
|
which acesses data in <firstterm>character</firstterm>
|
|
units. Examples of block devices are hard drives, CDROM
|
|
drives, and flash drives. Examples of character devices are
|
|
keyboards, modems, sound cards.</para></footnote>
|
|
|
|
This permits mounting an entire filesystem within a
|
|
single large file. See <xref linkend="createfs"/> and <xref
|
|
linkend="isomountref"/>.</para>
|
|
|
|
<para>A few of the pseudo-devices in <filename
|
|
class="directory">/dev</filename>
|
|
have other specialized uses, such as <link
|
|
linkend="zerosref"><filename>/dev/null</filename></link>, <link
|
|
linkend="zerosref1"><filename>/dev/zero</filename></link>, <link
|
|
linkend="urandomref"><filename>/dev/urandom</filename></link>,
|
|
<filename>/dev/sda1</filename> (hard drive partition),
|
|
<filename>/dev/udp</filename> (<firstterm>User
|
|
Datagram Packet</firstterm> port), and <link
|
|
linkend="devtcp"><filename>/dev/tcp</filename></link>.</para>
|
|
|
|
<para>For instance:</para>
|
|
|
|
<para>To manually <link linkend="mountref">mount</link>
|
|
a USB flash drive, append the following line to
|
|
<link linkend="fstabref"><filename>/etc/fstab</filename></link>.
|
|
|
|
<footnote>
|
|
<para>Of course, the mount point
|
|
<filename>/mnt/flashdrive</filename> must exist. If not,
|
|
then, as <firstterm>root</firstterm>, <command>mkdir
|
|
/mnt/flashdrive</command>.</para>
|
|
<para>To actually mount the drive, use the following command:
|
|
<command>mount /mnt/flashdrive</command></para>
|
|
<para>Newer Linux distros automount flash drives in the
|
|
<filename class="directory">/media</filename>
|
|
directory without user intervention.</para>
|
|
</footnote>
|
|
|
|
<programlisting>/dev/sda1 /mnt/flashdrive auto noauto,user,noatime 0 0</programlisting>
|
|
|
|
(See also <xref linkend="usbinst"/>.)</para>
|
|
|
|
<para>Checking whether a disk is in the CD-burner
|
|
(soft-linked to <filename>/dev/hdc</filename>):
|
|
|
|
<programlisting>head -1 /dev/hdc
|
|
|
|
|
|
# head: cannot open '/dev/hdc' for reading: No medium found
|
|
# (No disc in the drive.)
|
|
|
|
# head: error reading '/dev/hdc': Input/output error
|
|
# (There is a disk in the drive, but it can't be read;
|
|
#+ possibly it's an unrecorded CDR blank.)
|
|
|
|
# Stream of characters and assorted gibberish
|
|
# (There is a pre-recorded disk in the drive,
|
|
#+ and this is raw output -- a stream of ASCII and binary data.)
|
|
# Here we see the wisdom of using 'head' to limit the output
|
|
#+ to manageable proportions, rather than 'cat' or something similar.
|
|
|
|
|
|
# Now, it's just a matter of checking/parsing the output and taking
|
|
#+ appropriate action.</programlisting></para>
|
|
|
|
|
|
<para><anchor id="socketref"/></para>
|
|
|
|
<para>When executing a command on a
|
|
<filename>/dev/tcp/$host/$port</filename> pseudo-device file, Bash
|
|
opens a TCP connection to the associated
|
|
<firstterm>socket</firstterm>.</para>
|
|
|
|
|
|
<sidebar><para>A <firstterm>socket</firstterm> is a
|
|
communications node associated with a specific I/O
|
|
port. (This is analogous to a <firstterm>hardware
|
|
socket</firstterm>, or <firstterm>receptacle</firstterm>,
|
|
for a connecting cable.) It permits data transfer between
|
|
hardware devices on the same machine, between machines
|
|
on the same network, between machines across different
|
|
networks, and, of course, between machines at different
|
|
locations on the Internet.</para></sidebar>
|
|
|
|
|
|
<para><anchor id="npref"/>The following examples assume an active Internet
|
|
connection.</para>
|
|
|
|
<para>Getting the time from <filename>nist.gov</filename>:</para>
|
|
<screen><prompt>bash$ </prompt><userinput>cat </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 this example.]</para>
|
|
|
|
<para>Generalizing the above into a script:</para>
|
|
<para><programlisting>#!/bin/bash
|
|
# This script must run with root permissions.
|
|
|
|
URL="time.nist.gov/13"
|
|
|
|
Time=$(cat </dev/tcp/"$URL")
|
|
UTC=$(echo "$Time" | awk '{print$3}') # Third field is UTC (GMT) time.
|
|
# Exercise: modify this for different time zones.
|
|
|
|
echo "UTC Time = "$UTC""</programlisting></para>
|
|
|
|
<para><anchor id="nw001"/>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>
|
|
|
|
<example id="musicscr">
|
|
<title>Playing music</title>
|
|
<programlisting>&musicscr;</programlisting>
|
|
</example>
|
|
|
|
|
|
</sect1> <!-- /dev -->
|
|
|
|
|
|
|
|
<sect1 id="procref1">
|
|
<title><filename class="directory">/proc</filename></title>
|
|
|
|
|
|
<para><anchor id="procref2"/></para>
|
|
<para>The <filename class="directory">/proc</filename> directory
|
|
is actually a pseudo-filesystem. The files in <filename
|
|
class="directory">/proc</filename> mirror currently running
|
|
system and kernel <link linkend="processref">processes</link>
|
|
and contain information and statistics about them.</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>cat /proc/devices</userinput>
|
|
<computeroutput>Character devices:
|
|
1 mem
|
|
2 pty
|
|
3 ttyp
|
|
4 ttyS
|
|
5 cua
|
|
7 vcs
|
|
10 misc
|
|
14 sound
|
|
29 fb
|
|
36 netlink
|
|
128 ptm
|
|
136 pts
|
|
162 raw
|
|
254 pcmcia
|
|
|
|
Block devices:
|
|
1 ramdisk
|
|
2 fd
|
|
3 ide0
|
|
9 md</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>cat /proc/interrupts</userinput>
|
|
<computeroutput> CPU0
|
|
0: 84505 XT-PIC timer
|
|
1: 3375 XT-PIC keyboard
|
|
2: 0 XT-PIC cascade
|
|
5: 1 XT-PIC soundblaster
|
|
8: 1 XT-PIC rtc
|
|
12: 4231 XT-PIC PS/2 Mouse
|
|
14: 109373 XT-PIC ide0
|
|
NMI: 0
|
|
ERR: 0</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>cat /proc/partitions</userinput>
|
|
<computeroutput>major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
|
|
|
|
3 0 3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030
|
|
3 1 52416 hda1 27 395 844 960 4 2 14 180 0 800 1140
|
|
3 2 1 hda2 0 0 0 0 0 0 0 0 0 0 0
|
|
3 4 165280 hda4 10 0 20 210 0 0 0 0 0 210 210
|
|
...</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>cat /proc/loadavg</userinput>
|
|
<computeroutput>0.13 0.42 0.27 2/44 1119</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>cat /proc/apm</userinput>
|
|
<computeroutput>1.16 1.2 0x03 0x01 0xff 0x80 -1% -1 ?</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>cat /proc/acpi/battery/BAT0/info</userinput>
|
|
<computeroutput>present: yes
|
|
design capacity: 43200 mWh
|
|
last full capacity: 36640 mWh
|
|
battery technology: rechargeable
|
|
design voltage: 10800 mV
|
|
design capacity warning: 1832 mWh
|
|
design capacity low: 200 mWh
|
|
capacity granularity 1: 1 mWh
|
|
capacity granularity 2: 1 mWh
|
|
model number: IBM-02K6897
|
|
serial number: 1133
|
|
battery type: LION
|
|
OEM info: Panasonic</computeroutput>
|
|
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>fgrep Mem /proc/meminfo</userinput>
|
|
<computeroutput>MemTotal: 515216 kB
|
|
MemFree: 266248 kB</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Shell scripts may extract data from certain of the files in
|
|
<filename class="directory">/proc</filename>.
|
|
|
|
<footnote><para>Certain system commands, such as
|
|
<link linkend="procinforef">procinfo</link>,
|
|
<link linkend="freeref">free</link>,
|
|
<link linkend="vmstatref">vmstat</link>,
|
|
<link linkend="lsdevref">lsdev</link>,
|
|
and <link linkend="uptimeref">uptime</link>
|
|
do this as well.</para></footnote></para>
|
|
|
|
<para><programlisting>FS=iso # ISO filesystem support in kernel?
|
|
|
|
grep $FS /proc/filesystems # iso9660</programlisting></para>
|
|
|
|
|
|
<para><programlisting>kernel_version=$( awk '{ print $3 }' /proc/version )</programlisting></para>
|
|
|
|
<para><programlisting>CPU=$( awk '/model name/ {print $5}' < /proc/cpuinfo )
|
|
|
|
if [ "$CPU" = "Pentium(R)" ]
|
|
then
|
|
run_some_commands
|
|
...
|
|
else
|
|
run_other_commands
|
|
...
|
|
fi
|
|
|
|
|
|
|
|
cpu_speed=$( fgrep "cpu MHz" /proc/cpuinfo | awk '{print $4}' )
|
|
# Current operating speed (in MHz) of the cpu on your machine.
|
|
# On a laptop this may vary, depending on use of battery
|
|
#+ or AC power.</programlisting></para>
|
|
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
# get-commandline.sh
|
|
# Get the command-line parameters of a process.
|
|
|
|
OPTION=cmdline
|
|
|
|
# Identify PID.
|
|
pid=$( echo $(pidof "$1") | awk '{ print $1 }' )
|
|
# Get only first ^^^^^^^^^^^^^^^^^^ of multiple instances.
|
|
|
|
echo
|
|
echo "Process ID of (first instance of) "$1" = $pid"
|
|
echo -n "Command-line arguments: "
|
|
cat /proc/"$pid"/"$OPTION" | xargs -0 echo
|
|
# Formats output: ^^^^^^^^^^^^^^^
|
|
# (Thanks, Han Holl, for the fixup!)
|
|
|
|
echo; echo
|
|
|
|
|
|
# For example:
|
|
# sh get-commandline.sh xterm</programlisting></para>
|
|
|
|
<para>+</para>
|
|
|
|
<para><programlisting>devfile="/proc/bus/usb/devices"
|
|
text="Spd"
|
|
USB1="Spd=12"
|
|
USB2="Spd=480"
|
|
|
|
|
|
bus_speed=$(fgrep -m 1 "$text" $devfile | awk '{print $9}')
|
|
# ^^^^ Stop after first match.
|
|
|
|
if [ "$bus_speed" = "$USB1" ]
|
|
then
|
|
echo "USB 1.1 port found."
|
|
# Do something appropriate for USB 1.1.
|
|
fi</programlisting></para>
|
|
|
|
|
|
<note>
|
|
<para>It is even possible to control certain peripherals with commands
|
|
sent to the <filename class="directory">/proc</filename> directory.
|
|
|
|
<screen>
|
|
<prompt>root# </prompt><command>echo on > /proc/acpi/ibm/light</command>
|
|
</screen>
|
|
|
|
This turns on the <emphasis>Thinklight</emphasis> in certain models
|
|
of IBM/Lenovo Thinkpads. (May not work on all Linux distros.)</para>
|
|
|
|
<para>Of course, caution is advised when writing to <filename
|
|
class="directory">/proc</filename>.</para>
|
|
|
|
</note>
|
|
|
|
|
|
<para><anchor id="procrunning"/></para>
|
|
<para>The <filename class="directory">/proc</filename> directory
|
|
contains subdirectories with unusual numerical
|
|
names. Every one of these names maps to the <link
|
|
linkend="ppidref">process ID</link> of a currently running
|
|
process. Within each of these subdirectories, there are
|
|
a number of files that hold useful information about the
|
|
corresponding process. The <filename>stat</filename> and
|
|
<filename>status</filename> files keep running statistics
|
|
on the process, the <filename>cmdline</filename> file holds
|
|
the command-line arguments the process was invoked with, and
|
|
the <filename>exe</filename> file is a symbolic link to the
|
|
complete path name of the invoking process. There are a few
|
|
more such files, but these seem to be the most interesting
|
|
from a scripting standpoint.</para>
|
|
|
|
<example id="pidid">
|
|
<title>Finding the process associated with a PID</title>
|
|
<programlisting>&pidid;</programlisting>
|
|
</example>
|
|
|
|
<example id="constat">
|
|
<title>On-line connect status</title>
|
|
<programlisting>&constat;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="procwarning"/></para>
|
|
<warning><para>In general, it is dangerous to
|
|
<emphasis>write</emphasis> to the files in <filename
|
|
class="directory">/proc</filename>, as this can corrupt the
|
|
filesystem or crash the machine.</para></warning>
|
|
|
|
</sect1> <!-- /proc -->
|
|
|
|
</chapter> <!-- /dev and /proc -->
|
|
|
|
<chapter id="networkprogramming">
|
|
<title>Network Programming</title>
|
|
|
|
<epigraph>
|
|
<para>The Net's a cross between an elephant and a white
|
|
elephant sale: it never forgets, and it's always crap.</para>
|
|
<para>--Nemo</para>
|
|
</epigraph>
|
|
|
|
<para>A Linux system has quite a number of tools for accessing,
|
|
manipulating, and troubleshooting network connections. We can
|
|
incorporate some of these tools into scripts -- scripts that
|
|
expand our knowledge of networking, useful scripts that can
|
|
facilitate the administration of a network.</para>
|
|
|
|
<para><anchor id="cgiscript"/>Here is a simple CGI
|
|
script that demonstrates connecting to a remote server.</para>
|
|
|
|
<example id="testcgi">
|
|
<title>Print the server environment</title>
|
|
<programlisting>&testcgi;</programlisting>
|
|
</example>
|
|
|
|
<para>For security purposes, it may be helpful to identify the IP
|
|
addresses a computer is accessing.</para>
|
|
|
|
<para><anchor id="iptables02"/></para>
|
|
|
|
<example id="ipaddresses">
|
|
<title>IP addresses</title>
|
|
<programlisting>&ipaddresses;</programlisting>
|
|
</example>
|
|
|
|
<para>More examples of network programming:
|
|
<orderedlist>
|
|
<listitem><para><link linkend="npref">Getting the time from
|
|
<firstterm>nist.gov</firstterm></link></para></listitem>
|
|
<listitem><para><link linkend="nw001">Downloading a
|
|
URL</link></para></listitem>
|
|
<listitem><para><link linkend="ipscript0">A GRE
|
|
tunnel</link></para></listitem>
|
|
<listitem><para><link linkend="ping0">Checking
|
|
if an Internet server is up</link></para></listitem>
|
|
<listitem><para><xref linkend="isspammer"/></para></listitem>
|
|
<listitem><para><xref linkend="isspammer2"/></para></listitem>
|
|
<listitem><para><xref linkend="whx"/></para></listitem>
|
|
<listitem><para><xref linkend="devtcp"/></para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<para>See also the <link linkend="networksys1">networking commands</link>
|
|
in the <link linkend="system">System and
|
|
Administrative Commands</link> chapter and the <link
|
|
linkend="communications">communications commands</link> in
|
|
the <link linkend="external">External Filters, Programs and
|
|
Commands</link> chapter.</para>
|
|
|
|
|
|
</chapter> <!-- Network Programing -->
|
|
|
|
|
|
<chapter id="zeros">
|
|
<title>Of Zeros and Nulls</title>
|
|
|
|
<epigraph>
|
|
<para>Faultily faultless, icily regular, splendidly null</para>
|
|
<para>Dead perfection; no more.</para>
|
|
<para>--Alfred Lord Tennyson</para>
|
|
</epigraph>
|
|
|
|
<para><anchor id="zerosref"/></para>
|
|
|
|
<variablelist id="zeronull">
|
|
<title><anchor id="zeronull1"/><filename>/dev/zero</filename>
|
|
... <filename>/dev/null</filename></title>
|
|
<varlistentry>
|
|
<term><anchor id="devnullref"/>Uses of
|
|
<filename>/dev/null</filename></term>
|
|
<listitem>
|
|
<para>Think of <filename>/dev/null</filename> as a <firstterm>black
|
|
hole</firstterm>. It is essentially the equivalent of
|
|
a write-only file. Everything written to it disappears.
|
|
Attempts to read or output from it result in nothing. All
|
|
the same, <filename>/dev/null</filename> can be quite
|
|
useful from both the command-line and in scripts.</para>
|
|
|
|
<para>Suppressing <filename>stdout</filename>.
|
|
<programlisting>cat $filename >/dev/null
|
|
# Contents of the file will not list to stdout.</programlisting>
|
|
</para>
|
|
|
|
<para>Suppressing <filename>stderr</filename>
|
|
(from <xref linkend="ex57"/>).
|
|
<programlisting>rm $badname 2>/dev/null
|
|
# So error messages [stderr] deep-sixed.</programlisting>
|
|
</para>
|
|
|
|
<para>Suppressing output from <emphasis>both</emphasis>
|
|
<filename>stdout</filename> and <filename>stderr</filename>.
|
|
<programlisting>cat $filename 2>/dev/null >/dev/null
|
|
# If "$filename" does not exist, there will be no error message output.
|
|
# If "$filename" does exist, the contents of the file will not list to stdout.
|
|
# Therefore, no output at all will result from the above line of code.
|
|
#
|
|
# This can be useful in situations where the return code from a command
|
|
#+ needs to be tested, but no output is desired.
|
|
#
|
|
# cat $filename &>/dev/null
|
|
# also works, as Baris Cicek points out.</programlisting>
|
|
</para>
|
|
|
|
<para>Deleting contents of a file, but preserving the file itself, with
|
|
all attendant permissions (from <xref linkend="ex1"/> and <xref linkend="ex2"/>):
|
|
<programlisting>cat /dev/null > /var/log/messages
|
|
# : > /var/log/messages has same effect, but does not spawn a new process.
|
|
|
|
cat /dev/null > /var/log/wtmp</programlisting>
|
|
</para>
|
|
|
|
<para>Automatically emptying the contents of a logfile
|
|
(especially good for dealing with those nasty
|
|
<quote>cookies</quote> sent by commercial Web sites):</para>
|
|
|
|
<example id="cookies">
|
|
<title>Hiding the cookie jar</title>
|
|
<programlisting># Obsolete Netscape browser.
|
|
# Same principle applies to newer browsers.
|
|
|
|
if [ -f ~/.netscape/cookies ] # Remove, if exists.
|
|
then
|
|
rm -f ~/.netscape/cookies
|
|
fi
|
|
|
|
ln -s /dev/null ~/.netscape/cookies
|
|
# All cookies now get sent to a black hole, rather than saved to disk.</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="zerosref1"/>Uses of <filename>/dev/zero</filename></term>
|
|
<listitem>
|
|
<para>Like <filename>/dev/null</filename>,
|
|
<filename>/dev/zero</filename> is a pseudo-device file, but
|
|
it actually produces a stream of nulls
|
|
(<emphasis>binary</emphasis> zeros, not the <link
|
|
linkend="asciidef">ASCII</link> kind). Output written
|
|
to <filename>/dev/zero</filename> disappears, and it is
|
|
fairly difficult to actually read the nulls emitted there,
|
|
though it can be done with <link linkend="odref">od</link>
|
|
or a hex editor. <anchor id="swapfileref"/>The chief use of
|
|
<filename>/dev/zero</filename> is creating an initialized
|
|
dummy file of predetermined length intended as a temporary
|
|
swap file.</para>
|
|
|
|
<example id="ex73">
|
|
<title>Setting up a swapfile using <filename>/dev/zero</filename></title>
|
|
<programlisting>&ex73;</programlisting>
|
|
</example>
|
|
|
|
<para>Another application of <filename>/dev/zero</filename>
|
|
is to <quote>zero out</quote> a file of a designated
|
|
size for a special purpose, such as mounting a filesystem
|
|
on a <link linkend="loopbackref">loopback device</link>
|
|
(see <xref linkend="createfs"/>) or <quote>securely</quote>
|
|
deleting a file (see <xref linkend="blotout"/>).</para>
|
|
|
|
<example id="ramdisk">
|
|
<title>Creating a ramdisk</title>
|
|
<programlisting>&ramdisk;</programlisting>
|
|
</example>
|
|
|
|
<para>In addition to all the above,
|
|
<filename>/dev/zero</filename> is needed by ELF
|
|
(<firstterm>Executable and Linking Format</firstterm>)
|
|
UNIX/Linux binaries.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</chapter> <!-- Zeros and Nulls -->
|
|
|
|
|
|
|
|
<chapter id="debugging">
|
|
<title>Debugging</title>
|
|
|
|
<epigraph>
|
|
<para>Debugging is twice as hard as writing the code in the first
|
|
place. Therefore, if you write the code as cleverly as possible,
|
|
you are, by definition, not smart enough to debug it.</para>
|
|
<para>--Brian Kernighan</para>
|
|
</epigraph>
|
|
|
|
<para>The Bash shell contains no built-in debugger, and only bare-bones
|
|
debugging-specific commands and constructs. Syntax errors or
|
|
outright typos in the script generate cryptic error messages that
|
|
are often of no help in debugging a non-functional script.</para>
|
|
|
|
<example id="ex74">
|
|
<title>A buggy script</title>
|
|
<programlisting>&ex74;</programlisting>
|
|
</example>
|
|
|
|
<para>Output from script:
|
|
<screen><computeroutput>./ex74.sh: [37: command not found</computeroutput></screen>
|
|
What's wrong with the above script? Hint: after the
|
|
<firstterm>if</firstterm>.</para>
|
|
|
|
<example id="missingkeyword">
|
|
<title>Missing <link linkend="keywordref">keyword</link></title>
|
|
<programlisting>&missingkeyword;</programlisting>
|
|
</example>
|
|
|
|
<para>Output from script:
|
|
<screen>
|
|
<computeroutput>missing-keyword.sh: line 10: syntax error: unexpected end of file</computeroutput>
|
|
</screen>
|
|
Note that the error message does <emphasis>not</emphasis> necessarily
|
|
reference the line in which the error occurs, but the line where the
|
|
Bash interpreter finally becomes aware of the error.
|
|
</para>
|
|
|
|
<para>Error messages may disregard comment lines in a script when
|
|
reporting the line number of a syntax error.</para>
|
|
|
|
<para>What if the script executes, but does not work as expected? This is the
|
|
all too familiar logic error.</para>
|
|
|
|
<example id="ex75">
|
|
<title><firstterm>test24</firstterm>: another buggy script</title>
|
|
<programlisting>&ex75;</programlisting>
|
|
</example>
|
|
|
|
<para>Try to find out what's wrong with <xref linkend="ex75"/>
|
|
by uncommenting the <userinput>echo "$badname"</userinput> line. Echo
|
|
statements are useful for seeing whether what you expect is
|
|
actually what you get.</para>
|
|
|
|
<para>In this particular case, <userinput>rm "$badname"</userinput>
|
|
will not give the desired results because
|
|
<varname>$badname</varname> should not be quoted. Placing it
|
|
in quotes ensures that <command>rm</command> has only one
|
|
argument (it will match only one filename). A partial fix
|
|
is to remove to quotes from <varname>$badname</varname> and
|
|
to reset <varname>$IFS</varname> to contain only a newline,
|
|
<userinput>IFS=$'\n'</userinput>. However, there are simpler
|
|
ways of going about it.
|
|
<programlisting># Correct methods of deleting filenames containing spaces.
|
|
rm *\ *
|
|
rm *" "*
|
|
rm *' '*
|
|
# Thank you. S.C.</programlisting>
|
|
|
|
</para>
|
|
|
|
<para>Summarizing the symptoms of a buggy script,
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>It bombs with a <quote><errorname>syntax error</errorname></quote> message, or</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>It runs, but does not work as expected
|
|
(<errorname>logic error</errorname>).</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>It runs, works as expected, but has nasty side effects
|
|
(<errorname>logic bomb</errorname>).</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<para><anchor id="debugtools"/></para>
|
|
<para>Tools for debugging non-working scripts include
|
|
<orderedlist>
|
|
<listitem>
|
|
|
|
<para>Inserting <link linkend="echoref">echo</link>
|
|
statements at critical points in the script to trace the
|
|
variables, and otherwise give a snapshot of what is going
|
|
on.</para>
|
|
|
|
<tip>
|
|
<para>Even better is an <command>echo</command> that echoes
|
|
only when <firstterm>debug</firstterm> is on.</para>
|
|
|
|
<para><programlisting>### debecho (debug-echo), by Stefano Falsetto ###
|
|
### Will echo passed parameters only if DEBUG is set to a value. ###
|
|
debecho () {
|
|
if [ ! -z "$DEBUG" ]; then
|
|
echo "$1" >&2
|
|
# ^^^ to stderr
|
|
fi
|
|
}
|
|
|
|
DEBUG=on
|
|
Whatever=whatnot
|
|
debecho $Whatever # whatnot
|
|
|
|
DEBUG=
|
|
Whatever=notwhat
|
|
debecho $Whatever # (Will not echo.)</programlisting></para>
|
|
|
|
</tip>
|
|
|
|
</listitem>
|
|
<listitem>
|
|
<para>Using the <link linkend="teeref">tee</link> filter
|
|
to check processes or data flows at critical points.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Setting option flags <option>-n -v -x</option></para>
|
|
|
|
<para><userinput>sh -n scriptname</userinput> checks for
|
|
syntax errors without actually running the script. This is
|
|
the equivalent of inserting <userinput>set -n</userinput> or
|
|
<userinput>set -o noexec</userinput> into the script. Note
|
|
that certain types of syntax errors can slip past this
|
|
check.</para>
|
|
|
|
<para><userinput>sh -v scriptname</userinput> echoes each
|
|
command before executing it. This is the equivalent of
|
|
inserting <userinput>set -v</userinput> or <userinput>set
|
|
-o verbose</userinput> in the script.</para>
|
|
|
|
<para>The <option>-n</option> and <option>-v</option>
|
|
flags work well together. <userinput>sh -nv
|
|
scriptname</userinput> gives a verbose syntax check.</para>
|
|
|
|
<para><userinput>sh -x scriptname</userinput> echoes the result each
|
|
command, but in an abbreviated manner. This is the equivalent of
|
|
inserting <userinput>set -x</userinput> or
|
|
<userinput>set -o xtrace</userinput> in the script.</para>
|
|
|
|
<para><anchor id="undvarerr"/></para>
|
|
<para>Inserting <userinput>set -u</userinput> or
|
|
<userinput>set -o nounset</userinput> in the script runs it, but
|
|
gives an <errorname>unbound variable</errorname> error message
|
|
and aborts the script.
|
|
<programlisting>set -u # Or set -o nounset
|
|
|
|
# Setting a variable to null will not trigger the error/abort.
|
|
# unset_var=
|
|
|
|
echo $unset_var # Unset (and undeclared) variable.
|
|
|
|
echo "Should not echo!"
|
|
|
|
# sh t2.sh
|
|
# t2.sh: line 6: unset_var: unbound variable</programlisting></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>Using an <quote>assert</quote> function to test a
|
|
variable or condition at critical points in a script. (This is
|
|
an idea borrowed from C.)</para>
|
|
|
|
<example id="assert">
|
|
<title>Testing a condition with an
|
|
<firstterm>assert</firstterm></title>
|
|
<programlisting>&assert;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>Using the <link linkend="linenoref">$LINENO</link>
|
|
variable and the <link linkend="callerref">caller</link>
|
|
builtin.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="debugtrap"/>Trapping at exit.</para>
|
|
|
|
<para>The <link linkend="exitref">exit</link> command in a script
|
|
triggers a signal <returnvalue>0</returnvalue>, terminating
|
|
the process, that is, the script itself.
|
|
|
|
<footnote><para>By convention, <replaceable>signal
|
|
0</replaceable> is assigned to <link
|
|
linkend="exitcommandref">exit</link>. </para></footnote>
|
|
|
|
It is often useful to trap the
|
|
<firstterm>exit</firstterm>, forcing a <quote>printout</quote>
|
|
of variables, for example. The <firstterm>trap</firstterm>
|
|
must be the first command in the script.</para>
|
|
|
|
</listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<variablelist id="trapref">
|
|
<title><anchor id="trapref1"/>Trapping signals</title>
|
|
|
|
<varlistentry>
|
|
<term><command>trap</command></term>
|
|
<listitem>
|
|
<para>Specifies an action on receipt of a
|
|
signal; also useful for debugging.</para>
|
|
|
|
<para><anchor id="signald"/></para>
|
|
<sidebar>
|
|
<para>A <firstterm>signal</firstterm> is a message
|
|
sent to a process, either by the kernel or another
|
|
process, telling it to take some specified action
|
|
(usually to terminate). For example, hitting a
|
|
<link linkend="ctlcref">Control-C</link>
|
|
sends a user interrupt, an INT signal, to a running
|
|
program.</para></sidebar>
|
|
|
|
<para><emphasis>A simple instance:</emphasis>
|
|
<programlisting>trap '' 2
|
|
# Ignore interrupt 2 (Control-C), with no action specified.
|
|
|
|
trap 'echo "Control-C disabled."' 2
|
|
# Message when Control-C pressed.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<example id="ex76">
|
|
<title>Trapping at exit</title>
|
|
<programlisting>&ex76;</programlisting>
|
|
</example>
|
|
|
|
<example id="online">
|
|
<title>Cleaning up after <keycap>Control-C</keycap></title>
|
|
<programlisting>&online;</programlisting>
|
|
</example>
|
|
|
|
<example id="progressbar2">
|
|
<title>A Simple Implementation of a Progress Bar</title>
|
|
<programlisting>&progressbar2;</programlisting>
|
|
</example>
|
|
|
|
<note>
|
|
<para>The <option>DEBUG</option> argument to
|
|
<command>trap</command> causes a specified action to execute
|
|
after every command in a script. This permits tracing variables,
|
|
for example.
|
|
|
|
<example id="vartrace">
|
|
<title>Tracing a variable</title>
|
|
<programlisting>&vartrace;</programlisting>
|
|
</example>
|
|
|
|
</para>
|
|
</note>
|
|
|
|
|
|
<para>Of course, the <command>trap</command> command has other uses
|
|
aside from debugging, such as disabling certain keystrokes within a
|
|
script (see <xref linkend="stopwatch"/>).</para>
|
|
|
|
<example id="multipleproc">
|
|
<title>Running multiple processes (on an SMP box)</title>
|
|
<programlisting>&multipleproc;</programlisting>
|
|
</example>
|
|
|
|
|
|
<note><para><userinput>trap '' SIGNAL</userinput> (two adjacent
|
|
apostrophes) disables SIGNAL for the remainder of the
|
|
script. <userinput>trap SIGNAL</userinput> restores
|
|
the functioning of SIGNAL once more. This is useful to
|
|
protect a critical portion of a script from an undesirable
|
|
interrupt.</para></note>
|
|
|
|
<para><programlisting>
|
|
trap '' 2 # Signal 2 is Control-C, now disabled.
|
|
command
|
|
command
|
|
command
|
|
trap 2 # Reenables Control-C
|
|
</programlisting></para>
|
|
|
|
<sidebar>
|
|
<para><link linkend="bash3ref">Version 3</link> of Bash adds the
|
|
following <link linkend="internalvariables1">internal
|
|
variables</link> for use by the debugger.
|
|
|
|
<orderedlist>
|
|
|
|
<listitem>
|
|
<para><varname>$BASH_ARGC</varname></para>
|
|
<para>Number of command-line arguments passed to script,
|
|
similar to <link
|
|
linkend="clacountref"><varname>$#</varname></link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><varname>$BASH_ARGV</varname></para>
|
|
<para>Final command-line parameter passed to script, equivalent
|
|
<link
|
|
linkend="lastargref"><varname>${!#}</varname></link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><varname>$BASH_COMMAND</varname></para>
|
|
<para>Command currently executing.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><varname>$BASH_EXECUTION_STRING</varname></para>
|
|
<para>The <firstterm>option string</firstterm> following the
|
|
<option>-c</option> <link linkend="clopts">option</link>
|
|
to Bash.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><varname>$BASH_LINENO</varname></para>
|
|
<para>In a <link linkend="functionref">function</link>,
|
|
indicates the line number of the function call.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><varname>$BASH_REMATCH</varname></para>
|
|
<para>Array variable associated with <command>=~</command>
|
|
<link linkend="regexmatchref">conditional regex
|
|
matching</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="bashsourceref"/></para>
|
|
<para><varname>$BASH_SOURCE</varname></para>
|
|
<para>This is the name of the script, usually the same as
|
|
<link linkend="arg0">$0</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link
|
|
linkend="bashsubshellref"><varname>$BASH_SUBSHELL</varname></link></para>
|
|
</listitem>
|
|
|
|
</orderedlist></para>
|
|
</sidebar>
|
|
|
|
</chapter> <!-- Debugging -->
|
|
|
|
|
|
|
|
<chapter id="options">
|
|
<title>Options</title>
|
|
|
|
<para><anchor id="optionsref"/></para>
|
|
|
|
<para>Options are settings that change shell and/or script
|
|
behavior.</para>
|
|
|
|
<para>The <link linkend="setref">set</link> command
|
|
enables options within a script. At the point in the script
|
|
where you want the options to take effect, use <command>set
|
|
-o option-name</command> or, in short form, <command>set
|
|
-option-abbrev</command>. These two forms are equivalent.</para>
|
|
|
|
<para><programlisting>
|
|
#!/bin/bash
|
|
|
|
set -o verbose
|
|
# Echoes all commands before executing.
|
|
</programlisting></para>
|
|
|
|
<para><programlisting>
|
|
#!/bin/bash
|
|
|
|
set -v
|
|
# Exact same effect as above.
|
|
</programlisting></para>
|
|
|
|
<note><para>To <firstterm>disable</firstterm> an option within a script,
|
|
use <command>set +o option-name</command> or <command>set
|
|
+option-abbrev</command>.</para></note>
|
|
|
|
<para><programlisting>
|
|
#!/bin/bash
|
|
|
|
set -o verbose
|
|
# Command echoing on.
|
|
command
|
|
...
|
|
command
|
|
|
|
set +o verbose
|
|
# Command echoing off.
|
|
command
|
|
# Not echoed.
|
|
|
|
|
|
set -v
|
|
# Command echoing on.
|
|
command
|
|
...
|
|
command
|
|
|
|
set +v
|
|
# Command echoing off.
|
|
command
|
|
|
|
exit 0
|
|
</programlisting></para>
|
|
|
|
|
|
<para>An alternate method of enabling options in a script is
|
|
to specify them immediately following the
|
|
<replaceable>#!</replaceable> script header.</para>
|
|
|
|
<para><programlisting>
|
|
#!/bin/bash -x
|
|
#
|
|
# Body of script follows.
|
|
</programlisting></para>
|
|
|
|
|
|
<para><anchor id="invocationoptionsref"/></para>
|
|
<para>It is also possible to enable script options from the command
|
|
line. Some options that will not work with
|
|
<command>set</command> are available this way. Among these
|
|
are <replaceable>-i</replaceable>, force script to run
|
|
interactive.</para>
|
|
|
|
<para><userinput>bash -v script-name</userinput></para>
|
|
|
|
<para><userinput>bash -o verbose script-name</userinput></para>
|
|
|
|
|
|
<para>The following is a listing of some useful options. They may be
|
|
specified in either abbreviated form (preceded by a single dash)
|
|
or by complete name (preceded by a <emphasis>double</emphasis>
|
|
dash or by <option>-o</option>).</para>
|
|
|
|
<para><anchor id="optionstable"/></para>
|
|
|
|
<table>
|
|
<title>Bash options</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Abbreviation</entry>
|
|
<entry>Name</entry>
|
|
<entry>Effect</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>-B</option></entry>
|
|
<entry>brace expansion</entry>
|
|
<entry><emphasis>Enable</emphasis>
|
|
<link linkend="braceexpref">brace
|
|
expansion</link> (default setting =
|
|
<emphasis>on</emphasis>)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>+B</option></entry>
|
|
<entry>brace expansion</entry>
|
|
<entry><emphasis>Disable</emphasis>
|
|
brace expansion</entry>
|
|
</row>
|
|
<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>checkjobs</option></entry>
|
|
<entry></entry>
|
|
<entry>Informs user of any open <link
|
|
linkend="jobsref">jobs</link> upon shell exit.
|
|
Introduced in <link linkend="bash4ref">version 4</link>
|
|
of Bash, and still <quote>experimental.</quote>
|
|
<emphasis>Usage:</emphasis> shopt -s checkjobs
|
|
(<emphasis>Caution:</emphasis> may hang!)</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>globstar</option></entry>
|
|
<entry><link
|
|
linkend="globstarref"><firstterm>globbing</firstterm>
|
|
star-match</link></entry>
|
|
<entry>Enables the <token>**</token> <link
|
|
linkend="globbingref">globbing</link> operator
|
|
(<link linkend="bash4ref">version 4+</link> of Bash).
|
|
<emphasis>Usage:</emphasis> shopt -s globstar</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-i</option></entry>
|
|
<entry>interactive</entry>
|
|
<entry>Script runs in <firstterm>interactive</firstterm> mode</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-n</option></entry>
|
|
<entry>noexec</entry>
|
|
<entry>Read commands in script, but do not execute them (syntax check)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-o Option-Name</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>Invoke the <firstterm>Option-Name</firstterm>
|
|
option</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-o posix</option></entry>
|
|
<entry>POSIX</entry>
|
|
<entry>Change the behavior of Bash, or invoked script, to
|
|
conform to <link linkend="posix2ref">POSIX</link>
|
|
standard.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-o pipefail</option></entry>
|
|
<entry>pipe failure</entry>
|
|
<entry>Causes a pipeline to return the <link
|
|
linkend="exitstatusref">exit status</link> of
|
|
the last command in the pipe that returned a non-zero
|
|
return value.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-p</option></entry>
|
|
<entry>privileged</entry>
|
|
<entry>Script runs as <quote>suid</quote> (caution!)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-r</option></entry>
|
|
<entry>restricted</entry>
|
|
<entry>Script runs in <firstterm>restricted</firstterm>
|
|
mode (see <xref linkend="restricted-sh"/>).</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-s</option></entry>
|
|
<entry>stdin</entry>
|
|
<entry>Read commands from <filename>stdin</filename></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-t</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>Exit after first command</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-u</option></entry>
|
|
<entry>nounset</entry>
|
|
<entry>Attempt to use undefined variable
|
|
outputs error message, and forces an exit</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-v</option></entry>
|
|
<entry>verbose</entry>
|
|
<entry>Print each command to <filename>stdout</filename> before executing it</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-x</option></entry>
|
|
<entry>xtrace</entry>
|
|
<entry>Similar to <option>-v</option>, but expands commands</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>End of options flag. All other arguments
|
|
are <link linkend="posparamref">positional
|
|
parameters</link>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>--</option></entry>
|
|
<entry>(none)</entry>
|
|
<entry>Unset positional parameters.
|
|
If arguments given (<parameter>-- arg1 arg2</parameter>),
|
|
positional parameters set to arguments.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</chapter> <!-- Options -->
|
|
|
|
|
|
|
|
<chapter id="gotchas">
|
|
<title>Gotchas</title>
|
|
|
|
<epigraph>
|
|
<para>Turandot: <foreignphrase>Gli enigmi sono tre, la morte
|
|
una!</foreignphrase></para>
|
|
<para>Caleph: <foreignphrase>No, no! Gli enigmi sono tre, una la
|
|
vita!</foreignphrase></para>
|
|
<para>--Puccini</para>
|
|
</epigraph>
|
|
|
|
<para><anchor id="bash3gotcha"/></para>
|
|
|
|
<para>Here are some (non-recommended!) scripting practices that
|
|
will bring excitement into an otherwise dull life.</para>
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para><anchor id="inappvn"/></para>
|
|
|
|
<para>Assigning reserved words or characters to variable names.</para>
|
|
|
|
<para>
|
|
<programlisting>case=value0 # Causes problems.
|
|
23skidoo=value1 # Also problems.
|
|
# Variable names starting with a digit are reserved by the shell.
|
|
# Try _23skidoo=value1. Starting variables with an underscore is okay.
|
|
|
|
# However . . . using just an underscore will not work.
|
|
_=25
|
|
echo $_ # $_ is a special variable set to last arg of last command.
|
|
# But . . . _ is a valid function name!
|
|
|
|
xyz((!*=value2 # Causes severe problems.
|
|
# As of version 3 of Bash, periods are not allowed within variable names.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Using a hyphen or other reserved characters in a variable name (or
|
|
function name).</para>
|
|
<para>
|
|
<programlisting>var-1=23
|
|
# Use 'var_1' instead.
|
|
|
|
function-whatever () # Error
|
|
# Use 'function_whatever ()' instead.
|
|
|
|
|
|
# As of version 3 of Bash, periods are not allowed within function names.
|
|
function.whatever () # Error
|
|
# Use 'functionWhatever ()' instead.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Using the same name for a variable and a function. This can make a
|
|
script difficult to understand.</para>
|
|
<para>
|
|
<programlisting>do_something ()
|
|
{
|
|
echo "This function does something with \"$1\"."
|
|
}
|
|
|
|
do_something=do_something
|
|
|
|
do_something do_something
|
|
|
|
# All this is legal, but highly confusing.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="wsbad"/>Using <link
|
|
linkend="whitespaceref">whitespace</link> inappropriately.
|
|
In contrast to other programming languages, Bash can be quite
|
|
finicky about whitespace.</para>
|
|
|
|
<para>
|
|
<programlisting>var1 = 23 # 'var1=23' is correct.
|
|
# On line above, Bash attempts to execute command "var1"
|
|
# with the arguments "=" and "23".
|
|
|
|
let c = $a - $b # Instead: let c=$a-$b or let "c = $a - $b"
|
|
|
|
if [ $a -le 5] # if [ $a -le 5 ] is correct.
|
|
# ^^ if [ "$a" -le 5 ] is even better.
|
|
# [[ $a -le 5 ]] also works.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="omitsemicolon"/></para>
|
|
<para>Not terminating with a <link
|
|
linkend="semicolonref">semicolon</link> the final command
|
|
in a <link linkend="codeblockref">code block within curly
|
|
brackets</link>.</para>
|
|
<para>
|
|
<programlisting>{ ls -l; df; echo "Done." }
|
|
# bash: syntax error: unexpected end of file
|
|
|
|
{ ls -l; df; echo "Done."; }
|
|
# ^ ### Final command needs semicolon.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="uninitvar"/></para>
|
|
<para>
|
|
Assuming uninitialized variables (variables before a value is
|
|
assigned to them) are <quote>zeroed out</quote>. An
|
|
uninitialized variable has a value of <firstterm>null</firstterm>,
|
|
<emphasis>not</emphasis> zero.</para>
|
|
|
|
<para><anchor id="bash4.2-uninitialized"/></para>
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
echo "uninitialized_var = $uninitialized_var"
|
|
# uninitialized_var =
|
|
|
|
# However . . .
|
|
# if $BASH_VERSION ≥ 4.2; then
|
|
|
|
if [[ ! -v uninitialized_var ]]
|
|
then
|
|
uninitialized_var=0 # Initialize it to zero!
|
|
fi
|
|
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="eqdif"/></para>
|
|
<para>Mixing up <firstterm>=</firstterm> and
|
|
<firstterm>-eq</firstterm> in a test. Remember,
|
|
<firstterm>=</firstterm> is for comparing literal variables
|
|
and <firstterm>-eq</firstterm> for integers.</para>
|
|
|
|
<para>
|
|
<programlisting>if [ "$a" = 273 ] # Is $a an integer or string?
|
|
if [ "$a" -eq 273 ] # If $a is an integer.
|
|
|
|
# Sometimes you can interchange -eq and = without adverse consequences.
|
|
# However . . .
|
|
|
|
|
|
a=273.0 # Not an integer.
|
|
|
|
if [ "$a" = 273 ]
|
|
then
|
|
echo "Comparison works."
|
|
else
|
|
echo "Comparison does not work."
|
|
fi # Comparison does not work.
|
|
|
|
# Same with a=" 273" and a="0273".
|
|
|
|
|
|
# Likewise, problems trying to use "-eq" with non-integer values.
|
|
|
|
if [ "$a" -eq 273.0 ]
|
|
then
|
|
echo "a = $a"
|
|
fi # Aborts with an error message.
|
|
# test.sh: [: 273.0: integer expression expected</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="numstrcompne"/></para>
|
|
<para>Misusing <link linkend="scomparison1">string comparison</link>
|
|
operators.</para>
|
|
|
|
<example id="badop">
|
|
<title>Numerical and string comparison are not equivalent</title>
|
|
<programlisting>&badop;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="letbad"/></para>
|
|
<para>Attempting to use <link linkend="letref">let</link>
|
|
to set string variables.</para>
|
|
<para><programlisting>let "a = hello, you"
|
|
echo "$a" # 0</programlisting></para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="failquote"/></para>
|
|
<para>Sometimes variables within <quote>test</quote> brackets
|
|
([ ]) need to be quoted (double quotes). Failure to do so may
|
|
cause unexpected behavior. See <xref linkend="strtest"/>, <xref
|
|
linkend="redir2"/>, and <xref linkend="arglist"/>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="failnotquote"/></para>
|
|
<para>Quoting a variable containing whitespace <link
|
|
linkend="wsquo">prevents splitting</link>. Sometimes
|
|
this produces <link linkend="varsplitting">unintended
|
|
consequences</link>.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="execperm"/></para>
|
|
<para>Commands issued from a script may fail to execute because
|
|
the script owner lacks execute permission for them. If a user
|
|
cannot invoke a command from the command-line, then putting it
|
|
into a script will likewise fail. Try changing the attributes of
|
|
the command in question, perhaps even setting the suid bit
|
|
(as <firstterm>root</firstterm>, of course).</para>
|
|
</listitem>
|
|
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="dashnredr"/></para>
|
|
<para>Attempting to use <command>-</command> as a redirection
|
|
operator (which it is not) will usually result in an unpleasant
|
|
surprise.</para>
|
|
<para>
|
|
<programlisting>command1 2> - | command2
|
|
# Trying to redirect error output of command1 into a pipe . . .
|
|
# . . . will not work.
|
|
|
|
command1 2>& - | command2 # Also futile.
|
|
|
|
Thanks, S.C.</programlisting></para>
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="lateverf"/></para>
|
|
<para>Using Bash <link linkend="bash2ref">version 2+</link>
|
|
functionality may cause a bailout with error messages. Older
|
|
Linux machines may have version 1.XX of Bash as the default
|
|
installation.</para>
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
minimum_version=2
|
|
# Since Chet Ramey is constantly adding features to Bash,
|
|
# you may set $minimum_version to 2.XX, 3.XX, or whatever is appropriate.
|
|
E_BAD_VERSION=80
|
|
|
|
if [ "$BASH_VERSION" \< "$minimum_version" ]
|
|
then
|
|
echo "This script works only with Bash, version $minimum or greater."
|
|
echo "Upgrade strongly recommended."
|
|
exit $E_BAD_VERSION
|
|
fi
|
|
|
|
...</programlisting></para>
|
|
</listitem>
|
|
|
|
|
|
|
|
<listitem>
|
|
<para>Using Bash-specific functionality in a <link
|
|
linkend="bashdef">Bourne shell</link> script
|
|
(<userinput>#!/bin/sh</userinput>) on a non-Linux machine
|
|
<link linkend="binsh">may cause unexpected behavior</link>.
|
|
A Linux system usually aliases <command>sh</command> to
|
|
<command>bash</command>, but this does not necessarily hold true
|
|
for a generic UNIX machine.</para> </listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="undocf"/></para>
|
|
<para>Using undocumented features in Bash turns out to be a
|
|
dangerous practice. In previous releases of this
|
|
book there were several scripts that depended on the
|
|
<quote>feature</quote> that, although the maximum value
|
|
of an <link linkend="exitstatusref">exit</link> or <link
|
|
linkend="returnref">return</link> value was 255, that limit
|
|
did not apply to <emphasis>negative</emphasis> integers.
|
|
Unfortunately, in version 2.05b and later, that loophole
|
|
disappeared. See <xref linkend="returntest"/>.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="gotchaexitvalanamalies"/></para>
|
|
<para>In certain contexts, a misleading <link
|
|
linkend="exitstatusref">exit status</link>
|
|
may be returned. This may occur when <link
|
|
linkend="exitvalanomaly01">setting a local variable within a
|
|
function</link> or when <link linkend="exitvalanomaly02">assigning
|
|
an arithmetic value to a variable</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="arxs1"/>The <link linkend="arxs">exit
|
|
status of an arithmetic expression</link> is
|
|
<emphasis>not</emphasis> equivalent to an <firstterm>error
|
|
code</firstterm>.</para>
|
|
<para><programlisting>var=1 && ((--var)) && echo $var
|
|
# ^^^^^^^^^ Here the and-list terminates with exit status 1.
|
|
# $var doesn't echo!
|
|
echo $? # 1</programlisting></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="dosnewlines"/></para>
|
|
<para>
|
|
A script with DOS-type newlines (<replaceable>\r\n</replaceable>)
|
|
will fail to execute, since <userinput>#!/bin/bash\r\n</userinput>
|
|
is <emphasis>not</emphasis> recognized, <emphasis>not</emphasis>
|
|
the same as the expected <userinput>#!/bin/bash\n</userinput>. The
|
|
fix is to convert the script to UNIX-style newlines.</para>
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
echo "Here"
|
|
|
|
unix2dos $0 # Script changes itself to DOS format.
|
|
chmod 755 $0 # Change back to execute permission.
|
|
# The 'unix2dos' command removes execute permission.
|
|
|
|
./$0 # Script tries to run itself again.
|
|
# But it won't work as a DOS file.
|
|
|
|
echo "There"
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="binsh"/></para>
|
|
<para>A shell script headed by <userinput>#!/bin/sh</userinput>
|
|
will not run in full Bash-compatibility mode. Some Bash-specific
|
|
functions might be disabled. Scripts that need complete
|
|
access to all the Bash-specific extensions should start with
|
|
<userinput>#!/bin/bash</userinput>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><link linkend="indentedls">Putting whitespace in front of
|
|
the terminating limit string</link> of a <link
|
|
linkend="heredocref">here document</link> will cause unexpected
|
|
behavior in a script.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="rvtcaution2"/>Putting more than one
|
|
<firstterm>echo</firstterm> statement in a function <link
|
|
linkend="rvt">whose output is captured</link>.
|
|
<programlisting>add2 ()
|
|
{
|
|
echo "Whatever ... " # Delete this line!
|
|
let "retval = $1 + $2"
|
|
echo $retval
|
|
}
|
|
|
|
num1=12
|
|
num2=43
|
|
echo "Sum of $num1 and $num2 = $(add2 $num1 $num2)"
|
|
|
|
# Sum of 12 and 43 = Whatever ...
|
|
# 55
|
|
|
|
# The "echoes" concatenate.</programlisting>
|
|
This <link
|
|
linkend="rvtcaution">will not work</link>.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="parchildprobref"/></para>
|
|
|
|
<para>A script may not <command>export</command> variables back
|
|
to its <link linkend="forkref">parent process</link>, the shell,
|
|
or to the environment. Just as we learned in biology, a child
|
|
process can inherit from a parent, but not vice versa.</para>
|
|
<para>
|
|
<programlisting>WHATEVER=/home/bozo
|
|
export WHATEVER
|
|
exit 0</programlisting>
|
|
<screen><prompt>bash$ </prompt><command>echo $WHATEVER</command>
|
|
<computeroutput>
|
|
|
|
</computeroutput>
|
|
<prompt>bash$ </prompt></screen>
|
|
</para>
|
|
<para>
|
|
Sure enough, back at the command prompt, $WHATEVER remains unset.
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="varsubsh"/></para>
|
|
<para>Setting and manipulating variables in a <link
|
|
linkend="subshellsref">subshell</link>, then attempting
|
|
to use those same variables outside the scope of the subshell will
|
|
result an unpleasant surprise.</para>
|
|
|
|
<example id="subpit">
|
|
<title>Subshell Pitfalls</title>
|
|
<programlisting>&subpit;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="badread0"/></para>
|
|
<para><link linkend="piperef">Piping</link>
|
|
<command>echo</command> output to a <link
|
|
linkend="readref">read</link> may produce unexpected
|
|
results. In this scenario, the <command>read</command>
|
|
acts as if it were running in a subshell. Instead, use
|
|
the <link linkend="setref">set</link> command (as in <xref
|
|
linkend="setpos"/>).</para>
|
|
|
|
<example id="badread">
|
|
<title>Piping the output of <firstterm>echo</firstterm> to a
|
|
<firstterm>read</firstterm></title>
|
|
<programlisting>&badread;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="pipeloop"/></para>
|
|
<para>In fact, as Anthony Richardson points out, piping to
|
|
<emphasis>any</emphasis> loop can cause a similar problem.</para>
|
|
|
|
<para>
|
|
<programlisting># Loop piping troubles.
|
|
# This example by Anthony Richardson,
|
|
#+ with addendum by Wilbert Berendsen.
|
|
|
|
|
|
foundone=false
|
|
find $HOME -type f -atime +30 -size 100k |
|
|
while true
|
|
do
|
|
read f
|
|
echo "$f is over 100KB and has not been accessed in over 30 days"
|
|
echo "Consider moving the file to archives."
|
|
foundone=true
|
|
# ------------------------------------
|
|
echo "Subshell level = $BASH_SUBSHELL"
|
|
# Subshell level = 1
|
|
# Yes, we're inside a subshell.
|
|
# ------------------------------------
|
|
done
|
|
|
|
# foundone will always be false here since it is
|
|
#+ set to true inside a subshell
|
|
if [ $foundone = false ]
|
|
then
|
|
echo "No files need archiving."
|
|
fi
|
|
|
|
# =====================Now, here is the correct way:=================
|
|
|
|
foundone=false
|
|
for f in $(find $HOME -type f -atime +30 -size 100k) # No pipe here.
|
|
do
|
|
echo "$f is over 100KB and has not been accessed in over 30 days"
|
|
echo "Consider moving the file to archives."
|
|
foundone=true
|
|
done
|
|
|
|
if [ $foundone = false ]
|
|
then
|
|
echo "No files need archiving."
|
|
fi
|
|
|
|
# ==================And here is another alternative==================
|
|
|
|
# Places the part of the script that reads the variables
|
|
#+ within a code block, so they share the same subshell.
|
|
# Thank you, W.B.
|
|
|
|
find $HOME -type f -atime +30 -size 100k | {
|
|
foundone=false
|
|
while read f
|
|
do
|
|
echo "$f is over 100KB and has not been accessed in over 30 days"
|
|
echo "Consider moving the file to archives."
|
|
foundone=true
|
|
done
|
|
|
|
if ! $foundone
|
|
then
|
|
echo "No files need archiving."
|
|
fi
|
|
}</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="ptailgrep"/></para>
|
|
<para>
|
|
A lookalike 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.
|
|
# As Samuli Kaipiainen points out, this results from grep
|
|
#+ buffering its output.
|
|
# The fix is to add the "--line-buffered" parameter to grep.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="suidscr"/></para>
|
|
<para>Using <quote>suid</quote> commands within scripts is risky,
|
|
as it may compromise system security.
|
|
<footnote><para>Setting the <link linkend="suidref">suid</link>
|
|
permission on the script itself has no effect in Linux
|
|
and most other UNIX flavors.</para></footnote>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="cgiref"/></para>
|
|
<para>Using shell scripts for CGI programming may be problematic. Shell
|
|
script variables are not <quote>typesafe,</quote> and this can cause
|
|
undesirable behavior as far as CGI is concerned. Moreover, it is
|
|
difficult to <quote>cracker-proof</quote> shell scripts.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para>Bash does not handle the <link linkend="doubleslashref">double slash
|
|
(<token>//</token>) string</link> correctly.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="gnuref"/></para>
|
|
<para>Bash scripts written for Linux or BSD systems may need
|
|
fixups to run on a commercial UNIX machine. Such
|
|
scripts often employ the GNU set of commands and filters,
|
|
which have greater functionality than their generic UNIX
|
|
counterparts. This is particularly true of such text processing
|
|
utilites as <link linkend="trref">tr</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="updatebreaks"/></para>
|
|
<para>Sadly, updates to Bash itself have broken older scripts
|
|
that <link linkend="paragraphspace">used to work perfectly
|
|
fine</link>. Let us recall <link linkend="undocf">how
|
|
risky it is to use undocumented Bash features</link>.</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<epigraph>
|
|
<para>Danger is near thee --</para>
|
|
<para>Beware, beware, beware, beware.</para>
|
|
<para>Many brave hearts are asleep in the deep.</para>
|
|
<para>So beware --</para>
|
|
<para>Beware.</para>
|
|
<para>--A.J. Lamb and H.W. Petrie</para>
|
|
</epigraph>
|
|
|
|
</chapter> <!-- Gotchas -->
|
|
|
|
|
|
|
|
<chapter id="scrstyle">
|
|
<title>Scripting With Style</title>
|
|
|
|
<para>Get into the habit of writing shell scripts in a structured and
|
|
systematic manner. Even on-the-fly and <quote>written on the
|
|
back of an envelope</quote> scripts will benefit if you take a
|
|
few minutes to plan and organize your thoughts before sitting
|
|
down and coding.</para>
|
|
|
|
<para>Herewith are a few stylistic guidelines. This is not
|
|
(necessarily) intended as an <emphasis>Official Shell Scripting
|
|
Stylesheet</emphasis>.</para>
|
|
|
|
|
|
|
|
<sect1 id="unofficialst">
|
|
<title>Unofficial Shell Scripting Stylesheet</title>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>Comment your code. This makes it easier for others to
|
|
understand (and appreciate), and easier for you to maintain.
|
|
<programlisting>PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}"
|
|
# It made perfect sense when you wrote it last year,
|
|
#+ but now it's a complete mystery.
|
|
# (From Antek Sawicki's "pw.sh" script.)</programlisting>
|
|
</para>
|
|
|
|
<para>Add descriptive headers to your scripts and functions.
|
|
<programlisting>#!/bin/bash
|
|
|
|
#************************************************#
|
|
# xyz.sh #
|
|
# written by Bozo Bozeman #
|
|
# July 05, 2001 #
|
|
# #
|
|
# Clean up project files. #
|
|
#************************************************#
|
|
|
|
E_BADDIR=85 # No such directory.
|
|
projectdir=/home/bozo/projects # Directory to clean up.
|
|
|
|
# --------------------------------------------------------- #
|
|
# cleanup_pfiles () #
|
|
# Removes all files in designated directory. #
|
|
# Parameter: $target_directory #
|
|
# Returns: 0 on success, $E_BADDIR if something went wrong. #
|
|
# --------------------------------------------------------- #
|
|
cleanup_pfiles ()
|
|
{
|
|
if [ ! -d "$1" ] # Test if target directory exists.
|
|
then
|
|
echo "$1 is not a directory."
|
|
return $E_BADDIR
|
|
fi
|
|
|
|
rm -f "$1"/*
|
|
return 0 # Success.
|
|
}
|
|
|
|
cleanup_pfiles $projectdir
|
|
|
|
exit $?</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para>Avoid using <quote>magic numbers,</quote>
|
|
|
|
<footnote><para>In this context, <quote>magic
|
|
numbers</quote> have an entirely different meaning than
|
|
the <link linkend="magnumref">magic numbers</link> used
|
|
to designate file types.</para></footnote>
|
|
|
|
that is, <quote>hard-wired</quote> literal constants. Use
|
|
meaningful variable names instead. This makes the script
|
|
easier to understand and permits making changes and updates
|
|
without breaking the application.
|
|
|
|
<programlisting>if [ -f /var/log/messages ]
|
|
then
|
|
...
|
|
fi
|
|
# A year later, you decide to change the script to check /var/log/syslog.
|
|
# It is now necessary to manually change the script, instance by instance,
|
|
#+ and hope nothing breaks.
|
|
|
|
# A better way:
|
|
LOGFILE=/var/log/messages # Only line that needs to be changed.
|
|
if [ -f "$LOGFILE" ]
|
|
then
|
|
...
|
|
fi</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para>Choose descriptive names for variables and functions.
|
|
<programlisting>fl=`ls -al $dirname` # Cryptic.
|
|
file_listing=`ls -al $dirname` # Better.
|
|
|
|
|
|
MAXVAL=10 # All caps used for a script constant.
|
|
while [ "$index" -le "$MAXVAL" ]
|
|
...
|
|
|
|
|
|
E_NOTFOUND=95 # Uppercase for an errorcode,
|
|
#+ and name prefixed with E_.
|
|
if [ ! -e "$filename" ]
|
|
then
|
|
echo "File $filename not found."
|
|
exit $E_NOTFOUND
|
|
fi
|
|
|
|
|
|
MAIL_DIRECTORY=/var/spool/mail/bozo # Uppercase for an environmental
|
|
export MAIL_DIRECTORY #+ variable.
|
|
|
|
|
|
GetAnswer () # Mixed case works well for a
|
|
{ #+ function name, especially
|
|
prompt=$1 #+ when it improves legibility.
|
|
echo -n $prompt
|
|
read answer
|
|
return $answer
|
|
}
|
|
|
|
GetAnswer "What is your favorite number? "
|
|
favorite_number=$?
|
|
echo $favorite_number
|
|
|
|
|
|
_uservariable=23 # Permissible, but not recommended.
|
|
# It's better for user-defined variables not to start with an underscore.
|
|
# Leave that for system variables.</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para>Use <link linkend="exitcommandref">exit codes</link>
|
|
in a systematic and meaningful way.
|
|
|
|
<programlisting>E_WRONG_ARGS=95
|
|
...
|
|
...
|
|
exit $E_WRONG_ARGS</programlisting>
|
|
See also <xref linkend="exitcodes"/>.</para>
|
|
|
|
|
|
<para><emphasis>Ender</emphasis> suggests using the <link
|
|
linkend="sysexitsref">exit codes
|
|
in <filename>/usr/include/sysexits.h</filename></link> in shell
|
|
scripts, though these are primarily intended for C and C++
|
|
programming.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
|
<para>Use standardized parameter flags for script invocation.
|
|
<emphasis>Ender</emphasis> proposes the following set
|
|
of flags.</para>
|
|
|
|
<para>
|
|
<programlisting>-a All: Return all information (including hidden file info).
|
|
-b Brief: Short version, usually for other scripts.
|
|
-c Copy, concatenate, etc.
|
|
-d Daily: Use information from the whole day, and not merely
|
|
information for a specific instance/user.
|
|
-e Extended/Elaborate: (often does not include hidden file info).
|
|
-h Help: Verbose usage w/descs, aux info, discussion, help.
|
|
See also -V.
|
|
-l Log output of script.
|
|
-m Manual: Launch man-page for base command.
|
|
-n Numbers: Numerical data only.
|
|
-r Recursive: All files in a directory (and/or all sub-dirs).
|
|
-s Setup & File Maintenance: Config files for this script.
|
|
-u Usage: List of invocation flags for the script.
|
|
-v Verbose: Human readable output, more or less formatted.
|
|
-V Version / License / Copy(right|left) / Contribs (email too).</programlisting>
|
|
</para>
|
|
|
|
<para>See also <xref linkend="standard-options"/>.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para>Break complex scripts into simpler modules. Use functions
|
|
where appropriate. See <xref linkend="cards"/>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Don't use a complex construct where a simpler one will do.
|
|
|
|
<programlisting>COMMAND
|
|
if [ $? -eq 0 ]
|
|
...
|
|
# Redundant and non-intuitive.
|
|
|
|
if COMMAND
|
|
...
|
|
# More concise (if perhaps not quite as legible).</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<epigraph>
|
|
<para>... reading the UNIX source code to the Bourne shell (/bin/sh). I
|
|
was shocked at how much simple algorithms could be made cryptic, and
|
|
therefore useless, by a poor choice of code style. I asked myself,
|
|
<quote>Could someone be proud of this code?</quote></para>
|
|
<para>--Landon Noll</para>
|
|
</epigraph>
|
|
|
|
</sect1> <!-- Unofficial Shell Scripting Stylesheet -->
|
|
|
|
|
|
|
|
</chapter> <!-- Scripting With Style -->
|
|
|
|
|
|
|
|
<chapter id="miscellany">
|
|
<title>Miscellany</title>
|
|
|
|
<epigraph>
|
|
<para>Nobody really knows what the Bourne shell's grammar is. Even
|
|
examination of the source code is little help.</para>
|
|
<para>--Tom Duff</para>
|
|
</epigraph>
|
|
|
|
|
|
<sect1 id="intandnonint">
|
|
<title>Interactive and non-interactive shells and scripts</title>
|
|
|
|
<para>An <firstterm>interactive</firstterm> shell reads
|
|
commands from user input on a <filename>tty</filename>. Among
|
|
other things, such a shell reads startup files on activation,
|
|
displays a prompt, and enables job control by default. The
|
|
user can <firstterm>interact</firstterm> with the shell.</para>
|
|
|
|
<para>A shell running a script is always a non-interactive
|
|
shell. All the same, the script can still access its
|
|
<filename>tty</filename>. It is even possible to emulate an
|
|
interactive shell in a script.
|
|
|
|
<programlisting>#!/bin/bash
|
|
MY_PROMPT='$ '
|
|
while :
|
|
do
|
|
echo -n "$MY_PROMPT"
|
|
read line
|
|
eval "$line"
|
|
done
|
|
|
|
exit 0
|
|
|
|
# This example script, and much of the above explanation supplied by
|
|
# Stéphane Chazelas (thanks again).</programlisting></para>
|
|
|
|
<para>Let us consider an <firstterm>interactive</firstterm>
|
|
script to be one that requires input from the user, usually
|
|
with <link linkend="readref">read</link> statements (see <xref
|
|
linkend="ex36"/>). <quote>Real life</quote> is actually a
|
|
bit messier than that. For now, assume an interactive script
|
|
is bound to a tty, a script that a user has invoked from the
|
|
console or an <firstterm>xterm</firstterm>.</para>
|
|
|
|
<para>Init and startup scripts are necessarily non-interactive,
|
|
since they must run without human intervention. Many
|
|
administrative and system maintenance scripts are likewise
|
|
non-interactive. Unvarying repetitive tasks cry out for
|
|
automation by non-interactive scripts.</para>
|
|
|
|
<para>Non-interactive scripts can run in the background, but
|
|
interactive ones hang, waiting for input that never comes.
|
|
Handle that difficulty by having an <command>expect</command>
|
|
script or embedded <link linkend="heredocref">here
|
|
document</link> feed input to an interactive script running
|
|
as a background job. In the simplest case, redirect a
|
|
file to supply input to a <command>read</command> statement
|
|
(<command>read variable <file</command>). These particular
|
|
workarounds make possible general purpose scripts that run
|
|
in either interactive or non-interactive modes.</para>
|
|
|
|
<para>If a script needs to test whether it is running in an
|
|
interactive shell, it is simply a matter of finding
|
|
whether the <firstterm>prompt</firstterm> variable, <link
|
|
linkend="ps1ref">$PS1</link> is set. (If the user is being
|
|
prompted for input, then the script needs to display a
|
|
prompt.)</para>
|
|
|
|
<para><programlisting>if [ -z $PS1 ] # no prompt?
|
|
### if [ -v PS1 ] # On Bash 4.2+ ...
|
|
then
|
|
# non-interactive
|
|
...
|
|
else
|
|
# interactive
|
|
...
|
|
fi</programlisting></para>
|
|
|
|
<para><anchor id="iitest"/>Alternatively, the script can test
|
|
for the presence of option <quote>i</quote> in the <link
|
|
linkend="flpref">$-</link> flag.</para>
|
|
|
|
<para><programlisting>case $- in
|
|
*i*) # interactive shell
|
|
;;
|
|
*) # non-interactive shell
|
|
;;
|
|
# (Courtesy of "UNIX F.A.Q.," 1993)</programlisting></para>
|
|
|
|
<para><anchor id="ii2test"/>However, John Lange describes
|
|
an alternative method, using the <link
|
|
linkend="termtest"><token>-t</token>
|
|
<firstterm>test</firstterm> operator</link>.</para>
|
|
|
|
<para><programlisting># Test for a terminal!
|
|
|
|
fd=0 # stdin
|
|
|
|
# As we recall, the -t test option checks whether the stdin, [ -t 0 ],
|
|
#+ or stdout, [ -t 1 ], in a given script is running in a terminal.
|
|
if [ -t "$fd" ]
|
|
then
|
|
echo interactive
|
|
else
|
|
echo non-interactive
|
|
fi
|
|
|
|
|
|
# But, as John points out:
|
|
# if [ -t 0 ] works ... when you're logged in locally
|
|
# but fails when you invoke the command remotely via ssh.
|
|
# So for a true test you also have to test for a socket.
|
|
|
|
if [[ -t "$fd" || -p /dev/stdin ]]
|
|
then
|
|
echo interactive
|
|
else
|
|
echo non-interactive
|
|
fi</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 <firstterm>wrapper</firstterm> is a shell script that embeds
|
|
a system command or utility, that accepts and passes a set of
|
|
parameters to that command.
|
|
|
|
<footnote><para>Quite a number of Linux utilities are, in fact,
|
|
shell wrappers. Some examples are
|
|
<filename>/usr/bin/pdf2ps</filename>,
|
|
<filename>/usr/bin/batch</filename>, and
|
|
<filename>/usr/bin/xmkmf</filename>.</para></footnote>
|
|
|
|
Wrapping a script around a complex command-line
|
|
simplifies invoking it. This is expecially useful
|
|
with <link linkend="sedref">sed</link> and <link
|
|
linkend="awkref">awk</link>.</para>
|
|
|
|
<para>A
|
|
<command>
|
|
<indexterm>
|
|
<primary>sed</primary>
|
|
</indexterm> <indexterm>
|
|
<primary>script</primary> <secondary>sed</secondary>
|
|
</indexterm> sed</command> or
|
|
<command>
|
|
<indexterm>
|
|
<primary>awk</primary>
|
|
</indexterm> <indexterm>
|
|
<primary>script</primary> <secondary>awk</secondary>
|
|
</indexterm>
|
|
awk</command> script would normally be invoked
|
|
from the command-line by a <userinput>sed -e
|
|
<replaceable>'commands'</replaceable></userinput>
|
|
or <userinput>awk
|
|
<replaceable>'commands'</replaceable></userinput>. Embedding
|
|
such a script in a Bash script permits calling it more simply,
|
|
and makes it <firstterm>reusable</firstterm>. This also
|
|
enables combining the functionality of <firstterm>sed</firstterm>
|
|
and <firstterm>awk</firstterm>, for example <link
|
|
linkend="piperef">piping</link> the output of a set of
|
|
<firstterm>sed</firstterm> commands to
|
|
<firstterm>awk</firstterm>. As a saved executable file,
|
|
you can then repeatedly invoke it in its original form or
|
|
modified, without the inconvenience of retyping it on the
|
|
command-line.</para>
|
|
|
|
<example id="ex3">
|
|
<title><firstterm>shell wrapper</firstterm></title>
|
|
<programlisting>&ex3;</programlisting>
|
|
</example>
|
|
|
|
<example id="ex4">
|
|
<title> A slightly more complex <firstterm>shell
|
|
wrapper</firstterm></title>
|
|
<programlisting>&ex4;</programlisting>
|
|
</example>
|
|
|
|
<example id="loggingwrapper">
|
|
<title> A generic <firstterm>shell wrapper</firstterm> that
|
|
writes to a logfile</title>
|
|
<programlisting>&loggingwrapper;</programlisting>
|
|
</example>
|
|
|
|
<example id="prasc">
|
|
<title> A <firstterm>shell wrapper</firstterm> around an awk
|
|
script</title>
|
|
<programlisting>&prasc;</programlisting>
|
|
</example>
|
|
|
|
<example id="coltotaler">
|
|
<title> A <firstterm>shell wrapper</firstterm> around another
|
|
awk script</title>
|
|
<programlisting>&coltotaler;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><anchor id="perlref"/>For those scripts needing a single
|
|
do-it-all tool, a Swiss army knife, there is
|
|
<firstterm>Perl</firstterm>. Perl combines the
|
|
capabilities of <link linkend="sedref">sed</link> and <link
|
|
linkend="awkref">awk</link>, and throws in a large subset of
|
|
<command>C</command>, to boot. It is modular and contains support
|
|
for everything ranging from object-oriented programming up to and
|
|
including the kitchen sink. Short Perl scripts lend themselves to
|
|
embedding within shell scripts, and there may be some substance
|
|
to the claim that Perl can totally replace shell scripting
|
|
(though the author of the <emphasis>ABS Guide</emphasis> remains
|
|
skeptical).</para>
|
|
|
|
<para><anchor id="perlemb"/></para>
|
|
<example id="ex56">
|
|
<title>Perl embedded in a <firstterm>Bash</firstterm> script</title>
|
|
<programlisting>&ex56;</programlisting>
|
|
</example>
|
|
|
|
<para>It is even possible to combine a Bash script and Perl script
|
|
within the same file. Depending on how the script is invoked, either
|
|
the Bash part or the Perl part will execute.</para>
|
|
|
|
<para><anchor id="bashandperl0"/></para>
|
|
<example id="bashandperl">
|
|
<title>Bash and Perl scripts combined</title>
|
|
<programlisting>&bashandperl;</programlisting>
|
|
</example>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>bash bashandperl.sh</userinput>
|
|
<computeroutput>Greetings from the Bash part of the script.</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>perl -x bashandperl.sh</userinput>
|
|
<computeroutput>Greetings from the Perl part of the script.</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>It is, of course, possible to embed even more exotic scripting
|
|
languages within shell wrappers. <firstterm>Python</firstterm>,
|
|
for example ...</para>
|
|
|
|
<para><anchor id="pythonemb"/></para>
|
|
<example id="ex56py">
|
|
<title>Python embedded in a <firstterm>Bash</firstterm> script</title>
|
|
<programlisting>&ex56py;</programlisting>
|
|
</example>
|
|
|
|
<para>Wrapping a script around <firstterm>mplayer</firstterm>
|
|
and the Google's translation server, you can create something
|
|
that talks back to you.</para>
|
|
|
|
<para><anchor id="speech00"/></para>
|
|
<example id="speech0">
|
|
<title>A script that speaks</title>
|
|
<programlisting>&speech0;</programlisting>
|
|
</example>
|
|
|
|
<para>One interesting example of a complex shell wrapper is Martin
|
|
Matusiak's <ulink
|
|
url="http://sourceforge.net/projects/undvd/"><firstterm>undvd</firstterm>
|
|
script</ulink>, which provides an easy-to-use
|
|
command-line interface to the complex <ulink
|
|
url="http://www.mplayerhq.hu/DOCS/HTML/en/mencoder.html">mencoder</ulink>
|
|
utility. Another example is Itzchak Rehberg's <ulink
|
|
url="http://projects.izzysoft.de/trac/ext3undel">Ext3Undel</ulink>,
|
|
a set of scripts to recover deleted file on an
|
|
<firstterm>ext3</firstterm> filesystem.</para>
|
|
|
|
|
|
</sect1> <!-- Shell wrappers -->
|
|
|
|
|
|
|
|
<sect1 id="testsandcomparisons">
|
|
<title>Tests and Comparisons: Alternatives</title>
|
|
|
|
<para>For tests, the <link linkend="dblbrackets">[[ ]]</link>
|
|
construct may be more appropriate than <userinput>[
|
|
]</userinput>. Likewise, <link linkend="icomparison1">arithmetic
|
|
comparisons</link> might benefit from the <link
|
|
linkend="dblparens">(( ))</link> construct.
|
|
|
|
<programlisting>a=8
|
|
|
|
# All of the comparisons below are equivalent.
|
|
test "$a" -lt 16 && echo "yes, $a < 16" # "and list"
|
|
/bin/test "$a" -lt 16 && echo "yes, $a < 16"
|
|
[ "$a" -lt 16 ] && echo "yes, $a < 16"
|
|
[[ $a -lt 16 ]] && echo "yes, $a < 16" # Quoting variables within
|
|
(( a < 16 )) && echo "yes, $a < 16" # [[ ]] and (( )) not necessary.
|
|
|
|
city="New York"
|
|
# Again, all of the comparisons below are equivalent.
|
|
test "$city" \< Paris && echo "Yes, Paris is greater than $city"
|
|
# Greater ASCII order.
|
|
/bin/test "$city" \< Paris && echo "Yes, Paris is greater than $city"
|
|
[ "$city" \< Paris ] && echo "Yes, Paris is greater than $city"
|
|
[[ $city < Paris ]] && echo "Yes, Paris is greater than $city"
|
|
# Need not quote $city.
|
|
|
|
# Thank you, S.C.</programlisting></para>
|
|
|
|
</sect1> <!-- Tests and Comparisons: Alternatives -->
|
|
|
|
|
|
|
|
<sect1 id="recursionsct">
|
|
<title>Recursion: a script calling itself</title>
|
|
|
|
|
|
<para><anchor id="scriptrecursion"/></para>
|
|
<para>Can a script <link linkend="recursionref">recursively</link>
|
|
call itself? Indeed.</para>
|
|
|
|
<example id="recurse">
|
|
<title>A (useless) script that recursively calls itself</title>
|
|
<programlisting>&recurse;</programlisting>
|
|
</example>
|
|
|
|
<example id="pbook">
|
|
<title>A (useful) script that recursively calls itself</title>
|
|
<programlisting>&pbook;</programlisting>
|
|
</example>
|
|
|
|
<example id="usrmnt">
|
|
<title>Another (useful) script that recursively calls itself</title>
|
|
<programlisting>&usrmnt;</programlisting>
|
|
</example>
|
|
|
|
<caution><para>Too many levels of recursion can exhaust the
|
|
script's stack space, causing a segfault.</para></caution>
|
|
|
|
</sect1> <!-- Recursion -->
|
|
|
|
|
|
|
|
<sect1 id="colorizing">
|
|
<title><quote>Colorizing</quote> Scripts</title>
|
|
|
|
<para><anchor id="colorizingref"/></para>
|
|
|
|
<para>The ANSI
|
|
<footnote><para><acronym>ANSI</acronym> is, of course, the
|
|
acronym for the American National Standards
|
|
Institute. This august body establishes and maintains
|
|
various technical and industrial standards.</para></footnote>
|
|
escape sequences set screen attributes, such as bold
|
|
text, and color of foreground and background. <link
|
|
linkend="dosbatch1">DOS batch files</link> commonly used
|
|
ANSI escape codes for <emphasis>color</emphasis> output,
|
|
and so can Bash scripts.</para>
|
|
|
|
<example id="ex30a">
|
|
<title>A <quote>colorized</quote> address database</title>
|
|
<programlisting>&ex30a;</programlisting>
|
|
</example>
|
|
|
|
<example id="draw-box">
|
|
<title>Drawing a box</title>
|
|
<programlisting>&drawbox;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>The simplest, and perhaps most useful ANSI escape sequence is
|
|
bold text, <command>\033[1m ... \033[0m</command>. The
|
|
<token>\033</token> represents an <link
|
|
linkend="escp">escape</link>, the <quote>[1</quote> turns on the
|
|
bold attribute, while the <quote>[0</quote> switches it off. The
|
|
<quote>m</quote> terminates each term of the escape sequence.
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo -e "\033[1mThis is bold text.\033[0m"</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>A similar escape sequence switches on the underline
|
|
attribute (on an <firstterm>rxvt</firstterm> and an
|
|
<firstterm>aterm</firstterm>).
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo -e "\033[4mThis is underlined text.\033[0m"</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>With an <command>echo</command>, the
|
|
<option>-e</option> option enables the escape
|
|
sequences.</para></note>
|
|
|
|
<para>Other escape sequences change the text and/or background
|
|
color.</para>
|
|
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo -e '\E[34;47mThis prints in blue.'; tput sgr0</userinput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -e '\E[33;44m'"yellow text on blue background"; tput sgr0</userinput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>echo -e '\E[1;33;44m'"BOLD yellow text on blue background"; tput sgr0</userinput>
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>It's usually advisable to set the
|
|
<firstterm>bold</firstterm> attribute for light-colored foreground
|
|
text.</para></note>
|
|
|
|
<para>The <command>tput sgr0</command> restores the
|
|
terminal settings to normal. Omitting this lets all
|
|
subsequent output from that particular terminal remain
|
|
blue.</para>
|
|
|
|
<note><para>Since <command>tput sgr0</command> fails to restore
|
|
terminal settings under certain circumstances,
|
|
<command>echo -ne \E[0m</command> may be a better choice.</para></note>
|
|
|
|
<para><anchor id="coloriztempl"/></para>
|
|
<sidebar>
|
|
<para>Use the following template for writing colored text on a colored
|
|
background.</para>
|
|
|
|
<para>
|
|
<userinput>echo -e '\E[COLOR1;COLOR2mSome text goes here.'</userinput>
|
|
</para>
|
|
|
|
<para>The <quote>\E[</quote> begins the escape sequence.
|
|
The semicolon-separated numbers <quote>COLOR1</quote> and
|
|
<quote>COLOR2</quote> specify a foreground and a background
|
|
color, according to the table below. (The order of the
|
|
numbers does not matter, since the foreground and background
|
|
numbers fall in non-overlapping ranges.) The <quote>m</quote>
|
|
terminates the escape sequence, and the text begins immediately
|
|
after that.</para>
|
|
|
|
<para>Note also that <link linkend="snglquo">single quotes</link>
|
|
enclose the remainder of the command sequence following the
|
|
<command>echo -e</command>.</para>
|
|
</sidebar>
|
|
|
|
|
|
<para>The numbers in the following table work for an
|
|
<firstterm>rxvt</firstterm> terminal. Results may vary for other
|
|
terminal emulators.</para>
|
|
|
|
<para><anchor id="coloriztable"/></para>
|
|
<table>
|
|
<title>Numbers representing colors in Escape Sequences</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Color</entry>
|
|
<entry>Foreground</entry>
|
|
<entry>Background</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>black</option></entry>
|
|
<entry>30</entry>
|
|
<entry>40</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>red</option></entry>
|
|
<entry>31</entry>
|
|
<entry>41</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>green</option></entry>
|
|
<entry>32</entry>
|
|
<entry>42</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>yellow</option></entry>
|
|
<entry>33</entry>
|
|
<entry>43</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>blue</option></entry>
|
|
<entry>34</entry>
|
|
<entry>44</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>magenta</option></entry>
|
|
<entry>35</entry>
|
|
<entry>45</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>cyan</option></entry>
|
|
<entry>36</entry>
|
|
<entry>46</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>white</option></entry>
|
|
<entry>37</entry>
|
|
<entry>47</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<example id="colorecho">
|
|
<title>Echoing colored text</title>
|
|
<programlisting>&colorecho;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="horseraceref"/></para>
|
|
<example id="horserace">
|
|
<title>A <quote>horserace</quote> game</title>
|
|
<programlisting>&horserace;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="hashexample"/>, <xref
|
|
linkend="homework"/>, <xref linkend="showallc"/>, and <xref
|
|
linkend="petals"/>.</para>
|
|
|
|
<caution><para>There is, however, a major problem with all
|
|
this. <emphasis>ANSI escape sequences are emphatically
|
|
<link
|
|
linkend="portabilityissues">non-portable</link>.</emphasis>
|
|
What works fine on some terminal emulators (or the
|
|
console) may work differently, or not at all, on others.
|
|
A <quote>colorized</quote> script that looks stunning on the
|
|
script author's machine may produce unreadable output on
|
|
someone else's. This somewhat compromises the usefulness of
|
|
colorizing scripts, and possibly relegates this technique
|
|
to the status of a gimmick. Colorized scripts are probably
|
|
inappropriate in a commercial setting, i.e., your supervisor
|
|
might disapprove.</para></caution>
|
|
|
|
<para>Alister's <ulink url="http://code.google.com/p/ansi-color/">
|
|
ansi-color</ulink> utility (based on <ulink
|
|
url="http://bash.deta.in/color-1.1.tar.gz">Moshe
|
|
Jacobson's color utility</ulink> considerably simplifies using
|
|
ANSI escape sequences. It substitutes a clean and logical
|
|
syntax for the clumsy constructs just discussed.</para>
|
|
|
|
<para>Henry/teikedvl has likewise created a utility (<ulink
|
|
url="http://scriptechocolor.sourceforge.net/">http://scriptechocolor.sourceforge.net/</ulink>) to simplify creation of colorized scripts.</para>
|
|
|
|
|
|
</sect1> <!-- "Colorizing" scripts -->
|
|
|
|
|
|
|
|
<sect1 id="optimizations">
|
|
<title>Optimizations</title>
|
|
|
|
<para>Most shell scripts are quick 'n dirty solutions to non-complex
|
|
problems. As such, optimizing them for speed is not much of an
|
|
issue. Consider the case, though, where a script carries out
|
|
an important task, does it well, but runs too slowly. Rewriting
|
|
it in a compiled language may not be a palatable option. The
|
|
simplest fix would be to rewrite the parts of the script
|
|
that slow it down. Is it possible to apply principles of code
|
|
optimization even to a lowly shell script?</para>
|
|
|
|
<para>Check the loops in the script. Time consumed by repetitive
|
|
operations adds up quickly. If at all possible, remove
|
|
time-consuming operations from within loops.</para>
|
|
|
|
<para>Use <link linkend="builtinref">builtin</link> commands in
|
|
preference to system commands. Builtins execute faster and
|
|
usually do not launch a subshell when invoked.</para>
|
|
|
|
<para><anchor id="catabuse"/></para>
|
|
<para>Avoid unnecessary commands, particularly in a <link
|
|
linkend="piperef">pipe</link>.
|
|
<programlisting>cat "$file" | grep "$word"
|
|
|
|
grep "$word" "$file"
|
|
|
|
# The above command-lines have an identical effect,
|
|
#+ but the second runs faster since it launches one fewer subprocess.</programlisting>
|
|
The <link linkend="catref">cat</link> command seems especially
|
|
prone to overuse in scripts.</para>
|
|
|
|
<para><anchor id="lcall"/></para>
|
|
<sidebar><para>Disabling certain Bash options can speed up scripts.</para>
|
|
<para>As Erik Brandsberg points out:</para>
|
|
<para>If you don't need <link
|
|
linkend="unicoderef">Unicode</link> support, you can
|
|
get potentially a 2x or more improvement in speed by
|
|
simply setting the <userinput>LC_ALL</userinput> variable.
|
|
|
|
<programlisting> export LC_ALL=C
|
|
|
|
[specifies the locale as ANSI C,
|
|
thereby disabling Unicode support]
|
|
|
|
[In an example script ...]
|
|
|
|
Without [Unicode support]:
|
|
erik@erik-desktop:~/capture$ time ./cap-ngrep.sh
|
|
live2.pcap > out.txt
|
|
|
|
real 0m20.483s
|
|
user 1m34.470s
|
|
sys 0m12.869s
|
|
|
|
With [Unicode support]:
|
|
erik@erik-desktop:~/capture$ time ./cap-ngrep.sh
|
|
live2.pcap > out.txt
|
|
|
|
real 0m50.232s
|
|
user 3m51.118s
|
|
sys 0m11.221s
|
|
|
|
A large part of the overhead that is optimized is, I believe,
|
|
regex match using [[ string =~ REGEX ]],
|
|
but it may help with other portions of the code as well.
|
|
I hadn't [seen it] mentioned that this optimization helped
|
|
with Bash, but I had seen it helped with "grep,"
|
|
so why not try?</programlisting></para></sidebar>
|
|
|
|
<para><anchor id="optimes"/></para>
|
|
<note><para>Certain operators, notably <link
|
|
linkend="exprref">expr</link>, are very inefficient
|
|
and might be replaced by <link linkend="dblparens">double
|
|
parentheses</link> arithmetic expansion.
|
|
See <xref linkend="testexectime"/>.</para>
|
|
|
|
|
|
<para><programlisting>Math tests
|
|
|
|
math via $(( ))
|
|
real 0m0.294s
|
|
user 0m0.288s
|
|
sys 0m0.008s
|
|
|
|
math via expr:
|
|
real 1m17.879s # Much slower!
|
|
user 0m3.600s
|
|
sys 0m8.765s
|
|
|
|
math via let:
|
|
real 0m0.364s
|
|
user 0m0.372s
|
|
sys 0m0.000s</programlisting></para>
|
|
|
|
|
|
<para><link linkend="ifthen">Condition testing</link>
|
|
constructs in scripts deserve close scrutiny. Substitute
|
|
<link linkend="caseesac1">case</link> for <link
|
|
linkend="ifthen">if-then</link> constructs and combine tests
|
|
when possible, to minimize script execution time. Again,
|
|
refer to <xref linkend="testexectime"/>.</para>
|
|
|
|
|
|
<para><programlisting>Test using "case" construct:
|
|
real 0m0.329s
|
|
user 0m0.320s
|
|
sys 0m0.000s
|
|
|
|
|
|
Test with if [], no quotes:
|
|
real 0m0.438s
|
|
user 0m0.432s
|
|
sys 0m0.008s
|
|
|
|
|
|
Test with if [], quotes:
|
|
real 0m0.476s
|
|
user 0m0.452s
|
|
sys 0m0.024s
|
|
|
|
|
|
Test with if [], using -eq:
|
|
real 0m0.457s
|
|
user 0m0.456s
|
|
sys 0m0.000s</programlisting></para></note>
|
|
|
|
|
|
<para><anchor id="assocarrtst"/></para>
|
|
<note><para>Erik Brandsberg recommends using <link
|
|
linkend="assocarr">associative arrays</link> in preference to
|
|
conventional numeric-indexed arrays in most cases. When
|
|
overwriting values in a numeric array, there is a significant
|
|
performance penalty vs. associative arrays. Running a test
|
|
script confirms this. See <xref linkend="assocarrtest"/>.</para>
|
|
|
|
|
|
<para><programlisting>Assignment tests
|
|
|
|
Assigning a simple variable
|
|
real 0m0.418s
|
|
user 0m0.416s
|
|
sys 0m0.004s
|
|
|
|
Assigning a numeric index array entry
|
|
real 0m0.582s
|
|
user 0m0.564s
|
|
sys 0m0.016s
|
|
|
|
Overwriting a numeric index array entry
|
|
real 0m21.931s
|
|
user 0m21.913s
|
|
sys 0m0.016s
|
|
|
|
Linear reading of numeric index array
|
|
real 0m0.422s
|
|
user 0m0.416s
|
|
sys 0m0.004s
|
|
|
|
Assigning an associative array entry
|
|
real 0m1.800s
|
|
user 0m1.796s
|
|
sys 0m0.004s
|
|
|
|
Overwriting an associative array entry
|
|
real 0m1.798s
|
|
user 0m1.784s
|
|
sys 0m0.012s
|
|
|
|
Linear reading an associative array entry
|
|
real 0m0.420s
|
|
user 0m0.420s
|
|
sys 0m0.000s
|
|
|
|
Assigning a random number to a simple variable
|
|
real 0m0.402s
|
|
user 0m0.388s
|
|
sys 0m0.016s
|
|
|
|
Assigning a sparse numeric index array entry randomly into 64k cells
|
|
real 0m12.678s
|
|
user 0m12.649s
|
|
sys 0m0.028s
|
|
|
|
Reading sparse numeric index array entry
|
|
real 0m0.087s
|
|
user 0m0.084s
|
|
sys 0m0.000s
|
|
|
|
Assigning a sparse associative array entry randomly into 64k cells
|
|
real 0m0.698s
|
|
user 0m0.696s
|
|
sys 0m0.004s
|
|
|
|
Reading sparse associative index array entry
|
|
real 0m0.083s
|
|
user 0m0.084s
|
|
sys 0m0.000s</programlisting></para>
|
|
</note>
|
|
|
|
|
|
<para>Use the <link linkend="timref">time</link> and <link
|
|
linkend="timesref">times</link> tools to profile
|
|
computation-intensive commands. Consider rewriting time-critical
|
|
code sections in C, or even in assembler.</para>
|
|
|
|
<para>Try to minimize file I/O. Bash is not particularly
|
|
efficient at handling files, so consider using
|
|
more appropriate tools for this within the script,
|
|
such as <link linkend="awkref">awk</link> or <link
|
|
linkend="perlref">Perl</link>.</para>
|
|
|
|
<para>Write your scripts in a modular and coherent form,
|
|
<footnote><para>This usually means liberal use of
|
|
<link linkend="functionref">functions</link>.</para></footnote>
|
|
so they can be reorganized and tightened up as necessary. Some
|
|
of the optimization techniques applicable to high-level
|
|
languages may work for scripts, but others, such as
|
|
<firstterm>loop unrolling</firstterm>, are mostly
|
|
irrelevant. Above all, use common sense.</para>
|
|
|
|
<para>For an excellent demonstration of how optimization can
|
|
dramatically reduce the execution time of a script, see <xref
|
|
linkend="monthlypmt"/>.</para>
|
|
|
|
</sect1> <!-- Optimizations -->
|
|
|
|
|
|
|
|
<sect1 id="assortedtips">
|
|
<title>Assorted Tips</title>
|
|
|
|
|
|
<sect2>
|
|
<title>Ideas for more powerful scripts</title>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="pseudocoderef"/></para>
|
|
<para>You have a problem that you want to solve by writing a Bash
|
|
script. Unfortunately, you don't know quite where to start.
|
|
One method is to plunge right in and code those parts
|
|
of the script that come easily, and write the hard parts as
|
|
<firstterm>pseudo-code</firstterm>.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
ARGCOUNT=1 # Need name as argument.
|
|
E_WRONGARGS=65
|
|
|
|
if [ number-of-arguments is-not-equal-to "$ARGCOUNT" ]
|
|
# ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
|
|
# Can't figure out how to code this . . .
|
|
#+ . . . so write it in pseudo-code.
|
|
|
|
then
|
|
echo "Usage: name-of-script name"
|
|
# ^^^^^^^^^^^^^^ More pseudo-code.
|
|
exit $E_WRONGARGS
|
|
fi
|
|
|
|
. . .
|
|
|
|
exit 0
|
|
|
|
|
|
# Later on, substitute working code for the pseudo-code.
|
|
|
|
# Line 6 becomes:
|
|
if [ $# -ne "$ARGCOUNT" ]
|
|
|
|
# Line 12 becomes:
|
|
echo "Usage: `basename $0` name"</programlisting></para>
|
|
|
|
<para>For an example of using pseudo-code, see the <link
|
|
linkend="newtonsqrt">Square Root</link> exercise.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="trackingscr"/></para>
|
|
<para>To keep a record of which user scripts have run
|
|
during a particular session or over a number of sessions,
|
|
add the following lines to each script you want to keep track
|
|
of. This will keep a continuing file record of the script
|
|
names and invocation times. </para>
|
|
|
|
<para>
|
|
<programlisting># Append (>>) following to end of each script tracked.
|
|
|
|
whoami>> $SAVE_FILE # User invoking the script.
|
|
echo $0>> $SAVE_FILE # Script name.
|
|
date>> $SAVE_FILE # Date and time.
|
|
echo>> $SAVE_FILE # Blank line as separator.
|
|
|
|
# Of course, SAVE_FILE defined and exported as environmental variable in ~/.bashrc
|
|
#+ (something like ~/.scripts-run)</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="prependref"/></para>
|
|
<para>The <token>>></token> operator
|
|
<firstterm>appends</firstterm> lines to a file.
|
|
What if you wish to <firstterm>prepend</firstterm> a
|
|
line to an existing file, that is, to paste it in at the
|
|
beginning?</para>
|
|
|
|
<para>
|
|
<programlisting>file=data.txt
|
|
title="***This is the title line of data text file***"
|
|
|
|
echo $title | cat - $file >$file.new
|
|
# "cat -" concatenates stdout to $file.
|
|
# End result is
|
|
#+ to write a new file with $title appended at *beginning*.</programlisting>
|
|
</para>
|
|
|
|
<para>This is a simplified variant of the <xref
|
|
linkend="prependex"/> script given earlier. And, of course,
|
|
<link linkend="sedref">sed</link> can also do this.</para>
|
|
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="scriptasemb"/></para>
|
|
<para>A shell script may act as an embedded command inside
|
|
another shell script, a <firstterm>Tcl</firstterm> or
|
|
<firstterm>wish</firstterm> script, or even a <link
|
|
linkend="makefileref">Makefile</link>. It can be invoked
|
|
as an external shell command in a C program using the
|
|
<replaceable>system()</replaceable> call, i.e.,
|
|
<replaceable>system("script_name");</replaceable>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="setvaremb"/></para>
|
|
<para>Setting a variable to the contents of an embedded
|
|
<firstterm>sed</firstterm> or <firstterm>awk</firstterm>
|
|
script increases the readability of the surrounding <link
|
|
linkend="shwrapper">shell wrapper</link>. See <xref
|
|
linkend="mailformat"/> and <xref linkend="coltotaler3"/>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="libroutines"/></para>
|
|
<para>Put together files containing your favorite and most useful
|
|
definitions and functions. As necessary,
|
|
<quote>include</quote> one or more of these
|
|
<quote>library files</quote> in scripts with either the
|
|
<link linkend="dotref">dot</link> (<command>.</command>)
|
|
or <link linkend="sourceref">source</link> command.</para>
|
|
|
|
<para>
|
|
<programlisting># SCRIPT LIBRARY
|
|
# ------ -------
|
|
|
|
# Note:
|
|
# No "#!" here.
|
|
# No "live code" either.
|
|
|
|
|
|
# Useful variable definitions
|
|
|
|
ROOT_UID=0 # Root has $UID 0.
|
|
E_NOTROOT=101 # Not root user error.
|
|
MAXRETVAL=255 # Maximum (positive) return value of a function.
|
|
SUCCESS=0
|
|
FAILURE=-1
|
|
|
|
|
|
|
|
# Functions
|
|
|
|
Usage () # "Usage:" message.
|
|
{
|
|
if [ -z "$1" ] # No arg passed.
|
|
then
|
|
msg=filename
|
|
else
|
|
msg=$@
|
|
fi
|
|
|
|
echo "Usage: `basename $0` "$msg""
|
|
}
|
|
|
|
|
|
Check_if_root () # Check if root running script.
|
|
{ # From "ex39.sh" example.
|
|
if [ "$UID" -ne "$ROOT_UID" ]
|
|
then
|
|
echo "Must be root to run this script."
|
|
exit $E_NOTROOT
|
|
fi
|
|
}
|
|
|
|
|
|
CreateTempfileName () # Creates a "unique" temp filename.
|
|
{ # From "ex51.sh" example.
|
|
prefix=temp
|
|
suffix=`eval date +%s`
|
|
Tempfilename=$prefix.$suffix
|
|
}
|
|
|
|
|
|
isalpha2 () # Tests whether *entire string* is alphabetic.
|
|
{ # From "isalpha.sh" example.
|
|
[ $# -eq 1 ] || return $FAILURE
|
|
|
|
case $1 in
|
|
*[!a-zA-Z]*|"") return $FAILURE;;
|
|
*) return $SUCCESS;;
|
|
esac # Thanks, S.C.
|
|
}
|
|
|
|
|
|
abs () # Absolute value.
|
|
{ # Caution: Max return value = 255.
|
|
E_ARGERR=-999999
|
|
|
|
if [ -z "$1" ] # Need arg passed.
|
|
then
|
|
return $E_ARGERR # Obvious error value returned.
|
|
fi
|
|
|
|
if [ "$1" -ge 0 ] # If non-negative,
|
|
then #
|
|
absval=$1 # stays as-is.
|
|
else # Otherwise,
|
|
let "absval = (( 0 - $1 ))" # change sign.
|
|
fi
|
|
|
|
return $absval
|
|
}
|
|
|
|
|
|
tolower () # Converts string(s) passed as argument(s)
|
|
{ #+ to lowercase.
|
|
|
|
if [ -z "$1" ] # If no argument(s) passed,
|
|
then #+ send error message
|
|
echo "(null)" #+ (C-style void-pointer error message)
|
|
return #+ and return from function.
|
|
fi
|
|
|
|
echo "$@" | tr A-Z a-z
|
|
# Translate all passed arguments ($@).
|
|
|
|
return
|
|
|
|
# Use command substitution to set a variable to function output.
|
|
# For example:
|
|
# oldvar="A seT of miXed-caSe LEtTerS"
|
|
# newvar=`tolower "$oldvar"`
|
|
# echo "$newvar" # a set of mixed-case letters
|
|
#
|
|
# Exercise: Rewrite this function to change lowercase passed argument(s)
|
|
# to uppercase ... toupper() [easy].
|
|
}</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="commenth"/></para>
|
|
<para>Use special-purpose comment headers to increase clarity
|
|
and legibility in scripts.</para>
|
|
<para><programlisting>## Caution.
|
|
rm -rf *.zzy ## The "-rf" options to "rm" are very dangerous,
|
|
##+ especially with wild cards.
|
|
|
|
#+ Line continuation.
|
|
# This is line 1
|
|
#+ of a multi-line comment,
|
|
#+ and this is the final line.
|
|
|
|
#* Note.
|
|
|
|
#o List item.
|
|
|
|
#> Another point of view.
|
|
while [ "$var1" != "end" ] #> while test "$var1" != "end"</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="progbar"/></para>
|
|
<para>Dotan Barak contributes template code for a
|
|
<firstterm>progress bar</firstterm> in a script.</para>
|
|
|
|
<example id="progressbar">
|
|
<title>A Progress Bar</title>
|
|
<programlisting>&progressbar;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="comoutbl"/></para>
|
|
<para>A particularly clever use of <link
|
|
linkend="testconstructs1">if-test</link> constructs
|
|
is for comment blocks.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
COMMENT_BLOCK=
|
|
# Try setting the above variable to some value
|
|
#+ for an unpleasant surprise.
|
|
|
|
if [ $COMMENT_BLOCK ]; then
|
|
|
|
Comment block --
|
|
=================================
|
|
This is a comment line.
|
|
This is another comment line.
|
|
This is yet another comment line.
|
|
=================================
|
|
|
|
echo "This will not echo."
|
|
|
|
Comment blocks are error-free! Whee!
|
|
|
|
fi
|
|
|
|
echo "No more comments, please."
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
<para>Compare this with <link linkend="cblock1">using
|
|
here documents to comment out code blocks</link>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="intparam"/></para>
|
|
<para>Using the <link linkend="xstatvarref">$? exit status
|
|
variable</link>, a script may test if a parameter contains
|
|
only digits, so it can be treated as an integer.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
SUCCESS=0
|
|
E_BADINPUT=85
|
|
|
|
test "$1" -ne 0 -o "$1" -eq 0 2>/dev/null
|
|
# An integer is either equal to 0 or not equal to 0.
|
|
# 2>/dev/null suppresses error message.
|
|
|
|
if [ $? -ne "$SUCCESS" ]
|
|
then
|
|
echo "Usage: `basename $0` integer-input"
|
|
exit $E_BADINPUT
|
|
fi
|
|
|
|
let "sum = $1 + 25" # Would give error if $1 not integer.
|
|
echo "Sum = $sum"
|
|
|
|
# Any variable, not just a command-line parameter, can be tested this way.
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="rvt"/>The 0 - 255 range for function return
|
|
values is a severe limitation. Global variables and
|
|
other workarounds are often problematic. An alternative
|
|
method for a function to communicate a value back to
|
|
the main body of the script is to have the function
|
|
write to <filename>stdout</filename> (usually with
|
|
<link linkend="echoref">echo</link>) the <quote>return
|
|
value,</quote> and assign this to a variable. This is
|
|
actually a variant of <link linkend="commandsubref">command
|
|
substitution.</link></para>
|
|
|
|
<example id="multiplication">
|
|
<title>Return value trickery</title>
|
|
<programlisting>&multiplication;</programlisting>
|
|
</example>
|
|
|
|
<para>The same technique also works for alphanumeric
|
|
strings. This means that a function can <quote>return</quote>
|
|
a non-numeric value.</para>
|
|
|
|
<para>
|
|
<programlisting>capitalize_ichar () # Capitalizes initial character
|
|
{ #+ of argument string(s) passed.
|
|
|
|
string0="$@" # Accepts multiple arguments.
|
|
|
|
firstchar=${string0:0:1} # First character.
|
|
string1=${string0:1} # Rest of string(s).
|
|
|
|
FirstChar=`echo "$firstchar" | tr a-z A-Z`
|
|
# Capitalize first character.
|
|
|
|
echo "$FirstChar$string1" # Output to stdout.
|
|
|
|
}
|
|
|
|
newstring=`capitalize_ichar "every sentence should start with a capital letter."`
|
|
echo "$newstring" # Every sentence should start with a capital letter.</programlisting>
|
|
</para>
|
|
|
|
<para>It is even possible for a function to <quote>return</quote>
|
|
multiple values with this method.</para>
|
|
|
|
<example id="sumproduct">
|
|
<title>Even more return value trickery</title>
|
|
<programlisting>&sumproduct;</programlisting>
|
|
</example>
|
|
|
|
<caution><para><anchor id="rvtcaution"/>There can be only
|
|
<command>one</command> <firstterm>echo</firstterm> statement
|
|
in the function for this to work. If you alter the previous
|
|
example:</para>
|
|
|
|
<para><programlisting>sum_and_product ()
|
|
{
|
|
echo "This is the sum_and_product function." # This messes things up!
|
|
echo $(( $1 + $2 )) $(( $1 * $2 ))
|
|
}
|
|
...
|
|
retval=`sum_and_product $first $second` # Assigns output of function.
|
|
# Now, this will not work correctly.</programlisting></para></caution>
|
|
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="passarray"/></para>
|
|
<para>Next in our bag of tricks are techniques for passing
|
|
an <link linkend="arrayref">array</link> to a
|
|
<link linkend="functionref">function</link>, then
|
|
<quote>returning</quote> an array back to the main body of
|
|
the script.</para>
|
|
|
|
<para>Passing an array involves loading the space-separated
|
|
elements of the array into a variable with <link
|
|
linkend="commandsubref">command substitution</link>. <anchor
|
|
id="retarray"/>Getting an array back as the <quote>return
|
|
value</quote> from a function uses the previously mentioned
|
|
strategem of <link linkend="echoref">echoing</link> the
|
|
array in the function, then invoking command substitution
|
|
and the <command>( ... )</command> operator to assign it to
|
|
an array.</para>
|
|
|
|
<example id="arrfunc">
|
|
<title>Passing and returning arrays</title>
|
|
<programlisting>&arrfunc;</programlisting>
|
|
</example>
|
|
|
|
<para>For a more elaborate example of passing arrays to
|
|
functions, see <xref linkend="lifeslow"/>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="cstyle"/></para>
|
|
<para>Using the <link linkend="dblparens">double-parentheses
|
|
construct</link>, it is possible to use C-style syntax
|
|
for setting and incrementing/decrementing variables
|
|
and in <link linkend="forloopref1">for</link> and <link
|
|
linkend="whileloopref">while</link> loops. See <xref
|
|
linkend="forloopc"/> and <xref linkend="whloopc"/>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="setpum"/></para>
|
|
<para>Setting the <link linkend="pathref">path</link> and <link
|
|
linkend="umaskref">umask</link> at the beginning of a script makes
|
|
it more <link linkend="portabilityissues">portable</link>
|
|
-- more likely to run on a <quote>foreign</quote> machine
|
|
whose user may have bollixed up the <varname>$PATH</varname>
|
|
and <command>umask</command>.
|
|
<programlisting>#!/bin/bash
|
|
PATH=/bin:/usr/bin:/usr/local/bin ; export PATH
|
|
umask 022 # Files that the script creates will have 755 permission.
|
|
|
|
# Thanks to Ian D. Allen, for this tip.</programlisting></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="filteroutp"/></para>
|
|
<para>A useful scripting technique is to
|
|
<emphasis>repeatedly</emphasis> feed the output of a filter
|
|
(by piping) back to the <emphasis>same filter</emphasis>, but
|
|
with a different set of arguments and/or options. Especially
|
|
suitable for this are <link linkend="trref">tr</link> and
|
|
<link linkend="grepref">grep</link>.</para>
|
|
|
|
<para>
|
|
<programlisting># From "wstrings.sh" example.
|
|
|
|
wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \
|
|
tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '`</programlisting>
|
|
</para>
|
|
|
|
<example id="agram">
|
|
<title>Fun with anagrams</title>
|
|
<programlisting>&agram;</programlisting>
|
|
</example>
|
|
|
|
<para>See also <xref linkend="constat"/>, <xref
|
|
linkend="cryptoquote"/>, and <xref linkend="soundex"/>.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="commblahd"/></para>
|
|
<para>Use <quote><link linkend="anonheredoc0">anonymous here
|
|
documents</link></quote> to comment out blocks of code,
|
|
to save having to individually comment out each line with
|
|
a <token>#</token>. See <xref linkend="commentblock"/>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="whatisref3"/></para>
|
|
<para>Running a script on a machine that relies on a command
|
|
that might not be installed is dangerous. Use <link
|
|
linkend="whatisref">whatis</link> to avoid potential problems
|
|
with this.</para>
|
|
|
|
<para>
|
|
<programlisting>CMD=command1 # First choice.
|
|
PlanB=command2 # Fallback option.
|
|
|
|
command_test=$(whatis "$CMD" | grep 'nothing appropriate')
|
|
# If 'command1' not found on system , 'whatis' will return
|
|
#+ "command1: nothing appropriate."
|
|
#
|
|
# A safer alternative is:
|
|
# command_test=$(whereis "$CMD" | grep \/)
|
|
# But then the sense of the following test would have to be reversed,
|
|
#+ since the $command_test variable holds content only if
|
|
#+ the $CMD exists on the system.
|
|
# (Thanks, bojster.)
|
|
|
|
|
|
if [[ -z "$command_test" ]] # Check whether command present.
|
|
then
|
|
$CMD option1 option2 # Run command1 with options.
|
|
else # Otherwise,
|
|
$PlanB #+ run command2.
|
|
fi</programlisting>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="ifgrepfix"/></para>
|
|
<para>An <link linkend="ifgrepref">if-grep test</link> may not
|
|
return expected results in an error case, when text is output to
|
|
<filename>stderr</filename>, rather that
|
|
<filename>stdout</filename>.
|
|
<programlisting>if ls -l nonexistent_filename | grep -q 'No such file or directory'
|
|
then echo "File \"nonexistent_filename\" does not exist."
|
|
fi</programlisting></para>
|
|
|
|
<para><link linkend="ioredirref">Redirecting</link>
|
|
<filename>stderr</filename> to <filename>stdout</filename> fixes
|
|
this.
|
|
<programlisting>if ls -l nonexistent_filename 2>&1 | grep -q 'No such file or directory'
|
|
# ^^^^
|
|
then echo "File \"nonexistent_filename\" does not exist."
|
|
fi
|
|
|
|
# Thanks, Chris Martin, for pointing this out.</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="subshtmp"/>
|
|
If you absolutely must access a subshell variable outside the
|
|
subshell, here's a way to do it.
|
|
<programlisting>TMPFILE=tmpfile # Create a temp file to store the variable.
|
|
|
|
( # Inside the subshell ...
|
|
inner_variable=Inner
|
|
echo $inner_variable
|
|
echo $inner_variable >>$TMPFILE # Append to temp file.
|
|
)
|
|
|
|
# Outside the subshell ...
|
|
|
|
echo; echo "-----"; echo
|
|
echo $inner_variable # Null, as expected.
|
|
echo "-----"; echo
|
|
|
|
# Now ...
|
|
read inner_variable <$TMPFILE # Read back shell variable.
|
|
rm -f "$TMPFILE" # Get rid of temp file.
|
|
echo "$inner_variable" # It's an ugly kludge, but it works.</programlisting>
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="runpartsref2"/></para>
|
|
<para>The <link linkend="runpartsref">run-parts</link>
|
|
command is handy for running a set of command
|
|
scripts in a particular sequence, especially in
|
|
combination with <link linkend="cronref">cron</link> or
|
|
<link linkend="atref">at</link>.</para>
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="rcsref"/></para>
|
|
<para>For doing multiple revisions on a complex script, use the
|
|
<firstterm>rcs</firstterm> Revision Control System package.</para>
|
|
|
|
<para> Among other benefits of this is automatically updated ID
|
|
header tags. The <command>co</command> command in
|
|
<firstterm>rcs</firstterm> does a parameter replacement of
|
|
certain reserved key words, for example, replacing
|
|
<parameter># $Id$</parameter> in a script with something like:
|
|
<programlisting># $Id$</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
|
|
<sect2>
|
|
<title>Widgets</title>
|
|
|
|
<para><anchor id="widgetref"/></para>
|
|
<para>It would be nice to be able to invoke X-Windows widgets
|
|
from a shell script. There happen to exist several packages
|
|
that purport to do so, namely <firstterm>Xscript</firstterm>,
|
|
<firstterm>Xmenu</firstterm>, and <firstterm>widtools</firstterm>.
|
|
The first two of these no longer seem
|
|
to be maintained. Fortunately, it is still
|
|
possible to obtain <firstterm>widtools</firstterm> <ulink
|
|
url="http://www.batse.msfc.nasa.gov/~mallozzi/home/software/xforms/src/widtools-2.0.tgz">here</ulink>.
|
|
</para>
|
|
|
|
<caution><para>The <firstterm>widtools</firstterm> (widget tools)
|
|
package requires the <firstterm>XForms</firstterm> library to
|
|
be installed. Additionally, the <link
|
|
linkend="makefileref">Makefile</link> needs some judicious
|
|
editing before the package will build on a typical Linux
|
|
system. Finally, three of the six widgets offered do not work
|
|
(and, in fact, segfault).</para></caution>
|
|
|
|
|
|
<para><anchor id="dialogref"/></para>
|
|
|
|
<para>The <firstterm>dialog</firstterm> family of tools offers a method
|
|
of calling <quote>dialog</quote> widgets from a shell script. The
|
|
original <firstterm>dialog</firstterm> utility works in a text
|
|
console, but its successors, <firstterm>gdialog</firstterm>,
|
|
<firstterm>Xdialog</firstterm>, and <firstterm>kdialog</firstterm>
|
|
use X-Windows-based widget sets.</para>
|
|
|
|
<example id="dialog">
|
|
<title>Widgets invoked from a shell script</title>
|
|
<programlisting>&dialog;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="xmessageref2"/>
|
|
The <link linkend="xmessageref">xmessage</link> command is
|
|
a simple method of popping up a message/query window. For
|
|
example:
|
|
<programlisting>xmessage Fatal error in script! -button exit</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="zenityref2"/>
|
|
The latest entry in the widget sweepstakes is
|
|
<link linkend="zenityref">zenity</link>.
|
|
This utility pops up
|
|
<firstterm>GTK+</firstterm> dialog widgets-and-windows,
|
|
and it works very nicely within a script.
|
|
<programlisting>get_info ()
|
|
{
|
|
zenity --entry # Pops up query window . . .
|
|
#+ and prints user entry to stdout.
|
|
|
|
# Also try the --calendar and --scale options.
|
|
}
|
|
|
|
answer=$( get_info ) # Capture stdout in $answer variable.
|
|
|
|
echo "User entered: "$answer""</programlisting>
|
|
</para>
|
|
|
|
<para>For other methods of scripting with widgets, try
|
|
<firstterm>Tk</firstterm> or <firstterm>wish</firstterm>
|
|
(<firstterm>Tcl</firstterm> derivatives),
|
|
<firstterm>PerlTk</firstterm> (<firstterm>Perl</firstterm>
|
|
with <firstterm>Tk</firstterm> extensions),
|
|
<firstterm>tksh</firstterm> (<firstterm>ksh</firstterm>
|
|
with <firstterm>Tk</firstterm> extensions),
|
|
<firstterm>XForms4Perl</firstterm>
|
|
(<firstterm>Perl</firstterm> with
|
|
<firstterm>XForms</firstterm> extensions),
|
|
<firstterm>Gtk-Perl</firstterm> (<firstterm>Perl</firstterm>
|
|
with <firstterm>Gtk</firstterm> extensions), or
|
|
<firstterm>PyQt</firstterm> (<firstterm>Python</firstterm>
|
|
with <firstterm>Qt</firstterm> extensions).</para>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
</sect1> <!-- Assorted Tips -->
|
|
|
|
|
|
|
|
<sect1 id="securityissues">
|
|
<title>Security Issues</title>
|
|
|
|
<sect2 id="infectedscripts">
|
|
<title>Infected Shell Scripts</title>
|
|
|
|
<para><anchor id="infectedscripts1"/></para>
|
|
<para>A brief warning about script security is indicated.
|
|
A shell script may contain a <firstterm>worm</firstterm>,
|
|
<firstterm>trojan</firstterm>, or even a
|
|
<firstterm>virus</firstterm>. For that reason, never run
|
|
as <firstterm>root</firstterm> a script (or permit it to
|
|
be inserted into the system startup scripts in <filename
|
|
class="directory">/etc/rc.d</filename>) unless you have obtained
|
|
said script from a trusted source or you have carefully analyzed
|
|
it to make certain it does nothing harmful.</para>
|
|
|
|
<para>Various researchers at Bell Labs and other sites, including M.
|
|
Douglas McIlroy, Tom Duff, and Fred Cohen have investigated the
|
|
implications of shell script viruses. They conclude that it is
|
|
all too easy for even a novice, a <quote>script kiddie,</quote>
|
|
to write one.
|
|
<footnote><para>See Marius van Oers' article, <ulink
|
|
url="http://www.virusbtn.com/magazine/archives/200204/malshell.xml">Unix
|
|
Shell Scripting Malware</ulink>, and also the
|
|
<link linkend="denningref"><emphasis>Denning</emphasis>
|
|
reference</link> in the
|
|
<firstterm>bibliography</firstterm>.</para></footnote>
|
|
</para>
|
|
|
|
<para>Here is yet another reason to learn scripting. Being able to
|
|
look at and understand scripts may protect your system from
|
|
being compromised by a rogue script.</para>
|
|
|
|
</sect2> <!-- Infected Shell Scripts -->
|
|
|
|
<sect2 id="hidingsource">
|
|
<title>Hiding Shell Script Source</title>
|
|
|
|
<para>For security purposes, it may be necessary to render a script
|
|
unreadable. If only there were a utility to create a stripped
|
|
binary executable from a script. Francisco Rosales' <ulink
|
|
url="http://www.datsi.fi.upm.es/~frosal/sources/">shc --
|
|
generic shell script compiler</ulink> does exactly that.</para>
|
|
|
|
<para>Unfortunately, according to <ulink
|
|
url="http://www.linuxjournal.com/article/8256">an article</ulink> in
|
|
the October, 2005 <emphasis>Linux Journal</emphasis>,
|
|
the binary can, in at least some cases, be decrypted to recover
|
|
the original script source. Still, this could be a useful
|
|
method of keeping scripts secure from all but the most skilled
|
|
hackers.</para>
|
|
|
|
</sect2> <!-- Hiding Shell Script Source -->
|
|
|
|
|
|
<sect2 id="securitytips">
|
|
<title>Writing Secure Shell Scripts</title>
|
|
|
|
<para><anchor id="securitytips1"/></para>
|
|
<para><emphasis>Dan Stromberg</emphasis> suggests the following
|
|
guidelines for writing (relatively) secure shell scripts.</para>
|
|
|
|
<para>
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>Don't put secret data in <link
|
|
linkend="envref">environment variables</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Don't pass secret data in an external
|
|
command's arguments (pass them in via a <link
|
|
linkend="piperef">pipe</link> or <link
|
|
linkend="ioredirref">redirection</link> instead).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Set your <link linkend="pathref">$PATH</link>
|
|
carefully. Don't just trust whatever path you
|
|
inherit from the caller if your script is running as
|
|
<firstterm>root</firstterm>. In fact, whenever you use
|
|
an environment variable inherited from the caller, think
|
|
about what could happen if the caller put something
|
|
misleading in the variable, e.g., if the caller set
|
|
<link linkend="homedirref">$HOME</link> to <filename
|
|
class="directory">/etc</filename>.</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
</sect2> <!-- Security Tips -->
|
|
|
|
</sect1> <!-- Security -->
|
|
|
|
|
|
|
|
<sect1 id="portabilityissues">
|
|
<title>Portability Issues</title>
|
|
|
|
<epigraph>
|
|
<para>It is easier to port a shell than a shell script.</para>
|
|
<para>--Larry Wall</para>
|
|
</epigraph>
|
|
|
|
<para>This book deals specifically with Bash scripting on
|
|
a GNU/Linux system. All the same, users of <command>sh</command>
|
|
and <command>ksh</command> will find much of value here.</para>
|
|
|
|
<para><anchor id="posix3ref"/>As it happens, many of the various
|
|
shells and scripting languages seem to be converging toward the
|
|
<link linkend="posix2ref">POSIX</link> 1003.2 standard. Invoking
|
|
Bash with the <option>--posix</option> option or inserting
|
|
a <command>set -o posix</command> at the head of a script
|
|
causes Bash to conform very closely to this standard. Another
|
|
alternative is to use a <firstterm>#!/bin/sh</firstterm> <link
|
|
linkend="shabangref">sha-bang header</link> in the script,
|
|
rather than <firstterm>#!/bin/bash</firstterm>.
|
|
|
|
<footnote><para>Or, better yet, <link
|
|
linkend="envv2ref">#!/bin/env sh</link>.</para></footnote>
|
|
|
|
Note that <filename>/bin/sh</filename> is a <link
|
|
linkend="linkref">link</link> to <filename>/bin/bash</filename>
|
|
in Linux and certain other flavors of UNIX, and a script invoked
|
|
this way disables extended Bash functionality.</para>
|
|
|
|
<para>Most Bash scripts will run as-is under
|
|
<command>ksh</command>, and vice-versa, since Chet Ramey has
|
|
been busily porting <command>ksh</command> features to the
|
|
latest versions of Bash.</para>
|
|
|
|
<para>On a commercial UNIX machine, scripts using GNU-specific
|
|
features of standard commands may not work. This has become less
|
|
of a problem in the last few years, as the GNU utilities have
|
|
pretty much displaced their proprietary
|
|
counterparts even on <quote>big-iron</quote> UNIX.
|
|
<ulink url="http://linux.oreillynet.com/pub/a/linux/2002/02/28/caldera.html">Caldera's
|
|
release of the source</ulink> to many of the original UNIX
|
|
utilities has accelerated the trend.</para>
|
|
|
|
<para><anchor id="bashcompat"/></para>
|
|
<para>Bash has certain features that the traditional <link
|
|
linkend="bashdef">Bourne shell</link> 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><link linkend="braceexpref3">Brace expansion</link></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Certain <link linkend="arrayref">array</link> operations,
|
|
and <link linkend="assocarr">associative arrays</link></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <link linkend="dblbrackets">double brackets</link>
|
|
extended test construct</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <link linkend="dblparensref">double-parentheses</link>
|
|
arithmetic-evaluation construct</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Certain <link linkend="stringmanip">string manipulation</link>
|
|
operations</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><link linkend="processsubref">Process substitution</link></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>A Regular Expression <link linkend="regexmatchref">matching
|
|
operator</link></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Bash-specific <link linkend="builtinref">builtins</link></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><link linkend="coprocref">Coprocesses</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>
|
|
|
|
<sect2> <!-- A Test Suite -->
|
|
<title>A Test Suite</title>
|
|
|
|
<para><anchor id="testsuite0"/>Let us illustrate some of the
|
|
incompatibilities between Bash and the classic
|
|
Bourne shell. Download and install the <ulink
|
|
url="http://freshmeat.net/projects/bournesh"><quote>Heirloom
|
|
Bourne Shell</quote></ulink> and run the following
|
|
script, first using Bash, then the classic
|
|
<firstterm>sh</firstterm>.</para>
|
|
|
|
<example id="testsuite">
|
|
<title>Test Suite</title>
|
|
<programlisting>&testsuite;</programlisting>
|
|
</example>
|
|
|
|
</sect2> <!-- End: A Test Suite -->
|
|
|
|
</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>Another alternative is <ulink
|
|
url="http://www2.research.att.com/~gsf/download/uwin/uwin.html">
|
|
UWIN</ulink>, written by David Korn of AT&T, of <link
|
|
linkend="kornshellref">Korn Shell</link> fame.</para>
|
|
|
|
<para>In 2006, Microsoft released the <trademark
|
|
class="registered">Windows Powershell</trademark>,
|
|
which contains limited Bash-like command-line scripting
|
|
capabilities.</para>
|
|
|
|
</sect1> <!-- Shell Scripting Under Windows -->
|
|
|
|
|
|
|
|
</chapter> <!-- Miscellany -->
|
|
|
|
|
|
|
|
<chapter id="bash2">
|
|
<title>Bash, versions 2, 3, and 4</title>
|
|
|
|
<sect1 id="bashver2">
|
|
<title>Bash, version 2</title>
|
|
|
|
<para><anchor id="bash2ref"/></para>
|
|
|
|
<para>
|
|
The current version of <firstterm>Bash</firstterm>, the one
|
|
you have running on your machine, is most likely version 2.xx.yy,
|
|
3.xx.yy, or 4.xx.yy.
|
|
<screen><prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
|
|
<computeroutput>3.2.25(1)-release</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The version 2 update of the classic Bash scripting language
|
|
added array variables, string and parameter expansion, and
|
|
a better method of indirect variable references, among other
|
|
features.</para>
|
|
|
|
<example id="ex77">
|
|
<title>String expansion</title>
|
|
<programlisting>&ex77;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="varrefnew"/></para>
|
|
<example id="ex78">
|
|
<title>Indirect variable references - the new way</title>
|
|
<programlisting>&ex78;</programlisting>
|
|
</example>
|
|
|
|
<example id="resistor">
|
|
<title>Simple database application, using indirect variable
|
|
referencing</title>
|
|
<programlisting>&resistor;</programlisting>
|
|
</example>
|
|
|
|
<example id="cards">
|
|
<title>Using arrays and other miscellaneous trickery
|
|
to deal four random hands from a deck of cards</title>
|
|
<programlisting>&cards;</programlisting>
|
|
</example>
|
|
|
|
</sect1> <!-- Bash, Version 2 -->
|
|
|
|
|
|
|
|
<sect1 id="bashver3">
|
|
<title>Bash, version 3</title>
|
|
|
|
<para><anchor id="bash3ref"/></para>
|
|
|
|
<para>On July 27, 2004, Chet Ramey released version 3 of Bash.
|
|
This update fixed quite a number of bugs and added new
|
|
features.</para>
|
|
|
|
<para>Some of the more important added features:
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><anchor id="braceexpref3"/></para>
|
|
<para>A new, more generalized <command>{a..z}</command> <link
|
|
linkend="braceexpref">brace expansion</link> operator.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
for i in {1..10}
|
|
# Simpler and more straightforward than
|
|
#+ for i in $(seq 10)
|
|
do
|
|
echo -n "$i "
|
|
done
|
|
|
|
echo
|
|
|
|
# 1 2 3 4 5 6 7 8 9 10
|
|
|
|
|
|
|
|
# Or just . . .
|
|
|
|
echo {a..z} # a b c d e f g h i j k l m n o p q r s t u v w x y z
|
|
echo {e..m} # e f g h i j k l m
|
|
echo {z..a} # z y x w v u t s r q p o n m l k j i h g f e d c b a
|
|
# Works backwards, too.
|
|
echo {25..30} # 25 26 27 28 29 30
|
|
echo {3..-2} # 3 2 1 0 -1 -2
|
|
echo {X..d} # X Y Z [ ] ^ _ ` a b c d
|
|
# Shows (some of) the ASCII characters between Z and a,
|
|
#+ but don't rely on this type of behavior because . . .
|
|
echo {]..a} # {]..a}
|
|
# Why?
|
|
|
|
|
|
# You can tack on prefixes and suffixes.
|
|
echo "Number #"{1..4}, "..."
|
|
# Number #1, Number #2, Number #3, Number #4, ...
|
|
|
|
|
|
# You can concatenate brace-expansion sets.
|
|
echo {1..3}{x..z}" +" "..."
|
|
# 1x + 1y + 1z + 2x + 2y + 2z + 3x + 3y + 3z + ...
|
|
# Generates an algebraic expression.
|
|
# This could be used to find permutations.
|
|
|
|
# You can nest brace-expansion sets.
|
|
echo {{a..c},{1..3}}
|
|
# a b c 1 2 3
|
|
# The "comma operator" splices together strings.
|
|
|
|
# ########## ######### ############ ########### ######### ###############
|
|
# Unfortunately, brace expansion does not lend itself to parameterization.
|
|
var1=1
|
|
var2=5
|
|
echo {$var1..$var2} # {1..5}
|
|
|
|
|
|
# Yet, as Emiliano G. points out, using "eval" overcomes this limitation.
|
|
|
|
start=0
|
|
end=10
|
|
for index in $(eval echo {$start..$end})
|
|
do
|
|
echo -n "$index " # 0 1 2 3 4 5 6 7 8 9 10
|
|
done
|
|
|
|
echo</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para>The <command>${!array[@]}</command> operator, which
|
|
expands to all the indices of a given <link
|
|
linkend="arrayref">array</link>.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
Array=(element-zero element-one element-two element-three)
|
|
|
|
echo ${Array[0]} # element-zero
|
|
# First element of array.
|
|
|
|
echo ${!Array[@]} # 0 1 2 3
|
|
# All the indices of Array.
|
|
|
|
for i in ${!Array[@]}
|
|
do
|
|
echo ${Array[i]} # element-zero
|
|
# element-one
|
|
# element-two
|
|
# element-three
|
|
#
|
|
# All the elements in Array.
|
|
done</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="regexmatchref"/></para>
|
|
<para>The <command>=~</command> <link linkend="regexref">Regular
|
|
Expression</link> matching operator within a <link
|
|
linkend="dblbrackets">double brackets</link> test expression.
|
|
(Perl has a similar operator.)</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
variable="This is a fine mess."
|
|
|
|
echo "$variable"
|
|
|
|
# Regex matching with =~ operator within [[ double brackets ]].
|
|
if [[ "$variable" =~ T.........fin*es* ]]
|
|
# NOTE: As of version 3.2 of Bash, expression to match no longer quoted.
|
|
then
|
|
echo "match found"
|
|
# match found
|
|
fi</programlisting></para>
|
|
|
|
<para>Or, more usefully:</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
|
|
input=$1
|
|
|
|
|
|
if [[ "$input" =~ "[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]" ]]
|
|
# ^ NOTE: Quoting not necessary, as of version 3.2 of Bash.
|
|
# NNN-NN-NNNN (where each N is a digit).
|
|
then
|
|
echo "Social Security number."
|
|
# Process SSN.
|
|
else
|
|
echo "Not a Social Security number!"
|
|
# Or, ask for corrected input.
|
|
fi</programlisting></para>
|
|
|
|
<para>For additional examples of using the
|
|
<command>=~</command> operator, see <xref linkend="whx"/>,
|
|
<xref linkend="mailboxgrep"/>, <xref
|
|
linkend="findsplit"/>, and <xref linkend="tohtml"/>.</para>
|
|
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="pipefailref"/></para>
|
|
<para>The new <option>set -o pipefail</option> option is
|
|
useful for debugging <link linkend="piperef">pipes</link>. If
|
|
this option is set, then the <link
|
|
linkend="exitstatusref">exit status</link> of a pipe
|
|
is the exit status of the last command in the pipe to
|
|
<emphasis>fail</emphasis> (return a non-zero value), rather
|
|
than the actual final command in the pipe.</para>
|
|
<para>See <xref linkend="fc4upd"/>.</para>
|
|
</listitem>
|
|
|
|
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<caution>
|
|
<para>The update to version 3 of Bash breaks a few scripts
|
|
that worked under earlier versions. <emphasis>Test critical legacy
|
|
scripts to make sure they still work!</emphasis></para>
|
|
<para>As it happens, a couple of the scripts in the
|
|
<emphasis>Advanced Bash Scripting Guide</emphasis> had to be
|
|
fixed up (see <xref linkend="tout"/>, for instance).</para>
|
|
</caution>
|
|
|
|
|
|
<sect2> <!-- Bash, Version 3.1 -->
|
|
<title>Bash, version 3.1</title>
|
|
|
|
<para>The version 3.1 update of Bash introduces a number of bugfixes
|
|
and a few minor changes.</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>The <token>+=</token> operator is now permitted in
|
|
in places where previously only the <token>=</token>
|
|
assignment operator was recognized.</para>
|
|
|
|
<para><anchor id="pluseqstr"/></para>
|
|
|
|
<para><programlisting>a=1
|
|
echo $a # 1
|
|
|
|
a+=5 # Won't work under versions of Bash earlier than 3.1.
|
|
echo $a # 15
|
|
|
|
a+=Hello
|
|
echo $a # 15Hello</programlisting>
|
|
</para>
|
|
|
|
<para>Here, <token>+=</token> functions as a <firstterm>string
|
|
concatenation</firstterm> operator. Note that its behavior
|
|
in this particular context is different than within a
|
|
<link linkend="letref">let</link> construct.</para>
|
|
|
|
<para><programlisting>a=1
|
|
echo $a # 1
|
|
|
|
let a+=5 # Integer arithmetic, rather than string concatenation.
|
|
echo $a # 6
|
|
|
|
let a+=Hello # Doesn't "add" anything to a.
|
|
echo $a # 6</programlisting>
|
|
</para>
|
|
|
|
<para><anchor id="pathappend"/>Jeffrey Haemer points out
|
|
that this concatenation operator can be quite
|
|
useful. In this instance, we append a directory to the
|
|
<varname>$PATH</varname>.</para>
|
|
|
|
<para>
|
|
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>echo $PATH</userinput>
|
|
<computeroutput>/usr/bin:/bin:/usr/local/bin:/usr/X11R6/bin/:/usr/games</computeroutput>
|
|
|
|
|
|
<prompt>bash$ </prompt><userinput>PATH+=:/opt/bin</userinput>
|
|
|
|
<prompt>bash$ </prompt><userinput>echo $PATH</userinput>
|
|
<computeroutput>/usr/bin:/bin:/usr/local/bin:/usr/X11R6/bin/:/usr/games:/opt/bin</computeroutput>
|
|
</screen>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
</sect2> <!-- Bash, Version 3.1 -->
|
|
|
|
|
|
|
|
<sect2> <!-- Bash, Version 3.2 -->
|
|
<title>Bash, version 3.2</title>
|
|
|
|
<para>This is pretty much a bugfix update.</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>In <link linkend="psglob"><firstterm>global</firstterm>
|
|
parameter substitutions</link>, the pattern no longer anchors
|
|
at the start of the string.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <option>--wordexp</option> option disables
|
|
<link linkend="processsubref">process substitution</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <command>=~</command> <link
|
|
linkend="regexmatchref">Regular Expression
|
|
match operator</link> no longer requires
|
|
<link linkend="quotingref">quoting</link> of the
|
|
<firstterm>pattern</firstterm> within <link
|
|
linkend="dblbrackets">[[ ... ]]</link>.</para>
|
|
|
|
<caution>
|
|
<para>In fact, quoting in this context is
|
|
<emphasis>not</emphasis> advisable as it may
|
|
cause <firstterm>regex</firstterm> evaluation to fail.
|
|
Chet Ramey states in the <link linkend="bashfaq">Bash
|
|
FAQ</link> that quoting explicitly disables regex evaluation.
|
|
See also the <ulink
|
|
url="https://bugs.launchpad.net/ubuntu-website/+bug/109931">
|
|
Ubuntu Bug List</ulink> and <ulink
|
|
url="http://en.wikinerds.org/index.php/Bash_syntax_and_semantics">
|
|
Wikinerds on Bash syntax</ulink>.</para>
|
|
|
|
<para>Setting <emphasis>shopt -s compat31</emphasis>
|
|
in a script causes reversion to the original
|
|
behavior.</para>
|
|
</caution>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</sect2> <!-- Bash, Version 3.2 -->
|
|
|
|
|
|
</sect1> <!-- Bash, Version 3 -->
|
|
|
|
|
|
|
|
<sect1 id="bashver4">
|
|
<title>Bash, version 4</title>
|
|
|
|
<para><anchor id="bash4ref"/></para>
|
|
<para>Chet Ramey announced Version 4 of Bash on the 20th
|
|
of February, 2009. This release has a number of significant
|
|
new features, as well as some important bugfixes.</para>
|
|
|
|
<para>Among the new goodies:</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para><anchor id="assocarr"/>Associative arrays.
|
|
<footnote><para>To be more specific, Bash 4+ has
|
|
<emphasis>limited</emphasis> support for associative
|
|
arrays. It's a bare-bones implementation,
|
|
and it lacks the much of the functionality of such
|
|
arrays in other programming languages. Note, however,
|
|
that <link linkend="assocarrtst">associative arrays in
|
|
Bash seem to execute faster and more efficiently than
|
|
numerically-indexed arrays</link>.</para></footnote>
|
|
</para>
|
|
|
|
<sidebar>
|
|
<para>An <firstterm>associative</firstterm> array can
|
|
be thought of as a set of two linked arrays -- one holding
|
|
the <firstterm>data</firstterm>, and the other the
|
|
<firstterm>keys</firstterm> that index the individual elements
|
|
of the <firstterm>data</firstterm> array.</para>
|
|
</sidebar>
|
|
|
|
<example id="fetchaddress">
|
|
<title>A simple address database</title>
|
|
<programlisting>&fetchaddress;</programlisting>
|
|
</example>
|
|
|
|
<example id="fetchaddress2">
|
|
<title>A somewhat more elaborate address database</title>
|
|
<programlisting>&fetchaddress2;</programlisting>
|
|
</example>
|
|
|
|
<para>See <xref linkend="samorse"/> for an interesting
|
|
usage of an <firstterm>associative array</firstterm>.</para>
|
|
|
|
<caution><para>Elements of the <firstterm>index</firstterm> array
|
|
may include embedded <link linkend="whitespaceref">space
|
|
characters</link>, or even leading and/or trailing space
|
|
characters. However, index array elements containing
|
|
<emphasis>only</emphasis> <firstterm>whitespace</firstterm>
|
|
are <emphasis>not</emphasis> permitted.</para>
|
|
<para><programlisting>address[ ]="Blank" # Error!</programlisting>
|
|
</para></caution>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="ncterm"/>Enhancements to the
|
|
<link linkend="caseesac1">case</link> construct:
|
|
the <replaceable>;;&</replaceable> and
|
|
<replaceable>;&</replaceable> terminators.</para>
|
|
|
|
<example id="case4">
|
|
<title>Testing characters</title>
|
|
<programlisting>&case4;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="coprocref"/>The new <command>coproc</command>
|
|
builtin enables two parallel <link
|
|
linkend="processref">processes</link> to communicate and
|
|
interact. As Chet Ramey states in the
|
|
<link linkend="bashfaq">Bash FAQ</link>
|
|
<footnote><para>Copyright 1995-2009 by Chester Ramey.</para></footnote>
|
|
, ver. 4.01:
|
|
</para>
|
|
|
|
<blockquote>
|
|
<literallayout>
|
|
There is a new 'coproc' reserved word that specifies a coprocess:
|
|
an asynchronous command run with two pipes connected to the creating
|
|
shell. Coprocs can be named. The input and output file descriptors
|
|
and the PID of the coprocess are available to the calling shell in
|
|
variables with coproc-specific names.
|
|
|
|
George Dimitriu explains,
|
|
"... coproc ... is a feature used in Bash process substitution,
|
|
which now is made publicly available."
|
|
This means it can be explicitly invoked in a script, rather than
|
|
just being a behind-the-scenes mechanism used by Bash.
|
|
</literallayout>
|
|
</blockquote>
|
|
|
|
<para>Coprocesses use <firstterm>file descriptors</firstterm>.
|
|
<link linkend="fdref2">File descriptors enable processes and
|
|
pipes to communicate</link>.</para>
|
|
|
|
<para><programlisting>#!/bin/bash4
|
|
# A coprocess communicates with a while-read loop.
|
|
|
|
|
|
coproc { cat mx_data.txt; sleep 2; }
|
|
# ^^^^^^^
|
|
# Try running this without "sleep 2" and see what happens.
|
|
|
|
while read -u ${COPROC[0]} line # ${COPROC[0]} is the
|
|
do #+ file descriptor of the coprocess.
|
|
echo "$line" | sed -e 's/line/NOT-ORIGINAL-TEXT/'
|
|
done
|
|
|
|
kill $COPROC_PID # No longer need the coprocess,
|
|
#+ so kill its PID.</programlisting></para>
|
|
|
|
<para>But, be careful!</para>
|
|
|
|
<para><programlisting>#!/bin/bash4
|
|
|
|
echo; echo
|
|
a=aaa
|
|
b=bbb
|
|
c=ccc
|
|
|
|
coproc echo "one two three"
|
|
while read -u ${COPROC[0]} a b c; # Note that this loop
|
|
do #+ runs in a subshell.
|
|
echo "Inside while-read loop: ";
|
|
echo "a = $a"; echo "b = $b"; echo "c = $c"
|
|
echo "coproc file descriptor: ${COPROC[0]}"
|
|
done
|
|
|
|
# a = one
|
|
# b = two
|
|
# c = three
|
|
# So far, so good, but ...
|
|
|
|
echo "-----------------"
|
|
echo "Outside while-read loop: "
|
|
echo "a = $a" # a =
|
|
echo "b = $b" # b =
|
|
echo "c = $c" # c =
|
|
echo "coproc file descriptor: ${COPROC[0]}"
|
|
echo
|
|
# The coproc is still running, but ...
|
|
#+ it still doesn't enable the parent process
|
|
#+ to "inherit" variables from the child process, the while-read loop.
|
|
|
|
# Compare this to the "badread.sh" script.</programlisting></para>
|
|
|
|
<caution>
|
|
<para>The coprocess is <firstterm>asynchronous</firstterm>,
|
|
and this might cause a problem. It may terminate before another
|
|
process has finished communicating with it.</para>
|
|
|
|
<programlisting>#!/bin/bash4
|
|
|
|
coproc cpname { for i in {0..10}; do echo "index = $i"; done; }
|
|
# ^^^^^^ This is a *named* coprocess.
|
|
read -u ${cpname[0]}
|
|
echo $REPLY # index = 0
|
|
echo ${COPROC[0]} #+ No output ... the coprocess timed out
|
|
# after the first loop iteration.
|
|
|
|
|
|
|
|
# However, George Dimitriu has a partial fix.
|
|
|
|
coproc cpname { for i in {0..10}; do echo "index = $i"; done; sleep 1;
|
|
echo hi > myo; cat - >> myo; }
|
|
# ^^^^^ This is a *named* coprocess.
|
|
|
|
echo "I am main"$'\04' >&${cpname[1]}
|
|
myfd=${cpname[0]}
|
|
echo myfd=$myfd
|
|
|
|
### while read -u $myfd
|
|
### do
|
|
### echo $REPLY;
|
|
### done
|
|
|
|
echo $cpname_PID
|
|
|
|
# Run this with and without the commented-out while-loop, and it is
|
|
#+ apparent that each process, the executing shell and the coprocess,
|
|
#+ waits for the other to finish writing in its own write-enabled pipe.</programlisting>
|
|
</caution>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para><anchor id="mapfileref"/>The new <command>mapfile</command>
|
|
builtin makes it possible to load an array with the contents
|
|
of a text file without using a loop or <link
|
|
linkend="arrayinitcs">command substitution</link>.</para>
|
|
|
|
<para><programlisting>#!/bin/bash4
|
|
|
|
mapfile Arr1 < $0
|
|
# Same result as Arr1=( $(cat $0) )
|
|
echo "${Arr1[@]}" # Copies this entire script out to stdout.
|
|
|
|
echo "--"; echo
|
|
|
|
# But, not the same as read -a !!!
|
|
read -a Arr2 < $0
|
|
echo "${Arr2[@]}" # Reads only first line of script into the array.
|
|
|
|
exit</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <link linkend="readref">read</link> builtin got
|
|
a minor facelift. The <option>-t</option>
|
|
<link linkend="readtimed">timeout</link> option now accepts
|
|
(decimal) fractional values
|
|
<footnote><para>This only works with <link
|
|
linkend="piperef">pipes</link> and certain other
|
|
<firstterm>special</firstterm> files.</para></footnote>
|
|
and the <option>-i</option> option
|
|
permits preloading the edit buffer.
|
|
<footnote><para>But only in conjunction with
|
|
<link linkend="readlineref">readline</link>, i.e.,
|
|
from the command-line.</para></footnote>
|
|
Unfortunately, these enhancements are still a work in progress
|
|
and not (yet) usable in scripts.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="casemodparamsub"/>
|
|
<link linkend="paramsubref">Parameter substitution</link>
|
|
gets <firstterm>case-modification</firstterm> operators.</para>
|
|
|
|
<para><programlisting>#!/bin/bash4
|
|
|
|
var=veryMixedUpVariable
|
|
echo ${var} # veryMixedUpVariable
|
|
echo ${var^} # VeryMixedUpVariable
|
|
# * First char --> uppercase.
|
|
echo ${var^^} # VERYMIXEDUPVARIABLE
|
|
# ** All chars --> uppercase.
|
|
echo ${var,} # veryMixedUpVariable
|
|
# * First char --> lowercase.
|
|
echo ${var,,} # verymixedupvariable
|
|
# ** All chars --> lowercase.</programlisting></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="declarecasemod"/></para>
|
|
<para>The <link linkend="declareref">declare</link> builtin now
|
|
accepts the <option>-l</option> <firstterm>lowercase</firstterm>
|
|
and <option>-c</option> <firstterm>capitalize</firstterm>
|
|
options.</para>
|
|
|
|
<para><programlisting>#!/bin/bash4
|
|
|
|
declare -l var1 # Will change to lowercase
|
|
var1=MixedCaseVARIABLE
|
|
echo "$var1" # mixedcasevariable
|
|
# Same effect as echo $var1 | tr A-Z a-z
|
|
|
|
declare -c var2 # Changes only initial char to uppercase.
|
|
var2=originally_lowercase
|
|
echo "$var2" # Originally_lowercase
|
|
# NOT the same effect as echo $var2 | tr a-z A-Z</programlisting></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="braceexpref4"/>
|
|
<link linkend="braceexpref">Brace expansion</link> has more options.</para>
|
|
|
|
<para><firstterm>Increment/decrement</firstterm>, specified in the
|
|
final term within braces.</para>
|
|
<para><programlisting>#!/bin/bash4
|
|
|
|
echo {40..60..2}
|
|
# 40 42 44 46 48 50 52 54 56 58 60
|
|
# All the even numbers, between 40 and 60.
|
|
|
|
echo {60..40..2}
|
|
# 60 58 56 54 52 50 48 46 44 42 40
|
|
# All the even numbers, between 40 and 60, counting backwards.
|
|
# In effect, a decrement.
|
|
echo {60..40..-2}
|
|
# The same output. The minus sign is not necessary.
|
|
|
|
# But, what about letters and symbols?
|
|
echo {X..d}
|
|
# X Y Z [ ] ^ _ ` a b c d
|
|
# Does not echo the \ which escapes a space.</programlisting></para>
|
|
|
|
<para><firstterm>Zero-padding</firstterm>, specified in the
|
|
first term within braces, prefixes each term in the output
|
|
with the <emphasis>same number</emphasis> of zeroes.</para>
|
|
|
|
<screen>
|
|
<prompt>bash4$ </prompt><userinput>echo {010..15}</userinput>
|
|
<computeroutput>010 011 012 013 014 015</computeroutput>
|
|
|
|
|
|
<prompt>bash4$ </prompt><userinput>echo {000..10}</userinput>
|
|
<computeroutput>000 001 002 003 004 005 006 007 008 009 010</computeroutput>
|
|
</screen>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="substrextref4"/></para>
|
|
<para><link linkend="substrextref4"><firstterm>Substring
|
|
extraction</firstterm> on <firstterm>positional
|
|
parameters</firstterm></link> now starts with <link
|
|
linkend="scrnameparam">$0</link> as the
|
|
<firstterm>zero-index</firstterm>. (This corrects an
|
|
inconsistency in the treatment of positional parameters.)</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
# show-params.bash
|
|
# Requires version 4+ of Bash.
|
|
|
|
# Invoke this scripts with at least one positional parameter.
|
|
|
|
E_BADPARAMS=99
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
echo "Usage $0 param1 ..."
|
|
exit $E_BADPARAMS
|
|
fi
|
|
|
|
echo ${@:0}
|
|
|
|
# bash3 show-params.bash4 one two three
|
|
# one two three
|
|
|
|
# bash4 show-params.bash4 one two three
|
|
# show-params.bash4 one two three
|
|
|
|
# $0 $1 $2 $3</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="globstarref"/>The new <token>**</token>
|
|
<link linkend="globbingref">globbing</link> operator
|
|
matches filenames and directories
|
|
<link linkend="recursionref0">recursively</link>.</para>
|
|
|
|
<para><programlisting>#!/bin/bash4
|
|
# filelist.bash4
|
|
|
|
shopt -s globstar # Must enable globstar, otherwise ** doesn't work.
|
|
# The globstar shell option is new to version 4 of Bash.
|
|
|
|
echo "Using *"; echo
|
|
for filename in *
|
|
do
|
|
echo "$filename"
|
|
done # Lists only files in current directory ($PWD).
|
|
|
|
echo; echo "--------------"; echo
|
|
|
|
echo "Using **"
|
|
for filename in **
|
|
do
|
|
echo "$filename"
|
|
done # Lists complete file tree, recursively.
|
|
|
|
exit
|
|
|
|
Using *
|
|
|
|
allmyfiles
|
|
filelist.bash4
|
|
|
|
--------------
|
|
|
|
Using **
|
|
|
|
allmyfiles
|
|
allmyfiles/file.index.txt
|
|
allmyfiles/my_music
|
|
allmyfiles/my_music/me-singing-60s-folksongs.ogg
|
|
allmyfiles/my_music/me-singing-opera.ogg
|
|
allmyfiles/my_music/piano-lesson.1.ogg
|
|
allmyfiles/my_pictures
|
|
allmyfiles/my_pictures/at-beach-with-Jade.png
|
|
allmyfiles/my_pictures/picnic-with-Melissa.png
|
|
filelist.bash4</programlisting></para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The new <link linkend="bashpidref">$BASHPID</link>
|
|
internal variable.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><anchor id="cnfh"/></para>
|
|
<para>There is a new <link linkend="builtinref">builtin</link>
|
|
error-handling function named
|
|
<command>command_not_found_handle</command>.</para>
|
|
<para><programlisting>#!/bin/bash4
|
|
|
|
command_not_found_handle ()
|
|
{ # Accepts implicit parameters.
|
|
echo "The following command is not valid: \""$1\"""
|
|
echo "With the following argument(s): \""$2\"" \""$3\""" # $4, $5 ...
|
|
} # $1, $2, etc. are not explicitly passed to the function.
|
|
|
|
bad_command arg1 arg2
|
|
|
|
# The following command is not valid: "bad_command"
|
|
# With the following argument(s): "arg1" "arg2"</programlisting></para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<sidebar>
|
|
<para><emphasis>Editorial comment</emphasis></para>
|
|
<para>Associative arrays? Coprocesses? Whatever happened
|
|
to the lean and mean Bash we have come to know and love?
|
|
Could it be suffering from (horrors!) <quote>feature
|
|
creep</quote>? Or perhaps even Korn shell envy?</para>
|
|
<para><emphasis>Note to Chet Ramey:</emphasis> Please add only
|
|
<emphasis>essential</emphasis> features in future Bash
|
|
releases -- perhaps <firstterm>for-each</firstterm>
|
|
loops and support for multi-dimensional arrays.
|
|
<footnote><para>And while you're at it, consider fixing
|
|
the notorious <link linkend="pipereadref0">piped read</link>
|
|
problem.</para></footnote>
|
|
Most Bash users won't need, won't use, and likely won't greatly
|
|
appreciate complex <quote>features</quote> like built-in
|
|
debuggers, Perl interfaces, and bolt-on rocket boosters.</para>
|
|
</sidebar>
|
|
|
|
|
|
<sect2> <!-- Bash, Version 4.1 -->
|
|
<title>Bash, version 4.1</title>
|
|
|
|
<para><anchor id="bash41"/>Version 4.1 of Bash, released in May,
|
|
2010, was primarily a bugfix update.</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>The <link linkend="printfref">printf</link> command
|
|
now accepts a <option>-v</option> option for setting <link
|
|
linkend="arrayref">array</link> indices.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Within <link linkend="dblbrackets">double brackets</link>,
|
|
the <command>></command> and <command><</command>
|
|
string comparison operators now conform to the <link
|
|
linkend="localeref">locale</link>. Since the locale setting may
|
|
affect the sorting order of string expressions, this
|
|
has side-effects on comparison tests within
|
|
<emphasis>[[ ... ]]</emphasis> expressions.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <link linkend="readref">read</link> builtin
|
|
now takes a <option>-N</option> option (<firstterm>read -N
|
|
chars</firstterm>), which causes the <firstterm>read</firstterm>
|
|
to terminate after <firstterm>chars</firstterm>
|
|
characters.</para>
|
|
|
|
<example id="readn">
|
|
<title>Reading N characters</title>
|
|
<programlisting>&readn;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><link linkend="heredocref">Here documents</link>
|
|
embedded in <link linkend="commandsubref0">
|
|
<userinput>$( ... )</userinput> command substitution</link>
|
|
constructs may terminate with a simple
|
|
<command>)</command>.</para>
|
|
|
|
<example id="herecommsub">
|
|
<title>Using a <firstterm>here document</firstterm>
|
|
to set a variable</title>
|
|
<programlisting>&herecommsub;</programlisting>
|
|
</example>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</sect2> <!-- Bash, Version 4.1 -->
|
|
|
|
|
|
<sect2> <!-- Bash, Version 4.2 -->
|
|
<title>Bash, version 4.2</title>
|
|
|
|
<para><anchor id="bash42"/>Version 4.2 of Bash, released
|
|
in February, 2011, contains a number of new features and
|
|
enhancements, in addition to bugfixes.</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>Bash now supports the
|
|
<replaceable>\u</replaceable>
|
|
and <replaceable>\U</replaceable>
|
|
<firstterm>Unicode</firstterm> escape.</para>
|
|
|
|
<para><anchor id="unicoderef"/></para>
|
|
<sidebar><para>Unicode is a cross-platform standard for encoding
|
|
into numerical values letters and graphic symbols.
|
|
This permits representing and displaying characters
|
|
in foreign alphabets and unusual fonts.</para></sidebar>
|
|
<para><anchor id="unicoderef2"/></para>
|
|
|
|
<para><programlisting>echo -e '\u2630' # Horizontal triple bar character.
|
|
# Equivalent to the more roundabout:
|
|
echo -e "\xE2\x98\xB0"
|
|
# Recognized by earlier Bash versions.
|
|
|
|
echo -e '\u220F' # PI (Greek letter and mathematical symbol)
|
|
echo -e '\u0416' # Capital "ZHE" (Cyrillic letter)
|
|
echo -e '\u2708' # Airplane (Dingbat font) symbol
|
|
echo -e '\u2622' # Radioactivity trefoil
|
|
|
|
echo -e "The amplifier circuit requires a 100 \u2126 pull-up resistor."
|
|
|
|
|
|
unicode_var='\u2640'
|
|
echo -e $unicode_var # Female symbol
|
|
printf "$unicode_var \n" # Female symbol, with newline
|
|
|
|
|
|
# And for something a bit more elaborate . . .
|
|
|
|
# We can store Unicode symbols in an associative array,
|
|
#+ then retrieve them by name.
|
|
# Run this in a gnome-terminal or a terminal with a large, bold font
|
|
#+ for better legibility.
|
|
|
|
declare -A symbol # Associative array.
|
|
|
|
symbol[script_E]='\u2130'
|
|
symbol[script_F]='\u2131'
|
|
symbol[script_J]='\u2110'
|
|
symbol[script_M]='\u2133'
|
|
symbol[Rx]='\u211E'
|
|
symbol[TEL]='\u2121'
|
|
symbol[FAX]='\u213B'
|
|
symbol[care_of]='\u2105'
|
|
symbol[account]='\u2100'
|
|
symbol[trademark]='\u2122'
|
|
|
|
|
|
echo -ne "${symbol[script_E]} "
|
|
echo -ne "${symbol[script_F]} "
|
|
echo -ne "${symbol[script_J]} "
|
|
echo -ne "${symbol[script_M]} "
|
|
echo -ne "${symbol[Rx]} "
|
|
echo -ne "${symbol[TEL]} "
|
|
echo -ne "${symbol[FAX]} "
|
|
echo -ne "${symbol[care_of]} "
|
|
echo -ne "${symbol[account]} "
|
|
echo -ne "${symbol[trademark]} "
|
|
echo</programlisting></para>
|
|
|
|
<note>
|
|
<para>The above example uses the
|
|
<link linkend="strq"><command>$' ... '</command></link>
|
|
<firstterm>string-expansion</firstterm> construct.</para>
|
|
</note>
|
|
|
|
</listitem>
|
|
|
|
|
|
<listitem>
|
|
<para><anchor id="lastpiperef"/></para>
|
|
<para>When the <replaceable>lastpipe</replaceable> shell option
|
|
is set, the last command in a <link
|
|
linkend="piperef">pipe</link> <emphasis>doesn't run in a
|
|
subshell</emphasis>.</para>
|
|
|
|
<example id="lastpipeopt">
|
|
<title>Piping input to a <link
|
|
linkend="readref">read</link></title>
|
|
<programlisting>&lastpipeopt;</programlisting>
|
|
</example>
|
|
|
|
<para>This option offers possible <quote>fixups</quote>
|
|
for these example scripts:
|
|
<xref linkend="badread"/> and
|
|
<xref linkend="readpipe"/>.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
<para>Negative <link linkend="arrayref">array</link> indices
|
|
permit counting backwards from the end of an array.</para>
|
|
|
|
<example id="negarray">
|
|
<title>Negative array indices</title>
|
|
<programlisting>&negarray;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><link linkend="substrextr01">Substring extraction</link>
|
|
uses a negative <firstterm>length</firstterm> parameter to
|
|
specify an offset from the <firstterm>end</firstterm> of the
|
|
target string.</para>
|
|
|
|
<example id="negoffset">
|
|
<title>Negative parameter in string-extraction
|
|
construct</title>
|
|
<programlisting>&negoffset;</programlisting>
|
|
</example>
|
|
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</sect2> <!-- Bash, Version 4.2 -->
|
|
|
|
|
|
|
|
</sect1> <!-- Bash, Version 4 -->
|
|
|
|
|
|
|
|
|
|
</chapter> <!-- Bash, versions 2, 3, and 4 -->
|
|
|
|
</part> <!-- Part 5 (Advanced Topics) -->
|
|
|
|
|
|
|
|
<chapter id="endnotes">
|
|
<title>Endnotes</title>
|
|
|
|
|
|
<sect1 id="authorsnote">
|
|
<title>Author's Note</title>
|
|
|
|
<epigraph>
|
|
<para><foreignphrase>doce ut discas</foreignphrase></para>
|
|
<para>(Teach, that you yourself may learn.)</para>
|
|
</epigraph>
|
|
|
|
|
|
<para>How did I come to write a scripting book? It's a strange
|
|
tale. It seems that a few years back I needed to learn
|
|
shell scripting -- and what better way to do that than to read a
|
|
good book on the subject? I was looking to buy a tutorial and
|
|
reference covering all aspects of the subject. I was looking for a
|
|
book that would take difficult concepts, turn them inside out, and
|
|
explain them in excruciating detail, with well-commented examples.
|
|
<footnote><para>This is the notorious <emphasis>flog
|
|
it to death</emphasis> technique that works so well
|
|
with slow learners, eccentrics, odd ducks, fools and
|
|
geniuses.</para></footnote>
|
|
In fact, I was looking for <emphasis>this very book</emphasis>,
|
|
or something very much like it. Unfortunately, <link
|
|
linkend="kochanref">it didn't exist</link>, and if I wanted it,
|
|
I'd have to write it. And so, here we are, folks.</para>
|
|
|
|
<para>That reminds me of the apocryphal story about a mad
|
|
professor. Crazy as a loon, the fellow was. At the sight of a
|
|
book, any book -- at the library, at a bookstore, anywhere --
|
|
he would become totally obsessed with the idea that he could have
|
|
written it, should have written it -- and done a better job of it
|
|
to boot. He would thereupon rush home and proceed to do just that,
|
|
write a book with the very same title. When he died some years
|
|
later, he allegedly had several thousand books to his credit,
|
|
probably putting even Asimov to shame. The books might not have
|
|
been any good, who knows, but does that really matter? Here's
|
|
a fellow who lived his dream, even if he was obsessed by it,
|
|
driven by it . . . and somehow I can't help admiring the old
|
|
coot.</para>
|
|
|
|
</sect1> <!-- Author's Note -->
|
|
|
|
|
|
|
|
<sect1 id="aboutauthor">
|
|
<title>About the Author</title>
|
|
<subtitle>Who is this guy anyhow?</subtitle>
|
|
|
|
<para><anchor id="nocreds"/>The author claims no credentials or
|
|
special qualifications,
|
|
|
|
<footnote><para>In fact, he has no credentials or special
|
|
qualifications. He's a school dropout with no formal credentials
|
|
or professional experience whatsoever. None. Zero. Nada. Aside
|
|
from the <emphasis>ABS Guide</emphasis>, his major claim to
|
|
fame is a First Place in the sack race at the Colfax Elementary
|
|
School Field Day in June, 1958.</para></footnote>
|
|
|
|
other than a compulsion to write.
|
|
|
|
<footnote><para>Those who can, do. Those who can't . . . get an
|
|
MCSE.</para></footnote>
|
|
|
|
</para>
|
|
|
|
<para>This book is somewhat of a departure from his other major work,
|
|
<ulink url="http://bash.deta.in/hmw60.zip">
|
|
HOW-2 Meet Women: The Shy Man's Guide to
|
|
Relationships</ulink>. He has also written the <ulink
|
|
url="http://tldp.org/HOWTO/Software-Building-HOWTO.html">Software-Building
|
|
HOWTO</ulink>. Of late, he has been trying his
|
|
(heavy) hand at fiction: <ulink
|
|
url="http://bash.deta.in/dave-dawson-over-berlin.epub">Dave Dawson
|
|
Over Berlin (First Installment)</ulink>
|
|
<ulink url="http://bash.deta.in/dave-dawson-over-berlin.II.epub">Dave Dawson
|
|
Over Berlin (Second Installment)</ulink> and
|
|
<ulink url="http://bash.deta.in/dave-dawson-over-berlin.III.epub">Dave Dawson
|
|
Over Berlin (Third Installment)</ulink>
|
|
|
|
. He also has a few
|
|
<emphasis>Instructables</emphasis> (<ulink
|
|
url="http://www.instructables.com/id/Arduino-Morse-Code-Shield/">here</ulink>,
|
|
<ulink
|
|
url="http://www.instructables.com/id/Haywired-Hackduino/">here</ulink>,
|
|
<ulink
|
|
url="http://www.instructables.com/id/Arduino-DIY-SD-Card-Logging-Shield/">here</ulink>,
|
|
<ulink
|
|
url="http://www.instructables.com/id/Binguino-An-Arduino-based-Bingo-Number-Generato/">here</ulink>,
|
|
<ulink
|
|
url="http://www.instructables.com/id/The-Raspberry-Pi-Lapdock-Connection/">here</ulink>,
|
|
|
|
<ulink
|
|
url="http://www.instructables.com/id/The-Raspberry-Pi-Arduino-Connection/">here</ulink>, and
|
|
<ulink
|
|
url="http://www.instructables.com/id/Switchable-Dual-Voltage-33v5v-Hacduino/">here</ulink>
|
|
to his (dis)credit.</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, the <ulink
|
|
url="http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz">yawl</ulink>
|
|
word gaming list package, and the <ulink
|
|
url="http://bash.deta.in/qky.README.html">Quacky</ulink>
|
|
anagramming gaming package. He got off to a rather shaky start in the
|
|
computer game -- programming FORTRAN IV on a CDC 3800 (on paper coding
|
|
pads, with occasional forays on a keypunch machine and a Friden
|
|
Flexowriter) -- and is not the least bit nostalgic for those
|
|
days.</para>
|
|
|
|
<para>Living in an out-of-the-way community with wife and orange
|
|
tabby, he cherishes human frailty, especially his own.
|
|
<footnote><para>Sometimes it seems as if he has spent
|
|
his entire life flouting conventional wisdom and defying the
|
|
sonorous Voice of Authority: <quote><emphasis>Hey, you
|
|
can't do that!</emphasis></quote></para></footnote>
|
|
</para>
|
|
|
|
</sect1> <!-- About the Author -->
|
|
|
|
|
|
|
|
<sect1 id="wherehelp">
|
|
<title>Where to Go For Help</title>
|
|
|
|
<para><ulink url="mailto:thegrendel.abs@gmail.com">The author</ulink>
|
|
is no longer supporting or updating this document. He will not
|
|
answer questions about this book or about general scripting topics.
|
|
</para>
|
|
|
|
<sidebar>
|
|
<para>If you need assistance with a schoolwork assignment,
|
|
read the pertinent sections of this and other reference works.
|
|
Do your best to solve the problem using your own wits and
|
|
resources. <emphasis>Please do not waste the author's time.</emphasis>
|
|
You will get neither help nor sympathy.
|
|
<footnote><para>Well, if you <emphasis>absolutely</emphasis>
|
|
insist, you can try modifying <xref linkend="homework"/> to suit
|
|
your purposes.</para></footnote>
|
|
</para>
|
|
<para>Likewise, kindly refrain from annoying the author
|
|
with solicitations, offers of employment, or <quote>business
|
|
opportunities.</quote> He is doing just fine, and requires
|
|
neither help nor sympathy, thank you.</para>
|
|
<para>Please note that the author will <emphasis>not</emphasis> answer
|
|
scripting questions for Sun/Solaris/Oracle or Apple systems. The
|
|
endarkened execs and the arachnoid corporate attorneys of
|
|
those particular outfits have been using litigation in a
|
|
predatory manner and/or as a weapon against the Open Source
|
|
Community. Any Solaris or Apple users needing scripting help
|
|
will therefore kindly direct their concerns to corporate
|
|
customer service.</para>
|
|
|
|
</sidebar>
|
|
|
|
<epigraph>
|
|
<para>... sophisticated in mechanism but possibly agile
|
|
operating under noises being extremely suppressed ...</para>
|
|
<para>--<emphasis>CI-300 printer manual</emphasis></para>
|
|
</epigraph>
|
|
|
|
</sect1> <!-- Where to Go For Help -->
|
|
|
|
|
|
|
|
<sect1 id="toolsused">
|
|
<title>Tools Used to Produce This Book</title>
|
|
|
|
|
|
<sect2 id="software-hardware">
|
|
<title>Hardware</title>
|
|
|
|
<para>A used IBM Thinkpad, model 760XL laptop (P166, 104 meg RAM)
|
|
running Red Hat 7.1/7.3. Sure, it's slow and has a funky
|
|
keyboard, but it beats the heck out of a No. 2 pencil and a
|
|
Big Chief tablet.</para>
|
|
|
|
<para>
|
|
<emphasis>Update:</emphasis> upgraded to a
|
|
770Z Thinkpad (P2-366, 192 meg RAM) running FC3. Anyone
|
|
feel like donating a later-model laptop to a starving writer
|
|
<g>?
|
|
</para>
|
|
|
|
<para>
|
|
<emphasis>Update:</emphasis> upgraded to a T61 Thinkpad
|
|
running Mandriva 2011. No longer starving <g>,
|
|
but not too proud to accept donations.
|
|
</para>
|
|
|
|
</sect2> <!-- Hardware -->
|
|
|
|
|
|
<sect2 id="software-printware">
|
|
<title>Software and Printware</title>
|
|
|
|
<orderedlist id="software-printware2" numeration="lowerroman">
|
|
|
|
<listitem>
|
|
<para>Bram Moolenaar's powerful SGML-aware <ulink
|
|
url="http://www.vim.org">vim</ulink> text editor.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><ulink
|
|
url="http://www.netfolder.com/DSSSL/">OpenJade</ulink>,
|
|
a DSSSL rendering engine for converting SGML documents into other
|
|
formats.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><ulink url="http://nwalsh.com/docbook/dsssl/"> Norman
|
|
Walsh's DSSSL stylesheets</ulink>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><citetitle pubwork="book">DocBook, The Definitive
|
|
Guide</citetitle>, by Norman Walsh and Leonard Muellner
|
|
(O'Reilly, ISBN 1-56592-580-7). This is still the standard
|
|
reference for anyone attempting to write a document in Docbook
|
|
SGML format.</para>
|
|
</listitem>
|
|
|
|
</orderedlist>
|
|
|
|
</sect2> <!-- Software and Printware -->
|
|
|
|
</sect1> <!-- Tools Used -->
|
|
|
|
|
|
|
|
<sect1 id="credits">
|
|
<title>Credits</title>
|
|
|
|
<para><emphasis>Community participation made this project
|
|
possible.</emphasis> The author gratefully acknowledges that
|
|
writing this book would have been unthinkable without
|
|
help and feedback from all you people out there.</para>
|
|
|
|
<para><ulink url="mailto:feloy@free.fr">Philippe Martin</ulink>
|
|
translated the first version (0.1) of this document into
|
|
DocBook/SGML. While not on the job at a small French company as a
|
|
software developer, he enjoys working on GNU/Linux documentation
|
|
and software, reading literature, playing music, and, for his
|
|
peace of mind, making merry with friends. You may run across him
|
|
somewhere in France or in the Basque Country, or you can email him
|
|
at <ulink url="mailto:feloy@free.fr">feloy@free.fr</ulink>.</para>
|
|
|
|
<para>Philippe Martin also pointed out that positional parameters
|
|
past $9 are possible using {bracket} notation. (See <xref
|
|
linkend="ex17"/>).</para>
|
|
|
|
<para><ulink url="mailto:stephane_chazelas@yahoo.fr">Stéphane
|
|
Chazelas</ulink> sent a long list of corrections, additions,
|
|
and example scripts. More than a contributor, he had, in effect,
|
|
for a while taken on the role of <emphasis>co-editor</emphasis>
|
|
for this document. <foreignphrase>Merci
|
|
beaucoup!</foreignphrase></para>
|
|
|
|
<para>Paulo Marcel Coelho Aragao offered many corrections, both major
|
|
and minor, and contributed quite a number of helpful
|
|
suggestions.</para>
|
|
|
|
<para>I would like to especially thank <emphasis>Patrick
|
|
Callahan</emphasis>, <emphasis>Mike Novak</emphasis>, and
|
|
<emphasis>Pal Domokos</emphasis> for catching bugs, pointing out
|
|
ambiguities, and for suggesting clarifications and changes in the
|
|
preliminary version (0.1) of this document. Their lively
|
|
discussion of shell scripting and general documentation issues
|
|
inspired me to try to make this document more readable.</para>
|
|
|
|
<para>I'm grateful to Jim Van Zandt for pointing out errors and
|
|
omissions in version 0.2 of this document. He also contributed
|
|
an instructive <link linkend="zfifo">example script</link>.</para>
|
|
|
|
<para>Many thanks to <ulink
|
|
url="mailto:mikaku@fiwix.org">Jordi Sanfeliu</ulink>
|
|
for giving permission to use his fine tree script (<xref
|
|
linkend="tree"/>), and to Rick Boivie for revising it.</para>
|
|
|
|
<para>Likewise, thanks to <ulink
|
|
url="mailto:charpov@cs.unh.edu">Michel Charpentier</ulink> for
|
|
permission to use his <link linkend="dcref">dc</link> factoring script
|
|
(<xref linkend="factr"/>).</para>
|
|
|
|
<para>Kudos to <ulink
|
|
url="mailto:friedman@prep.ai.mit.edu">Noah Friedman</ulink>
|
|
for permission to use his string function script (<xref
|
|
linkend="string"/>).</para>
|
|
|
|
<para><ulink url="mailto:emmanuel.rouat@wanadoo.fr">Emmanuel
|
|
Rouat</ulink> suggested corrections and additions on <link
|
|
linkend="commandsubref">command substitution</link>,
|
|
<link linkend="aliasref">aliases</link>, and <link
|
|
linkend="pathmanagement">path management</link>. He also
|
|
contributed a very nice sample <filename>.bashrc</filename> file
|
|
(<xref linkend="sample-bashrc"/>).</para>
|
|
|
|
<para><ulink url="mailto:heiner.steven@odn.de">Heiner Steven</ulink>
|
|
kindly gave permission to use his base conversion script, <xref
|
|
linkend="base"/>. He also made a number of corrections and many
|
|
helpful suggestions. Special thanks.</para>
|
|
|
|
<para>Rick Boivie contributed the delightfully recursive
|
|
<emphasis>pb.sh</emphasis> script (<xref linkend="pbook"/>),
|
|
revised the <emphasis>tree.sh</emphasis> script (<xref
|
|
linkend="tree"/>), and suggested performance improvements
|
|
for the <emphasis>monthlypmt.sh</emphasis> script (<xref
|
|
linkend="monthlypmt"/>).</para>
|
|
|
|
<para>Florian Wisser enlightened me on some of the fine points of
|
|
testing strings (see <xref linkend="strtest"/>), and on other
|
|
matters.</para>
|
|
|
|
<para>Oleg Philon sent suggestions concerning <link
|
|
linkend="cutref">cut</link> and <link
|
|
linkend="pidofref">pidof</link>.</para>
|
|
|
|
<para>Michael Zick extended the <link linkend="emptyarray">empty
|
|
array</link> example to demonstrate some surprising array
|
|
properties. He also contributed the <emphasis>isspammer</emphasis>
|
|
scripts (<xref linkend="isspammer"/> and <xref
|
|
linkend="isspammer2"/>).</para>
|
|
|
|
<para>Marc-Jano Knopp sent corrections and clarifications on DOS
|
|
batch files.</para>
|
|
|
|
<para>Hyun Jin Cha found several typos in the document in the
|
|
process of doing a Korean translation. Thanks for pointing
|
|
these out.</para>
|
|
|
|
<para>Andreas Abraham sent in a long list of typographical
|
|
errors and other corrections. Special thanks!</para>
|
|
|
|
|
|
<para>Others contributing scripts, making helpful suggestions, and
|
|
pointing out errors were Gabor Kiss, Leopold Toetsch,
|
|
Peter Tillier, Marcus Berglof, Tony Richardson, Nick Drage
|
|
(script ideas!), Rich Bartell, Jess Thrysoee, Adam Lazur, Bram
|
|
Moolenaar, Baris Cicek, Greg Keraunen, Keith Matthews, Sandro
|
|
Magi, Albert Reiner, Dim Segebart, Rory Winston, Lee Bigelow,
|
|
Wayne Pollock, <quote>jipe,</quote> <quote>bojster,</quote>
|
|
<quote>nyal,</quote> <quote>Hobbit,</quote> <quote>Ender,</quote>
|
|
<quote>Little Monster</quote> (Alexis), <quote>Mark,</quote>
|
|
<quote>Patsie,</quote> <quote>vladz,</quote> Peggy Russell,
|
|
Emilio Conti, Ian. D. Allen, Hans-Joerg Diers, Arun Giridhar,
|
|
Dennis Leeuw, Dan Jacobson, Aurelio Marinho Jargas, Edward
|
|
Scholtz, Jean Helou, Chris Martin, Lee Maschmeyer, Bruno Haible,
|
|
Wilbert Berendsen, Sebastien Godard, Bjön Eriksson, John
|
|
MacDonald, John Lange, Joshua Tschida, Troy Engel, Manfred
|
|
Schwarb, Amit Singh, Bill Gradwohl, E. Choroba, David Lombard,
|
|
Jason Parker, Steve Parker, Bruce W. Clare, William Park, Vernia
|
|
Damiano, Mihai Maties, Mark Alexander, Jeremy Impson, Ken Fuchs,
|
|
Jared Martin, Frank Wang, Sylvain Fourmanoit, Matthew Sage,
|
|
Matthew Walker, Kenny Stauffer, Filip Moritz, Andrzej Stefanski,
|
|
Daniel Albers, Jeffrey Haemer, Stefano Palmeri, Nils Radtke,
|
|
Sigurd Solaas, Serghey Rodin, Jeroen Domburg, Alfredo Pironti,
|
|
Phil Braham, Bruno de Oliveira Schneider, Stefano Falsetto,
|
|
Chris Morgan, Walter Dnes, Linc Fessenden, Michael Iatrou, Pharis
|
|
Monalo, Jesse Gough, Fabian Kreutz, Mark Norman, Harald Koenig,
|
|
Dan Stromberg, Peter Knowles, Francisco Lobo, Mariusz Gniazdowski,
|
|
Sebastian Arming, Chetankumar Phulpagare, Benno Schulenberg,
|
|
Tedman Eng, Jochen DeSmet, Juan Nicolas Ruiz, Oliver Beckstein,
|
|
Achmed Darwish, Dotan Barak, Richard Neill, Albert Siersema,
|
|
Omair Eshkenazi, Geoff Lee, Graham Ewart, JuanJo Ciarlante,
|
|
Cliff Bamford, Nathan Coulter, Ramses Rodriguez Martinez,
|
|
Evgeniy Ivanov, Craig Barnes, George Dimitriu, Kevin LeBlanc,
|
|
Antonio Macchi, Tomas Pospisek, David Wheeler, Erik Brandsberg,
|
|
YongYe, Andreas Kühne, Pádraig Brady, Joseph
|
|
Steinhauser, and David Lawyer (himself an author of four
|
|
HOWTOs).</para>
|
|
|
|
<para>My gratitude to <ulink url="mailto:chet@po.cwru.edu">Chet
|
|
Ramey</ulink> and Brian Fox for writing <firstterm>Bash</firstterm>,
|
|
and building into it elegant and powerful scripting
|
|
capabilities rivaling those of <firstterm>ksh</firstterm>.</para>
|
|
|
|
<para>Very special thanks to the hard-working volunteers at
|
|
the <ulink url="http://www.tldp.org">Linux Documentation
|
|
Project</ulink>. The LDP hosts a repository of Linux knowledge
|
|
and lore, and has, to a great extent, enabled the publication
|
|
of this book.</para>
|
|
|
|
<para>Thanks and appreciation to IBM, Red Hat, Google, 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>Belated thanks to my fourth grade teacher, Miss Spencer,
|
|
for emotional support and for convincing me that maybe, just
|
|
maybe I wasn't a total loss.</para>
|
|
|
|
<para>Thanks most of all to my wife, Anita, for her encouragement,
|
|
inspiration, and emotional support.</para>
|
|
|
|
</sect1> <!-- Credits -->
|
|
|
|
<sect1 id="disclaimer">
|
|
<title>Disclaimer</title>
|
|
|
|
|
|
<para>(This is a variant of the standard <ulink
|
|
url="http://www.tldp.org">LDP</ulink> disclaimer.)</para>
|
|
|
|
<para>No liability for the contents of this document can be
|
|
accepted. Use the concepts, examples and information at your
|
|
own risk. There may be errors, omissions, and inaccuracies
|
|
that could cause you to lose data, harm your system, or induce
|
|
involuntary electrocution, so <emphasis>proceed with appropriate
|
|
caution</emphasis>. The author takes no responsibility for any
|
|
damages, incidental or otherwise.</para>
|
|
|
|
<para>As it happens, it is highly unlikely that either you or
|
|
your system will suffer ill effects, aside from uncontrollable
|
|
hiccups. In fact, the <foreignphrase>raison
|
|
d'etre</foreignphrase> of this book is to enable its readers
|
|
to analyze shell scripts and determine whether they have <link
|
|
linkend="gotchas">unanticipated consequences</link>.</para>
|
|
|
|
</sect1> <!-- Disclaimer -->
|
|
|
|
</chapter> <!-- End Notes -->
|
|
|
|
|
|
|
|
<bibliography id="biblio">
|
|
<anchor id="biblioref"/>
|
|
|
|
<epigraph>
|
|
<para>Those who do not understand UNIX are condemned to reinvent it,
|
|
poorly.</para>
|
|
<para>--Henry Spencer</para>
|
|
<para><anchor id="denningref"/></para>
|
|
</epigraph>
|
|
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<editor><firstname>Peter</firstname><surname>Denning</surname></editor>
|
|
</authorgroup>
|
|
<title>Computers Under Attack: Intruders, Worms, and Viruses</title>
|
|
<publisher>
|
|
<publishername>ACM Press</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1990</year>
|
|
</copyright>
|
|
<isbn>0-201-53067-8</isbn>
|
|
<abstract><para>This compendium contains a couple of articles on
|
|
shell script viruses.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Ken</firstname><surname>Burtch</surname></author>
|
|
</authorgroup>
|
|
<title><ulink url="http://www.samspublishing.com/title/0672326426">Linux Shell Scripting with Bash</ulink></title>
|
|
<edition>1st edition</edition>
|
|
<publisher>
|
|
<publishername>Sams Publishing (Pearson)</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2004</year>
|
|
</copyright>
|
|
<isbn>0672326426</isbn>
|
|
<abstract><para>
|
|
Covers much of the same material as the <emphasis>ABS
|
|
Guide</emphasis>, though in a different style.</para>
|
|
<para>*</para>
|
|
<para><anchor id="dgsedref"/></para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Daniel</firstname><surname>Goldman</surname></author>
|
|
</authorgroup>
|
|
<title><ulink url="http://www.sed-book.com/">Definitive Guide
|
|
to Sed</ulink></title>
|
|
<edition>1st edition</edition>
|
|
<copyright>
|
|
<year>2013</year>
|
|
</copyright>
|
|
<abstract><para>
|
|
This ebook is an excellent introduction to
|
|
<firstterm>sed</firstterm>. Rather than being a conversion from
|
|
a printed volume, it was specifically designed and formatted
|
|
for viewing on an ebook reader. Well-written, informative,
|
|
and useful as a reference as well as a tutorial. Highly
|
|
recommended.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Dale</firstname><surname>Dougherty</surname></author>
|
|
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
|
|
</authorgroup>
|
|
<title>Sed and Awk</title>
|
|
<edition>2nd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1997</year>
|
|
</copyright>
|
|
<isbn>1-156592-225-5</isbn>
|
|
<abstract><para>
|
|
Unfolding the full power of shell scripting requires at least a passing
|
|
familiarity with <link linkend="sedref"><firstterm>sed</firstterm>
|
|
and <firstterm>awk</firstterm></link>. This is the classic
|
|
tutorial. It includes an excellent introduction to
|
|
<firstterm>Regular Expressions</firstterm>. Recommended.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Jeffrey</firstname><surname>Friedl</surname></author>
|
|
</authorgroup>
|
|
<title>Mastering Regular Expressions</title>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2002</year>
|
|
</copyright>
|
|
<isbn>0-596-00289-0</isbn>
|
|
<abstract><para>Still the best all-around reference on <link
|
|
linkend="regexref">Regular Expressions</link>.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Aeleen</firstname><surname>Frisch</surname></author>
|
|
</authorgroup>
|
|
<title>Essential System Administration</title>
|
|
<edition>3rd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2002</year>
|
|
</copyright>
|
|
<isbn>0-596-00343-9</isbn>
|
|
<abstract><para>This excellent manual provides a decent introduction
|
|
to shell scripting from a sys admin point of view. It includes
|
|
comprehensive explanations of the startup and initialization
|
|
scripts in a UNIX system.</para>
|
|
<para>*</para>
|
|
<para><anchor id="kochanref"/></para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Stephen</firstname><surname>Kochan</surname></author>
|
|
<author><firstname>Patrick</firstname><surname>Wood</surname></author>
|
|
</authorgroup>
|
|
<title>Unix Shell Programming</title>
|
|
<publisher>
|
|
<publishername>Hayden</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1990</year>
|
|
</copyright>
|
|
<isbn>067248448X</isbn>
|
|
<abstract>
|
|
<para>Still considered a standard reference, though somewhat dated, and
|
|
a bit <quote>wooden</quote> stylistically speaking.
|
|
<footnote><para>It was hard to resist the obvious pun. No slight
|
|
intended, since the book is a pretty decent introduction to
|
|
the basic concepts of shell scripting.</para></footnote>
|
|
In fact, this book was the <firstterm>ABS Guide</firstterm> author's
|
|
first exposure to UNIX shell scripting, lo these many years ago.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Neil</firstname><surname>Matthew</surname></author>
|
|
<author><firstname>Richard</firstname><surname>Stones</surname></author>
|
|
</authorgroup>
|
|
<title>Beginning Linux Programming</title>
|
|
<publisher>
|
|
<publishername>Wrox Press</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1996</year>
|
|
</copyright>
|
|
<isbn>1874416680</isbn>
|
|
<abstract><para>Surprisingly good in-depth coverage of various
|
|
programming languages available for Linux, including a fairly
|
|
strong chapter on shell scripting.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry id="mayerref">
|
|
<authorgroup>
|
|
<author><firstname>Herbert</firstname><surname>Mayer</surname></author>
|
|
</authorgroup>
|
|
<title>Advanced C Programming on the IBM PC</title>
|
|
<publisher>
|
|
<publishername>Windcrest Books</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1989</year>
|
|
</copyright>
|
|
<isbn>0830693637</isbn>
|
|
<abstract><para>Excellent coverage of algorithms and general
|
|
programming practices. Highly recommended, but unfortunately
|
|
out of print.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>David</firstname><surname>Medinets</surname></author>
|
|
</authorgroup>
|
|
<title>Unix Shell Programming Tools</title>
|
|
<publisher>
|
|
<publishername>McGraw-Hill</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1999</year>
|
|
</copyright>
|
|
<isbn>0070397333</isbn>
|
|
<abstract><para>Pretty good treatment of shell scripting, with
|
|
examples, and a short intro to Tcl and Perl.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Cameron</firstname><surname>Newham</surname></author>
|
|
<author><firstname>Bill</firstname><surname>Rosenblatt</surname></author>
|
|
</authorgroup>
|
|
<title>Learning the Bash Shell</title>
|
|
<edition>2nd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1998</year>
|
|
</copyright>
|
|
<isbn>1-56592-347-2</isbn>
|
|
<abstract><para>This is a valiant effort at a decent shell primer,
|
|
but sadly deficient in its coverage of writing scripts and
|
|
lacking sufficient examples.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Anatole</firstname><surname>Olczak</surname></author>
|
|
</authorgroup>
|
|
<title>Bourne Shell Quick Reference Guide</title>
|
|
<publisher>
|
|
<publishername>ASP, Inc.</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1991</year>
|
|
</copyright>
|
|
<isbn>093573922X</isbn>
|
|
<abstract><para>A very handy pocket reference, despite lacking
|
|
coverage of Bash-specific features.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Jerry</firstname><surname>Peek</surname></author>
|
|
<author><firstname>Tim</firstname><surname>O'Reilly</surname></author>
|
|
<author><firstname>Mike</firstname><surname>Loukides</surname></author>
|
|
</authorgroup>
|
|
<title>Unix Power Tools</title>
|
|
<edition>3rd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<publisher>
|
|
<publishername>Random House</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2002</year>
|
|
</copyright>
|
|
<isbn>0-596-00330-7</isbn>
|
|
<abstract><para>Contains a couple of sections of very informative
|
|
in-depth articles on shell programming, but falls short of being
|
|
a self-teaching manual. It reproduces much of the <link
|
|
linkend="regexref">Regular Expressions</link> tutorial from the
|
|
Dougherty and Robbins book, above. The comprehensive coverage
|
|
of UNIX commands makes this book worthy of a place on your
|
|
bookshelf.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Clifford</firstname><surname>Pickover</surname></author>
|
|
</authorgroup>
|
|
<title>Computers, Pattern, Chaos, and Beauty</title>
|
|
<publisher>
|
|
<publishername>St. Martin's Press</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1990</year>
|
|
</copyright>
|
|
<isbn>0-312-04123-3</isbn>
|
|
<abstract><para>A treasure trove of ideas and recipes for
|
|
computer-based exploration of mathematical oddities.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>George</firstname><surname>Polya</surname></author>
|
|
</authorgroup>
|
|
<title>How To Solve It</title>
|
|
<publisher>
|
|
<publishername>Princeton University Press</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1973</year>
|
|
</copyright>
|
|
<isbn>0-691-02356-5</isbn>
|
|
<abstract><para>The classic tutorial on problem-solving methods
|
|
(algorithms), with special emphasis on how to teach them.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Chet</firstname><surname>Ramey</surname></author>
|
|
<author><firstname>Brian</firstname><surname>Fox</surname></author>
|
|
</authorgroup>
|
|
<title><ulink
|
|
url="http://www.network-theory.co.uk/bash/manual/">The GNU Bash Reference Manual</ulink></title>
|
|
<publisher>
|
|
<publishername>Network Theory Ltd</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2003</year>
|
|
</copyright>
|
|
<isbn>0-9541617-7-7</isbn>
|
|
<abstract><para>This manual is the definitive reference for
|
|
GNU Bash. The authors of this manual, Chet Ramey and Brian Fox,
|
|
are the original developers of GNU Bash. For each copy sold,
|
|
the publisher donates $1 to the Free Software Foundation.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
|
|
</authorgroup>
|
|
<title>Bash Reference Card</title>
|
|
<publisher>
|
|
<publishername>SSC</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1998</year>
|
|
</copyright>
|
|
<isbn>1-58731-010-5</isbn>
|
|
<abstract>
|
|
<para>Excellent Bash pocket reference (don't leave home without it,
|
|
especially if you're a sysadmin). A bargain at $4.95, but
|
|
unfortunately no longer available for free download.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
|
|
</authorgroup>
|
|
<title>Effective Awk Programming</title>
|
|
<publisher>
|
|
<publishername>Free Software Foundation / O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2000</year>
|
|
</copyright>
|
|
<isbn>1-882114-26-4</isbn>
|
|
<abstract>
|
|
<para>The absolute best <link linkend="awkref">awk</link>
|
|
tutorial and reference. The free electronic version of this
|
|
book is part of the <firstterm>awk</firstterm> documentation,
|
|
and printed copies of the latest version are available from
|
|
O'Reilly and Associates.</para>
|
|
<para>This book served as an inspiration for the author
|
|
of the <firstterm>ABS Guide</firstterm>.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Bill</firstname><surname>Rosenblatt</surname></author>
|
|
</authorgroup>
|
|
<title>Learning the Korn Shell</title>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1993</year>
|
|
</copyright>
|
|
<isbn>1-56592-054-6</isbn>
|
|
<abstract>
|
|
<para><anchor id="kornshellref"/>This well-written book contains
|
|
some excellent pointers on shell scripting in general.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Paul</firstname><surname>Sheer</surname></author>
|
|
</authorgroup>
|
|
<title>LINUX: Rute User's Tutorial and Exposition</title>
|
|
<edition>1st edition</edition>
|
|
<publisher>
|
|
<publishername></publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2002</year>
|
|
</copyright>
|
|
<isbn>0-13-033351-4</isbn>
|
|
<abstract>
|
|
<para>Very detailed and readable introduction to Linux system
|
|
administration.</para>
|
|
<para>The book is available in print, or
|
|
<ulink
|
|
url="http://burks.brighton.ac.uk/burks/linux/rute/rute.htm">on-line</ulink>.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Ellen</firstname><surname>Siever</surname></author>
|
|
<author><surname>the staff of O'Reilly and Associates</surname></author>
|
|
</authorgroup>
|
|
<title>Linux in a Nutshell</title>
|
|
<edition>2nd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>1999</year>
|
|
</copyright>
|
|
<isbn>1-56592-585-8</isbn>
|
|
<abstract><para>The all-around best Linux command reference.
|
|
It even has a Bash section.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<authorgroup>
|
|
<author><firstname>Dave</firstname><surname>Taylor</surname></author>
|
|
</authorgroup>
|
|
<title>Wicked Cool Shell Scripts: 101 Scripts for Linux, Mac OS X, and Unix Systems</title>
|
|
<edition>1st edition</edition>
|
|
<publisher>
|
|
<publishername>No Starch Press</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2004</year>
|
|
</copyright>
|
|
<isbn>1-59327-012-7</isbn>
|
|
<abstract><para>Pretty much what the title promises . . .</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<title>The UNIX CD Bookshelf</title>
|
|
<edition>3rd edition</edition>
|
|
<publisher>
|
|
<publishername>O'Reilly and Associates</publishername>
|
|
</publisher>
|
|
<copyright>
|
|
<year>2003</year>
|
|
</copyright>
|
|
<isbn>0-596-00392-7</isbn>
|
|
<abstract><para>An array of seven UNIX books on CD ROM, including
|
|
<citetitle pubwork="book">UNIX Power Tools</citetitle>,
|
|
<citetitle pubwork="book">Sed and Awk</citetitle>, and <citetitle
|
|
pubwork="book">Learning the Korn Shell</citetitle>. A complete
|
|
set of all the UNIX references and tutorials you would ever need
|
|
at about $130. Buy this one, even if it means going into debt
|
|
and not paying the rent.</para>
|
|
<para>Update: Seems to have somehow fallen out of print.
|
|
Ah, well. You can still buy the dead-tree editions of these books.</para>
|
|
<para>*</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The O'Reilly books on Perl. (Actually,
|
|
<emphasis>any</emphasis> O'Reilly books.)</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>* * *</para>
|
|
<para><command>Other Resources</command></para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract><para>Fioretti, Marco, <quote>Scripting for X
|
|
Productivity,</quote> <ulink url="linuxjournal.com"><citetitle
|
|
pubwork="journal">Linux Journal</citetitle></ulink>, Issue 113,
|
|
September, 2003, pp. 86-9.</para></abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Ben Okopnik's well-written <citetitle
|
|
pubwork="article">introductory Bash scripting</citetitle>
|
|
articles in issues 53, 54, 55, 57, and 59 of the
|
|
<ulink url="http://www.linuxgazette.net"><citetitle
|
|
pubwork="journal">Linux Gazette</citetitle></ulink>, and his
|
|
explanation of <quote>The Deep, Dark Secrets of Bash</quote>
|
|
in issue 56.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract><para>Chet Ramey's <citetitle pubwork="article">Bash -
|
|
The GNU Shell</citetitle>, a two-part series published in issues 3
|
|
and 4 of the <ulink url="http://www.linuxjournal.com"><citetitle
|
|
pubwork="journal">Linux Journal</citetitle></ulink>, July-August
|
|
1994.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Mike G's <ulink
|
|
url="http://www.tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html">Bash-Programming-Intro
|
|
HOWTO</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Richard's <ulink url="http://www.injunea.demon.co.uk/index.htm">Unix
|
|
Scripting Universe</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><anchor id="bashfaq"/>Chet Ramey's
|
|
<ulink url="http://tiswww.case.edu/php/chet/bash/FAQ">Bash
|
|
FAQ</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><ulink url="http://wooledge.org:8000/BashFAQ">
|
|
Greg's WIKI: Bash FAQ</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Example shell scripts at <ulink
|
|
url="http://alge.anart.no/linux/scripts/">Lucc's Shell Scripts
|
|
</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Example shell scripts at <ulink
|
|
url="http://www.shelldorado.com">SHELLdorado </ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Example shell scripts at <ulink
|
|
url="http://www.splode.com/~friedman/software/scripts/src/">Noah
|
|
Friedman's script site</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><ulink url="http://bashcookbook.com/bashinfo/">Examples</ulink>
|
|
from the <citetitle pubwork="book">The Bash Scripting
|
|
Cookbook</citetitle>, by Albing, Vossen, and Newham.</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>. In fact, all of his shell scripting
|
|
books are highly recommended. See also Steve's <ulink
|
|
url="http://nixshell.wordpress.com/2011/07/13/arcade-games-written-in-a-shell-script/">Arcade
|
|
Games written in a shell script</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>An excellent collection of Bash scripting tips, tricks,
|
|
and resources at the <ulink
|
|
url="http://www.bash-hackers.org/wiki.doku.php">Bash Hackers
|
|
Wiki</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Giles Orr's <ulink
|
|
url="http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/">Bash-Prompt
|
|
HOWTO</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The <ulink
|
|
url="http://www.pixelbeat.org/cmdline.html"><emphasis>Pixelbeat</emphasis>
|
|
command-line reference</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Very nice <command>sed</command>,
|
|
<command>awk</command>, and regular expression tutorials at
|
|
<ulink url="http://www.grymoire.com/Unix/index.html">The UNIX
|
|
Grymoire</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The GNU <ulink
|
|
url="http://www.gnu.org/software/sed/manual/">sed</ulink>
|
|
and
|
|
<ulink url="http://www.gnu.org/software/gawk/manual/">
|
|
gawk</ulink> manuals. As you recall, <link
|
|
linkend="gnugawk">gawk</link> is the enhanced GNU version of
|
|
<command>awk</command>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Many interesting sed scripts at the <ulink
|
|
url="http://sed.sourceforge.net/grabbag/"> seder's grab bag</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Tips and tricks at <ulink
|
|
url="http://linuxreviews.org"> Linux Reviews</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Trent Fisher's <ulink
|
|
url="http://www.cs.pdx.edu/~trent/gnu/groff/groff.html">groff
|
|
tutorial</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>David Wheeler's <ulink
|
|
url="http://www.dwheeler.com/essays/filenames-in-shell.html">Filenames
|
|
in Shell</ulink> essay.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><quote>Shelltris</quote> and <quote>shellitaire</quote>
|
|
at <ulink url="http://www.shellscriptgames.com">Shell Script
|
|
Games</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>YongYe's wonderfully complex <ulink
|
|
url="http://bash.deta.in/Tetris_Game.sh">Tetris game
|
|
script</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
|
|
<firstterm>osimpa</firstterm> i386 assembler
|
|
entirely as Bash scripts.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><firstterm>dgatwood</firstterm>
|
|
has a very nice <ulink url="http://www.shellscriptgames.com/">
|
|
shell script games</ulink> site, featuring a Tetris®
|
|
clone and solitaire.</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 project
|
|
to incorporate certain <firstterm>Awk</firstterm> and
|
|
<firstterm>Python</firstterm> features into Bash. Among these is
|
|
a <firstterm>gdbm</firstterm> interface. He has released
|
|
<firstterm>bashdiff</firstterm>
|
|
on <ulink url="http://freshmeat.net">Freshmeat.net</ulink>. He
|
|
has an <ulink
|
|
url="http://linuxgazette.net/108/park.html">article</ulink>
|
|
in the November, 2004 issue of the <ulink
|
|
url="http://www.linuxgazette.net"><citetitle
|
|
pubwork="journal">Linux Gazette</citetitle></ulink>
|
|
on adding string functions to Bash, with a <ulink
|
|
url="http://linuxgazette.net/109/park.html">followup
|
|
article</ulink> in the December issue, and <ulink
|
|
url="http://linuxgazette.net/110/park.htm">yet another</ulink>
|
|
in the January, 2005 issue.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Peter Knowles has written an
|
|
<ulink url="http://booklistgensh.peterknowles.com/">elaborate
|
|
Bash script</ulink> that generates a book list on the <ulink
|
|
url="http://www.dottocomu.com/b/archives/002571.html">Sony
|
|
Librie</ulink> e-book reader. This useful tool facilitates
|
|
loading non-DRM user content on the <emphasis>Librie</emphasis>
|
|
(and the newer <emphasis>PRS-xxx-series</emphasis> devices).</para>
|
|
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Tim Waugh's <ulink
|
|
url="http://cyberelk.net/tim/xmlto/">xmlto</ulink> is an
|
|
elaborate Bash script for converting Docbook XML documents to
|
|
other formats.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Philip Patterson's <ulink
|
|
url="http://www.gossiplabs.org">logforbash</ulink>
|
|
logging/debugging script.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><ulink
|
|
url="http://auctiongallery.sourceforge.net">AuctionGallery</ulink>,
|
|
an application for eBay <quote>power sellers</quote> coded
|
|
in Bash.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Of historical interest are Colin Needham's
|
|
<firstterm>original International Movie Database (IMDB)
|
|
reader polling scripts</firstterm>, which nicely illustrate
|
|
the use of <link linkend="awkref">awk</link> for string
|
|
parsing. Unfortunately, the URL link is broken.</para>
|
|
<para>---</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Fritz Mehner has written a <ulink
|
|
url="http://vim.sourceforge.net/scripts/script.php?script_id=365">bash-support
|
|
plugin</ulink> for the <firstterm>vim</firstterm> text editor.
|
|
He has also also come up with his own <ulink
|
|
url="http://lug.fh-swf.de/vim/vim-bash/StyleGuideShell.en.pdf">stylesheet
|
|
for Bash</ulink>. Compare it with the <link linkend="unofficialst">ABS Guide
|
|
Unofficial Stylesheet</link>.</para>
|
|
<para>---</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><emphasis>Penguin Pete</emphasis> has quite a number of
|
|
shell scripting tips and hints on <ulink
|
|
url="http://www.penguinpetes.com">his superb
|
|
site</ulink>. Highly recommended.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The excellent <citetitle pubwork="book"> Bash Reference
|
|
Manual</citetitle>, by Chet Ramey and Brian Fox, distributed as
|
|
part of the <firstterm>bash-2-doc</firstterm> package (available
|
|
as an <link linkend="rpmref">rpm</link>). See especially the
|
|
instructive example scripts in this package.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>John Lion's classic, <ulink
|
|
url="http://www.lemis.com/grog/Documentation/Lions/index.html">
|
|
<emphasis>A Commentary on the Sixth Edition UNIX Operating
|
|
System</emphasis></ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The <ulink
|
|
url="news:comp.unix.shell">comp.os.unix.shell</ulink>
|
|
newsgroup.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para><anchor id="ddlink"/></para>
|
|
<para>The <ulink
|
|
url="http://www.linuxquestions.org/questions/showthread.php?t=362506"><firstterm>dd</firstterm>
|
|
thread</ulink> on <ulink
|
|
url="http://www.linuxquestions.org">Linux Questions</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The
|
|
<ulink
|
|
url="http://www.newsville.com/cgi-bin/getfaq?file=comp.unix.shell/comp.unix.shell_FAQ_-_Answers_to_Frequently_Asked_Questions">comp.os.unix.shell
|
|
FAQ</ulink>.</para>
|
|
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>Assorted comp.os.unix <ulink
|
|
url="http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.shell.html">
|
|
FAQs</ulink>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The <ulink
|
|
url="http://en.wikipedia.org/wiki/Dc_(Unix)"><firstterm>Wikipedia</firstterm>
|
|
article</ulink> covering <link linkend="dcref">dc</link>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<abstract>
|
|
<para>The <link linkend="manref">manpages</link> for
|
|
<command>bash</command> and <command>bash2</command>,
|
|
<command>date</command>, <command>expect</command>,
|
|
<command>expr</command>, <command>find</command>,
|
|
<command>grep</command>, <command>gzip</command>,
|
|
<command>ln</command>, <command>patch</command>,
|
|
<command>tar</command>, <command>tr</command>,
|
|
<command>bc</command>, <command>xargs</command>.
|
|
The <firstterm>texinfo</firstterm> documentation on
|
|
<command>bash</command>, <command>dd</command>,
|
|
<command>m4</command>, <command>gawk</command>, and
|
|
<command>sed</command>.</para>
|
|
</abstract>
|
|
</biblioentry>
|
|
|
|
|
|
</bibliography>
|
|
|
|
|
|
|
|
<appendix id="contributed-scripts">
|
|
<title>Contributed Scripts</title>
|
|
|
|
<para>These scripts, while not fitting into the text of this document, do
|
|
illustrate some interesting shell programming techniques. Some are useful,
|
|
too. Have fun analyzing and running them.</para>
|
|
|
|
<example id="mailformat">
|
|
<title><firstterm>mailformat</firstterm>: Formatting an e-mail
|
|
message</title>
|
|
<programlisting>&mailformat;</programlisting>
|
|
</example>
|
|
|
|
<example id="rn">
|
|
<title><firstterm>rn</firstterm>: A simple-minded file renaming
|
|
utility</title>
|
|
<para>This script is a modification of <xref
|
|
linkend="lowercase"/>.</para>
|
|
<programlisting>&rn;</programlisting>
|
|
</example>
|
|
|
|
<example id="blankrename">
|
|
<title><firstterm>blank-rename</firstterm>: Renames filenames containing
|
|
blanks</title>
|
|
<para>This is an even simpler-minded version of previous script.</para>
|
|
<programlisting>&blankrename;</programlisting>
|
|
</example>
|
|
|
|
<example id="encryptedpw">
|
|
<title><firstterm>encryptedpw</firstterm>: Uploading to an ftp site,
|
|
using a locally encrypted password</title>
|
|
<programlisting>&encryptedpw;</programlisting>
|
|
</example>
|
|
|
|
<example id="copycd">
|
|
<title><firstterm>copy-cd</firstterm>: Copying a data CD</title>
|
|
<programlisting>©cd;</programlisting>
|
|
</example>
|
|
|
|
<example id="collatz">
|
|
<title>Collatz series</title>
|
|
<programlisting>&collatz;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="daysbetween0"/></para>
|
|
<example id="daysbetween">
|
|
<title><firstterm>days-between</firstterm>: Days between two
|
|
dates</title>
|
|
<programlisting>&daysbetween;</programlisting>
|
|
</example>
|
|
|
|
<example id="makedict">
|
|
<title>Making a <firstterm>dictionary</firstterm></title>
|
|
<programlisting>&makedict;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="soundex0"/></para>
|
|
<example id="soundex">
|
|
<title>Soundex conversion</title>
|
|
<programlisting>&soundex;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="liferef"/></para>
|
|
<example id="lifeslow">
|
|
<title><firstterm>Game of Life</firstterm></title>
|
|
<programlisting>&lifeslow;</programlisting>
|
|
</example>
|
|
|
|
<example id="gen0data">
|
|
<title>Data file for <firstterm>Game of Life</firstterm></title>
|
|
<programlisting>&gen0data;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para>+++</para>
|
|
|
|
<para>The following script is by Mark Moraes of the University
|
|
of Toronto. See the file <filename>Moraes-COPYRIGHT</filename>
|
|
for permissions and restrictions. This file is included in the
|
|
combined <link linkend="where_tarball">HTML/source tarball</link>
|
|
of the <emphasis>ABS Guide</emphasis>.</para>
|
|
|
|
<example id="behead">
|
|
<title><firstterm>behead</firstterm>: Removing mail and news
|
|
message headers</title>
|
|
<programlisting>&behead;</programlisting>
|
|
</example>
|
|
|
|
<para>+</para>
|
|
|
|
<para>Antek Sawicki contributed the following script, which makes very
|
|
clever use of the parameter substitution operators discussed in
|
|
<xref linkend="Parameter-Substitution"/>.</para>
|
|
|
|
<para><anchor id="pw0"/></para>
|
|
<example id="pw">
|
|
<title><firstterm>password</firstterm>: Generating random
|
|
8-character passwords</title>
|
|
<programlisting>&pw;</programlisting>
|
|
</example>
|
|
|
|
<para>+</para>
|
|
|
|
<para><anchor id="zfifo"/>James R. Van Zandt contributed this script
|
|
which uses named pipes and, in his words, <quote>really exercises
|
|
quoting and escaping.</quote></para>
|
|
|
|
<example id="fifo">
|
|
<title><firstterm>fifo</firstterm>: Making daily backups, using
|
|
named pipes</title>
|
|
<programlisting>&fifo;</programlisting>
|
|
</example>
|
|
|
|
<para>+</para>
|
|
|
|
<para><anchor id="primes1"/></para>
|
|
<para>Stéphane Chazelas used the following script to
|
|
demonstrate generating prime numbers without arrays.</para>
|
|
|
|
<para><anchor id="primes00"/></para>
|
|
<example id="primes">
|
|
<title>Generating prime numbers using the modulo operator</title>
|
|
<programlisting>ℙ</programlisting>
|
|
</example>
|
|
|
|
<para>+</para>
|
|
|
|
<para>Rick Boivie's revision of Jordi Sanfeliu's
|
|
<emphasis>tree</emphasis> script.</para>
|
|
|
|
<example id="tree">
|
|
<title><firstterm>tree</firstterm>: Displaying a directory tree</title>
|
|
<programlisting>&tree;</programlisting>
|
|
</example>
|
|
|
|
<para>Patsie's version of a directory <firstterm>tree</firstterm>
|
|
script.</para>
|
|
|
|
<example id="tree2">
|
|
<title><firstterm>tree2</firstterm>: Alternate directory tree script</title>
|
|
<programlisting>&tree2;</programlisting>
|
|
</example>
|
|
|
|
<para>Noah Friedman permitted use of his <emphasis>string
|
|
function</emphasis> script. It essentially reproduces some
|
|
of the <firstterm>C</firstterm>-library string manipulation
|
|
functions.</para>
|
|
|
|
<example id="string">
|
|
<title><firstterm>string functions</firstterm>: C-style string
|
|
functions</title>
|
|
<programlisting>&string;</programlisting>
|
|
</example>
|
|
|
|
<para>Michael Zick's complex array example uses the <link
|
|
linkend="md5sumref">md5sum</link> check sum command to encode directory
|
|
information.</para>
|
|
|
|
<example id="directoryinfo">
|
|
<title>Directory information</title>
|
|
<programlisting>&directoryinfo;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>Stéphane Chazelas demonstrates object-oriented programming in a
|
|
Bash script.</para>
|
|
|
|
<para>Mariusz Gniazdowski contributed a <link linkend="hashref">hash</link>
|
|
library for use in scripts.</para>
|
|
|
|
<example id="hashlib">
|
|
<title>Library of hash functions</title>
|
|
<programlisting>&hashlib;</programlisting>
|
|
</example>
|
|
|
|
<para>Here is an example script using the foregoing hash library.</para>
|
|
|
|
<example id="hashexample">
|
|
<title>Colorizing text using hash functions</title>
|
|
<programlisting>&hashexample;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="hashex2_0"/>An example illustrating the mechanics
|
|
of hashing, but from a different point of view.</para>
|
|
|
|
<example id="hashex2">
|
|
<title>More on hash functions</title>
|
|
<programlisting>&hashex2;</programlisting>
|
|
</example>
|
|
|
|
<para>Now for a script that installs and mounts
|
|
those cute USB keychain solid-state <quote>hard drives.</quote></para>
|
|
|
|
<example id="usbinst">
|
|
<title>Mounting USB keychain storage devices</title>
|
|
<programlisting>&usbinst;</programlisting>
|
|
</example>
|
|
|
|
<para>Converting a text file to HTML format.</para>
|
|
|
|
<example id="tohtml">
|
|
<title>Converting to HTML</title>
|
|
<programlisting>&tohtml;</programlisting>
|
|
</example>
|
|
|
|
<para>Here is something to warm the hearts of webmasters and mistresses:
|
|
a script that saves weblogs.</para>
|
|
|
|
<example id="archivweblogs">
|
|
<title>Preserving weblogs</title>
|
|
<programlisting>&archiveweblogs;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="protectliteral0"/>How to keep the shell from
|
|
expanding and reinterpreting text strings.</para>
|
|
|
|
<example id="protectliteral">
|
|
<title>Protecting literal strings</title>
|
|
<programlisting>&protectliteral;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="unprotectliteral0"/>But, what if you
|
|
<emphasis>want</emphasis> the shell to expand
|
|
and reinterpret strings?</para>
|
|
|
|
<example id="unprotectliteral">
|
|
<title>Unprotecting literal strings</title>
|
|
<programlisting>&unprotectliteral;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>This interesting script helps hunt down spammers.</para>
|
|
|
|
<para><anchor id="isspammer2_0"/></para>
|
|
<example id="isspammer2">
|
|
<title>Spammer Identification</title>
|
|
<programlisting>&isspammer2;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para>Another anti-spam script.</para>
|
|
|
|
<para><anchor id="whx0"/></para>
|
|
<example id="whx">
|
|
<title>Spammer Hunt</title>
|
|
<programlisting>&whx;</programlisting>
|
|
</example>
|
|
|
|
|
|
<para><quote>Little Monster's</quote> front end to <link
|
|
linkend="wgetref">wget</link>.</para>
|
|
|
|
<example id="wgetter2">
|
|
<title>Making <firstterm>wget</firstterm> easier to use</title>
|
|
<programlisting>&wgetter2;</programlisting>
|
|
</example>
|
|
|
|
<example id="bashpodder">
|
|
<title>A <firstterm>podcasting</firstterm> script</title>
|
|
<programlisting>&bashpodder;</programlisting>
|
|
</example>
|
|
|
|
<example id="nightlybackup">
|
|
<title>Nightly backup to a firewire HD</title>
|
|
<programlisting>&nightlybackup;</programlisting>
|
|
</example>
|
|
|
|
<example id="cdll">
|
|
<title>An expanded <firstterm>cd</firstterm> command</title>
|
|
<programlisting>&cdll;</programlisting>
|
|
</example>
|
|
|
|
<example id="soundcardon">
|
|
<title>A soundcard setup script</title>
|
|
<programlisting>&soundcardon;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="findsplit0"/></para>
|
|
<example id="findsplit">
|
|
<title>Locating split paragraphs in a text file</title>
|
|
<programlisting>&findsplit;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="insertionsort0"/></para>
|
|
<example id="insertionsort">
|
|
<title>Insertion sort</title>
|
|
<programlisting>&insertionsort;</programlisting>
|
|
</example>
|
|
|
|
<example id="stddev">
|
|
<title>Standard Deviation</title>
|
|
<programlisting>&stddev;</programlisting>
|
|
</example>
|
|
|
|
<example id="padsw">
|
|
<title>A <firstterm>pad</firstterm> file generator for shareware
|
|
authors</title>
|
|
<programlisting>&padsw;</programlisting>
|
|
</example>
|
|
|
|
<example id="maned">
|
|
<title>A <firstterm>man page</firstterm> editor</title>
|
|
<programlisting>&maned;</programlisting>
|
|
</example>
|
|
|
|
<example id="petals">
|
|
<title>Petals Around the Rose</title>
|
|
<programlisting>&petals;</programlisting>
|
|
</example>
|
|
|
|
<example id="qky">
|
|
<title>Quacky: a Perquackey-type word game</title>
|
|
<programlisting>&qky;</programlisting>
|
|
</example>
|
|
|
|
<example id="nim">
|
|
<title>Nim</title>
|
|
<programlisting>&nim;</programlisting>
|
|
</example>
|
|
|
|
<example id="stopwatch">
|
|
<title>A command-line stopwatch</title>
|
|
<programlisting>&stopwatch;</programlisting>
|
|
</example>
|
|
|
|
<example id="homework">
|
|
<title>An all-purpose shell scripting homework assignment solution</title>
|
|
<programlisting>&homework;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="ktour0"/></para>
|
|
<example id="ktour">
|
|
<title>The Knight's Tour</title>
|
|
<programlisting>&ktour;</programlisting>
|
|
</example>
|
|
|
|
<example id="msquare">
|
|
<title>Magic Squares</title>
|
|
<programlisting>&msquare;</programlisting>
|
|
</example>
|
|
|
|
<example id="fifteen">
|
|
<title>Fifteen Puzzle</title>
|
|
<programlisting>&fifteen;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="hanoi2ref"/></para>
|
|
<example id="hanoi2">
|
|
<title><firstterm>The Towers of Hanoi, graphic
|
|
version</firstterm></title>
|
|
<programlisting>&hanoi2;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="hanoi2aref"/></para>
|
|
<example id="hanoi2a">
|
|
<title><firstterm>The Towers of Hanoi, alternate graphic
|
|
version</firstterm></title>
|
|
<programlisting>&hanoi2a;</programlisting>
|
|
</example>
|
|
|
|
<example id="usegetopt">
|
|
<title>An alternate version of the
|
|
<link linkend="getoptsimple">getopt-simple.sh</link> script</title>
|
|
<programlisting>&usegetopt;</programlisting>
|
|
</example>
|
|
|
|
<example id="usegetopt2">
|
|
<title>The version of the
|
|
<firstterm>UseGetOpt.sh</firstterm> example used in the <link
|
|
linkend="tabexpansion">Tab Expansion appendix</link></title>
|
|
<programlisting>&usegetopt2;</programlisting>
|
|
</example>
|
|
|
|
<example id="showallc">
|
|
<title>Cycling through all the possible color backgrounds</title>
|
|
<programlisting>&showallc;</programlisting>
|
|
</example>
|
|
|
|
<example id="samorse">
|
|
<title>Morse Code Practice</title>
|
|
<programlisting>&samorse;</programlisting>
|
|
</example>
|
|
|
|
<example id="base64">
|
|
<title>Base64 encoding/decoding</title>
|
|
<programlisting>&base64;</programlisting>
|
|
</example>
|
|
|
|
<example id="sedappend">
|
|
<title>Inserting text in a file using
|
|
<firstterm>sed</firstterm></title>
|
|
<programlisting>&sedappend;</programlisting>
|
|
</example>
|
|
|
|
<example id="gronsfeld">
|
|
<title>The Gronsfeld Cipher</title>
|
|
<programlisting>&gronsfeld;</programlisting>
|
|
</example>
|
|
|
|
<example id="bingo">
|
|
<title>Bingo Number Generator</title>
|
|
<programlisting>&bingo;</programlisting>
|
|
</example>
|
|
|
|
<para><anchor id="basicsrev0"/>To end this section, a review of the
|
|
basics . . . and more.</para>
|
|
|
|
<example id="basicsreviewed">
|
|
<title>Basics Reviewed</title>
|
|
<programlisting>&basicsreviewed;</programlisting>
|
|
</example>
|
|
|
|
<example id="testexectime">
|
|
<title>Testing execution times of various commands</title>
|
|
<programlisting>&testexectime;</programlisting>
|
|
</example>
|
|
|
|
<example id="assocarrtest">
|
|
<title>Associative arrays vs. conventional arrays (execution
|
|
times)</title>
|
|
<programlisting>&assocarrtest;</programlisting>
|
|
</example>
|
|
|
|
|
|
</appendix>
|
|
<!-- End Contributed Scripts appendix -->
|
|
|
|
|
|
|
|
|
|
<appendix id="refcards">
|
|
<title>Reference Cards</title>
|
|
|
|
<para>The following reference cards provide a useful
|
|
<emphasis>summary</emphasis> of certain scripting concepts.
|
|
The foregoing text treats these matters in more depth, as well as
|
|
giving usage examples.</para>
|
|
|
|
<para><anchor id="specshvartab"/></para>
|
|
<table pgwide="0">
|
|
<title>Special Shell Variables</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Variable</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>$0</option></entry>
|
|
<entry>Filename of script</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$1</option></entry>
|
|
<entry>Positional parameter #1</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$2 - $9</option></entry>
|
|
<entry>Positional parameters #2 - #9</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${10}</option></entry>
|
|
<entry>Positional parameter #10</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$#</option></entry>
|
|
<entry>Number of positional parameters</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>"$*"</option></entry>
|
|
<entry>All the positional parameters (as a single word) *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>"$@"</option></entry>
|
|
<entry>All the positional parameters (as separate strings)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${#*}</option></entry>
|
|
<entry>Number of positional parameters</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${#@}</option></entry>
|
|
<entry>Number of positional parameters</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$?</option></entry>
|
|
<entry>Return value</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$$</option></entry>
|
|
<entry>Process ID (PID) of script</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$-</option></entry>
|
|
<entry>Flags passed to script (using
|
|
<firstterm>set</firstterm>)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$_</option></entry>
|
|
<entry>Last argument of previous command</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>$!</option></entry>
|
|
<entry>Process ID (PID) of last job run in background</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para><command>*</command> <emphasis>Must be quoted</emphasis>,
|
|
otherwise it defaults to
|
|
<varname>$@</varname>.</para>
|
|
|
|
|
|
<para><anchor id="bincomptab"/></para>
|
|
<table>
|
|
<title>TEST Operators: Binary Comparison</title>
|
|
<tgroup cols="5">
|
|
<thead>
|
|
<row>
|
|
<entry>Operator</entry>
|
|
<entry>Meaning</entry>
|
|
<entry>-----</entry>
|
|
<entry>Operator</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="icomparison1">Arithmetic
|
|
Comparison</link></entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry><link linkend="scomparison1">String
|
|
Comparison</link></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-eq</option></entry>
|
|
<entry>Equal to</entry>
|
|
<entry></entry>
|
|
<entry><option>=</option></entry>
|
|
<entry>Equal to</entry>
|
|
</row>
|
|
<row>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
<entry><option>==</option></entry>
|
|
<entry>Equal to</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-ne</option></entry>
|
|
<entry>Not equal to</entry>
|
|
<entry></entry>
|
|
<entry><option>!=</option></entry>
|
|
<entry>Not equal to</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-lt</option></entry>
|
|
<entry>Less than</entry>
|
|
<entry></entry>
|
|
<entry><option>\<</option></entry>
|
|
<entry>Less than (<link linkend="asciidef">ASCII</link>) *</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><link linkend="dblprx">within double
|
|
parentheses</link> (( ... ))</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> <token>[[ ... ]]</token> <emphasis>test construct,
|
|
then no escape</emphasis> <token>\</token> <emphasis>is
|
|
needed.</emphasis></para>
|
|
|
|
<para><anchor id="filestab"/></para>
|
|
<table>
|
|
<title>TEST Operators: Files</title>
|
|
<tgroup cols="5">
|
|
<thead>
|
|
<row>
|
|
<entry>Operator</entry>
|
|
<entry>Tests Whether</entry>
|
|
<entry>-----</entry>
|
|
<entry>Operator</entry>
|
|
<entry>Tests Whether</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>-e</option></entry>
|
|
<entry>File exists</entry>
|
|
<entry></entry>
|
|
<entry><option>-s</option></entry>
|
|
<entry>File is not zero size</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-f</option></entry>
|
|
<entry>File is a <firstterm>regular</firstterm> file</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-d</option></entry>
|
|
<entry>File is a <firstterm>directory</firstterm></entry>
|
|
<entry></entry>
|
|
<entry><option>-r</option></entry>
|
|
<entry>File has <firstterm>read</firstterm>
|
|
permission</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-h</option></entry>
|
|
<entry>File is a <link linkend="symlinkref">symbolic link</link></entry>
|
|
<entry></entry>
|
|
<entry><option>-w</option></entry>
|
|
<entry>File has <firstterm>write</firstterm>
|
|
permission</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-L</option></entry>
|
|
<entry>File is a <firstterm>symbolic link</firstterm></entry>
|
|
<entry></entry>
|
|
<entry><option>-x</option></entry>
|
|
<entry>File has <firstterm>execute</firstterm>
|
|
permission</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-b</option></entry>
|
|
<entry>File is a <link linkend="blockdevref">block
|
|
device</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-c</option></entry>
|
|
<entry>File is a <link linkend="chardevref">character
|
|
device</link></entry>
|
|
<entry></entry>
|
|
<entry><option>-g</option></entry>
|
|
<entry><firstterm>sgid</firstterm> flag set</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-p</option></entry>
|
|
<entry>File is a <link linkend="piperef">pipe</link></entry>
|
|
<entry></entry>
|
|
<entry><option>-u</option></entry>
|
|
<entry><firstterm>suid</firstterm> flag set</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-S</option></entry>
|
|
<entry>File is a <link linkend="socketref">socket</link></entry>
|
|
<entry></entry>
|
|
<entry><option>-k</option></entry>
|
|
<entry><quote>sticky bit</quote> set</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-t</option></entry>
|
|
<entry>File is associated with a
|
|
<firstterm>terminal</firstterm></entry>
|
|
</row>
|
|
<row><entry></entry></row>
|
|
<row>
|
|
<entry><option>-N</option></entry>
|
|
<entry>File modified since it was last read</entry>
|
|
<entry></entry>
|
|
<entry><option>F1 -nt F2</option></entry>
|
|
<entry>File F1 is <emphasis>newer</emphasis> than F2 *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-O</option></entry>
|
|
<entry>You own the file</entry>
|
|
<entry></entry>
|
|
<entry><option>F1 -ot F2</option></entry>
|
|
<entry>File F1 is <emphasis>older</emphasis> than F2 *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>-G</option></entry>
|
|
<entry><firstterm>Group id</firstterm> of file same as
|
|
yours</entry>
|
|
<entry></entry>
|
|
<entry><option>F1 -ef F2</option></entry>
|
|
<entry>Files F1 and F2 are <firstterm>hard links</firstterm>
|
|
to the same file *</entry>
|
|
</row>
|
|
<row><entry></entry></row>
|
|
<row>
|
|
<entry><option>!</option></entry>
|
|
<entry>NOT (inverts sense of above tests)</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
<para><command>*</command> <firstterm>Binary</firstterm> operator
|
|
(requires two operands).</para>
|
|
|
|
|
|
|
|
|
|
<para><anchor id="parsubtab"/></para>
|
|
<table pgwide="0">
|
|
<title>Parameter Substitution and Expansion</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>${var}</option></entry>
|
|
<entry>Value of <parameter>var</parameter> (same as
|
|
<parameter>$var</parameter>)</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${var-$DEFAULT}</option></entry>
|
|
<entry>If <parameter>var</parameter> not set, <link
|
|
linkend="evalref">evaluate</link> expression
|
|
as <parameter>$DEFAULT</parameter> *</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${var:-$DEFAULT}</option></entry>
|
|
<entry>If <parameter>var</parameter> not set or is empty,
|
|
<firstterm>evaluate</firstterm> 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 or is empty, 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> and abort script
|
|
with an exit status of <errorcode>1</errorcode>.*</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${var:?$ERR_MSG}</option></entry>
|
|
<entry>If <parameter>var</parameter> not set, print
|
|
<parameter>$ERR_MSG</parameter> and abort script
|
|
with an exit status of <errorcode>1</errorcode>.*</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> If <parameter>var</parameter>
|
|
<emphasis>is</emphasis> set, evaluate the expression as
|
|
<parameter>$var</parameter> with no side-effects.</para>
|
|
<para><command># Note</command> that some of the above behavior
|
|
of operators has changed from earlier versions of Bash.</para>
|
|
|
|
|
|
<para><anchor id="stringopstab"/></para>
|
|
<table pgwide="0">
|
|
<title>String Operations</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Meaning</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>${#string}</option></entry>
|
|
<entry>Length of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><option>${string:position}</option></entry>
|
|
<entry>Extract substring from <parameter>$string</parameter>
|
|
at <parameter>$position</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${string:position:length}</option></entry>
|
|
<entry>Extract <parameter>$length</parameter>
|
|
characters substring from <parameter>$string</parameter>
|
|
at <parameter>$position</parameter> [zero-indexed,
|
|
first character is at position 0]</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 [0 if no match, first character counts as
|
|
position 1]</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> [0 if no match, first
|
|
character counts as position 1]</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr match "$string"
|
|
'\($substring\)'</option></entry>
|
|
<entry>Extract <parameter>$substring</parameter>*, searching
|
|
from beginning of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr "$string" :
|
|
'\($substring\)'</option></entry>
|
|
<entry>Extract <parameter>$substring</parameter>* , searching
|
|
from beginning of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr match "$string"
|
|
'.*\($substring\)'</option></entry>
|
|
<entry>Extract <parameter>$substring</parameter>*, searching
|
|
from end of <parameter>$string</parameter></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>expr "$string" :
|
|
'.*\($substring\)'</option></entry>
|
|
<entry>Extract <parameter>$substring</parameter>*, searching
|
|
from end of <parameter>$string</parameter></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para><command>*</command> Where <parameter>$substring</parameter> is a
|
|
<link linkend="regexref">Regular Expression</link>.</para>
|
|
|
|
|
|
|
|
<para><anchor id="misctab"/></para>
|
|
<table pgwide="0">
|
|
<title>Miscellaneous Constructs</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Interpretation</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><link linkend="bracketsref">Brackets</link></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>if [ CONDITION ]</option></entry>
|
|
<entry><link linkend="leftbracket">Test construct</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>if [[ CONDITION ]]</option></entry>
|
|
<entry><link linkend="dblbrackets">Extended test construct</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>Array[1]=element1</option></entry>
|
|
<entry><link linkend="arrayref">Array initialization</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option> [a-z]</option></entry>
|
|
<entry><link linkend="bracketsref">Range of
|
|
characters</link> within a <link linkend="regexref">Regular
|
|
Expression</link></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry>Curly Brackets</entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${variable}</option></entry>
|
|
<entry><link linkend="paramsubref">Parameter substitution</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>${!variable}</option></entry>
|
|
<entry><link linkend="ivrref">Indirect variable reference</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>{ command1; command2; . . . commandN; }</option></entry>
|
|
<entry><link linkend="codeblockref">Block of code</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>{string1,string2,string3,...}</option></entry>
|
|
<entry><link linkend="braceexpref">Brace expansion</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>{a..z}</option></entry>
|
|
<entry><link linkend="braceexpref3">Extended brace expansion</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>{}</option></entry>
|
|
<entry>Text replacement, after <link
|
|
linkend="curlybracketsref">find</link> and <link
|
|
linkend="xargscurlyref">xargs</link></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><link linkend="parensref">Parentheses</link></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>( command1; command2 )</option></entry>
|
|
<entry>Command group executed within a <link
|
|
linkend="subshellsref">subshell</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>Array=(element1 element2 element3)</option></entry>
|
|
<entry><link linkend="arrayinit0">Array initialization</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>result=$(COMMAND)</option></entry>
|
|
<entry><link linkend="csparens">Command substitution</link>,
|
|
new style</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>>(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><link linkend="dblparens">Double Parentheses</link></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>(( var = 78 ))</option></entry>
|
|
<entry><link linkend="dblparensref">Integer arithmetic</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>var=$(( 20 + 5 ))</option></entry>
|
|
<entry>Integer arithmetic, with variable assignment</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>(( var++ ))</option></entry>
|
|
<entry><firstterm>C-style</firstterm> <link
|
|
linkend="plusplusref"> variable increment</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>(( var-- ))</option></entry>
|
|
<entry><firstterm>C-style</firstterm> <link
|
|
linkend="plusplusref"> variable decrement</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>(( var0 = var1<98?9:21 ))</option></entry>
|
|
<entry><firstterm>C-style</firstterm> <link
|
|
linkend="cstrinary"> ternary</link> operation</entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><link linkend="quotingref">Quoting</link></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>"$variable"</option></entry>
|
|
<entry><link linkend="dblquo">"Weak" quoting</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>'string'</option></entry>
|
|
<entry><link linkend="snglquo">'Strong' quoting</link></entry>
|
|
</row>
|
|
<row><entry></entry><entry></entry></row>
|
|
<row>
|
|
<entry><link linkend="backquotesref">Back Quotes</link></entry><entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>result=`COMMAND`</option></entry>
|
|
<entry><link linkend="commandsubref">Command
|
|
substitution</link>, classic style</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
</appendix>
|
|
<!-- Reference Cards appendix -->
|
|
|
|
|
|
|
|
|
|
|
|
<appendix id="sedawk">
|
|
<title>A Sed and Awk Micro-Primer</title>
|
|
|
|
<para><anchor id="sedref"/></para>
|
|
|
|
<para>This is a very brief introduction to the <command>sed</command>
|
|
and <command>awk</command> text processing utilities. We will
|
|
deal with only a few basic commands here, but that will suffice
|
|
for understanding simple sed and awk constructs within shell
|
|
scripts.</para>
|
|
|
|
|
|
<para><command>sed</command>: a non-interactive
|
|
text file editor</para>
|
|
|
|
<para><command>awk</command>: a field-oriented pattern processing
|
|
language with a <command>C</command>-style syntax</para>
|
|
|
|
<para>For all their differences, the two utilities share a similar
|
|
invocation syntax, use <link linkend="regexref">regular
|
|
expressions </link>, read input by default
|
|
from <filename>stdin</filename>, and output to
|
|
<filename>stdout</filename>. These are well-behaved UNIX tools,
|
|
and they work together well. The output from one can be piped
|
|
to the other, and their combined capabilities give shell scripts
|
|
some of the power of <link linkend="perlref">Perl</link>.</para>
|
|
|
|
<note><para>One important difference between the utilities is
|
|
that while shell scripts can easily pass arguments to sed, it
|
|
is more cumbersome for awk (see <xref linkend="coltotaler"/>
|
|
and <xref linkend="coltotaler2"/>).
|
|
</para></note>
|
|
|
|
|
|
<sect1>
|
|
<title>Sed</title>
|
|
|
|
<para><firstterm>Sed</firstterm> is a non-interactive
|
|
<footnote><para><firstterm>Sed</firstterm> executes without
|
|
user intervention.</para></footnote>
|
|
<command>s</command>tream <command>ed</command>itor. It
|
|
receives text input, whether from <filename>stdin</filename>
|
|
or from a file, performs certain operations on specified lines
|
|
of the input, one line at a time, then outputs the result to
|
|
<filename>stdout</filename> or to a file. Within a shell script,
|
|
<firstterm>sed</firstterm> is usually one of several tool
|
|
components in a pipe.</para>
|
|
|
|
<para><firstterm>Sed</firstterm> determines which lines of
|
|
its input that it will operate on from the <firstterm>address
|
|
range</firstterm> passed to it.
|
|
<footnote><para>If no address range is specified, the default
|
|
is <emphasis>all</emphasis> lines.</para></footnote>
|
|
Specify this address range either by line number or by a
|
|
pattern to match. For example, <replaceable>3d</replaceable>
|
|
signals <firstterm>sed</firstterm> 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 <firstterm>sed</firstterm>
|
|
toolkit, we will focus primarily on the three most commonly
|
|
used ones. These are <command>p</command>rinting (to
|
|
<filename>stdout</filename>), <command>d</command>eletion,
|
|
and <command>s</command>ubstitution.</para>
|
|
|
|
|
|
<para><anchor id="sedbasictable"/></para>
|
|
<table>
|
|
<title>Basic sed operators</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Operator</entry>
|
|
<entry>Name</entry>
|
|
<entry>Effect</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>[address-range]/p</option></entry>
|
|
<entry>print</entry>
|
|
<entry>Print [specified address range]</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>[address-range]/d</option></entry>
|
|
<entry>delete</entry>
|
|
<entry>Delete [specified address range]</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/pattern1/pattern2/</option></entry>
|
|
<entry>substitute</entry>
|
|
<entry>Substitute pattern2 for first instance of pattern1 in a line</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>[address-range]/s/pattern1/pattern2/</option></entry>
|
|
<entry>substitute</entry>
|
|
<entry>Substitute pattern2 for first instance of pattern1 in a
|
|
line, over <replaceable>address-range</replaceable></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>[address-range]/y/pattern1/pattern2/</option></entry>
|
|
<entry>transform</entry>
|
|
<entry>replace any character in pattern1 with the
|
|
corresponding character in pattern2, over
|
|
<replaceable>address-range</replaceable> (equivalent of
|
|
<command>tr</command>)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>[address] i pattern Filename</option></entry>
|
|
<entry>insert</entry>
|
|
<entry>Insert pattern at address indicated in file Filename.
|
|
Usually used with <option>-i</option>
|
|
<replaceable>in-place</replaceable> option.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>g</option></entry>
|
|
<entry>global</entry>
|
|
<entry>Operate on <emphasis>every</emphasis> pattern match
|
|
within each matched line of input</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<note><para>Unless the <option>g</option>
|
|
(<firstterm>global</firstterm>) operator is appended to a
|
|
<firstterm>substitute</firstterm> command, the substitution
|
|
operates only on the <emphasis>first</emphasis> instance of a
|
|
pattern match within each line.</para></note>
|
|
|
|
<para>From the command-line and in a shell script, a sed operation may
|
|
require quoting and certain options.</para>
|
|
|
|
<para><programlisting>sed -e '/^$/d' $filename
|
|
# The -e option causes the next string to be interpreted as an editing instruction.
|
|
# (If passing only a single instruction to sed, the "-e" is optional.)
|
|
# The "strong" quotes ('') protect the RE characters in the instruction
|
|
#+ from reinterpretation as special characters by the body of the script.
|
|
# (This reserves RE expansion of the instruction for sed.)
|
|
#
|
|
# Operates on the text contained in file $filename.
|
|
</programlisting></para>
|
|
|
|
<para>In certain cases, a <firstterm>sed</firstterm> editing command will
|
|
not work with single quotes.</para>
|
|
|
|
<para><programlisting>
|
|
filename=file1.txt
|
|
pattern=BEGIN
|
|
|
|
sed "/^$pattern/d" "$filename" # Works as specified.
|
|
# sed '/^$pattern/d' "$filename" has unexpected results.
|
|
# In this instance, with strong quoting (' ... '),
|
|
#+ "$pattern" will not expand to "BEGIN".</programlisting></para>
|
|
|
|
|
|
<note><para><firstterm>Sed</firstterm> uses the <option>-e</option>
|
|
option to specify that the following string is an instruction
|
|
or set of instructions. If there is only a single instruction
|
|
contained in the string, then this may be omitted.</para></note>
|
|
|
|
<para><programlisting>sed -n '/xzy/p' $filename
|
|
# The -n option tells sed to print only those lines matching the pattern.
|
|
# Otherwise all input lines would print.
|
|
# The -e option not necessary here since there is only a single editing instruction.
|
|
</programlisting></para>
|
|
|
|
<para><anchor id="sedoptable"/></para>
|
|
<table>
|
|
<title>Examples of sed operators</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Notation</entry>
|
|
<entry>Effect</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>8d</option></entry>
|
|
<entry>Delete 8th line of input.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>/^$/d</option></entry>
|
|
<entry>Delete all blank lines.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1,/^$/d</option></entry>
|
|
<entry>Delete from beginning of input up to, and including
|
|
first blank line.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>/Jones/p</option></entry>
|
|
<entry>Print only lines containing <quote>Jones</quote> (with
|
|
<token>-n</token> option).</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/Windows/Linux/</option></entry>
|
|
<entry>Substitute <quote>Linux</quote> for first instance
|
|
of <quote>Windows</quote> found in each input line.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/BSOD/stability/g</option></entry>
|
|
<entry>Substitute <quote>stability</quote> for every instance
|
|
of <quote>BSOD</quote> found in each input line.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/ *$//</option></entry>
|
|
<entry>Delete all spaces at the end of every line.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/00*/0/g</option></entry>
|
|
<entry>Compress all consecutive sequences of zeroes into
|
|
a single zero.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>echo "Working on it." | sed -e '1i How far are you along?'</option></entry>
|
|
<entry>Prints "How far are you along?" as first line,
|
|
"Working on it" as second.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>5i 'Linux is great.' file.txt</option></entry>
|
|
<entry>Inserts 'Linux is great.' at line 5 of the file
|
|
file.txt.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>/GUI/d</option></entry>
|
|
<entry>Delete all lines containing <quote>GUI</quote>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>s/GUI//g</option></entry>
|
|
<entry>Delete all instances of <quote>GUI</quote>, leaving the
|
|
remainder of each line intact.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
<para>Substituting a zero-length string for another is equivalent
|
|
to deleting that string within a line of input. This leaves the
|
|
remainder of the line intact. Applying <userinput>s/GUI//</userinput>
|
|
to the line
|
|
<screen><userinput>The most important parts of any application are its GUI and sound effects</userinput></screen>
|
|
results in
|
|
<screen><computeroutput>The most important parts of any application are its and sound effects</computeroutput></screen></para>
|
|
|
|
<para>A backslash forces the <command>sed</command> replacement
|
|
command to continue on to the next line. This has the effect of
|
|
using the <firstterm>newline</firstterm> at the end of the first
|
|
line as the <firstterm>replacement string</firstterm>.
|
|
|
|
<programlisting>s/^ */\
|
|
/g</programlisting>
|
|
|
|
This substitution replaces line-beginning spaces with a
|
|
newline. The net result is to replace paragraph indents with a
|
|
blank line between paragraphs.</para>
|
|
|
|
<para>An address range followed by one or more operations may require
|
|
open and closed curly brackets, with appropriate newlines.
|
|
<programlisting>/[0-9A-Za-z]/,/^$/{
|
|
/^$/d
|
|
}</programlisting>
|
|
This deletes only the first of each set of consecutive blank
|
|
lines. That might be useful for single-spacing a text file,
|
|
but retaining the blank line(s) between paragraphs.</para>
|
|
|
|
|
|
<note><para>The usual delimiter that <firstterm>sed</firstterm> uses is
|
|
<token>/</token>. However, <emphasis>sed</emphasis> allows other
|
|
delimiters, such as <token>%</token>. This is useful when
|
|
<token>/</token> is part of a replacement string, as in a file pathname.
|
|
See <xref linkend="findstring"/> and <xref
|
|
linkend="stripc"/>.</para></note>
|
|
|
|
<para><anchor id="doublespace"/></para>
|
|
<tip><para>A quick way to double-space a text file is <userinput>sed G
|
|
filename</userinput>.</para></tip>
|
|
|
|
<para>For illustrative examples of sed within shell scripts, see:
|
|
<orderedlist>
|
|
<listitem><para><xref linkend="ex3"/></para></listitem>
|
|
<listitem><para><xref linkend="ex4"/></para></listitem>
|
|
<listitem><para><xref linkend="ex57"/></para></listitem>
|
|
<listitem><para><xref linkend="rn"/></para></listitem>
|
|
<listitem><para><xref linkend="grp"/></para></listitem>
|
|
<listitem><para><xref linkend="col"/></para></listitem>
|
|
<listitem><para><xref linkend="behead"/></para></listitem>
|
|
<listitem><para><xref linkend="tree"/></para></listitem>
|
|
<listitem><para><xref linkend="tree2"/></para></listitem>
|
|
<listitem><para><xref linkend="stripc"/></para></listitem>
|
|
<listitem><para><xref linkend="findstring"/></para></listitem>
|
|
<listitem><para><xref linkend="base"/></para></listitem>
|
|
<listitem><para><xref linkend="mailformat"/></para></listitem>
|
|
<listitem><para><xref linkend="rnd"/></para></listitem>
|
|
<listitem><para><xref linkend="wf"/></para></listitem>
|
|
<listitem><para><xref linkend="lifeslow"/></para></listitem>
|
|
<listitem><para><xref linkend="selfdocument"/></para></listitem>
|
|
<listitem><para><xref linkend="dictlookup"/></para></listitem>
|
|
<listitem><para><xref linkend="whx"/></para></listitem>
|
|
<listitem><para><xref linkend="bashpodder"/></para></listitem>
|
|
<listitem><para><xref linkend="tohtml"/></para></listitem>
|
|
<listitem><para><xref linkend="stopwatch"/></para></listitem>
|
|
<listitem><para><xref linkend="sedappend"/></para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<para>For a more extensive treatment of <firstterm>sed</firstterm>,
|
|
refer to the <link linkend="dgsedref">pertinent references</link>
|
|
in the <xref linkend="biblio"/>.</para>
|
|
|
|
</sect1>
|
|
<!-- End sed primer -->
|
|
|
|
|
|
|
|
<sect1 id="awk">
|
|
<title>Awk</title>
|
|
|
|
<para><anchor id="awkref"/></para>
|
|
|
|
<para><firstterm>Awk</firstterm>
|
|
<footnote><para>Its name derives from the initials of its authors,
|
|
<command>A</command>ho, <command>W</command>einberg, and
|
|
<command>K</command>ernighan.</para></footnote>
|
|
is a full-featured text processing language with a syntax
|
|
reminiscent of <firstterm>C</firstterm>. While it possesses an
|
|
extensive set of operators and capabilities, we will cover only
|
|
a few of these here - the ones most useful in shell scripts.</para>
|
|
|
|
<para>Awk breaks each line of input passed to it into
|
|
<anchor id="fieldref2"/>
|
|
<link linkend="fieldref">fields</link>. By default, a field
|
|
is a string of consecutive characters delimited by <link
|
|
linkend="whitespaceref">whitespace</link>, though there are options
|
|
for changing this. Awk parses and operates on each separate
|
|
field. This makes it ideal for handling structured text files
|
|
-- especially tables -- data organized into consistent chunks,
|
|
such as rows and columns.</para>
|
|
|
|
<para><link linkend="snglquo">Strong quoting</link> and <link
|
|
linkend="codeblockref">curly brackets</link> enclose blocks of
|
|
awk code within a shell script.</para>
|
|
|
|
<para><programlisting># $1 is field #1, $2 is field #2, etc.
|
|
|
|
echo one two | awk '{print $1}'
|
|
# one
|
|
|
|
echo one two | awk '{print $2}'
|
|
# two
|
|
|
|
# But what is field #0 ($0)?
|
|
echo one two | awk '{print $0}'
|
|
# one two
|
|
# All the fields!
|
|
|
|
|
|
awk '{print $3}' $filename
|
|
# Prints field #3 of file $filename to stdout.
|
|
|
|
awk '{print $1 $5 $6}' $filename
|
|
# Prints fields #1, #5, and #6 of file $filename.
|
|
|
|
awk '{print $0}' $filename
|
|
# Prints the entire file!
|
|
# Same effect as: cat $filename . . . or . . . sed '' $filename</programlisting></para>
|
|
|
|
<para>We have just seen the awk <firstterm>print</firstterm> command
|
|
in action. The only other feature of awk we need to deal with
|
|
here is variables. Awk handles variables similarly to shell
|
|
scripts, though a bit more flexibly.</para>
|
|
|
|
<para><programlisting>{ total += ${column_number} }</programlisting>
|
|
This adds the value of <parameter>column_number</parameter> to
|
|
the running total of <parameter>total</parameter>>. Finally, to print
|
|
<quote>total</quote>, there is an <command>END</command> command
|
|
block, executed after the script has processed all its input.
|
|
<programlisting>END { print total }</programlisting></para>
|
|
|
|
<para>Corresponding to the <command>END</command>, there is a
|
|
<command>BEGIN</command>, for a code block to be performed before awk
|
|
starts processing its input.</para>
|
|
|
|
<para>The following example illustrates how <command>awk</command> can
|
|
add text-parsing tools to a shell script.</para>
|
|
|
|
<example id="lettercount2">
|
|
<title>Counting Letter Occurrences</title>
|
|
<programlisting>&lettercount2;</programlisting>
|
|
</example>
|
|
|
|
<para>For simpler examples of awk within shell scripts, see:
|
|
<orderedlist>
|
|
<listitem><para><xref linkend="ex44"/></para></listitem>
|
|
<listitem><para><xref linkend="redir4"/></para></listitem>
|
|
<listitem><para><xref linkend="stripc"/></para></listitem>
|
|
<listitem><para><xref linkend="coltotaler"/></para></listitem>
|
|
<listitem><para><xref linkend="coltotaler2"/></para></listitem>
|
|
<listitem><para><xref linkend="coltotaler3"/></para></listitem>
|
|
<listitem><para><xref linkend="pidid"/></para></listitem>
|
|
<listitem><para><xref linkend="constat"/></para></listitem>
|
|
<listitem><para><xref linkend="fileinfo"/></para></listitem>
|
|
<listitem><para><xref linkend="blotout"/></para></listitem>
|
|
<listitem><para><xref linkend="seedingrandom"/></para></listitem>
|
|
<listitem><para><xref linkend="idelete"/></para></listitem>
|
|
<listitem><para><xref linkend="substringex"/></para></listitem>
|
|
<listitem><para><xref linkend="sumproduct"/></para></listitem>
|
|
<listitem><para><xref linkend="userlist"/></para></listitem>
|
|
<listitem><para><xref linkend="prasc"/></para></listitem>
|
|
<listitem><para><xref linkend="hypot"/></para></listitem>
|
|
<listitem><para><xref linkend="ascii3sh"/></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="pathmanagement">
|
|
<title>Parsing and Managing Pathnames</title>
|
|
|
|
<para>Emmanual Rouat contributed the following example of parsing
|
|
and transforming <firstterm>filenames</firstterm> and, in
|
|
particular, <link linkend="pathnameref">pathnames</link>. It draws
|
|
heavily on the functionality of <firstterm>sed</firstterm>.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/usr/bin/env bash
|
|
#-----------------------------------------------------------
|
|
# Management of PATH, LD_LIBRARY_PATH, MANPATH variables...
|
|
# By Emmanuel Rouat <no-email>
|
|
# (Inspired by the bash documentation 'pathfuncs' and on
|
|
# discussions found on stackoverflow:
|
|
# http://stackoverflow.com/questions/370047/
|
|
# http://stackoverflow.com/questions/273909/#346860 )
|
|
# Last modified: Sat Sep 22 12:01:55 CEST 2012
|
|
#
|
|
# The following functions handle spaces correctly.
|
|
# These functions belong in .bash_profile rather than in
|
|
# .bashrc, I guess.
|
|
#
|
|
# The modular aspect of these functions should make it easy
|
|
# to expand them to handle path substitutions instead
|
|
# of path removal etc....
|
|
#
|
|
# See http://www.catonmat.net/blog/awk-one-liners-explained-part-two/
|
|
# (item 43) for an explanation of the 'duplicate-entries' removal
|
|
# (it's a nice trick!)
|
|
#-----------------------------------------------------------
|
|
|
|
# Show $@ (usually PATH) as list.
|
|
function p_show() { local p="$@" && for p; do [[ ${!p} ]] &&
|
|
echo -e ${!p//:/\\n}; done }
|
|
|
|
# Filter out empty lines, multiple/trailing slashes, and duplicate entries.
|
|
function p_filter()
|
|
{ awk '/^[ \t]*$/ {next} {sub(/\/+$/, "");gsub(/\/+/, "/")}!x[$0]++' ;}
|
|
|
|
# Rebuild list of items into ':' separated word (PATH-like).
|
|
function p_build() { paste -sd: ;}
|
|
|
|
# Clean $1 (typically PATH) and rebuild it
|
|
function p_clean()
|
|
{ local p=${1} && eval ${p}='$(p_show ${p} | p_filter | p_build)' ;}
|
|
|
|
# Remove $1 from $2 (found on stackoverflow, with modifications).
|
|
function p_rm()
|
|
{ local d=$(echo $1 | p_filter) p=${2} &&
|
|
eval ${p}='$(p_show ${p} | p_filter | grep -xv "${d}" | p_build)' ;}
|
|
|
|
# Same as previous, but filters on a pattern (dangerous...
|
|
#+ don't use 'bin' or '/' as pattern!).
|
|
function p_rmpat()
|
|
{ local d=$(echo $1 | p_filter) p=${2} && eval ${p}='$(p_show ${p} |
|
|
p_filter | grep -v "${d}" | p_build)' ;}
|
|
|
|
# Delete $1 from $2 and append it cleanly.
|
|
function p_append()
|
|
{ local d=$(echo $1 | p_filter) p=${2} && p_rm "${d}" ${p} &&
|
|
eval ${p}='$(p_show ${p} d | p_build)' ;}
|
|
|
|
# Delete $1 from $2 and prepend it cleanly.
|
|
function p_prepend()
|
|
{ local d=$(echo $1 | p_filter) p=${2} && p_rm "${d}" ${p} &&
|
|
eval ${p}='$(p_show d ${p} | p_build)' ;}
|
|
|
|
# Some tests:
|
|
echo
|
|
MYPATH="/bin:/usr/bin/:/bin://bin/"
|
|
p_append "/project//my project/bin" MYPATH
|
|
echo "Append '/project//my project/bin' to '/bin:/usr/bin/:/bin://bin/'"
|
|
echo "(result should be: /bin:/usr/bin:/project/my project/bin)"
|
|
echo $MYPATH
|
|
|
|
echo
|
|
MYOTHERPATH="/bin:/usr/bin/:/bin:/project//my project/bin"
|
|
p_prepend "/project//my project/bin" MYOTHERPATH
|
|
echo "Prepend '/project//my project/bin' \
|
|
to '/bin:/usr/bin/:/bin:/project//my project/bin/'"
|
|
echo "(result should be: /project/my project/bin:/bin:/usr/bin)"
|
|
echo $MYOTHERPATH
|
|
|
|
echo
|
|
p_prepend "/project//my project/bin" FOOPATH # FOOPATH doesn't exist.
|
|
echo "Prepend '/project//my project/bin' to an unset variable"
|
|
echo "(result should be: /project/my project/bin)"
|
|
echo $FOOPATH
|
|
|
|
echo
|
|
BARPATH="/a:/b/://b c://a:/my local pub"
|
|
p_clean BARPATH
|
|
echo "Clean BARPATH='/a:/b/://b c://a:/my local pub'"
|
|
echo "(result should be: /a:/b:/b c:/my local pub)"
|
|
echo $BARPATH
|
|
</programlisting>
|
|
</para>
|
|
|
|
<para>***</para>
|
|
|
|
<para>David Wheeler kindly permitted me to use his instructive
|
|
examples.</para>
|
|
|
|
<para><programlisting>Doing it correctly: A quick summary
|
|
by David Wheeler
|
|
http://www.dwheeler.com/essays/filenames-in-shell.html
|
|
|
|
So, how can you process filenames correctly in shell? Here's a quick
|
|
summary about how to do it correctly, for the impatient who "just want the
|
|
answer". In short: Double-quote to use "$variable" instead of $variable,
|
|
set IFS to just newline and tab, prefix all globs/filenames so they cannot
|
|
begin with "-" when expanded, and use one of a few templates that work
|
|
correctly. Here are some of those templates that work correctly:
|
|
|
|
|
|
IFS="$(printf '\n\t')"
|
|
# Remove SPACE, so filenames with spaces work well.
|
|
|
|
# Correct glob use:
|
|
#+ always use "for" loop, prefix glob, check for existence:
|
|
for file in ./* ; do # Use "./*" ... NEVER bare "*" ...
|
|
if [ -e "$file" ] ; then # Make sure it isn't an empty match.
|
|
COMMAND ... "$file" ...
|
|
fi
|
|
done
|
|
|
|
|
|
|
|
# Correct glob use, but requires nonstandard bash extension.
|
|
shopt -s nullglob # Bash extension,
|
|
#+ so that empty glob matches will work.
|
|
for file in ./* ; do # Use "./*", NEVER bare "*"
|
|
COMMAND ... "$file" ...
|
|
done
|
|
|
|
|
|
|
|
# These handle all filenames correctly;
|
|
#+ can be unwieldy if COMMAND is large:
|
|
find ... -exec COMMAND... {} \;
|
|
find ... -exec COMMAND... {} \+ # If multiple files are okay for COMMAND.
|
|
|
|
|
|
|
|
# This skips filenames with control characters
|
|
#+ (including tab and newline).
|
|
IFS="$(printf '\n\t')"
|
|
controlchars="$(printf '*[\001-\037\177]*')"
|
|
for file in $(find . ! -name "$controlchars"') ; do
|
|
COMMAND "$file" ...
|
|
done
|
|
|
|
|
|
|
|
# Okay if filenames can't contain tabs or newlines --
|
|
#+ beware the assumption.
|
|
IFS="$(printf '\n\t')"
|
|
for file in $(find .) ; do
|
|
COMMAND "$file" ...
|
|
done
|
|
|
|
|
|
|
|
# Requires nonstandard but common extensions in find and xargs:
|
|
find . -print0 | xargs -0 COMMAND
|
|
|
|
# Requires nonstandard extensions to find and to shell (bash works).
|
|
# variables might not stay set once the loop ends:
|
|
find . -print0 | while IFS="" read -r -d "" file ; do ...
|
|
COMMAND "$file" # Use quoted "$file", not $file, everywhere.
|
|
done
|
|
|
|
|
|
|
|
# Requires nonstandard extensions to find and to shell (bash works).
|
|
# Underlying system must include named pipes (FIFOs)
|
|
#+ or the /dev/fd mechanism.
|
|
# In this version, variables *do* stay set after the loop ends,
|
|
# and you can read from stdin.
|
|
#+ (Change the 4 to another number if fd 4 is needed.)
|
|
|
|
while IFS="" read -r -d "" file <&4 ; do
|
|
COMMAND "$file" # Use quoted "$file" -- not $file, everywhere.
|
|
done 4< <(find . -print0)
|
|
|
|
|
|
# Named pipe version.
|
|
# Requires nonstandard extensions to find and to shell's read (bash ok).
|
|
# Underlying system must include named pipes (FIFOs).
|
|
# Again, in this version, variables *do* stay set after the loop ends,
|
|
# and you can read from stdin.
|
|
# (Change the 4 to something else if fd 4 needed).
|
|
|
|
mkfifo mypipe
|
|
|
|
find . -print0 > mypipe &
|
|
while IFS="" read -r -d "" file <&4 ; do
|
|
COMMAND "$file" # Use quoted "$file", not $file, everywhere.
|
|
done 4< mypipe</programlisting></para>
|
|
|
|
</appendix>
|
|
<!-- End path management appendix -->
|
|
|
|
|
|
<appendix id="exitcodes">
|
|
<title>Exit Codes With Special Meanings</title>
|
|
|
|
<para><anchor id="exitcodesref"/></para>
|
|
|
|
<table>
|
|
<title><firstterm>Reserved</firstterm> Exit Codes</title>
|
|
<tgroup cols="4">
|
|
<thead>
|
|
<row>
|
|
<entry>Exit Code Number</entry>
|
|
<entry>Meaning</entry>
|
|
<entry>Example</entry>
|
|
<entry>Comments</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>1</option></entry>
|
|
<entry>Catchall for general errors</entry>
|
|
<entry>let "var1 = 1/0"</entry>
|
|
<entry>Miscellaneous errors, such as <quote>divide by
|
|
zero</quote> and other impermissible operations</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2</option></entry>
|
|
<entry>Misuse of shell builtins (according to Bash documentation)</entry>
|
|
<entry>empty_function() {}</entry>
|
|
<entry><link linkend="missingkeyword">Missing keyword</link>
|
|
or command, or permission problem (and <link
|
|
linkend="differr2"><firstterm>diff</firstterm> return code
|
|
on a failed binary file comparison</link>).</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>126</option></entry>
|
|
<entry>Command invoked cannot execute</entry>
|
|
<entry>/dev/null</entry>
|
|
<entry>Permission problem or command is not an executable</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>127</option></entry>
|
|
<entry><quote>command not found</quote></entry>
|
|
<entry>illegal_command</entry>
|
|
<entry>Possible problem with <varname>$PATH</varname> or a typo</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>128</option></entry>
|
|
<entry>Invalid argument to <link linkend="exitcommandref">exit</link></entry>
|
|
<entry>exit 3.14159</entry>
|
|
<entry><command>exit</command> takes only integer args in the
|
|
range <returnvalue>0 - 255</returnvalue> (see
|
|
first footnote)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>128+n</option></entry>
|
|
<entry>Fatal error signal <quote>n</quote></entry>
|
|
<entry><firstterm>kill -9</firstterm> <varname>$PPID</varname> of script</entry>
|
|
<entry><userinput>$?</userinput> returns
|
|
<errorcode>137</errorcode> (128 + 9)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>130</option></entry>
|
|
<entry>Script terminated by Control-C</entry>
|
|
<entry><emphasis>Ctl-C</emphasis></entry>
|
|
<entry>Control-C is fatal error signal
|
|
<errorcode>2</errorcode>, (130 = 128 + 2, see above)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>255*</option></entry>
|
|
<entry>Exit status out of range</entry>
|
|
<entry>exit <returnvalue>-1</returnvalue></entry>
|
|
<entry><command>exit</command> takes only integer args in the
|
|
range <errorcode>0 - 255</errorcode></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>According to the above table, exit codes <errorcode>1 - 2,
|
|
126 - 165, and 255</errorcode>
|
|
|
|
<footnote><para><anchor id="excoor"/>Out of range exit values
|
|
can result in unexpected exit codes. An exit value
|
|
greater than <errorcode>255</errorcode> returns an
|
|
exit code <link linkend="moduloref">modulo</link>
|
|
<errorcode>256</errorcode>. For example, <firstterm>exit
|
|
3809</firstterm> gives an exit code of <errorcode>225</errorcode>
|
|
(3809 % 256 = 225).</para></footnote>
|
|
|
|
have special meanings, and should therefore be avoided for
|
|
user-specified exit parameters. Ending a script with <firstterm>exit
|
|
127</firstterm> would certainly cause confusion when troubleshooting
|
|
(is the error code a <quote>command not found</quote> or a
|
|
user-defined one?). However, many scripts use an <firstterm>exit
|
|
1</firstterm> as a general bailout-upon-error. Since exit code
|
|
<errorcode>1</errorcode> signifies so many possible errors,
|
|
it is not particularly useful in debugging.</para>
|
|
|
|
<para><anchor id="sysexitsref"/></para>
|
|
<para>There has been an attempt to systematize exit status numbers
|
|
(see <filename
|
|
class="headerfile">/usr/include/sysexits.h</filename>),
|
|
but this is intended for C and C++ programmers. A similar
|
|
standard for scripting might be appropriate. The author of
|
|
this document proposes restricting user-defined exit codes to
|
|
the range <returnvalue>64 - 113</returnvalue> (in addition to
|
|
<returnvalue>0</returnvalue>, for success), to conform with
|
|
the C/C++ standard. This would allot 50 valid codes, and make
|
|
troubleshooting scripts more straightforward.
|
|
<footnote><para>An update of <filename
|
|
class="headerfile">/usr/include/sysexits.h</filename>
|
|
allocates previously unused exit codes from <returnvalue>64
|
|
- 78</returnvalue>. It may be anticipated that the range of
|
|
unallotted exit codes will be further restricted in the future.
|
|
The author of this document will <emphasis>not</emphasis> do
|
|
fixups on the scripting examples to conform to the changing
|
|
standard. This should not cause any problems, since there
|
|
is no overlap or conflict in usage of exit codes between
|
|
compiled C/C++ binaries and shell scripts.</para></footnote>
|
|
All user-defined exit codes in the accompanying examples to
|
|
this document conform to this standard, except where overriding
|
|
circumstances exist, as in <xref linkend="tmdin"/>.</para>
|
|
|
|
<note><para>Issuing a <link linkend="xstatvarref">$?</link> from
|
|
the command-line after a shell script exits gives
|
|
results consistent with the table above only from the
|
|
Bash or <firstterm>sh</firstterm> prompt. Running the
|
|
<firstterm>C-shell</firstterm> or <firstterm>tcsh</firstterm>
|
|
may give different values in some cases.</para></note>
|
|
|
|
|
|
</appendix>
|
|
<!-- End Reserved Exit Code appendix -->
|
|
|
|
|
|
<appendix id="ioredirintro">
|
|
<title>A Detailed Introduction to I/O and I/O Redirection</title>
|
|
|
|
<para><emphasis>written by Stéphane Chazelas, and revised
|
|
by the document author</emphasis></para>
|
|
|
|
<para><anchor id="stdinoutdef"/></para>
|
|
<para>A command expects the first three <link linkend="fdref">file
|
|
descriptors</link> to be available. The first, <firstterm>fd
|
|
0</firstterm> (standard input, <filename>stdin</filename>),
|
|
is for reading. The other two (<firstterm>fd 1</firstterm>,
|
|
<filename>stdout</filename> and <firstterm>fd 2</firstterm>,
|
|
<filename>stderr</filename>) are for writing.</para>
|
|
|
|
<para>There is a <filename>stdin</filename>, <filename>stdout</filename>,
|
|
and a <filename>stderr</filename> associated with each command.
|
|
<userinput>ls 2>&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 <link
|
|
linkend="subshellsref">subshell</link>, a <link
|
|
linkend="redirref">while or if or case or for loop</link>...),
|
|
or globally, for the remainder of the shell (using <link
|
|
linkend="execref">exec</link>).</para>
|
|
|
|
<para><userinput>ls > /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.
|
|
# Good luck!
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
</appendix>
|
|
<!-- A Detailed Introduction to I/O and I/O Redirection -->
|
|
|
|
|
|
<appendix id="command-line-options">
|
|
<title>Command-Line Options</title>
|
|
|
|
<para>Many executables, whether binaries or script files, accept
|
|
options to modify their run-time behavior. For example: from
|
|
the command-line, typing <command>command -o</command>
|
|
would invoke <emphasis>command</emphasis>, with option
|
|
<option>o</option>.</para>
|
|
|
|
|
|
<sect1 id="standard-options">
|
|
<title>Standard Command-Line Options</title>
|
|
|
|
<para>Over time, there has evolved a loose standard for the
|
|
meanings of command-line option flags. The GNU utilities conform
|
|
more closely to this <quote>standard</quote> than older UNIX
|
|
utilities.</para>
|
|
|
|
<para>Traditionally, UNIX command-line options consist of a dash,
|
|
followed by one or more lowercase letters. The GNU utilities
|
|
added a double-dash, followed by a complete word or compound
|
|
word.</para>
|
|
|
|
|
|
<para>The two most widely-accepted options are:</para>
|
|
|
|
<itemizedlist id="widelyaccopt">
|
|
|
|
<listitem>
|
|
<para><option>-h</option></para>
|
|
<para><option>--help</option></para>
|
|
<para><firstterm>Help</firstterm>: Give usage message and exit.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-v</option></para>
|
|
<para><option>--version</option></para>
|
|
<para><firstterm>Version</firstterm>: Show program version and exit.</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<para>Other common options are:</para>
|
|
|
|
<itemizedlist id="otheroptns">
|
|
|
|
<listitem>
|
|
<para><option>-a</option></para>
|
|
<para><option>--all</option></para>
|
|
<para><firstterm>All</firstterm>: show <emphasis>all</emphasis>
|
|
information or operate on <emphasis>all</emphasis> arguments.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-l</option></para>
|
|
<para><option>--list</option></para>
|
|
<para><firstterm>List</firstterm>: list files or arguments without
|
|
taking other action.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-o</option></para>
|
|
<para><firstterm>Output</firstterm> filename</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-q</option></para>
|
|
<para><option>--quiet</option></para>
|
|
<para><firstterm>Quiet</firstterm>: suppress
|
|
<filename>stdout</filename>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-r</option></para>
|
|
<para><option>-R</option></para>
|
|
<para><option>--recursive</option></para>
|
|
<para><firstterm>Recursive</firstterm>: Operate recursively (down
|
|
directory tree).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-v</option></para>
|
|
<para><option>--verbose</option></para>
|
|
<para><firstterm>Verbose</firstterm>: output additional information to
|
|
<filename>stdout</filename> or <filename>stderr</filename>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-z</option></para>
|
|
<para><option>--compress</option></para>
|
|
<para><firstterm>Compress</firstterm>: apply compression (usually
|
|
<link linkend="gzipref">gzip</link>).</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<para>However:</para>
|
|
|
|
<itemizedlist id="exceptionsopts">
|
|
|
|
<listitem>
|
|
<para>In <command>tar</command> and <command>gawk</command>:</para>
|
|
<para><option>-f</option></para>
|
|
<para><option>--file</option></para>
|
|
<para><firstterm>File</firstterm>: filename follows.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>In <command>cp</command>, <command>mv</command>,
|
|
<command>rm</command>:</para>
|
|
<para><option>-f</option></para>
|
|
<para><option>--force</option></para>
|
|
<para><firstterm>Force</firstterm>: force overwrite of target file(s).</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
<caution><para>Many UNIX and Linux utilities deviate from this
|
|
<quote>standard,</quote> so it is dangerous to
|
|
<emphasis>assume</emphasis> that a given option will behave in a
|
|
standard way. Always check the man page for the command in question
|
|
when in doubt.</para></caution>
|
|
|
|
<para>A complete table of recommended options for the GNU utilities
|
|
is available at <ulink
|
|
url="http://www.gnu.org/prep/standards/">the GNU standards page</ulink>.</para>
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
<sect1 id="bash-options">
|
|
<title>Bash Command-Line Options</title>
|
|
|
|
<para><anchor id="clopts"/></para>
|
|
<para><firstterm>Bash</firstterm> itself has a number of command-line
|
|
options. Here are some of the more useful ones.</para>
|
|
|
|
<itemizedlist id="bash-commline-opts">
|
|
|
|
<listitem>
|
|
<para><option>-c</option></para>
|
|
<para><emphasis>Read commands from the following string and assign any
|
|
arguments to the <link linkend="posparamref">positional
|
|
parameters</link>.</emphasis></para>
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>bash -c 'set a b c d; IFS="+-;"; echo "$*"'</userinput>
|
|
<computeroutput>a+b+c+d</computeroutput>
|
|
</screen>
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>-r</option></para>
|
|
<para><option>--restricted</option></para>
|
|
<para><emphasis>Runs the shell, or a script, in <link
|
|
linkend="restrictedshref">restricted mode</link>.</emphasis></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>--posix</option></para>
|
|
<para><emphasis>Forces Bash to conform to <link
|
|
linkend="posix2ref">POSIX</link> mode.</emphasis></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>--version</option></para>
|
|
<para><emphasis>Display Bash version information and
|
|
exit.</emphasis></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><option>--</option></para>
|
|
<para><emphasis>End of options. Anything further on the command
|
|
line is an argument, not an option.</emphasis></para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</sect1>
|
|
|
|
|
|
</appendix>
|
|
<!-- End Command-Line Options appendix -->
|
|
|
|
|
|
<appendix id="files">
|
|
<title> Important Files</title>
|
|
|
|
<variablelist id="filesref">
|
|
<title><anchor id="filesref1"/>startup files</title>
|
|
|
|
<varlistentry>
|
|
<term></term>
|
|
<listitem>
|
|
<para>These files contain the aliases and <link
|
|
linkend="envref">environmental variables</link>
|
|
made available to Bash running as a user shell and to all
|
|
Bash scripts invoked after system initialization.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><filename>/etc/profile</filename></term>
|
|
<listitem>
|
|
<para>Systemwide defaults, mostly setting the environment
|
|
(all Bourne-type shells, not just Bash
|
|
<footnote><para>This does not apply to <command>csh</command>,
|
|
<command>tcsh</command>, and other shells not related to or
|
|
descended from the classic Bourne shell
|
|
(<command>sh</command>).</para></footnote>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><filename>/etc/bashrc</filename></term>
|
|
<listitem>
|
|
<para>systemwide functions and <link
|
|
linkend="aliasref">aliases</link> for Bash</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><filename><varname>$HOME</varname>/.bash_profile</filename></term>
|
|
<listitem>
|
|
<para>user-specific Bash environmental default settings,
|
|
found in each user's home directory (the local counterpart
|
|
to <filename>/etc/profile</filename>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><filename><varname>$HOME</varname>/.bashrc</filename></term>
|
|
<listitem>
|
|
<para>user-specific Bash init file, found in each user's home
|
|
directory (the local counterpart to
|
|
<filename>/etc/bashrc</filename>). Only interactive
|
|
shells and user scripts read this file. See
|
|
<xref linkend="sample-bashrc"/> for a sample
|
|
<filename>.bashrc</filename> file.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="logoutfileref">
|
|
<title><anchor id="logoutfileref1"/>logout file</title>
|
|
<varlistentry>
|
|
<term><filename><varname>$HOME</varname>/.bash_logout</filename></term>
|
|
|
|
<listitem>
|
|
<para>user-specific instruction file, found in
|
|
each user's home directory. Upon exit from a login (Bash)
|
|
shell, the commands in this file execute.</para>
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="datafilesref">
|
|
<title><anchor id="datafilesref1"/>data files</title>
|
|
|
|
<varlistentry>
|
|
<term><filename>/etc/passwd</filename></term>
|
|
<listitem>
|
|
<para>A listing of all the user accounts on the system,
|
|
their identities, their home directories, the groups they
|
|
belong to, and their default shell. Note that the user
|
|
passwords are <emphasis>not</emphasis>
|
|
stored in this file,
|
|
<footnote><para>In older versions of UNIX, passwords
|
|
<emphasis>were</emphasis> stored in
|
|
<filename>/etc/passwd</filename>, and that explains
|
|
the name of the file.</para></footnote>
|
|
but in <filename>/etc/shadow</filename> in encrypted form.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="sysconfref">
|
|
<title><anchor id="sysconfref1"/>system configuration files</title>
|
|
|
|
<varlistentry>
|
|
<term><filename>/etc/sysconfig/hwconf</filename></term>
|
|
<listitem>
|
|
<para>Listing and description of attached hardware devices.
|
|
This information is in text form and can be extracted and
|
|
parsed.</para>
|
|
<para>
|
|
<screen>
|
|
<prompt>bash$ </prompt><userinput>grep -A 5 AUDIO /etc/sysconfig/hwconf</userinput>
|
|
<computeroutput>class: AUDIO
|
|
bus: PCI
|
|
detached: 0
|
|
driver: snd-intel8x0
|
|
desc: "Intel Corporation 82801CA/CAM AC'97 Audio Controller"
|
|
vendorId: 8086</computeroutput>
|
|
</screen>
|
|
</para>
|
|
<note><para>This file is present on Red Hat and Fedora Core
|
|
installations, but may be missing from other
|
|
distros.</para></note>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</appendix>
|
|
<!-- End Files appendix -->
|
|
|
|
|
|
|
|
|
|
|
|
<appendix id="systemdirs">
|
|
|
|
<title>Important System Directories</title>
|
|
|
|
|
|
<para>Sysadmins and anyone else writing administrative scripts
|
|
should be intimately familiar with the following system
|
|
directories.</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/bin</filename></para>
|
|
<para>Binaries (executables). Basic system programs
|
|
and utilities (such as <command>bash</command>).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/bin</filename>
|
|
|
|
<footnote>
|
|
<para>Some early UNIX systems had a fast, small-capacity fixed
|
|
disk (containing <filename class="directory">/</filename>,
|
|
the root partition), and a second drive which
|
|
was larger, but slower (containing <filename
|
|
class="directory">/usr</filename> and other
|
|
partitions). The most frequently used programs and
|
|
utilities therefore resided on the small-but-fast
|
|
drive, in <filename class="directory">/bin</filename>,
|
|
and the others on the slower drive, in <filename
|
|
class="directory">/usr/bin</filename>.</para>
|
|
|
|
<para>This likewise accounts for the split between
|
|
<filename class="directory">/sbin</filename> and
|
|
<filename class="directory">/usr/sbin</filename>,
|
|
<filename class="directory">/lib</filename> and <filename
|
|
class="directory">/usr/lib</filename>, etc.</para>
|
|
</footnote>
|
|
|
|
</para>
|
|
|
|
<para>More system binaries.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/local/bin</filename></para>
|
|
<para>Miscellaneous binaries local to the particular machine.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/sbin</filename></para>
|
|
<para>System binaries. Basic system administrative programs
|
|
and utilities (such as <command>fsck</command>).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/sbin</filename></para>
|
|
<para>More system administrative programs and utilities.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/etc</filename></para>
|
|
|
|
<para><firstterm>Et cetera</firstterm>. Systemwide configuration
|
|
scripts.</para>
|
|
|
|
<para>Of particular interest are the
|
|
<link
|
|
linkend="fstabref"><filename>/etc/fstab</filename></link>
|
|
(filesystem table),
|
|
<filename>/etc/mtab</filename>
|
|
(mounted filesystem table), and the <link
|
|
linkend="inittabref"><filename>/etc/inittab</filename></link>
|
|
files.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/etc/rc.d</filename></para>
|
|
<para>Boot scripts, on Red Hat and derivative distributions
|
|
of Linux.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/share/doc</filename></para>
|
|
<para>Documentation for installed packages.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/man</filename></para>
|
|
<para>The systemwide <link linkend="manref">manpages</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/dev</filename></para>
|
|
<para>Device directory. Entries (but <emphasis>not</emphasis>
|
|
mount points) for physical and virtual devices.
|
|
See <xref linkend="devproc"/>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/proc</filename></para>
|
|
<para>Process directory. Contains information and statistics
|
|
about running processes and kernel parameters.
|
|
See <xref linkend="devproc"/>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/sys</filename></para>
|
|
<para>Systemwide device directory. Contains information and
|
|
statistics about device and device names. This is newly
|
|
added to Linux with the 2.6.X kernels.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/mnt</filename></para>
|
|
<para><firstterm>Mount</firstterm>. Directory for mounting
|
|
hard drive partitions, such as <filename
|
|
class="directory">/mnt/dos</filename>, and physical
|
|
devices. In newer Linux distros, the <filename
|
|
class="directory">/media</filename> directory has taken
|
|
over as the preferred mount point for I/O devices.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/media</filename></para>
|
|
<para>In newer Linux distros, the preferred mount point for
|
|
I/O devices, such as CD/DVD drives or USB flash drives.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/var</filename></para>
|
|
<para><firstterm>Variable</firstterm> (changeable) system
|
|
files. This is a catchall <quote>scratchpad</quote>
|
|
directory for data generated while a Linux/UNIX machine
|
|
is running.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/var/log</filename></para>
|
|
<para>Systemwide log files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/var/spool/mail</filename></para>
|
|
<para>User mail spool.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/lib</filename></para>
|
|
<para>Systemwide library files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/usr/lib</filename></para>
|
|
<para>More systemwide library files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/tmp</filename></para>
|
|
<para>System temporary files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="directory">/boot</filename></para>
|
|
<para>System <firstterm>boot</firstterm> directory. The kernel,
|
|
module links, system map, and boot manager reside here.</para>
|
|
<warning><para>Altering files in this directory may result in an
|
|
unbootable system.</para></warning>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</appendix>
|
|
|
|
|
|
|
|
<appendix id="tabexpansion">
|
|
|
|
&TABEXP;
|
|
|
|
</appendix>
|
|
<!-- End Tab Expansion appendix -->
|
|
|
|
|
|
|
|
<appendix id="localization">
|
|
<title>Localization</title>
|
|
|
|
|
|
<para>Localization is an undocumented Bash feature.</para>
|
|
|
|
<para><anchor id="localeref"/>A localized shell script echoes
|
|
its text output in the language defined as the system's locale.
|
|
A Linux user in Berlin, Germany, would get script output in German,
|
|
whereas his cousin in Berlin, Maryland, would get output from
|
|
the same script in English.</para>
|
|
|
|
<para>To create a localized script, use the following template to
|
|
write all messages to the user (error messages, prompts,
|
|
etc.).</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
# localized.sh
|
|
# Script by Stéphane Chazelas,
|
|
#+ modified by Bruno Haible, bugfixed by Alfredo Pironti.
|
|
|
|
. gettext.sh
|
|
|
|
E_CDERROR=65
|
|
|
|
error()
|
|
{
|
|
printf "$@" >&2
|
|
exit $E_CDERROR
|
|
}
|
|
|
|
cd $var || error "`eval_gettext \"Can\'t cd to \\\$var.\"`"
|
|
# The triple backslashes (escapes) in front of $var needed
|
|
#+ "because eval_gettext expects a string
|
|
#+ where the variable values have not yet been substituted."
|
|
# -- per Bruno Haible
|
|
read -p "`gettext \"Enter the value: \"`" var
|
|
# ...
|
|
|
|
|
|
# ------------------------------------------------------------------
|
|
# Alfredo Pironti comments:
|
|
|
|
# This script has been modified to not use the $"..." syntax in
|
|
#+ favor of the "`gettext \"...\"`" syntax.
|
|
# This is ok, but with the new localized.sh program, the commands
|
|
#+ "bash -D filename" and "bash --dump-po-string filename"
|
|
#+ will produce no output
|
|
#+ (because those command are only searching for the $"..." strings)!
|
|
# The ONLY way to extract strings from the new file is to use the
|
|
# 'xgettext' program. However, the xgettext program is buggy.
|
|
|
|
# Note that 'xgettext' has another bug.
|
|
#
|
|
# The shell fragment:
|
|
# gettext -s "I like Bash"
|
|
# will be correctly extracted, but . . .
|
|
# xgettext -s "I like Bash"
|
|
# . . . fails!
|
|
# 'xgettext' will extract "-s" because
|
|
#+ the command only extracts the
|
|
#+ very first argument after the 'gettext' word.
|
|
|
|
|
|
# Escape characters:
|
|
#
|
|
# To localize a sentence like
|
|
# echo -e "Hello\tworld!"
|
|
#+ you must use
|
|
# echo -e "`gettext \"Hello\\tworld\"`"
|
|
# The "double escape character" before the `t' is needed because
|
|
#+ 'gettext' will search for a string like: 'Hello\tworld'
|
|
# This is because gettext will read one literal `\')
|
|
#+ and will output a string like "Bonjour\tmonde",
|
|
#+ so the 'echo' command will display the message correctly.
|
|
#
|
|
# You may not use
|
|
# echo "`gettext -e \"Hello\tworld\"`"
|
|
#+ due to the xgettext bug explained above.
|
|
|
|
|
|
|
|
# Let's localize the following shell fragment:
|
|
# echo "-h display help and exit"
|
|
#
|
|
# First, one could do this:
|
|
# echo "`gettext \"-h display help and exit\"`"
|
|
# This way 'xgettext' will work ok,
|
|
#+ but the 'gettext' program will read "-h" as an option!
|
|
#
|
|
# One solution could be
|
|
# echo "`gettext -- \"-h display help and exit\"`"
|
|
# This way 'gettext' will work,
|
|
#+ but 'xgettext' will extract "--", as referred to above.
|
|
#
|
|
# The workaround you may use to get this string localized is
|
|
# echo -e "`gettext \"\\0-h display help and exit\"`"
|
|
# We have added a \0 (NULL) at the beginning of the sentence.
|
|
# This way 'gettext' works correctly, as does 'xgettext.'
|
|
# Moreover, the NULL character won't change the behavior
|
|
#+ of the 'echo' command.
|
|
# ------------------------------------------------------------------</programlisting>
|
|
</para>
|
|
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>bash -D localized.sh</userinput>
|
|
<computeroutput>"Can't cd to %s."
|
|
"Enter the value: "</computeroutput></screen>
|
|
|
|
This lists all the localized text. (The <option>-D</option>
|
|
option lists double-quoted strings prefixed by a <token>$</token>,
|
|
without executing the script.)</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>bash --dump-po-strings localized.sh</userinput>
|
|
<computeroutput>#: a:6
|
|
msgid "Can't cd to %s."
|
|
msgstr ""
|
|
#: a:7
|
|
msgid "Enter the value: "
|
|
msgstr ""</computeroutput></screen>
|
|
|
|
The <option>--dump-po-strings</option> option to Bash
|
|
resembles the <option>-D</option> option, but uses <link
|
|
linkend="gettextref">gettext</link> <quote>po</quote> format.
|
|
|
|
</para>
|
|
|
|
<note>
|
|
<para>Bruno Haible points out:</para>
|
|
|
|
<para>Starting with gettext-0.12.2, <command>xgettext -o - localized.sh</command>
|
|
is recommended instead of <command>bash --dump-po-strings
|
|
localized.sh</command>, because <command>xgettext</command> . . .</para>
|
|
|
|
<para>1. understands the gettext and eval_gettext commands
|
|
(whereas bash --dump-po-strings understands only its deprecated
|
|
$"..." syntax)</para>
|
|
|
|
<para>2. can extract comments placed by the programmer, intended
|
|
to be read by the translator.</para>
|
|
|
|
<para>This shell code is then not specific to Bash any
|
|
more; it works the same way with Bash 1.x and other /bin/sh
|
|
implementations.</para>
|
|
</note>
|
|
|
|
|
|
<para>Now, build a <filename>language.po</filename>
|
|
file for each language that the script will be translated
|
|
into, specifying the <replaceable>msgstr</replaceable>. Alfredo
|
|
Pironti gives the following example:</para>
|
|
|
|
<para>fr.po:
|
|
|
|
<programlisting>#: a:6
|
|
msgid "Can't cd to $var."
|
|
msgstr "Impossible de se positionner dans le repertoire $var."
|
|
#: a:7
|
|
msgid "Enter the value: "
|
|
msgstr "Entrez la valeur : "
|
|
|
|
# The string are dumped with the variable names, not with the %s syntax,
|
|
#+ similar to C programs.
|
|
#+ This is a very cool feature if the programmer uses
|
|
#+ variable names that make sense!</programlisting>
|
|
</para>
|
|
|
|
<para>Then, run <link linkend="msgfmtref">msgfmt</link>.</para>
|
|
<para><userinput>msgfmt -o localized.sh.mo fr.po</userinput></para>
|
|
|
|
<para>Place the resulting <filename>localized.sh.mo</filename> file in the
|
|
<filename class="directory">/usr/local/share/locale/fr/LC_MESSAGES</filename>
|
|
directory, and at the beginning of the script, insert the lines:
|
|
|
|
<programlisting>TEXTDOMAINDIR=/usr/local/share/locale
|
|
TEXTDOMAIN=localized.sh</programlisting>
|
|
</para>
|
|
|
|
<para>If a user on a French system runs the script, she will get
|
|
French messages.</para>
|
|
|
|
<note>
|
|
<para>With older versions of Bash or other shells, localization requires
|
|
<link linkend="gettextref">gettext</link>, using the
|
|
<option>-s</option> option. In this case, the script becomes:</para>
|
|
|
|
<para><anchor id="gettextexample"/>
|
|
<programlisting>#!/bin/bash
|
|
# localized.sh
|
|
|
|
E_CDERROR=65
|
|
|
|
error() {
|
|
local format=$1
|
|
shift
|
|
printf "$(gettext -s "$format")" "$@" >&2
|
|
exit $E_CDERROR
|
|
}
|
|
cd $var || error "Can't cd to %s." "$var"
|
|
read -p "$(gettext -s "Enter the value: ")" var
|
|
# ...</programlisting>
|
|
</para>
|
|
</note>
|
|
|
|
<para>The <varname>TEXTDOMAIN</varname> and
|
|
<varname>TEXTDOMAINDIR</varname> variables need to be set and
|
|
exported to the environment. This should be done within the
|
|
script itself.</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para>This appendix written by Stéphane Chazelas,
|
|
with modifications suggested by Alfredo Pironti,
|
|
and by Bruno Haible, maintainer of GNU <link
|
|
linkend="gettextref">gettext</link>.</para>
|
|
|
|
</appendix>
|
|
<!-- Localization -->
|
|
|
|
|
|
|
|
<appendix id="histcommands">
|
|
<title>History Commands</title>
|
|
|
|
<para>The Bash shell provides command-line tools for editing and
|
|
manipulating a user's <firstterm>command history</firstterm>. This
|
|
is primarily a convenience, a means of saving keystrokes.</para>
|
|
|
|
<para>Bash history commands:
|
|
<orderedlist>
|
|
<listitem><para><command>history</command></para></listitem>
|
|
<listitem><para><command>fc</command></para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>history</userinput>
|
|
<computeroutput> 1 mount /mnt/cdrom
|
|
2 cd /mnt/cdrom
|
|
3 ls
|
|
...</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Internal variables associated with Bash history commands:
|
|
<orderedlist>
|
|
<listitem><para>$HISTCMD</para></listitem>
|
|
<listitem><para>$HISTCONTROL</para></listitem>
|
|
<listitem><para>$HISTIGNORE</para></listitem>
|
|
<listitem><para>$HISTFILE</para></listitem>
|
|
<listitem><para>$HISTFILESIZE</para></listitem>
|
|
<listitem><para>$HISTSIZE</para></listitem>
|
|
<listitem><para>$HISTTIMEFORMAT (Bash, ver. 3.0 or later)</para></listitem>
|
|
<listitem><para>!!</para></listitem>
|
|
<listitem><para>!$</para></listitem>
|
|
<listitem><para>!#</para></listitem>
|
|
<listitem><para>!N</para></listitem>
|
|
<listitem><para>!-N</para></listitem>
|
|
<listitem><para>!STRING</para></listitem>
|
|
<listitem><para>!?STRING?</para></listitem>
|
|
<listitem><para>^STRING^string^</para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<para>Unfortunately, the Bash history tools find no use in
|
|
scripting.</para>
|
|
|
|
<para><programlisting>#!/bin/bash
|
|
# history.sh
|
|
# A (vain) attempt to use the 'history' command in a script.
|
|
|
|
history # No output.
|
|
|
|
var=$(history); echo "$var" # $var is empty.
|
|
|
|
# History commands are, by default, disabled within a script.
|
|
# However, as dhw points out,
|
|
#+ set -o history
|
|
#+ enables the history mechanism.
|
|
|
|
set -o history
|
|
var=$(history); echo "$var" # 1 var=$(history)</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
<screen><prompt>bash$ </prompt><userinput>./history.sh</userinput>
|
|
<computeroutput>(no output)</computeroutput>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The <ulink
|
|
url="http://samrowe.com/wordpress/advancing-in-the-bash-shell/">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>Sample <filename>.bashrc</filename> and
|
|
<filename>.bash_profile</filename> Files</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>
|
|
|
|
<para>And, here is a snippet from Andrzej Szelachowski's instructive
|
|
<filename>.bash_profile</filename> file.</para>
|
|
|
|
<example id="bashprof">
|
|
<title><filename>.bash_profile</filename> file</title>
|
|
<programlisting>&bashprof;</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><anchor id="dosunixequiv"/></para>
|
|
<para>Batch files usually contain DOS commands. These must be
|
|
translated into their UNIX equivalents in order to convert a
|
|
batch file into a shell script.</para>
|
|
|
|
<table>
|
|
<title>DOS commands and their UNIX equivalents</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>DOS Command</entry>
|
|
<entry>UNIX Equivalent</entry>
|
|
<entry>Effect</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><option>ASSIGN</option></entry>
|
|
<entry>ln</entry>
|
|
<entry>link file or directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>ATTRIB</option></entry>
|
|
<entry>chmod</entry>
|
|
<entry>change file permissions</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>CD</option></entry>
|
|
<entry>cd</entry>
|
|
<entry>change directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>CHDIR</option></entry>
|
|
<entry>cd</entry>
|
|
<entry>change directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>CLS</option></entry>
|
|
<entry>clear</entry>
|
|
<entry>clear screen</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>COMP</option></entry>
|
|
<entry>diff, comm, cmp</entry>
|
|
<entry>file compare</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>COPY</option></entry>
|
|
<entry>cp</entry>
|
|
<entry>file copy</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>Ctl-C</option></entry>
|
|
<entry>Ctl-C</entry>
|
|
<entry>break (signal)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>Ctl-Z</option></entry>
|
|
<entry>Ctl-D</entry>
|
|
<entry>EOF (end-of-file)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>DEL</option></entry>
|
|
<entry>rm</entry>
|
|
<entry>delete file(s)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>DELTREE</option></entry>
|
|
<entry>rm -rf</entry>
|
|
<entry>delete directory recursively</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>DIR</option></entry>
|
|
<entry>ls -l</entry>
|
|
<entry>directory listing</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>ERASE</option></entry>
|
|
<entry>rm</entry>
|
|
<entry>delete file(s)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>EXIT</option></entry>
|
|
<entry>exit</entry>
|
|
<entry>exit current process</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>FC</option></entry>
|
|
<entry>comm, cmp</entry>
|
|
<entry>file compare</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>FIND</option></entry>
|
|
<entry>grep</entry>
|
|
<entry>find strings in files</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>MD</option></entry>
|
|
<entry>mkdir</entry>
|
|
<entry>make directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>MKDIR</option></entry>
|
|
<entry>mkdir</entry>
|
|
<entry>make directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>MORE</option></entry>
|
|
<entry>more</entry>
|
|
<entry>text file paging filter</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>MOVE</option></entry>
|
|
<entry>mv</entry>
|
|
<entry>move</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>PATH</option></entry>
|
|
<entry>$PATH</entry>
|
|
<entry>path to executables</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>REN</option></entry>
|
|
<entry>mv</entry>
|
|
<entry>rename (move)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>RENAME</option></entry>
|
|
<entry>mv</entry>
|
|
<entry>rename (move)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>RD</option></entry>
|
|
<entry>rmdir</entry>
|
|
<entry>remove directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>RMDIR</option></entry>
|
|
<entry>rmdir</entry>
|
|
<entry>remove directory</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>SORT</option></entry>
|
|
<entry>sort</entry>
|
|
<entry>sort file</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>TIME</option></entry>
|
|
<entry>date</entry>
|
|
<entry>display system time</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>TYPE</option></entry>
|
|
<entry>cat</entry>
|
|
<entry>output file to <filename>stdout</filename></entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>XCOPY</option></entry>
|
|
<entry>cp</entry>
|
|
<entry>(extended) file copy</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
<note>
|
|
<para>Virtually all UNIX and shell operators and commands have
|
|
many more options and enhancements than their DOS and batch file
|
|
counterparts. Many DOS batch files rely on auxiliary utilities,
|
|
such as <command>ask.com</command>, a crippled counterpart to
|
|
<link linkend="readref">read</link>.</para>
|
|
|
|
<para>DOS supports only a very limited and incompatible subset of
|
|
filename <link linkend="globbingref">wild-card expansion</link>,
|
|
recognizing just the <token>*</token> and <token>?</token>
|
|
characters.</para>
|
|
</note>
|
|
|
|
<para>Converting a DOS batch file into a shell script is generally
|
|
straightforward, and the result ofttimes reads better than the
|
|
original.</para>
|
|
|
|
<example id="VIEWDAT">
|
|
<title>VIEWDATA.BAT: DOS Batch File</title>
|
|
<programlisting>&VIEWDAT;</programlisting>
|
|
</example>
|
|
|
|
<para>
|
|
The script conversion is somewhat of an improvement.
|
|
<footnote><para>Various readers have suggested modifications
|
|
of the above batch file to prettify it and make it more
|
|
compact and efficient. In the opinion of the <emphasis>ABS
|
|
Guide</emphasis> author, this is wasted effort. A Bash script
|
|
can access a DOS filesystem, or even an NTFS partition (with
|
|
the help of <ulink url="http://www.ntfs-3g.org">ntfs-3g</ulink>)
|
|
to do batch or scripted operations.</para></footnote>
|
|
</para>
|
|
|
|
<example id="viewdata">
|
|
<title><firstterm>viewdata.sh</firstterm>: Shell Script Conversion
|
|
of VIEWDATA.BAT</title>
|
|
<programlisting>&viewdata;</programlisting>
|
|
</example>
|
|
|
|
|
|
|
|
<para>Ted Davis' <ulink url="http://www.maem.umr.edu/batch/">Shell
|
|
Scripts on the PC</ulink> site had a set of comprehensive
|
|
tutorials on the old-fashioned art of batch file
|
|
programming. Unfortunately the page has vanished without a
|
|
trace.</para>
|
|
|
|
|
|
</appendix>
|
|
<!-- End DOS Batch File Conversion appendix -->
|
|
|
|
|
|
<appendix id="exercises">
|
|
<title>Exercises</title>
|
|
|
|
<para>The exercises that follow test and extend your knowledge
|
|
of scripting. Think of them as a challenge, as an entertaining way
|
|
to take you further along the stony path toward UNIX wizardry.</para>
|
|
|
|
<para>
|
|
<literallayout>
|
|
On a dingy side street in a run-down section of Hoboken, New Jersey,
|
|
there sits a nondescript squat two-story brick building with an inscription
|
|
incised on a marble plate in its wall:
|
|
|
|
<computeroutput>Bash Scripting Hall of Fame</computeroutput>.
|
|
|
|
Inside, among various dusty uninteresting exhibits is a corroding,
|
|
cobweb-festooned brass plaque inscribed with a short, very short
|
|
list of those few persons who have successfully mastered the material
|
|
in the <firstterm>Advanced Bash Scripting Guide</firstterm>, as evidenced by their performance
|
|
on the following Exercise sections.
|
|
|
|
(Alas, the author of the <firstterm>ABS Guide</firstterm> is not represented among the exhibits.
|
|
This is possibly due to malicious rumors about <link linkend="nocreds">lack of credentials</link> and
|
|
<link linkend="ktour0">deficient scripting skills</link>.)
|
|
</literallayout>
|
|
</para>
|
|
|
|
<sect1 id="scriptanalysis">
|
|
<title>Analyzing Scripts</title>
|
|
|
|
<para>Examine the following script. Run it, then explain what it
|
|
does. Annotate the script and rewrite it in a more compact and
|
|
elegant manner.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
MAX=10000
|
|
|
|
|
|
for((nr=1; nr<$MAX; nr++))
|
|
do
|
|
|
|
let "t1 = nr % 5"
|
|
if [ "$t1" -ne 3 ]
|
|
then
|
|
continue
|
|
fi
|
|
|
|
let "t2 = nr % 7"
|
|
if [ "$t2" -ne 4 ]
|
|
then
|
|
continue
|
|
fi
|
|
|
|
let "t3 = nr % 9"
|
|
if [ "$t3" -ne 5 ]
|
|
then
|
|
continue
|
|
fi
|
|
|
|
break # What happens when you comment out this line? Why?
|
|
|
|
done
|
|
|
|
echo "Number = $nr"
|
|
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para>Explain what the following script does. It is really just
|
|
a parameterized command-line pipe.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
DIRNAME=/usr/bin
|
|
FILETYPE="shell script"
|
|
LOGFILE=logfile
|
|
|
|
file "$DIRNAME"/* | fgrep "$FILETYPE" | tee $LOGFILE | wc -l
|
|
|
|
exit 0</programlisting>
|
|
</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para>Examine and explain the following script. For hints, you
|
|
might refer to the listings for <link
|
|
linkend="findref">find</link> and <link
|
|
linkend="statref">stat</link>.</para>
|
|
|
|
<para>
|
|
<programlisting>#!/bin/bash
|
|
|
|
# Author: Nathan Coulter
|
|
# This code is released to the public domain.
|
|
# The author gave permission to use this code snippet in the ABS Guide.
|
|
|
|
find -maxdepth 1 -type f -printf '%f\000' | {
|
|
while read -d $'\000'; do
|
|
mv "$REPLY" "$(date -d "$(stat -c '%y' "$REPLY") " '+%Y%m%d%H%M%S'
|
|
)-$REPLY"
|
|
done
|
|
}
|
|
|
|
# Warning: Test-drive this script in a "scratch" directory.
|
|
# It will somehow affect all the files there.</programlisting>
|
|
</para>
|
|
|
|
<para>---</para>
|
|
|
|
<para>A reader sent in the following code snippet.</para>
|
|
|
|
<para>
|
|
<programlisting>while read LINE
|
|
do
|
|
echo $LINE
|
|
done < `tail -f /var/log/messages`</programlisting>
|
|
</para>
|
|
|
|
<para>He wished to write a script tracking changes to the system log
|
|
file, <filename>/var/log/messages</filename>. Unfortunately,
|
|
the above code block hangs and does nothing
|
|
useful. Why? Fix this so it does work. (Hint:
|
|
rather than <link linkend="redirref">redirecting the
|
|
<filename>stdin</filename> of the loop</link>, try a <link
|
|
linkend="piperef">pipe</link>.)</para>
|
|
|
|
|
|
<para>---</para>
|
|
|
|
<para>Analyze the following <quote>one-liner</quote> (here
|
|
split into two lines for clarity) contributed by Rory
|
|
Winston:</para>
|
|
|
|
<para>
|
|
<programlisting>export SUM=0; for f in $(find src -name "*.java");
|
|
do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUM</programlisting>
|
|
</para>
|
|
|
|
<para>Hint: First, break the script up into bite-sized
|
|
sections. Then, carefully examine its use of <link
|
|
linkend="dblparens">double-parentheses</link> arithmetic,
|
|
the <link linkend="exportref">export</link> command,
|
|
the <link linkend="findref">find</link> command, the
|
|
<link linkend="wcref">wc</link> command, and <link
|
|
linkend="awkref">awk</link>.</para>
|
|
|
|
<para>---</para>
|
|
|
|
|
|
<para>Analyze <xref linkend="lifeslow"/>, and reorganize it in a
|
|
simplified and more logical style. See how many of the variables
|
|
can be eliminated, and try to optimize the script to speed up
|
|
its execution time.</para>
|
|
|
|
<para>Alter the script so that it accepts any ordinary ASCII
|
|
text file as input for its initial <quote>generation</quote>. The
|
|
script will read the first <parameter>$ROW*$COL</parameter>
|
|
characters, and set the occurrences of vowels as
|
|
<quote>living</quote> cells. Hint: be sure to translate the
|
|
spaces in the input file to underscore characters.</para>
|
|
|
|
</sect1>
|
|
<!-- End Analyzing Scripts section -->
|
|
|
|
|
|
|
|
<sect1 id="writingscripts">
|
|
<title>Writing Scripts</title>
|
|
|
|
<para><anchor id="writingscripts1"/></para>
|
|
|
|
<para>Write a script to carry out each of the following tasks.</para>
|
|
|
|
|
|
<variablelist id="exeasy">
|
|
<title><anchor id="exeasy1"/>EASY</title>
|
|
|
|
<varlistentry>
|
|
<term><command>Self-reproducing Script</command></term>
|
|
<listitem>
|
|
<para>Write a script that backs itself up, that is, copies
|
|
itself to a file named <filename>backup.sh</filename>.</para>
|
|
<para>Hint: Use the <link linkend="catref">cat</link> command
|
|
and the appropriate <link linkend="scrnameparam">positional
|
|
parameter</link>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Home Directory Listing</command></term>
|
|
<listitem>
|
|
<para>Perform a recursive directory listing on the user's home
|
|
directory and save the information to a file. Compress
|
|
the file, have the script prompt the user to insert
|
|
a USB flash drive, then press <keycap>ENTER</keycap>.
|
|
Finally, save the file to the flash drive after making
|
|
certain the flash drive has properly mounted by parsing
|
|
the output of <link linkend="dfref">df</link>. Note that
|
|
the flash drive must be <firstterm>unmounted</firstterm>
|
|
before it is removed.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Converting <link linkend="forloopref1">for</link>
|
|
loops to <link linkend="whileloopref">while</link> and <link
|
|
linkend="untilloopref">until</link> loops</command></term>
|
|
<listitem>
|
|
<para>Convert the <firstterm>for loops</firstterm> in <xref
|
|
linkend="ex22"/> to <firstterm>while
|
|
loops</firstterm>. Hint: store the data in an <link
|
|
linkend="arrayref">array</link> and step through the array
|
|
elements.</para>
|
|
<para>Having already done the <quote>heavy lifting,</quote>
|
|
now convert the loops in the example to <firstterm> until
|
|
loops</firstterm>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Changing the line spacing of a text file</command></term>
|
|
<listitem>
|
|
|
|
<para>Write a script that reads each line of a target file, then
|
|
writes the line back to <filename>stdout</filename>, but with
|
|
an extra blank line following. This has the effect of
|
|
<emphasis>double-spacing</emphasis> the file.</para>
|
|
|
|
<para>Include all necessary code to check whether the script
|
|
gets the necessary command-line argument (a filename),
|
|
and whether the specified file exists.</para>
|
|
|
|
<para>When the script runs correctly, modify it to
|
|
<emphasis>triple-space</emphasis> the target file.</para>
|
|
|
|
<para>Finally, write a script to remove all blank lines from
|
|
the target file, <emphasis>single-spacing</emphasis> it.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Backwards Listing</command></term>
|
|
<listitem>
|
|
<para>Write a script that echoes itself to
|
|
<filename>stdout</filename>, but
|
|
<emphasis>backwards</emphasis>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Automatically Decompressing Files</command></term>
|
|
<listitem>
|
|
<para>Given a list of filenames as input, this script
|
|
queries each target file (parsing the output of the
|
|
<link linkend="fileref">file</link> command) for
|
|
the type of compression used on it. Then the script
|
|
automatically invokes the appropriate decompression command
|
|
(<command>gunzip</command>, <command>bunzip2</command>,
|
|
<command>unzip</command>, <command>uncompress</command>,
|
|
or whatever). If a target file is not compressed, the
|
|
script emits a warning message, but takes no other action
|
|
on that particular file.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Unique System ID</command></term>
|
|
<listitem>
|
|
<para>Generate a <quote>unique</quote> 6-digit hexadecimal
|
|
identifier for your computer. Do <emphasis>not</emphasis>
|
|
use the flawed <link linkend="hostidref">hostid</link>
|
|
command. Hint: <command><link
|
|
linkend="md5sumref">md5sum</link>
|
|
<link
|
|
linkend="datafilesref1"><filename>/etc/passwd</filename></link></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>
|
|
<para>Optional: you may use this as the basis of a
|
|
<firstterm>backup</firstterm> script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Checking whether a process is still running</command></term>
|
|
<listitem>
|
|
<para>Given a <link linkend="processidref">process ID</link>
|
|
(<firstterm>PID</firstterm>) as an argument, this script
|
|
will check, at user-specified intervals, whether
|
|
the given process is still running. You may use
|
|
the <link linkend="ppssref">ps</link> and <link
|
|
linkend="sleepref">sleep</link> commands.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Primes</command></term>
|
|
<listitem>
|
|
<para>Print (to <filename>stdout</filename>) all
|
|
prime numbers between 60000 and 63000. The output
|
|
should be nicely formatted in columns (hint:
|
|
use <link linkend="printfref">printf</link>).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Lottery Numbers</command></term>
|
|
<listitem>
|
|
<para>One type of lottery involves picking five
|
|
different numbers, in the range of 1 - 50. Write a
|
|
script that generates five pseudorandom numbers in this
|
|
range, <emphasis>with no duplicates</emphasis>. The
|
|
script will give the option of echoing the numbers to
|
|
<filename>stdout</filename> or saving them to a file,
|
|
along with the date and time the particular number set
|
|
was generated. (If your script consistently generates
|
|
<emphasis>winning</emphasis> lottery numbers, then you
|
|
can retire on the proceeds and leave shell scripting to
|
|
those of us who have to work for a living.)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="exmedium">
|
|
<title><anchor id="exmedium1"/>INTERMEDIATE</title>
|
|
|
|
<varlistentry>
|
|
<term><command>Integer or String</command></term>
|
|
<listitem>
|
|
<para>Write a script <link linkend="functionref">function</link>
|
|
that determines if an argument passed to it is an integer
|
|
or a string. The function will return TRUE (0) if
|
|
passed an integer, and FALSE (1) if passed a string.</para>
|
|
<para>Hint: What does the following expression return
|
|
when <varname>$1</varname> is <emphasis>not</emphasis>
|
|
an integer?</para>
|
|
<para><varname>expr $1 + 0</varname></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command><link linkend="asciidef">ASCII</link>
|
|
to Integer</command></term>
|
|
<listitem>
|
|
<para>The <firstterm>atoi</firstterm> function in
|
|
<command>C</command> converts a string character to
|
|
an integer. Write a shell script function that performs
|
|
the same operation. Likewise, write a shell script function
|
|
that does the inverse, mirroring the <command>C</command>
|
|
<firstterm>itoa</firstterm> function which converts an
|
|
integer into an ASCII character.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Managing Disk Space</command></term>
|
|
<listitem>
|
|
<para>List, one at a time, all files larger than 100K in
|
|
the <filename class="directory">/home/username</filename>
|
|
directory tree. Give the user the option to delete or
|
|
compress the file, then proceed to show the next one. Write
|
|
to a logfile the names of all deleted files and the
|
|
deletion times.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Banner</command></term>
|
|
<listitem>
|
|
<para>Simulate the functionality of the deprecated <link
|
|
linkend="bannerref">banner</link> command in a script.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Removing Inactive Accounts</command></term>
|
|
<listitem>
|
|
<para>Inactive accounts on a network server waste disk space and may
|
|
become a security risk. Write an administrative script
|
|
(to be invoked by <firstterm>root</firstterm> or the <link
|
|
linkend="cronref">cron daemon</link>) that checks
|
|
for and deletes user accounts that have not been accessed
|
|
within the last 90 days.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Enforcing Disk Quotas</command></term>
|
|
<listitem>
|
|
<para>Write a script for a multi-user system that checks users'
|
|
disk usage. If a user surpasses a preset limit
|
|
(500 MB, for example) in her <filename
|
|
class="directory">/home/username</filename>
|
|
directory, then the script automatically sends her a
|
|
<quote>pigout</quote> warning e-mail.</para> <para>The
|
|
script will use the <link linkend="duref">du</link>
|
|
and <link linkend="commmail1">mail</link> commands. As
|
|
an option, it will allow setting and enforcing quotas
|
|
using the <link linkend="quotaref">quota</link> and <link
|
|
linkend="setquotaref">setquota</link> commands.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Logged in User Information</command></term>
|
|
<listitem>
|
|
|
|
<para>For all logged in users, show their real names and the time
|
|
and date of their last login.</para>
|
|
|
|
<para>Hint: use <link linkend="whoref">who</link>,
|
|
<link linkend="lastlogref">lastlog</link>,
|
|
and parse <link
|
|
linkend="datafilesref1"><filename>/etc/passwd</filename></link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Safe Delete</command></term>
|
|
<listitem>
|
|
<para>Implement, as a script, a <quote>safe</quote> delete
|
|
command, <filename>sdel.sh</filename>. Filenames passed as
|
|
command-line arguments to this script are not deleted,
|
|
but instead <link linkend="gzipref">gzipped</link>
|
|
if not already compressed (use <link
|
|
linkend="fileref">file</link> to check), then moved
|
|
to a <filename class="directory">~/TRASH</filename>
|
|
directory. Upon invocation, the script checks the <filename
|
|
class="directory">~/TRASH</filename> directory for files
|
|
older than 48 hours and <link linkend="rmref">permanently
|
|
deletes</link> them. (An better alternative might be to
|
|
have a second script handle this, periodically invoked
|
|
by the <link linkend="cronref">cron daemon</link>.)</para>
|
|
<para><emphasis>Extra credit:</emphasis> Write the script
|
|
so it can handle files and directories <link
|
|
linkend="rmrecurs">recursively</link>. This would give it
|
|
the capability of <quote>safely deleting</quote> entire
|
|
directory structures.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Making Change</command></term>
|
|
<listitem>
|
|
<para>What is the most efficient way to make change for $1.68,
|
|
using only coins in common circulations (up to 25c)? It's
|
|
6 quarters, 1 dime, a nickel, and three cents.</para>
|
|
<para>Given any arbitrary command-line input in dollars and
|
|
cents ($*.??), calculate the change, using the minimum
|
|
number of coins. If your home country is not the United
|
|
States, you may use your local currency units instead. The
|
|
script will need to parse the command-line input, then
|
|
change it to multiples of the smallest monetary unit (cents
|
|
or whatever). Hint: look at <xref linkend="ex61"/>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Quadratic Equations</command></term>
|
|
<listitem>
|
|
<para>Solve a <firstterm>quadratic</firstterm> equation of the form
|
|
<parameter>Ax^2 + Bx + C = 0</parameter>. Have a script take
|
|
as arguments the coefficients, <userinput>A</userinput>,
|
|
<userinput>B</userinput>, and <userinput>C</userinput>,
|
|
and return the solutions to five decimal places.</para>
|
|
|
|
<para>Hint: pipe the coefficients to <link
|
|
linkend="bcref">bc</link>, using the well-known formula,
|
|
<parameter>x = ( -B +/- sqrt( B^2 - 4AC ) ) / 2A</parameter>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Table of Logarithms</command></term>
|
|
<listitem>
|
|
<para>Using the <link linkend="bcref">bc</link> and <link
|
|
linkend="printfref">printf</link> commands, print out a
|
|
nicely-formatted table of eight-place natural logarithms
|
|
in the interval between 0.00 and 100.00, in steps of
|
|
.01.</para>
|
|
<para>Hint: <firstterm>bc</firstterm> requires the
|
|
<option>-l</option> option to load the math library.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Unicode Table</command></term>
|
|
<listitem>
|
|
<para>Using <xref linkend="asciish"/> as a template,
|
|
write a script that prints to a file a complete
|
|
<link linkend="unicoderef">Unicode</link> table.</para>
|
|
<para>Hint: Use the <option>-e</option> option to
|
|
<link linkend="echoref">echo</link>:
|
|
<command>echo -e '\uXXXX'</command>, where
|
|
<replaceable>XXXX</replaceable>
|
|
is the Unicode numerical character designation.
|
|
This requires <link linkend="bash42">version 4.2</link>
|
|
or later of Bash.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Sum of Matching Numbers</command></term>
|
|
<listitem>
|
|
<para>Find the sum of all five-digit numbers (in the range
|
|
10000 - 99999) containing <emphasis>exactly two</emphasis>
|
|
out of the following set of digits: { 4, 5, 6 }. These may
|
|
repeat within the same number, and if so, they count once
|
|
for each occurrence.</para>
|
|
<para>Some examples of <firstterm>matching numbers</firstterm> are
|
|
42057, 74638, and 89515.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Lucky Numbers</command></term>
|
|
<listitem>
|
|
<para>A <firstterm>lucky number</firstterm> is one whose
|
|
individual digits add up to 7, in successive additions. For
|
|
example, 62431 is a <firstterm>lucky number</firstterm>
|
|
(6 + 2 + 4 + 3 + 1 = 16, 1 + 6 = 7). Find all the
|
|
<firstterm>lucky numbers</firstterm> between 1000 and
|
|
10000.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Craps</command></term>
|
|
<listitem>
|
|
<para>Borrowing the ASCII graphics from <xref linkend="petals"/>,
|
|
write a script that plays the well-known gambling game of
|
|
<firstterm>craps</firstterm>. The script will accept bets
|
|
from one or more players, roll the dice, and keep track of
|
|
wins and losses, as well as of each player's bankroll.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Tic-tac-toe</command></term>
|
|
<listitem>
|
|
<para>Write a script that plays the child's game of
|
|
<firstterm>tic-tac-toe</firstterm> against a human
|
|
player. The script will let the human choose whether
|
|
to take the first move. The script will follow
|
|
an optimal strategy, and therefore never lose. To simplify
|
|
matters, you may use ASCII graphics:</para>
|
|
|
|
<para><programlisting> o | x |
|
|
----------
|
|
| x |
|
|
----------
|
|
| o |
|
|
|
|
Your move, human (row, column)?</programlisting></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Alphabetizing a String</command></term>
|
|
<listitem>
|
|
<para>Alphabetize (in ASCII order) an arbitrary string
|
|
read from the command-line.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Parsing</command></term>
|
|
<listitem>
|
|
<para>Parse <link
|
|
linkend="datafilesref1"><filename>/etc/passwd</filename></link>,
|
|
and output its contents in nice, easy-to-read tabular
|
|
form.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Logging Logins</command></term>
|
|
<listitem>
|
|
<para>Parse <filename>/var/log/messages</filename> to
|
|
produce a nicely formatted file of user logins and login
|
|
times. The script may need to run as
|
|
<firstterm>root</firstterm>. (Hint: Search for the string
|
|
<quote>LOGIN.</quote>)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Pretty-Printing a Data File</command></term>
|
|
<listitem>
|
|
<para>Certain database and spreadsheet packages use
|
|
save-files with the fields separated by commas, commonly
|
|
referred to as <firstterm>comma-separated values</firstterm>
|
|
or CSVs. Other applications often need to parse these
|
|
files.</para> <para>Given a data file with comma-separated
|
|
<link linkend="fieldref">fields</link>, of the form:
|
|
<programlisting>Jones,Bill,235 S. Williams St.,Denver,CO,80221,(303) 244-7989
|
|
Smith,Tom,404 Polk Ave.,Los Angeles,CA,90003,(213) 879-5612
|
|
...</programlisting>
|
|
Reformat the data and print it out to
|
|
<filename>stdout</filename> in labeled, evenly-spaced columns.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Justification</command></term>
|
|
<listitem>
|
|
<para>Given ASCII text input either from
|
|
<filename>stdin</filename> or a file, adjust
|
|
the word spacing to right-justify each line to a
|
|
user-specified line-width, then send the output to
|
|
<filename>stdout</filename>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Mailing List</command></term>
|
|
<listitem>
|
|
<para>Using the <link linkend="commmail1">mail</link> command,
|
|
write a script that manages a simple mailing list. The
|
|
script automatically e-mails the monthly company newsletter,
|
|
read from a specified text file, and sends it to all the
|
|
addresses on the mailing list, which the script reads from
|
|
another specified file.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Generating Passwords</command></term>
|
|
<listitem>
|
|
<para>Generate pseudorandom 8-character passwords, using
|
|
characters in the ranges [0-9], [A-Z], [a-z]. Each password
|
|
must contain at least two digits.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Monitoring a User</command></term>
|
|
<listitem>
|
|
|
|
<para>You suspect that one particular user on the network
|
|
has been abusing her privileges and possibly attempting to
|
|
hack the system. Write a script to automatically monitor
|
|
and log her activities when she's signed on. The log file
|
|
will save entries for the previous week, and delete those
|
|
entries more than seven days old.</para>
|
|
|
|
<para>You may use <link linkend="lastref">last</link>,
|
|
<link linkend="lastlogref">lastlog</link>, and <link
|
|
linkend="lastcommref">lastcomm</link> to aid your
|
|
surveillance of the suspected fiend.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Checking for Broken Links</command></term>
|
|
<listitem>
|
|
<para>Using <link linkend="lynxref">lynx</link> with the
|
|
<option>-traversal</option> option, write a script that
|
|
checks a Web site for broken links.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<variablelist id="exdifficult">
|
|
<title><anchor id="exdifficult1"/>DIFFICULT</title>
|
|
|
|
<varlistentry>
|
|
<term><command>Testing Passwords</command></term>
|
|
<listitem>
|
|
<para>Write a script to check and validate passwords. The object
|
|
is to flag <quote>weak</quote> or easily guessed password
|
|
candidates.</para>
|
|
|
|
<para>A trial password will be input to the script as a
|
|
command-line parameter. To be considered acceptable,
|
|
a password must meet the following minimum qualifications:
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Minimum length of 8 characters</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Must contain at least one numeric character</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Must contain at least one of the following
|
|
non-alphabetic characters: <token>@</token>,
|
|
<token>#</token>, <token>$</token>, <token>%</token>,
|
|
<token>&</token>, <token>*</token>, <token>+</token>,
|
|
<token>-</token>, <token>=</token></para>
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>Optional:
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Do a dictionary check on every sequence of at least
|
|
four consecutive alphabetic characters in the password under
|
|
test. This will eliminate passwords containing embedded
|
|
<quote>words</quote> found in a standard dictionary.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Enable the script to check all the passwords on your
|
|
system. These do not reside in
|
|
<link
|
|
linkend="datafilesref1"><filename>/etc/passwd</filename></link>.</para>
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>This exercise tests mastery of <link
|
|
linkend="regexref">Regular Expressions</link>.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Cross Reference</command></term>
|
|
<listitem>
|
|
<para>Write a script that generates a
|
|
<firstterm>cross-reference</firstterm>
|
|
(<firstterm>concordance</firstterm>) on a target file.
|
|
The output will be a listing of all word occurrences in
|
|
the target file, along with the line numbers in which
|
|
each word occurs. Traditionally, <firstterm>linked
|
|
list</firstterm> constructs would be used in such
|
|
applications. Therefore, you should investigate <link
|
|
linkend="arrayref">arrays</link> in the course of
|
|
this exercise. <xref linkend="wf"/> is probably
|
|
<emphasis>not</emphasis> a good place to start.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="newtonsqrt"/><command>Square Root</command></term>
|
|
<listitem>
|
|
<para>Write a script to calculate square roots of numbers
|
|
using <firstterm>Newton's Method</firstterm>.</para>
|
|
|
|
<para>The algorithm for this, expressed as a snippet of Bash
|
|
<link linkend="pseudocoderef">pseudo-code</link> is:</para>
|
|
|
|
<para><programlisting># (Isaac) Newton's Method for speedy extraction
|
|
#+ of square roots.
|
|
|
|
guess = $argument
|
|
# $argument is the number to find the square root of.
|
|
# $guess is each successive calculated "guess" -- or trial solution --
|
|
#+ of the square root.
|
|
# Our first "guess" at a square root is the argument itself.
|
|
|
|
oldguess = 0
|
|
# $oldguess is the previous $guess.
|
|
|
|
tolerance = .000001
|
|
# To how close a tolerance we wish to calculate.
|
|
|
|
loopcnt = 0
|
|
# Let's keep track of how many times through the loop.
|
|
# Some arguments will require more loop iterations than others.
|
|
|
|
|
|
while [ ABS( $guess $oldguess ) -gt $tolerance ]
|
|
# ^^^^^^^^^^^^^^^^^^^^^^^ Fix up syntax, of course.
|
|
|
|
# "ABS" is a (floating point) function to find the absolute value
|
|
#+ of the difference between the two terms.
|
|
# So, as long as difference between current and previous
|
|
#+ trial solution (guess) exceeds the tolerance, keep looping.
|
|
|
|
do
|
|
oldguess = $guess # Update $oldguess to previous $guess.
|
|
|
|
# =======================================================
|
|
guess = ( $oldguess + ( $argument / $oldguess ) ) / 2.0
|
|
# = 1/2 ( ($oldguess **2 + $argument) / $oldguess )
|
|
# equivalent to:
|
|
# = 1/2 ( $oldguess + $argument / $oldguess )
|
|
# that is, "averaging out" the trial solution and
|
|
#+ the proportion of argument deviation
|
|
#+ (in effect, splitting the error in half).
|
|
# This converges on an accurate solution
|
|
#+ with surprisingly few loop iterations . . .
|
|
#+ for arguments > $tolerance, of course.
|
|
# =======================================================
|
|
|
|
(( loopcnt++ )) # Update loop counter.
|
|
done</programlisting></para>
|
|
|
|
<para>It's a simple enough recipe, and
|
|
<emphasis>seems</emphasis> at first glance easy enough to
|
|
convert into a working Bash script. The problem, though,
|
|
is that Bash has <link linkend="nofloatingpoint">no native
|
|
support for floating point numbers</link>. So, the script
|
|
writer needs to use <link linkend="bcref">bc</link> or
|
|
possibly <link linkend="awkref">awk</link> to convert the
|
|
numbers and do the calculations. It could get rather messy
|
|
. . .</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>Logging File Accesses</command></term>
|
|
<listitem>
|
|
<para>Log all accesses to the files in <filename
|
|
class="directory">/etc</filename> during the course of
|
|
a single day. This information should include the filename,
|
|
user name, and access time. If any alterations to the
|
|
files take place, that will be flagged. Write this data
|
|
as tabular (tab-separated) formatted records in a logfile.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Monitoring Processes</command></term>
|
|
<listitem>
|
|
<para>Write a script to continually monitor all running
|
|
processes and to keep track of how many child processes each
|
|
parent spawns. If a process spawns more than five children,
|
|
then the script sends an e-mail to the system administrator
|
|
(or <firstterm>root</firstterm>) with all relevant
|
|
information, including the time, PID of the parent, PIDs
|
|
of the children, etc. The script appends a report to a log
|
|
file every ten minutes. </para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Strip Comments</command></term>
|
|
<listitem>
|
|
<para>Strip all comments from a shell script whose name
|
|
is specified on the command-line. Note that the initial
|
|
<link linkend="shabangref">#! line</link> must not be
|
|
stripped out.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Strip HTML Tags</command></term>
|
|
<listitem>
|
|
<para>Strip all the 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>
|
|
<para>Optional: A script that converts Docbook/SGML to XML.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><anchor id="cspammers"/><command>Chasing Spammers</command></term>
|
|
<listitem>
|
|
|
|
<para> Write a script that analyzes a spam e-mail by doing
|
|
DNS lookups on the IP addresses in the headers to identify
|
|
the relay hosts as well as the originating ISP. The
|
|
script will forward the unaltered spam message to the
|
|
responsible ISPs. Of course, it will be necessary to
|
|
filter out <emphasis>your own ISP's IP address</emphasis>,
|
|
so you don't end up complaining about yourself.</para>
|
|
|
|
<para>As necessary, use the appropriate <link
|
|
linkend="communinfo1">network analysis commands</link>.</para>
|
|
|
|
<para>For some ideas, see <xref linkend="isspammer"/> and <xref
|
|
linkend="isspammer2"/>.</para>
|
|
|
|
<para>Optional: Write a script that searches through a list of
|
|
e-mail messages and deletes the spam according to specified
|
|
filters.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Creating man pages</command></term>
|
|
<listitem>
|
|
|
|
<para>Write a script that automates the process of creating
|
|
<link linkend="manref">man pages</link>.</para>
|
|
|
|
<para>Given a text file which contains information to be
|
|
formatted into a <firstterm>man page</firstterm>, the
|
|
script will read the file, then invoke the appropriate
|
|
<link linkend="groffref">groff</link> commands to
|
|
output the corresponding <firstterm>man page</firstterm>
|
|
to <filename>stdout</filename>. The text file contains
|
|
blocks of information under the standard <firstterm>man
|
|
page</firstterm> headings, i.e., NAME, SYNOPSIS,
|
|
DESCRIPTION, etc.</para>
|
|
|
|
<para><xref linkend="maned"/> is an instructive first step.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
|
|
<varlistentry>
|
|
<term><command>Hex Dump</command></term>
|
|
<listitem>
|
|
<para>Do a hex(adecimal) dump on a binary file
|
|
specified as an argument to the script. The output should
|
|
be in neat tabular <link linkend="fieldref">fields</link>,
|
|
with the first field showing the address, each of the
|
|
next 8 fields a 4-byte hex number, and the final field
|
|
the ASCII equivalent of the previous 8 fields.</para>
|
|
<para>The obvious followup to this is to extend the hex
|
|
dump script into a disassembler. Using a lookup table,
|
|
or some other clever gimmick, convert the hex values into
|
|
80x86 op codes.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Emulating a Shift Register</command></term>
|
|
<listitem>
|
|
<para>Using <xref linkend="stackex"/> as an inspiration,
|
|
write a script that emulates a 64-bit shift register as
|
|
an <link linkend="arrayref">array</link>. Implement
|
|
functions to <firstterm>load</firstterm> the register,
|
|
<firstterm>shift left</firstterm>, <firstterm>shift
|
|
right</firstterm>, and <firstterm>rotate</firstterm>
|
|
it. Finally, write a function that interprets the register
|
|
contents as eight 8-bit ASCII characters.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Calculating Determinants</command></term>
|
|
<listitem>
|
|
<para>Write a script that calculates
|
|
determinants
|
|
<footnote>
|
|
<para>For all you clever types who failed intermediate algebra,
|
|
a <firstterm>determinant</firstterm> is a numerical value
|
|
associated with a multidimensional
|
|
<firstterm>matrix</firstterm> (<link
|
|
linkend="arrayref">array</link> of numbers).
|
|
<programlisting>For the simple case of a 2 x 2 determinant:
|
|
|
|
|a b|
|
|
|b a|
|
|
|
|
The solution is a*a - b*b, where "a" and "b" represent numbers.</programlisting>
|
|
</para></footnote>
|
|
|
|
by <link
|
|
linkend="recursionref0">recursively</link> expanding the
|
|
<firstterm>minors</firstterm>. Use a 4 x 4 determinant as
|
|
a test case.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Hidden Words</command></term>
|
|
<listitem>
|
|
<para>Write a <quote>word-find</quote> puzzle generator,
|
|
a script that hides 10 input words in a 10 x 10 array
|
|
of random letters. The words may be hidden across, down,
|
|
or diagonally.</para>
|
|
<para>Optional: Write a script that <emphasis>solves</emphasis>
|
|
word-find puzzles. To keep this from becoming too difficult,
|
|
the solution script will find only horizontal and vertical
|
|
words. (Hint: Treat each row and column as a string, and
|
|
search for substrings.)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Anagramming</command></term>
|
|
<listitem>
|
|
<para> Anagram 4-letter input. For example, the
|
|
anagrams of <emphasis>word</emphasis> are:
|
|
<emphasis>do or rod row word</emphasis>. You may use
|
|
<filename>/usr/share/dict/linux.words</filename> as the
|
|
reference list.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Word Ladders</command></term>
|
|
<listitem>
|
|
<para>A <quote>word ladder</quote> is a sequence of words,
|
|
with each successive word in the sequence differing from
|
|
the previous one by a single letter.</para>
|
|
|
|
<para>For example, to <quote>ladder</quote> from
|
|
<emphasis>mark</emphasis> to
|
|
<emphasis>vase</emphasis>:</para>
|
|
|
|
<para>
|
|
<programlisting>
|
|
mark --> park --> part --> past --> vast --> vase
|
|
^ ^ ^ ^ ^</programlisting>
|
|
</para>
|
|
|
|
<para>Write a script that solves word ladder puzzles. Given
|
|
a starting and an ending word, the script will list all
|
|
intermediate steps in the <quote>ladder.</quote> Note
|
|
that <emphasis>all</emphasis> words in the sequence must
|
|
be legitimate dictionary words.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Fog Index</command></term>
|
|
<listitem>
|
|
|
|
<para>The <quote>fog index</quote> of a passage of text
|
|
estimates its reading difficulty, as a number corresponding
|
|
roughly to a school grade level. For example, a passage
|
|
with a fog index of 12 should be comprehensible to anyone
|
|
with 12 years of schooling.</para>
|
|
|
|
<para>The Gunning version of the fog index uses the following
|
|
algorithm.</para>
|
|
|
|
<orderedlist>
|
|
|
|
<listitem><para>Choose a section of the text at least
|
|
100 words in length.</para></listitem>
|
|
|
|
<listitem><para>Count the number of sentences (a portion of
|
|
a sentence truncated by the boundary of the text section
|
|
counts as one).</para></listitem>
|
|
|
|
<listitem>
|
|
<para>Find the average number of words per
|
|
sentence.</para>
|
|
|
|
<para>AVE_WDS_SEN = TOTAL_WORDS / SENTENCES</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Count the number of <quote>difficult</quote>
|
|
words in the segment -- those containing at least
|
|
3 syllables. Divide this quantity by total words to
|
|
get the proportion of difficult words.</para>
|
|
|
|
<para>PRO_DIFF_WORDS = LONG_WORDS / TOTAL_WORDS</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The Gunning fog index is the sum of the above two
|
|
quantities, multiplied by 0.4, then rounded to the
|
|
nearest integer.</para>
|
|
|
|
<para>G_FOG_INDEX = int ( 0.4 * ( AVE_WDS_SEN + PRO_DIFF_WORDS ) )</para>
|
|
</listitem>
|
|
|
|
</orderedlist>
|
|
|
|
<para>Step 4 is by far the most difficult portion of the
|
|
exercise. There exist various algorithms for estimating
|
|
the syllable count of a word. A rule-of-thumb formula
|
|
might consider the number of letters in a word and the
|
|
vowel-consonant mix.</para>
|
|
|
|
<para>A strict interpretation of the Gunning fog index does
|
|
not count compound words and proper nouns as
|
|
<quote>difficult</quote> words, but this would enormously
|
|
complicate the script.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Calculating PI using Buffon's Needle</command></term>
|
|
<listitem>
|
|
|
|
<para>The Eighteenth Century French mathematician de Buffon
|
|
came up with a novel experiment. Repeatedly drop a needle
|
|
of length <replaceable>n</replaceable> onto a wooden floor
|
|
composed of long and narrow parallel boards. The cracks
|
|
separating the equal-width floorboards are a fixed distance
|
|
<replaceable>d</replaceable> apart. Keep track of the
|
|
total drops and the number of times the needle intersects
|
|
a crack on the floor. The ratio of these two quantities
|
|
turns out to be a fractional multiple of PI.</para>
|
|
|
|
<para>In the spirit of <xref linkend="cannon"/>, write a
|
|
script that runs a Monte Carlo simulation of
|
|
<firstterm>Buffon's Needle</firstterm>. To simplify matters,
|
|
set the needle length equal to the distance between the
|
|
cracks, <parameter>n = d</parameter>.</para>
|
|
|
|
<para>Hint: there are actually two critical variables:
|
|
the distance from the center of the needle to the nearest
|
|
crack, and the inclination angle of the needle to that crack.
|
|
You may use <link linkend="bcref">bc</link> to handle
|
|
the calculations.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><command>Playfair Cipher</command></term>
|
|
<listitem>
|
|
|
|
<para>Implement the Playfair (Wheatstone) Cipher in a
|
|
script.</para>
|
|
|
|
<para>The Playfair Cipher encrypts text by substitution
|
|
of <firstterm>digrams</firstterm> (2-letter groupings).
|
|
It is traditional to use a 5 x 5 letter scrambled-alphabet
|
|
<firstterm>key square</firstterm> for the encryption and
|
|
decryption.</para>
|
|
|
|
<para>
|
|
<programlisting> C O D E S
|
|
A B F G H
|
|
I K L M N
|
|
P Q R T U
|
|
V W X Y Z
|
|
|
|
Each letter of the alphabet appears once, except "I" also represents
|
|
"J". The arbitrarily chosen key word, "CODES" comes first, then all
|
|
the rest of the alphabet, in order from left to right, skipping letters
|
|
already used.
|
|
|
|
To encrypt, separate the plaintext message into digrams (2-letter
|
|
groups). If a group has two identical letters, delete the second, and
|
|
form a new group. If there is a single letter left over at the end,
|
|
insert a "null" character, typically an "X."
|
|
|
|
THIS IS A TOP SECRET MESSAGE
|
|
|
|
TH IS IS AT OP SE CR ET ME SA GE
|
|
|
|
|
|
|
|
For each digram, there are three possibilities.
|
|
-----------------------------------------------
|
|
|
|
1) Both letters will be on the same row of the key square:
|
|
For each letter, substitute the one immediately to the right, in that
|
|
row. If necessary, wrap around left to the beginning of the row.
|
|
|
|
or
|
|
|
|
2) Both letters will be in the same column of the key square:
|
|
For each letter, substitute the one immediately below it, in that
|
|
row. If necessary, wrap around to the top of the column.
|
|
|
|
or
|
|
|
|
3) Both letters will form the corners of a rectangle within the key square:
|
|
For each letter, substitute the one on the other corner the rectangle
|
|
which lies on the same row.
|
|
|
|
|
|
The "TH" digram falls under case #3.
|
|
G H
|
|
M N
|
|
T U (Rectangle with "T" and "H" at corners)
|
|
|
|
T --> 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 description of the Playfair Cipher and its solution methods.</programlisting>
|
|
</para>
|
|
|
|
<para>This script will have three main sections</para>
|
|
|
|
<orderedlist id="playfairexref" numeration="upperroman">
|
|
<listitem><para>Generating the <firstterm>key square</firstterm>,
|
|
based on a user-input keyword.</para></listitem>
|
|
<listitem><para>Encrypting a <firstterm>plaintext</firstterm>
|
|
message.</para></listitem>
|
|
<listitem><para>Decrypting encrypted
|
|
text.</para></listitem>
|
|
</orderedlist>
|
|
|
|
<para>The script will make extensive use of <link
|
|
linkend="arrayref">arrays</link> and <link
|
|
linkend="functionref">functions</link>.
|
|
You may use <xref linkend="gronsfeld"/> as an
|
|
inspiration.</para>
|
|
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
<para>--</para>
|
|
<para>Please do not send the author your solutions to these
|
|
exercises. There are more appropriate ways to impress him with
|
|
your cleverness, such as submitting bugfixes and suggestions
|
|
for improving the book.</para>
|
|
|
|
|
|
</sect1>
|
|
<!-- End Writing Scripts section -->
|
|
|
|
</appendix>
|
|
<!-- End Exercises appendix -->
|
|
|
|
|
|
|
|
<appendix id="revisionhistory">
|
|
<title>Revision History</title>
|
|
|
|
<synopsis>
|
|
This document first appeared as a 60-page HOWTO in the late spring
|
|
of 2000. Since then, it has gone through quite a number of updates
|
|
and revisions. This book could not have been written without the
|
|
assistance of the Linux community, and especially of the volunteers
|
|
of the <ulink url="http://www.tldp.org">Linux Documentation Project</ulink>.
|
|
</synopsis>
|
|
|
|
<para>Here is the e-mail to the LDP requesting permission to submit
|
|
version 0.1.</para>
|
|
|
|
<para><programlisting>From thegrendel@theriver.com Sat Jun 10 09:05:33 2000 -0700
|
|
Date: Sat, 10 Jun 2000 09:05:28 -0700 (MST)
|
|
From: "M. Leo Cooper" <thegrendel@theriver.com>
|
|
X-Sender: thegrendel@localhost
|
|
To: ldp-discuss@lists.linuxdoc.org
|
|
Subject: Permission to submit HOWTO
|
|
|
|
Dear HOWTO Coordinator,
|
|
|
|
I am working on and would like to submit to the LDP a HOWTO on the subject
|
|
of "Bash Scripting" (shell scripting, using 'bash'). As it happens,
|
|
I have been writing this document, off and on, for about the last eight
|
|
months or so, and I could produce a first draft in ASCII text format in
|
|
a matter of just a few more days.
|
|
|
|
I began writing this out of frustration at being unable to find a
|
|
decent book on shell scripting. I managed to locate some pretty good
|
|
articles on various aspects of scripting, but nothing like a complete,
|
|
beginning-to-end tutorial. Well, in keeping with my philosophy, if all
|
|
else fails, do it yourself.
|
|
|
|
As it stands, this proposed "Bash-Scripting HOWTO" would serve as a
|
|
combination tutorial and reference, with the heavier emphasis on the
|
|
tutorial. It assumes Linux experience, but only a very basic level
|
|
of programming skills. Interspersed with the text are 79 illustrative
|
|
example scripts of varying complexity, all liberally commented. There
|
|
are even exercises for the reader.
|
|
|
|
At this stage, I'm up to 18,000+ words (124k), and that's over 50 pages of
|
|
text (whew!).
|
|
|
|
|
|
I haven't mentioned that I've previously authored an LDP HOWTO, the
|
|
"Software-Building HOWTO", which I wrote in Linuxdoc/SGML. I don't know
|
|
if I could handle Docbook/SGML, and I'm glad you have volunteers to do
|
|
the conversion. You people seem to have gotten on a more organized basis
|
|
these last few months. Working with Greg Hankins and Tim Bynum was nice,
|
|
but a professional team is even nicer.
|
|
|
|
Anyhow, please advise.
|
|
|
|
|
|
Mendel Cooper
|
|
thegrendel@theriver.com</programlisting></para>
|
|
|
|
|
|
<table frame="none">
|
|
<title>Revision History</title>
|
|
<tgroup cols="3" colsep="0" rowsep="0">
|
|
<thead>
|
|
<row>
|
|
<entry>Release</entry>
|
|
<entry>Date</entry>
|
|
<entry>Comments</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>0.1</entry>
|
|
<entry>14 Jun 2000</entry>
|
|
<entry>Initial release.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>0.2</option></entry>
|
|
<entry>30 Oct 2000</entry>
|
|
<entry>Bugs fixed, plus much additional material and more
|
|
example scripts.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>0.3</option></entry>
|
|
<entry>12 Feb 2001</entry>
|
|
<entry>Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>0.4</option></entry>
|
|
<entry>08 Jul 2001</entry>
|
|
<entry>Complete revision and expansion of the book.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>0.5</option></entry>
|
|
<entry>03 Sep 2001</entry>
|
|
<entry>Major update: Bugfixes, material added,
|
|
sections reorganized.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.0</option></entry>
|
|
<entry>14 Oct 2001</entry>
|
|
<entry>Stable release: Bugfixes, reorganization, material
|
|
added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.1</option></entry>
|
|
<entry>06 Jan 2002</entry>
|
|
<entry>Bugfixes, material and scripts added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.2</option></entry>
|
|
<entry>31 Mar 2002</entry>
|
|
<entry>Bugfixes, material and scripts added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.3</option></entry>
|
|
<entry>02 Jun 2002</entry>
|
|
<entry>TANGERINE release: A few bugfixes, much more material and
|
|
scripts added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.4</option></entry>
|
|
<entry>16 Jun 2002</entry>
|
|
<entry>MANGO release: A number of typos fixed, more
|
|
material and scripts.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.5</option></entry>
|
|
<entry>13 Jul 2002</entry>
|
|
<entry>PAPAYA release: A few bugfixes, much more material and
|
|
scripts added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.6</option></entry>
|
|
<entry>29 Sep 2002</entry>
|
|
<entry>POMEGRANATE release: Bugfixes, more material,
|
|
one more script.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.7</option></entry>
|
|
<entry>05 Jan 2003</entry>
|
|
<entry>COCONUT release: A couple of bugfixes, more material,
|
|
one more script.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.8</option></entry>
|
|
<entry>10 May 2003</entry>
|
|
<entry>BREADFRUIT release: A number of bugfixes, more scripts and
|
|
material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>1.9</option></entry>
|
|
<entry>21 Jun 2003</entry>
|
|
<entry>PERSIMMON release: Bugfixes, and more material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.0</option></entry>
|
|
<entry>24 Aug 2003</entry>
|
|
<entry>GOOSEBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.1</option></entry>
|
|
<entry>14 Sep 2003</entry>
|
|
<entry>HUCKLEBERRY release: Bugfixes, and more material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.2</option></entry>
|
|
<entry>31 Oct 2003</entry>
|
|
<entry>CRANBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.3</option></entry>
|
|
<entry>03 Jan 2004</entry>
|
|
<entry>STRAWBERRY release: Bugfixes and more material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.4</option></entry>
|
|
<entry>25 Jan 2004</entry>
|
|
<entry>MUSKMELON release: Bugfixes.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.5</option></entry>
|
|
<entry>15 Feb 2004</entry>
|
|
<entry>STARFRUIT release: Bugfixes and more material.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.6</option></entry>
|
|
<entry>15 Mar 2004</entry>
|
|
<entry>SALAL release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.7</option></entry>
|
|
<entry>18 Apr 2004</entry>
|
|
<entry>MULBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>2.8</option></entry>
|
|
<entry>11 Jul 2004</entry>
|
|
<entry>ELDERBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.0</option></entry>
|
|
<entry>03 Oct 2004</entry>
|
|
<entry>LOGANBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.1</option></entry>
|
|
<entry>14 Nov 2004</entry>
|
|
<entry>BAYBERRY release: Bugfix update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.2</option></entry>
|
|
<entry>06 Feb 2005</entry>
|
|
<entry>BLUEBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.3</option></entry>
|
|
<entry>20 Mar 2005</entry>
|
|
<entry>RASPBERRY release: Bugfixes, much material added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.4</option></entry>
|
|
<entry>08 May 2005</entry>
|
|
<entry>TEABERRY release: Bugfixes, stylistic revisions.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.5</option></entry>
|
|
<entry>05 Jun 2005</entry>
|
|
<entry>BOXBERRY release: Bugfixes, some material added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.6</option></entry>
|
|
<entry>28 Aug 2005</entry>
|
|
<entry>POKEBERRY release: Bugfixes, some material added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.7</option></entry>
|
|
<entry>23 Oct 2005</entry>
|
|
<entry>WHORTLEBERRY release: Bugfixes, some material added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.8</option></entry>
|
|
<entry>26 Feb 2006</entry>
|
|
<entry>BLAEBERRY release: Bugfixes, some material added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>3.9</option></entry>
|
|
<entry>15 May 2006</entry>
|
|
<entry>SPICEBERRY release: Bugfixes, some material added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>4.0</option></entry>
|
|
<entry>18 Jun 2006</entry>
|
|
<entry>WINTERBERRY release: Major reorganization.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>4.1</option></entry>
|
|
<entry>08 Oct 2006</entry>
|
|
<entry>WAXBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>4.2</option></entry>
|
|
<entry>10 Dec 2006</entry>
|
|
<entry>SPARKLEBERRY release: Important update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>4.3</option></entry>
|
|
<entry>29 Apr 2007</entry>
|
|
<entry>INKBERRY release: Bugfixes, material added.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>5.0</option></entry>
|
|
<entry>24 Jun 2007</entry>
|
|
<entry>SERVICEBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>5.1</option></entry>
|
|
<entry>10 Nov 2007</entry>
|
|
<entry>LINGONBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>5.2</option></entry>
|
|
<entry>16 Mar 2008</entry>
|
|
<entry>SILVERBERRY release: Important update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>5.3</option></entry>
|
|
<entry>11 May 2008</entry>
|
|
<entry>GOLDENBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>5.4</option></entry>
|
|
<entry>21 Jul 2008</entry>
|
|
<entry>ANGLEBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>5.5</option></entry>
|
|
<entry>23 Nov 2008</entry>
|
|
<entry>FARKLEBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>5.6</option></entry>
|
|
<entry>26 Jan 2009</entry>
|
|
<entry>WORCESTERBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>6.0</option></entry>
|
|
<entry>23 Mar 2009</entry>
|
|
<entry>THIMBLEBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>6.1</option></entry>
|
|
<entry>30 Sep 2009</entry>
|
|
<entry>BUFFALOBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>6.2</option></entry>
|
|
<entry>17 Mar 2010</entry>
|
|
<entry>ROWANBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>6.3</option></entry>
|
|
<entry>30 Apr 2011</entry>
|
|
<entry>SWOZZLEBERRY release: Major update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>6.4</option></entry>
|
|
<entry>30 Aug 2011</entry>
|
|
<entry>VORTEXBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>6.5</option></entry>
|
|
<entry>05 Apr 2012</entry>
|
|
<entry>TUNGSTENBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>6.6</option></entry>
|
|
<entry>27 Nov 2012</entry>
|
|
<entry>YTTERBIUMBERRY release: Minor update.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><option>10</option></entry>
|
|
<entry>10 Mar 2014</entry>
|
|
<entry>YTTERBIUMBERRY release: License change.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
|
|
</appendix> <!-- End Revision History appendix -->
|
|
|
|
<appendix id="mirrorsites">
|
|
<title>Download and Mirror Sites</title>
|
|
|
|
<para><anchor id="where_tarball"/></para>
|
|
|
|
<para>The latest update of this document, as an archived,
|
|
<link linkend="bzipref">bzip2-ed</link>
|
|
<quote>tarball</quote> including both the SGML source
|
|
and rendered HTML, may be downloaded from the <ulink
|
|
url="http://bash.deta.in/abs-guide-latest.tar.bz2">author's
|
|
home site</ulink>).
|
|
|
|
A <ulink
|
|
url="http://bash.deta.in/abs-guide.pdf">
|
|
pdf version</ulink> is also available (<ulink
|
|
url="http://www.mediafire.com/file/xi34ape1bifcnlb/abs-guide.pdf">mirror
|
|
site</ulink>).
|
|
There is likewise an <ulink
|
|
url="http://bash.deta.in/abs-guide.epub">
|
|
epub version</ulink>, courtesy of Craig Barnes and Michael Satke.
|
|
|
|
The <ulink
|
|
url="http://bash.deta.in/Change.log">change
|
|
log</ulink> gives a detailed revision history.
|
|
The <emphasis>ABS Guide</emphasis> even has <ulink
|
|
url="http://freecode.com/projects/advancedbashscriptingguide/">
|
|
its own <filename>freshmeat.net/freecode</filename> page</ulink>
|
|
to keep track of major updates, user comments, and popularity
|
|
ratings for the project.</para>
|
|
|
|
<para>The legacy hosting 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>Many thanks to Ronny Bangsund for donating <ulink
|
|
url="http://bash.deta.in/">server space</ulink> to host
|
|
this project.</para>
|
|
|
|
|
|
</appendix> <!-- Mirror Sites appendix -->
|
|
|
|
|
|
|
|
<appendix id="todolist">
|
|
<title>To Do List</title>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>A comprehensive survey of <link
|
|
linkend="bashcompat">incompatibilities</link> between
|
|
Bash and the classic <link linkend="bashdef">Bourne
|
|
shell</link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Same as above, but for the Korn shell
|
|
(<firstterm>ksh</firstterm>).</para>
|
|
</listitem>
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
</appendix> <!-- End Todo List appendix -->
|
|
|
|
|
|
<appendix id="copyright">
|
|
<title>Copyright</title>
|
|
|
|
<para>The <citetitle pubwork="book">Advanced Bash Scripting
|
|
Guide</citetitle> is herewith granted to the PUBLIC DOMAIN.
|
|
This has the following implications and consequences.
|
|
</para>
|
|
|
|
|
|
<para><programlisting>
|
|
A. All previous releases of the Advanced Bash Scripting Guide
|
|
are as well granted to the Public Domain.
|
|
|
|
A1. All printed editions, whether authorized by the author or not,
|
|
are as well granted to the Public Domain. This legally overrides
|
|
any stated intention or wishes of the publishers. Any statement
|
|
of copyright is void and invalid.
|
|
THERE ARE NO EXCEPTIONS TO THIS.
|
|
|
|
A2. Any release of the Advanced Bash Scripting Guide, whether in
|
|
electronic or print form is granted to the Public Domain by the
|
|
express directive of the author and previous copyright holder, Mendel
|
|
Cooper. No other person(s) or entities have ever held a valid copyright.
|
|
|
|
B. As a Public Domain document, unlimited copying and distribution rights
|
|
are granted. There can be NO restrictions. If anyone has published or will
|
|
in the future publish an original or modified version of this document,
|
|
then only additional original material may be copyrighted. The core
|
|
work will remain in the Public Domain.</programlisting></para>
|
|
|
|
<para>By law, distributors and publishers (including on-line
|
|
publishers) are prohibited from imposing any conditions,
|
|
strictures, or provisions on this document, any previous versions,
|
|
or any derivative versions. The author asserts
|
|
that he has <emphasis>not</emphasis> entered into any contractual
|
|
obligations that would alter the foregoing declarations.</para>
|
|
|
|
<para>Essentially, you may freely distribute this book or any
|
|
derivative thereof in electronic or printed form. If you have previously
|
|
purchased or are in possession of a printed copy of a current or
|
|
previous edition, you have the LEGAL RIGHT to copy and/or redistribute
|
|
it, regardless of any copyright notice. Any copyright notice is
|
|
void.</para>
|
|
|
|
|
|
<para><emphasis>Additionally, the author wishes to state his intention
|
|
that:</emphasis></para>
|
|
|
|
<para><programlisting>If you copy or distribute this book, kindly DO NOT
|
|
use the materials within, or any portion thereof, in a patent or copyright
|
|
lawsuit against the Open Source community, its developers, its
|
|
distributors, or against any of its associated software or documentation
|
|
including, but not limited to, the Linux kernel, Open Office, Samba,
|
|
and Wine. Kindly DO NOT use any of the materials within
|
|
this book in testimony or depositions as a plaintiff's "expert witness" in
|
|
any lawsuit against the Open Source community, any of its developers, its
|
|
distributors, or any of its associated software or documentation.
|
|
</programlisting></para>
|
|
|
|
|
|
<para>A Public Domain license essentially does not restrict ANY
|
|
legitimate distribution or use of this book. The author especially
|
|
encourages its (royalty-free!) use for classroom and instructional
|
|
purposes.</para>
|
|
|
|
<para>
|
|
To date, limited print rights (Lulu edition) have been granted
|
|
to one individual and to <emphasis>no one else</emphasis>. Neither
|
|
that individual nor Lulu holds or ever has held a valid copyright.</para>
|
|
|
|
<warning><para>It has come to the attention of the author that
|
|
<emphasis>unauthorized</emphasis> electronic and print
|
|
editions of this book are being sold commercially on <trademark
|
|
class="registered">itunes</trademark>, <emphasis>amazon.com</emphasis>
|
|
and elsewhere. These are illegal and pirated editions produced
|
|
without the author's permission, and readers of this book are
|
|
strongly urged not to purchase them. In fact, these pirated editions are
|
|
now legal, but necessarily fall into the Public Domain, and any
|
|
copyright notices contained within them are invalid and void.</para></warning>
|
|
|
|
<para>The author produced this book in a manner consistent with the
|
|
spirit of the <ulink url="http://www.tldp.org/manifesto.html">LDP
|
|
Manifesto</ulink>.</para>
|
|
|
|
|
|
<sidebar>
|
|
<para>Linux is a trademark registered to Linus Torvalds.</para>
|
|
<para>Fedora is a trademark registered to Red Hat.</para>
|
|
<para>Unix and UNIX are trademarks registered to the Open Group.</para>
|
|
<para>MS Windows is a trademark registered to the Microsoft Corp.</para>
|
|
<para>Solaris is a trademark registered to Oracle, Inc.</para>
|
|
<para>OSX is a trademark registered to Apple, Inc.</para>
|
|
<para>Yahoo is a trademark registered to Yahoo, Inc.</para>
|
|
<para>Pentium is a trademark registered to Intel, Inc.</para>
|
|
<para>Thinkpad is a trademark registered to Lenovo, Inc.</para>
|
|
<para>Scrabble is a trademark registered to Hasbro, Inc.</para>
|
|
<para>Librie, PRS-500, and PRS-505 are trademarks registered to
|
|
Sony, Inc.</para>
|
|
<para>All other commercial trademarks mentioned in the body of this work
|
|
are registered to their respective owners.</para>
|
|
</sidebar>
|
|
|
|
|
|
<para>Hyun Jin Cha has done a <ulink
|
|
url="http://kldp.org/HOWTO/html/Adv-Bash-Scr-HOWTO/index.html">Korean
|
|
translation</ulink> of version 1.0.11 of this book. Spanish,
|
|
Portuguese, <ulink
|
|
url="http://abs.traduc.org/">French</ulink>, German, <ulink
|
|
url="http://it.tldp.org/guide/abs/index.html">Italian</ulink>,
|
|
<ulink
|
|
url="http://gazette.linux.ru.net/rus/articles/index-abs-guide.html">Russian</ulink>,
|
|
<ulink url="http://premekvihan.net/bash">Czech</ulink>, <ulink
|
|
url="http://www.linuxsir.org/bbs/showthread.php?t=256887">Chinese</ulink>,
|
|
Indonesian, Dutch, Romanian, Bulgarian, and Turkish 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>
|
|
|
|
<sidebar><para>Those generous readers desiring to
|
|
make a donation to the author may contribute a small
|
|
amount via Paypal to my e-mail address,
|
|
<email>thegrendel.abs@gmail.com</email>.
|
|
(An <userinput>Honor Roll of Supporters</userinput>
|
|
is given at the beginning of the <ulink
|
|
url="http://bash.deta.in/Change.log">Change Log</ulink>.)
|
|
This is <emphasis>not</emphasis> a requirement.
|
|
The <firstterm>ABS Guide</firstterm> is a free and freely
|
|
distributed document for the use and enjoyment of the Linux
|
|
community. However, in these difficult times, showing support
|
|
for voluntary projects and especially to authors of limited
|
|
means is more critically important than ever.</para></sidebar>
|
|
|
|
|
|
</appendix> <!-- End Copyright appendix -->
|
|
|
|
<appendix id="asciitable">
|
|
<title>ASCII Table</title>
|
|
|
|
|
|
<para>Traditionally, a book of this sort has an <link
|
|
linkend="asciidef">ASCII</link> Table appendix.
|
|
This book does not. Instead, here are several short
|
|
scripts, each of which generates a complete ASCII table.</para>
|
|
|
|
<example id="asciish">
|
|
<title>A script that generates an ASCII table</title>
|
|
<programlisting>&asciish;</programlisting>
|
|
</example>
|
|
|
|
<example id="ascii2sh">
|
|
<title>Another ASCII table script</title>
|
|
<programlisting>&ascii2sh;</programlisting>
|
|
</example>
|
|
|
|
<example id="ascii3sh">
|
|
<title>A third ASCII table script, using
|
|
<firstterm>awk</firstterm></title>
|
|
<programlisting>&ascii3sh;</programlisting>
|
|
</example>
|
|
|
|
</appendix> <!-- End ASCII Table appendix -->
|
|
|
|
|
|
|
|
<index id="xrefindex"> <!-- Begin Index -->
|
|
|
|
&INDEX00;
|
|
|
|
</index> <!-- End Index -->
|
|
|
|
|
|
|
|
</book>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: xml
|
|
sgml-indent-step:2
|
|
sgml-indent-data:t
|
|
End:
|
|
-->
|