mirror of https://github.com/tLDP/LDP
17253 lines
552 KiB
Plaintext
17253 lines
552 KiB
Plaintext
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
|
|||
|
<!--
|
|||
|
Uncomment line below to generate index.
|
|||
|
-->
|
|||
|
<!ENTITY doc-index SYSTEM "index.sgml">
|
|||
|
<!ENTITY ex1 SYSTEM "ex1.sh">
|
|||
|
<!ENTITY ex2 SYSTEM "ex2.sh">
|
|||
|
<!ENTITY ex3 SYSTEM "ex3.sh">
|
|||
|
<!ENTITY ex4 SYSTEM "ex4.sh">
|
|||
|
<!ENTITY ex5 SYSTEM "ex5.sh">
|
|||
|
<!ENTITY ex6 SYSTEM "ex6.sh">
|
|||
|
<!ENTITY ex7 SYSTEM "ex7.sh">
|
|||
|
<!ENTITY ex8 SYSTEM "ex8.sh">
|
|||
|
<!ENTITY ex9 SYSTEM "ex9.sh">
|
|||
|
<!ENTITY ex10 SYSTEM "ex10.sh">
|
|||
|
<!ENTITY ex11 SYSTEM "ex11.sh">
|
|||
|
<!ENTITY ex12 SYSTEM "ex12.sh">
|
|||
|
<!ENTITY ex13 SYSTEM "ex13.sh">
|
|||
|
<!ENTITY ex14 SYSTEM "ex14.sh">
|
|||
|
<!ENTITY ex15 SYSTEM "ex15.sh">
|
|||
|
<!ENTITY ex16 SYSTEM "ex16.sh">
|
|||
|
<!ENTITY ex17 SYSTEM "ex17.sh">
|
|||
|
<!ENTITY ex18 SYSTEM "ex18.sh">
|
|||
|
<!ENTITY ex19 SYSTEM "ex19.sh">
|
|||
|
<!ENTITY ex20 SYSTEM "ex20.sh">
|
|||
|
<!ENTITY ex21 SYSTEM "ex21.sh">
|
|||
|
<!ENTITY ex22 SYSTEM "ex22.sh">
|
|||
|
<!ENTITY ex22a SYSTEM "ex22a.sh">
|
|||
|
<!ENTITY ex23 SYSTEM "ex23.sh">
|
|||
|
<!ENTITY ex24 SYSTEM "ex24.sh">
|
|||
|
<!ENTITY ex25 SYSTEM "ex25.sh">
|
|||
|
<!ENTITY ex26 SYSTEM "ex26.sh">
|
|||
|
<!ENTITY ex26a SYSTEM "ex26a.sh">
|
|||
|
<!ENTITY ex27 SYSTEM "ex27.sh">
|
|||
|
<!ENTITY ex28 SYSTEM "ex28.sh">
|
|||
|
<!ENTITY ex29 SYSTEM "ex29.sh">
|
|||
|
<!ENTITY ex30 SYSTEM "ex30.sh">
|
|||
|
<!ENTITY ex31 SYSTEM "ex31.sh">
|
|||
|
<!ENTITY ex32 SYSTEM "ex32.sh">
|
|||
|
<!ENTITY ex33 SYSTEM "ex33.sh">
|
|||
|
<!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 ex46 SYSTEM "ex46.sh">
|
|||
|
<!ENTITY ex47 SYSTEM "ex47.sh">
|
|||
|
<!ENTITY ex48 SYSTEM "ex48.sh">
|
|||
|
<!ENTITY ex49 SYSTEM "ex49.sh">
|
|||
|
<!ENTITY ex50 SYSTEM "ex50.sh">
|
|||
|
<!ENTITY ex51 SYSTEM "ex51.sh">
|
|||
|
<!ENTITY ex52 SYSTEM "ex52.sh">
|
|||
|
<!ENTITY ex53 SYSTEM "ex53.sh">
|
|||
|
<!ENTITY ex54 SYSTEM "ex54.sh">
|
|||
|
<!ENTITY ex55 SYSTEM "ex55.sh">
|
|||
|
<!ENTITY ex56 SYSTEM "ex56.sh">
|
|||
|
<!ENTITY ex57 SYSTEM "ex57.sh">
|
|||
|
<!ENTITY ex58 SYSTEM "ex58.sh">
|
|||
|
<!ENTITY ex59 SYSTEM "ex59.sh">
|
|||
|
<!ENTITY ex60 SYSTEM "ex60.sh">
|
|||
|
<!ENTITY ex61 SYSTEM "ex61.sh">
|
|||
|
<!ENTITY ex62 SYSTEM "ex62.sh">
|
|||
|
<!ENTITY ex63 SYSTEM "ex63.sh">
|
|||
|
<!ENTITY ex64 SYSTEM "ex64.sh">
|
|||
|
<!ENTITY ex65 SYSTEM "ex65.sh">
|
|||
|
<!ENTITY ex66 SYSTEM "ex66.sh">
|
|||
|
<!ENTITY ex67 SYSTEM "ex67.sh">
|
|||
|
<!ENTITY ex68 SYSTEM "ex68.sh">
|
|||
|
<!ENTITY ex69 SYSTEM "ex69.sh">
|
|||
|
<!ENTITY ex70 SYSTEM "ex70.sh">
|
|||
|
<!ENTITY ex71 SYSTEM "ex71.sh">
|
|||
|
<!ENTITY ex71a SYSTEM "ex71a.sh">
|
|||
|
<!ENTITY ex71b SYSTEM "ex71b.sh">
|
|||
|
<!ENTITY ex71c SYSTEM "ex71c.sh">
|
|||
|
<!ENTITY ex72 SYSTEM "ex72.sh">
|
|||
|
<!ENTITY ex73 SYSTEM "ex73.sh">
|
|||
|
<!ENTITY ex74 SYSTEM "ex74.sh">
|
|||
|
<!ENTITY ex75 SYSTEM "ex75.sh">
|
|||
|
<!ENTITY ex76 SYSTEM "ex76.sh">
|
|||
|
<!ENTITY ex77 SYSTEM "ex77.sh">
|
|||
|
<!ENTITY ex78 SYSTEM "ex78.sh">
|
|||
|
<!ENTITY ex79 SYSTEM "ex79.sh">
|
|||
|
<!ENTITY andor SYSTEM "and-or.sh">
|
|||
|
<!ENTITY lnum SYSTEM "line-number.sh">
|
|||
|
<!ENTITY manview SYSTEM "manview.sh">
|
|||
|
<!ENTITY rfe SYSTEM "rfe.sh">
|
|||
|
<!ENTITY behead SYSTEM "behead.sh">
|
|||
|
<!ENTITY ftpget SYSTEM "ftpget.sh">
|
|||
|
<!ENTITY encryptedpw SYSTEM "encryptedpw.sh">
|
|||
|
<!ENTITY rpmcheck SYSTEM "rpm-check.sh">
|
|||
|
<!ENTITY subshell SYSTEM "subshell.sh">
|
|||
|
<!ENTITY lowercase SYSTEM "lowercase.sh">
|
|||
|
<!ENTITY online SYSTEM "online.sh">
|
|||
|
<!ENTITY reply SYSTEM "reply.sh">
|
|||
|
<!ENTITY seconds SYSTEM "seconds.sh">
|
|||
|
<!ENTITY numbers SYSTEM "numbers.sh">
|
|||
|
<!ENTITY indref SYSTEM "ind-ref.sh">
|
|||
|
<!ENTITY bubble SYSTEM "bubble.sh">
|
|||
|
<!ENTITY paramsub SYSTEM "param-sub.sh">
|
|||
|
<!ENTITY restricted SYSTEM "restricted.sh">
|
|||
|
<!ENTITY pw SYSTEM "pw.sh">
|
|||
|
<!ENTITY rn SYSTEM "rn.sh">
|
|||
|
<!ENTITY coltotaler SYSTEM "col-totaler.sh">
|
|||
|
<!ENTITY coltotaler2 SYSTEM "col-totaler2.sh">
|
|||
|
<!ENTITY coltotaler3 SYSTEM "col-totaler3.sh">
|
|||
|
<!ENTITY tmdin SYSTEM "timed-input.sh">
|
|||
|
<!ENTITY fifo SYSTEM "fifo.sh">
|
|||
|
<!ENTITY tree SYSTEM "tree.sh">
|
|||
|
<!ENTITY secretpw SYSTEM "secret-pw.sh">
|
|||
|
<!ENTITY stripc SYSTEM "strip-comments.sh">
|
|||
|
<!ENTITY al SYSTEM "alias.sh">
|
|||
|
<!ENTITY unal SYSTEM "unalias.sh">
|
|||
|
<!ENTITY redir1 SYSTEM "redir1.sh">
|
|||
|
<!ENTITY redir2 SYSTEM "redir2.sh">
|
|||
|
<!ENTITY redir2a SYSTEM "redir2a.sh">
|
|||
|
<!ENTITY redir3 SYSTEM "redir3.sh">
|
|||
|
<!ENTITY redir4 SYSTEM "redir4.sh">
|
|||
|
<!ENTITY redir5 SYSTEM "redir5.sh">
|
|||
|
<!ENTITY wipedir SYSTEM "wipedir.sh">
|
|||
|
<!ENTITY grp SYSTEM "grp.sh">
|
|||
|
<!ENTITY killprocess SYSTEM "kill-process.sh">
|
|||
|
<!ENTITY strtest SYSTEM "str-test.sh">
|
|||
|
<!ENTITY col SYSTEM "col.sh">
|
|||
|
<!ENTITY lookup SYSTEM "lookup.sh">
|
|||
|
<!ENTITY arglist SYSTEM "arglist.sh">
|
|||
|
<!ENTITY rot13 SYSTEM "rot13.sh">
|
|||
|
<!ENTITY rot13_2 SYSTEM "rot13_2.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 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 findstring SYSTEM "findstring.sh">
|
|||
|
<!ENTITY listglob SYSTEM "list-glob.sh">
|
|||
|
<!ENTITY realname SYSTEM "realname.sh">
|
|||
|
<!ENTITY escaped SYSTEM "escaped.sh">
|
|||
|
<!ENTITY fileinfo SYSTEM "file-info.sh">
|
|||
|
<!ENTITY weirdvars SYSTEM "weirdvars.sh">
|
|||
|
<!ENTITY breaklevels SYSTEM "break-levels.sh">
|
|||
|
<!ENTITY copycd SYSTEM "copy-cd.sh">
|
|||
|
<!ENTITY arithops SYSTEM "arith-ops.sh">
|
|||
|
<!ENTITY continuelevels SYSTEM "continue-nlevel.sh">
|
|||
|
<!ENTITY timeout SYSTEM "timeout.sh">
|
|||
|
<!ENTITY randomtest SYSTEM "random-test.sh">
|
|||
|
<!ENTITY seedingrandom SYSTEM "seeding-random.sh">
|
|||
|
<!ENTITY pattmatching SYSTEM "patt-matching.sh">
|
|||
|
<!ENTITY isalpha SYSTEM "isalpha.sh">
|
|||
|
<!ENTITY rnd SYSTEM "rnd.sh">
|
|||
|
<!ENTITY du SYSTEM "du.sh">
|
|||
|
<!ENTITY refparams SYSTEM "ref-params.sh">
|
|||
|
<!ENTITY primes SYSTEM "primes.sh">
|
|||
|
<!ENTITY vartrace SYSTEM "vartrace.sh">
|
|||
|
<!ENTITY amiroot SYSTEM "am-i-root.sh">
|
|||
|
<!ENTITY twodim SYSTEM "twodim.sh">
|
|||
|
<!ENTITY arithtests SYSTEM "arith-tests.sh">
|
|||
|
<!ENTITY incompat SYSTEM "incompat.sh">
|
|||
|
<!ENTITY ifsh SYSTEM "ifs.sh">
|
|||
|
<!ENTITY ifsempty SYSTEM "ifs-empty.sh">
|
|||
|
<!ENTITY logevents SYSTEM "logevents.sh">
|
|||
|
<!ENTITY keypress SYSTEM "keypress.sh">
|
|||
|
<!ENTITY ddkeypress SYSTEM "dd-keypress.sh">
|
|||
|
<!ENTITY objoriented SYSTEM "obj-oriented.sh">
|
|||
|
<!ENTITY emptyarray SYSTEM "empty-array.sh">
|
|||
|
<!ENTITY length SYSTEM "length.sh">
|
|||
|
<!ENTITY monthlypmt SYSTEM "monthlypmt.sh">
|
|||
|
<!ENTITY bashrc SYSTEM "bashrc">
|
|||
|
]>
|
|||
|
|
|||
|
<book>
|
|||
|
<bookinfo>
|
|||
|
<title>Advanced Bash-Scripting Guide</title>
|
|||
|
<subtitle>A complete guide to shell scripting, using Bash</subtitle>
|
|||
|
|
|||
|
|
|||
|
<author>
|
|||
|
<firstname>Mendel</firstname>
|
|||
|
<surname>Cooper</surname>
|
|||
|
<affiliation>
|
|||
|
<orgname>Brindlesoft</orgname>
|
|||
|
<address><email>thegrendel@theriver.com</email></address>
|
|||
|
</affiliation>
|
|||
|
</author>
|
|||
|
|
|||
|
|
|||
|
<pubdate>v0.4, 08 July 2001</pubdate>
|
|||
|
|
|||
|
|
|||
|
<revhistory>
|
|||
|
<revision>
|
|||
|
<revnumber>0.4</revnumber>
|
|||
|
<date>08 July 2001</date>
|
|||
|
<authorinitials>mc</authorinitials>
|
|||
|
<revremark>More bugfixes, much more material, more
|
|||
|
scripts - a complete revision and expansion of the book</revremark>
|
|||
|
</revision>
|
|||
|
|
|||
|
<revision>
|
|||
|
<revnumber>0.3</revnumber>
|
|||
|
<date>12 February 2001</date>
|
|||
|
<authorinitials>mc</authorinitials>
|
|||
|
<revremark>Another major update.</revremark>
|
|||
|
</revision>
|
|||
|
|
|||
|
<revision>
|
|||
|
<revnumber>0.2</revnumber>
|
|||
|
<date>30 October 2000</date>
|
|||
|
<authorinitials>mc</authorinitials>
|
|||
|
<revremark>Bugs fixed, plus much additional material and more example
|
|||
|
scripts.</revremark>
|
|||
|
</revision>
|
|||
|
|
|||
|
<revision>
|
|||
|
<revnumber>0.1</revnumber>
|
|||
|
<date>14 June 2000</date>
|
|||
|
<authorinitials>mc</authorinitials>
|
|||
|
<revremark>Initial release.</revremark>
|
|||
|
</revision>
|
|||
|
|
|||
|
</revhistory>
|
|||
|
|
|||
|
|
|||
|
<abstract>
|
|||
|
|
|||
|
<para>This document is both a tutorial and a reference on shell
|
|||
|
scripting with Bash. It assumes no previous knowledge of
|
|||
|
scripting or programming, but progresses rapidly toward an
|
|||
|
intermediate/advanced level of instruction.
|
|||
|
|
|||
|
<footnote><para>...all the while sneaking in little snippets of UNIX
|
|||
|
wisdom and lore.</para></footnote>
|
|||
|
|
|||
|
The exercises and heavily-commented examples invite active reader
|
|||
|
participation. Still, it is a work in progress. The intention
|
|||
|
is to add much supplementary material in future updates to this
|
|||
|
document, as it evolves into a comprehensive book that matches
|
|||
|
or surpasses any of the shell scripting manuals in print.</para>
|
|||
|
|
|||
|
<para>The latest version of this document, as an archived
|
|||
|
<quote>tarball</quote> including both the SGML
|
|||
|
source and rendered HTML, may be downloaded from <ulink
|
|||
|
url="http://personal.riverusers.com/~thegrendel/abs-HOWTO-0.4.tar.gz">
|
|||
|
the author's home site</ulink>.</para>
|
|||
|
|
|||
|
<para>This is a major update on version 0.3. -- more bugs swatted,
|
|||
|
plus much additional material and example scripts added.
|
|||
|
This project has now reached the equivalent of a 300-page book.
|
|||
|
See <filename>NEWS</filename> for a revision history.</para>
|
|||
|
|
|||
|
</abstract>
|
|||
|
</bookinfo>
|
|||
|
|
|||
|
<chapter id="why-shell">
|
|||
|
<title>Why Shell Programming?</title>
|
|||
|
|
|||
|
<para>The shell is a command interpreter. It is the insulating layer between
|
|||
|
the operating system kernel and the user. Yet, it is also a fairly
|
|||
|
powerful programming language. A shell program, called a
|
|||
|
<firstterm>
|
|||
|
<indexterm>
|
|||
|
<primary>script</primary>
|
|||
|
</indexterm>
|
|||
|
script
|
|||
|
</firstterm>,
|
|||
|
is an easy-to-use tool for building applications by <quote>gluing</quote> together
|
|||
|
system calls, tools, utilities, and compiled binaries. Virtually the
|
|||
|
entire repertoire of UNIX commands, utilities, and tools is available for
|
|||
|
invocation by a shell script. If that were not enough, internal shell
|
|||
|
commands, such as testing and loop constructs, give additional power
|
|||
|
and flexibility to scripts. Shell scripts lend themselves exceptionally
|
|||
|
well to to administrative system tasks and other routine repetitive jobs
|
|||
|
not requiring the bells and whistles of a full-blown tightly structured
|
|||
|
programming language.</para>
|
|||
|
|
|||
|
<para>A working knowledge of shell scripting is essential to everyone wishing
|
|||
|
to become reasonably adept at system administration, even if they
|
|||
|
do not anticipate ever having to actually write a script. Consider
|
|||
|
that as a Linux machine boots up, it executes the shell scripts in
|
|||
|
<filename class="directory">/etc/rc.d</filename> to restore the
|
|||
|
system configuration and set up services. A detailed understanding
|
|||
|
of these scripts is important for analyzing the behavior of a
|
|||
|
system, and possibly modifying it.</para>
|
|||
|
|
|||
|
<para>Writing shell scripts is not hard to learn, since the scripts
|
|||
|
can be built in bite-sized sections and there is only a fairly
|
|||
|
small set of shell-specific operators and options
|
|||
|
|
|||
|
<footnote><para>These are referred to as <link
|
|||
|
linkend="builtinref">builtins</link>, features internal to the
|
|||
|
shell.</para></footnote>
|
|||
|
|
|||
|
to learn. The syntax is simple and straightforward, similar to
|
|||
|
that of invoking and chaining together utilities at the command
|
|||
|
line, and there are only a few <quote>rules</quote> to learn.
|
|||
|
Most short scripts work right the first time, and debugging even
|
|||
|
the longer ones is straightforward.</para>
|
|||
|
|
|||
|
<para>A shell script is a <quote>quick and dirty</quote> method of
|
|||
|
prototyping a complex application. Getting even a limited subset
|
|||
|
of the functionality to work in a shell script, even if slowly,
|
|||
|
is often a useful first stage in project development. This way,
|
|||
|
the structure of the application can be tested and played with,
|
|||
|
and the major pitfalls found before proceeding to the final coding
|
|||
|
in C, C++, Java, or Perl.</para>
|
|||
|
|
|||
|
<para>Shell scripting hearkens back to the classical UNIX philosophy
|
|||
|
of breaking complex projects into simpler subtasks, of chaining
|
|||
|
together components and utilities. Many consider this a better,
|
|||
|
or at least more esthetically pleasing approach to problem solving
|
|||
|
than using one of the new generation of high powered all-in-one
|
|||
|
languages, such as Perl, which attempt to be all things to all
|
|||
|
people, but at the cost of forcing you to alter your thinking
|
|||
|
processes to fit the tool.</para>
|
|||
|
|
|||
|
<para>When not to use shell scripts
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
<listitem>
|
|||
|
<para>resource-intensive tasks, especially where speed is
|
|||
|
a factor (sorting, hashing, etc.)</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>procedures involving heavy-duty math operations,
|
|||
|
especially arbitrary precision calculations or complex numbers
|
|||
|
(use C++ or FORTRAN instead)</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>cross-platform portability required (use C instead)</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>complex applications, where structured programming is
|
|||
|
a necessity (need typechecking of variables, function
|
|||
|
prototypes, etc.)</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>mission-critical applications upon which you are betting the
|
|||
|
ranch, or the future of the company</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>situations where security is important, where you need to
|
|||
|
protect against hacking</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>project consists of subcomponents with interlocking
|
|||
|
dependencies</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>extensive file operations required (Bash is limited to
|
|||
|
serial file access, and that only in a particularly clumsy
|
|||
|
and inefficient line-by-line fashion)</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>need multi-dimensional arrays</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>need to generate or manipulate graphics or GUIs</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>need direct access to system hardware</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>need port or socket I/O</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>need to use libraries or interface with legacy code</para>
|
|||
|
</listitem> <listitem>
|
|||
|
<para>proprietary, closed-source applications (shell scripts are
|
|||
|
necessarily Open Source)</para>
|
|||
|
</listitem>
|
|||
|
</itemizedlist></para>
|
|||
|
|
|||
|
<para>If any of the above applies, consider a more powerful scripting
|
|||
|
language, perhaps Perl, Tcl, Python, or possibly a high-level
|
|||
|
compiled language such as C, C++, or Java. Even then, prototyping
|
|||
|
the application as a shell script might still be a useful
|
|||
|
development step.</para>
|
|||
|
|
|||
|
<para>We will be using Bash, an acronym for <quote>Bourne-Again
|
|||
|
Shell</quote> and a pun on Stephen Bourne's now classic Bourne
|
|||
|
Shell. Bash has become a <foreignphrase>de facto</foreignphrase>
|
|||
|
standard for shell scripting on all flavors of UNIX. Most of
|
|||
|
the principles dealt with in this document apply equally well to
|
|||
|
scripting with other shells, such as the Korn Shell, from which
|
|||
|
Bash derives some of its features,
|
|||
|
|
|||
|
<footnote><para>Many of the features of <emphasis>ksh88</emphasis>,
|
|||
|
and even a few from the updated <emphasis>ksh93</emphasis>
|
|||
|
have been merged into Bash.</para></footnote>
|
|||
|
|
|||
|
and the C Shell and its variants. (Note that C Shell programming
|
|||
|
is not recommended due to certain inherent problems, as pointed
|
|||
|
out in a <ulink
|
|||
|
url="http://www.etext.org/Quartz/computer/unix/csh.harmful.gz">news
|
|||
|
group posting</ulink> by Tom Christiansen in October of 1993).
|
|||
|
</para>
|
|||
|
|
|||
|
<para>The following is a tutorial in shell scripting. It relies
|
|||
|
heavily on examples to illustrate features of the shell.
|
|||
|
As far as possible, the example scripts have been tested, and
|
|||
|
some of them may actually be useful in real life. The reader
|
|||
|
should use the actual examples in the the source archive
|
|||
|
(<filename>something-or-other.sh</filename>),
|
|||
|
|
|||
|
<footnote><para>By convention, user-written shell scripts that are
|
|||
|
Bourne shell compliant generally take a name with a
|
|||
|
<filename>.sh</filename> extension. System scripts, such as
|
|||
|
those found in <filename class="directory">/etc/rc.d</filename>,
|
|||
|
do not follow this guideline.</para></footnote>
|
|||
|
|
|||
|
give them execute permission (<userinput>chmod u+rx
|
|||
|
scriptname</userinput>), then run them to see what happens.
|
|||
|
Should the source archive not be available, then cut-and-paste from
|
|||
|
the HTML, pdf, or text rendered versions. Be aware that some of
|
|||
|
the scripts below introduce features before they are explained,
|
|||
|
and this may require the reader to temporarily skip ahead for
|
|||
|
enlightenment.</para>
|
|||
|
|
|||
|
<para>Unless otherwise noted, the author of this document wrote
|
|||
|
the example scripts that follow.</para>
|
|||
|
|
|||
|
</chapter> <!-- Why Shell Programming? -->
|
|||
|
|
|||
|
|
|||
|
<chapter id="sha-bang">
|
|||
|
<title>Starting Off With a Sha-Bang</title>
|
|||
|
|
|||
|
<para>In the simplest case, a script is nothing more than a list of system
|
|||
|
commands stored in a file. At the very least, this saves the
|
|||
|
effort of retyping that particular sequence of commands each time
|
|||
|
it is invoked.</para>
|
|||
|
|
|||
|
<example id="ex1">
|
|||
|
<title><command>cleanup</command>: A script to clean up the log
|
|||
|
files in /var/log </title> <programlisting>&ex1;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>There is nothing unusual here, just a set of commands that
|
|||
|
could just as easily be invoked one by one from the command line on
|
|||
|
the console or in an xterm. The advantages of placing the commands
|
|||
|
in a script go beyond not having to retype them time and again. The
|
|||
|
script can easily be modified, customized, or generalized for a
|
|||
|
particular application.</para>
|
|||
|
|
|||
|
<example id="ex2">
|
|||
|
<title><command>cleanup</command>: An enhanced
|
|||
|
and generalized version of above script.</title>
|
|||
|
<programlisting>&ex2;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Since you may not wish to wipe out the entire system log, this variant of
|
|||
|
the first script keeps the last section of the message log intact. You
|
|||
|
will constantly discover ways of refining previously written scripts
|
|||
|
for increased effectiveness.</para>
|
|||
|
|
|||
|
<para>The
|
|||
|
<firstterm><indexterm>
|
|||
|
<primary>sha-bang</primary>
|
|||
|
</indexterm>
|
|||
|
sha-bang</firstterm>
|
|||
|
(<token>
|
|||
|
<indexterm>
|
|||
|
<primary>#!</primary>
|
|||
|
</indexterm>
|
|||
|
#!</token>) at the head of a script
|
|||
|
tells your system that this file
|
|||
|
is a set of commands to be fed to the command interpreter indicated.
|
|||
|
<anchor id="magnumref">The <token>#!</token> is actually a two-byte
|
|||
|
|
|||
|
<footnote><para>Some flavors
|
|||
|
of UNIX take a four-byte magic number,
|
|||
|
requiring a blank after the <token>!</token>,
|
|||
|
<userinput>#! bin/sh</userinput>.</para></footnote>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>magic number</primary>
|
|||
|
</indexterm>
|
|||
|
<quote>magic number</quote>, a special marker that
|
|||
|
designates a file type, or in this case an executable
|
|||
|
shell script (see <userinput>man magic</userinput> for more
|
|||
|
details on this fascinating topic). Immediately following
|
|||
|
the <emphasis>sha-bang</emphasis> is a path name. This is the
|
|||
|
path to the program that interprets the commands in the script,
|
|||
|
whether it be a shell, a programming language, or a utility. This
|
|||
|
command interpreter then executes the commands in the script,
|
|||
|
starting at the top (line 1 of the script), ignoring comments.
|
|||
|
<footnote><para>The <token>#!</token> line in a shell script
|
|||
|
will be the first thing the command interpreter
|
|||
|
(<command>sh</command> or <command>bash</command>)
|
|||
|
sees. Since this line begins with a <token>#</token>,
|
|||
|
it will be correctly interpreted as a comment when the
|
|||
|
command interpreter finally executes the script. The
|
|||
|
line has already served its purpose - calling the command
|
|||
|
interpreter.</para></footnote>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para><programlisting>#!/bin/sh
|
|||
|
#!/bin/bash
|
|||
|
#!/usr/bin/perl
|
|||
|
#!/bin/tcl
|
|||
|
#!/bin/sed -f
|
|||
|
#!/usr/awk -f</programlisting></para>
|
|||
|
|
|||
|
<para>Each of the above script header lines calls a different command
|
|||
|
interpreter, be it <filename>/bin/sh</filename>, the default shell
|
|||
|
(<command>bash</command> in a Linux system) or otherwise.
|
|||
|
|
|||
|
<footnote>
|
|||
|
<para>This allows some cute tricks.</para>
|
|||
|
<para><programlisting>#!/bin/rm
|
|||
|
# Self-deleting script.
|
|||
|
|
|||
|
# Nothing much seems to happen when you run this... except that the file disappears.
|
|||
|
|
|||
|
WHATEVER=65
|
|||
|
|
|||
|
echo "This line will never print (betcha!)."
|
|||
|
|
|||
|
exit $WHATEVER # Doesn't matter. The script will not exit here.</programlisting></para>
|
|||
|
<para>Also, try starting a <filename>README</filename> file with a
|
|||
|
<userinput>#!/bin/more</userinput>, and making it executable.
|
|||
|
The result is a self-listing documentation file.</para>
|
|||
|
</footnote>
|
|||
|
|
|||
|
Using <userinput>#!/bin/sh</userinput>, the default Bourne Shell
|
|||
|
in most commercial variants of UNIX, makes the script portable
|
|||
|
to non-Linux machines, though you may have to sacrifice a few
|
|||
|
Bash-specific features (the script will conform to the POSIX
|
|||
|
<command>sh</command> standard).</para>
|
|||
|
|
|||
|
<para>Note that the path given at the <quote>sha-bang</quote> must
|
|||
|
be correct, otherwise an error message, usually <quote>Command not
|
|||
|
found</quote> will be the only result of running the script.</para>
|
|||
|
|
|||
|
<para><token>#!</token> can be omitted if the script consists only
|
|||
|
of a set of generic system commands, using no internal
|
|||
|
shell directives. Example 2, above, requires the initial
|
|||
|
<token>#!</token>, since the variable assignment line,
|
|||
|
<userinput>lines=50</userinput>, uses a shell-specific construct.
|
|||
|
Note that <userinput>#!/bin/sh</userinput> invokes the default
|
|||
|
shell interpreter, which defaults to <filename>/bin/bash</filename>
|
|||
|
on a Linux machine.</para>
|
|||
|
|
|||
|
<important><para>This tutorial encourages a modular approach
|
|||
|
to constructing a script. Make note of and collect
|
|||
|
<quote>boilerplate</quote> code snippets that might be useful
|
|||
|
in future scripts. Eventually you can build a quite extensive
|
|||
|
library of nifty routines. As an example, the following script
|
|||
|
prolog tests whether the script has been invoked with the correct
|
|||
|
number of parameters.
|
|||
|
|
|||
|
<programlisting>if [ $# -ne Number_of_expected args ]
|
|||
|
then
|
|||
|
echo "Usage: `basename $0` whatever"
|
|||
|
exit $WRONG_ARGS
|
|||
|
fi</programlisting>
|
|||
|
</para></important>
|
|||
|
|
|||
|
|
|||
|
<sect1 id="invoking">
|
|||
|
<title>Invoking the script</title>
|
|||
|
<para>Having written the script, you can invoke it by <userinput>sh
|
|||
|
scriptname</userinput>,
|
|||
|
|
|||
|
<footnote><para>Caution: invoking a Bash script by <userinput>sh
|
|||
|
scriptname</userinput> turns off Bash-specific extensions, and the
|
|||
|
script may therefore fail to execute.</para></footnote>
|
|||
|
|
|||
|
or alternately <userinput>bash scriptname</userinput>. (Not
|
|||
|
recommended is using <userinput>sh <scriptname</userinput>,
|
|||
|
since this effectively disables reading from
|
|||
|
<filename>stdin</filename> within the script.) Much more
|
|||
|
convenient is to make the script itself directly executable with
|
|||
|
a <link linkend="chmodref">chmod</link>.
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term>Either:</term> <listitem>
|
|||
|
<para><userinput>chmod 555 scriptname</userinput> (gives
|
|||
|
everyone read/execute permission)
|
|||
|
<footnote><para>A script needs <emphasis>read</emphasis>, as
|
|||
|
well as execute permission for it to run, since the shell
|
|||
|
needs to be able to read it.</para></footnote>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry> <varlistentry>
|
|||
|
<term>or</term> <listitem>
|
|||
|
<para><userinput>chmod +rx scriptname</userinput> (gives
|
|||
|
everyone read/execute permission)</para> <para><userinput>chmod
|
|||
|
u+rx scriptname</userinput> (gives only the
|
|||
|
script owner read/execute permission)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Having made the script executable, you may now test it by
|
|||
|
<userinput>./scriptname</userinput>.
|
|||
|
|
|||
|
<footnote><para>Why not simply invoke the script with
|
|||
|
<userinput>scriptname</userinput>? If the directory
|
|||
|
you are in (<link linkend="pwdref">$PWD</link>) is where
|
|||
|
<emphasis>scriptname</emphasis> is located, why doesn't this
|
|||
|
work? This fails because, for security reasons, the current
|
|||
|
directory, <quote>.</quote> is not included in a user's <link
|
|||
|
linkend="pathref">$PATH</link>. It is therefore necessary to
|
|||
|
explicitly invoke the script in the current directory with
|
|||
|
a <userinput>./scriptname</userinput>.</para></footnote>
|
|||
|
|
|||
|
If it begins with a <quote>sha-bang</quote> line, invoking the
|
|||
|
script calls the correct command interpreter to run it.</para>
|
|||
|
|
|||
|
<para>As a final step, after testing and debugging,
|
|||
|
you would likely want to move it to <filename
|
|||
|
class="directory">/usr/local/bin</filename> (as root, of
|
|||
|
course), to make the script available to yourself and all
|
|||
|
other users as a system-wide executable. The script could
|
|||
|
then be invoked by simply typing <command>scriptname</command>
|
|||
|
<keycap>[ENTER]</keycap> from the command line.</para>
|
|||
|
|
|||
|
</sect1> <!-- Invoking the script -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="wrapper">
|
|||
|
<title>Shell wrapper, self-executing script</title>
|
|||
|
|
|||
|
<para>A
|
|||
|
<command>
|
|||
|
<indexterm>
|
|||
|
<primary>sed</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>script</primary>
|
|||
|
<secondary>sed</secondary>
|
|||
|
</indexterm>
|
|||
|
sed</command> or
|
|||
|
<command>
|
|||
|
<indexterm>
|
|||
|
<primary>awk</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>script</primary>
|
|||
|
<secondary>awk</secondary>
|
|||
|
</indexterm>
|
|||
|
awk</command> script would normally be invoked
|
|||
|
from the command line by a <userinput>sed -e
|
|||
|
<replaceable>'commands'</replaceable></userinput>
|
|||
|
or <userinput>awk
|
|||
|
<replaceable>'commands'</replaceable></userinput>.
|
|||
|
Embedding such a script in a bash script
|
|||
|
permits calling it more simply, and makes it
|
|||
|
<quote>reusable</quote>. This also enables combining
|
|||
|
the functionality of <link linkend="sedref">sed</link>
|
|||
|
and <link linkend="awkref">awk</link>, for example <link
|
|||
|
linkend="piperef">piping</link> the output of a set of
|
|||
|
<command>sed</command> commands to <command>awk</command>.
|
|||
|
As a saved executable file, you can then repeatedly invoke it
|
|||
|
in its original form or modified, without the inconvenience
|
|||
|
of retyping it on the command line.</para>
|
|||
|
|
|||
|
<example id="ex3">
|
|||
|
<title><command>shell wrapper</command></title>
|
|||
|
<programlisting>&ex3;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ex4">
|
|||
|
<title> A slightly more complex <command>shell wrapper</command></title>
|
|||
|
<programlisting>&ex4;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="coltotaler">
|
|||
|
<title> A <command>shell wrapper</command> around an awk script</title>
|
|||
|
<programlisting>&coltotaler;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para><anchor id="perlref">For those scripts needing a single
|
|||
|
do-it-all tool, a Swiss army knife, there is Perl. Perl combines
|
|||
|
the capabilities of <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 can be effectively
|
|||
|
embedded in shell scripts, and there may even be some substance
|
|||
|
to the claim that Perl can totally replace shell scripting
|
|||
|
(though the author of this document remains skeptical).</para>
|
|||
|
|
|||
|
<example id="ex56">
|
|||
|
<title>Perl embedded in a <command>bash</command> script</title>
|
|||
|
<programlisting>&ex56;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<formalpara><title>Exercise</title>
|
|||
|
<para>Write a shell script that performs a simple task.</para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
</sect1> <!-- Shell wrapper, self-executing script -->
|
|||
|
</chapter> <!-- Starting Off With a Sha-Bang -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<chapter id="tutorial">
|
|||
|
<title>Tutorial / Reference</title>
|
|||
|
<epigraph>
|
|||
|
<attribution>Chet Ramey</attribution>
|
|||
|
<para>...there are dark corners in the Bourne shell, and people use all
|
|||
|
of them.</para>
|
|||
|
</epigraph>
|
|||
|
|
|||
|
<sect1 id="exit-status">
|
|||
|
<title>Exit and Exit Status</title>
|
|||
|
<para><anchor id="exitcommandref">The
|
|||
|
<command>
|
|||
|
<indexterm>
|
|||
|
<primary>exit</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>exit</secondary>
|
|||
|
</indexterm>
|
|||
|
exit
|
|||
|
</command>
|
|||
|
command may be used to terminate a script, just as in a C program.
|
|||
|
It can also return a value, which is available to the script's parent
|
|||
|
process.</para>
|
|||
|
|
|||
|
|
|||
|
<para><anchor id="exitstatusref">Every command returns an
|
|||
|
<firstterm>
|
|||
|
<indexterm>
|
|||
|
<primary>exit status</primary>
|
|||
|
</indexterm>
|
|||
|
exit status
|
|||
|
</firstterm>
|
|||
|
(sometimes referred to as a
|
|||
|
<firstterm>
|
|||
|
<indexterm>
|
|||
|
<primary>return status</primary>
|
|||
|
</indexterm>
|
|||
|
return status
|
|||
|
</firstterm>). A successful command returns a
|
|||
|
<returnvalue>0</returnvalue>, while an unsuccessful one returns
|
|||
|
a <returnvalue>non-zero</returnvalue> value that usually may
|
|||
|
be interpreted as an error code. Well-behaved UNIX commands,
|
|||
|
programs, and utilities return a <returnvalue>0</returnvalue>
|
|||
|
exit code upon successful completion, though there are some
|
|||
|
exceptions.</para>
|
|||
|
|
|||
|
<para>Likewise, functions within a script and the script itself
|
|||
|
return an exit status. The last command executed in the function
|
|||
|
or script determines the exit status. Within a script, an
|
|||
|
<userinput>exit <replaceable>nn</replaceable></userinput>
|
|||
|
command may be used to deliver an
|
|||
|
<returnvalue><replaceable>nn</replaceable></returnvalue> exit status
|
|||
|
to the shell (<returnvalue><replaceable>nn</replaceable></returnvalue>
|
|||
|
must be a decimal number in the <returnvalue>0</returnvalue> -
|
|||
|
<returnvalue>255</returnvalue> range).</para>
|
|||
|
|
|||
|
<note><para>When a script ends with an <command>exit</command> that has
|
|||
|
no parameter, the exit status of the script is the exit status of
|
|||
|
the last command executed in the script (<emphasis>not</emphasis>
|
|||
|
counting the <command>exit</command>).</para></note>
|
|||
|
|
|||
|
<para>
|
|||
|
<varname>
|
|||
|
<indexterm>
|
|||
|
<primary>$?</primary>
|
|||
|
</indexterm> <indexterm>
|
|||
|
<primary>variable</primary> <secondary>$?</secondary>
|
|||
|
</indexterm> $?</varname> reads the exit status of the last
|
|||
|
command executed. After a function returns,
|
|||
|
<varname>$?</varname> gives the exit status of the last
|
|||
|
command executed in the function. This is Bash's way of
|
|||
|
giving functions a <quote>return value</quote>. After a
|
|||
|
script terminates, a <varname>$?</varname> from the command
|
|||
|
line gives the exit status of the script, that is, the last
|
|||
|
command executed in the script, which is, by convention,
|
|||
|
<userinput>0</userinput> on success or an integer in the
|
|||
|
range 1 - 255 on error.</para>
|
|||
|
|
|||
|
<example id="ex5">
|
|||
|
<title>exit / exit status</title>
|
|||
|
<programlisting>&ex5;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para><link linkend="xstatvarref">$?</link> is especially useful
|
|||
|
for testing the result of a command in a script (see <xref
|
|||
|
linkend="filecomp"> and <xref linkend="lookup">).</para>
|
|||
|
|
|||
|
<note>
|
|||
|
<para>The <link linkend="notref">!</link>, the logical
|
|||
|
<quote>not</quote> qualifier, reverses the outcome of a test or
|
|||
|
command, and this affects its <link linkend="exitstatusref">exit
|
|||
|
status</link>.
|
|||
|
|
|||
|
<example id="negcond">
|
|||
|
<title>Negating a condition using <token>!</token></title>
|
|||
|
<programlisting>true # the "true" builtin.
|
|||
|
echo "exit status of \"true\" = $?" # 0
|
|||
|
|
|||
|
! true
|
|||
|
echo "exit status of \"! true\" = $?" # 1
|
|||
|
# Note that the "!" needs a space.
|
|||
|
# !true leads to a "command not found" error
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</para>
|
|||
|
</note>
|
|||
|
|
|||
|
|
|||
|
<caution><para>Certain exit status codes have <link
|
|||
|
linkend="exitcodesref">reserved meanings</link> and should not
|
|||
|
be user-specified in a script. </para></caution>
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- exit and exit status -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="special-chars">
|
|||
|
<title>Special characters used in shell scripts</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry><term><token>#</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>#</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>#</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>comment</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<formalpara><title>Comments</title>
|
|||
|
<para>Lines beginning with a <token>#</token>
|
|||
|
(<link linkend="magnumref">with the exception of
|
|||
|
<token>#!</token></link>) are comments.</para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<para><programlisting># This line is a comment.</programlisting></para>
|
|||
|
|
|||
|
<para>Comments may also occur at the end of a command.</para>
|
|||
|
|
|||
|
<para><programlisting>echo "A comment will follow." # Comment here.</programlisting></para>
|
|||
|
|
|||
|
<para>Comments may also follow <link
|
|||
|
linkend="whitespaceref">whitespace</link> at the beginning
|
|||
|
of a line.</para>
|
|||
|
|
|||
|
<para><programlisting> # A tab precedes this comment.</programlisting></para>
|
|||
|
|
|||
|
<caution><para>A command may not follow a comment on the
|
|||
|
same line. There is no method of terminating the comment,
|
|||
|
in order for <quote>live code</quote> to begin on the same
|
|||
|
line. Use a new line for the next command.</para></caution>
|
|||
|
|
|||
|
<note><para>Of course, an escaped <token>#</token> in an
|
|||
|
<command>echo</command> statement does
|
|||
|
<emphasis>not</emphasis> begin a comment. Likewise, a
|
|||
|
<token>#</token> appears in <link linkend="psub2">certain
|
|||
|
parameter substitution constructs</link> and in <link
|
|||
|
linkend="numconstants">numerical constant expressions</link>.
|
|||
|
|
|||
|
<programlisting>echo "The # here does not begin a comment."
|
|||
|
echo 'The # here does not begin a comment.'
|
|||
|
echo The \# here does not begin a comment.
|
|||
|
echo The # here begins a comment.
|
|||
|
|
|||
|
echo ${PATH#*:} # Parameter substitution, not a comment.
|
|||
|
echo $(( 2#101011 )) # Base conversion, not a comment.
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
|
|||
|
The standard <link linkend="quotingref">quoting and
|
|||
|
escape</link> characters (" ' \) escape the #.
|
|||
|
</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>;</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>;</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>;</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>separator</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<formalpara><title>Command separator</title>
|
|||
|
<para>Permits putting two or more commands on the same line.</para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<para><programlisting>echo hello; echo there</programlisting></para>
|
|||
|
|
|||
|
<para>Note that the <quote><token>;</token></quote> sometimes
|
|||
|
needs to be <link linkend="escp">escaped</link>.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry><term><anchor id="dotref"><token>.</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>.</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>.</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>dot command</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>source</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<formalpara><title><quote>dot</quote> command</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><formalpara><title><link linkend="dblquo">partial
|
|||
|
quoting</link></title>
|
|||
|
<para><emphasis>"STRING"</emphasis> preserves (from
|
|||
|
interpretation) most of the special characters
|
|||
|
within <emphasis>STRING</emphasis>. See also <xref
|
|||
|
linkend="quoting">.</para>
|
|||
|
</formalpara> </listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>'</token></term>
|
|||
|
<listitem><formalpara><title><link linkend="snglquo">full
|
|||
|
quoting</link></title>
|
|||
|
<para><emphasis>'STRING'</emphasis> preserves all special
|
|||
|
characters within <emphasis>STRING</emphasis>. This is
|
|||
|
a stronger form of quoting than using <token>"</token>.
|
|||
|
See also <xref linkend="quoting">.</para>
|
|||
|
</formalpara> </listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>\</token></term>
|
|||
|
<listitem><formalpara><title><link linkend="escp">escape</link></title>
|
|||
|
<para><emphasis>\X</emphasis> <quote>escapes</quote> the
|
|||
|
character <emphasis>X</emphasis>. This has the effect of
|
|||
|
<quote>quoting</quote> <emphasis>X</emphasis>, equivalent
|
|||
|
to <emphasis>'X'</emphasis>. The <token>\</token> may
|
|||
|
be used to quote <token>"</token> and <token>'</token>,
|
|||
|
so they are expressed literally.</para>
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>`</token></term>
|
|||
|
<listitem><formalpara><title><link
|
|||
|
linkend="commandsubref">command substitution</link></title>
|
|||
|
<para><emphasis>`command`</emphasis> makes available the
|
|||
|
output of <emphasis>command</emphasis> for
|
|||
|
setting a variable. This is also known as <link
|
|||
|
linkend="backquotesref">backticks</link> or
|
|||
|
backquotes.</para></formalpara> </listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><anchor id="nullref"><token>:</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>:</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>:</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>null command</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>true</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>endless loop</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<formalpara><title>null command</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>. Note
|
|||
|
that <token>:</token> is a Bash builtin, and its
|
|||
|
<link linkend="exitstatusref">exit status</link> is
|
|||
|
<returnvalue>0</returnvalue>.</para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
|
|||
|
<para>Endless loop:</para>
|
|||
|
|
|||
|
<para><programlisting>
|
|||
|
while :
|
|||
|
do
|
|||
|
operation-1
|
|||
|
operation-2
|
|||
|
...
|
|||
|
operation-n
|
|||
|
done
|
|||
|
|
|||
|
# Same as:
|
|||
|
# while true
|
|||
|
# do
|
|||
|
# ...
|
|||
|
# done</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Placeholder in if/then test:</para>
|
|||
|
|
|||
|
<para><programlisting>
|
|||
|
if condition
|
|||
|
then : # Do nothing and branch ahead
|
|||
|
else
|
|||
|
take-some-action
|
|||
|
fi</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Provide a placeholder where a binary operation is
|
|||
|
expected, see <xref linkend="arithops"> and <link
|
|||
|
linkend="defparam">default parameters</link>.</para>
|
|||
|
|
|||
|
<para><programlisting>: ${username=`whoami`}
|
|||
|
# ${username=`whoami`} without the leading : gives an error
|
|||
|
# unless "username" is a command or builtin...</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Provide a placeholder where a command is expected in a
|
|||
|
<link linkend="heredocref">here document</link>. See <xref
|
|||
|
linkend="anonheredoc">.</para>
|
|||
|
|
|||
|
<para>Evaluate string of variables using
|
|||
|
<link linkend="paramsubref">parameter substitution</link>,
|
|||
|
see <xref linkend="ex6">:</para>
|
|||
|
|
|||
|
<para><programlisting>: ${HOSTNAME?} ${USER?} ${MAIL?}
|
|||
|
#Prints error message if one or more of essential environmental variables not set.</programlisting>
|
|||
|
</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, updates a file access/modification
|
|||
|
time (<userinput>: >> new_file</userinput>).
|
|||
|
If the file did not previously exist, creates it. This is
|
|||
|
equivalent to <link linkend="touchref">touch</link>.</para>
|
|||
|
|
|||
|
<note><para>This applies to regular files, not pipes,
|
|||
|
symlinks, and certain special files.</para></note>
|
|||
|
|
|||
|
|
|||
|
<para>May be used to begin a comment line, although this is not
|
|||
|
recommended. Using <token>#</token> for a comment turns
|
|||
|
off error checking for the remainder of that line, so
|
|||
|
almost anything may be appear in a comment. However,
|
|||
|
this is not the case with
|
|||
|
<token>:</token>.
|
|||
|
<programlisting>: This is a comment that generates an error, ( if [ $x -eq 3] ).</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="notref"><token>!</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>!</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>!</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>not</primary>
|
|||
|
<secondary>logical</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>not</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem><formalpara><title>reverse (or negate) the sense of
|
|||
|
a test or exit status</title>
|
|||
|
|
|||
|
<para>The <token>!</token> operator inverts the <link
|
|||
|
linkend="exitstatusref">exit status</link>
|
|||
|
of the command to which it is applied (see
|
|||
|
<xref linkend="negcond">). It also inverts
|
|||
|
the meaning of a test operator. This can, for
|
|||
|
example, change the sense of <quote>equal</quote>
|
|||
|
( <link linkend="equalsignref">=</link>
|
|||
|
) to <quote>not-equal</quote> ( != ). The
|
|||
|
<token>!</token> operator is a Bash <link
|
|||
|
linkend="keywordref">keyword</link>.</para>
|
|||
|
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>*</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>*</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>*</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>wild card</primary>
|
|||
|
<secondary>globbing</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>regular expression</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem><formalpara><title>wild card</title>
|
|||
|
|
|||
|
<para>The <token>*</token> character serves as a <quote>wild
|
|||
|
card</quote> for filename expansion in <link
|
|||
|
linkend="globbingref">globbing</link>, as well as
|
|||
|
representing any number (or zero) characters in a <link
|
|||
|
linkend="regexref">regular expression</link>.</para>
|
|||
|
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>$*</token></term>
|
|||
|
<term><token>$@</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$*</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>$*</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>$@</primary>
|
|||
|
<secondary>positional parameters</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>$@</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem><formalpara><title>positional parameters</title>
|
|||
|
|
|||
|
<para>The list of the <link linkend="appref">positional
|
|||
|
parameters</link> (command-line arguments) passed to a
|
|||
|
script.</para>
|
|||
|
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>$_</token></term>
|
|||
|
<listitem><formalpara><title>last argument</title>
|
|||
|
<para>Internal shell variable set to last argument
|
|||
|
of previous command executed. See <xref
|
|||
|
linkend="uscref">.</para>
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="whitespaceref">Whitespace</term>
|
|||
|
<listitem><formalpara><title>functions as a separator, separating commands or variables.</title>
|
|||
|
<para>Whitespace consists of either spaces, tabs, blank
|
|||
|
lines, or any combination thereof. In some contexts,
|
|||
|
such as <link linkend="wsbad">variable assignment</link>,
|
|||
|
whitespace is not permitted, and results in a syntax
|
|||
|
error.</para>
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>()</token></term>
|
|||
|
|
|||
|
<listitem><formalpara><title>command group</title>
|
|||
|
<para><programlisting>(a=hello; echo $a)</programlisting></para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<important>
|
|||
|
|
|||
|
<para>A listing of commands within
|
|||
|
<replaceable>parentheses</replaceable> starts a <link
|
|||
|
linkend="subshellsref">subshell</link>.</para>
|
|||
|
|
|||
|
<para>Variables inside parentheses, within the subshell, are not
|
|||
|
visible to the rest of the script. The parent process,
|
|||
|
the script, <link linkend="parvis">cannot read variables
|
|||
|
created in the child process</link>, the subshell.
|
|||
|
<programlisting>a=123
|
|||
|
( a=321; )
|
|||
|
|
|||
|
echo "a = $a" # a = 123
|
|||
|
# "a" within parentheses acts like a local variable.</programlisting></para>
|
|||
|
</important>
|
|||
|
|
|||
|
|
|||
|
<formalpara><title>array initialization</title>
|
|||
|
<para><programlisting>Array=(element1 element2 element3)</programlisting></para>
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry><term><token>${}</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>${}</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>${}</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>parameter substitution</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<formalpara><title><link linkend="paramsubref">Parameter
|
|||
|
substitution</link></title>
|
|||
|
<para></para></formalpara>
|
|||
|
</listitem>
|
|||
|
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<indexterm>
|
|||
|
<primary>{xxx,yyy,zzz..}</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>{}</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>brace expansion</primary>
|
|||
|
</indexterm>
|
|||
|
<term><token>{xxx,yyy,zzz,...}</token></term>
|
|||
|
<listitem><formalpara><title>Brace expansion</title>
|
|||
|
<para><programlisting>grep Linux file*.{txt,htm*}
|
|||
|
# Finds all instances of the work "Linux"
|
|||
|
# in the files "fileA.txt", "file2.txt", "fileR.html", "file-87.htm", etc.</programlisting></para>
|
|||
|
</formalpara>
|
|||
|
<para>A command may act upon a comma-separated list of file specs within
|
|||
|
<replaceable>braces</replaceable>.
|
|||
|
|
|||
|
<footnote><para>The shell does the <emphasis>brace
|
|||
|
expansion</emphasis>. The command itself acts upon the
|
|||
|
<emphasis>result</emphasis> of the expansion.</para></footnote>
|
|||
|
|
|||
|
Filename expansion (<link linkend="globbingref">globbing</link>)
|
|||
|
applies to the file specs between the braces.</para>
|
|||
|
|
|||
|
<caution>
|
|||
|
<para>No spaces allowed within the braces
|
|||
|
<emphasis>unless</emphasis> the spaces are quoted or escaped.</para>
|
|||
|
|
|||
|
<para><userinput>echo {file1,file2}\ :{\ A," B",' C'}</userinput></para>
|
|||
|
<para><computeroutput>file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C</computeroutput></para>
|
|||
|
|
|||
|
</caution>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="codeblockref"><token>{}</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>{}</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>{}</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>block of code</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem><formalpara><title>Block of code</title>
|
|||
|
<para>Also referred to as an <quote>inline group</quote>,
|
|||
|
this construct, in effect, creates an
|
|||
|
anonymous function. However, unlike a <link
|
|||
|
linkend="functionref">function</link>, the variables
|
|||
|
in a code block remain visible to the remainder of the
|
|||
|
script.</para></formalpara>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>{ local a; a=123; }</userinput>
|
|||
|
<computeroutput>bash: local: can only be used in a function</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para><programlisting>a=123
|
|||
|
{ a=321; }
|
|||
|
echo "a = $a" # a = 321 (value inside code block)
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>The code block enclosed in braces may have <link
|
|||
|
linkend="ioredirref">I/O redirected</link> to and from
|
|||
|
it.</para>
|
|||
|
|
|||
|
<example id="ex8">
|
|||
|
<title>Code blocks and I/O redirection</title>
|
|||
|
<programlisting>&ex8;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="rpmcheck">
|
|||
|
<title>Saving the results of a code block to a file</title>
|
|||
|
<programlisting>&rpmcheck;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<note><para>Unlike a command group within (parentheses),
|
|||
|
as above, a code block enclosed by {braces} will
|
|||
|
<emphasis>not</emphasis> normally launch a <link
|
|||
|
linkend="subshellsref">subshell</link>.
|
|||
|
|
|||
|
<footnote><para>Exception: a code block in braces as
|
|||
|
part of a pipe <emphasis>may</emphasis> be run as a
|
|||
|
<link linkend="subshellsref">subshell</link>.
|
|||
|
|
|||
|
<programlisting>ls | { read firstline; read secondline; }
|
|||
|
# Error. The code block in braces runs as a subshell,
|
|||
|
# so the output of "ls" cannot be passed to variables within the block.
|
|||
|
echo "First line is $firstline; second line is $secondline" # Will not work.
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting></para></footnote>
|
|||
|
|
|||
|
</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>{} \;</token></term>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<formalpara><title>pathname</title>
|
|||
|
<para>Mostly used in <link linkend="findref">find</link>
|
|||
|
constructs. This is <emphasis>not</emphasis> a shell
|
|||
|
<link linkend="builtinref">builtin</link>.</para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<note><para>The <quote><token>;</token></quote> ends
|
|||
|
the <option>-exec</option> option of a
|
|||
|
<command>find</command> command sequence. It needs
|
|||
|
to be escaped to protect it from interpretation by the
|
|||
|
shell.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry><term><token>[ ]</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>[]</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>[]</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>test</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<formalpara><title>test</title>
|
|||
|
<para></para></formalpara>
|
|||
|
<para><anchor id="leftbracket"><link
|
|||
|
linkend="ifthen">Test</link> expression between <command>[
|
|||
|
]</command>. Note that <command>[</command> is part of
|
|||
|
the shell builtin <command>test</command> (and a synonym
|
|||
|
for it), <emphasis>not</emphasis> a link to the external
|
|||
|
command <filename>/usr/bin/test</filename>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>[[ ]]</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>[[]]</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>[[]]</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>test</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<formalpara><title>test</title>
|
|||
|
<para></para></formalpara>
|
|||
|
<para>Test expression between <token>[[ ]]</token> (shell
|
|||
|
<link linkend="keywordref">keyword</link>).</para>
|
|||
|
<para>See the discussion on the <link
|
|||
|
linkend="dblbrackets">[[ ... ]] construct</link> for more
|
|||
|
details.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>></token> <token>>&</token> <token>>></token> <token><</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>></primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>>&</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>>></primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary><</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>></secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>>&</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>>></secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary><</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>redirection</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem><formalpara><title><link linkend="ioredirref">redirection</link></title>
|
|||
|
<para></para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<para><userinput>scriptname >filename</userinput> redirects the output of
|
|||
|
<filename>scriptname</filename> to file
|
|||
|
<filename>filename</filename>. Overwrite
|
|||
|
<filename>filename</filename> if it already exists.</para>
|
|||
|
|
|||
|
<para><userinput>command >&2</userinput> redirects
|
|||
|
output of <filename>command</filename> to
|
|||
|
<filename>stderr</filename>.</para>
|
|||
|
|
|||
|
<para><userinput>scriptname >>filename</userinput> appends
|
|||
|
the output of <filename>scriptname</filename>
|
|||
|
to file <filename>filename</filename>. If
|
|||
|
<filename>filename</filename> does not already exist,
|
|||
|
it will be created.</para>
|
|||
|
|
|||
|
|
|||
|
<formalpara><title><link linkend="processsubref">process substitution</link></title>
|
|||
|
<para></para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<para><userinput>(command)></userinput></para>
|
|||
|
<para><userinput><(command)</userinput></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token><<</token></term>
|
|||
|
<listitem><formalpara><title>redirection used in a <link
|
|||
|
linkend="heredocref">here document</link></title>
|
|||
|
<para></para>
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="piperef"><token>|</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>|</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>|</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>pipe</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem><formalpara><title>pipe</title>
|
|||
|
<para>Passes the output of previous command to next one, or to shell.
|
|||
|
This is a method of chaining commands together.</para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<para><programlisting>echo ls -l | sh</programlisting>
|
|||
|
passes the output of <quote>echo ls -l</quote> to the shell,
|
|||
|
with the same result as a simple <quote>ls -l</quote>.</para>
|
|||
|
|
|||
|
<para><programlisting>cat *.lst | sort | uniq</programlisting>
|
|||
|
sorts the output of all the <filename>.lst</filename> files and
|
|||
|
deletes duplicate lines.</para>
|
|||
|
|
|||
|
<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.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<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>If one of the commands in the pipe
|
|||
|
aborts, this prematurely terminates execution of the
|
|||
|
pipe. Called a <emphasis>broken pipe</emphasis>, this
|
|||
|
condition sends a <emphasis>SIGPIPE</emphasis> <link
|
|||
|
linkend="signald">signal</link>.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>>|</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>>|</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>>|</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>redirection</primary>
|
|||
|
<secondary>force</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>noclobber</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem><formalpara><title>force redirection (even if
|
|||
|
the <link linkend="noclobberref">noclobber option</link>
|
|||
|
is set)</title>
|
|||
|
<para>This will forcibly overwrite an existing file.</para>
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>-</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>-</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>redirection</primary>
|
|||
|
<secondary>from/to stdin/stdout</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><formalpara><title>redirection from/to <filename>stdin</filename> or <filename>stdout</filename></title>
|
|||
|
<para></para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<para><anchor id="coxex"><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 ../target-directory; tar xzf -)
|
|||
|
#
|
|||
|
# cp -a /source/directory /dest also has same effect.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
<para><programlisting>bunzip2 linux-2.4.3.tar.bz2 | tar xvf -
|
|||
|
# --uncompress tar file-- | --then pass it to "tar"--
|
|||
|
# If "tar" has not been patched to handle "bunzip2",
|
|||
|
# this needs to be done in two discrete steps, using a pipe.
|
|||
|
# The purpose of the exercise is to unarchive "bzipped" kernel source.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
<para>Note that in this context the <quote>-</quote> is not
|
|||
|
itself a Bash operator, but rather an option recognized by
|
|||
|
certain UNIX utilities that write to
|
|||
|
<filename>stdout</filename>, such as <command>tar</command>,
|
|||
|
<command>cat</command>, etc.</para>
|
|||
|
|
|||
|
<para>Where a filename is expected,
|
|||
|
<replaceable>-</replaceable> redirects output to
|
|||
|
<filename>stdout</filename> (sometimes seen with
|
|||
|
<userinput>tar cf</userinput>), or accepts input from
|
|||
|
<filename>stdin</filename>, rather than from a file. This
|
|||
|
is a method of using a file-oriented utility as a filter
|
|||
|
in a pipe.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>file</userinput>
|
|||
|
<computeroutput>Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...</computeroutput>
|
|||
|
</screen>
|
|||
|
By itself on the command line, <link
|
|||
|
linkend="fileref">file</link> fails with an error message.
|
|||
|
</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>file -</userinput>
|
|||
|
<userinput>#!/bin/bash</userinput>
|
|||
|
<computeroutput>standard input: Bourne-Again shell script text executable</computeroutput>
|
|||
|
</screen>
|
|||
|
This time, it accepts input from <filename>stdin</filename>
|
|||
|
and filters it.
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Try using <link linkend="diffref">diff</link> to
|
|||
|
compare a file with a <emphasis>section</emphasis>
|
|||
|
of another.</para>
|
|||
|
|
|||
|
<para><userinput>grep bash 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
|
|||
|
<replaceable>-</replaceable> may cause problems when
|
|||
|
coupled with the <replaceable>-</replaceable> redirection
|
|||
|
operator. A script should check for this and pass such
|
|||
|
filenames as <replaceable>./-FILENAME</replaceable> or
|
|||
|
<replaceable>$PWD/-FILENAME</replaceable>.</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><command>cd -</command> changes to previous working
|
|||
|
directory. This uses the <link
|
|||
|
linkend="oldpwd">$OLDPWD</link> environmental
|
|||
|
variable.</para>
|
|||
|
</formalpara>
|
|||
|
<caution><para>This is not to be confused 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>home directory</title>
|
|||
|
|
|||
|
<para>This corresponds to the <link
|
|||
|
linkend="homedirref">$HOME</link> internal variable.
|
|||
|
|
|||
|
<emphasis>~bozo</emphasis> is bozo's home directory,
|
|||
|
and <command>ls ~bozo</command> lists the contents of it.
|
|||
|
<token>~/</token> is the current user's home directory,
|
|||
|
and <command>ls ~/</command> lists the contents of it.
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><userinput>echo ~bozo</userinput>
|
|||
|
<computeroutput>/home/bozo</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo ~</userinput>
|
|||
|
<computeroutput>/home/bozo</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo ~/</userinput>
|
|||
|
<computeroutput>/home/bozo/</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo ~:</userinput>
|
|||
|
<computeroutput>/home/bozo:</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo ~nonexistent-user</userinput>
|
|||
|
<computeroutput>~nonexistent-user</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</formalpara>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term>Blank lines</term>
|
|||
|
<listitem><para>Blank lines have no effect on the action of a script, and are therefore useful
|
|||
|
for visually separating functional sections of the script.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect1> <!-- Special characters used in shell scripts -->
|
|||
|
|
|||
|
<sect1 id="variables">
|
|||
|
<title>Introduction to Variables and Parameters</title>
|
|||
|
|
|||
|
<para>Variables are at the heart of every programming and scripting
|
|||
|
language. They appear in arithmetic operations and manipulation
|
|||
|
of quantities, string parsing, and are indispensable for working
|
|||
|
in the abstract with symbols - tokens that represent something
|
|||
|
else. A variable is nothing more than a location or set of
|
|||
|
locations in computer memory that holds an item of data.</para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term><token>$</token></term> <indexterm>
|
|||
|
<primary>$</primary>
|
|||
|
</indexterm> <indexterm>
|
|||
|
<primary>variable</primary> <secondary>$</secondary>
|
|||
|
</indexterm> <indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>substitution</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<formalpara><title>variable substitution</title>
|
|||
|
<para>Let us carefully distinguish between the
|
|||
|
<emphasis>name</emphasis> of a variable
|
|||
|
and its <emphasis>value</emphasis>. If
|
|||
|
<userinput>variable1</userinput> is the name of a
|
|||
|
variable, then <userinput>$variable1</userinput>
|
|||
|
is a reference to its <emphasis>value</emphasis>,
|
|||
|
the data item it contains. The only time a
|
|||
|
variable appears <quote>naked</quote>, without the
|
|||
|
<token>$</token> prefix, is when declared or assigned,
|
|||
|
when <emphasis>unset</emphasis>, or when <link
|
|||
|
linkend="exportref">exported</link>. Assignment
|
|||
|
may be with an <token>=</token> (as in
|
|||
|
<emphasis>var1=27</emphasis>), in a <link
|
|||
|
linkend="readref">read</link> statement, and at the head
|
|||
|
of a loop (<emphasis>for var2 in 1 2 3</emphasis>).</para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<para><anchor id="dblquo">Enclosing a referenced value in
|
|||
|
double quotes (<token>" "</token>) does not
|
|||
|
interfere with variable substitution. This is called
|
|||
|
partial quoting, sometimes referred to as <quote>weak
|
|||
|
quoting</quote>. <anchor id="snglquo">Using single quotes
|
|||
|
(<token>' '</token>) causes the variable name to be used
|
|||
|
literally, and no substitution will take place. This is
|
|||
|
full quoting, sometimes referred to as <quote>strong
|
|||
|
quoting</quote>. See <xref linkend="quoting"> for a
|
|||
|
detailed discussion.</para>
|
|||
|
|
|||
|
<para>Note that <userinput>$variable</userinput> is actually a
|
|||
|
simplified alternate form of
|
|||
|
<userinput>${variable}</userinput>. In contexts
|
|||
|
where the <userinput>$variable</userinput> syntax
|
|||
|
causes an error, the longer form may work (see <xref
|
|||
|
linkend="Parameter-Substitution">, below).</para>
|
|||
|
|
|||
|
<example id="ex9">
|
|||
|
<title>Variable assignment and substitution</title>
|
|||
|
<programlisting>&ex9;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<warning><para>An uninitialized variable has a
|
|||
|
<quote>null</quote> value - no assigned value at all
|
|||
|
(not zero!). Using a variable before assigning a value
|
|||
|
to it will inevitably cause problems.</para></warning>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<sect2 id="Parameter-Substitution">
|
|||
|
<title>Parameter Substitution</title>
|
|||
|
|
|||
|
<para><anchor id="paramsubref"></para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term>
|
|||
|
<userinput>${parameter}</userinput></term>
|
|||
|
<listitem>
|
|||
|
<para>Same as <replaceable>$parameter</replaceable>, i.e.,
|
|||
|
value of the variable <replaceable>parameter</replaceable>.</para>
|
|||
|
<para>May be used for concatenating variables with strings.</para>
|
|||
|
<para><programlisting>
|
|||
|
your_id=${USER}-on-${HOSTNAME}
|
|||
|
echo "$your_id"
|
|||
|
#
|
|||
|
echo "Old \$PATH = $PATH"
|
|||
|
PATH=${PATH}:/opt/bin #Add /opt/bin to $PATH for duration of script.
|
|||
|
echo "New \$PATH = $PATH"
|
|||
|
</programlisting></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>${parameter-default}</userinput></term>
|
|||
|
<listitem>
|
|||
|
<para>If parameter not set, use default.</para>
|
|||
|
<para><programlisting>
|
|||
|
echo ${username-`whoami`}
|
|||
|
# Echoes the result of `whoami`, but variable "username" is still unset.</programlisting></para>
|
|||
|
|
|||
|
<note><para>This is almost equivalent to
|
|||
|
<replaceable>${parameter:-default}</replaceable>. The
|
|||
|
extra <token>:</token> makes a difference only when
|
|||
|
<emphasis>parameter</emphasis> has been declared,
|
|||
|
but is null. </para></note>
|
|||
|
|
|||
|
<para><programlisting>¶msub;</programlisting></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="defparam"><userinput>${parameter=default}</userinput></term>
|
|||
|
<term><userinput>${parameter:=default}</userinput></term>
|
|||
|
<listitem><para>If parameter not set, set it to
|
|||
|
default.</para>
|
|||
|
|
|||
|
<para>Both forms nearly equivalent. The <token>:</token>
|
|||
|
makes a difference only when <emphasis>$parameter</emphasis>
|
|||
|
has been declared and is null,
|
|||
|
<footnote>
|
|||
|
<para>If $parameter is null in a
|
|||
|
non-interactive script, it will terminate with a <link
|
|||
|
linkend="exitcodesref"><returnvalue>127</returnvalue>
|
|||
|
exit status</link> (the Bash error code code for
|
|||
|
<quote>command not found</quote>).</para>
|
|||
|
</footnote>
|
|||
|
as above.
|
|||
|
</para>
|
|||
|
|
|||
|
<para><programlisting>
|
|||
|
echo ${username=`whoami`}
|
|||
|
# Variable "username" is now set to `whoami`.</programlisting></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>${parameter+otherwise}</userinput></term>
|
|||
|
<term><userinput>${parameter:+otherwise}</userinput></term>
|
|||
|
<listitem><para>If parameter set, use 'otherwise", else use null string.</para>
|
|||
|
<para>Both forms nearly equivalent. The <token>:</token>
|
|||
|
makes a difference only when <emphasis>parameter</emphasis>
|
|||
|
has been declared and is null, as above.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>${parameter?err_msg}</userinput></term>
|
|||
|
<term><userinput>${parameter:?err_msg}</userinput></term>
|
|||
|
<listitem><para>If parameter set, use it, else print err_msg.</para>
|
|||
|
<para>Both forms nearly equivalent. The <token>:</token>
|
|||
|
makes a difference only when <emphasis>parameter</emphasis>
|
|||
|
has been declared and is null, as above.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<example id="ex6">
|
|||
|
<title>Using param substitution and <token>:</token></title>
|
|||
|
<programlisting>&ex6;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<formalpara><title>Parameter substitution and/or expansion</title>
|
|||
|
|
|||
|
<para><anchor id="psub2">The following expressions are
|
|||
|
the complement to the <command>match</command>
|
|||
|
<replaceable>in</replaceable> <command>expr</command>
|
|||
|
string operations (see <xref linkend="ex45">).
|
|||
|
These particular ones are used mostly in parsing file
|
|||
|
path names.</para></formalpara>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>${#var}</userinput></term>
|
|||
|
<listitem>
|
|||
|
<para>String length (number of characters
|
|||
|
in <varname>$var</varname>). For an
|
|||
|
<link linkend="arrayref">array</link>,
|
|||
|
<command>${#array}</command> is the length of the
|
|||
|
first element in the array.</para>
|
|||
|
|
|||
|
<note><para>
|
|||
|
Exceptions:
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
<listitem><para>
|
|||
|
<command>${#*}</command> and
|
|||
|
<command>${#@}</command> give the <emphasis>number
|
|||
|
of positional parameters</emphasis>.
|
|||
|
</para></listitem>
|
|||
|
|
|||
|
<listitem><para>
|
|||
|
For an array, <command>${#array[*]}</command> and
|
|||
|
<command>${#array[@]}</command> give the number
|
|||
|
of elements in the array.
|
|||
|
</para></listitem>
|
|||
|
</itemizedlist>
|
|||
|
</para></note>
|
|||
|
|
|||
|
<example id="length">
|
|||
|
<title>Length of a variable</title>
|
|||
|
<programlisting>&length;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>${var#pattern}</userinput></term>
|
|||
|
<term><userinput>${var##pattern}</userinput></term>
|
|||
|
|
|||
|
<listitem><para>Remove from <varname>$var</varname>
|
|||
|
the shortest/longest part of <varname>$pattern</varname>
|
|||
|
that matches the <replaceable>front end</replaceable>
|
|||
|
of <varname>$var</varname>.
|
|||
|
</para></listitem>
|
|||
|
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>${var%pattern}</userinput></term>
|
|||
|
<term><userinput>${var%%pattern}</userinput></term>
|
|||
|
|
|||
|
<listitem><para>Remove from <varname>$var</varname>
|
|||
|
the shortest/longest part of <varname>$pattern</varname>
|
|||
|
that matches the <replaceable>back end</replaceable>
|
|||
|
of <varname>$var</varname>.
|
|||
|
</para></listitem>
|
|||
|
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<para>Version 2 of bash adds 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>
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>${var:pos}</userinput></term>
|
|||
|
<listitem>
|
|||
|
<para>Variable <replaceable>var</replaceable> expanded,
|
|||
|
starting from offset <replaceable>pos</replaceable>.
|
|||
|
</para>
|
|||
|
<para>This expansion adopted from <emphasis>ksh93</emphasis>.</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>
|
|||
|
<para>This expansion adopted from <emphasis>ksh93</emphasis>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>${var/patt/replacement}</userinput></term>
|
|||
|
<listitem>
|
|||
|
<para>First match of <replaceable>patt</replaceable>,
|
|||
|
within <replaceable>var</replaceable> replaced with
|
|||
|
<replaceable>replacement</replaceable>.</para>
|
|||
|
<para>If <replaceable>replacement</replaceable> is
|
|||
|
omitted, then the first match of
|
|||
|
<replaceable>patt</replaceable> is replaced by
|
|||
|
<emphasis>nothing</emphasis>, that is, deleted.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>${var//patt/replacement}</userinput></term>
|
|||
|
<listitem>
|
|||
|
<para>All matches of <replaceable>patt</replaceable>,
|
|||
|
within <replaceable>var</replaceable> replaced with
|
|||
|
<replaceable>replacement</replaceable>.</para>
|
|||
|
<para>Similar to above, if
|
|||
|
<replaceable>replacement</replaceable> is omitted,
|
|||
|
then all occurrences <replaceable>patt</replaceable>
|
|||
|
are replaced by <emphasis>nothing</emphasis>, that
|
|||
|
is, deleted.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<example id="ex7">
|
|||
|
<title>Using pattern matching to parse arbitrary strings</title>
|
|||
|
<programlisting>&ex7;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</sect2> <!-- Parameter Substitution -->
|
|||
|
|
|||
|
</sect1> <!-- Variables -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="quoting">
|
|||
|
<title>Quoting</title>
|
|||
|
|
|||
|
<para><anchor id="quotingref"></para>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>"</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>"</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>'</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>'</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>quote</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>\</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>\</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escape</primary>
|
|||
|
</indexterm>
|
|||
|
<para>Quoting means just that, bracketing a string in quotes. This
|
|||
|
has the effect of protecting special characters in the string from
|
|||
|
reinterpretation or expansion by the shell or shell script. (A character
|
|||
|
is <quote>special</quote> if it has an interpretation other than its
|
|||
|
literal meaning, such as the <token>wild card</token> character,
|
|||
|
<token>*</token>.)</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>ls -l [Vv]*</userinput>
|
|||
|
<computeroutput>-rw-rw-r-- 1 bozo bozo 324 Apr 2 15:05 VIEWDATA.BAT
|
|||
|
-rw-rw-r-- 1 bozo bozo 507 May 4 14:25 vartrace.sh
|
|||
|
-rw-rw-r-- 1 bozo bozo 539 Apr 14 17:11 viewdata.sh
|
|||
|
</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>ls -l '[Vv]*'</userinput>
|
|||
|
<computeroutput>ls: [Vv]*: No such file or directory</computeroutput></screen>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<note>
|
|||
|
<para>Certain programs and utilities can still reinterpret or expand
|
|||
|
special characters in a quoted string. This is an important use
|
|||
|
of quoting, protecting a command-line parameter from the shell,
|
|||
|
but still letting the calling program expand it.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>grep '[Ff]irst' *.txt</userinput>
|
|||
|
<computeroutput>file1.txt:This is the first line of file1.txt.
|
|||
|
file2.txt:This is the First line of file2.txt.</computeroutput></screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Of course, <userinput>grep [Ff]irst *.txt</userinput>
|
|||
|
would not work.</para>
|
|||
|
</note>
|
|||
|
|
|||
|
|
|||
|
<para>When referencing a variable, it is generally advisable in
|
|||
|
enclose it in double quotes (<token>" "</token>). This
|
|||
|
preserves all special characters within the variable name,
|
|||
|
except <token>$</token>, <token>`</token> (backquote),
|
|||
|
and <token>\</token> (escape). Keeping <token>$</token>
|
|||
|
as a special character permits referencing a quoted variable
|
|||
|
(<replaceable>"$variable"</replaceable>), that is, replacing the
|
|||
|
variable with its value (see <xref linkend="ex9">, above).</para>
|
|||
|
|
|||
|
<para>Use double quotes to prevent word splitting.
|
|||
|
<footnote><para><quote>Word splitting</quote>, in this context,
|
|||
|
means dividing a character string into a number of separate and
|
|||
|
discrete arguments.</para></footnote>
|
|||
|
An argument enclosed in double quotes presents
|
|||
|
itself as a single word, even if it contains <link
|
|||
|
linkend="whitespaceref">whitespace</link> separators.
|
|||
|
|
|||
|
<programlisting>variable1="a variable containing five words"
|
|||
|
COMMAND This is $variable1 # Executes COMMAND with 7 arguments:
|
|||
|
# "This" "is" "a" "variable" "containing" "five" "words"
|
|||
|
|
|||
|
COMMAND "This is $variable1" # Executes COMMAND with 1 argument:
|
|||
|
# "This is a variable containing five words"
|
|||
|
|
|||
|
|
|||
|
variable2="" # Empty.
|
|||
|
|
|||
|
COMMAND $variable2 $variable2 $variable2 # Executes COMMAND with no arguments.
|
|||
|
COMMAND "$variable2" "$variable2" "$variable2" # Executes COMMAND with 3 empty arguments.
|
|||
|
COMMAND "$variable2 $variable2 $variable2" # Executes COMMAND with 1 argument (2 spaces).
|
|||
|
|
|||
|
# Thanks, S.C.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<tip><para>Enclosing the arguments to an <command>echo</command>
|
|||
|
statement in double quotes is necessary only when word splitting
|
|||
|
is an issue.</para></tip>
|
|||
|
|
|||
|
<example id="weirdvars">
|
|||
|
<title>Echoing Weird Variables</title>
|
|||
|
<programlisting>&weirdvars;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Single quotes (<token>' '</token>) operate similarly to double
|
|||
|
quotes, but do not permit referencing variables, since
|
|||
|
the special meaning of <token>$</token> is turned off.
|
|||
|
Within single quotes, <emphasis>every</emphasis> special
|
|||
|
character except <token>'</token> gets interpreted literally.
|
|||
|
Consider single quotes (<quote>full quoting</quote>) to be a
|
|||
|
stricter method of quoting than double quotes (<quote>partial
|
|||
|
quoting</quote>).</para>
|
|||
|
|
|||
|
<note><para>Since even the escape character (<token>\</token>)
|
|||
|
gets a literal interpretation within single quotes, trying to
|
|||
|
enclose a single quote within single quotes will not yield the
|
|||
|
expected result.
|
|||
|
<programlisting>echo "Why can't I write 's between single quotes"
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
# The roundabout method.
|
|||
|
echo 'Why can'\''t I write '"'"'s between single quotes'
|
|||
|
# |-------| |----------| |-----------------------|
|
|||
|
# Three single-quoted strings, with escaped and quoted single quotes between.
|
|||
|
|
|||
|
# This example courtesy of Stephane Chazelas.</programlisting>
|
|||
|
</para></note>
|
|||
|
|
|||
|
|
|||
|
<para><anchor id="escp"><firstterm>Escaping</firstterm> is a method
|
|||
|
of quoting single characters. The <token>escape</token>
|
|||
|
(<token>\</token>) preceding a character tells the shell to
|
|||
|
interpret that character literally.</para>
|
|||
|
|
|||
|
<caution><para>With certain commands and utilities, such as <link
|
|||
|
linkend="echoref">echo</link> and <link
|
|||
|
linkend="sedref">sed</link>, escaping a character may have the
|
|||
|
opposite effect - it can toggle on a special meaning for that
|
|||
|
character.</para></caution>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<title>Special meanings of certain escaped characters used with
|
|||
|
<command>echo</command> and <command>sed</command></title>
|
|||
|
|
|||
|
<varlistentry><term><token>\n</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\n</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\n</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>newline</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>means newline</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>\r</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\r</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\r</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>carriage return</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>means return</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>\t</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\t</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\t</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>tabulation</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>means tab</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>\v</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\v</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\v</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>vertical tabulation</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para> means vertical tab</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>\b</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\b</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\b</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>backspace</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>means backspace</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>\a</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\a</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\a</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>alert</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>beep</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>flash</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>means <quote>alert</quote> (beep or flash)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>\0xx</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\0xx</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\0xx</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>octal ASCII</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>translates to the octal ASCII
|
|||
|
equivalent of <replaceable>0xx</replaceable></para>
|
|||
|
|
|||
|
<example id="escaped">
|
|||
|
<title>Escaped Characters</title>
|
|||
|
<programlisting>&escaped;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See <xref linkend="ex77"> for another example of the
|
|||
|
<userinput>$' '</userinput> string expansion
|
|||
|
construct.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>\"</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\"</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\"</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>quote</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para> gives the quote its literal meaning</para>
|
|||
|
<para><programlisting>echo "Hello" # Hello
|
|||
|
echo "\"Hello\", he said." # "Hello", he said.</programlisting></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>\$</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\$</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\$</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>dollar</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>gives the dollar sign its literal meaning
|
|||
|
(variable name following <token>\$</token> will not be
|
|||
|
referenced)</para>
|
|||
|
<para><programlisting>echo "\$variable01" # results in $variable01</programlisting></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry><term><token>\\</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>\\</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\\</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>double backslash</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>gives the backslash its literal meaning</para>
|
|||
|
<para><programlisting>echo "\\" # results in \</programlisting></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<note><para>The behavior of <token>\</token> depends on whether
|
|||
|
it is itself escaped, quoted, or appearing within a <link
|
|||
|
linkend="heredocref">here document</link>.
|
|||
|
|
|||
|
<programlisting>echo \z # z
|
|||
|
echo \\z # \z
|
|||
|
echo '\z' # \z
|
|||
|
echo '\\z' # \\z
|
|||
|
echo "\z" # \z
|
|||
|
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
|
|||
|
echo `echo "\\z"` # \z
|
|||
|
|
|||
|
cat <<EOF
|
|||
|
\z
|
|||
|
EOF # \z
|
|||
|
|
|||
|
cat <<EOF
|
|||
|
\\z
|
|||
|
EOF # \z
|
|||
|
|
|||
|
# These examples supplied by Stephane Chazelas.</programlisting>
|
|||
|
</para></note>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<para>Escaping a space can prevent word splitting in a command's argument list.
|
|||
|
<programlisting>file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
|
|||
|
# List of files as argument(s) to a command.
|
|||
|
|
|||
|
# Add two files to the list, and list all.
|
|||
|
ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list
|
|||
|
|
|||
|
echo "-------------------------------------------------------------------------"
|
|||
|
|
|||
|
# What happens if we escape a couple of spaces?
|
|||
|
ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
|
|||
|
# Error: the first three files concatenated into a single argument to 'ls -l'
|
|||
|
# because the two escaped spaces prevent argument (word) splitting.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para>The <token>escape</token> also provides a means of writing a
|
|||
|
multi-line command. Normally, each separate line constitutes
|
|||
|
a different command, but an <token>escape</token> at the end
|
|||
|
of a line <emphasis>escapes the newline character</emphasis>,
|
|||
|
and the command sequence continues on to the next line.</para>
|
|||
|
<para><programlisting>(cd /source/directory && tar cf - . ) | \
|
|||
|
(cd /dest/directory && tar xpvf -)
|
|||
|
# Repeating Alan Cox's directory tree copy command,
|
|||
|
# but split into two lines for increased legibility.
|
|||
|
|
|||
|
# As an alternative:
|
|||
|
tar cf - -C /source/directory |
|
|||
|
tar xpvf - -C /dest/directory
|
|||
|
# See note below.
|
|||
|
# (Thanks, Stephane Chazelas.)</programlisting>
|
|||
|
|
|||
|
<note><para>If a script line ends with a <token>|</token>, a pipe
|
|||
|
character, then a <token>\</token>, an escape, is not strictly
|
|||
|
necessary. It is, however, good programming practice to always
|
|||
|
escape the end of a line of code that continues to the
|
|||
|
following line.</para></note></para>
|
|||
|
|
|||
|
<para><programlisting>echo "foo
|
|||
|
bar"
|
|||
|
#foo
|
|||
|
#bar
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
echo 'foo
|
|||
|
bar' # No difference yet.
|
|||
|
#foo
|
|||
|
#bar
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
echo foo\
|
|||
|
bar # Newline escaped.
|
|||
|
#foobar
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
echo "foo\
|
|||
|
bar" # Same here, as \ still interpreted as escape within weak quotes.
|
|||
|
#foobar
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
echo 'foo\
|
|||
|
bar' # Escape character \ taken literally because of strong quoting.
|
|||
|
#foor\
|
|||
|
#bar
|
|||
|
|
|||
|
# Examples suggested by Stephane Chazelas.</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- Quoting -->
|
|||
|
|
|||
|
<sect1 id="tests">
|
|||
|
<title>Tests</title>
|
|||
|
|
|||
|
<para><anchor id="ifthen"></para>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>if</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>test</primary>
|
|||
|
<secondary>if</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>then</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>else if</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>elif</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
|
|||
|
<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>Bash also introduces the <link linkend="dblbrackets">[[ ... ]]</link>
|
|||
|
construct, which performs comparisons in a
|
|||
|
manner more familiar to programmers from other
|
|||
|
languages. Note that <command>[[</command> is a <link
|
|||
|
linkend="keywordref">keyword</link>, not a command.</para>
|
|||
|
|
|||
|
<para>Bash sees <userinput>[[ $a -lt $b ]]</userinput> as a
|
|||
|
single element, which returns an exit status.</para>
|
|||
|
|
|||
|
<para>The <link linkend="dblparens">(( ... ))</link> and <link
|
|||
|
linkend="letref">let ...</link> constructs also return an
|
|||
|
exit status of <returnvalue>0</returnvalue> if the arithmetic
|
|||
|
expressions they evaluate expand to a non-zero value. These
|
|||
|
<link linkend="arithexpref">arithmetic expansion</link>
|
|||
|
constructs may therefore be used to perform arithmetic
|
|||
|
comparisons.
|
|||
|
|
|||
|
<programlisting>let "1<2" returns 0 (as "1<2" expands to "1")
|
|||
|
(( 0 && 1 )) returns 1 (as "0 && 1" expands to "0")</programlisting>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>An <command>if</command> can test any command, not just
|
|||
|
conditions enclosed within brackets.
|
|||
|
<programlisting>if cmp a b > /dev/null # Suppress output.
|
|||
|
then echo "Files a and b are identical."
|
|||
|
else echo "Files a and b differ."
|
|||
|
fi
|
|||
|
|
|||
|
if grep -q Bash file
|
|||
|
then echo "File contains at least one occurrence of Bash."
|
|||
|
fi
|
|||
|
|
|||
|
if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED
|
|||
|
then echo "Command succeeded."
|
|||
|
else echo "Command failed."
|
|||
|
fi</programlisting>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>An <command>if/then</command> construct can contain nested
|
|||
|
comparisons and tests.
|
|||
|
<programlisting>if echo "Next *if* is part of the comparison for the first *if*."
|
|||
|
|
|||
|
if [[ $comparison = "integer" ]]
|
|||
|
then (( a < b ))
|
|||
|
else
|
|||
|
[[ $a < $b ]]
|
|||
|
fi
|
|||
|
|
|||
|
then
|
|||
|
echo '$a is less than $b'
|
|||
|
fi</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para><emphasis>This detailed <quote>if-test</quote> explanation
|
|||
|
courtesy of Stephane Chazelas.</emphasis></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<example id="ex10">
|
|||
|
<title>What is truth?</title>
|
|||
|
<programlisting>&ex10;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<formalpara><title>Exercise</title>
|
|||
|
<para>Explain the behavior of <xref linkend="ex10">, above.</para>
|
|||
|
</formalpara>
|
|||
|
|
|||
|
<para><programlisting>if [ condition-true ]
|
|||
|
then
|
|||
|
command 1
|
|||
|
command 2
|
|||
|
...
|
|||
|
else
|
|||
|
# Optional (may be left out if not needed).
|
|||
|
# Adds default code block executing if original condition tests false.
|
|||
|
command 3
|
|||
|
command 4
|
|||
|
...
|
|||
|
fi</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Add a semicolon when 'if' and 'then' are on same line.</para>
|
|||
|
<para><programlisting>if [ -x "$filename" ]; then</programlisting></para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term><token>elif</token></term>
|
|||
|
<listitem><para> This is a contraction for <token>else if</token>.
|
|||
|
The effect is to nest an inner <token>if/then</token> construction
|
|||
|
within an outer one.</para>
|
|||
|
|
|||
|
<para><programlisting>if [ condition1 ]
|
|||
|
then
|
|||
|
command1
|
|||
|
command2
|
|||
|
command3
|
|||
|
elif [ condition2 ]
|
|||
|
# Same as else if
|
|||
|
then
|
|||
|
command4
|
|||
|
command5
|
|||
|
else
|
|||
|
default-command
|
|||
|
fi</programlisting>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<para>
|
|||
|
<indexterm>
|
|||
|
<primary>test</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>test</primary>
|
|||
|
<secondary>test</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>[</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>[</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>]</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>]</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
The <userinput>if test condition-true</userinput> construct is the
|
|||
|
exact equivalent of <userinput>if [ condition-true ]</userinput>.
|
|||
|
As it happens, the left bracket, <command>[</command> , is a token
|
|||
|
which invokes the <command>test</command> command. The closing
|
|||
|
right bracket, <command>]</command> , in an if/test should not
|
|||
|
therefore be strictly necessary, however newer versions of Bash
|
|||
|
require it.</para>
|
|||
|
|
|||
|
<note><para>The <command>test</command> command is a Bash <link
|
|||
|
linkend="builtinref">builtin</link> which tests file
|
|||
|
types and compares strings. Therefore, in a Bash script,
|
|||
|
<command>test</command> does <emphasis>not</emphasis> call
|
|||
|
the external <filename>/usr/bin/test</filename> binary,
|
|||
|
which is part of the <emphasis>sh-utils</emphasis>
|
|||
|
package. Likewise, <token>[</token> does not call
|
|||
|
<filename>/usr/bin/[</filename>, which is linked to
|
|||
|
<filename>/usr/bin/test</filename>.</para></note>
|
|||
|
|
|||
|
<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>
|
|||
|
|
|||
|
|
|||
|
<example id="ex11">
|
|||
|
<title>Equivalence of <token>[ ]</token> and <token>test</token></title>
|
|||
|
<programlisting>&ex11;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>test</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>test</primary>
|
|||
|
<secondary>test</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>[[</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>[[</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>]]</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>]]</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para><anchor id="dblbrackets">The <token>[[ ]]</token> construct
|
|||
|
is the shell equivalent of <token>[ ]</token>. No filename
|
|||
|
expansion or word splitting take 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>
|
|||
|
|
|||
|
<tip>
|
|||
|
<para>Using the newer <command>[[ ... ]]</command> test construct,
|
|||
|
rather than <command>[ ... ]</command> can prevent many logic
|
|||
|
errors in scripts.</para>
|
|||
|
</tip>
|
|||
|
|
|||
|
<note>
|
|||
|
<para>Following an <command>if</command>, neither the
|
|||
|
<command>test</command> command nor the test brackets ( [ ] or [[ ]] )
|
|||
|
are strictly necessary.
|
|||
|
|
|||
|
<programlisting>dir=/home/bozo
|
|||
|
|
|||
|
if cd "$dir" 2>/dev/null; then # "2>/dev/null" hides error message.
|
|||
|
echo "Now in $dir."
|
|||
|
else
|
|||
|
echo "Can't change to $dir."
|
|||
|
fi</programlisting>
|
|||
|
|
|||
|
The "if COMMAND" construct returns the exit status of COMMAND.
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para>Similarly, a condition within test brackets may stand alone
|
|||
|
without an <command>if</command>, when used in combination
|
|||
|
with a <link linkend="listconsref">list construct</link>.
|
|||
|
|
|||
|
<programlisting>var1=20
|
|||
|
var2=22
|
|||
|
[ "$var1" -ne "$var2" ] && echo "$var1 is not equal to $var2"
|
|||
|
|
|||
|
home=/home/bozo
|
|||
|
[ -d "$home" ] || echo "$home directory does not exist."</programlisting></para>
|
|||
|
</note>
|
|||
|
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>test</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>test</primary>
|
|||
|
<secondary>test</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>((</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>))</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>((</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>))</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para>The <link linkend="dblparens">(( )) construct</link> expands
|
|||
|
and evaluates an arithmetic expression. If
|
|||
|
the expression evaluates as zero, it returns an
|
|||
|
<link linkend="exitstatusref">exit status</link> of
|
|||
|
<returnvalue>1</returnvalue>, or <quote>false</quote>. A non-zero
|
|||
|
expression returns an exit status of <returnvalue>0</returnvalue>,
|
|||
|
or <quote>true</quote>. This is in marked contrast to using
|
|||
|
the <command>test</command> and <token>[ ]</token> constructs
|
|||
|
previously discussed.</para>
|
|||
|
|
|||
|
<example id="arithtests">
|
|||
|
<title>Arithmetic Tests using <token>(( ))</token></title>
|
|||
|
<programlisting>&arithtests;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<sect2>
|
|||
|
<title>File test operators</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<title>Returns true if...</title>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-e</token></term>
|
|||
|
<listitem><para>file exists</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-f</token></term>
|
|||
|
<listitem><para>file is a <replaceable>regular</replaceable>
|
|||
|
file (not a directory or device file)</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-s</token></term>
|
|||
|
<listitem><para>file is not zero size</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-d</token></term>
|
|||
|
<listitem><para>file is a directory</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-b</token></term>
|
|||
|
<listitem><para>file is a block device (floppy, cdrom, etc.)
|
|||
|
</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-c</token></term>
|
|||
|
<listitem><para>file is a character device (keyboard, modem, sound
|
|||
|
card, etc.)</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-p</token></term>
|
|||
|
<listitem><para>file is a pipe</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-h</token></term>
|
|||
|
<listitem><para>file is a symbolic link</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-L</token></term>
|
|||
|
<listitem><para>file is a symbolic link</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-S</token></term>
|
|||
|
<listitem><para>file is a socket</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-t</token></term>
|
|||
|
<listitem>
|
|||
|
<para>file (<link linkend="fdref">descriptor</link>) is
|
|||
|
associated with a terminal device</para>
|
|||
|
<para>This test option may be used to check whether the
|
|||
|
<filename>stdin</filename> (<userinput>[ -t 0 ]</userinput>)
|
|||
|
or <filename>stdout</filename> (<userinput>[ -t 1 ]</userinput>)
|
|||
|
in a given script is a terminal.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-r</token></term>
|
|||
|
<listitem><para>file has read permission (<emphasis>for the
|
|||
|
user running the test</emphasis>)</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-w</token></term>
|
|||
|
<listitem><para>file has write permission (for the user running
|
|||
|
the test)</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-x</token></term>
|
|||
|
<listitem><para>file has execute permission (for the user running
|
|||
|
the test)</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-g</token></term>
|
|||
|
<listitem>
|
|||
|
<para>set-group-id (sgid) flag set on file or directory</para>
|
|||
|
<para>If a directory has the <replaceable>sgid</replaceable>
|
|||
|
flag set, then a file created within that directory belongs
|
|||
|
to the group that owns the directory, not necessarily to
|
|||
|
the group of the user who created the file. This may be
|
|||
|
useful for a directory shared by a workgroup.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-u</token></term>
|
|||
|
<listitem>
|
|||
|
<para>set-user-id (suid) flag set on file</para>
|
|||
|
<para>A binary owned by <emphasis>root</emphasis>
|
|||
|
with <replaceable>set-user-id</replaceable> flag set
|
|||
|
runs with <emphasis>root</emphasis> privileges, even
|
|||
|
when an ordinary user invokes it.
|
|||
|
|
|||
|
<footnote><para>Be aware that <emphasis>suid</emphasis>
|
|||
|
binaries may open security holes and that the
|
|||
|
<emphasis>suid</emphasis> flag should not be set on
|
|||
|
shell scripts.</para></footnote>
|
|||
|
|
|||
|
This is useful for executables (such as
|
|||
|
<command>pppd</command> and <command>cdrecord</command>)
|
|||
|
that need to access system hardware. Lacking the
|
|||
|
<emphasis>suid</emphasis> flag, these binaries could not
|
|||
|
be invoked by a non-root user.
|
|||
|
|
|||
|
<screen>
|
|||
|
<computeroutput>-rwsr-xr-t 1 root 178236 Oct 2 2000 /usr/sbin/pppd</computeroutput>
|
|||
|
</screen>
|
|||
|
|
|||
|
A file with the <replaceable>suid</replaceable> flag set shows
|
|||
|
an <emphasis>s</emphasis> in its permissions.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-k</token></term>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para><replaceable>sticky bit</replaceable> set</para>
|
|||
|
|
|||
|
<para>Commonly known as the <quote>sticky bit</quote>, the
|
|||
|
<emphasis>save-text-mode</emphasis> flag is a special
|
|||
|
type of file permission. If a file has this flag set,
|
|||
|
that file will be kept in cache memory, for quicker access.
|
|||
|
<footnote><para>On modern UNIX systems, the sticky
|
|||
|
bit is no longer used for files, only on
|
|||
|
directories.</para></footnote>
|
|||
|
If set on a directory, it restricts write permission.
|
|||
|
Setting the sticky bit adds a <emphasis>t</emphasis>
|
|||
|
to the permissions on the file or directory listing.
|
|||
|
|
|||
|
<screen>
|
|||
|
<computeroutput>drwxrwxrwt 7 root 1024 May 19 21:26 tmp/</computeroutput>
|
|||
|
</screen>
|
|||
|
|
|||
|
If a user does not own a directory that has the sticky
|
|||
|
bit set, but has write permission in that directory,
|
|||
|
he can only delete files in it that he owns. This keeps
|
|||
|
users from inadvertently overwriting or deleting each
|
|||
|
other's files in a publicly accessible directory, such
|
|||
|
as <filename class="directory">/tmp</filename>.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-O</token></term>
|
|||
|
<listitem><para>you are owner of file</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-G</token></term>
|
|||
|
<listitem><para>group-id of file same as yours</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-N</token></term>
|
|||
|
<listitem><para>file modified since it was last read</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>f1 -nt f2</token></term>
|
|||
|
<listitem><para>file <replaceable>f1</replaceable> is newer than
|
|||
|
<replaceable>f2</replaceable></para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>f1 -ot f2</token></term>
|
|||
|
<listitem><para>file <replaceable>f1</replaceable> is older than
|
|||
|
<replaceable>f2</replaceable></para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>f1 -ef f2</token></term>
|
|||
|
<listitem><para>files <replaceable>f1</replaceable> and
|
|||
|
<replaceable>f2</replaceable> are hard links to the same
|
|||
|
file</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>!</token></term>
|
|||
|
<listitem><para><quote>not</quote> -- reverses the sense of the
|
|||
|
tests above (returns true if condition absent).</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<para><xref linkend="cookies">, <xref linkend="bingrep">,
|
|||
|
<xref linkend="fileinfo">, and <xref linkend="mailformat">
|
|||
|
illustrate uses of the file test operators.</para>
|
|||
|
|
|||
|
|
|||
|
</sect2> <!-- File test operators -->
|
|||
|
|
|||
|
<sect2>
|
|||
|
<title>Comparison operators (binary)</title>
|
|||
|
<variablelist>
|
|||
|
<title><anchor id="equalref">integer comparison</title>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-eq</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is equal to</para>
|
|||
|
<para><userinput>if [ "$a" -eq "$b" ]</userinput></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-ne</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is not equal to</para>
|
|||
|
<para><userinput>if [ "$a" -ne "$b" ]</userinput></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-gt</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is greater than</para>
|
|||
|
<para><userinput>if ["$a" -gt "$b" ]</userinput></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-ge</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is greater than or equal to</para>
|
|||
|
<para><userinput>if [ "$a" -ge "$b" ]</userinput></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-lt</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is less than</para>
|
|||
|
<para><userinput>if [ "$a" -lt "$b" ]</userinput></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-le</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is less than or equal to</para>
|
|||
|
<para><userinput>if [ "$a" -le "$b" ]</userinput></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<title><anchor id="equalsignref">string comparison</title>
|
|||
|
<varlistentry>
|
|||
|
<term><token>=</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is equal to</para>
|
|||
|
<para><userinput>if [ "$a" = "$b" ]</userinput></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>==</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is equal to</para>
|
|||
|
<para><userinput>if [ "$a" == "$b" ]</userinput></para>
|
|||
|
<para>This is a synonym for <token>=</token>.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<programlisting>[[ $a == z* ]] # true if $a starts with an "z" (pattern matching)
|
|||
|
[[ $a == "z*" ]] # true if $a is equal to z*
|
|||
|
|
|||
|
[ $a == z* ] # file globbing and word splitting take place
|
|||
|
[ "$a" == "z*" ] # true if $a is equal to z*
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>!=</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is not equal to</para>
|
|||
|
<para><userinput>if [ "$a" != "$b" ]</userinput></para>
|
|||
|
<para>This operator uses pattern matching within a <link
|
|||
|
linkend="dblbrackets">[[ ... ]]</link> construct.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>\<</token></term>
|
|||
|
<listitem>
|
|||
|
<para>is less than, in ASCII alphabetical order</para>
|
|||
|
<para><userinput>if [ "$a" \< "$b" ]</userinput></para>
|
|||
|
<para>Note that the <quote><</quote> needs to be
|
|||
|
escaped.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>\></token></term>
|
|||
|
<listitem>
|
|||
|
<para>is greater than, in ASCII alphabetical order</para>
|
|||
|
<para><userinput>if [ "$a" \> "$b" ]</userinput></para>
|
|||
|
<para>Note that the <quote>></quote> needs to be
|
|||
|
escaped.</para>
|
|||
|
<para>See <xref linkend="bubble"> for an application of this
|
|||
|
comparison operator.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-z</token></term>
|
|||
|
<listitem><para>string is <quote>null</quote>, that is, has zero length</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-n</token></term>
|
|||
|
<listitem>
|
|||
|
<para>string is not <quote>null</quote>.</para>
|
|||
|
|
|||
|
<caution><para>The <userinput>-n</userinput> test absolutely
|
|||
|
requires that the string be quoted within the
|
|||
|
test brackets. Using an unquoted string with
|
|||
|
<userinput>! -z</userinput>, or even just the
|
|||
|
unquoted string alone within test brackets (see <xref
|
|||
|
linkend="strtest">) normally works, however, this is
|
|||
|
an unsafe practice. <emphasis>Always</emphasis> quote
|
|||
|
a tested string.
|
|||
|
<footnote><para>As S.C. points out, in a compound test,
|
|||
|
even quoting the string variable might not
|
|||
|
suffice. <userinput>[ -n "$string" -o "$a" =
|
|||
|
"$b" ]</userinput> may cause an error with some
|
|||
|
versions of Bash if <varname>$string</varname>
|
|||
|
is empty. The safe way is to append an extra
|
|||
|
character to possibly empty variables, <userinput>[
|
|||
|
"x$string" != x -o "x$a" = "x$b" ]</userinput>
|
|||
|
(the <quote>x's</quote> cancel out).</para></footnote>
|
|||
|
</para></caution>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<example id="ex13">
|
|||
|
<title>arithmetic and string comparisons</title>
|
|||
|
<programlisting>&ex13;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="strtest">
|
|||
|
<title>testing whether a string is <emphasis>null</emphasis></title>
|
|||
|
<programlisting>&strtest;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ex14">
|
|||
|
<title><command>zmost</command></title>
|
|||
|
<programlisting>&ex14;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<title>compound comparison</title>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-a</token></term>
|
|||
|
<listitem>
|
|||
|
<para>logical and</para>
|
|||
|
<para><replaceable>exp1 -a exp2</replaceable> returns true if
|
|||
|
<emphasis>both</emphasis> exp1 and exp2 are true.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-o</token></term>
|
|||
|
<listitem>
|
|||
|
<para>logical or </para>
|
|||
|
<para><replaceable>exp1 -o exp2</replaceable> returns
|
|||
|
true if either exp1 <emphasis>or</emphasis> exp2 are
|
|||
|
true.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<para>These are similar to the Bash comparison operators
|
|||
|
<command>&&</command> and <command>||</command>, used
|
|||
|
within <link linkend="dblbrackets">double brackets</link>.
|
|||
|
<programlisting>[[ condition1 && condition2 ]]</programlisting>
|
|||
|
The <command>-o</command> and <command>-a</command> operators
|
|||
|
work with the <command>test</command> command or occur within
|
|||
|
test brackets.
|
|||
|
<programlisting>if [ "$exp1" -a "$exp2" ]</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Refer to <xref linkend="andor"> and <xref linkend="twodim">
|
|||
|
to see compound comparison operators in action.</para>
|
|||
|
|
|||
|
</sect2> <!-- Comparison operators (binary) -->
|
|||
|
|
|||
|
<sect2 id="nestedifthen">
|
|||
|
<title>Nested if/then Condition Tests</title>
|
|||
|
|
|||
|
<para>Condition tests using the <command>if/then</command>
|
|||
|
construct may be nested. The net result is identical to using the
|
|||
|
<command>&&</command> compound comparison operator above.</para>
|
|||
|
|
|||
|
<para><programlisting>if [ condition1 ]
|
|||
|
then
|
|||
|
if [ condition2 ]
|
|||
|
then
|
|||
|
do-something # But only if both "condition1" and "condition2" valid.
|
|||
|
fi
|
|||
|
fi</programlisting></para>
|
|||
|
|
|||
|
<para>See <xref linkend="ex79"> for an example of nested
|
|||
|
<replaceable>if/then</replaceable> condition tests.</para>
|
|||
|
|
|||
|
</sect2> <!-- Nested if/then Tests -->
|
|||
|
|
|||
|
</sect1> <!-- Tests -->
|
|||
|
|
|||
|
<sect1 id="operations">
|
|||
|
<title>Operations and Related Topics</title>
|
|||
|
|
|||
|
<sect2 id="ops">
|
|||
|
<title>Operators</title>
|
|||
|
|
|||
|
<variablelist><title>assignment</title>
|
|||
|
<varlistentry>
|
|||
|
<indexterm>
|
|||
|
<primary>=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>=</secondary>
|
|||
|
</indexterm>
|
|||
|
<term>=</term>
|
|||
|
<listitem><para>All-purpose assignment operator, which works for both arithmetic and
|
|||
|
string assignments.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<programlisting>var=27
|
|||
|
category=minerals # No spaces allowed after the "=".</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<caution>
|
|||
|
<para>Do not confuse the <quote>=</quote> assignment
|
|||
|
operator with the <link linkend="equalsignref">=</link> test
|
|||
|
operator.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<programlisting># = as a test operator
|
|||
|
|
|||
|
if [ "$string1" = "$string2" ]
|
|||
|
# if [ "Xstring1" = "Xstring2" ] is safer,
|
|||
|
# to prevent an error message should one of the variables be empty.
|
|||
|
# (The prepended "X" characters cancel out.)
|
|||
|
then
|
|||
|
command
|
|||
|
fi</programlisting>
|
|||
|
</para>
|
|||
|
</caution>
|
|||
|
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>expr</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>expr</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>let</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>let</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
|
|||
|
<variablelist><title>arithmetic operators</title>
|
|||
|
<varlistentry>
|
|||
|
<term><token>+</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>+</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>+</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>addition</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>plus</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>plus</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>-</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>-</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>subtraction</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>minus</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>minus</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>*</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>*</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>*</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>multiplication</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>multiplication</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>/</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>/</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>/</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>division</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>division</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>%</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>%</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>%</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>modulo</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>modulo, or mod (returns the remainder of an integer
|
|||
|
division operation)</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>echo `expr 5 % 3`</userinput>
|
|||
|
<computeroutput>2</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>This operator finds use in, among other things,
|
|||
|
generating numbers within a specific range (see <xref
|
|||
|
linkend="ex21"> and <xref linkend="randomtest">)
|
|||
|
and formatting program output (see <xref
|
|||
|
linkend="qfunction">). It can even be used to generate prime
|
|||
|
numbers, (see <xref linkend="primes">).</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>+=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>+=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>+=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>plus-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>plus-equal</quote> (increment variable by a constant)</para>
|
|||
|
<para><userinput>let "var += 5"</userinput> results in
|
|||
|
<varname>var</varname> being incremented by
|
|||
|
<literal>5</literal>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>-=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>-=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>minus-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>minus-equal</quote> (decrement variable by a constant)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>*=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>*=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>*=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>times-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>times-equal</quote> (multiply variable by a constant)</para>
|
|||
|
<para><userinput>let "var *= 4"</userinput> results in <varname>var</varname>
|
|||
|
being multiplied by <literal>4</literal>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>/=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>/=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>/=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>slash-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>slash-equal</quote> (divide variable by a constant)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>%=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>%=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>%=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>mod-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>mod-equal</quote> (remainder of dividing variable by a constant)</para>
|
|||
|
|
|||
|
<para><emphasis>Arithmetic operators often occur in an
|
|||
|
<link linkend="exprref">expr</link> or <link
|
|||
|
linkend="letref">let</link> expression.</emphasis></para>
|
|||
|
|
|||
|
<example id="arithops">
|
|||
|
<title>Using Arithmetic Operations</title>
|
|||
|
<programlisting>&arithops;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<caution><para>Bash does not understand floating point arithmetic. It
|
|||
|
treats numbers containing a decimal point as strings.
|
|||
|
<programlisting>a=1.5
|
|||
|
|
|||
|
let "b = $a + 1.3" # Error.
|
|||
|
# t2.sh: let: b = 1.5 + 1.3: syntax error in expression (error token is ".5 + 1.3")
|
|||
|
|
|||
|
echo "b = $b" # b=1</programlisting>
|
|||
|
|
|||
|
Use <link linkend="bcref">bc</link> in scripts that that need floating
|
|||
|
point calculations or math library functions.</para></caution>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<formalpara><title>bitwise operators</title>
|
|||
|
<para>The bitwise operators seldom make an appearance in shell scripts.
|
|||
|
Their chief use seems to be manipulating and testing values
|
|||
|
read from ports or sockets. <quote>Bit flipping</quote> is more
|
|||
|
relevant to compiled languages, such as C and C++, which run
|
|||
|
fast enough to permit its use on the fly.</para></formalpara>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token><<</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary><<</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary><<</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>left shift</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>bitwise left shift (multiplies by <literal>2</literal>
|
|||
|
for each shift position)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token><<=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary><<=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary><<=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>left-shift-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>left-shift-equal</quote></para>
|
|||
|
<para><userinput>let "var <<= 2"</userinput> results in <varname>var</varname>
|
|||
|
left-shifted <literal>2</literal> bits (multiplied by <literal>4</literal>)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>>></token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>>></primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>>></secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>right shift</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>bitwise right shift (divides by <literal>2</literal>
|
|||
|
for each shift position)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>>>=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>>>=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>>>=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>right-shift-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>right-shift-equal</quote> (inverse of <token><<=</token>)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>&</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>&</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>&</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>AND</primary>
|
|||
|
<secondary>bitwise</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>bitwise and</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>&=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>&=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>&=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>and-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>bitwise and-equal</quote></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>|</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>|</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>|</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>OR</primary>
|
|||
|
<secondary>bitwise</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>bitwise OR</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>|=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>|=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>|=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>OR-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>bitwise OR-equal</quote></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>~</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>~</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>~</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>negate</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>bitwise negate</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>!</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>!</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>!</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>NOT</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>bitwise NOT</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>^</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>^</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>^</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>XOR</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>bitwise XOR</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>^=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>^=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>^=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>XOR-equal</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>bitwise XOR-equal</quote></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
|
|||
|
<variablelist><title>relational tests</title>
|
|||
|
<varlistentry>
|
|||
|
<term><token><</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary><</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary><</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>less than</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>less than</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>></token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>></primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>></secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>greater than</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>greater than</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token><=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary><=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary><=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>less than or equal to</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>less than or equal to</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>>=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>>=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>>=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>greater than or equal to</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>greater than or equal to</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>==</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>==</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>==</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>equal to</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>equal to (test)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>!=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>!=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operation</primary>
|
|||
|
<secondary>!=</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>not equal to</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>not equal to</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<variablelist><title>logical operators</title>
|
|||
|
<varlistentry>
|
|||
|
<term><token>&&</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>&&</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operator</primary>
|
|||
|
<secondary>&&</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>AND</primary>
|
|||
|
<secondary>logical</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>and (logical)</para>
|
|||
|
<para><programlisting>if [ $condition1 ] && [ $condition2 ]
|
|||
|
# Same as: if [ condition1 -a condition2 ]
|
|||
|
# Returns true if both condition1 and condition2 hold true...</programlisting></para>
|
|||
|
|
|||
|
<note><para><token>&&</token> may also, depending on context, be
|
|||
|
used in an <link linkend="listconsref">and list</link>
|
|||
|
to concatenate commands.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>||</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>||</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>operator</primary>
|
|||
|
<secondary>||</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>OR</primary>
|
|||
|
<secondary>logical</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>or (logical)</para>
|
|||
|
<para><programlisting>if [ $condition1 ] || [ $condition2 ]
|
|||
|
# Same as: if [ condition1 -o condition2 ]
|
|||
|
# Returns true if either condition1 or condition2 holds true...</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>
|
|||
|
|
|||
|
</sect2>
|
|||
|
|
|||
|
<sect2 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> is evaluated as
|
|||
|
<replaceable>BASE#NUMBER</replaceable> (this option is of limited
|
|||
|
usefulness because of range restrictions).</para>
|
|||
|
|
|||
|
<example id="numbers">
|
|||
|
<title>Representation of numerical constants<token>:</token></title>
|
|||
|
<programlisting>&numbers;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</sect2>
|
|||
|
|
|||
|
</sect1> <!-- Operations -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="variables2">
|
|||
|
<title>Variables Revisited</title>
|
|||
|
|
|||
|
<para>Used properly, variables can add power and flexibility
|
|||
|
to scripts. This requires learning their subtleties and
|
|||
|
nuances.</para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term><replaceable>Internal (<link
|
|||
|
linkend="builtinref">builtin</link>) variables</replaceable></term>
|
|||
|
<listitem><para>variables affecting bash script behavior</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$BASH</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$BASH</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$BASH</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>path to bash</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>the path to the <emphasis>Bash</emphasis>
|
|||
|
binary itself, usually <filename>/bin/bash</filename></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$BASH_ENV</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$BASH_ENV</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$BASH_ENV</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>an environmental variable pointing to a Bash startup
|
|||
|
file to be read when a script is invoked</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$BASH_VERSION</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$BASH_VERSION</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$BASH_VERSION</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>the version of Bash installed on the system</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>echo $BASH_VERSION</userinput>
|
|||
|
<computeroutput>2.04.12(1)-release</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>tcsh% </prompt><userinput>echo $BASH_VERSION</userinput>
|
|||
|
<computeroutput>BASH_VERSION: Undefined variable.</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Checking $BASH_VERSION is a good method of determining which
|
|||
|
shell is running. $SHELL does not necessarily give the correct
|
|||
|
answer.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="dirstackref"><varname>$DIRSTACK</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$DIRSTACK</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$DIRSTACK</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>directory stack</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>directory</primary>
|
|||
|
<secondary>stack</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>contents of the directory stack (affected by
|
|||
|
<link linkend="pushdref">pushd</link> and <link
|
|||
|
linkend="popdref">popd</link>)</para> <para>This
|
|||
|
builtin variable is the counterpart to the <link
|
|||
|
linkend="dirsd">dirs</link> command.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$EDITOR</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$EDITOR</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$EDITOR</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>editor</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>the default editor invoked by a script, usually
|
|||
|
<command>vi</command> or <command>emacs</command>.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="euidref"><varname>$EUID</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$EUID</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$EUID</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>effective user id</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><quote>effective</quote> user id number</para>
|
|||
|
<para>Identification number of whatever identity the
|
|||
|
current user has assumed, perhaps by means of <link
|
|||
|
linkend="suref">su</link>.</para>
|
|||
|
<caution><para>The <varname>$EUID</varname> is not necessarily
|
|||
|
the same as the <link
|
|||
|
linkend="uidref">$UID</link>.</para></caution>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="groupsref"><varname>$GROUPS</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$GROUPS</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$GROUPS</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>groups</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>groups current user belongs to</para>
|
|||
|
<para>This is a listing (array) of the group id numbers for
|
|||
|
current user, as recorded in
|
|||
|
<filename>/etc/passwd</filename>.
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="homedirref"><varname>$HOME</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$HOME</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$HOME</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>home directory</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>directory</primary>
|
|||
|
<secondary>home</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>home directory of the user, usually <filename
|
|||
|
class="directory">/home/username</filename> (see <xref
|
|||
|
linkend="ex6">)</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="hostnameref"><varname>$HOSTNAME</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$HOSTNAME</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$HOSTNAME</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>system name</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>name</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <link linkend="hnameref">hostname</link> command
|
|||
|
assigns the system name at bootup in an init script.
|
|||
|
However, the <function>gethostname()</function> function
|
|||
|
sets the Bash internal variable <varname>$HOSTNAME</varname>.
|
|||
|
See also <xref linkend="ex6">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$HOSTTYPE</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$HOSTTYPE</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$HOSTTYPE</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>host type</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>host type</para>
|
|||
|
<para>Like <link linkend="machtyperef">$MACHTYPE</link>,
|
|||
|
identifies the system hardware.</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>echo $HOSTTYPE</userinput>
|
|||
|
<computeroutput>i686</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="ifsref"><varname>$IFS</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$IFS</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$IFS</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>input field separator</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>input field separator</para>
|
|||
|
<para>This defaults to <link
|
|||
|
linkend="whitespaceref">whitespace</link> (space,
|
|||
|
tab, and newline), but may be changed, for example,
|
|||
|
to parse a comma-separated data file. Note that
|
|||
|
<link linkend="appref">$*</link> uses the first
|
|||
|
character held in <varname>$IFS</varname>. See <xref
|
|||
|
linkend="weirdvars">.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>echo $IFS | cat -vte</userinput>
|
|||
|
<computeroutput>$</computeroutput>
|
|||
|
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>bash -c 'set w x y z; IFS=":-;"; echo "$*"'</userinput>
|
|||
|
<computeroutput>w:x:y:z</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<caution><para><varname>$IFS</varname> does not handle whitespace
|
|||
|
the same as it does other characters.
|
|||
|
|
|||
|
<example id="ifsh">
|
|||
|
<title>$IFS and whitespace</title>
|
|||
|
<programlisting>&ifsh;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</para></caution>
|
|||
|
|
|||
|
<para>(Thanks, S. C., for clarification and examples.)</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$IGNOREEOF</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$IGNOREEOF</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$IGNOREEOF</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>ignore EOF</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>ignore EOF: how many end-of-files (control-D)
|
|||
|
the shell will ignore before logging out.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$LINENO</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$LINENO</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$LINENO</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>line number</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>This variable is the line number of the shell
|
|||
|
script in which this variable appears. It has significance only
|
|||
|
within the script in which it appears, and is chiefly useful for
|
|||
|
debugging purposes.</para>
|
|||
|
<para><programlisting>last_cmd_arg=$_ # Save it.
|
|||
|
|
|||
|
echo "At line number $LINENO, variable \"v1\" = $v1"
|
|||
|
echo "Last command argument processed = $last_cmd_arg"</programlisting></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="machtyperef"><varname>$MACHTYPE</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$MACHTYPE</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$MACHTYPE</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>machine type</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>machine type</para>
|
|||
|
<para>Identifies the system hardware.</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>echo $MACHTYPE</userinput>
|
|||
|
<computeroutput>i686-debian-linux-gnu</computeroutput></screen>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="oldpwd"><varname>$OLDPWD</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$OLDPWD</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$OLDPWD</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>previous working directory</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>directory</primary>
|
|||
|
<secondary>working</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>old working directory
|
|||
|
(<quote>OLD-print-working-directory</quote>,
|
|||
|
previous directory you were in)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$OSTYPE</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$OSTYPE</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$OSTYPE</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>os type</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>operating system type</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>echo $OSTYPE</userinput>
|
|||
|
<computeroutput>linux-gnu</computeroutput></screen>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="pathref"><varname>$PATH</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$PATH</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$PATH</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>path to binaries</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>path to binaries, usually
|
|||
|
<filename class="directory">/usr/bin/</filename>,
|
|||
|
<filename class="directory">/usr/X11R6/bin/</filename>,
|
|||
|
<filename class="directory">/usr/local/bin</filename>, etc.</para>
|
|||
|
|
|||
|
<para>When given a command, the shell automatically does
|
|||
|
a hash table search on the directories listed in the
|
|||
|
<emphasis>path</emphasis> for the executable. The
|
|||
|
path is stored in the environmental variable,
|
|||
|
<varname>$PATH</varname>, a list of directories,
|
|||
|
separated by colons. Normally, the system
|
|||
|
stores the <varname>$PATH</varname> definition
|
|||
|
in <filename>/etc/profile</filename> and/or
|
|||
|
<filename>~/.bashrc</filename> (see <xref
|
|||
|
linkend="files">).</para>
|
|||
|
|
|||
|
<para><screen><prompt>bash$ </prompt><command>echo $PATH</command>
|
|||
|
<computeroutput>/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin</computeroutput></screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para><userinput>PATH=${PATH}:/opt/bin</userinput> appends
|
|||
|
the <filename class="directory">/opt/bin</filename>
|
|||
|
directory to the current path. In a script, it may be
|
|||
|
expedient to temporarily add a directory to the path
|
|||
|
in this way. When the script exits, this restores the
|
|||
|
original <varname>$PATH</varname> (a child process, such
|
|||
|
as a script, may not change the environment of the parent
|
|||
|
process, the shell).</para>
|
|||
|
|
|||
|
<note><para>The current <quote>working directory</quote>,
|
|||
|
<filename class="directory">./</filename>, is usually
|
|||
|
omitted from the <varname>$PATH</varname> as a security
|
|||
|
measure.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="ppidref"><varname>$PPID</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$PPID</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$PPID</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>process id</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para></para>
|
|||
|
<para>The <varname>$PPID</varname> of a process is
|
|||
|
the process id (<varname>pid</varname>) of its parent process.
|
|||
|
|
|||
|
<footnote><para>The pid of the currently running script is
|
|||
|
<varname>$$</varname>, of course.</para></footnote>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Compare this with the <link
|
|||
|
linkend="pidofref">pidof</link> command.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="ps1ref"><varname>$PS1</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$PS1</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$PS1</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>prompt</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>This is the main prompt, seen at the command line.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$PS2</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$PS2</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$PS2</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>prompt</primary>
|
|||
|
<secondary>secondary</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>The secondary prompt, seen when additional input is
|
|||
|
expected. It displays as <quote>></quote>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$PS3</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$PS3</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$PS3</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>prompt</primary>
|
|||
|
<secondary>tertiary</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>The tertiary prompt, displayed in a
|
|||
|
<link linkend="selectref">select</link> loop (see <xref
|
|||
|
linkend="ex31">).</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$PS4</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$PS4</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$PS4</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>prompt</primary>
|
|||
|
<secondary>quartenary</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The quartenary prompt, shown at the beginning of
|
|||
|
each line of output when invoking a script with the
|
|||
|
<token>-x</token> <link linkend="optionsref">option</link>.
|
|||
|
It displays as <quote>+</quote>.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="pwdref"><varname>$PWD</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$PWD</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$PWD</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>working directory</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>directory</primary>
|
|||
|
<secondary>working</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>working directory (directory you are in at the time)</para>
|
|||
|
<para>This is the analog to the <link linkend="pwd2ref">pwd</link>
|
|||
|
builtin command.</para>
|
|||
|
<para><programlisting>&wipedir;</programlisting></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$REPLY</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$REPLY</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$REPLY</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>default value of read</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>reply</primary>
|
|||
|
<secondary>read</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>The default value when a variable is not
|
|||
|
supplied to <link linkend="readref">read</link>. Also
|
|||
|
applicable to <link linkend="selectref">select</link> menus,
|
|||
|
but only supplies the item number of the variable chosen,
|
|||
|
not the value of the variable itself.</para>
|
|||
|
<para><programlisting>&reply;</programlisting></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$SECONDS</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$SECONDS</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$SECONDS</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>number of seconds the script has been running</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>runtime</primary>
|
|||
|
<secondary>seconds</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>The number of seconds the script has been running.</para>
|
|||
|
<para><programlisting>&seconds;</programlisting></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$SHELLOPTS</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$SHELLOPTS</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$SHELLOPTS</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>shell options</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>the list of enabled shell <link
|
|||
|
linkend="optionsref">options</link>, a readonly
|
|||
|
variable</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$TMOUT</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$TMOUT</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$TMOUT</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>timeout interval</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>If the <replaceable>$TMOUT</replaceable>
|
|||
|
environmental variable is set to a non-zero value
|
|||
|
<emphasis>time</emphasis>, then the shell prompt will time out
|
|||
|
after <emphasis>time</emphasis> seconds. This will cause a
|
|||
|
logout.</para>
|
|||
|
|
|||
|
<note><para>Unfortunately, this works only while waiting
|
|||
|
for input at the shell prompt console or in an xterm. While
|
|||
|
it would be nice to speculate on the uses of this
|
|||
|
internal variable for timed input, for example in
|
|||
|
combination with <link linkend="readref">read</link>,
|
|||
|
<replaceable>$TMOUT</replaceable> does not work
|
|||
|
in that context and is virtually useless for shell
|
|||
|
scripting. (Reportedly the <emphasis>ksh</emphasis> version
|
|||
|
of a timed <command>read</command> does work).</para></note>
|
|||
|
|
|||
|
<para>Implementing timed input in a script is certainly
|
|||
|
possible, but hardly seems worth the effort. One method is to
|
|||
|
set up a timing loop to signal the script when it times out.
|
|||
|
This also requires a signal handling routine to trap (see
|
|||
|
<xref linkend="ex76">) the interrupt generated by the timing
|
|||
|
loop (whew!).</para>
|
|||
|
|
|||
|
<example id="tmdin">
|
|||
|
<title>Timed Input</title>
|
|||
|
<programlisting>&tmdin;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>An alternative is using <link
|
|||
|
linkend="sttyref">stty</link>.</para>
|
|||
|
|
|||
|
<example id="timeout">
|
|||
|
<title>Once more, timed input</title>
|
|||
|
<programlisting>&timeout;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="uidref"><varname>$UID</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$UID</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$UID</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>user id</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>user id number</para>
|
|||
|
|
|||
|
<para>current user's user identification number, as
|
|||
|
recorded in <filename>/etc/passwd</filename>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>This is the current user's real id, even if she has
|
|||
|
temporarily assumed another identity through <link
|
|||
|
linkend="suref">su</link>. <varname>$UID</varname> is a
|
|||
|
readonly variable, not subject to change from the command
|
|||
|
line or within a script, and is the counterpart to the
|
|||
|
<link linkend="idref">id</link> builtin.</para>
|
|||
|
|
|||
|
<example id="amiroot">
|
|||
|
<title>Am I root?</title>
|
|||
|
<programlisting>&amiroot;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See also <xref linkend="ex2">.</para>
|
|||
|
|
|||
|
|
|||
|
<!-- Nest note within last entry -->
|
|||
|
<note><para>The variables <varname>$USER</varname>,
|
|||
|
<varname>$USERNAME</varname>, <varname>$LOGNAME</varname>,
|
|||
|
<varname>$MAIL</varname>, and <varname>$ENV</varname>
|
|||
|
are <emphasis>not</emphasis> Bash <link
|
|||
|
linkend="builtinref">builtins</link>. These are,
|
|||
|
however, often set as environmental variables
|
|||
|
in one of the Bash <link linkend="filesref">startup
|
|||
|
files</link>. <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></note>
|
|||
|
<!-- Nest note within last entry -->
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<!-- Last entry of intrinsic BASH variables -->
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="posparamref"><varname>$0</varname>, <varname>$1</varname>,
|
|||
|
<varname>$2</varname>, etc.</term>
|
|||
|
<indexterm>
|
|||
|
<primary>$0</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$0</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>positional parameter</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>parameter</primary>
|
|||
|
<secondary>positional</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>positional parameters, passed from command
|
|||
|
line to script, passed to a function, or <link
|
|||
|
linkend="setref">set</link> to a variable (see <xref
|
|||
|
linkend="ex17"> and <xref linkend="ex34">)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$#</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$#</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$#</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>positional parameter</primary>
|
|||
|
<secondary>number of</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>parameter</primary>
|
|||
|
<secondary>positional</secondary>
|
|||
|
<tertiary>number of</tertiary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>number of command line arguments
|
|||
|
<footnote><para>The words <quote>argument</quote>
|
|||
|
and <quote>parameter</quote> are often used
|
|||
|
interchangeably. In the context of this document, they
|
|||
|
have the same precise meaning, that of a variable passed
|
|||
|
to a script or function.</para></footnote>
|
|||
|
or positional parameters (see <xref linkend="ex4">)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$$</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$$</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$$</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>PID</primary>
|
|||
|
<secondary>of script</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>process id of script, often used in scripts
|
|||
|
to construct temp file names (see <xref linkend="ftpget"> and
|
|||
|
<xref linkend="online">)</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="xstatvarref"><varname>$?</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$?</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$?</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>exit status</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para><link linkend="exitstatusref">exit status</link>
|
|||
|
of a command, <link linkend="functionref">function</link>,
|
|||
|
or the script itself (see <xref linkend="max">)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="appref"><varname>$*</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$*</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$*</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>positional parameter</primary>
|
|||
|
<secondary>all</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>parameter</primary>
|
|||
|
<secondary>positional</secondary>
|
|||
|
<tertiary>all</tertiary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>All of the positional parameters, seen as a single
|
|||
|
word</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$@</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$@</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$*</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>positional parameter</primary>
|
|||
|
<secondary>all</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>Same as <token>$*</token>, but each parameter is a
|
|||
|
quoted string, that is, the parameters are passed on
|
|||
|
intact, without interpretation or expansion. This means,
|
|||
|
among other things, that each parameter in the argument
|
|||
|
list is seen as a separate word.</para>
|
|||
|
|
|||
|
<example id="arglist">
|
|||
|
<title><command>arglist</command>: Listing arguments with $* and $@</title>
|
|||
|
<programlisting>&arglist;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<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">.</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>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="flpref"><varname>$-</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$-</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$-</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>flags</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Flags passed to script</para>
|
|||
|
<caution><para>This was originally a <emphasis>ksh</emphasis>
|
|||
|
construct adopted into Bash, and unfortunately it does not
|
|||
|
seem to work reliably in Bash scripts. One possible use
|
|||
|
for it is to have a script <link linkend="iitest">self-test
|
|||
|
whether it is interactive</link>.</para></caution>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><varname>$!</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$!</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$!</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>PID</primary>
|
|||
|
<secondary>last job run in background</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>PID (process id) of last job run in background</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="underscoreref"><varname>$_</varname></term>
|
|||
|
<indexterm>
|
|||
|
<primary>$_</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$_</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>underscore</primary>
|
|||
|
<secondary>last argument</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Special variable set to last argument of previous command
|
|||
|
executed.</para>
|
|||
|
|
|||
|
|
|||
|
<example id="uscref">
|
|||
|
<title>underscore variable</title>
|
|||
|
<programlisting>#!/bin/bash
|
|||
|
|
|||
|
echo $_ # bash
|
|||
|
# Just executed "bash" to run script.
|
|||
|
|
|||
|
du
|
|||
|
echo $_ # du
|
|||
|
|
|||
|
ls -al
|
|||
|
echo $_ # -al
|
|||
|
# (last argument)
|
|||
|
|
|||
|
:
|
|||
|
echo $_ # :</programlisting></example>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><replaceable>variable assignment</replaceable></term>
|
|||
|
<listitem><para>Initializing or changing the value of a variable</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>=</token></term>
|
|||
|
<indexterm>
|
|||
|
<primary>=</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>assignment</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>the assignment operator (<emphasis>no space before &
|
|||
|
after</emphasis>)</para>
|
|||
|
|
|||
|
|
|||
|
<caution>
|
|||
|
<para>Do not confuse this with <link
|
|||
|
linkend="equalsignref">=</link> and <link
|
|||
|
linkend="equalref">-eq</link>, which test, rather than
|
|||
|
assign!</para>
|
|||
|
|
|||
|
<para>Note that <token>=</token> can be either an assignment
|
|||
|
or a test operator, depending on context.</para>
|
|||
|
</caution>
|
|||
|
|
|||
|
|
|||
|
<example id="ex15">
|
|||
|
<title>Variable Assignment</title>
|
|||
|
<programlisting>&ex15;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ex16">
|
|||
|
<title>Variable Assignment, plain and fancy</title>
|
|||
|
<programlisting>&ex16;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Variable assignment using the <token>$()</token> mechanism
|
|||
|
(a newer method than <link
|
|||
|
linkend="backquotesref">backquotes</link>)</para>
|
|||
|
|
|||
|
<para><programlisting># From /etc/rc.d/rc.local
|
|||
|
R=$(cat /etc/redhat-release)
|
|||
|
arch=$(uname -m)</programlisting></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><replaceable>local variables</replaceable></term>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>local</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem><para>variables visible only within a <link
|
|||
|
linkend="codeblockref">code block</link> or function
|
|||
|
(see also <link linkend="localref">local variables</link>
|
|||
|
in <link linkend="functionref">functions</link>)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><replaceable>environmental variables</replaceable></term>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>environmental</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>variables that affect the behavior of the shell and
|
|||
|
user interface</para>
|
|||
|
|
|||
|
<note>
|
|||
|
|
|||
|
<para>In a more general context, each process has an
|
|||
|
<quote>environment</quote>, that is, a group of
|
|||
|
variables that hold information that the process
|
|||
|
may reference. In this sense, the shell behaves like
|
|||
|
any other process.</para>
|
|||
|
|
|||
|
<para>Every time a shell starts, it creates shell variables that
|
|||
|
correspond to its own environmental variables. Updating or
|
|||
|
adding new shell variables causes the shell to update its
|
|||
|
environment, and all the shell's child processes (the commands
|
|||
|
it executes) inherit this environment.</para>
|
|||
|
|
|||
|
</note>
|
|||
|
|
|||
|
<caution>
|
|||
|
<para>The space allotted to the environment is limited.
|
|||
|
Creating too many environmental variables or ones that use up
|
|||
|
excessive space may cause problems.</para>
|
|||
|
<para>
|
|||
|
<screen>
|
|||
|
<prompt>bash$ </prompt><userinput>eval "`seq 10000 | sed -e 's/.*/export var&=ZZZZZZZZZZZZZZ/'`"</userinput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>du</userinput>
|
|||
|
<computeroutput>bash: /usr/bin/du: Argument list too long</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
<para>(Thank you, S. C. for the clarification, and
|
|||
|
for providing the above example.)</para>
|
|||
|
</caution>
|
|||
|
|
|||
|
<para>If a script sets environmental variables, they need to be
|
|||
|
<quote>exported</quote>, that is, reported to the
|
|||
|
environment local to the script. This is the function of
|
|||
|
the <link linkend="exportref">export</link> command.</para>
|
|||
|
|
|||
|
<note><para>A script can <command>export</command> variables only
|
|||
|
to child processes, that is, only to commands or processes
|
|||
|
which that particular script initiates. A script invoked
|
|||
|
from the command line <replaceable>cannot</replaceable>
|
|||
|
export variables back to the command line environment. <link
|
|||
|
linkend="forkref">Child processes</link> cannot export
|
|||
|
variables back to the parent processes that spawned
|
|||
|
them.</para></note>
|
|||
|
|
|||
|
<para>---</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><replaceable>positional parameters</replaceable></term>
|
|||
|
<indexterm>
|
|||
|
<primary>parameter</primary>
|
|||
|
<secondary>positional</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>arguments passed to the script from the command
|
|||
|
line - $0, $1, $2, $3... $0 is the name of the script
|
|||
|
itself, $1 is the first argument, $2 the second, $3 the
|
|||
|
third, and so forth.
|
|||
|
|
|||
|
<footnote><para>The process calling the script sets the
|
|||
|
<replaceable>$0</replaceable> parameter. By convention, this
|
|||
|
parameter is the name of the script. See the man page for
|
|||
|
<command>execv</command>.</para></footnote>
|
|||
|
|
|||
|
After $9, the arguments must be enclosed in brackets,
|
|||
|
for example, ${10}, ${11}, ${12}.</para>
|
|||
|
|
|||
|
<example id="ex17">
|
|||
|
<title>Positional Parameters</title>
|
|||
|
<programlisting>&ex17;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Some scripts can perform different operations,
|
|||
|
depending on which name they are invoked with. For this
|
|||
|
to work, the script needs to check <varname>$0</varname>,
|
|||
|
the name it was invoked by. There must also exist symbolic
|
|||
|
links to all the alternate names of the script.</para>
|
|||
|
|
|||
|
<tip><para>If a script expects a command line parameter
|
|||
|
but is invoked without one, this may cause a null variable
|
|||
|
assignment, generally an undesirable result. One way to prevent
|
|||
|
this is to append an extra character to both sides of the
|
|||
|
assignment statement using the expected positional parameter.
|
|||
|
</para></tip>
|
|||
|
|
|||
|
<programlisting>variable1x=$1x
|
|||
|
# This will prevent an error, even if positional parameter is absent.
|
|||
|
|
|||
|
critical_argument01=$variable1x
|
|||
|
|
|||
|
# The extra character can be stripped off later, if desired, like so.
|
|||
|
variable1=${variable1x/x/} # It works even if variable1x contains an 'x'.
|
|||
|
# This uses one of the parameter substitution templates previously discussed.
|
|||
|
# Leaving out the replacement pattern results in a deletion.
|
|||
|
|
|||
|
# A more straightforward way of dealing with this is to simply test
|
|||
|
# to simply test whether expected positional parameters have been passed.
|
|||
|
if [ -z $1 ]
|
|||
|
then
|
|||
|
exit $POS_PARAMS_MISSING
|
|||
|
fi
|
|||
|
</programlisting>
|
|||
|
|
|||
|
<para>---</para>
|
|||
|
|
|||
|
<example id="ex18">
|
|||
|
<title><command>wh</command>, whois domain name lookup</title>
|
|||
|
<programlisting>&ex18;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>---</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
|
|||
|
<varname>$0</varname> does not change. If you use a
|
|||
|
large number of positional parameters to a script,
|
|||
|
<command>shift</command> lets you access those past
|
|||
|
<literal>10</literal>, although {bracket} notation also
|
|||
|
permits this (see <xref linkend="ex17">).</para>
|
|||
|
|
|||
|
<example id="ex19">
|
|||
|
<title>Using <command>shift</command></title>
|
|||
|
<programlisting>&ex19;</programlisting>
|
|||
|
</example>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect2>
|
|||
|
<indexterm>
|
|||
|
<primary><anchor id="declareref">declare</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>typeset</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>declare</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>typeset</secondary>
|
|||
|
</indexterm>
|
|||
|
<title>Typing variables: <command>declare</command> or <command>typeset</command></title>
|
|||
|
|
|||
|
<para>The <command>declare</command> or <command>typeset</command>
|
|||
|
keywords (they are exact synonyms) permit restricting
|
|||
|
the properties of variables. This is a very weak form of
|
|||
|
the typing available in certain programming languages. The
|
|||
|
<command>declare</command> command is specific to version 2
|
|||
|
or later of Bash. The <command>typeset</command> command also
|
|||
|
works in ksh scripts.</para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term><token>-r</token> <replaceable>readonly</replaceable></term>
|
|||
|
<listitem><para><programlisting>declare -r var1</programlisting></para>
|
|||
|
<para>(<userinput>declare -r var1</userinput> works the same as
|
|||
|
<userinput>readonly var1</userinput>)</para>
|
|||
|
<para>This is the rough equivalent of the C
|
|||
|
<command>const</command> type qualifier. An
|
|||
|
attempt to change the value of a readonly variable fails with an
|
|||
|
error message.</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-i</token> <replaceable>integer</replaceable></term>
|
|||
|
<listitem><para><programlisting>declare -i var2</programlisting></para>
|
|||
|
<para>The script treats subsequent occurrences of
|
|||
|
<varname>var2</varname> as an integer. Note that
|
|||
|
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></listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-a</token> <replaceable>array</replaceable></term>
|
|||
|
<listitem><para><programlisting>declare -a indices</programlisting></para>
|
|||
|
<para>The variable <varname>indices</varname> will be treated as
|
|||
|
an array.</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-f</token> <replaceable>functions</replaceable></term>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para><programlisting>declare -f</programlisting></para>
|
|||
|
<para>A <userinput>declare -f</userinput> line with no
|
|||
|
arguments in a script causes a listing of all the
|
|||
|
functions previously defined in that script.</para>
|
|||
|
|
|||
|
<para><programlisting>declare -f function_name</programlisting></para>
|
|||
|
<para>A <userinput>declare -f function_name</userinput>
|
|||
|
in a script lists just the function named.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>-x</token> <link linkend="exportref">export</link></term>
|
|||
|
<listitem><para><programlisting>declare -x var3</programlisting></para>
|
|||
|
<para>This declares a variable as available for exporting outside the
|
|||
|
environment of the script itself.</para></listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<example id="ex20">
|
|||
|
<title>Using <command>declare</command> to type variables</title>
|
|||
|
<programlisting>&ex20;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</sect2> <!-- Typing variables: declare or typeset -->
|
|||
|
|
|||
|
|
|||
|
<sect2 id="ivr">
|
|||
|
<title>Indirect References to Variables</title>
|
|||
|
|
|||
|
<para><anchor id="ivrref"></para>
|
|||
|
|
|||
|
<para>Assume that the value of a variable is the name of a second
|
|||
|
variable. Is it somehow possible to retrieve the value
|
|||
|
of this second variable from the first one? For example,
|
|||
|
if <replaceable>a=letter_of_alphabet</replaceable>
|
|||
|
and <replaceable>letter_of_alphabet=z</replaceable>,
|
|||
|
can a reference to <replaceable>a</replaceable> return
|
|||
|
<replaceable>z</replaceable>? This can indeed be done, and
|
|||
|
it is called an <emphasis>indirect reference</emphasis>. It
|
|||
|
uses the unusual <replaceable>eval var1=\$$var2</replaceable>
|
|||
|
notation.</para>
|
|||
|
|
|||
|
<example id="indref">
|
|||
|
<title>Indirect References</title>
|
|||
|
<programlisting>&indref;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="coltotaler2">
|
|||
|
<title>Passing an indirect reference to <replaceable>awk</replaceable></title>
|
|||
|
<programlisting>&coltotaler2;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<caution><para>This method of indirect referencing is a bit tricky.
|
|||
|
If the second order variable changes its value, then the the first
|
|||
|
order variable must be properly dereferenced (as in the above
|
|||
|
example). Fortunately, the <replaceable>${!variable}</replaceable>
|
|||
|
notation introduced with <link linkend="bash2ref">version 2</link>
|
|||
|
of Bash (see <xref linkend="ex78">) makes indirect referencing
|
|||
|
more intuitive.</para></caution>
|
|||
|
|
|||
|
</sect2> <!-- Indirect References to Variables -->
|
|||
|
|
|||
|
|
|||
|
<sect2>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>$RANDOM</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$RANDOM</secondary>
|
|||
|
</indexterm>
|
|||
|
<title>$RANDOM: generate random integer</title>
|
|||
|
<note><para>$RANDOM is an internal Bash function (not a constant) that
|
|||
|
returns a <emphasis>pseudorandom</emphasis> integer in the range
|
|||
|
0 - 32767. $RANDOM should <replaceable>not</replaceable> be used
|
|||
|
to generate an encryption key.</para></note>
|
|||
|
|
|||
|
<example id="ex21">
|
|||
|
<title>Generating random numbers</title>
|
|||
|
<programlisting>&ex21;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Just how random is RANDOM? The best way to test this is
|
|||
|
to write a script that tracks the distribution of
|
|||
|
<quote>random</quote> numbers generated by RANDOM. Let's roll
|
|||
|
a RANDOM die a few times...</para>
|
|||
|
|
|||
|
<example id="randomtest">
|
|||
|
<title>Rolling the die with RANDOM</title>
|
|||
|
<programlisting>&randomtest;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>As we have seen in the last example, it is best to
|
|||
|
<quote>reseed</quote> the <varname>RANDOM</varname>
|
|||
|
generator each time it is invoked. Using the same seed
|
|||
|
for <varname>RANDOM</varname> repeats the same series
|
|||
|
of numbers. (This mirrors the behavior of the
|
|||
|
<replaceable>random()</replaceable> function in C.)</para>
|
|||
|
|
|||
|
<example id="seedingrandom">
|
|||
|
<title>Reseeding RANDOM</title>
|
|||
|
<programlisting>&seedingrandom;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<note><para>The <filename>/dev/urandom</filename> device/file provides
|
|||
|
a means of generating much more <quote>random</quote>
|
|||
|
pseudorandom numbers than the <varname>$RANDOM</varname>
|
|||
|
variable. <userinput>dd if=/dev/urandom of=targetfile
|
|||
|
bs=1 count=XX</userinput> creates a file of well-scattered
|
|||
|
pseudorandom numbers. However, assigning these numbers
|
|||
|
to a variable in a script requires a workaround, such as
|
|||
|
filtering through <link linkend="odref">od</link> (as in above
|
|||
|
example).</para></note>
|
|||
|
|
|||
|
|
|||
|
</sect2> <!-- RANDOM: generate random integer -->
|
|||
|
|
|||
|
|
|||
|
<sect2 id="dblparens">
|
|||
|
<title>The Double Parentheses Construct</title>
|
|||
|
|
|||
|
<para>Similar to the <link linkend="letref">let</link> command,
|
|||
|
the <command>((...))</command> construct permits arithmetic
|
|||
|
expansion and evaluation. In its simplest form, <userinput>a=$((
|
|||
|
5 + 3 ))</userinput> would set <quote>a</quote> to <quote>5 +
|
|||
|
3</quote>, or 8. However, this double parentheses construct is
|
|||
|
also a mechanism for allowing C-type manipulation of variables
|
|||
|
in Bash.</para>
|
|||
|
|
|||
|
<example id="cvars">
|
|||
|
<title>C-type manipulation of variables</title>
|
|||
|
<programlisting>&cvars;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See also <xref linkend="forloopc">.</para>
|
|||
|
|
|||
|
|
|||
|
</sect2> <!-- The Double Parentheses Construct -->
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- Variables Revisited -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="loops">
|
|||
|
<title>Loops and Branches</title>
|
|||
|
|
|||
|
<para>Operations on code blocks are the key to structured, organized
|
|||
|
shell scripts. Looping and branching constructs provide the tools for
|
|||
|
accomplishing this.</para>
|
|||
|
|
|||
|
<sect2 id="loops1">
|
|||
|
<title>Loops</title>
|
|||
|
|
|||
|
<para>A <emphasis>loop</emphasis> is a block of code that iterates
|
|||
|
(repeats) a list of commands as long as the loop control condition is
|
|||
|
true.</para>
|
|||
|
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="forloopref"><command>for (in)</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>for</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>in</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>do</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>done</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>loop</primary>
|
|||
|
<secondary>for</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This is the basic looping construct. It differs significantly
|
|||
|
from its C counterpart.</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>for</command>
|
|||
|
<arg choice="plain"><replaceable>arg</replaceable></arg>
|
|||
|
<arg choice="plain">in</arg>
|
|||
|
<arg choice="opt"><replaceable>list</replaceable></arg><sbr>
|
|||
|
<arg choice="plain">do</arg><sbr>
|
|||
|
<arg rep=repeat choice=plain><replaceable> command</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
|
|||
|
variable in the <replaceable>list</replaceable>.</para></note>
|
|||
|
|
|||
|
<para><programlisting>for arg in "$var1" "$var2" "$var3" ... "$varN"
|
|||
|
# In pass 1 of the loop, $arg = $var1
|
|||
|
# In pass 2 of the loop, $arg = $var2
|
|||
|
# In pass 3 of the loop, $arg = $var3
|
|||
|
# ...
|
|||
|
# In pass N of the loop, $arg = $varN
|
|||
|
|
|||
|
# Arguments in [list] quoted to prevent possible word splitting.</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>The argument <replaceable>list</replaceable> may contain wild cards.</para>
|
|||
|
|
|||
|
<para>If <command>do</command> is on same line as
|
|||
|
<command>for</command>, there needs to be a semicolon
|
|||
|
after list.</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>for</command>
|
|||
|
<arg choice="plain"><replaceable>arg</replaceable></arg>
|
|||
|
<arg choice="plain">in</arg>
|
|||
|
<arg choice="opt"><replaceable>list</replaceable></arg>
|
|||
|
<arg choice="plain">;</arg>
|
|||
|
<arg choice="plain">do</arg><sbr>
|
|||
|
</cmdsynopsis></para>
|
|||
|
|
|||
|
<example id="ex22">
|
|||
|
<title>Simple <command>for</command> loops</title>
|
|||
|
<programlisting>&ex22;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<note><para>Each <userinput>[list]</userinput> element
|
|||
|
may contain multiple parameters. This is useful when
|
|||
|
processing parameters in groups. In such cases, use the
|
|||
|
<command>set</command> command (see <xref linkend="ex34">)
|
|||
|
to force parsing of each <userinput>[list]</userinput>
|
|||
|
element and assignment of each component to the positional
|
|||
|
parameters.</para></note>
|
|||
|
|
|||
|
<example id="ex22a">
|
|||
|
<title><command>for</command> loop with two parameters in each
|
|||
|
[list] element</title>
|
|||
|
<programlisting>&ex22a;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>A variable may supply the <userinput>[list]</userinput> in a
|
|||
|
<command>for</command> loop.</para>
|
|||
|
|
|||
|
<example id="fileinfo">
|
|||
|
<title><emphasis>Fileinfo:</emphasis> operating on a file list
|
|||
|
contained in a variable</title>
|
|||
|
<programlisting>&fileinfo;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>The <userinput>[list]</userinput> in a
|
|||
|
<command>for</command> loop may contain filename <link
|
|||
|
linkend="globbingref">globbing</link>, that is, using
|
|||
|
wildcards for filename expansion.</para>
|
|||
|
|
|||
|
<example id="listglob">
|
|||
|
<title><command>Operating on files with a for</command> loop</title>
|
|||
|
<programlisting>&listglob;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>Omitting the <userinput>in [list]</userinput> part of a
|
|||
|
<command>for</command> loop causes the loop to operate on
|
|||
|
<token>$@</token>, the list of arguments given on the command line
|
|||
|
to the script.</para>
|
|||
|
|
|||
|
<example id="ex23">
|
|||
|
<title>Missing <userinput>in [list]</userinput> in a
|
|||
|
<command>for</command> loop</title>
|
|||
|
<programlisting>&ex23;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>It is possible to use <link
|
|||
|
linkend="commandsubref">command substitution</link>
|
|||
|
to generate the <userinput>[list]</userinput> in a
|
|||
|
<command>for</command> loop. See also <xref linkend="ex53">,
|
|||
|
<xref linkend="symlinks"> and <xref linkend="base">.</para>
|
|||
|
|
|||
|
<example id="forloopcmd">
|
|||
|
<title>Generating the [list] in a <command>for</command>
|
|||
|
loop with command substitution</title>
|
|||
|
<programlisting>&forloopcmd;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>This is a somewhat more complex example of using command
|
|||
|
substitution to create the [list].</para>
|
|||
|
|
|||
|
<example id="bingrep">
|
|||
|
<title>A <link linkend="grepref">grep</link> replacement
|
|||
|
for binary files</title>
|
|||
|
<programlisting>&bingrep;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>Here is yet another example of the [list] resulting
|
|||
|
from command substitution.</para>
|
|||
|
|
|||
|
<example id="findstring">
|
|||
|
<title>Checking all the binaries in a directory for
|
|||
|
authorship</title>
|
|||
|
<programlisting>&findstring;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>The output of a <command>for</command> loop may be piped to
|
|||
|
a command or commands.</para>
|
|||
|
|
|||
|
<example id="symlinks">
|
|||
|
<title>Listing the symbolic links in a directory</title>
|
|||
|
<programlisting>&symlinks;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>There is an alternative syntax to a <command>for</command>
|
|||
|
loop that will look very familiar to C programmers. This
|
|||
|
requires double parentheses.</para>
|
|||
|
|
|||
|
<example id="forloopc">
|
|||
|
<title>A C-like <command>for</command> loop</title>
|
|||
|
<programlisting>&forloopc;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See also <xref linkend="qfunction"> and <xref
|
|||
|
linkend="twodim">.</para>
|
|||
|
|
|||
|
<para>---</para>
|
|||
|
|
|||
|
<para>Now, for an example from <quote>real life</quote>.</para>
|
|||
|
|
|||
|
<example id="ex24">
|
|||
|
<title>Using <command>efax</command> in batch mode</title>
|
|||
|
<programlisting>&ex24;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="whileloopref"><command>while</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>while</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>do</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>done</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>loop</primary>
|
|||
|
<secondary>while</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This construct tests for a condition at the top of a
|
|||
|
loop, and keeps looping as long as that condition is
|
|||
|
true (returns a <returnvalue>0</returnvalue> <link
|
|||
|
linkend="exitstatusref">exit status</link>).</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>while</command>
|
|||
|
<arg choice="opt"><replaceable>condition</replaceable></arg><sbr>
|
|||
|
<arg choice="plain">do</arg><sbr>
|
|||
|
<arg choice="plain" rep="repeat"><replaceable> command</replaceable></arg><sbr>
|
|||
|
<arg choice="plain">done</arg>
|
|||
|
</cmdsynopsis></para>
|
|||
|
|
|||
|
<para>As is the case with <token>for/in</token> loops, placing the
|
|||
|
<command>do</command> on the same line as the condition test
|
|||
|
requires a semicolon.</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>while</command>
|
|||
|
<arg choice="opt"><replaceable>condition</replaceable></arg>
|
|||
|
<arg choice="plain">;</arg>
|
|||
|
<arg choice="plain">do</arg>
|
|||
|
</cmdsynopsis></para>
|
|||
|
|
|||
|
<para>Note that certain specialized <command>while</command>
|
|||
|
loops, as, for example, a <link
|
|||
|
linkend="getoptsx">getopts construct</link>, deviate
|
|||
|
somewhat from the standard template given here.</para>
|
|||
|
|
|||
|
<example id="ex25">
|
|||
|
<title>Simple <command>while</command> loop</title>
|
|||
|
<programlisting>&ex25;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ex26">
|
|||
|
<title>Another <command>while</command> loop</title>
|
|||
|
<programlisting>&ex26;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<note><para>A <command>while</command> loop may have multiple
|
|||
|
conditions. Only the final condition determines when the loop
|
|||
|
terminates. This necessitates a slightly different loop syntax,
|
|||
|
however.</para></note>
|
|||
|
|
|||
|
<example id="ex26a">
|
|||
|
<title><command>while</command> loop with multiple conditions</title>
|
|||
|
<programlisting>&ex26a;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>As with a <command>for</command> loop, a
|
|||
|
<command>while</command> loop may employ C-like syntax
|
|||
|
by using the double parentheses construct (see also <xref
|
|||
|
linkend="cvars">).</para>
|
|||
|
|
|||
|
<example id="whloopc">
|
|||
|
<title>C-like syntax in a <command>while</command> loop</title>
|
|||
|
<programlisting>&whloopc;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<note><para>A <command>while</command> loop may have its
|
|||
|
<filename>stdin</filename> <link
|
|||
|
linkend="redirref">redirected to a file</link> by a
|
|||
|
<token><</token> at its end.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="untilloopref"><command>until</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>until</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>do</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>done</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>loop</primary>
|
|||
|
<secondary>until</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>This construct tests for a condition at the top of a loop, and keeps
|
|||
|
looping as long as that condition is false (opposite of
|
|||
|
<command>while</command> loop).</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>until</command>
|
|||
|
<arg choice="opt"><replaceable>condition-is-true</replaceable></arg><sbr>
|
|||
|
<arg choice="plain">do</arg><sbr>
|
|||
|
<arg choice="plain" rep="repeat"><replaceable> command</replaceable></arg><sbr>
|
|||
|
<arg choice="plain">done</arg>
|
|||
|
</cmdsynopsis></para>
|
|||
|
|
|||
|
<para>Note that an <command>until</command> loop tests for the
|
|||
|
terminating condition at the top of the loop, differing from a
|
|||
|
similar construct in some programming languages.</para>
|
|||
|
|
|||
|
<para>As is the case with <token>for/in</token> loops, placing the
|
|||
|
<command>do</command> on the same line as the condition test
|
|||
|
requires a semicolon.</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>until</command>
|
|||
|
<arg choice="opt"><replaceable>condition-is-true</replaceable></arg>
|
|||
|
<arg choice="plain">;</arg>
|
|||
|
<arg choice="plain">do</arg>
|
|||
|
</cmdsynopsis></para>
|
|||
|
|
|||
|
<example id="ex27">
|
|||
|
<title><command>until</command> loop</title>
|
|||
|
<programlisting>&ex27;</programlisting>
|
|||
|
</example>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- Loops -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect2 id="nestedloops">
|
|||
|
<title>Nested Loops</title>
|
|||
|
|
|||
|
<para>A nested loop is a loop within a loop, an inner loop within the
|
|||
|
body of an outer one. What happens is that the first pass of the
|
|||
|
outer loop triggers the inner loop, which executes to completion.
|
|||
|
Then the second pass of the outer loop triggers the inner loop
|
|||
|
again. This repeats until the outer loop finishes. Of course, a
|
|||
|
<command>break</command> within either the inner or outer loop may
|
|||
|
interrupt this process.</para>
|
|||
|
|
|||
|
<example id="nestedloop">
|
|||
|
<title>Nested Loop</title>
|
|||
|
<programlisting>&nestedloop;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See <xref linkend="bubble"> for an illustration of nested
|
|||
|
<quote>while</quote> loops, and <xref linkend="ex68"> to see a
|
|||
|
<quote>while</quote> loop nested inside an <quote>until</quote>
|
|||
|
loop.</para>
|
|||
|
|
|||
|
</sect2> <!-- Nested Loops -->
|
|||
|
|
|||
|
|
|||
|
<sect2 id="loopcontrol">
|
|||
|
<title>Loop Control Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<indexterm>
|
|||
|
<primary>break</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>continue</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>loop</primary>
|
|||
|
<secondary>break</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>loop</primary>
|
|||
|
<secondary>continue</secondary>
|
|||
|
</indexterm>
|
|||
|
<term><command>break</command></term>
|
|||
|
<term><command>continue</command></term>
|
|||
|
<listitem>
|
|||
|
<para>The <command>break</command> and <command>continue</command>
|
|||
|
loop control commands
|
|||
|
<footnote><para>These are shell <link
|
|||
|
linkend="builtinref">builtins</link>, whereas other
|
|||
|
loop commands, such as <command>while</command>
|
|||
|
and <command>case</command>, are <link
|
|||
|
linkend="keywordref">keywords</link>.</para></footnote>
|
|||
|
correspond exactly to their counterparts in
|
|||
|
other programming languages. The <command>break</command> command
|
|||
|
terminates the loop (breaks out of it), while <command>continue</command>
|
|||
|
causes a jump to the next iteration of the loop, skipping all the
|
|||
|
remaining commands in that particular loop cycle.</para>
|
|||
|
|
|||
|
<example id="ex28">
|
|||
|
<title>Effects of <command>break</command> and
|
|||
|
<command>continue</command> in a loop</title>
|
|||
|
<programlisting>&ex28;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>The <command>break</command> command may optionally take a
|
|||
|
parameter. A plain <command>break</command> terminates
|
|||
|
only the innermost loop in which it is embedded,
|
|||
|
but a <command>break N</command> breaks out of
|
|||
|
<parameter>N</parameter> levels of loop.</para>
|
|||
|
|
|||
|
<example id="breaklevels">
|
|||
|
<title>Breaking out of multiple loop levels</title>
|
|||
|
<programlisting>&breaklevels;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>The <command>continue</command> command, similar to
|
|||
|
<command>break</command>, optionally takes a parameter. A
|
|||
|
plain <command>continue</command> cuts short the
|
|||
|
current iteration within its loop and begins the next.
|
|||
|
A <command>continue N</command> terminates all remaining
|
|||
|
iterations at its loop level and continues with the
|
|||
|
next iteration at the loop <option>N</option> levels
|
|||
|
above.</para>
|
|||
|
|
|||
|
<example id="continuelevels">
|
|||
|
<title>Continuing at a higher loop level</title>
|
|||
|
<programlisting>&continuelevels;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<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>
|
|||
|
|
|||
|
</sect2> <!-- Loop Control Commands -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect2 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 a
|
|||
|
code block. Like loops, however, they direct program flow according
|
|||
|
to conditions at the top or bottom of the block.</para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>case (in) / esac</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>case</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>in</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>esac</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>switch</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>;;</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>menus</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>The <command>case</command> construct is the shell equivalent
|
|||
|
of <command>switch</command> in C/C++.
|
|||
|
It permits branching to one of a number of code blocks, depending
|
|||
|
on condition tests. It serves as a kind of shorthand for multiple
|
|||
|
<token>if/then/else</token> statements and is an appropriate tool
|
|||
|
for creating menus.</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>case</command>
|
|||
|
<arg choice="plain">"$<replaceable>variable</replaceable>"</arg>
|
|||
|
<arg choice="plain">in</arg><sbr><sbr>
|
|||
|
<arg choice="plain"> "$<replaceable>condition1</replaceable>" )</arg><sbr>
|
|||
|
<arg choice="plain" rep="repeat"> <replaceable>command</replaceable></arg><sbr>
|
|||
|
<arg choice="plain"> ;;</arg><sbr><sbr>
|
|||
|
<arg choice="plain"> "$<replaceable>condition2</replaceable>" )</arg><sbr>
|
|||
|
<arg choice="plain" rep="repeat"> <replaceable>command</replaceable></arg><sbr>
|
|||
|
<arg choice="plain"> ;;</arg><sbr><sbr>
|
|||
|
<arg choice="plain">esac</arg>
|
|||
|
</cmdsynopsis></para>
|
|||
|
|
|||
|
<note><para>
|
|||
|
<itemizedlist>
|
|||
|
<listitem><para>Quoting the variables is not mandatory, since
|
|||
|
word splitting does not take place.</para>
|
|||
|
</listitem>
|
|||
|
<listitem><para>Each test line ends with a right paren <token>)</token>.</para>
|
|||
|
</listitem>
|
|||
|
<listitem><para>Each condition block ends with a <emphasis>double</emphasis>
|
|||
|
semicolon <token>;;</token>.</para>
|
|||
|
</listitem>
|
|||
|
<listitem><para>The entire <command>case</command> block terminates with an
|
|||
|
<command>esac</command> (<wordasword>case</wordasword> spelled
|
|||
|
backwards).</para>
|
|||
|
</listitem>
|
|||
|
</itemizedlist>
|
|||
|
</para></note>
|
|||
|
|
|||
|
<example id="ex29">
|
|||
|
<title>Using <command>case</command></title>
|
|||
|
<programlisting>&ex29;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ex30">
|
|||
|
<title>Creating menus using <command>case</command></title>
|
|||
|
<programlisting>&ex30;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>An exceptionally clever use of <command>case</command>
|
|||
|
involves testing for command-line parameters.
|
|||
|
<programlisting>#! /bin/bash
|
|||
|
|
|||
|
case "$1" in
|
|||
|
"") echo "Usage: ${0##*/} <filename>"; exit 65;; # No command-line parameters,
|
|||
|
# or first parameter empty.
|
|||
|
# Note that ${0##*/} is ${var##pattern} param substitution. Net result is $0.
|
|||
|
|
|||
|
-*) FILENAME=./$1;; # If filename passed as argument ($1) starts with a dash,
|
|||
|
# replace it with ./$1
|
|||
|
# so further commands don't interpret it as an option.
|
|||
|
|
|||
|
* ) FILENAME=$1;; # Otherwise, $1.
|
|||
|
esac</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<example id="casecmd">
|
|||
|
<title>Using command substitution to generate the
|
|||
|
<command>case</command> variable</title>
|
|||
|
<programlisting>&casecmd;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>A <command>case</command> construct can filter strings for
|
|||
|
<link linkend="globbingref">globbing</link> patterns.</para>
|
|||
|
|
|||
|
<example id="isalpha">
|
|||
|
<title>Checking for alphabetic input</title>
|
|||
|
<programlisting>&isalpha;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="selectref"><command>select</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>select</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>menus</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>select</command> construct, adopted from the Korn
|
|||
|
Shell, is yet another tool for building menus.</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>select</command>
|
|||
|
<arg choice="plain"><replaceable>variable</replaceable></arg>
|
|||
|
<arg choice="opt">in <replaceable>list</replaceable></arg><sbr>
|
|||
|
<arg choice="plain">do</arg><sbr>
|
|||
|
<arg choice="plain" rep="repeat"> <replaceable>command</replaceable></arg><sbr>
|
|||
|
<arg choice="plain"> break</arg><sbr>
|
|||
|
<arg choice="plain">done</arg>
|
|||
|
</cmdsynopsis></para>
|
|||
|
|
|||
|
<para>This prompts the user to enter one of the choices presented in the
|
|||
|
variable list. Note that <command>select</command> uses the
|
|||
|
<varname>PS3</varname> prompt (<prompt>#? </prompt>) by default,
|
|||
|
but that this may be changed.</para>
|
|||
|
|
|||
|
<example id="ex31">
|
|||
|
<title>Creating menus using <command>select</command></title>
|
|||
|
<programlisting>&ex31;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>If <userinput>in <replaceable>list</replaceable></userinput> is
|
|||
|
omitted, then <command>select</command> uses the list of command
|
|||
|
line arguments (<varname>$@</varname>) passed to the script or to
|
|||
|
the function in which the <command>select</command> construct is
|
|||
|
embedded.</para>
|
|||
|
|
|||
|
<para>Compare this to the behavior of a
|
|||
|
<cmdsynopsis>
|
|||
|
<command>for</command>
|
|||
|
<arg choice="plain"><replaceable>variable</replaceable></arg>
|
|||
|
<arg choice="opt">in <replaceable>list</replaceable></arg>
|
|||
|
</cmdsynopsis>
|
|||
|
construct with the
|
|||
|
<userinput>in <replaceable>list</replaceable></userinput>
|
|||
|
omitted.</para>
|
|||
|
|
|||
|
<example id="ex32">
|
|||
|
<title>Creating menus using <command>select</command> in a function</title>
|
|||
|
<programlisting>&ex32;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- Testing and Branching -->
|
|||
|
|
|||
|
</sect1> <!-- Loops -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="internal">
|
|||
|
<title>Internal Commands and Builtins</title>
|
|||
|
<indexterm>
|
|||
|
<primary>builtin</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
|
|||
|
<para><anchor id="builtinref">A <firstterm>builtin</firstterm> is a command contained
|
|||
|
within the Bash tool set, literally <emphasis>built
|
|||
|
in</emphasis>. A builtin may be a synonym to a system command
|
|||
|
of the same name, but Bash reimplements it internally.
|
|||
|
|
|||
|
<footnote><para>This is either for performance reasons (builtins
|
|||
|
execute much faster than external commands, which usually
|
|||
|
require <emphasis>forking</emphasis> off a process) or
|
|||
|
because a particular builtin needs direct access to the
|
|||
|
shell internals.</para></footnote>
|
|||
|
|
|||
|
For example, the Bash <command>echo</command> command is not the
|
|||
|
same as <filename>/bin/echo</filename>, although their behavior
|
|||
|
is almost identical.</para>
|
|||
|
|
|||
|
<para><anchor id="keywordref">A <firstterm>keyword</firstterm>
|
|||
|
is a <emphasis>reserved</emphasis> word, token or
|
|||
|
operator. Keywords have a special meaning to the shell,
|
|||
|
and indeed are the building blocks of the shell's
|
|||
|
syntax. As examples, <quote><token>for</token></quote>,
|
|||
|
<quote><token>while</token></quote> and
|
|||
|
<quote><token>!</token></quote> are keywords. Similar to a
|
|||
|
<emphasis>builtin</emphasis>, a keyword is hard-coded into
|
|||
|
Bash.</para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="echoref"><command>echo</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>echo</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>echo</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>prints (to <filename>stdout</filename>) an expression
|
|||
|
or variable (see <xref linkend="ex9">).
|
|||
|
<programlisting>echo Hello
|
|||
|
echo $a</programlisting></para>
|
|||
|
|
|||
|
<para>Normally, each <command>echo</command> command prints a terminal newline, but
|
|||
|
the <option>-n</option> option suppresses this.</para>
|
|||
|
|
|||
|
<note>
|
|||
|
<para>An <command>echo</command> can be used to feed a
|
|||
|
sequence of commands down a pipe.</para>
|
|||
|
<para><programlisting>if echo "$VAR" | grep -q txt # if [[ $VAR = *txt* ]]
|
|||
|
then
|
|||
|
echo "$VAR contains the substring sequence \"txt\""
|
|||
|
fi</programlisting></para>
|
|||
|
</note>
|
|||
|
|
|||
|
<note><para>An <command>echo</command>, in combination with
|
|||
|
<link linkend="commandsubref">command substitution</link>
|
|||
|
can set a variable.</para> <para><userinput>a=`echo
|
|||
|
"HELLO" | tr A-Z a-z`</userinput></para>
|
|||
|
<para>See also <xref linkend="lowercase">, <xref
|
|||
|
linkend="ex57">, <xref linkend="monthlypmt">, and <xref
|
|||
|
linkend="base">.</para></note>
|
|||
|
|
|||
|
|
|||
|
<caution><para>Be aware that <command>echo `command`</command>
|
|||
|
deletes any linefeeds that the output
|
|||
|
of <replaceable>command</replaceable>
|
|||
|
generates. Since <varname>$IFS</varname> normally
|
|||
|
contains <token>\n</token> as one of its set of <link
|
|||
|
linkend="whitespaceref">whitespace</link> characters, Bash
|
|||
|
segments the output of <replaceable>command</replaceable>
|
|||
|
at linefeeds into arguments to <command>echo</command>,
|
|||
|
which then emits these arguments separated by
|
|||
|
spaces.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen>
|
|||
|
<prompt>bash$ </prompt><userinput> printf '\n\n1\n2\n3\n\n\n\n'</userinput>
|
|||
|
<computeroutput>
|
|||
|
|
|||
|
|
|||
|
1
|
|||
|
2
|
|||
|
3
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</computeroutput>
|
|||
|
<prompt>bash $</prompt>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo "`printf '\n\n1\n2\n3\n\n\n\n'`"</userinput>
|
|||
|
<computeroutput>
|
|||
|
|
|||
|
|
|||
|
1
|
|||
|
2
|
|||
|
3
|
|||
|
</computeroutput>
|
|||
|
<prompt>bash $</prompt>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
</caution>
|
|||
|
|
|||
|
<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><command>cd</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>cd</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cd</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The familiar <command>cd</command> change directory command finds use in scripts where
|
|||
|
execution of a command requires being in a specified directory.
|
|||
|
<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>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>printf</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>printf</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>printf</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>printf</command>, formatted print, command is an
|
|||
|
enhanced <command>echo</command>. It is a limited variant of the
|
|||
|
C language <function>printf</function>, and the syntax is somewhat
|
|||
|
different.</para>
|
|||
|
<cmdsynopsis>
|
|||
|
<command>printf</command>
|
|||
|
<arg choice=plain rep=repeat><replaceable>format-string</replaceable></arg>
|
|||
|
<arg choice=plain rep=repeat><replaceable>parameter</replaceable></arg>
|
|||
|
</cmdsynopsis>
|
|||
|
|
|||
|
<para>This is the Bash builtin version
|
|||
|
of the <filename>/bin/printf</filename> or
|
|||
|
<filename>/usr/bin/printf</filename> command. See the
|
|||
|
<command>printf</command> man page (of the system command)
|
|||
|
for in-depth coverage.</para>
|
|||
|
|
|||
|
<caution><para>Older versions of <command>bash</command>
|
|||
|
may not support <command>printf</command>.</para></caution>
|
|||
|
|
|||
|
<example id="ex47">
|
|||
|
<title><command>printf</command> in action</title>
|
|||
|
<programlisting>&ex47;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Formatting error messages is a useful application of
|
|||
|
<command>printf</command>
|
|||
|
|
|||
|
<programlisting>E_BADDIR=65
|
|||
|
|
|||
|
var=nonexistent_directory
|
|||
|
|
|||
|
error()
|
|||
|
{
|
|||
|
printf "$@" >&2
|
|||
|
# Formats positional params passed, and sents them to stderr.
|
|||
|
echo
|
|||
|
exit $E_BADDIR
|
|||
|
}
|
|||
|
|
|||
|
cd $var || error $"Can't cd to %s." "$var"
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="getoptsx"><command>getopts</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>getopts</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>getopts</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>$OPTIND</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$OPTIND</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>$OPTARG</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$OPTARG</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This powerful tool parses command line arguments passed to the
|
|||
|
script. This is the bash analog of the <command>getopt</command>
|
|||
|
library function familiar to C programmers. It permits passing and
|
|||
|
concatenating multiple options
|
|||
|
|
|||
|
<footnote><para>A option is an argument that acts as a
|
|||
|
flag, switching script behaviors on or off. The
|
|||
|
argument associated with a particular option indicates
|
|||
|
the behavior that the option (flag) switches on or
|
|||
|
off.</para></footnote>
|
|||
|
|
|||
|
and associated arguments to a script (for
|
|||
|
example <userinput>scriptname -abc -e
|
|||
|
/usr/local</userinput>).</para>
|
|||
|
|
|||
|
<para>The <command>getopts</command> construct uses two implicit
|
|||
|
variables. <varname>$OPTIND</varname> is the argument
|
|||
|
pointer (<wordasword>OPTion INDex</wordasword>)
|
|||
|
and <varname>$OPTARG</varname> (<wordasword>OPTion
|
|||
|
ARGument</wordasword>) the (optional) argument attached
|
|||
|
to an option. A colon following the option name in the
|
|||
|
declaration tags that option as having an associated
|
|||
|
argument.</para>
|
|||
|
|
|||
|
<para>A <command>getopts</command> construct usually comes
|
|||
|
packaged in a <link linkend="whileloopref">while
|
|||
|
loop</link>, which processes the options and
|
|||
|
arguments one at a time, then decrements the implicit
|
|||
|
<varname>$OPTIND</varname> variable to step to the
|
|||
|
next.</para>
|
|||
|
|
|||
|
<note>
|
|||
|
<para>
|
|||
|
<orderedlist>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>The arguments must be passed from the
|
|||
|
command line to the script preceded by
|
|||
|
a minus (<option>-</option>) or a plus
|
|||
|
(<option>+</option>). It is the prefixed
|
|||
|
<option>-</option> or <option>+</option> that lets
|
|||
|
<command>getopts</command> recognize command-line
|
|||
|
arguments as <emphasis>options</emphasis>.
|
|||
|
In fact, <command>getopts</command> will not process
|
|||
|
arguments without the prefixed <option>-</option>
|
|||
|
or <option>+</option>, and will terminate option
|
|||
|
processing at the first argument encountered
|
|||
|
lacking them.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
<listitem><para>The <command>getopts</command> template
|
|||
|
differs slightly from the standard <command>while</command>
|
|||
|
loop, in that it lacks condition brackets.</para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>The <command>getopts</command>
|
|||
|
construct replaces the obsolete
|
|||
|
<command>getopt</command> command.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</orderedlist>
|
|||
|
</para>
|
|||
|
</note>
|
|||
|
|
|||
|
<para><programlisting>
|
|||
|
while getopts ":abcde:fg" Option
|
|||
|
# Initial declaration.
|
|||
|
# a, b, c, d, e, f, and g are the options (flags) expected.
|
|||
|
# The : after option 'e' shows it will have an argument passed with it.
|
|||
|
do
|
|||
|
case $Option in
|
|||
|
a ) # Do something with variable 'a'.
|
|||
|
b ) # Do something with variable 'b'.
|
|||
|
...
|
|||
|
e) # Do something with 'e', and also with $OPTARG,
|
|||
|
# which is the associated argument passed with option 'e'.
|
|||
|
...
|
|||
|
g ) # Do something with variable 'g'.
|
|||
|
esac
|
|||
|
done
|
|||
|
shift $(($OPTIND - 1))
|
|||
|
# Move argument pointer to next.
|
|||
|
|
|||
|
# All this is not nearly as complicated as it looks <grin>.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
<example id="ex33">
|
|||
|
<title>Using <command>getopts</command> to read the
|
|||
|
options/arguments passed to a script</title>
|
|||
|
<programlisting>&ex33;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>exit</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>exit</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>exit</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Unconditionally terminates a script. The
|
|||
|
<command>exit</command> command may optionally take an
|
|||
|
integer argument, which is returned to the shell as
|
|||
|
the <link linkend="exitstatusref">exit status</link>
|
|||
|
of the script. It is a good practice to end all but the
|
|||
|
simplest scripts with an <userinput>exit 0</userinput>,
|
|||
|
indicating a successful run.</para>
|
|||
|
|
|||
|
<note><para>If a script terminates with an <command>exit</command>
|
|||
|
lacking an argument, the exit status of the script is the exit
|
|||
|
status of the last command executed in the script, not counting
|
|||
|
the <command>exit</command>.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>eval</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>eval</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>eval</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para><userinput>eval arg1, arg2, ...</userinput></para>
|
|||
|
|
|||
|
<para>Translates into commands the arguments in a list
|
|||
|
(useful for code generation within a script).</para>
|
|||
|
|
|||
|
<example id="ex43">
|
|||
|
<title>Showing the effect of <command>eval</command></title>
|
|||
|
<programlisting>&ex43;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ex44">
|
|||
|
<title>Forcing a log-off</title>
|
|||
|
<programlisting>&ex44;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="rot13_2">
|
|||
|
<title>A version of <quote>rot13</quote></title>
|
|||
|
<programlisting>&rot13_2;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<caution><para>The <command>eval</command> command can be
|
|||
|
risky, and normally should be avoided when there
|
|||
|
exists a reasonable alternative. An <userinput>eval
|
|||
|
$COMMANDS</userinput> executes the contents of
|
|||
|
<replaceable>COMMANDS</replaceable>, which may
|
|||
|
contain such unpleasant surprises as <command>rm -rf
|
|||
|
*</command>. Running an <command>eval</command> on
|
|||
|
unfamiliar code written by persons unknown is living
|
|||
|
dangerously.</para></caution>
|
|||
|
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="execref"><command>exec</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>exec</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>exec</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This shell builtin replaces the current process with
|
|||
|
a specified command. Normally, when the shell encounters
|
|||
|
a command, it forks <anchor id="forkref"> off
|
|||
|
|
|||
|
<footnote><para>When a command or the shell itself
|
|||
|
initiates (or <emphasis>spawns</emphasis>) a new
|
|||
|
subprocess to carry out a task, this is called
|
|||
|
<emphasis>forking</emphasis>. This new process
|
|||
|
is the <quote>child</quote>, and the process
|
|||
|
that <emphasis>forked</emphasis> it off is the
|
|||
|
<quote>parent</quote>. While the <emphasis>child
|
|||
|
process</emphasis> is doing its work, the
|
|||
|
<emphasis>parent process</emphasis> is still
|
|||
|
running.</para></footnote>
|
|||
|
|
|||
|
a child process to actually execute the command. Using the
|
|||
|
<command>exec</command> builtin, the shell does not fork,
|
|||
|
and the command exec'ed replaces the shell. When used in
|
|||
|
a script, therefore, it forces an exit from the script when
|
|||
|
the <command>exec</command>'ed command terminates. For this
|
|||
|
reason, if an <command>exec</command> appears in a script,
|
|||
|
it would probably be the final command.</para>
|
|||
|
|
|||
|
<para>An <command>exec</command> also serves to reassign <link
|
|||
|
linkend="fdref">file descriptors</link>. <userinput>exec
|
|||
|
<zzz-file</userinput> replaces <filename>stdin</filename>
|
|||
|
with the file <filename>zzz-file</filename> (see <xref
|
|||
|
linkend="redir1">).</para>
|
|||
|
|
|||
|
<example id="ex54">
|
|||
|
<title>Effects of <command>exec</command></title>
|
|||
|
<programlisting>&ex54;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<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="setref"><command>set</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>set</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>set</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>The <command>set</command> command changes the value
|
|||
|
of internal script variables. One use for this
|
|||
|
is to toggle <link linkend="optionsref">option
|
|||
|
flags</link> which help determine the behavior of the
|
|||
|
script. Another application for it is to reset the <link
|
|||
|
linkend="posparamref">positional parameters</link> that
|
|||
|
a script sees as the result of a command (<userinput>set
|
|||
|
`command`</userinput>). The script can then parse the
|
|||
|
fields of the command output.</para>
|
|||
|
|
|||
|
<example id="ex34">
|
|||
|
<title>Using <command>set</command> with positional
|
|||
|
parameters</title> <programlisting>&ex34;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See also <xref linkend="ex22a">.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>unset</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>unset</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>unset</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>The <command>unset</command> command deletes a
|
|||
|
shell variable. Note that this command does not affect
|
|||
|
positional parameters.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen>
|
|||
|
<prompt>bash$ </prompt><userinput>unset PATH</userinput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo $PATH</userinput>
|
|||
|
<computeroutput>
|
|||
|
|
|||
|
|
|||
|
</computeroutput>
|
|||
|
<prompt>bash$ </prompt></screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<example id="uns">
|
|||
|
<title><quote>unsetting</quote> a variable</title>
|
|||
|
<programlisting>&uns;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>shopt</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>shopt</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>shopt</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This command permits changing shell options on the fly (see
|
|||
|
<xref linkend="al"> and <xref linkend="unal">). It often
|
|||
|
appears in the Bash <link linkend="filesref">startup
|
|||
|
files</link>, but also has its uses in scripts. Needs
|
|||
|
<link linkend="bash2ref">version 2</link> or later of Bash.
|
|||
|
|
|||
|
<programlisting>shopt -s cdspell
|
|||
|
# Allows minor misspelling directory names with 'cd'
|
|||
|
command.</programlisting></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="exportref"><command>export</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>export</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>export</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>The <command>export</command> command makes
|
|||
|
available variables to all child processes of the
|
|||
|
running script or shell. Unfortunately, there is no way
|
|||
|
to <command>export</command> variables back to the parent
|
|||
|
process, to the process that called or invoked the script
|
|||
|
or shell. One important use of <command>export</command>
|
|||
|
command is in <link linkend="filesref">startup files</link>,
|
|||
|
to initialize and make accessible environmental variables
|
|||
|
to subsequent user processes.</para>
|
|||
|
|
|||
|
|
|||
|
<example id="coltotaler3">
|
|||
|
<title>Using <command>export</command> to pass a variable to an
|
|||
|
embedded <link linkend="awkref">awk</link> script</title>
|
|||
|
<programlisting>&coltotaler3;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<tip><para>It is possible to initialize and export
|
|||
|
variables in the same operation, as in <command>export
|
|||
|
var1=xxx</command>.</para></tip>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>readonly</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>readonly</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>readonly</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>Same as <link linkend="declareref">declare -r</link>,
|
|||
|
sets a variable as read-only, or, in effect, as a
|
|||
|
constant. Attempts to change the variable fail with an
|
|||
|
error message. This is the shell analog of the C language
|
|||
|
<command>const</command> type qualifier.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="readref"><command>read</command></term> <indexterm>
|
|||
|
<primary>read</primary>
|
|||
|
</indexterm> <indexterm>
|
|||
|
<primary>command</primary> <secondary>read</secondary>
|
|||
|
</indexterm> <listitem><para><quote>Reads</quote> the value
|
|||
|
of a variable from <filename>stdin</filename>, that
|
|||
|
is, interactively fetches input from the keyboard. The
|
|||
|
<option>-a</option> option lets <command>read</command>
|
|||
|
get array variables (see <xref linkend="ex67">).</para>
|
|||
|
|
|||
|
<example id="ex36">
|
|||
|
<title>Variable assignment, using <command>read</command></title>
|
|||
|
<programlisting>&ex36;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>The <command>read</command> command has some interesting
|
|||
|
options that permit echoing a prompt and even reading keystrokes
|
|||
|
without hitting <keycap>ENTER</keycap>.</para>
|
|||
|
|
|||
|
<para><programlisting># Read a keypress without hitting ENTER.
|
|||
|
|
|||
|
read -s -n1 -p "Hit a key " keypress
|
|||
|
echo; echo "Keypress was "\"$keypress\""."
|
|||
|
|
|||
|
# -s option means do not echo input.
|
|||
|
# -n N option means accept only N characters of input.
|
|||
|
# -p option means echo the following prompt before reading input.
|
|||
|
|
|||
|
# Using these options is tricky, since they need to be in the correct order.</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>The <command>read</command> command may also
|
|||
|
<quote>read</quote> its variable value from a file
|
|||
|
<link linkend="ioredirref">redirected</link> to
|
|||
|
<filename>stdin</filename>. If the file contains
|
|||
|
more than one line, only the first line is assigned
|
|||
|
to the variable. If <command>read</command>
|
|||
|
has more than one parameter, then each of
|
|||
|
these variables gets assigned a successive <link
|
|||
|
linkend="whitespaceref">whitespace-delineated</link>
|
|||
|
string. Caution!</para>
|
|||
|
|
|||
|
<example id="readredir">
|
|||
|
<title>Using <command>read</command> with
|
|||
|
<link linkend="ioredirref">file redirection</link></title>
|
|||
|
<programlisting>&readredir;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="letref"><command>let</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>let</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>let</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>let</command> command carries out arithmetic
|
|||
|
operations on variables. In many cases, it functions as a less
|
|||
|
complex version of <link linkend="exprref">expr</link>.</para>
|
|||
|
|
|||
|
<example id="ex46">
|
|||
|
<title>Letting <command>let</command> do some arithmetic.</title>
|
|||
|
<programlisting>&ex46;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="trueref"><command>true</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>true</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>true</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>A command that returns a successful
|
|||
|
(<returnvalue>zero</returnvalue>) <link
|
|||
|
linkend="exitstatusref">exit status</link>, but does
|
|||
|
nothing else.
|
|||
|
</para>
|
|||
|
|
|||
|
<para><programlisting># Endless loop
|
|||
|
while true # alias for ":"
|
|||
|
do
|
|||
|
operation-1
|
|||
|
operation-2
|
|||
|
...
|
|||
|
operation-n
|
|||
|
# Need a way to break out of loop.
|
|||
|
done</programlisting></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>false</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>false</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>false</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>A command that returns an unsuccessful <link
|
|||
|
linkend="exitstatusref">exit status</link>,
|
|||
|
but does nothing else.</para>
|
|||
|
|
|||
|
<para><programlisting># Null loop
|
|||
|
while false
|
|||
|
do
|
|||
|
# The following code will not execute.
|
|||
|
operation-1
|
|||
|
operation-2
|
|||
|
...
|
|||
|
operation-n
|
|||
|
# Nothing happens!
|
|||
|
done
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>hash [cmds]</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>hash</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>hash</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>$PATH</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$PATH</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>Record the path name of specified commands (in the
|
|||
|
shell hash table), so the shell or script will not need to search
|
|||
|
the <varname>$PATH</varname> on subsequent calls to those
|
|||
|
commands. When <command>hash</command> is called with no
|
|||
|
arguments, it simply lists the commands that have been hashed.
|
|||
|
The <option>-r</option> option resets the hash table.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>type [cmd]</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>type</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>type</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>which</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>Similar to the <link
|
|||
|
linkend="whichref">which</link> external command,
|
|||
|
<command>type cmd</command> gives the full pathname to
|
|||
|
<quote>cmd</quote>. Unlike <command>which</command>,
|
|||
|
<command>type</command> is a Bash builtin. The useful
|
|||
|
<option>-a</option> option to <command>type</command>
|
|||
|
accesses identifies <replaceable>keywords</replaceable>
|
|||
|
and <replaceable>builtins</replaceable>, and also locates
|
|||
|
system commands with identical names.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen>
|
|||
|
<prompt>bash$ </prompt><userinput>type '['</userinput>
|
|||
|
<computeroutput>[ is a shell builtin</computeroutput>
|
|||
|
<prompt>bash$ </prompt><userinput>type -a '['</userinput>
|
|||
|
<computeroutput>[ is a shell builtin
|
|||
|
[ is /usr/bin/[</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="pwd2ref"><command>pwd</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>pwd</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>pwd</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>$PWD</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>$PWD</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>directory</primary>
|
|||
|
<secondary>working</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>Print Working Directory. This gives the user's
|
|||
|
(or script's) current directory (see <xref
|
|||
|
linkend="ex37">). The effect is identical to
|
|||
|
reading the value of the builtin variable <link
|
|||
|
linkend="pwdref">$PWD</link>.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="dirsd"><command>pushd</command></term>
|
|||
|
<term><command>popd</command></term>
|
|||
|
<term><command>dirs</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>pushd</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>pushd</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>popd</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>popd</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>dirs</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>dirs</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>directory</primary>
|
|||
|
<secondary>working</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>bookmark</primary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>This command set is a mechanism for bookmarking working directories,
|
|||
|
a means of moving back and forth through directories in an orderly
|
|||
|
manner. A pushdown stack is used to keep track of directory names.
|
|||
|
Options allow various manipulations of the directory stack.</para>
|
|||
|
|
|||
|
<para><anchor id="pushdref"><userinput>pushd
|
|||
|
dir-name</userinput> pushes the path
|
|||
|
<replaceable>dir-name</replaceable> onto the directory
|
|||
|
stack and simultaneously changes the current working
|
|||
|
directory to <replaceable>dir-name</replaceable></para>
|
|||
|
|
|||
|
<para><anchor id="popdref"><command>popd</command> removes (pops) the top directory path
|
|||
|
name off the directory stack and simultaneously changes the
|
|||
|
current working directory to that directory popped from the stack.
|
|||
|
</para>
|
|||
|
|
|||
|
<para><command>dirs</command> lists the contents of the directory
|
|||
|
stack (counterpart to <link
|
|||
|
linkend="dirstackref">$DIRSTACK</link>) 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>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="sourceref"><command>source</command></term>
|
|||
|
<term><token>.</token> (<link linkend="dotref">dot</link> command)</term>
|
|||
|
<indexterm>
|
|||
|
<primary>source</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>source</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>.</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>.</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem><para>This command, when invoked from the command line, executes a script. Within
|
|||
|
a script, a <userinput>source file-name</userinput> loads the file
|
|||
|
<filename>file-name</filename>. This is the
|
|||
|
shell scripting equivalent of a C/C++ <userinput>#include</userinput>
|
|||
|
directive. It is useful in situations when multiple scripts use a
|
|||
|
common data file or function library.</para>
|
|||
|
|
|||
|
<example id="ex38">
|
|||
|
<title><quote>Including</quote> a data file</title>
|
|||
|
<programlisting>&ex38;</programlisting>
|
|||
|
<para>File <filename>data-file</filename> for <xref linkend="ex38">, above.
|
|||
|
Must be present in same directory.</para>
|
|||
|
<programlisting>&ex38bis;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>help</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>help</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary></secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para><command>help</command> COMMAND looks up
|
|||
|
a short usage summary of the shell builtin COMMAND. This is
|
|||
|
the counterpart to <link linkend="whatisref">whatis</link>,
|
|||
|
but for builtins.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>help exit</userinput>
|
|||
|
<computeroutput>exit: exit [n]
|
|||
|
Exit the shell with a status of N. If N is omitted, the exit status
|
|||
|
is that of the last command executed.</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<sect2>
|
|||
|
<title>Job Control Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>ps</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>ps</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>ps</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para><replaceable>P</replaceable>rocess
|
|||
|
<replaceable>S</replaceable>tatistics: lists currently
|
|||
|
executing processes by owner and PID (process id). This
|
|||
|
is usually invoked with <option>ax</option> options,
|
|||
|
and may be piped to <link linkend="grepref">grep</link>
|
|||
|
or <link linkend="sedref">sed</link> to search for a
|
|||
|
specific process (see <xref linkend="ex44"> and <xref
|
|||
|
linkend="pidid">).</para>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><userinput> ps ax | grep sendmail</userinput>
|
|||
|
<computeroutput>295 ? S 0:00 sendmail: accepting connections on port 25</computeroutput></screen>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>pstree</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>pstree</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>pstree</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Lists currently executing processes in
|
|||
|
<quote>tree</quote> format. The <option>-p</option> option
|
|||
|
shows the PIDs, as well as the process names.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="waitref"><command>wait</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>wait</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>wait</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Stop script execution until all jobs running in
|
|||
|
background have terminated, or until the job number or
|
|||
|
process id specified as an option terminates. Returns the <link
|
|||
|
linkend="exitstatusref">exit status</link> of waited-for
|
|||
|
command.</para>
|
|||
|
|
|||
|
<para>You may use the <command>wait</command> command
|
|||
|
to prevent a script from exiting before a background
|
|||
|
job finishes executing (this would create a dreaded
|
|||
|
orphan process).</para>
|
|||
|
|
|||
|
<example id="ex39">
|
|||
|
<title>Waiting for a process to finish before proceeding</title>
|
|||
|
<programlisting>&ex39;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>suspend</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>suspend</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>suspend</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This has a similar effect to
|
|||
|
<keycombo><keycap>Control</keycap><keycap>Z</keycap></keycombo>,
|
|||
|
but it suspends the shell (the shell's parent process should
|
|||
|
resume it at an appropriate time).</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>disown</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>disown</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>disown</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Remove job(s) from the shell's table of active jobs.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>jobs</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>jobs</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>jobs</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>ps</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>ps</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Lists the jobs running in the background, giving the job number.
|
|||
|
Not as useful as <command>ps</command>.</para>
|
|||
|
|
|||
|
<note>
|
|||
|
<para>It is all too easy to confuse
|
|||
|
<emphasis>jobs</emphasis> and
|
|||
|
<emphasis>processes</emphasis>. Certain <link
|
|||
|
linkend="builtinref">builtins</link>, such as
|
|||
|
<command>kill</command>, <command>disown</command>, and
|
|||
|
<command>wait</command> accept either a job number or a
|
|||
|
process number as an argument. The <command>fg</command>,
|
|||
|
<command>bg</command> and <command>jobs</command>
|
|||
|
commands accept only a job number.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>sleep 100 &</userinput>
|
|||
|
<computeroutput>[1] 1384</computeroutput>
|
|||
|
|
|||
|
<prompt>bash $ </prompt><userinput>jobs</userinput>
|
|||
|
<computeroutput>[1]+ Running sleep 100 &</computeroutput></screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para><quote>1</quote> is the job number (jobs are
|
|||
|
maintained by the current shell), and <quote>1384</quote>
|
|||
|
is the process number (processes are maintained by
|
|||
|
the system). To kill this job/process, either a <command>kill
|
|||
|
%1</command> or a <command>kill 1384</command> works.</para>
|
|||
|
|
|||
|
<para><emphasis>Thanks, S.C.</emphasis></para>
|
|||
|
</note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="timesref"><command>times</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>times</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>times</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Gives statistics on the system time used in executing commands, in the
|
|||
|
following form:
|
|||
|
<screen><computeroutput>0m0.020s 0m0.020s</computeroutput></screen>
|
|||
|
This capability is of very limited value, since it is uncommon to
|
|||
|
profile and benchmark shell scripts.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="killref"><command>kill</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>kill</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>kill</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Forcibly terminate a process by sending it an
|
|||
|
appropriate <emphasis>terminate</emphasis> signal (see <xref
|
|||
|
linkend="killprocess">).</para>
|
|||
|
|
|||
|
<note><para><userinput>kill -l</userinput> lists all the
|
|||
|
<link linkend="signald">signals</link>. A <userinput>kill
|
|||
|
-9</userinput> is a <quote>sure kill</quote>, which will
|
|||
|
usually terminate a process that stubbornly refuses to
|
|||
|
die with a plain <command>kill</command>. Sometimes, a
|
|||
|
<userinput>kill -15</userinput> works. A <quote>zombie
|
|||
|
process</quote>, that is, a process whose <link
|
|||
|
linkend="forkref">parent</link> has terminated, cannot be
|
|||
|
killed (you can't kill something that is already dead),
|
|||
|
but <command>init</command> will usually clean it up
|
|||
|
sooner or later.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>command</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>command</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>The <command>command COMMAND</command> directive
|
|||
|
disables aliases and functions for the command
|
|||
|
<quote>COMMAND</quote>.</para>
|
|||
|
|
|||
|
<note><para>This is one of three shell directives that
|
|||
|
effect script command processing. The others are
|
|||
|
<link linkend="bltref">builtin</link> and <link
|
|||
|
linkend="enableref">enable</link>.</para></note>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="bltref"><command>builtin</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>builtin</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>builtin</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>Invoking <command>builtin
|
|||
|
BUILTIN_COMMAND</command> runs the command
|
|||
|
<quote>BUILTIN_COMMAND</quote> as a shell <link
|
|||
|
linkend="builtinref">builtin</link>, temporarily disabling
|
|||
|
both functions and external system commands with the
|
|||
|
same name.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="enableref"><command>enable</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>enable</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>enable</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>This either enables or disables a shell
|
|||
|
builtin command. As an example, <command>enable -n
|
|||
|
kill</command> disables the shell builtin <link
|
|||
|
linkend="killref">kill</link>, so that when Bash
|
|||
|
subsequently encounters <command>kill</command>, it invokes
|
|||
|
<filename>/bin/kill</filename>. The <option>-a</option>
|
|||
|
option lists all the shell builtins, indicating whether
|
|||
|
or not they are enabled.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- Job Control Commands -->
|
|||
|
</sect1> <!-- Internal Commands and Builtins -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="external">
|
|||
|
<title>External Filters, Programs and Commands</title>
|
|||
|
<para>This is a descriptive listing of standard UNIX commands useful in shell
|
|||
|
scripts. The power of scripts comes from coupling system commands and
|
|||
|
shell directives with simple programming constructs.</para>
|
|||
|
|
|||
|
<sect2 id="basic">
|
|||
|
<title>Basic Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>ls</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>ls</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>ls</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The basic file <quote>list</quote> command. It is all too easy
|
|||
|
to underestimate the power of this humble command. For example,
|
|||
|
using the <option>-R</option>, recursive option,
|
|||
|
<command>ls</command> provides a tree-like listing of a directory
|
|||
|
structure.</para>
|
|||
|
|
|||
|
<example id="ex40">
|
|||
|
<title>Using <command>ls</command> to create a table of contents
|
|||
|
for burning a <abbrev>CDR</abbrev> disk</title>
|
|||
|
<programlisting>&ex40;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>cat</command></term>
|
|||
|
<term><command>tac</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>cat</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cat</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>tac</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>tac</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para><command>cat</command>, an acronym for
|
|||
|
<wordasword>concatenate</wordasword>,
|
|||
|
lists a file to <filename>stdout</filename>. When
|
|||
|
combined with redirection (<token>></token> or
|
|||
|
<token>>></token>), it is commonly used to concatenate
|
|||
|
files.
|
|||
|
|
|||
|
<programlisting>cat filename cat file.1 file.2 file.3 > file.123</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.</para>
|
|||
|
|
|||
|
<para>See also <xref linkend="lnum"> and <xref linkend="rot13">.</para>
|
|||
|
|
|||
|
<para><command>tac</command>, is the inverse of
|
|||
|
<wordasword>cat</wordasword>, listing a file backwards from its end.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>rev</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>rev</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>rev</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>reverses each line of a file, and outputs to
|
|||
|
<filename>stdout</filename>. This is not the same effect
|
|||
|
as <command>tac</command>, as it preserves the order of
|
|||
|
the lines, but flips each one around.</para>
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>cat file1.txt</userinput>
|
|||
|
<computeroutput>This is line 1.
|
|||
|
This is line 2.</computeroutput>
|
|||
|
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>tac file1.txt</userinput>
|
|||
|
<computeroutput>This is line 2.
|
|||
|
This is line 1.</computeroutput>
|
|||
|
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>rev file1.txt</userinput>
|
|||
|
<computeroutput>.1 enil si sihT
|
|||
|
.2 enil si sihT</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>cp</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>cp</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cp</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This is the file copy command. <userinput>cp file1
|
|||
|
file2</userinput> copies <filename>file1</filename>
|
|||
|
to <filename>file2</filename>, overwriting
|
|||
|
<filename>file2</filename> if it already exists (see <xref
|
|||
|
linkend="ex42">).</para>
|
|||
|
|
|||
|
<tip><para>Particularly useful are the <option>-a</option>
|
|||
|
archive flag (for copying an entire directory tree)
|
|||
|
and the <option>-r</option> and <option>-R</option>
|
|||
|
recursive flags.</para></tip>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>mv</command></term>
|
|||
|
<listitem>
|
|||
|
<para>This is the file move 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. For some examples of using
|
|||
|
<command>mv</command> in a script, see <xref linkend="rfe"> and
|
|||
|
<xref linkend="rn">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>rm</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>rm</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>rm</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Delete (remove) a file or files. The <option>-f</option>
|
|||
|
forces removal of even readonly files.</para>
|
|||
|
|
|||
|
<warning><para>When used with the recursive flag
|
|||
|
<option>-r</option>, this command removes files all the way
|
|||
|
down the directory tree.</para></warning>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>rmdir</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>rmdir</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>rmdir</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Remove directory. The directory must be empty of
|
|||
|
all files, including <anchor id="dotfilesref"> invisible
|
|||
|
<quote>dotfiles</quote>,
|
|||
|
|
|||
|
<footnote><para>These are files whose names begin with
|
|||
|
a dot, such as <filename>~/.Xdefaults</filename>. Such
|
|||
|
filenames do not show up in a normal
|
|||
|
<command>ls</command> listing, and they cannot
|
|||
|
be deleted by an accidental <command>rm -rf
|
|||
|
*</command>. Dotfiles are generally used as
|
|||
|
setup and configuration files in a user's home
|
|||
|
directory.</para></footnote>
|
|||
|
|
|||
|
for this command to succeed.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>mkdir</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>mkdir</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>mkdir</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Make directory, creates a new directory.
|
|||
|
<userinput>mkdir -p project/programs/December</userinput>
|
|||
|
creates the named directory. The
|
|||
|
<replaceable>-p</replaceable> option automatically creates
|
|||
|
any necessary parent directories.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="chmodref"><command>chmod</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>chmod</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>chmod</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Changes the attributes of an existing file (see <xref
|
|||
|
linkend="ex44">).</para>
|
|||
|
|
|||
|
<para><programlisting>chmod +x filename
|
|||
|
# Makes "filename" executable for all users.
|
|||
|
|
|||
|
chmod u+s filename
|
|||
|
# Sets "suid" bit on "filename" permissions.
|
|||
|
# An ordinary user may execute "filename" with same privileges as the file's owner.
|
|||
|
# (This does not apply to shell scripts.)</programlisting></para>
|
|||
|
|
|||
|
<para><programlisting>chmod 644 filename
|
|||
|
# Makes "filename" readable/writable to owner, readable to
|
|||
|
# others
|
|||
|
# (octal mode).</programlisting></para>
|
|||
|
|
|||
|
<para><programlisting>chmod 1777 directory-name
|
|||
|
# Gives everyone read, write, and execute permission in directory,
|
|||
|
# however also sets the "sticky bit".
|
|||
|
# This means that only the owner of the directory,
|
|||
|
# owner of the file, and, of course, root
|
|||
|
# can delete any particular file in that directory.</programlisting></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>chattr</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>chattr</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>chattr</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Change file attributes. This has the same effect
|
|||
|
as <command>chmod</command> above, but with a
|
|||
|
different invocation syntax, and it works only on an
|
|||
|
<emphasis>ext2</emphasis> filesystem.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>ln</command></term>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Creates links to pre-existings files. Most often used
|
|||
|
with the <option>-s</option>, symbolic or
|
|||
|
<quote>soft</quote> link flag. This permits referencing
|
|||
|
the linked file by more than one name and is a superior
|
|||
|
alternative to aliasing (see <xref linkend="ex18">).</para>
|
|||
|
|
|||
|
<para><userinput>ln -s oldfile newfile</userinput>
|
|||
|
links the previously existing
|
|||
|
<filename>oldfile</filename> to the newly created link,
|
|||
|
<filename>newfile</filename>.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- End Basic Commands -->
|
|||
|
|
|||
|
|
|||
|
<sect2 id="moreadv">
|
|||
|
<title>Complex Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="findref"><command>find</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>find</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>find</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>{}</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>{}</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>\;</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>escaped character</primary>
|
|||
|
<secondary>\;</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>-exec <replaceable>COMMAND</replaceable> \;</para>
|
|||
|
<para>Carries out <replaceable>COMMAND</replaceable> on
|
|||
|
each file that <command>find</command> scores a hit
|
|||
|
on. <replaceable>COMMAND</replaceable> terminates
|
|||
|
with <token>\;</token> (the <token>;</token>
|
|||
|
is escaped to make certain the shell passes it to
|
|||
|
<command>find</command> literally, which concludes the
|
|||
|
command sequence). If <replaceable>COMMAND</replaceable>
|
|||
|
contains <token>{}</token>, then <command>find</command>
|
|||
|
substitutes the full path name of the selected file.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>find ~/ -name '*.txt'</userinput>
|
|||
|
<computeroutput>/home/bozo/.kde/share/apps/karm/karmdata.txt
|
|||
|
/home/bozo/misc/irmeyc.txt
|
|||
|
/home/bozo/test-scripts/1.txt</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<programlisting>find /home/bozo/projects -mtime 1
|
|||
|
# Lists all files in /home/bozo/projects directory tree
|
|||
|
# that were modified within the last day.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<para><programlisting>find /etc -exec grep '[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*' {} \;
|
|||
|
|
|||
|
# Finds all IP addresses (xxx.xxx.xxx.xxx) in /etc directory files.
|
|||
|
# There a few extraneous hits - how can they be filtered out?
|
|||
|
|
|||
|
# Perhaps by:
|
|||
|
|
|||
|
find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
|
|||
|
| grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'
|
|||
|
|
|||
|
# Thanks, S.C.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<caution><para>The <option>-exec</option> option to
|
|||
|
<command>find</command> should not be confused with the <link
|
|||
|
linkend="execref">exec</link> shell builtin.</para></caution>
|
|||
|
|
|||
|
<example id="ex57">
|
|||
|
<title><command>Badname</command>, eliminate file names
|
|||
|
in current directory containing bad characters and <link
|
|||
|
linkend="whitespaceref">whitespace</link>.</title>
|
|||
|
<programlisting>&ex57;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See <xref linkend="ex48">, <xref linkend="ex58">,
|
|||
|
and <xref linkend="findstring"> for scripts using
|
|||
|
<command>find</command>. Its man page provides more detail
|
|||
|
on this complex and powerful command.</para>
|
|||
|
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>xargs</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>xargs</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>xargs</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>A filter for feeding arguments to a command, and also a tool for
|
|||
|
assembling the commands themselves. It breaks a data
|
|||
|
stream into small enough chunks for filters and commands
|
|||
|
to process. Consider it as a powerful replacement
|
|||
|
for backquotes. In situations where backquotes fail
|
|||
|
with a <errorname>too many arguments</errorname>
|
|||
|
error, substituting <command>xargs</command> often
|
|||
|
works. Normally, <command>xargs</command> reads from
|
|||
|
<filename>stdin</filename> or from a pipe, but it can also
|
|||
|
be given the output of a file.</para>
|
|||
|
|
|||
|
<para>The default command for <command>xargs</command> is
|
|||
|
<link linkend="echoref">echo</link>.</para>
|
|||
|
|
|||
|
<para><userinput>ls | xargs -p -l gzip</userinput> <link
|
|||
|
linkend="gzipref">gzips</link> every file in current
|
|||
|
directory, one at a time, prompting before each
|
|||
|
operation.</para>
|
|||
|
|
|||
|
<tip>
|
|||
|
<para>An interesting <command>xargs</command>
|
|||
|
option is <option>-n <replaceable>XX</replaceable></option>,
|
|||
|
which limits the number of arguments passed
|
|||
|
to <replaceable>XX</replaceable>.</para>
|
|||
|
<para><userinput>ls | xargs -n 8 echo</userinput> lists the files in the
|
|||
|
current directory in <literal>8</literal> columns.</para>
|
|||
|
</tip>
|
|||
|
|
|||
|
|
|||
|
<tip>
|
|||
|
<para>Another useful option is
|
|||
|
<option>-0</option>, in combination with <command>find
|
|||
|
-print0</command> or <command>grep -lZ</command>. This
|
|||
|
allows handling arguments containing whitespace or
|
|||
|
quotes.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<userinput>find / -type f -print0 | xargs -0 grep -liwZ GUI | xargs -0 rm -f</userinput>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<userinput>grep -rliwZ GUI / | xargs -0 rm -f</userinput>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Either of the above will remove any file containing <quote>GUI</quote>.
|
|||
|
<emphasis>(Thanks, S.C.)</emphasis></para>
|
|||
|
</tip>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<example id="ex41">
|
|||
|
<title>Log file using <command>xargs</command> to monitor system log</title>
|
|||
|
<programlisting>&ex41;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ex42">
|
|||
|
<title><command>copydir</command>, copying files in current
|
|||
|
directory to another, using <command>xargs</command></title>
|
|||
|
<programlisting>&ex42;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="exprref"><userinput>expr arg1 operation arg2 ...</userinput></term>
|
|||
|
<indexterm>
|
|||
|
<primary>expr</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>expr</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>All-purpose expression evaluator:
|
|||
|
Concatenates and evaluates the arguments according
|
|||
|
to the operation given (arguments must be separated
|
|||
|
by spaces). Operations may be arithmetic, comparison,
|
|||
|
string, or logical.</para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>expr 3 + 5</userinput></term>
|
|||
|
<listitem>
|
|||
|
<para>returns <literal>8</literal></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>expr 5 % 3</userinput></term>
|
|||
|
<listitem>
|
|||
|
<para>returns 2</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><userinput>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><userinput>z=`expr substr $string28 $position $length`</userinput></term>
|
|||
|
<listitem>
|
|||
|
<para>External programs, such as <link
|
|||
|
linkend="sedref">sed</link> and
|
|||
|
<command>Perl</command> have far superior string
|
|||
|
parsing facilities, and it might well be advisable
|
|||
|
to use these rather than the built-in Bash ones.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<example id="ex45">
|
|||
|
<title>Using <command>expr</command></title>
|
|||
|
<programlisting>&ex45;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Note that <link linkend="nullref">:</link> can
|
|||
|
substitute for <command>match</command>. Indeed,
|
|||
|
<userinput>b=`expr $a : [0-9]*`</userinput> is the
|
|||
|
exact equivalent of <userinput>b=`expr match $a
|
|||
|
[0-9]*`</userinput> in the above example.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- End Complex Commands -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect2 id="timedate">
|
|||
|
<title>Time / Date Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>date</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>date</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>date</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Simply invoked, <command>date</command> prints the date and
|
|||
|
time to <filename>stdout</filename>. Where this command gets
|
|||
|
interesting is in its formatting and parsing options.</para>
|
|||
|
|
|||
|
<example id="ex51">
|
|||
|
<title>Using <command>date</command></title>
|
|||
|
<programlisting>&ex51;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="timref"><command>time</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>time</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>time</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Outputs very verbose timing statistics for executing a command.</para>
|
|||
|
|
|||
|
<para><userinput>time ls -l /</userinput> gives something like this:
|
|||
|
<screen><computeroutput>0.00user 0.01system 0:00.05elapsed 16%CPU (0avgtext+0avgdata 0maxresident)k
|
|||
|
0inputs+0outputs (149major+27minor)pagefaults 0swaps</computeroutput></screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>See also the very similar <link
|
|||
|
linkend="timesref">times</link> command in the previous
|
|||
|
section.</para>
|
|||
|
|
|||
|
<note><para>As of <link linkend="bash2ref">version 2.0</link>
|
|||
|
of Bash, <command>time</command> became a shell reserved word,
|
|||
|
with slightly altered behavior in a pipeline.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="touchref"><command>touch</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>touch</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>touch</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Utility for updating access/modification times of a
|
|||
|
file to current system time or other specified time,
|
|||
|
but also useful for creating a new file. The command
|
|||
|
<userinput>touch zzz</userinput> will create a new file
|
|||
|
of zero length, named <filename>zzz</filename>, assuming
|
|||
|
that <filename>zzz</filename> did not previously exist.
|
|||
|
Time-stamping empty files in this way is useful for
|
|||
|
storing date information, for example in keeping track of
|
|||
|
modification times on a project.
|
|||
|
</para>
|
|||
|
|
|||
|
<para>The <command>touch</command> command is equivalent to
|
|||
|
<userinput>: >> newfile</userinput> (for ordinary
|
|||
|
files).</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="atref"><command>at</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>at</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>at</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>cron</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cron</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>at</command> job control command executes a given
|
|||
|
set of commands at a specified time. This is a user version of
|
|||
|
<link linkend="cronref">cron</link>.</para>
|
|||
|
|
|||
|
<para><userinput>at 2pm January 15</userinput> prompts for a set of
|
|||
|
commands to execute at that time. These commands may include
|
|||
|
executable shell scripts.</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 can
|
|||
|
include shell scripts, though they should, of course,
|
|||
|
be noninteractive.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>at 2:30 am Friday < at-jobs.list</userinput>
|
|||
|
<computeroutput>job 2 at 2000-10-27 02:30</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>batch</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>batch</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>batch</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>at</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>at</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>batch</command> job control command is similar to
|
|||
|
<command>at</command>, but it runs a command list when the system
|
|||
|
load drops below <literal>.8</literal>. Like
|
|||
|
<command>at</command>, it can read commands from a file with the
|
|||
|
<option>-f</option> option.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>cal</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>cal</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cal</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Prints a neatly formatted monthly calendar to
|
|||
|
<filename>stdout</filename>. Will do current year or a large
|
|||
|
range of past and future years.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>sleep</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>sleep</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>sleep</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This is the shell equivalent of a wait loop. It pauses for a
|
|||
|
specified number of seconds, doing nothing. This can be useful for
|
|||
|
timing or in processes running in the background, checking for a
|
|||
|
specific event every so often (see <xref linkend="online">).
|
|||
|
<programlisting>sleep 3
|
|||
|
# Pauses 3 seconds.</programlisting>
|
|||
|
</para>
|
|||
|
<note><para>The <command>sleep</command> command defaults to
|
|||
|
seconds, but minute, hours, or days may also be specified.
|
|||
|
<programlisting>sleep 3 h
|
|||
|
# Pauses 3 hours!</programlisting>
|
|||
|
</para></note>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>usleep</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>usleep</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>usleep</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para><emphasis>Microsleep</emphasis> (the <quote>u</quote>
|
|||
|
may be read as the Greek <quote>mu</quote>, or micro
|
|||
|
prefix). This is the same as <command>sleep</command>,
|
|||
|
above, but <quote>sleeps</quote> in microsecond
|
|||
|
intervals. This can be used for fine-grain timing, or for
|
|||
|
polling an ongoing process at very frequent intervals.
|
|||
|
<programlisting>usleep 30
|
|||
|
# Pauses 30 microseconds.</programlisting>
|
|||
|
</para>
|
|||
|
<caution><para>The <command>usleep</command> command does not
|
|||
|
provide particularly accurate timing, and is therefore
|
|||
|
unsuitable for critical timing loops.</para></caution>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>hwclock</command></term>
|
|||
|
<term><command>clock</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>hwclock</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>hwclock</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>clock</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>clock</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>hwclock</command> command accesses or
|
|||
|
adjusts the machine's hardware clock. Some
|
|||
|
options require root privileges. The
|
|||
|
<filename>/etc/rc.d/rc.sysinit</filename> startup file
|
|||
|
uses <command>hwclock</command> to set the system time
|
|||
|
from the hardware clock at bootup.</para>
|
|||
|
|
|||
|
<para>The <command>clock</command> command is a synonym for
|
|||
|
<command>hwclock</command>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- End Time / Date Commands -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect2 id="textproc">
|
|||
|
<title>Text Processing Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="sortref"><command>sort</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>sort</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>sort</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>File sorter, often used as a filter in a pipe. This
|
|||
|
command can sort a text stream or file forwards or
|
|||
|
backwards, or according to various keys or character
|
|||
|
positions. The <emphasis>info page</emphasis> lists its
|
|||
|
many options. See <xref linkend="findstring"> and <xref
|
|||
|
linkend="symlinks">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="diffref"><command>diff</command></term>
|
|||
|
<term><command>patch</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>diff</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>diff</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>patch</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>patch</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para><command>diff</command>: flexible file comparison
|
|||
|
utility. It compares the target files line-by-line
|
|||
|
sequentially. In some applications, such as comparing
|
|||
|
word dictionaries, it may be helpful to filter the
|
|||
|
files through <link linkend="sortref">sort</link>
|
|||
|
and <command>uniq</command> before piping them
|
|||
|
to <command>diff</command>. <userinput>diff file-1
|
|||
|
file-2</userinput> outputs the lines in the files that
|
|||
|
differ, with carets showing which file each particular
|
|||
|
line belongs to.</para>
|
|||
|
|
|||
|
<para>The <option>--side-by-side</option> option to
|
|||
|
<command>diff</command> outputs each compared file, line by line,
|
|||
|
in separate columns, with non-matching lines marked.</para>
|
|||
|
|
|||
|
<para>There are available various fancy frontends for
|
|||
|
<command>diff</command>, such as <command>spiff</command>,
|
|||
|
<command>wdiff</command>, <command>xdiff</command>, and
|
|||
|
<command>mgdiff</command>. </para>
|
|||
|
|
|||
|
<tip><para>The <command>diff</command> command returns an exit
|
|||
|
status of 0 if the compared files are identical, and 1 if
|
|||
|
they differ. This permits use of <command>diff</command>
|
|||
|
in a test construct within a shell script (see
|
|||
|
below).</para></tip>
|
|||
|
|
|||
|
|
|||
|
<para>A common use for <command>diff</command> is generating
|
|||
|
difference files to be used with <command>patch</command>
|
|||
|
The <option>-e</option> option outputs files suitable
|
|||
|
for <command>ed</command> or <command>ex</command>
|
|||
|
scripts.</para>
|
|||
|
|
|||
|
|
|||
|
<para><command>patch</command>: flexible versioning
|
|||
|
utility. Given a difference file generated by
|
|||
|
<command>diff</command>, <command>patch</command> can
|
|||
|
upgrade a previous version of a package to a newer version.
|
|||
|
It is much more convenient to distribute a relatively
|
|||
|
small <quote>diff</quote> file than the entire body of a
|
|||
|
newly revised package. Kernel <quote>patches</quote> have
|
|||
|
become the preferred method of distributing the frequent
|
|||
|
releases of the Linux kernel.</para>
|
|||
|
|
|||
|
<para><programlisting>patch -p1 <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 ~/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>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>diff3</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>diff3</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>diff3</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>An extended version of <command>diff</command> that compares
|
|||
|
three files at a time. This command returns an exit value
|
|||
|
of 0 upon successful execution, but unfortunately this gives
|
|||
|
no information about the results of the comparison.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>sdiff</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>sdiff</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>sdiff</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Compare and/or edit two files in order to merge
|
|||
|
them into an output file. Because of its interactive nature,
|
|||
|
this command would find little use in a script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>cmp</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>cmp</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cmp</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>cmp</command> command is a simpler version of
|
|||
|
<command>diff</command>, above. Whereas <command>diff</command>
|
|||
|
reports the differences between two files,
|
|||
|
<command>cmp</command> merely shows at what point they
|
|||
|
differ.</para>
|
|||
|
|
|||
|
<note><para>Like <command>diff</command>, <command>cmp</command>
|
|||
|
returns an exit status of 0 if the compared files are
|
|||
|
identical, and 1 if they differ. This permits use in a test
|
|||
|
construct within a shell script.</para></note>
|
|||
|
|
|||
|
<example id="filecomp">
|
|||
|
<title>Using <command>cmp</command> to compare two files
|
|||
|
within a script.</title>
|
|||
|
<programlisting>&filecomp;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>comm</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>comm</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>comm</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Versatile file comparison utility. The files must be
|
|||
|
sorted for this to be useful.</para>
|
|||
|
|
|||
|
<para><command>comm
|
|||
|
<replaceable>-options</replaceable>
|
|||
|
<replaceable>first-file</replaceable>
|
|||
|
<replaceable>second-file</replaceable></command></para>
|
|||
|
|
|||
|
<para><userinput>comm file-1 file-2</userinput> outputs three columns:
|
|||
|
<itemizedlist>
|
|||
|
<listitem><para>column 1 = lines unique to <filename>file-1</filename></para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem><para>column 2 = lines unique to <filename>file-2</filename></para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem><para>column 3 = lines common to both.</para>
|
|||
|
</listitem>
|
|||
|
</itemizedlist></para>
|
|||
|
|
|||
|
<para>The options allow suppressing output of one or more columns.
|
|||
|
<itemizedlist>
|
|||
|
<listitem><para><option>-1</option> suppresses column
|
|||
|
<literal>1</literal></para>
|
|||
|
</listitem>
|
|||
|
<listitem><para><option>-2</option> suppresses column
|
|||
|
<literal>2</literal></para>
|
|||
|
</listitem>
|
|||
|
<listitem><para><option>-3</option> suppresses column
|
|||
|
<literal>3</literal></para>
|
|||
|
</listitem>
|
|||
|
<listitem><para><option>-12</option> suppresses both columns
|
|||
|
<literal>1</literal> and <literal>2</literal>, etc.</para>
|
|||
|
</listitem>
|
|||
|
</itemizedlist>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="uniqref"><command>uniq</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>uniq</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>uniq</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This filter removes duplicate lines from a sorted
|
|||
|
file. It is often seen in a pipe coupled with
|
|||
|
<link linkend="sortref">sort</link>.
|
|||
|
<programlisting>cat list-1 list-2 list-3 | sort | uniq > final.list
|
|||
|
# Concatenates the list files,
|
|||
|
# sorts them,
|
|||
|
# removes duplicate lines,
|
|||
|
# and finally writes the result to an output file.</programlisting></para>
|
|||
|
|
|||
|
<para>The useful <option>-c</option> option prefixes each line of
|
|||
|
the input file with the number of occurrences.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="expandref"><command>expand</command></term>
|
|||
|
<term><command>unexpand</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>expand</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>expand</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>unexpand</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>unexpand</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>expand</command> filter converts tabs to
|
|||
|
spaces. It is often used in a pipe.</para>
|
|||
|
<para>The <command>unexpand</command> filter
|
|||
|
converts spaces to tabs. This reverses the effect of
|
|||
|
<command>expand</command>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>cut</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>cut</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cut</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>awk</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>awk</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>A tool for extracting fields from files. It is similar to the
|
|||
|
<userinput>print $N</userinput> command set in <link
|
|||
|
linkend="awkref">awk</link>, but more limited. It may be
|
|||
|
simpler to use <command>cut</command> in a script than
|
|||
|
<command>awk</command>. Particularly important are the
|
|||
|
<option>-d</option> (delimiter) and <option>-f</option>
|
|||
|
(field specifier) options.</para>
|
|||
|
|
|||
|
<para>Using <command>cut</command> to obtain a listing of the
|
|||
|
mounted filesystems:
|
|||
|
<programlisting>cat /etc/mtab | cut -d ' ' -f1,2</programlisting></para>
|
|||
|
|
|||
|
<para>Using <command>cut</command> to list the OS and kernel version:
|
|||
|
<programlisting>uname -a | cut -d" " -f1,3,11,12</programlisting></para>
|
|||
|
|
|||
|
<para><userinput>cut -d ' ' -f2,3 filename</userinput> is equivalent to
|
|||
|
<userinput>awk -F'[ ]' '{ print $2, $3 }' filename</userinput></para>
|
|||
|
|
|||
|
<para>See also <xref linkend="base">.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>colrm</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>colrm</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>colrm</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Column removal filter. This removes columns (characters)
|
|||
|
from a file and writes the file, lacking the range of
|
|||
|
specified columns, back to <filename>stdout</filename>.
|
|||
|
<userinput>colrm 2 4 <filename</userinput> removes the
|
|||
|
second through fourth characters from each line of the
|
|||
|
text file <filename>filename</filename>.</para>
|
|||
|
<warning><para>If the file contains tabs or nonprintable
|
|||
|
characters, this may cause unpredictable
|
|||
|
behavior. In such cases, consider using
|
|||
|
<link linkend="expandref">expand</link> and
|
|||
|
<command>unexpand</command> in a pipe preceding
|
|||
|
<command>colrm</command>.</para></warning>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>paste</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>paste</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>paste</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>cut</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cut</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Tool for merging together different files into a single,
|
|||
|
multi-column file. In combination with
|
|||
|
<command>cut</command>, useful for creating system log
|
|||
|
files.
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>join</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>join</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>join</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Consider this a special-purpose cousin of
|
|||
|
<command>paste</command>. This powerful utility allows
|
|||
|
merging two files in a meaningful fashion, which essentially
|
|||
|
creates a simple version of a relational database.</para>
|
|||
|
|
|||
|
<para>The <command>join</command> command operates on
|
|||
|
exactly two files, but pastes together only those lines
|
|||
|
with a common tagged field (usually a numerical label),
|
|||
|
and writes the result to <filename>stdout</filename>.
|
|||
|
The files to be joined should be sorted according to the
|
|||
|
tagged field for the matchups to work properly.</para>
|
|||
|
|
|||
|
<para><programlisting>File: 1.data
|
|||
|
|
|||
|
100 Shoes
|
|||
|
200 Laces
|
|||
|
300 Socks</programlisting></para>
|
|||
|
|
|||
|
<para><programlisting>File: 2.data
|
|||
|
|
|||
|
100 $40.00
|
|||
|
200 $1.00
|
|||
|
300 $2.00</programlisting></para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>join 1.data 2.data</userinput>
|
|||
|
<computeroutput>File: 1.data 2.data
|
|||
|
|
|||
|
100 Shoes $40.00
|
|||
|
200 Laces $1.00
|
|||
|
300 Socks $2.00</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<note><para>The tagged field appears only once in the
|
|||
|
output.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>head</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>head</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>head</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>lists the beginning of a file to
|
|||
|
<filename>stdout</filename> (the default is
|
|||
|
<literal>10</literal> lines, but this can be changed). It
|
|||
|
has a number of interesting options.
|
|||
|
|
|||
|
<example id="rnd">
|
|||
|
<title>Generating 10-digit random numbers</title>
|
|||
|
<programlisting>&rnd;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
See also <xref linkend="ex52">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>tail</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>tail</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>tail</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>lists the end of a file to <filename>stdout</filename>
|
|||
|
(the default is <literal>10</literal> lines). Commonly used
|
|||
|
to keep track of changes to a system logfile, using the
|
|||
|
<option>-f</option> option, which outputs lines appended
|
|||
|
to the file.</para>
|
|||
|
|
|||
|
<example id="ex12">
|
|||
|
<title>Using <command>tail</command> to monitor the system log</title>
|
|||
|
<programlisting>&ex12;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See also <xref linkend="ex41">, <xref linkend="ex52"> and
|
|||
|
<xref linkend="online">.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="grepref"><command>grep</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>grep</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>grep</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>A multi-purpose file search tool that uses
|
|||
|
<link linkend="regexref">regular
|
|||
|
expressions</link>. Originally a command/filter
|
|||
|
in the ancient <command>ed</command> line editor,
|
|||
|
<userinput>g/re/p</userinput>, or <emphasis>global -
|
|||
|
regular expression - print</emphasis>.</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>grep</command> <arg
|
|||
|
choice="plain"><replaceable>pattern</replaceable></arg>
|
|||
|
<arg choice="opt"
|
|||
|
rep="repeat"><replaceable>file</replaceable></arg>
|
|||
|
</cmdsynopsis> search the files
|
|||
|
<filename>file</filename>, etc. for occurrences of
|
|||
|
<replaceable>pattern</replaceable>.</para>
|
|||
|
|
|||
|
<para><userinput>ls -l | grep '\.txt$'</userinput> has the
|
|||
|
same effect as <userinput>ls -l *.txt</userinput> (although
|
|||
|
symbolic links may cause problems).</para>
|
|||
|
|
|||
|
<para>The <option>-i</option> option causes a case-insensitive
|
|||
|
search.</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>-v</option> (or <option>--invert-match</option>)
|
|||
|
option <emphasis>filters out</emphasis> matches.
|
|||
|
<programlisting>grep pattern1 *.txt | grep -v pattern2
|
|||
|
|
|||
|
# Matches all lines in "*.txt" files containing "pattern1",
|
|||
|
# but ***not*** "pattern2".
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
<para>The <option>-c</option> (<option>--count</option>)
|
|||
|
option gives a numerical count of matches, rather than
|
|||
|
actually listing the matches.
|
|||
|
|
|||
|
<programlisting>grep -c txt *.sgml # (number of occurrences of "txt" in "*.sgml" files)
|
|||
|
|
|||
|
|
|||
|
# grep -cz .
|
|||
|
# ^ dot
|
|||
|
# means count (-c) zero-separated (-z) items matching "."
|
|||
|
# that is, non-empty ones (containing at least 1 character).
|
|||
|
#
|
|||
|
printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz . # 4
|
|||
|
printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '$' # 5
|
|||
|
printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '^' # 5
|
|||
|
#
|
|||
|
printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -c '$' # 9
|
|||
|
# By default, newline chars (\n) separate items to match.
|
|||
|
|
|||
|
# Note that the -z option is GNU "grep" specific.
|
|||
|
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para><xref linkend="online"> demonstrates how to use
|
|||
|
<command>grep</command> to search for a word pattern in
|
|||
|
a system log file.</para>
|
|||
|
|
|||
|
<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.</para>
|
|||
|
|
|||
|
<example id="grp">
|
|||
|
<title>Emulating <quote>grep</quote> in a script</title>
|
|||
|
<programlisting>&grp;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<note><para><command>egrep</command> 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 somewhat
|
|||
|
more flexible.</para></note>
|
|||
|
|
|||
|
<note><para><command>fgrep</command> is the same as <command>grep
|
|||
|
-F</command>. It does a literal string search (no regular
|
|||
|
expressions), which generally speeds things up quite a
|
|||
|
bit.</para></note>
|
|||
|
|
|||
|
<tip><para>To search compressed files, use
|
|||
|
<command>zgrep</command>. It also works on non-compressed
|
|||
|
files, though slower than plain <command>grep</command>.
|
|||
|
This is handy for searching through a mixed set of files,
|
|||
|
some of them compressed, some not. </para></tip>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>look</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>look</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>look</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The command <command>look</command> works like
|
|||
|
<command>grep</command>, but does a lookup on
|
|||
|
a <quote>dictionary</quote>, a sorted word list.
|
|||
|
By default, <command>look</command> searches for a match
|
|||
|
in <filename>/usr/dict/words</filename>, but a different
|
|||
|
dictionary file may be specified.</para>
|
|||
|
|
|||
|
<example id="lookup">
|
|||
|
<title>Checking words in a list for validity</title>
|
|||
|
<programlisting>&lookup;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>sed</command></term>
|
|||
|
<term><command>awk</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>sed</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>sed</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>awk</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>awk</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Scripting languages especially suited for parsing text
|
|||
|
files and command output. May be embedded singly or in
|
|||
|
combination in pipes and shell scripts.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command><link linkend="sedref">sed</link></command></term>
|
|||
|
<listitem>
|
|||
|
<para>Non-interactive <quote>stream editor</quote>, permits using
|
|||
|
many <command>ex</command> commands in batch mode. It
|
|||
|
finds many uses in shell scripts.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command><link linkend="awkref">awk</link></command></term>
|
|||
|
<listitem>
|
|||
|
<para>Programmable file extractor and formatter, good for
|
|||
|
manipulating and/or extracting fields (columns) in
|
|||
|
structured text files. Its syntax is similar to C.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>groff</command></term>
|
|||
|
<term><command>gs</command></term>
|
|||
|
<term><command>TeX</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>groff</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>groff</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>gs</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>Postscript</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>TeX</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>TeX</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Groff, TeX, and Postscript are text markup languages
|
|||
|
used for preparing copy for printing or formatted video
|
|||
|
display.</para>
|
|||
|
|
|||
|
<para><emphasis>Man pages</emphasis> use
|
|||
|
<command>groff</command> (see <xref linkend="manview">).
|
|||
|
<emphasis>Ghostscript</emphasis> (<command>gs</command>)
|
|||
|
is a GPL Postscript interpreter. <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>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>wc</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>wc</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>wc</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para><emphasis>wc</emphasis> gives a <quote>word count</quote> on a file or I/O stream:
|
|||
|
<screen><prompt>bash $ </prompt><userinput>wc /usr/doc/sed-3.02/README</userinput>
|
|||
|
<computeroutput>20 127 838 /usr/doc/sed-3.02/README</computeroutput>
|
|||
|
[20 lines 127 words 838 characters]</screen></para>
|
|||
|
|
|||
|
<para><userinput>wc -w</userinput> gives only the word count.</para>
|
|||
|
<para><userinput>wc -l</userinput> gives only the line count.</para>
|
|||
|
<para><userinput>wc -c</userinput> gives only the character count.</para>
|
|||
|
<para><userinput>wc -L</userinput> gives only the length of the longest line.</para>
|
|||
|
|
|||
|
<para>Using <emphasis>wc</emphasis> to count how many
|
|||
|
<emphasis>.txt</emphasis> files are in current working directory:
|
|||
|
<programlisting>$ ls *.txt | wc -l
|
|||
|
# Will work as long as none of the "*.txt" files have a linefeed in their name.
|
|||
|
|
|||
|
# Alternative ways of doing this are:
|
|||
|
# find . -maxdepth 1 -name \*.txt -print0 | grep -cz .
|
|||
|
# (shopt -s nullglob; set -- *.txt; echo $#)
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>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><command>tr</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>tr</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>tr</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>character translation filter.</para>
|
|||
|
|
|||
|
<caution><para><link linkend="ucref">Must use quoting and/or
|
|||
|
brackets</link>, as appropriate. Quotes prevent the
|
|||
|
shell from reinterpreting the special characters in
|
|||
|
<command>tr</command> command sequences. Brackets should be
|
|||
|
quoted to prevent expansion by the shell. </para></caution>
|
|||
|
|
|||
|
<para>Either <userinput>tr "A-Z" "*" <filename</userinput>
|
|||
|
or <userinput>tr A-Z \* <filename</userinput> changes
|
|||
|
all the uppercase letters in <filename>filename</filename>
|
|||
|
to asterisks (writes to <filename>stdout</filename>).
|
|||
|
On some systems this may not work, but <userinput>tr A-Z
|
|||
|
'[**]'</userinput> will.</para>
|
|||
|
|
|||
|
<para>The <option>-d</option> option deletes a range of
|
|||
|
characters.
|
|||
|
<programlisting>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>
|
|||
|
|
|||
|
<example id="ex49">
|
|||
|
<title><command>toupper</command>: Transforms a file to all uppercase.</title>
|
|||
|
<programlisting>&ex49;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<example id="lowercase">
|
|||
|
<title><command>lowercase</command>: Changes all filenames in working directory to lowercase.</title>
|
|||
|
<programlisting>&lowercase;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="du">
|
|||
|
<title><command>du</command>: DOS to UNIX text file conversion.</title>
|
|||
|
<programlisting>&du;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="rot13">
|
|||
|
<title><command>rot13</command>: rot13, ultra-weak encryption.</title>
|
|||
|
<programlisting>&rot13;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<sidebar><title><command>tr</command> variants</title>
|
|||
|
<para>
|
|||
|
The <command>tr</command> utility has two historic
|
|||
|
variants. The BSD version does not use brackets
|
|||
|
(<userinput>tr a-z A-Z</userinput>), but the SysV one does
|
|||
|
(<userinput>tr '[a-z]' '[A-Z]'</userinput>). The GNU version
|
|||
|
of <command>tr</command> resembles the BSD one, so quoting
|
|||
|
letter ranges within brackets is mandatory.
|
|||
|
</para>
|
|||
|
</sidebar>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="foldref"><command>fold</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>fold</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>fold</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>A filter that wraps lines of input to a specified width.
|
|||
|
This is especially useful with the <option>-s</option>
|
|||
|
option, which breaks lines at word spaces (see <xref
|
|||
|
linkend="ex50"> and <xref linkend="mailformat">).</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>fmt</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>fmt</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>fmt</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Simple-minded file formatter, used as a filter in a
|
|||
|
pipe to <quote>wrap</quote> long lines of text
|
|||
|
output.</para>
|
|||
|
|
|||
|
<example id="ex50">
|
|||
|
<title>Formatted file listing.</title>
|
|||
|
<programlisting>&ex50;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See also <xref linkend="ex41">.</para>
|
|||
|
|
|||
|
<tip><para>A powerful alternative to <command>fmt</command> is
|
|||
|
Kamil Toman's <command>par</command>
|
|||
|
utility, available from <ulink
|
|||
|
url="http://www.cs.berkeley.edu/~amc/Par/">http://www.cs.berkeley.edu/~amc/Par/</ulink>.
|
|||
|
</para></tip>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>ptx</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>ptx</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>index</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>ptx [targetfile]</command> command
|
|||
|
outputs a permuted index (cross-reference list) of the
|
|||
|
targetfile. This may be further filtered and formatted in a
|
|||
|
pipe, if necessary.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>column</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>column</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>column</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Column formatter. This filter transforms list-type
|
|||
|
text output into a <quote>pretty-printed</quote> table
|
|||
|
by inserting tabs at appropriate places.</para>
|
|||
|
|
|||
|
<example id="col">
|
|||
|
<title>Using <command>column</command> to format a directory
|
|||
|
listing</title>
|
|||
|
<programlisting>&col;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>nl</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>nl</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>fmt</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Line numbering filter. <userinput>nl filename</userinput>
|
|||
|
lists <filename>filename</filename> to
|
|||
|
<filename>stdout</filename>, but inserts consecutive
|
|||
|
numbers at the beginning of each non-blank line. If
|
|||
|
<filename>filename</filename> omitted, operates on
|
|||
|
<filename>stdin.</filename></para>
|
|||
|
|
|||
|
<example id="lnum">
|
|||
|
<title><command>nl</command>: A self-numbering script.</title>
|
|||
|
<programlisting>&lnum;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>pr</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>pr</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>pr</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Print formatting filter. This will paginate files
|
|||
|
(or <filename>stdout</filename>) into sections suitable for
|
|||
|
hard copy printing or viewing on screen. Various options
|
|||
|
permit row and column manipulation, joining lines, setting
|
|||
|
margins, numbering lines, adding page headers, and merging
|
|||
|
files, among other things. The <command>pr</command>
|
|||
|
command combines much of the functionality of
|
|||
|
<command>nl</command>, <command>paste</command>,
|
|||
|
<command>fold</command>, <command>column</command>, and
|
|||
|
<command>expand</command>.</para>
|
|||
|
|
|||
|
<para><userinput>pr -o 5 --width=65 fileZZZ | more</userinput>
|
|||
|
gives a nice paginated listing to screen of
|
|||
|
<filename>fileZZZ</filename> with margins set at 5 and
|
|||
|
65.</para>
|
|||
|
|
|||
|
<para>A particularly useful option is <option>-d</option>,
|
|||
|
forcing double-spacing (same effect as <command>sed
|
|||
|
-G</command>).</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="gettextref"><command>gettext</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>gettext</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>gettext</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>A GNU utility for <link
|
|||
|
linkend="localization">localization</link> and
|
|||
|
translating the text output of programs into
|
|||
|
foreign languages. While primarily intended for C
|
|||
|
programs, <command>gettext</command> also finds
|
|||
|
use in shell scripts. See the <replaceable>info
|
|||
|
page</replaceable>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- End Text Processing Commands -->
|
|||
|
|
|||
|
|
|||
|
<sect2 id="filearchiv">
|
|||
|
<title>File and Archiving Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="tarref"><command>tar</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>tar</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>tar</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>The standard UNIX archiving utility. Originally a
|
|||
|
<wordasword>Tape ARchiving</wordasword> program,
|
|||
|
it has developed into a general purpose package that
|
|||
|
can handle all manner of archiving with all types of
|
|||
|
destination devices, ranging from tape drives to regular
|
|||
|
files to even <filename>stdout</filename> (see <xref
|
|||
|
linkend="ex58">). GNU tar has long since been patched to
|
|||
|
accept <link linkend="gzipref">gzip</link> compression
|
|||
|
options, such as <command>tar czvf archive-name.tar.gz
|
|||
|
*</command>, which recursively archives and compresses all
|
|||
|
files (except <link linkend="dotfilesref">dotfiles</link>)
|
|||
|
in a directory tree.</para>
|
|||
|
|
|||
|
<para>Some useful <command>tar</command> options:
|
|||
|
<orderedlist>
|
|||
|
<listitem><para><option>-c</option> create (a new archive)</para></listitem>
|
|||
|
<listitem><para><option>--delete</option> delete (files from the archive)</para></listitem>
|
|||
|
<listitem><para><option>-r</option> append (files to the archive)</para></listitem>
|
|||
|
<listitem><para><option>-t</option> list (archive contents)</para></listitem>
|
|||
|
<listitem><para><option>-u</option> update archive</para></listitem>
|
|||
|
<listitem><para><option>-x</option> extract (files from the archive)</para></listitem>
|
|||
|
<listitem><para><option>-z</option> <link linkend="gzipref">gzip</link> the archive</para></listitem>
|
|||
|
</orderedlist>
|
|||
|
</para>
|
|||
|
|
|||
|
<caution><para>It may be difficult to recover data from a
|
|||
|
corrupted <emphasis>gzipped</emphasis> tar
|
|||
|
archive. When archiving important files, make multiple
|
|||
|
backups.</para></caution>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>cpio</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>cpio</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cpio</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This specialized archiving copy command is rarely seen any more,
|
|||
|
having been supplanted by
|
|||
|
<command>tar</command>/<command>gzip</command>. It still
|
|||
|
has its uses, such as moving a directory tree.</para>
|
|||
|
|
|||
|
<example id="ex48">
|
|||
|
<title>Using <command>cpio</command> to move a directory tree</title>
|
|||
|
<programlisting>&ex48;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>install</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>install</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>install</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Special purpose file copying command, similar to
|
|||
|
<command>cp</command>, but capable of setting permissions
|
|||
|
and attributes of the copied files. This command seems
|
|||
|
tailormade for installing software packages, and as such it
|
|||
|
shows up frequently in <filename>Makefiles</filename> (in
|
|||
|
the <replaceable>make install :</replaceable> section). It
|
|||
|
could likewise find use in installation scripts.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="gzipref"><command>gzip</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>gzip</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>gzip</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>The standard GNU/UNIX compression utility, replacing
|
|||
|
the inferior and proprietary
|
|||
|
<command>compress</command>. The corresponding decompression
|
|||
|
command is <command>gunzip</command>, which is the equivalent of
|
|||
|
<command>gzip -d</command>.</para>
|
|||
|
|
|||
|
<para>The <command>zcat</command> filter decompresses a
|
|||
|
<emphasis>gzipped</emphasis> file to
|
|||
|
<filename>stdout</filename>, as possible input to a pipe or
|
|||
|
redirection. This is, in effect, a <command>cat</command>
|
|||
|
command that works on compressed files (including files
|
|||
|
processed with the older <command>compress</command>
|
|||
|
utility). The <command>zcat</command> command is equivalent to
|
|||
|
<command>gzip -dc</command>.</para>
|
|||
|
|
|||
|
<caution><para>On some commercial UNIX systems, <command>zcat</command>
|
|||
|
is a synonym for <command>uncompress -c</command>,
|
|||
|
and will not work on <emphasis>gzipped</emphasis>
|
|||
|
files.</para></caution>
|
|||
|
|
|||
|
<para>See also <xref linkend="ex14">.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>bzip2</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>bzip2</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>bzip2</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>An alternate compression utility, usually more efficient
|
|||
|
than <command>gzip</command>, especially on large files. The
|
|||
|
corresponding decompression command is
|
|||
|
<command>bunzip2</command>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>compress</command></term>
|
|||
|
<term><command>uncompress</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>compress</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>compress</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>uncompress</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>uncompress</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This is an older, proprietary compression
|
|||
|
utility found in commercial UNIX distributions. The
|
|||
|
more efficient <command>gzip</command> has largely
|
|||
|
replaced it. Linux distributions generally include a
|
|||
|
<command>compress</command> workalike for compatibility,
|
|||
|
although <command>gunzip</command> can unarchive files
|
|||
|
treated with <command>compress</command>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>sq</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>sq</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>sq</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Yet another compression utility, a filter that works
|
|||
|
only on sorted ASCII word lists. It uses the standard
|
|||
|
invocation syntax for a filter, <command>sq < input-file >
|
|||
|
output-file</command>. Fast, but not nearly as efficient
|
|||
|
as <link linkend="gzipref">gzip</link>. The corresponding
|
|||
|
uncompression filter is <command>unsq</command>, invoked
|
|||
|
like <command>sq</command>.</para>
|
|||
|
|
|||
|
<tip><para>The output of <command>sq</command> may be
|
|||
|
piped to <command>gzip</command> for further
|
|||
|
compression.</para></tip>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>shar</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>shar</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>shar</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Shell archiving utility. The files in a shell archive are concatenated
|
|||
|
without compression, and the resultant archive is essentially a
|
|||
|
shell script, complete with <token>#!/bin/sh</token> header, and containing all
|
|||
|
the necessary unarchiving commands. Shar archives still show up in
|
|||
|
Internet newsgroups, but otherwise <command>shar</command> has
|
|||
|
been pretty well replaced by
|
|||
|
<command>tar</command>/<command>gzip</command>. The <command>unshar</command>
|
|||
|
command unpacks <command>shar</command> archives.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>split</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>split</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>split</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Utility for splitting a file into smaller chunks. Usually used
|
|||
|
for splitting up large files in order to back them up on floppies or
|
|||
|
preparatory to e-mailing or uploading them.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="fileref"><command>file</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>file</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>file</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>A utility for identifying file types. The command
|
|||
|
<userinput>file file-name</userinput> will return a
|
|||
|
file specification for <filename>file-name</filename>,
|
|||
|
such as <computeroutput>ascii text</computeroutput> or
|
|||
|
<computeroutput>data</computeroutput>. It references
|
|||
|
the <link linkend="magnumref">magic numbers</link>
|
|||
|
found in <filename>/usr/share/magic</filename>,
|
|||
|
<filename>/etc/magic</filename>, or
|
|||
|
<filename>/usr/lib/magic</filename>, depending on the
|
|||
|
Linux/UNIX distribution.</para>
|
|||
|
|
|||
|
<example id="stripc">
|
|||
|
<title>stripping comments from C program files</title>
|
|||
|
<programlisting>&stripc;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="whichref"><command>which</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>which</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>which</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para><command>which command-xxx</command> gives the full path
|
|||
|
to <quote>command-xxx</quote>. This is useful for finding
|
|||
|
out whether a particular command or utility is installed
|
|||
|
on the system.</para>
|
|||
|
<para><userinput>$bash which rm</userinput>
|
|||
|
<screen><computeroutput>/usr/bin/rm</computeroutput></screen>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>whereis</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>whereis</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>whereis</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Similar to <command>which</command>, above,
|
|||
|
<command>whereis command-xxx</command> gives the
|
|||
|
full path to <quote>command-xxx</quote>, but also to its
|
|||
|
<emphasis>man page</emphasis>.</para>
|
|||
|
<para><userinput>$bash whereis rm</userinput>
|
|||
|
<screen><computeroutput>rm: /bin/rm /usr/share/man/man1/rm.1.bz2</computeroutput></screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="whatisref"><command>whatis</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>whatis</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>whatis</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para><command>whatis filexxx</command> looks up
|
|||
|
<quote>filexxx</quote> in the
|
|||
|
<replaceable>whatis</replaceable> database. This is useful
|
|||
|
for identifying system commands and important configuration
|
|||
|
files. Consider it a simplified <command>man</command>
|
|||
|
command.</para>
|
|||
|
<para><userinput>$bash whatis whatis</userinput>
|
|||
|
<screen><computeroutput>whatis (1) - search the whatis database for complete words</computeroutput></screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<example id="what">
|
|||
|
<title><command>Exploring <filename
|
|||
|
class="directory">/usr/X11R6/bin</filename></command></title>
|
|||
|
<programlisting>&what;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See also <xref linkend="fileinfo">.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>locate</command></term>
|
|||
|
<term><command>slocate</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>locate</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>locate</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>slocate</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>slocate</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>locate</command> command searches for files using a
|
|||
|
database stored for just that purpose. The
|
|||
|
<command>slocate</command> command is the secure version of
|
|||
|
<command>locate</command> (which may be aliased to
|
|||
|
<command>slocate</command>).</para>
|
|||
|
<para><userinput>$bash locate hickson</userinput>
|
|||
|
<screen><computeroutput>/usr/lib/xephem/catalogs/hickson.edb</computeroutput></screen></para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>basename</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>basename</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>basename</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>Strips the path information from a file name, printing
|
|||
|
only the file name. The construction <userinput>basename
|
|||
|
$0</userinput> lets the script know its name, that is, the name it
|
|||
|
was invoked by. This can be used for <quote>usage</quote> messages if,
|
|||
|
for example a script is called with missing arguments:
|
|||
|
<programlisting>echo "Usage: `basename $0` arg1 arg2 ... argn"</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>dirname</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>dirname</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>dirname</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>Strips the <command>basename</command> from a file
|
|||
|
name, printing only the path information.</para>
|
|||
|
<note>
|
|||
|
<para><command>basename</command> and <command>dirname</command>
|
|||
|
can operate on any arbitrary string. The filename given as an
|
|||
|
argument does not need to refer to an existing file.</para>
|
|||
|
</note>
|
|||
|
|
|||
|
<example id="ex35">
|
|||
|
<title><command>basename</command> and <command>dirname</command></title>
|
|||
|
<programlisting>&ex35;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>uuencode</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>uuencode</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>uuencode</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This utility encodes binary files into ASCII characters, making them
|
|||
|
suitable for transmission in the body of an e-mail message or in a
|
|||
|
newsgroup posting.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>uudecode</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>uudecode</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>uudecode</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This reverses the encoding, decoding uuencoded files back into the
|
|||
|
original binaries.</para>
|
|||
|
|
|||
|
<example id="ex52">
|
|||
|
<title>uudecoding encoded files</title>
|
|||
|
<programlisting>&ex52;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<tip><para>The <link linkend="foldref">fold -s</link> command
|
|||
|
may be useful (possibly in a pipe) to process long uudecoded
|
|||
|
text messages downloaded from Usenet newsgroups.</para></tip>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>sum</command></term>
|
|||
|
<term><command>cksum</command></term>
|
|||
|
<term><command>md5sum</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>sum</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>sum</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>cksum</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cksum</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>md5sum</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>md5sum</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>These are utilities for generating checksums. A
|
|||
|
<emphasis>checksum</emphasis> is a number mathematically
|
|||
|
calculated from the contents of a file, for the purpose
|
|||
|
of checking its integrity. A script might refer to a list
|
|||
|
of checksums for security purposes, such as ensuring that
|
|||
|
the contents of key system files have not been altered or
|
|||
|
corrupted. The <command>md5sum</command> command is the most
|
|||
|
appropriate of these in security applications.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>crypt</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>crypt</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>crypt</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>At one time, this was the standard UNIX file encryption
|
|||
|
utility.
|
|||
|
|
|||
|
<footnote><para>This is a symmetric block cipher, used to
|
|||
|
encrypt files on a single system or local network, as opposed
|
|||
|
to the <quote>public key</quote> cipher class, of which
|
|||
|
<command>pgp</command> is a well-known
|
|||
|
example.</para></footnote>
|
|||
|
|
|||
|
Politically motivated government regulations
|
|||
|
prohibiting the export of encryption software resulted
|
|||
|
in the disappearance of <command>crypt</command>
|
|||
|
from much of the UNIX world, and it is still
|
|||
|
missing from most Linux distributions. Fortunately,
|
|||
|
programmers have come up with a number of decent
|
|||
|
alternatives to it, among them the author's very own <ulink
|
|||
|
url="ftp://metalab.unc.edu/pub/Linux/utils/file/cruft-0.2.tar.gz">cruft</ulink>
|
|||
|
(see <xref linkend="encryptedpw">). </para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>strings</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>strings</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>strings</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Use the <command>strings</command> command to find
|
|||
|
printable strings in a binary or data file. It will list
|
|||
|
sequences of printable characters found in the target
|
|||
|
file. This might be handy for a quick 'n dirty examination
|
|||
|
of a core dump or for looking at an unknown graphic image
|
|||
|
file (<userinput>strings image-file | more</userinput> might
|
|||
|
show something like <computeroutput>JFIF</computeroutput>,
|
|||
|
which would identify the file as a <emphasis>jpeg</emphasis>
|
|||
|
graphic). In a script, you would probably
|
|||
|
parse the output of <command>strings</command>
|
|||
|
with <link linkend="grepref">grep</link> or <link
|
|||
|
linkend="sedref">sed</link>. See <xref linkend="bingrep">
|
|||
|
and <xref linkend="findstring">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>more</command></term>
|
|||
|
<term><command>less</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>more</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>more</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>less</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>less</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Pagers that display a text file or stream to
|
|||
|
<filename>stdout</filename>, one screenful at a time.
|
|||
|
These may be used to filter the output of a script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- End File and Archiving Commands -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect2 id="communications">
|
|||
|
<title>Communications Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>host</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>host</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>host</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Searches for information about an Internet host by name or
|
|||
|
IP address, using DNS.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>vrfy</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>vrfy</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>vrfy</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Verify an Internet e-mail address.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>nslookup</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>nslookup</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>name server lookup</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Do an Internet <quote>name server lookup</quote> on a host
|
|||
|
by IP address. This may be run either interactively or
|
|||
|
noninteractively, i.e., from within a script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>dig</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>dig</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>domain information groper</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Similar to <command>nslookup</command>, do an Internet
|
|||
|
<quote>name server lookup</quote> on a host. May be run
|
|||
|
either interactively or noninteractively, i.e., from within
|
|||
|
a script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>traceroute</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>traceroute</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>traceroute</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Trace the route taken by packets sent to a remote host. This
|
|||
|
command works within a LAN, WAN, or over the
|
|||
|
Internet. The remote host may be specified by an IP
|
|||
|
address. The output of this command may be filtered
|
|||
|
by <link linkend="grepref">grep</link> or <link
|
|||
|
linkend="sedref">sed</link> in a pipe.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>rcp</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>rcp</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>rcp</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para><quote>Remote copy</quote>, copies files between two different networked machines.
|
|||
|
Using <command>rcp</command> and similar utilities with security
|
|||
|
implications in a shell script may not be advisable. Consider
|
|||
|
instead, using an <command>expect</command> script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>sx</command></term>
|
|||
|
<term><command>rx</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>sx</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>sx</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>rx</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>rx</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>sx</command> and <command>rx</command>
|
|||
|
command set serves to transfer files to and from a remote
|
|||
|
host using the <emphasis>xmodem</emphasis> protocol. These
|
|||
|
are generally part of a communications package, such as
|
|||
|
<command>minicom</command>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>sz</command></term>
|
|||
|
<term><command>rz</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>sz</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>sz</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>rz</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>rz</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>sz</command> and <command>rz</command>
|
|||
|
command set serves to transfer files to and from a remote
|
|||
|
host using the <emphasis>zmodem</emphasis> protocol.
|
|||
|
<emphasis>Zmodem</emphasis> has certain advantages over
|
|||
|
<emphasis>xmodem</emphasis>, such as greater transmission
|
|||
|
rate and resumption of interrupted file transfers.
|
|||
|
Like <command>sx</command> and <command>rx</command>,
|
|||
|
these are generally part of a communications package.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="writeref"><command>write</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>write</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>write</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This is a utility for terminal-to-terminal communication.
|
|||
|
It allows sending lines from your terminal (console
|
|||
|
or xterm) to that of another user. The <link
|
|||
|
linkend="mesgref">mesg</link> command may, of course,
|
|||
|
be used to disable write access to a terminal</para>
|
|||
|
|
|||
|
<para>Since <command>write</command> is interactive, it
|
|||
|
would not normally find use in a script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>uucp</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>uucp</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>uucp</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para><emphasis>UNIX to UNIX copy</emphasis>. This is a
|
|||
|
communications package for transferring files between UNIX
|
|||
|
servers. A shell script is an effective way to handle a
|
|||
|
<command>uucp</command> command sequence.</para>
|
|||
|
|
|||
|
<para>Since the advent of the Internet and e-mail,
|
|||
|
<command>uucp</command> seems to have faded into obscurity,
|
|||
|
but it still exists and remains perfectly workable in
|
|||
|
situations where an Internet connection is not available
|
|||
|
or appropriate.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- End Communications Commands -->
|
|||
|
|
|||
|
<sect2 id="terminalccmds">
|
|||
|
<title>Terminal Control Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>tput</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>tput</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>terminal</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Initialize terminal and/or fetch information about it from
|
|||
|
<filename>terminfo</filename> data. Various options permit
|
|||
|
certain terminal operations. <command>tput clear</command>
|
|||
|
is the equivalent of <command>clear</command>,
|
|||
|
below. <command>tput reset</command> is the equivalent of
|
|||
|
<command>reset</command>, below.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>tput longname</userinput>
|
|||
|
<computeroutput>xterm terminal emulator (XFree86 4.0 Window System)</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Note that <link linkend="sttyref">stty</link> offers
|
|||
|
a more powerful command set for controlling a terminal.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>reset</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>reset</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>reset</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Reset terminal parameters and clear text screen. As with
|
|||
|
<command>clear</command>, the cursor and prompt reappear in the
|
|||
|
upper lefthand corner of the terminal.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>clear</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>clear</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>clear</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>clear</command> command simply clears
|
|||
|
the text screen at the console or in an xterm. The
|
|||
|
prompt and cursor reappear at the upper lefthand corner
|
|||
|
of the screen or xterm window. This command may be used
|
|||
|
either at the command line or in a script. See <xref
|
|||
|
linkend="ex30">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>script</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>script</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>script</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This utility records (saves to a file) all the user keystrokes at
|
|||
|
the command line in a console or an xterm window. This, in effect,
|
|||
|
create a record of a session.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- End Terminal Control Commands -->
|
|||
|
|
|||
|
|
|||
|
<sect2 id="mathc">
|
|||
|
<title>Math Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>factor</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>factor</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>factor</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem><para>Factor an integer into prime factors.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>factor 27417</userinput>
|
|||
|
<computeroutput>27417: 3 13 19 37</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="bcref"><command>bc</command></term>
|
|||
|
<term><command>dc</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>bc</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>bc</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>dc</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>dc</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>These are flexible, arbitrary precision calculation
|
|||
|
utilities.</para>
|
|||
|
<para><command>bc</command> has a syntax vaguely resembling C.</para>
|
|||
|
<para><command>dc</command> uses RPN (<quote>Reverse Polish
|
|||
|
Notation</quote>).</para>
|
|||
|
<para>Of the two, <command>bc</command> seems more useful in
|
|||
|
scripting. It is a fairly well-behaved UNIX utility, and may
|
|||
|
therefore be used in a pipe.</para>
|
|||
|
|
|||
|
<para>Bash can't handle floating point calculations, and
|
|||
|
it lacks operators for certain important mathematical
|
|||
|
functions. Fortunately, <command>bc</command> comes to
|
|||
|
the rescue.</para>
|
|||
|
|
|||
|
<para>Here is a simple template for using
|
|||
|
<command>bc</command> to calculate a script variable.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen>
|
|||
|
<userinput>variable=$(echo "OPTIONS; OPERATIONS" | bc)</userinput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<example id="monthlypmt">
|
|||
|
<title>Monthly Payment on a Mortgage</title>
|
|||
|
<programlisting>&monthlypmt;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="base">
|
|||
|
<title>Base Conversion</title>
|
|||
|
<programlisting>&base;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- End Math Commands -->
|
|||
|
|
|||
|
|
|||
|
<sect2 id="extmisc">
|
|||
|
<title>Miscellaneous Commands</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>jot</command></term>
|
|||
|
<term><command>seq</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>jot</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>jot</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>seq</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>seq</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>loop</primary>
|
|||
|
<secondary>arguments</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>These utilities emit a sequence of integers, with a
|
|||
|
user selected increment. This can be used to advantage in
|
|||
|
a <link linkend="forloopref">for loop</link>.</para>
|
|||
|
|
|||
|
<example id="ex53">
|
|||
|
<title>Using <command>seq</command> to generate loop arguments</title>
|
|||
|
<programlisting>&ex53;</programlisting>
|
|||
|
</example>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>yes</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>yes</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>yes</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>In its default behavior the <command>yes</command>
|
|||
|
command feeds a continuous string of the character
|
|||
|
<computeroutput>y</computeroutput> followed
|
|||
|
by a line feed to <filename>stdout</filename>. A
|
|||
|
<keycombo><keycap>control</keycap><keycap>c</keycap></keycombo>
|
|||
|
terminates the run. A different output string
|
|||
|
may be specified, as in <userinput>yes different
|
|||
|
string</userinput>, which would continually output
|
|||
|
<computeroutput>different string</computeroutput> to
|
|||
|
<filename>stdout</filename>. One might well ask the purpose
|
|||
|
of this. From the command line or in a script, the output
|
|||
|
of <command>yes</command> can be redirected or piped into a
|
|||
|
program expecting user input. In effect, this becomes a sort
|
|||
|
of poor man's version of <command>expect</command>.</para>
|
|||
|
|
|||
|
<para><userinput>yes | fsck /dev/hda1</userinput> runs
|
|||
|
<command>fsck</command> non-interactively (careful!).</para>
|
|||
|
|
|||
|
<para><userinput>yes | rm -r dirname</userinput> has same effect as
|
|||
|
<userinput>rm -rf dirname</userinput> (careful!).</para>
|
|||
|
|
|||
|
<warning><para>Be very cautious when piping <command>yes</command>
|
|||
|
to a potentially dangerous system command, such as
|
|||
|
<link linkend="fsckref">fsck</link> or
|
|||
|
<link linkend="fdiskref">fdisk</link>.</para></warning>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>printenv</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>printenv</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>environment</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Show all the environmental variables set for a particular
|
|||
|
user.</para>
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>printenv | grep HOME</userinput>
|
|||
|
<computeroutput>HOME=/home/bozo</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>lp</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>lp</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>lpr</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>lp</command> and <command>lpr</command>
|
|||
|
commands send file(s) to the print queue, to be printed as
|
|||
|
hard copy.
|
|||
|
|
|||
|
<footnote><para>The <emphasis>print queue</emphasis> is
|
|||
|
the group of jobs <quote>waiting in line</quote> to be
|
|||
|
printed.</para></footnote>
|
|||
|
|
|||
|
These commands trace the origin of their names to the
|
|||
|
line printers of another era.</para>
|
|||
|
|
|||
|
<para><prompt>bash$ </prompt><userinput>lp file1.txt</userinput>
|
|||
|
or <prompt>bash </prompt><userinput>lp
|
|||
|
<file1.txt</userinput></para>
|
|||
|
|
|||
|
<para>It is often useful to pipe the formatted output from
|
|||
|
<command>pr</command> to <command>lp</command>.</para>
|
|||
|
|
|||
|
<para><prompt>bash$ </prompt><userinput>pr -options file1.txt | lp</userinput>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Formatting packages, such as <command>groff</command> and
|
|||
|
<emphasis>Ghostscript</emphasis> may send their output
|
|||
|
directly to <command>lp</command>.</para>
|
|||
|
|
|||
|
<para><prompt>bash$ </prompt><userinput>groff -Tascii file.tr | lp</userinput>
|
|||
|
</para>
|
|||
|
|
|||
|
<para><prompt>bash$ </prompt><userinput>gs -options | lp file.ps</userinput>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Related commands are <command>lpq</command>, for viewing
|
|||
|
the print queue, and <command>lprm</command>, for removing
|
|||
|
jobs from the print queue.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>tee</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>tee</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>tee</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>[UNIX borrows an idea here from the plumbing trade.]</para>
|
|||
|
<para>This is a redirection operator, but with a difference. Like the
|
|||
|
plumber's <emphasis>tee</emphasis>, it permits <quote>siponing
|
|||
|
off</quote> the output of a command
|
|||
|
or commands within a pipe, but without affecting the result. This is
|
|||
|
useful for printing an ongoing process to a file or paper, perhaps to
|
|||
|
keep track of it for debugging purposes.</para>
|
|||
|
|
|||
|
<screen>
|
|||
|
tee
|
|||
|
|------> to file
|
|||
|
|
|
|||
|
===============|===============
|
|||
|
command--->----|-operator-->---> result of command(s)
|
|||
|
===============================
|
|||
|
</screen>
|
|||
|
|
|||
|
|
|||
|
<para><programlisting>cat listfile* | sort | tee check.file | uniq > result.file</programlisting>
|
|||
|
(The file <filename>check.file</filename> contains
|
|||
|
the concatenated sorted <quote>listfiles</quote>,
|
|||
|
before the duplicate lines are removed by <link
|
|||
|
linkend="uniqref">uniq</link>.)</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>mkfifo</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>mkfifo</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>mkfifo</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para><anchor id="namedpiperef">This obscure command
|
|||
|
creates a <emphasis>named pipe</emphasis>, a temporary
|
|||
|
<emphasis>first-in-first-out buffer</emphasis> for
|
|||
|
transferring data between processes.
|
|||
|
|
|||
|
<footnote><para>For an excellent overview of this
|
|||
|
topic, see Andy Vaught's article, <ulink
|
|||
|
url="http://www2.linuxjournal.com/lj-issues/issue41/2156.html">Introduction
|
|||
|
to Named Pipes</ulink>, in the September, 1997 issue
|
|||
|
of <ulink url="http://www.linuxjournal.com">Linux
|
|||
|
Journal</ulink>.</para></footnote>
|
|||
|
|
|||
|
Typically, one process writes to the FIFO, and the other
|
|||
|
reads from it. See <xref linkend="fifo">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>pathchk</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>pathchk</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>pathchk</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This command checks the validity of a filename. If the
|
|||
|
filename exceeds the maximum allowable length (255
|
|||
|
characters) or one or more of the directories in
|
|||
|
its path is not searchable, then an error message
|
|||
|
results. Unfortunately, <command>pathchk</command> does
|
|||
|
not return a recognizable error code, and it is therefore
|
|||
|
pretty much useless in a script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>dd</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>dd</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>dd</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This is the somewhat obscure and much feared <quote>data
|
|||
|
duplicator</quote> command. Originally a utility
|
|||
|
for exchanging data on magnetic tapes between UNIX
|
|||
|
minicomputers and IBM mainframes, this command still
|
|||
|
has its uses. The <command>dd</command> command simply
|
|||
|
copies a file (or <filename>stdin/stdout</filename>), but
|
|||
|
with conversions. Possible conversions are ASCII/EBCDIC,
|
|||
|
upper/lower case, swapping of byte pairs between input
|
|||
|
and output, and skipping and/or truncating the head or
|
|||
|
tail of the input file. A <userinput>dd --help</userinput>
|
|||
|
lists the conversion and other options that this powerful
|
|||
|
utility takes.</para>
|
|||
|
|
|||
|
<para><programlisting># Exercising 'dd'.
|
|||
|
|
|||
|
n=3
|
|||
|
p=5
|
|||
|
input_file=project.txt
|
|||
|
output_file=log.txt
|
|||
|
|
|||
|
dd if=$input_file of=$output_file bs=1 skip=$((n-1)) count=$((p-n+1)) 2> /dev/null
|
|||
|
# Extracts characters n to p from file $input_file.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
echo -n "hello world" | dd cbs=1 conv=unblock 2> /dev/null
|
|||
|
# Echoes "hello world" vertically.
|
|||
|
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>To demonstrate just how versatile <command>dd</command> is,
|
|||
|
let's use it to capture keystrokes.</para>
|
|||
|
|
|||
|
<example id="ddkeypress">
|
|||
|
<title>Capturing Keystrokes</title>
|
|||
|
<programlisting>&ddkeypress;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>The <command>dd</command> command can do random access on a
|
|||
|
data stream.
|
|||
|
|
|||
|
<programlisting>echo -n . | dd bs=1 seek=4 of=file conv=notrunc
|
|||
|
# The "conv=notrunc" option means that the output file will not be truncated.
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para>The <command>dd</command> command can copy raw data
|
|||
|
and disk images to and from devices, such as floppies and
|
|||
|
tape drives (<xref linkend="copycd">). A common use is
|
|||
|
creating boot floppies.
|
|||
|
<programlisting>dd if=kernel-image of=/dev/fd0H1440</programlisting>
|
|||
|
One important use for <command>dd</command> is initializing
|
|||
|
temporary swap files (<xref linkend="ex73">). It can even
|
|||
|
do a low-level copy of an entire hard drive partition,
|
|||
|
although this is not necessarily recommended.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="odref"><command>od</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>od</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>od</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>od</command>, or <emphasis>octal
|
|||
|
dump</emphasis> command converts input (or files) to octal
|
|||
|
(base-8) or other bases. This is useful for viewing or
|
|||
|
processing binary data files or otherwise unreadable system
|
|||
|
device files, such as <filename>/dev/urandom</filename>,
|
|||
|
and as a filter for binary data. See <xref
|
|||
|
linkend="seedingrandom"> and <xref linkend="rnd">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- End Miscellaneous Commands -->
|
|||
|
|
|||
|
</sect1> <!-- External Filters, Programs and Commands -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="system">
|
|||
|
<title>System and Administrative Commands</title>
|
|||
|
|
|||
|
|
|||
|
<para>The startup and shutdown scripts in
|
|||
|
<filename class="directory">/etc/rc.d</filename> illustrate the uses
|
|||
|
(and usefulness) of many of these comands. These are usually
|
|||
|
invoked by root and used for system maintenance or emergency
|
|||
|
filesystem repairs. Use with caution, as some of these commands
|
|||
|
may damage your system if misused.</para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>chown</command></term>
|
|||
|
<term><command>chgrp</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>chown</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>chown</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>chgrp</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>chgrp</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>chown</command> command changes the
|
|||
|
ownership of a file or files. This command is a useful
|
|||
|
method that <replaceable>root</replaceable> can use to
|
|||
|
shift file ownership from one user to another. An ordinary
|
|||
|
user may not change the ownership of files, not even her
|
|||
|
own files.
|
|||
|
<footnote><para>This is the case on a Linux machine or a UNIX
|
|||
|
system with disk quotas.</para></footnote>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>root# </prompt><userinput>chown bozo *.txt</userinput>
|
|||
|
<computeroutput></computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>The <command>chgrp</command> command changes the
|
|||
|
<replaceable>group</replaceable> ownership of a file or
|
|||
|
files. You must be owner of the file(s) as well as a member
|
|||
|
of the destination group (or <replaceable>root</replaceable>)
|
|||
|
to use this operation.
|
|||
|
<programlisting>chgrp --recursive dunderheads *.data
|
|||
|
# The "dunderheads" group will now own all the "*.data" files
|
|||
|
# in the $PWD directory tree (that's what "recursive" means).
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>uname</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>uname</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>uname</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Output system specifications (OS, kernel version,
|
|||
|
etc.) to <filename>stdout</filename>. Invoked with the
|
|||
|
<option>-a</option> option, gives verbose system info
|
|||
|
(see <xref linkend="ex41">).</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>uname -a</userinput>
|
|||
|
<computeroutput>Linux localhost.localdomain 2.2.15-2.5.0 #1 Sat Feb 5 00:13:43 EST 2000 i686 unknown</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>arch</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>arch</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>arch</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Show system architecture.
|
|||
|
Equivalent to <command>uname -m</command>. See <xref
|
|||
|
linkend="casecmd">.</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>arch</userinput>
|
|||
|
<computeroutput>i686</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>uname -m</userinput>
|
|||
|
<computeroutput>i686</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="idref"><command>id</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>id</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>id</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>The <command>id</command> command lists the real and
|
|||
|
effective user IDs and the group IDs of
|
|||
|
the current user. This is the counterpart
|
|||
|
to the <link linkend="uidref">$UID</link>,
|
|||
|
<link linkend="euidref">$EUID</link>, and <link
|
|||
|
linkend="groupsref">$GROUPS</link> internal Bash
|
|||
|
variables.</para>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><userinput>id</userinput>
|
|||
|
<computeroutput>uid=501(bozo) gid=501(bozo) groups=501(bozo),22(cdrom),80(cdwriter),81(audio)</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo $UID</userinput>
|
|||
|
<computeroutput>501</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>who</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>who</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>whoami</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Show all users logged on to the system.</para>
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>who</userinput>
|
|||
|
<computeroutput>bozo tty1 Apr 27 17:45
|
|||
|
bozo pts/0 Apr 27 17:46
|
|||
|
bozo pts/1 Apr 27 17:47
|
|||
|
bozo pts/2 Apr 27 17:49
|
|||
|
</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>The <option>-m</option> gives detailed information about
|
|||
|
only the current user. Passing any two arguments to
|
|||
|
<command>who</command> is the equivalent of <command>who
|
|||
|
-m</command>, as in <command>who am i</command> or <command>who
|
|||
|
The Man</command>.</para>
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>who -m</userinput>
|
|||
|
<computeroutput>localhost.localdomain!bozo pts/2 Apr 27 17:49</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para><anchor id="whoamiref"><command>whoami</command> is similar to <command>who
|
|||
|
-m</command>, but only lists the user name.</para>
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>whoami</userinput>
|
|||
|
<computeroutput>bozo</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>w</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>w</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>w</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Show all logged on users and the processes belonging to them. This is
|
|||
|
an extended version of <command>who</command>. The output of <command>w</command>
|
|||
|
may be piped to <command>grep</command> to find a specific user and/or process.</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>w | grep startx</userinput>
|
|||
|
<computeroutput>bozo tty1 - 4:22pm 6:41 4.47s 0.45s startx</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>logname</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>logname</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>logname</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Show current user's login name (as found in
|
|||
|
<filename>/var/run/utmp</filename>). This is a
|
|||
|
near-equivalent to <link linkend="whoamiref">whoami</link>,
|
|||
|
above.</para>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><userinput>logname</userinput>
|
|||
|
<computeroutput>bozo</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>whoami</userinput>
|
|||
|
<computeroutput>bozo</computeroutput></screen>
|
|||
|
|
|||
|
<para>However...</para>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><userinput>su</userinput>
|
|||
|
<computeroutput>Password: ......</computeroutput>
|
|||
|
|
|||
|
<prompt>bash# </prompt><userinput>whoami</userinput>
|
|||
|
<computeroutput>root</computeroutput>
|
|||
|
<prompt>bash# </prompt><userinput>logname</userinput>
|
|||
|
<computeroutput>bozo</computeroutput></screen>
|
|||
|
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>users</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>users</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>users</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Show all logged on users. This is the approximate
|
|||
|
equivalent of <command>who -q</command>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>groups</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>groups</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>groups</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Lists the current user and the groups she belongs to.
|
|||
|
This corresponds to the <link
|
|||
|
linkend="groupsref">$GROUPS</link> internal variable,
|
|||
|
but gives the group names, rather than the numbers.</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>groups</userinput>
|
|||
|
<computeroutput>bozita cdrom cdwriter audio xgrp</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo $GROUPS</userinput>
|
|||
|
<computeroutput>501</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>newgrp</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>newgrp</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>group</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Change user's group ID without logging out. This permits
|
|||
|
access to the new group's files. Since users may be
|
|||
|
members of multiple groups simultaneously, this command
|
|||
|
finds little use.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>useradd</command></term>
|
|||
|
<term><command>userdel</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>useradd</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>useradd</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>userdel</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>userdel</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>useradd</command> administrative command
|
|||
|
adds a user account to the system and creates a home
|
|||
|
directory for that particular user, if so specified. The
|
|||
|
corresponding <command>userdel</command> command removes
|
|||
|
a user account from the system
|
|||
|
<footnote><para>The <command>userdel</command> command
|
|||
|
will fail if the particular user being deleted is
|
|||
|
still logged on.</para></footnote>
|
|||
|
and deletes associated files.</para>
|
|||
|
|
|||
|
<note><para>The <command>adduser</command> command is a synonym
|
|||
|
for <command>useradd</command> and is usually a symbolic link to
|
|||
|
it.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="hnameref"><command>hostname</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>hostname</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>hostname</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Lists the system's host name. This command sets the host
|
|||
|
name in an <filename class="directory">/etc/rc.d</filename>
|
|||
|
setup script (<filename>/etc/rc.d/rc.sysinit</filename>
|
|||
|
or similar). It is equivalent to <command>uname
|
|||
|
-n</command>, and a counterpart to the <link
|
|||
|
linkend="hostnameref">$HOSTNAME</link> internal
|
|||
|
variable.</para>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><userinput>hostname</userinput>
|
|||
|
<computeroutput>localhost.localdomain</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo $HOSTNAME</userinput>
|
|||
|
<computeroutput>localhost.localdomain</computeroutput></screen>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>ulimit</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>ulimit</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>ulimit</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Sets an <emphasis>upper limit</emphasis> on system
|
|||
|
resources. Usually invoked with the <option>-f</option>
|
|||
|
option, which sets a limit on file size (<command>ulimit
|
|||
|
-f 1000</command> limits files to 1 meg maximum). The
|
|||
|
<option>-t</option> option limits the coredump size
|
|||
|
(<command>ulimit -c 0</command> eliminates coredumps).
|
|||
|
Normally, the value of <command>ulimit</command>
|
|||
|
would be set in <filename>/etc/profile</filename>
|
|||
|
and/or <filename>~/.bash_profile</filename> (see <xref
|
|||
|
linkend="files">).</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="uptimeref"><command>uptime</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>uptime</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>uptime</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Shows how long the system has been running, along with
|
|||
|
associated statistics.</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>uptime</userinput>
|
|||
|
<computeroutput>10:28pm up 1:57, 3 users, load average: 0.17, 0.34, 0.27</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>ac</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>ac</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>accounting</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Show users' logged in time, as read from
|
|||
|
<filename>/var/log/wtmp</filename>. This is one of the GNU
|
|||
|
accounting utilities.</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>ac</userinput>
|
|||
|
<computeroutput> total 68.08</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>last</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>last</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>logged in</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>List <emphasis>last</emphasis> logged in users, as read from
|
|||
|
<filename>/var/log/wtmp</filename>. This command can also
|
|||
|
show remote logins.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>lastcomm</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>lastcomm</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>last</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para> Gives information about previous commands, as stored
|
|||
|
in the <filename>/var/account/pacct</filename> file. Command
|
|||
|
name and user name can be specified by options. This is
|
|||
|
one of the GNU accounting utilities.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>env</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>env</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>env</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Runs a program or script with certain environmental
|
|||
|
variables set or changed (without changing the overall
|
|||
|
system environment). The <option>[varname=xxx]</option>
|
|||
|
permits changing the environmental variable
|
|||
|
<varname>varname</varname> for the duration of the
|
|||
|
script. With no options specified, this command lists all
|
|||
|
the environmental variable settings.</para>
|
|||
|
|
|||
|
<note><para>In Bash and other Bourne shell derivatives, it is
|
|||
|
possible to set variables in a single command's environment.
|
|||
|
<programlisting>var1=value1 var2=value2 commandXXX
|
|||
|
# $var1 and $var2 set in the environment of 'commandXXX' only.</programlisting>
|
|||
|
</para></note>
|
|||
|
|
|||
|
<tip><para>The first line of a script (the
|
|||
|
<quote>sha-bang</quote> line) may use <command>env</command>
|
|||
|
when the path to the shell or interpreter is unknown.
|
|||
|
<programlisting>#! /usr/bin/env perl
|
|||
|
|
|||
|
print "This Perl script will run,\n";
|
|||
|
print "even when I don't know where to find Perl.\n";
|
|||
|
|
|||
|
# Good for portable cross-platform scripts,
|
|||
|
# where the Perl binaries may not be in the expected place.
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para></tip>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="suref"><command>su</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>su</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>su</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Runs a program or script as a
|
|||
|
<emphasis>s</emphasis>ubstitute <emphasis>u</emphasis>ser.
|
|||
|
<command>su rjones</command> starts a shell as user
|
|||
|
<emphasis>rjones</emphasis>. A naked <command>su</command>
|
|||
|
defaults to <emphasis>root</emphasis>. See <xref
|
|||
|
linkend="fifo">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>lockfile</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>lockfile</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>lockfile</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This utility is part of the <command>procmail</command>
|
|||
|
package (<ulink url="http://www.procmail.org">www.procmail.org</ulink>).
|
|||
|
It creates a <emphasis>lock file</emphasis>, a semaphore file that
|
|||
|
controls access to a file, device, or resource. The lock file
|
|||
|
serves as a flag that this particular file, device, or resource is
|
|||
|
in use by a particular process (<quote>busy</quote>), and
|
|||
|
permitting only restricted access (or no access) to other
|
|||
|
processes. Lock files are used in such applications as protecting
|
|||
|
system mail folders from simultaneously being changed by multiple
|
|||
|
users, indicating that a modem port is being accessed, and showing
|
|||
|
that an instance of <application>Netscape</application> is using its
|
|||
|
cache. Scripts may check for the existence of a lock file created
|
|||
|
by a certain process to check if that process is running. Note
|
|||
|
that if a script attempts create a lock file that already exists,
|
|||
|
the script will likely hang.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="cronref"><command>cron</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>cron</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>cron</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Administrative program scheduler, performing such
|
|||
|
duties as cleaning up and deleting system log
|
|||
|
files and updating the <database>slocate</database>
|
|||
|
database. This is the superuser version of <link
|
|||
|
linkend="atref">at</link> (although each user may have their
|
|||
|
own <filename>crontab</filename> file which can be changed
|
|||
|
with the <command>crontab</command> command). It runs
|
|||
|
as a daemon (background process) and executes scheduled
|
|||
|
entries from <filename>/etc/crontab</filename>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>logrotate</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>logrotate</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>logrotate</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>This utility manages the system log files, rotating,
|
|||
|
compressing, deleting, and/or mailing them, as appropriate.
|
|||
|
Usually <command>cron</command> runs
|
|||
|
<command>logrotate</command> on a daily basis.</para>
|
|||
|
|
|||
|
<para>Adding an appropriate entry to
|
|||
|
<filename>/etc/logrotate.conf</filename> makes it possible
|
|||
|
to manage personal log files, as well as system-wide
|
|||
|
ones.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>chroot</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>chroot</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>chroot</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>directory</primary>
|
|||
|
<secondary>root</secondary>
|
|||
|
<tertiary>change</tertiary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>CHange ROOT directory. Normally commands are fetched
|
|||
|
from <link linkend="pathref">$PATH</link>, relative to
|
|||
|
<filename class="directory">/</filename>, the default root
|
|||
|
directory. This changes the root directory to a different
|
|||
|
one (and also changes the working directory to there).
|
|||
|
This is useful for security purposes, for instance when
|
|||
|
the system administrator wishes to restrict certain users,
|
|||
|
such as those telnetting in, to a secured portion of the
|
|||
|
filesystem (this is sometimes referred to as confining
|
|||
|
a guest user to a <quote>chroot jail</quote>). Note that
|
|||
|
after a <command>chroot</command>, the execution path for
|
|||
|
system binaries is no longer valid.</para>
|
|||
|
|
|||
|
<para>A <userinput>chroot /opt</userinput> would cause
|
|||
|
references to <filename
|
|||
|
class="directory">/usr/bin</filename>
|
|||
|
to be translated to <filename
|
|||
|
class="directory">/opt/usr/bin</filename>. Likewise,
|
|||
|
<userinput>chroot /aaa/bbb /bin/ls</userinput> would
|
|||
|
redirect future instances of <command>ls</command>
|
|||
|
to <filename>/aaa/bbb</filename> as the base directory,
|
|||
|
rather than <filename class="directory">/</filename> as is
|
|||
|
normally the case. An <command>alias XX 'chroot /aaa/bbb
|
|||
|
ls'</command> in a user's <filename>~/.bashrc</filename>
|
|||
|
effectively restricts which portion of the filesystem
|
|||
|
she may run command <quote>XX</quote> on.</para>
|
|||
|
|
|||
|
|
|||
|
<para>The <command>chroot</command> command is also handy
|
|||
|
when running from an emergency boot floppy
|
|||
|
(<command>chroot</command> to <filename>/dev/fd0</filename>),
|
|||
|
or as an option to <command>lilo</command> when recovering
|
|||
|
from a system crash. Other uses include installation
|
|||
|
from a different filesystem (an <command>rpm</command>
|
|||
|
option) or running a readonly filesystem from a CD ROM.
|
|||
|
Invoke only as root, and use with care.</para>
|
|||
|
|
|||
|
<caution><para>It might be necessary to copy certain system
|
|||
|
files to a <emphasis>chrooted</emphasis> directory,
|
|||
|
since the normal <varname>$PATH</varname> can no longer
|
|||
|
be relied upon.</para></caution>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<indexterm>
|
|||
|
<primary>umask</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>umask</secondary>
|
|||
|
</indexterm>
|
|||
|
<term><command>umask</command></term>
|
|||
|
<listitem>
|
|||
|
<para>User file creation MASK. Limit the default file attributes
|
|||
|
for a particular user. All files created by that user take
|
|||
|
on the attributes specified by <command>umask</command>. The
|
|||
|
(octal) value passed to <command>umask</command> defines the
|
|||
|
the file permissions <emphasis>disabled</emphasis>. For
|
|||
|
example, <command>umask 022</command> ensures that
|
|||
|
new files will have at most 755 permissions (777 NAND 022).
|
|||
|
|
|||
|
<footnote><para>NAND is the logical <quote>not-and</quote>
|
|||
|
operator. Its effect is somewhat similar to
|
|||
|
subtraction.</para></footnote>
|
|||
|
|
|||
|
Of course, the user may later change the
|
|||
|
attributes of particular files with <link
|
|||
|
linkend="chmodref">chmod</link>.The usual practice
|
|||
|
is to set the value of <command>umask</command>
|
|||
|
in <filename>/etc/profile</filename> and/or
|
|||
|
<filename>~/.bash_profile</filename> (see <xref
|
|||
|
linkend="files">).</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>ldd</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>ldd</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>ldd</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Show shared lib dependencies for an executable file.</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>ldd /bin/ls</userinput>
|
|||
|
<computeroutput>libc.so.6 => /lib/libc.so.6 (0x4000c000)
|
|||
|
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>tty</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>tty</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>tty</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Echoes the name of the current user's terminal.
|
|||
|
Note that each separate xterm window counts as a different
|
|||
|
terminal.</para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>tty</userinput>
|
|||
|
<computeroutput>/dev/pts/1</computeroutput></screen>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="sttyref"><command>stty</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>stty</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>stty</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Shows and/or changes terminal settings. This complex
|
|||
|
command, used in a script, can control terminal behavior
|
|||
|
and the way output displays. See the info page, and study
|
|||
|
it carefully.</para>
|
|||
|
|
|||
|
<example id="secretpw">
|
|||
|
<title><command>secret password</command>:
|
|||
|
Turning off terminal echoing </title>
|
|||
|
<programlisting>&secretpw;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>A creative use of <command>stty</command> is detecting a
|
|||
|
user keypress (without hitting
|
|||
|
<keycap>ENTER</keycap>).</para>
|
|||
|
|
|||
|
<example id="keypress">
|
|||
|
<title>Keypress detection</title>
|
|||
|
<programlisting>&keypress;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Also see <xref linkend="timeout">.</para>
|
|||
|
|
|||
|
|
|||
|
<sidebar><title>terminals and modes</title>
|
|||
|
|
|||
|
<para>Normally, a terminal works in the
|
|||
|
<emphasis>canonical</emphasis> mode. When a user hits a
|
|||
|
key, the resulting character does not immediately go to
|
|||
|
the program actually running in this terminal. A buffer
|
|||
|
local to the terminal stores keystrokes. When the user
|
|||
|
hits the <keycap>ENTER</keycap> key, this sends all the
|
|||
|
stored keystrokes to the program running. There is even
|
|||
|
a basic line editor inside the terminal.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>stty -a</userinput>
|
|||
|
<computeroutput>speed 9600 baud; rows 36; columns 96; line = 0;
|
|||
|
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
|
|||
|
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O;
|
|||
|
...
|
|||
|
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Using canonical mode, it is possible to redefine the
|
|||
|
special keys for the local terminal line editor.
|
|||
|
|
|||
|
<screen>
|
|||
|
<prompt>bash$ </prompt><userinput>cat > filexxx</userinput>
|
|||
|
<userinput>wha<ctl-W>I<ctl-H>foo bar<ctl-U>hello world<ENTER></userinput>
|
|||
|
<userinput><ctl-D></userinput>
|
|||
|
<prompt>bash$ </prompt><userinput>cat filexxx</userinput>
|
|||
|
<computeroutput>hello world</computeroutput>
|
|||
|
<prompt>bash$ </prompt><userinput>bash$ wc -c < file</userinput>
|
|||
|
<computeroutput>13</computeroutput>
|
|||
|
</screen>
|
|||
|
|
|||
|
The process controlling the terminal receives only 13
|
|||
|
characters (12 alphabetic ones, plus a newline), although
|
|||
|
the user hit 26 keys.
|
|||
|
</para>
|
|||
|
|
|||
|
<para>In non-canonical (<quote>raw</quote>) mode, every
|
|||
|
key hit (including special editing keys such as
|
|||
|
<keycap>ctl-H</keycap>) sends a character immediately to
|
|||
|
the controlling process.</para>
|
|||
|
|
|||
|
|
|||
|
<para>The Bash prompt disables both <option>icanon</option>
|
|||
|
and <option>echo</option>, since it replaces the basic
|
|||
|
terminal line editor with its own more elaborate one. For
|
|||
|
example, when you hit <keycap>ctl-A</keycap> at the Bash
|
|||
|
prompt, there's no <keycap>^A</keycap> echoed by the
|
|||
|
terminal, but Bash gets a <keycap>\1</keycap> character,
|
|||
|
interprets it, and moves the cursor to the begining of
|
|||
|
the line.</para>
|
|||
|
|
|||
|
<para><emphasis>Stephane Chazelas</emphasis></para>
|
|||
|
|
|||
|
</sidebar>
|
|||
|
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>tset</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>tset</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>tset</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Show or initialize terminal settings.
|
|||
|
This is a less capable version of
|
|||
|
<command>stty</command>.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>tset -r</userinput>
|
|||
|
<computeroutput>Terminal type is xterm-xfree86.
|
|||
|
Kill is control-U (^U).
|
|||
|
Interrupt is control-C (^C).</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>getty</command></term>
|
|||
|
<term><command>agetty</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>getty</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>getty</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>agetty</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>agetty</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The initialization process for a terminal uses
|
|||
|
<command>getty</command> or <command>agetty</command>
|
|||
|
to set it up for login by a user. These commands are not
|
|||
|
used within user shell scripts. Their scripting counterpart
|
|||
|
is <command>stty</command>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="mesgref"><command>mesg</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>mesg</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>mesg</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Enables or disables write access to the current user's
|
|||
|
terminal. Disabling access would prevent another user
|
|||
|
on the network to <link linkend="writeref">write</link>
|
|||
|
to the terminal.</para>
|
|||
|
|
|||
|
<tip><para>It can be very annoying to have a message
|
|||
|
about ordering pizza suddenly appear in the middle of
|
|||
|
the text file you are editing. On a multi-user network,
|
|||
|
you might therefore wish to disable write access to your
|
|||
|
terminal when you need to avoid interruptions.</para></tip>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>wall</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>wall</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>wall</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>This is an acronym for <quote><link
|
|||
|
linkend="writeref">write</link> all</quote>, i.e., sending
|
|||
|
a message to all users at every terminal logged into the
|
|||
|
network. It is primarily a system administrator's tool,
|
|||
|
useful, for example, when warning everyone that the
|
|||
|
system will shortly go down due to a problem (see <xref
|
|||
|
linkend="ex70">).</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>wall System going down for maintenance in 5 minutes!</userinput>
|
|||
|
<computeroutput>Broadcast message from bozo (pts/1) Sun Jul 8 13:53:27 2001...
|
|||
|
|
|||
|
System going down for maintenance in 5 minutes!</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<note><para>If write access to a particular terminal has been
|
|||
|
disabled with <command>mesg</command>, then
|
|||
|
<command>wall</command> cannot send a message to
|
|||
|
it.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>logger</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>logger</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>logger</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Appends a user-generated message to the system log
|
|||
|
(<filename>/var/log/messages</filename>). You do not have
|
|||
|
to be root to invoke <command>logger</command>.
|
|||
|
<programlisting>logger Experiencing instability in network connection at 23:10, 05/21.
|
|||
|
# Now, do a 'tail /var/log/messages'.</programlisting></para>
|
|||
|
|
|||
|
<para>By embedding a <command>logger</command> command in a script,
|
|||
|
it is possible to write debugging information to
|
|||
|
<filename>/var/log/messages</filename>.
|
|||
|
<programlisting>logger -t $0 -i Logging at line "$LINENO".
|
|||
|
# The "-t" option specifies the tag for the logger entry.
|
|||
|
# The "-i" option records the process ID.
|
|||
|
|
|||
|
# tail /var/log/message
|
|||
|
# ...
|
|||
|
# Jul 7 20:48:58 localhost ./test.sh[1712]: Logging at line 3.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>dmesg</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>dmesg</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>dmesg</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Lists all system bootup messages to
|
|||
|
<filename>stdout</filename>. Handy for debugging and
|
|||
|
ascertaining which device drivers were installed
|
|||
|
and which system interrupts in use. The output
|
|||
|
of <command>dmesg</command> may, of course, be
|
|||
|
parsed with <link linkend="grepref">grep</link>,
|
|||
|
<link linkend="sedref">sed</link>, or <link
|
|||
|
linkend="awkref">awk</link> from within a script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>fuser</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>fuser</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>fuser</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Identifies the processes (by pid) that are accessing
|
|||
|
a given file, set of files, or directory. May also be
|
|||
|
invoked with the <option>-k</option> option, which kills
|
|||
|
those processes. This has interesting implications for
|
|||
|
system security, especially in scripts preventing
|
|||
|
unauthorized users from accessing system services.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>stat</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>stat</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>stat</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Gives detailed and verbose <emphasis>stat</emphasis>istics
|
|||
|
on a given file (even a directory or device file) or set
|
|||
|
of files.</para>
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>stat test.cru</userinput>
|
|||
|
<computeroutput> File: "test.cru"
|
|||
|
Size: 49970 Allocated Blocks: 100 Filetype: Regular File
|
|||
|
Mode: (0664/-rw-rw-r--) Uid: ( 501/ bozo) Gid: ( 501/ bozo)
|
|||
|
Device: 3,8 Inode: 18185 Links: 1
|
|||
|
Access: Sat Jun 2 16:40:24 2001
|
|||
|
Modify: Sat Jun 2 16:40:24 2001
|
|||
|
Change: Sat Jun 2 16:40:24 2001</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>lsof</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>lsof</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>lsof</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>List open files. This command outputs a detailed
|
|||
|
table of all currently open files and gives information
|
|||
|
about their owner, size, the processes associated with
|
|||
|
them, and more. Of course, <command>lsof</command> may
|
|||
|
be piped to <link linkend="grepref">grep</link> and/or
|
|||
|
<link linkend="awkref">awk</link> to parse and analyze
|
|||
|
its results.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>lsof</userinput>
|
|||
|
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
|
|||
|
init 1 root mem REG 3,5 30748 30303 /sbin/init
|
|||
|
init 1 root mem REG 3,5 73120 8069 /lib/ld-2.1.3.so
|
|||
|
init 1 root mem REG 3,5 931668 8075 /lib/libc-2.1.3.so
|
|||
|
cardmgr 213 root mem REG 3,5 36956 30357 /sbin/cardmgr
|
|||
|
...</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="pidofref"><command>pidof</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>pidof</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>process id</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Identifies <emphasis>process id (pid)</emphasis> of a
|
|||
|
running job. Since job control commands, such as <link
|
|||
|
linkend="killref">kill</link> and <command>renice</command>
|
|||
|
act on the <emphasis>pid</emphasis> of a process (not
|
|||
|
its name), it is sometimes necessary to identify that
|
|||
|
<emphasis>pid</emphasis>. The <command>pidof</command>
|
|||
|
command is the approximate counterpart to the <link
|
|||
|
linkend="ppidref">$PPID</link> internal variable.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>pidof xclock</userinput>
|
|||
|
<computeroutput>880</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<example id="killprocess">
|
|||
|
<title><command>pidof</command> helps kill a process</title>
|
|||
|
<programlisting>&killprocess;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>nice</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>nice</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>nice</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Run a background job with an altered
|
|||
|
priority. Priorities run from 19 (lowest) to -20
|
|||
|
(highest). Only <emphasis>root</emphasis> may set the
|
|||
|
negative (higher) priorities. Related commands are
|
|||
|
<command>renice</command>, <command>snice</command>,
|
|||
|
and <command>skill</command>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>nohup</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>nohup</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>nohup</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Keeps a command running even after user logs off.
|
|||
|
The command will run as a foreground process unless followed
|
|||
|
by <token>&</token>. If you use <command>nohup</command>
|
|||
|
within a script, consider coupling it with a <link
|
|||
|
linkend="waitref">wait</link> to avoid creating an orphan
|
|||
|
or zombie process.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="freeref"><command>free</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>free</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>free</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Shows memory and cache usage in tabular form. The
|
|||
|
output of this command lends itself to parsing, using
|
|||
|
<link linkend="grepref">grep</link>, <link
|
|||
|
linkend="awkref">awk</link> or <command>Perl</command>. The
|
|||
|
<command>procinfo</command> command shows all the
|
|||
|
information that <command>free</command> does, and much
|
|||
|
more.</para>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><command>free</command>
|
|||
|
<computeroutput> total used free shared buffers cached
|
|||
|
Mem: 30504 28624 1880 15820 1608 16376
|
|||
|
-/+ buffers/cache: 10640 19864
|
|||
|
Swap: 68540 3128 65412</computeroutput></screen>
|
|||
|
|
|||
|
<para>To show unused RAM memory:</para>
|
|||
|
<screen><prompt>bash$ </prompt><command>free | grep Mem | awk '{ print $4 }'</command>
|
|||
|
<computeroutput>1880</computeroutput></screen>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="procinforef"><command>procinfo</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>procinfo</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>procinfo</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Extract and list information and statistics from the
|
|||
|
<link linkend="devprocref"><filename
|
|||
|
class="directory">/proc</filename>
|
|||
|
pseudo-filesystem</link>. This gives a very extensive and
|
|||
|
detailed listing.</para>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><userinput>procinfo | grep Bootup</userinput>
|
|||
|
<computeroutput>Bootup: Wed Mar 21 15:15:50 2001 Load average: 0.04 0.21 0.34 3/47 6829</computeroutput>
|
|||
|
</screen>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>du</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>du</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>du</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Show (disk) file usage, recursively. Defaults to current
|
|||
|
working directory, unless otherwise specified.</para>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><command>du -ach</command>
|
|||
|
<computeroutput>1.0k ./wi.sh
|
|||
|
1.0k ./tst.sh
|
|||
|
1.0k ./random.file
|
|||
|
6.0k .
|
|||
|
6.0k total</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>df</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>df</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>df</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Shows filesystem usage in tabular form.</para>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><command>df</command>
|
|||
|
<computeroutput>Filesystem 1k-blocks Used Available Use% Mounted on
|
|||
|
/dev/hda5 273262 92607 166547 36% /
|
|||
|
/dev/hda8 222525 123951 87085 59% /home
|
|||
|
/dev/hda7 1408796 1075744 261488 80% /usr</computeroutput></screen>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>sync</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>sync</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>sync</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Forces an immediate write of all updated data from
|
|||
|
buffers to hard drive (synchronize drive
|
|||
|
with buffers). While not strictly necessary, a
|
|||
|
<command>sync</command> assures the sys admin or
|
|||
|
user that the data just changed will survive a sudden
|
|||
|
power failure. In the olden days, a <userinput>sync;
|
|||
|
sync</userinput> (twice, just to make absolutely sure) was a
|
|||
|
useful precautionary measure before a system reboot.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>init</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>init</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>init</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>init</command> command is the <link
|
|||
|
linkend="forkref">parent</link> of all processes. Called
|
|||
|
in the final step of a bootup, <command>init</command>
|
|||
|
determines the runlevel of the system from
|
|||
|
<filename>/etc/inittab</filename>. Invoked by its alias
|
|||
|
<command>telinit</command>, and by root only.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>telinit</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>telinit</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>telinit</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Symlinked to <command>init</command>, this is a means of changing the system runlevel,
|
|||
|
usually done for system maintenance or emergency filesystem
|
|||
|
repairs. Invoked only by root. This command can be dangerous - be
|
|||
|
certain you understand it well before using!</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>runlevel</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>runlevel</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>runlevel</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Shows the current and last runlevel, that is, whether the system
|
|||
|
is halted (runlevel <literal>0</literal>), in single-user mode
|
|||
|
(<literal>1</literal>), in multi-user mode (<literal>2</literal>
|
|||
|
or <literal>3</literal>), in X Windows (<literal>5</literal>), or
|
|||
|
rebooting (<literal>6</literal>). This command accesses the
|
|||
|
<filename>/var/run/utmp</filename> file.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>halt</command></term>
|
|||
|
<term><command>shutdown</command></term>
|
|||
|
<term><command>reboot</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>halt</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>halt</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>shutdown</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>shutdown</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>reboot</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>reboot</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Command set to shut the system down, usually just prior to a power down.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>ifconfig</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>ifconfig</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>ifconfig</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Network interface configuration and tuning utility.
|
|||
|
It is most often used at bootup to set up the interfaces,
|
|||
|
or to shut them down when rebooting.
|
|||
|
<programlisting># Code snippets from /etc/rc.d/init.d/network
|
|||
|
|
|||
|
# ...
|
|||
|
|
|||
|
# Check that networking is up.
|
|||
|
[ ${NETWORKING} = "no" ] && exit 0
|
|||
|
|
|||
|
[ -x /sbin/ifconfig ] || exit 0
|
|||
|
|
|||
|
# ...
|
|||
|
|
|||
|
for i in $interfaces ; do
|
|||
|
if ifconfig $i 2>/dev/null | grep -q "UP" >/dev/null 2>&1 ; then
|
|||
|
action "Shutting down interface $i: " ./ifdown $i boot
|
|||
|
fi
|
|||
|
# The GNU-specific "-q" option to 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>
|
|||
|
|
|||
|
See also <xref linkend="online">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>route</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>route</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>route</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Show info about or make changes to the kernel routing table.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>route</userinput>
|
|||
|
<computeroutput>Destination Gateway Genmask Flags Metric Ref Use Iface
|
|||
|
127.0.0.0 * 255.0.0.0 U 0 0 0 lo</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>netstat</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>netstat</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>netstat</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Show current network information and statistics,
|
|||
|
such as routing tables and active connections. This utility
|
|||
|
accesses information in <filename>/proc/net</filename>
|
|||
|
(<xref linkend="devproc">). See <xref
|
|||
|
linkend="constat">.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>mknod</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>mknod</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>mknod</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Creates block or character device files (may be necessary when installing
|
|||
|
new hardware on the system).</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>mount</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>mount</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>mount</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Mount a filesystem, usually on an external device,
|
|||
|
such as a floppy or CDROM. The file
|
|||
|
<filename>/etc/fstab</filename> provides a handy listing
|
|||
|
of available filesystems, partitions, and devices,
|
|||
|
including options, that may be automatically or manually
|
|||
|
mounted. The file <filename>/etc/mtab</filename> shows
|
|||
|
the currently mounted filesystems and partitions
|
|||
|
(including the virtual ones, such as <filename
|
|||
|
class="directory">/proc</filename>).</para>
|
|||
|
|
|||
|
<para><command>mount -a</command> mounts all filesystems and
|
|||
|
partitions listed in <filename>/etc/fstab</filename>,
|
|||
|
except those with a <option>noauto</option>
|
|||
|
option. At bootup, a startup script in
|
|||
|
<filename class="directory">/etc/rc.d</filename>
|
|||
|
(<filename>rc.sysinit</filename> or something similar)
|
|||
|
invokes this to get everything mounted.</para>
|
|||
|
|
|||
|
|
|||
|
<para><programlisting>mount -t iso9660 /dev/cdrom /mnt/cdrom
|
|||
|
# Mounts CDROM
|
|||
|
mount /mnt/cdrom
|
|||
|
# Shortcut, if /mnt/cdrom listed in /etc/fstab</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>This versatile command can even mount an ordinary file as if
|
|||
|
it were a filesystem on a block device. It accomplishes that by
|
|||
|
associating the file with a <link linkend="loopbackref">loopback
|
|||
|
device</link>. One application of this is to mount and examine an
|
|||
|
ISO9660 image before burning it onto a CDR.
|
|||
|
|
|||
|
<footnote><para>For more detail on burning CDRs, see Alex
|
|||
|
Withers' article, <ulink
|
|||
|
url="http://www2.linuxjournal.com/lj-issues/issue66/3335.html">Creating
|
|||
|
CDs</ulink>, in the October, 1999 issue of <ulink
|
|||
|
url="http://www.linuxjournal.com">Linux
|
|||
|
Journal</ulink>.</para></footnote>
|
|||
|
|
|||
|
</para>
|
|||
|
|
|||
|
<example id="isomountref">
|
|||
|
<title>Checking a CD image</title>
|
|||
|
<programlisting># As root...
|
|||
|
|
|||
|
mkdir /mnt/cdtest # Prepare a mount point, if not already there.
|
|||
|
|
|||
|
mount -r -t iso9660 -o loop cd-image.iso /mnt/cdtest # Mount the image.
|
|||
|
# "-o loop" option equivalent to "losetup /dev/loop0"
|
|||
|
cd /mnt/cdtest # Now, check the image.
|
|||
|
ls -alR # List the files in the directory tree there.
|
|||
|
# And so forth.</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>umount</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>umount</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>umount</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Unmount a currently mounted filesystem. Before physically removing a
|
|||
|
previously mounted floppy or CDROM disk, the device must be
|
|||
|
<command>umount</command>ed, else filesystem corruption may result.
|
|||
|
<programlisting>umount /mnt/cdrom
|
|||
|
# You may now press the eject button and safely remove the disk.</programlisting></para>
|
|||
|
|
|||
|
<note><para>The <command>automount</command> utility, if
|
|||
|
properly installed, can mount and unmount floppies or
|
|||
|
CDROM disks as they are accessed or removed. On laptops
|
|||
|
with swappable floppy and CDROM drives, this can cause
|
|||
|
problems, though.</para></note>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>mkswap</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>mkswap</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>mkswap</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Creates a swap partition or file. The swap area must
|
|||
|
subsequently be enabled with
|
|||
|
<command>swapon</command>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>swapon</command></term>
|
|||
|
<term><command>swapoff</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>swapon</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>swapon</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>swapoff</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>swapoff</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Enable / disable swap partitition or file.
|
|||
|
These commands usually take effect at bootup and
|
|||
|
shutdown.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>dumpe2fs</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>dumpe2fs</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>dumpe2fs</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Dump (list to <filename>stdout</filename>) very verbose
|
|||
|
filesystem info. This must be invoked as root.</para>
|
|||
|
|
|||
|
<screen><prompt>root# </prompt><command>dumpe2fs /dev/hda7 | grep 'ount count'</command>
|
|||
|
<computeroutput>dumpe2fs 1.19, 13-Jul-2000 for EXT2 FS 0.5b, 95/08/09
|
|||
|
Mount count: 6
|
|||
|
Maximum mount count: 20</computeroutput></screen>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>tune2fs</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>tune2fs</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>tune2fs</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Tune ext2 filesystem. May be used to change filesystem
|
|||
|
parameters, such as maximum mount count. This must be
|
|||
|
invoked as root.</para>
|
|||
|
|
|||
|
<warning><para>This is an extremely dangerous command. Use it at
|
|||
|
your own risk, as you may inadvertently destroy your filesystem.
|
|||
|
</para></warning>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="fdiskref"><command>fdisk</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>fdisk</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>fdisk</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Create or change a partition table on a storage device,
|
|||
|
usually a hard drive. This command must be invoked as
|
|||
|
root.</para>
|
|||
|
<warning><para>Use this command with extreme caution. If something
|
|||
|
goes wrong, you may destroy an existing
|
|||
|
filesystem.</para></warning>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>mke2fs</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>mke2fs</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>mke2fs</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Create a Linux ext2 filesystem. This command must be invoked
|
|||
|
as root.</para>
|
|||
|
|
|||
|
<example id="adddrv">
|
|||
|
<title>Adding a new hard drive</title>
|
|||
|
<programlisting>&adddrv;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>dump</command></term>
|
|||
|
<term><command>restore</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>dump</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>dump</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>restore</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>restore</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>The <command>dump</command> command is an elaborate
|
|||
|
filesystem backup utility, generally used on larger
|
|||
|
installations and networks.
|
|||
|
<footnote><para>Operators of single-user Linux systems
|
|||
|
generally prefer something simpler for backups, such
|
|||
|
as <command>tar</command>.</para></footnote>
|
|||
|
It reads raw disk partitions and writes a backup file
|
|||
|
in a binary format. Files to be backed up may be saved
|
|||
|
to a variety of storage media, including disks and tape
|
|||
|
drives. The <command>restore</command> command restores
|
|||
|
backups made with <command>dump</command>.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>rdist</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>rdist</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>rdist</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Remote distribution client: synchronizes, clones,
|
|||
|
or backs up a file system on a remote server.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="fsckref"><command>fsck</command></term>
|
|||
|
<term><command>e2fsck</command></term>
|
|||
|
<term><command>debugfs</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>fsck</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>fsck</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>e2fsck</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>e2fsck</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>debugfs</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>debugfs</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Filesystem check, repair, and debug command set.</para>
|
|||
|
<para><command>fsck</command>: a front end for checking a UNIX
|
|||
|
filesystem (may invoke other utilities). The actual
|
|||
|
filesystem type generally defaults to ext2.</para>
|
|||
|
<para><command>e2fsck</command>: ext2 filesystem checker.</para>
|
|||
|
<para><command>debugfs</command>: ext2 filesystem debugger.</para>
|
|||
|
<caution><para>All of these should be invoked as root, and they
|
|||
|
can damage or destroy a filesystem if misused.</para></caution>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>lsmod</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>lsmod</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>lsmod</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>List installed kernel modules.</para>
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>lsmod</userinput>
|
|||
|
<computeroutput>Module Size Used by
|
|||
|
autofs 9456 2 (autoclean)
|
|||
|
opl3 11376 0
|
|||
|
serial_cs 5456 0 (unused)
|
|||
|
sb 34752 0
|
|||
|
uart401 6384 0 [sb]
|
|||
|
sound 58368 0 [opl3 sb uart401]
|
|||
|
soundlow 464 0 [sound]
|
|||
|
soundcore 2800 6 [sb sound]
|
|||
|
ds 6448 2 [serial_cs]
|
|||
|
i82365 22928 2
|
|||
|
pcmcia_core 45984 0 [serial_cs ds i82365]</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>insmod</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>insmod</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>insmod</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Force insertion of a kernel module. Must be invoked as root.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>modprobe</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>modprobe</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>modprobe</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Module loader that is normally invoked automatically in a startup script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>depmod</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>depmod</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>depmod</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Creates module dependency file, usually invoked from startup script.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="losetupref"><command>losetup</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>losetup</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>losetup</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Sets up and configures <link linkend="loopbackref">
|
|||
|
loopback devices</link>.</para>
|
|||
|
|
|||
|
<example id="createfs">
|
|||
|
<title>Creating a filesystem in a file</title>
|
|||
|
<programlisting>SIZE=1000000 # 1 meg
|
|||
|
|
|||
|
head -c $SIZE < /dev/zero > file # Set up file of designated size.
|
|||
|
losetup /dev/loop0 file # Set it up as loopback device.
|
|||
|
mke2fs /dev/loop0 # Create filesystem.
|
|||
|
mount -o loop /dev/loop0 /mnt # Mount it.
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>rdev</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>rdev</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>rdev</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>Get info about or make changes to root device, swap space, or video
|
|||
|
mode. The functionality of <command>rdev</command> has generally been taken over by
|
|||
|
<command>lilo</command>, but <command>rdev</command> remains
|
|||
|
useful for setting up a ram disk. This is another dangerous command, if misused.
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
<para>Using our knowledge of administrative commands, let us examine a system
|
|||
|
script. One of the shortest and simplest to understand scripts is
|
|||
|
<command>killall</command>, used to suspend running processes at system shutdown.</para>
|
|||
|
|
|||
|
<example id="ex55">
|
|||
|
<title><command>killall</command>, from <filename class="directory">/etc/rc.d/init.d</filename></title>
|
|||
|
<programlisting>&ex55;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>That wasn't so bad. Aside from a little fancy footwork with variable
|
|||
|
matching, there is no new material there.</para>
|
|||
|
|
|||
|
<formalpara><title>Exercise</title>
|
|||
|
<para>In <filename class="directory">/etc/rc.d/init.d</filename>,
|
|||
|
analyze the <command>halt</command> script. It is a bit longer than
|
|||
|
<command>killall</command>, but similar in concept. Make a copy of this script somewhere in
|
|||
|
your home directory and experiment with it (do <emphasis>not</emphasis> run it as root). Do
|
|||
|
a simulated run with the <option>-vn</option> flags
|
|||
|
(<userinput>sh -vn scriptname</userinput>). Add extensive comments. Change
|
|||
|
the <quote>action</quote> commands to <quote>echos</quote>.</para></formalpara>
|
|||
|
|
|||
|
<para>Now, look at some of the more complex scripts in
|
|||
|
<filename class="directory">/etc/rc.d/init.d</filename>. See if
|
|||
|
you can understand parts of them. Follow the above procedure
|
|||
|
to analyze them. For some additional insight, you might also
|
|||
|
examine the file <filename>sysvinitfiles</filename> in <filename
|
|||
|
class="directory">/usr/doc/initscripts-X.XX</filename>, which
|
|||
|
is part of the <quote>initscripts</quote> documentation.</para>
|
|||
|
|
|||
|
</sect1> <!-- System and Administrative Commands -->
|
|||
|
|
|||
|
<sect1 id="commandsub">
|
|||
|
<title>Command Substitution</title>
|
|||
|
<indexterm>
|
|||
|
<primary>$</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>`</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term>Command substitution</term>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>substitution</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para><emphasis><anchor id="commandsubref">Command
|
|||
|
substitution</emphasis> reassigns the output of a command
|
|||
|
or even multiple commands; it literally plugs the command
|
|||
|
output into another context.</para>
|
|||
|
|
|||
|
|
|||
|
<para><anchor id="backquotesref">The classic form of <emphasis>command
|
|||
|
substitution</emphasis> uses backquotes ('...'). Commands
|
|||
|
within backquotes (backticks) generate command line text.
|
|||
|
|
|||
|
<programlisting>script_name=`basename $0`
|
|||
|
echo "The name of this script is $script_name."</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>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 <quote>for</quote> loop.
|
|||
|
|
|||
|
<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_listing
|
|||
|
# Same result.
|
|||
|
|
|||
|
# A possible problem with putting a list of files into a single string
|
|||
|
# is that a newline may creep in.
|
|||
|
#
|
|||
|
# A safer way to assign a list of files to a parameter is with an array.
|
|||
|
# shopt -s nullglob # If no match, filename expands to nothing.
|
|||
|
# textfile_listing=( *.txt )
|
|||
|
#
|
|||
|
# Thanks, S.C.</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<caution><para>Command substitution may result in word splitting.
|
|||
|
<programlisting>COMMAND `echo a b` # 2 args: a and b
|
|||
|
|
|||
|
COMMAND "`echo a b`" # 1 arg: "a b"
|
|||
|
|
|||
|
COMMAND `echo` # no arg
|
|||
|
|
|||
|
COMMAND "`echo`" # one empty arg
|
|||
|
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting></para></caution>
|
|||
|
|
|||
|
<caution>
|
|||
|
<para>Word splitting resulting from command
|
|||
|
substitution may remove trailing newlines characters
|
|||
|
from the output of the reassigned command(s). This can
|
|||
|
cause unpleasant surprises.
|
|||
|
|
|||
|
<programlisting>dir_listing=`ls -l`
|
|||
|
echo $dirlisting
|
|||
|
|
|||
|
# Expecting a nicely ordered directory listing, such as:
|
|||
|
# -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
|
|||
|
|
|||
|
# 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.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Even when there is no word splitting, command
|
|||
|
substitution can remove trailing newlines.
|
|||
|
|
|||
|
<programlisting># cd "`pwd`" # This should always work.
|
|||
|
# However...
|
|||
|
|
|||
|
mkdir 'dir with trailing newline
|
|||
|
'
|
|||
|
|
|||
|
cd 'dir with trailing newline
|
|||
|
'
|
|||
|
|
|||
|
cd "`pwd`" # Error message:
|
|||
|
# bash: cd: /tmp/file with trailing newline: No such file or directory
|
|||
|
|
|||
|
cd "$PWD" # Works fine.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
old_tty_setting=$(stty -g) # Save old terminal setting.
|
|||
|
echo "Hit a key "
|
|||
|
stty -icanon -echo # Disable "canonical" mode for terminal.
|
|||
|
# Also, disable *local* echo.
|
|||
|
key=$(dd bs=1 count=1 2> /dev/null) # Using 'dd' to get a keypress.
|
|||
|
stty "$old_tty_setting" # Restore old setting.
|
|||
|
echo "You hit ${#key} key." # ${#variable} = number of characters in $variable
|
|||
|
#
|
|||
|
# Hit any key except RETURN, and the output is "You hit 1 key."
|
|||
|
# Hit RETURN, and it's "You hit 0 key."
|
|||
|
# The newline gets eaten in the command substitution.
|
|||
|
|
|||
|
Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
</caution>
|
|||
|
|
|||
|
|
|||
|
<note><para>The <command>$(COMMAND)</command> form has
|
|||
|
superseded backticks for command substitution.
|
|||
|
<programlisting>output=$(sed -n /"$1"/p $file)
|
|||
|
# From "grp.sh" example.</programlisting></para></note>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<para>Examples of command substitution in shell scripts:
|
|||
|
<orderedlist>
|
|||
|
<listitem><para><xref linkend="bingrep"></para></listitem>
|
|||
|
<listitem><para><xref linkend="casecmd"></para></listitem>
|
|||
|
<listitem><para><xref linkend="seedingrandom"></para></listitem>
|
|||
|
<listitem><para><xref linkend="ex57"></para></listitem>
|
|||
|
<listitem><para><xref linkend="lowercase"></para></listitem>
|
|||
|
<listitem><para><xref linkend="grp"></para></listitem>
|
|||
|
<listitem><para><xref linkend="ex53"></para></listitem>
|
|||
|
<listitem><para><xref linkend="ex24"></para></listitem>
|
|||
|
<listitem><para><xref linkend="symlinks"></para></listitem>
|
|||
|
<listitem><para><xref linkend="stripc"></para></listitem>
|
|||
|
<listitem><para><xref linkend="redir4"></para></listitem>
|
|||
|
<listitem><para><xref linkend="tree"></para></listitem>
|
|||
|
<listitem><para><xref linkend="pidid"></para></listitem>
|
|||
|
<listitem><para><xref linkend="monthlypmt"></para></listitem>
|
|||
|
<listitem><para><xref linkend="base"></para></listitem>
|
|||
|
</orderedlist>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect1> <!-- Command Substitution -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="arithexp">
|
|||
|
<title>Arithmetic Expansion</title>
|
|||
|
|
|||
|
<para><anchor id="arithexpref">Arithmetic expansion provides a
|
|||
|
powerful tool for performing arithmetic operations in
|
|||
|
scripts. Translating a string into a numerical expression is
|
|||
|
relatively straightforward using backticks, double parentheses,
|
|||
|
or <command>let</command>.</para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term>Arithmetic expansion with backticks (often used in
|
|||
|
conjunction with <link linkend="exprref">expr</link>)</term> <indexterm>
|
|||
|
<primary>arithmetic</primary> <secondary>expansion</secondary>
|
|||
|
</indexterm> <indexterm>
|
|||
|
<primary>arithmetic</primary> <secondary>expansion</secondary>
|
|||
|
</indexterm> <listitem>
|
|||
|
<para><programlisting>z=`expr $z + 3` # 'expr' does the expansion.</programlisting></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term>Arithmetic expansion with double parentheses</term>
|
|||
|
<indexterm><primary>double</primary>
|
|||
|
<secondary>parentheses</secondary></indexterm>
|
|||
|
<term>and using <link linkend="letref">let</link></term>
|
|||
|
<indexterm><primary>let</primary>
|
|||
|
<secondary>let</secondary></indexterm>
|
|||
|
|
|||
|
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>The use of backticks in arithmetic
|
|||
|
expansion has been superseded by double parentheses
|
|||
|
<userinput>$((...))</userinput> or the very
|
|||
|
convenient <command>let</command> construction.
|
|||
|
|
|||
|
<programlisting>z=$(($z+3))
|
|||
|
# $((EXPRESSION)) is arithmetic expansion. # Not to be confused with
|
|||
|
# command substitution.
|
|||
|
|
|||
|
let z=z+3
|
|||
|
let "z += 3" #If quotes, then spaces and special operators allowed.
|
|||
|
# 'let' is actually arithmetic evaluation, rather than expansion.</programlisting>
|
|||
|
|
|||
|
All the above are equivalent. You may use whichever one
|
|||
|
<quote>rings your chimes</quote>.
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Examples of arithmetic expansion in scripts:
|
|||
|
<orderedlist>
|
|||
|
<listitem><para><xref linkend="ex45"></para></listitem>
|
|||
|
<listitem><para><xref linkend="ex25"></para></listitem>
|
|||
|
<listitem><para><xref linkend="ex66"></para></listitem>
|
|||
|
<listitem><para><xref linkend="bubble"></para></listitem>
|
|||
|
<listitem><para><xref linkend="tree"></para></listitem>
|
|||
|
</orderedlist>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect1> <!-- Arithmetic Expansion -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="io-redirection">
|
|||
|
<title>I/O Redirection</title>
|
|||
|
|
|||
|
<para><anchor id="ioredirref"></para>
|
|||
|
|
|||
|
<para>There are always three default <quote>files</quote>
|
|||
|
open, <filename>stdin</filename> (the keyboard),
|
|||
|
<filename>stdout</filename> (the screen), and
|
|||
|
<filename>stderr</filename> (error messages output to the
|
|||
|
screen). These, and any other open files, can be redirected.
|
|||
|
Redirection simply means capturing output from a file, command,
|
|||
|
program, script, or even code block within a script (see <xref
|
|||
|
linkend="ex8"> and <xref linkend="rpmcheck">) and sending it as
|
|||
|
input to another file, command, program, or script.</para>
|
|||
|
|
|||
|
<para><anchor id="fdref">Each open file gets assigned a file descriptor.
|
|||
|
|
|||
|
<footnote><para>A <emphasis>file descriptor</emphasis>
|
|||
|
is simply a number that the operating system assigns
|
|||
|
to an open file to keep track of it. Consider it
|
|||
|
a simplified version of a file pointer. It is
|
|||
|
analogous to a <emphasis>file handle</emphasis> in
|
|||
|
C.</para></footnote>
|
|||
|
|
|||
|
The file descriptors for <filename>stdin</filename>,
|
|||
|
<filename>stdout</filename>, and <filename>stderr</filename> are
|
|||
|
0, 1, and 2, respectively. For opening additional files, there
|
|||
|
remain descriptors 3 to 9. It is sometimes useful to assign one of
|
|||
|
these additional file descriptors to <filename>stdin</filename>,
|
|||
|
<filename>stdout</filename>, or <filename>stderr</filename>
|
|||
|
as a temporary duplicate link.
|
|||
|
<footnote><para>Using <replaceable>file
|
|||
|
descriptor 5</replaceable> might cause problems.
|
|||
|
When Bash creates a child process, as with <link
|
|||
|
linkend="execref">exec</link>, the child inherits
|
|||
|
fd 5 (see Chet Ramey's archived e-mail, <ulink
|
|||
|
url="http://www.geocrawler.com/archives/3/342/1996/1/0/1939805/">
|
|||
|
SUBJECT: RE: File descriptor 5 is held open</ulink>).
|
|||
|
Best leave this particular fd alone.</para></footnote>
|
|||
|
This simplifies restoration to normal after complex redirection
|
|||
|
and reshuffling (see <xref linkend="redir1">).</para>
|
|||
|
|
|||
|
<para><anchor id="ioredirectionref"></para>
|
|||
|
|
|||
|
<programlisting> >
|
|||
|
# 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.
|
|||
|
# The : serves as a dummy placeholder, producing no output.
|
|||
|
|
|||
|
>>
|
|||
|
# Redirect stdout to a file.
|
|||
|
# Creates the file if not present, otherwise appends to it.
|
|||
|
|
|||
|
2>&1
|
|||
|
# Redirects stderr to stdout.
|
|||
|
# Error messages get sent to same place as standard output.
|
|||
|
|
|||
|
i>&j
|
|||
|
# Redirects file descriptor <emphasis>i</emphasis> to <emphasis>j</emphasis>.
|
|||
|
# All output of file pointed to by <emphasis>i</emphasis> gets sent to file pointed to by <emphasis>j</emphasis>.
|
|||
|
|
|||
|
>&j
|
|||
|
# Redirects, by default, file descriptor <emphasis>1</emphasis> (stdout) to <emphasis>j</emphasis>.
|
|||
|
# All stdout gets sent to file pointed to by <emphasis>j</emphasis>.
|
|||
|
|
|||
|
0<
|
|||
|
<
|
|||
|
# Accept input from a file.
|
|||
|
# Companion command to <quote>></quote>, and often used in combination with it.
|
|||
|
#
|
|||
|
# grep search-word <filename
|
|||
|
|
|||
|
|
|||
|
[j]<>filename
|
|||
|
# Open file "filename" for reading and writing, and assign file descriptor "j" to it.
|
|||
|
# If "filename" does not exist, create it.
|
|||
|
# If file descriptor "j" is not specified, default to fd 0, stdin.
|
|||
|
#
|
|||
|
# An application of this is writing at a specified place in a file.
|
|||
|
echo 1234567890 > File # Write string to "File".
|
|||
|
exec 3<> File # Open "File" and assign fd 3 to it.
|
|||
|
read -n 4 <&3 # Read only 4 characters.
|
|||
|
echo -n . >&3 # Write a decimal point there.
|
|||
|
exec 3>&- # Close fd 3.
|
|||
|
cat File # ==> 1234.67890
|
|||
|
# Random access, by golly.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|
|||
|
# Pipe.
|
|||
|
# General purpose process and command chaining tool.
|
|||
|
# Similar to <quote>></quote>, but more general in effect.
|
|||
|
# Useful for chaining commands, scripts, files, and programs together.
|
|||
|
cat *.txt | sort | uniq > result-file
|
|||
|
# Sorts the output of all the .txt files and deletes duplicate lines,
|
|||
|
# finally saves results to <quote>result-file</quote>.
|
|||
|
</programlisting>
|
|||
|
|
|||
|
<para>Multiple instances of input and output redirection
|
|||
|
and/or pipes can be combined in a single command
|
|||
|
line.
|
|||
|
|
|||
|
<programlisting>command < input-file > output-file
|
|||
|
|
|||
|
command1 | command2 | command3 > output-file</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>Multiple output streams may be redirected to one file.
|
|||
|
|
|||
|
<programlisting>ls -yz >> command.log 2>&1
|
|||
|
# Capture result of illegal options "yz" to "ls" in file "command.log".
|
|||
|
# Because stderr redirected to the file, any error messages will also be there.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<title>Closing File Descriptors</title>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>n<&-</token></term>
|
|||
|
<listitem>
|
|||
|
<para>Close input file descriptor
|
|||
|
<replaceable>n</replaceable>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>0<&-</token></term>
|
|||
|
<term><token><&-</token></term>
|
|||
|
<listitem>
|
|||
|
<para>Close <filename>stdin</filename>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>n>&-</token></term>
|
|||
|
<listitem>
|
|||
|
<para>Close output file descriptor <replaceable>n</replaceable>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><token>1>&-</token></term>
|
|||
|
<term><token>>&-</token></term>
|
|||
|
<listitem>
|
|||
|
<para>Close <filename>stdout</filename>.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
|
|||
|
<para>Child processes inherit open file descriptors. This is why pipes
|
|||
|
work. To prevent an fd from being inherited, close it.
|
|||
|
<programlisting># Redirecting only stderr to a pipe.
|
|||
|
|
|||
|
exec 3>&1 # Save current "value" of stdout.
|
|||
|
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'ls' and 'grep'.
|
|||
|
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>
|
|||
|
|
|||
|
|
|||
|
<sect2><title>Using <command>exec</command></title>
|
|||
|
|
|||
|
|
|||
|
<para>The <command>exec <filename</command> command redirects
|
|||
|
<filename>stdin</filename> to a file. From that point on, all
|
|||
|
<filename>stdin</filename> comes from that file, rather than
|
|||
|
its normal source (usually keyboard input). This provides a
|
|||
|
method of reading a file line by line and possibly parsing
|
|||
|
each line of input using <link linkend="sedref">sed</link>
|
|||
|
and/or <link linkend="awkref">awk</link>.</para>
|
|||
|
|
|||
|
<example id="redir1">
|
|||
|
<title>Redirecting <filename>stdin</filename> using
|
|||
|
<command>exec</command></title>
|
|||
|
<programlisting>&redir1;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</sect2><!-- Using exec For Redirection -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect2><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="forloopref">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 the end of the code
|
|||
|
block accomplishes this.</para>
|
|||
|
|
|||
|
<example id="redir2">
|
|||
|
<title>Redirected <emphasis>while</emphasis> loop</title>
|
|||
|
<programlisting>&redir2;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="redir2a">
|
|||
|
<title>Alternate form of redirected <emphasis>while</emphasis> loop</title>
|
|||
|
<programlisting>&redir2a;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="redir3">
|
|||
|
<title>Redirected <emphasis>until</emphasis> loop</title>
|
|||
|
<programlisting>&redir3;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="redir4">
|
|||
|
<title>Redirected <emphasis>for</emphasis> loop</title>
|
|||
|
<programlisting>&redir4;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="redir5">
|
|||
|
<title>Redirected <emphasis>if/then</emphasis> test</title>
|
|||
|
<programlisting>&redir5;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<note><para><link linkend="heredocref">Here documents</link>
|
|||
|
are a special case of redirected code blocks.</para></note>
|
|||
|
|
|||
|
</sect2><!-- Redirecting Code Blocks -->
|
|||
|
|
|||
|
|
|||
|
<sect2><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>
|
|||
|
|
|||
|
|
|||
|
</sect2><!-- Log Files -->
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- I/O Redirection -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="here-docs">
|
|||
|
<title>Here Documents</title>
|
|||
|
|
|||
|
<para><anchor id="heredocref"></para>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary><<</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary><<</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para>A <firstterm>here document</firstterm> uses a special form
|
|||
|
of <link linkend="ioredirref">I/O redirection</link>
|
|||
|
to feed a command script to an interactive program, such
|
|||
|
as <command>ftp</command>, <command>telnet</command>, or
|
|||
|
<command>ex</command>. Typically, the script consists of
|
|||
|
a command list to the program, delineated by a limit string.
|
|||
|
The special symbol <token><<</token> precedes the limit string.
|
|||
|
This has the effect of redirecting the output of a file into
|
|||
|
the program, similar to
|
|||
|
<userinput>interactive-program < command-file</userinput>,
|
|||
|
where <filename>command-file</filename> contains
|
|||
|
<programlisting>command #1
|
|||
|
command #2
|
|||
|
...</programlisting></para>
|
|||
|
|
|||
|
<para>The <quote>here document</quote> alternative looks like this:
|
|||
|
<programlisting>#!/bin/bash
|
|||
|
interactive-program <<LimitString
|
|||
|
command #1
|
|||
|
command #2
|
|||
|
...
|
|||
|
LimitString</programlisting></para>
|
|||
|
|
|||
|
<para>Choose a limit string sufficiently unusual that it will not occur anywhere
|
|||
|
in the command list and confuse matters.</para>
|
|||
|
|
|||
|
<para>Note that <emphasis>here documents</emphasis> may sometimes
|
|||
|
be used to good effect with non-interactive utilities and
|
|||
|
commands.</para>
|
|||
|
|
|||
|
<example id="ex69">
|
|||
|
<title><command>dummyfile</command>: Creates a 2-line dummy file</title>
|
|||
|
<programlisting>&ex69;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>The above script could just as effectively have been implemented with
|
|||
|
<command>ex</command>, rather than <command>vi</command>. Here documents
|
|||
|
containing a list of <command>ex</command> commands are common enough to
|
|||
|
form their own category, known as <firstterm>ex scripts</firstterm>.</para>
|
|||
|
|
|||
|
<example id="ex70">
|
|||
|
<title><command>broadcast</command>: Sends message to everyone logged in</title>
|
|||
|
<programlisting>&ex70;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ex71">
|
|||
|
<title>Multi-line message using <command>cat</command></title>
|
|||
|
<programlisting>&ex71;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>The <option>-</option> option to mark a here document limit string
|
|||
|
(<userinput><<-LimitString</userinput>) suppresses tabs (but
|
|||
|
not spaces) in the output. This may be useful in making a script
|
|||
|
more readable.</para>
|
|||
|
|
|||
|
<example id="ex71a">
|
|||
|
<title>Multi-line message, with tabs suppressed</title>
|
|||
|
<programlisting>&ex71a;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>A here document supports parameter and command substitution.
|
|||
|
It is therefore possible to pass different parameters to the
|
|||
|
body of the here document, changing its output accordingly.</para>
|
|||
|
|
|||
|
<example id="ex71b">
|
|||
|
<title>Here document with parameter substitution</title>
|
|||
|
<programlisting>&ex71b;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>Quoting or escaping the <quote>limit string</quote> at the
|
|||
|
head of a here document disables parameter substitution within its
|
|||
|
body. This has very limited usefulness.</para>
|
|||
|
|
|||
|
<example id="ex71c">
|
|||
|
<title>Parameter substitution turned off</title>
|
|||
|
<programlisting>&ex71c;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>This is a useful script containing a here document with
|
|||
|
parameter substitution.</para>
|
|||
|
|
|||
|
<example id="ex72">
|
|||
|
<title><command>upload</command>: Uploads a file pair to <quote>Sunsite</quote>
|
|||
|
incoming directory</title>
|
|||
|
<programlisting>&ex72;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>It is possible to use <token>:</token> as a dummy command
|
|||
|
accepting output from a here document. This, in effect, creates an
|
|||
|
<quote>anonymous</quote> here document.</para>
|
|||
|
|
|||
|
<example id="anonheredoc">
|
|||
|
<title><quote>Anonymous</quote> Here Document</title>
|
|||
|
<programlisting>#!/bin/bash
|
|||
|
|
|||
|
: <<TESTVARIABLES
|
|||
|
${HOSTNAME?}${USER?}${MAIL?} # Print error message if one of the variables not set.
|
|||
|
TESTVARIABLES
|
|||
|
|
|||
|
exit 0</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<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 in a here
|
|||
|
document.</para></caution>
|
|||
|
|
|||
|
<para>For those tasks too complex for a <quote>here
|
|||
|
document</quote>, consider using the <command>expect</command>
|
|||
|
scripting language, which is specifically tailored for feeding
|
|||
|
input into interactive programs.</para>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- Here Documents -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="Recess-Time">
|
|||
|
<title>Recess Time</title>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<literallayout>
|
|||
|
This bizarre little intermission gives the reader a chance to
|
|||
|
relax and maybe laugh a bit.
|
|||
|
|
|||
|
Fellow Linux user, greetings! You are reading something
|
|||
|
which will bring you luck and good fortune. Just e-mail a
|
|||
|
copy of this document to 10 of your friends. Before you make
|
|||
|
the copies, send a 100-line Bash script to the first person
|
|||
|
on the list given at the bottom of this letter. Then delete
|
|||
|
their name and add yours to the bottom of the list.
|
|||
|
|
|||
|
Don't break the chain! Make the copies within 48 hours.
|
|||
|
Wilfred P. of Brooklyn failed to send out his ten copies and
|
|||
|
woke the next morning to find his job description changed
|
|||
|
to "COBOL programmer." Howard L. of Newport News sent
|
|||
|
out his ten copies and within a month had enough hardware
|
|||
|
to build a 100-node Beowulf cluster dedicated to playing
|
|||
|
<emphasis>xbill</emphasis>. Amelia V. of Chicago laughed at this letter and
|
|||
|
broke the chain. Shortly thereafter, a fire broke out in her
|
|||
|
terminal and she now spends her days writing documentation
|
|||
|
for MS Windows.
|
|||
|
|
|||
|
Don't break the chain! Send out your ten copies today!
|
|||
|
|
|||
|
|
|||
|
<emphasis>Courtesy 'NIX "fortune cookies", with some
|
|||
|
alterations and many apologies</emphasis>
|
|||
|
</literallayout>
|
|||
|
|
|||
|
</blockquote>
|
|||
|
|
|||
|
</sect1> <!-- Recess Time -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="regexp">
|
|||
|
<title>Regular Expressions</title>
|
|||
|
|
|||
|
<para><anchor id="regexref"></para>
|
|||
|
|
|||
|
<para>In order 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="sedref">sed</link> and <link
|
|||
|
linkend="awkref">awk</link> interpret and use REs.</para>
|
|||
|
|
|||
|
<sect2><title>A Brief Introduction to Regular Expressions</title>
|
|||
|
|
|||
|
<para>An expression is a string of characters. Those characters
|
|||
|
that have an interpretation above and beyond their literal
|
|||
|
meaning are called <emphasis>metacharacters</emphasis>. A
|
|||
|
quote symbol (<token>"</token>), for example, may denote
|
|||
|
speech by a person, ditto, or a meta-meaning for the symbols
|
|||
|
that follow. Regular expressions are sets of characters and/or
|
|||
|
metacharacters that UNIX endows with special features.
|
|||
|
<footnote><para>The simplest type or regular expression is a
|
|||
|
character string that retains its literal meaning, not
|
|||
|
containing any metacharacters.</para></footnote>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>The main uses for Regular Expressions (REs) are text
|
|||
|
searches and string manipulation. An RE
|
|||
|
<firstterm>matches</firstterm> a single character or a set of
|
|||
|
characters (a substring or an entire string).</para>
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
<listitem>
|
|||
|
<indexterm>
|
|||
|
<primary>*</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>*</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para>The asterisk <token>*</token> matches any number of
|
|||
|
repeats of the character string or RE preceding it,
|
|||
|
<emphasis>including zero</emphasis>.</para>
|
|||
|
|
|||
|
<para><quote>1133*</quote> matches <replaceable>11 +
|
|||
|
one or more 3's + possibly other characters</replaceable>:
|
|||
|
<replaceable>113</replaceable>, <replaceable>1133</replaceable>,
|
|||
|
<replaceable>111312</replaceable>, and so forth.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<indexterm>
|
|||
|
<primary>.</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>.</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para>The dot <token>.</token> matches any one character,
|
|||
|
except a newline.
|
|||
|
<footnote><para>Since <link linkend="sedref">sed</link>, <link
|
|||
|
linkend="awkref">awk</link>, and <link
|
|||
|
linkend="grepref">grep</link> process single lines, there
|
|||
|
will usually not be a newline to match. In those cases where
|
|||
|
there is a newline in a multiple line expression, the dot
|
|||
|
will match the newline.
|
|||
|
<programlisting>#!/bin/bash
|
|||
|
|
|||
|
sed -e 'N;s/.*/[&]/' << EOF # Here Document
|
|||
|
line1
|
|||
|
line2
|
|||
|
EOF
|
|||
|
# OUTPUT:
|
|||
|
# [line1
|
|||
|
# line2]
|
|||
|
|
|||
|
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
awk '{ $0=$1 "\n" $2; if (/line.1/) {print}}' << EOF
|
|||
|
line 1
|
|||
|
line 2
|
|||
|
EOF
|
|||
|
# OUTPUT:
|
|||
|
# line
|
|||
|
# 1
|
|||
|
|
|||
|
|
|||
|
# Thanks, S.C.
|
|||
|
|
|||
|
exit 0</programlisting></para></footnote>
|
|||
|
</para>
|
|||
|
|
|||
|
<para><quote>13.</quote> matches <replaceable>13 + at
|
|||
|
least one of any character (including a
|
|||
|
space)</replaceable>: <replaceable>1133</replaceable>,
|
|||
|
<replaceable>11333</replaceable>, but not
|
|||
|
<replaceable>13</replaceable> (additional character
|
|||
|
missing).</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
<listitem>
|
|||
|
<indexterm>
|
|||
|
<primary>^</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>^</secondary>
|
|||
|
</indexterm>
|
|||
|
<para>The caret <token>^</token> matches the beginning of
|
|||
|
a line, but sometimes, depending on context, negates the
|
|||
|
meaning of a set of characters in an RE.
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<indexterm>
|
|||
|
<primary>$</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>$</secondary>
|
|||
|
</indexterm>
|
|||
|
<para>The dollar sign <token>$</token> at the end of an
|
|||
|
RE matches the end of a line.</para>
|
|||
|
<para><quote>^$</quote> matches blank lines.</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<indexterm>
|
|||
|
<primary>[...]</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>[...]</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para>Brackets <token>[...]</token> enclose a set of characters
|
|||
|
to match in a single RE.</para>
|
|||
|
|
|||
|
<para><quote>[xyz]</quote> matches the characters
|
|||
|
<replaceable>x</replaceable>, <replaceable>y</replaceable>,
|
|||
|
or <replaceable>z</replaceable>.</para>
|
|||
|
|
|||
|
<para><quote>[c-n]</quote> matches any of the
|
|||
|
characters in the range <replaceable>c</replaceable>
|
|||
|
to <replaceable>n</replaceable>.</para>
|
|||
|
|
|||
|
<para><quote>[B-Pk-y]</quote> matches any of the
|
|||
|
characters in the ranges <replaceable>B</replaceable>
|
|||
|
to <replaceable>P</replaceable>
|
|||
|
and <replaceable>k</replaceable> to
|
|||
|
<replaceable>y</replaceable>.</para>
|
|||
|
|
|||
|
<para><quote>[a-z0-9]</quote> matches any lowercase letter or any
|
|||
|
digit.</para>
|
|||
|
|
|||
|
<para><quote>[^b-d]</quote> matches all characters
|
|||
|
<emphasis>except</emphasis> those in
|
|||
|
the range <replaceable>b</replaceable> to
|
|||
|
<replaceable>d</replaceable>. This is an instance of
|
|||
|
<token>^</token> negating or inverting the meaning
|
|||
|
of the following RE (taking on a role similar to
|
|||
|
<token>!</token> in a different context).</para>
|
|||
|
|
|||
|
<para>Combined sequences of bracketed characters match
|
|||
|
common word patterns. <quote>[Yy][Ee][Ss]</quote> matches
|
|||
|
<replaceable>yes</replaceable>, <replaceable>Yes</replaceable>,
|
|||
|
<replaceable>YES</replaceable>, <replaceable>yEs</replaceable>,
|
|||
|
and so forth.
|
|||
|
<quote>[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]</quote>
|
|||
|
matches any Social Security number.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
<listitem>
|
|||
|
<indexterm>
|
|||
|
<primary>\</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>\</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para>The backslash <token>\</token> <link
|
|||
|
linkend="escp">escapes</link> a special character, which
|
|||
|
means that character gets interpreted literally.</para>
|
|||
|
|
|||
|
<para>A <quote>\$</quote> reverts back to its
|
|||
|
literal meaning of <quote>$</quote>, rather than its
|
|||
|
RE meaning of end-of-line. Likewise a <quote>\\</quote>
|
|||
|
has the literal meaning of <quote>\</quote>.</para>
|
|||
|
</listitem>
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
|
|||
|
<listitem>
|
|||
|
|
|||
|
<formalpara><title>Extended REs</title>
|
|||
|
<para>Used in <command>egrep</command>, <link linkend="awkref">awk</link>,
|
|||
|
and <link linkend="perlref">Perl</link></para></formalpara>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>?</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>?</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<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>The plus <token>+</token> matches one or more of the
|
|||
|
previous RE. It serves a role similar to the <token>*</token>, but
|
|||
|
does <emphasis>not</emphasis> match zero occurrences.</para>
|
|||
|
|
|||
|
<para><programlisting># GNU versions of sed and awk can use "+",
|
|||
|
# but it needs to be escaped.
|
|||
|
|
|||
|
echo a111b | sed -ne '/a1\+b/p'
|
|||
|
echo a111b | grep 'a1\+b'
|
|||
|
echo a111b | gawk '/a1+b/'
|
|||
|
# All of above are equivalent.
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting></para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<indexterm>
|
|||
|
<primary>\{ \}</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>\{ \}</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para><link linkend="escp">Escaped</link> <quote>curly
|
|||
|
brackets</quote> <token>\{ \}</token> indicate the number
|
|||
|
of occurrences of a preceding RE to match.</para>
|
|||
|
|
|||
|
<para>It is necessary to escape the curly brackets since
|
|||
|
they have only their literal character meaning
|
|||
|
otherwise. This usage is technically not part of the basic
|
|||
|
RE set.</para>
|
|||
|
|
|||
|
<para><quote>[0-9]\{5\}</quote> matches exactly five digits
|
|||
|
(characters in the range of 0 to 9).</para>
|
|||
|
|
|||
|
<caution>
|
|||
|
<para>Curly brackets are not available as an RE in the
|
|||
|
<quote>classic</quote> version of <link
|
|||
|
linkend="awkref">awk</link>. However,
|
|||
|
<command>gawk</command> has the
|
|||
|
<option>--re-interval</option> option that permits them
|
|||
|
(without being escaped).</para>
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>echo 2222 | gawk --re-interval '/2{3}/'</userinput>
|
|||
|
<computeroutput>2222</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
</caution>
|
|||
|
|
|||
|
</listitem>
|
|||
|
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
<para>"Sed & Awk", by Dougherty and Robbins gives a very complete
|
|||
|
and lucid treatment of REs (see the <xref
|
|||
|
linkend="biblio">).</para>
|
|||
|
|
|||
|
</sect2> <!-- A Brief Introduction to Regular Expressions -->
|
|||
|
|
|||
|
<sect2>
|
|||
|
<title>Using REs in Scripts</title>
|
|||
|
|
|||
|
<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>
|
|||
|
|
|||
|
<caution>
|
|||
|
<para>Bash itself does not recognize Regular Expressions. In
|
|||
|
scripts, commands and utilities, such as <command>sed</command>
|
|||
|
and <command>awk</command>, interpret RE's.</para>
|
|||
|
|
|||
|
|
|||
|
<para><anchor id="globbingref">Bash does carry out filename
|
|||
|
expansion, but does <emphasis>not</emphasis> use the
|
|||
|
standard RE set. Instead, it recognizes and expands
|
|||
|
wildcards, a process known as <quote>globbing</quote>.
|
|||
|
Globbing interprets the standard wildcard characters,
|
|||
|
<token>*</token> and <token>?</token>, in addition to certain
|
|||
|
other special characters. There are some important limitations
|
|||
|
on wildcard characters in globbing, however. Strings containing
|
|||
|
<replaceable>*</replaceable> will not match filenames that start
|
|||
|
with a dot (such as <filename>.bashrc</filename>).
|
|||
|
|
|||
|
<footnote>
|
|||
|
<para>
|
|||
|
Filename expansion <emphasis>can</emphasis>
|
|||
|
match dotfiles, but only if the pattern explicitly includes the dot.
|
|||
|
<programlisting>~/[.]bashrc # Will not expand to ~/.bashrc
|
|||
|
~/?bashrc # Neither will this.
|
|||
|
# Wild cards and metacharacters will not expand to a dot in globbing.
|
|||
|
|
|||
|
~/.[b]ashrc # Will expand to ~./bashrc
|
|||
|
~/.ba?hrc # Likewise.
|
|||
|
~/.bashr* # Likewise.
|
|||
|
|
|||
|
# Setting the "dotglob" option turns this off.
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
</footnote>
|
|||
|
|
|||
|
Likewise, the <replaceable>?</replaceable> has a different
|
|||
|
meaning in globbing than as part of an RE.</para>
|
|||
|
|
|||
|
|
|||
|
<para>See <xref linkend="listglob">.</para>
|
|||
|
</caution>
|
|||
|
|
|||
|
</sect2> <!-- Using REs in Scripts -->
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- Regular Expressions -->
|
|||
|
|
|||
|
<!-- *************************** -->
|
|||
|
|
|||
|
<sect1 id="subshells">
|
|||
|
<title>Subshells</title>
|
|||
|
|
|||
|
<para><anchor id="subshellsref"></para>
|
|||
|
|
|||
|
<para>Running a shell script launches another instance of the
|
|||
|
command processor. Just as your commands are interpreted at the
|
|||
|
command line prompt, similarly does a script batch process a list
|
|||
|
of commands in a file. Each shell script running is, in effect,
|
|||
|
a subprocess of the <link linkend="forkref">parent</link> shell,
|
|||
|
the one that gives you the prompt at the console or in an xterm
|
|||
|
window.</para>
|
|||
|
|
|||
|
<para>A shell script can also launch subprocesses. These
|
|||
|
<emphasis>subshells</emphasis> let the script do
|
|||
|
parallel processing, in effect executing multiple subtasks
|
|||
|
simultaneously.</para>
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
<listitem>
|
|||
|
<para>( command1; command2; command3; ... )</para>
|
|||
|
<para>A command list embedded between
|
|||
|
<replaceable>parentheses</replaceable> runs as a
|
|||
|
subshell.</para>
|
|||
|
</listitem>
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
<note><para><anchor id="parvis">Variables in a subshell are
|
|||
|
<emphasis>not</emphasis> visible outside the block of code
|
|||
|
in the subshell. They are not accessible to the <link
|
|||
|
linkend="forkref">parent process</link>, to the shell
|
|||
|
that launched the subshell. These are, in effect, <link
|
|||
|
linkend="localref">local variables</link>.</para></note>
|
|||
|
|
|||
|
<example id="subshell">
|
|||
|
<title>Variable scope in a subshell</title>
|
|||
|
<programlisting>&subshell;</programlisting>
|
|||
|
</example>
|
|||
|
<para>See also <xref linkend="subpit">.</para>
|
|||
|
|
|||
|
<para>+</para>
|
|||
|
|
|||
|
<para>Directory changes made in a subshell do not carry over to the
|
|||
|
parent shell.</para>
|
|||
|
|
|||
|
<example id="allprofs">
|
|||
|
<title>List User Profiles</title>
|
|||
|
<programlisting>&allprofs;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>A subshell may be used to set up a <quote>dedicated
|
|||
|
environment</quote> for a command group.
|
|||
|
<programlisting>COMMAND1
|
|||
|
COMMAND2
|
|||
|
COMMAND3
|
|||
|
(
|
|||
|
IFS=:
|
|||
|
PATH=/bin
|
|||
|
unset TERMINFO
|
|||
|
set -C
|
|||
|
shift 5
|
|||
|
COMMAND4
|
|||
|
COMMAND5
|
|||
|
exit 3 # Only exits the subshell.
|
|||
|
)
|
|||
|
# The parent shell has not been affected, and the environment is preserved.
|
|||
|
COMMAND6
|
|||
|
COMMAND7</programlisting>
|
|||
|
|
|||
|
One application of this is testing whether a variable is defined.
|
|||
|
<programlisting>if (set -u; : $variable) 2> /dev/null
|
|||
|
then
|
|||
|
echo "Variable is set."
|
|||
|
fi
|
|||
|
|
|||
|
# Could also be written [[ ${variable-x} != x || ${variable-y} != y ]]
|
|||
|
# or [[ ${variable-x} != x$variable ]]
|
|||
|
# or [[ ${variable+x} = x ]])</programlisting>
|
|||
|
|
|||
|
Another application is checking for a lock file:
|
|||
|
<programlisting>if (set -C; : > lock_file) 2> /dev/null
|
|||
|
then
|
|||
|
echo "Another user is already running that script."
|
|||
|
exit 65
|
|||
|
fi
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para>Processes may execute in parallel within different
|
|||
|
subshells. This permits breaking a complex task into subcomponents
|
|||
|
processed concurrently.</para>
|
|||
|
|
|||
|
<example id="parallel-processes">
|
|||
|
<title>Running parallel processes in subshells</title>
|
|||
|
<programlisting>
|
|||
|
(cat list1 list2 list3 | sort | uniq > list123) &
|
|||
|
(cat list4 list5 list6 | sort | uniq > list456) &
|
|||
|
# Merges and sorts both sets of lists simultaneously.
|
|||
|
# Running in background ensures parallel execution.
|
|||
|
#
|
|||
|
# Same effect as
|
|||
|
# cat list1 list2 list3 | sort | uniq > list123 &
|
|||
|
# cat list4 list5 list6 | sort | uniq > list456 &
|
|||
|
|
|||
|
wait # Don't execute the next command until subshells finish.
|
|||
|
|
|||
|
diff list123 list456</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Redirecting I/O to a subshell uses the <quote>|</quote> pipe
|
|||
|
operator, as in <userinput>ls -al | (command)</userinput>.</para>
|
|||
|
|
|||
|
|
|||
|
<note><para>A command block between <replaceable>curly
|
|||
|
braces</replaceable> does <emphasis>not</emphasis> launch
|
|||
|
a subshell.</para>
|
|||
|
<para>{ command1; command2; command3; ... }</para></note>
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- Subshells -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="restricted-sh">
|
|||
|
<title>Restricted Shells</title>
|
|||
|
|
|||
|
<para>Running a script or portion of a script in
|
|||
|
<emphasis>restricted</emphasis> mode disables certain commands that
|
|||
|
would otherwise be available. This is a security measure intended
|
|||
|
to limit the privileges of the script user and to minimize possible
|
|||
|
damage from running the script.</para>
|
|||
|
|
|||
|
<para>Disabled commands in restricted shells
|
|||
|
|
|||
|
<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> environmental variables.</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>/'s</token>.</para>
|
|||
|
</listitem><listitem>
|
|||
|
<para>Invoking <emphasis>exec</emphasis> 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></para>
|
|||
|
|
|||
|
<example id="restricted">
|
|||
|
<title>Running a script in restricted mode</title>
|
|||
|
<programlisting>&restricted;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</sect1> <!-- Restricted Shells -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="process-sub">
|
|||
|
<title>Process Substitution</title>
|
|||
|
|
|||
|
<para><anchor id="processsubref"><replaceable>Process
|
|||
|
substitution</replaceable> is the counterpart to <link
|
|||
|
linkend="commandsubref">command substitution</link>. Command
|
|||
|
substitution sets a variable to the result of a command, as in
|
|||
|
<command>dir_contents=`ls -al`</command> or <command>xref=$(
|
|||
|
grep word datafile)</command>. Process substitution feeds the
|
|||
|
output of a process to another process (in other words, it sends
|
|||
|
the results of a command to another command).</para>
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
<listitem>
|
|||
|
<para><command>>(command)</command></para>
|
|||
|
<para><command><(command)</command></para>
|
|||
|
<para>These initiate process substitution. This uses
|
|||
|
<filename>/dev/fd/<n></filename> files to send the
|
|||
|
results of the process within parentheses to another process.
|
|||
|
<footnote><para>This has the same effect as a
|
|||
|
<link linkend="namedpiperef">named pipe</link> (temp
|
|||
|
file), and, in fact, named pipes were at one time used
|
|||
|
in process substitution.</para></footnote>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
</listitem>
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
<note><para>There are <emphasis>no</emphasis> spaces between the
|
|||
|
parentheses and the <quote><</quote> or <quote>></quote>.
|
|||
|
Space there would give an error message.</para></note>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>echo >(true)</userinput>
|
|||
|
<computeroutput>/dev/fd/63</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo <(true)</userinput>
|
|||
|
<computeroutput>/dev/fd/63</computeroutput>
|
|||
|
</screen>
|
|||
|
|
|||
|
Bash creates a pipe with two <link linkend="fdref">file
|
|||
|
descriptors</link>, <filename>--fIn</filename> and
|
|||
|
<filename>fOut--</filename>. The <filename>stdin</filename>
|
|||
|
of <link linkend="trueref">true</link> connects
|
|||
|
to <filename>fOut</filename> (dup2(fOut, 0)),
|
|||
|
then Bash passes a <filename>/dev/fd/fIn</filename>
|
|||
|
argument to <command>echo</command>. On systems lacking
|
|||
|
<filename>/dev/fd/<n></filename> files, Bash may use
|
|||
|
temporary files. (Thanks, S.C.)</para>
|
|||
|
|
|||
|
<para><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) dir
|
|||
|
# Calls "tar cf /dev/fd/?? dir", 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 dir
|
|||
|
rm pipe
|
|||
|
# or
|
|||
|
exec 3>&1
|
|||
|
tar cf /dev/fd/4 dir 4>&1 >&3 3>&- | bzip2 -c > file.tar.bz2 3>&-
|
|||
|
exec 3>&-
|
|||
|
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>A reader of this document sent in the following interesting
|
|||
|
example of process substitution.</para>
|
|||
|
|
|||
|
<para><programlisting># Script fragment taken from SuSE distribution:
|
|||
|
|
|||
|
while read des what mask iface; do
|
|||
|
# Some commands ...
|
|||
|
done < <(route -n)
|
|||
|
|
|||
|
|
|||
|
# To test it, let's make it do something.
|
|||
|
while read des what mask iface; do
|
|||
|
echo $des $what $mask $iface
|
|||
|
done < <(route -n)
|
|||
|
|
|||
|
# Output:
|
|||
|
# Kernel IP routing table
|
|||
|
# Destination Gateway Genmask Flags Metric Ref Use Iface
|
|||
|
# 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
|
|||
|
|
|||
|
|
|||
|
# As S.C. points out, an easier-to-understand equivalent is:
|
|||
|
route -n |
|
|||
|
while read des what mask iface; do # Variables set from output of pipe.
|
|||
|
echo $des $what $mask $iface
|
|||
|
done # Same output as above.</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- Process Substitution -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="functions">
|
|||
|
<title>Functions</title>
|
|||
|
|
|||
|
<para><anchor id="functionref"></para>
|
|||
|
|
|||
|
<para>Like <quote>real</quote> programming languages,
|
|||
|
Bash has functions, though in a somewhat limited implementation.
|
|||
|
A function is a subroutine, a <link linkend="codeblockref">code
|
|||
|
block</link> that implements a set of operations, a <quote>black
|
|||
|
box</quote> that performs a specified task. Wherever there is
|
|||
|
repetitive code, when a task repeats with only slight variations,
|
|||
|
then consider using a function.</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<command>function</command>
|
|||
|
<arg choice="plain"><replaceable>function_name</replaceable></arg>
|
|||
|
<arg choice="plain">{</arg><sbr>
|
|||
|
<arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr>
|
|||
|
<arg choice="plain">}</arg><sbr>
|
|||
|
</cmdsynopsis>
|
|||
|
or
|
|||
|
<cmdsynopsis>
|
|||
|
<arg choice="plain"><replaceable>function_name</replaceable></arg>
|
|||
|
<arg choice="plain">()</arg>
|
|||
|
<arg choice="plain">{</arg><sbr>
|
|||
|
<arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr>
|
|||
|
<arg choice="plain">}</arg><sbr>
|
|||
|
</cmdsynopsis>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>This second form will cheer the hearts of C programmers
|
|||
|
(and is more portable).</para>
|
|||
|
|
|||
|
<para>As in C, the function's opening bracket may optionally appear
|
|||
|
on the second line.</para>
|
|||
|
|
|||
|
<para><cmdsynopsis>
|
|||
|
<arg choice="plain"><replaceable>function_name</replaceable></arg>
|
|||
|
<arg choice="plain">()</arg><sbr>
|
|||
|
<arg choice="plain">{</arg><sbr>
|
|||
|
<arg rep="repeat" choice="plain"><replaceable>command</replaceable></arg><sbr>
|
|||
|
<arg choice="plain">}</arg><sbr>
|
|||
|
</cmdsynopsis>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Functions are called, <firstterm>triggered</firstterm>, simply by
|
|||
|
invoking their names.</para>
|
|||
|
|
|||
|
<example id="ex59">
|
|||
|
<title>Simple function</title>
|
|||
|
<programlisting>&ex59;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>The function definition must precede the first call to
|
|||
|
it. There is no method of <quote>declaring</quote> the function,
|
|||
|
as, for example, in C.
|
|||
|
<programlisting># f1
|
|||
|
# Will give an error message, since function "f1" not yet defined.
|
|||
|
|
|||
|
# However...
|
|||
|
|
|||
|
|
|||
|
f1 ()
|
|||
|
{
|
|||
|
echo "Calling function \"f2\" from within function \"f1\"."
|
|||
|
f2
|
|||
|
}
|
|||
|
|
|||
|
f2 ()
|
|||
|
{
|
|||
|
echo "Function \"f2\"."
|
|||
|
}
|
|||
|
|
|||
|
f1 # Function "f2" is not actually called until this point,
|
|||
|
# although it is referenced before its definition.
|
|||
|
# This is permissable.
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>It is even possible to nest a function within another function,
|
|||
|
although this is not very useful.
|
|||
|
<programlisting>f1 ()
|
|||
|
{
|
|||
|
|
|||
|
f2 () # nested
|
|||
|
{
|
|||
|
echo "Function \"f2\", inside \"f1\"."
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
# f2
|
|||
|
# Gives an error message.
|
|||
|
|
|||
|
f1 # Does nothing, since calling "f1" does not automatically call "f2".
|
|||
|
f2 # Now, it's all right to call "f2",
|
|||
|
# since its definition has been made visible by calling "f1".
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Function declarations can appear in unlikely places, even where a
|
|||
|
command would otherwise go.
|
|||
|
<programlisting>ls -l | foo() { echo "foo"; } # Permissable, but useless.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if [ "$USER" = bozo ]
|
|||
|
then
|
|||
|
bozo_greet () # Function definition embedded in an if/then construct.
|
|||
|
{
|
|||
|
echo "Hello, Bozo."
|
|||
|
}
|
|||
|
fi
|
|||
|
|
|||
|
bozo_greet # Works only for Bozo, and other users get an error.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
# Something like this might be useful in some contexts.
|
|||
|
NO_EXIT=1 # Will enable function definition below.
|
|||
|
|
|||
|
[[ $NO_EXIT -eq 1 ]] && exit() { true; } # Function definition in an "and-list".
|
|||
|
# If $NO_EXIT is 1, declares "exit ()".
|
|||
|
# This disables the "exit" builtin by aliasing it to "true".
|
|||
|
|
|||
|
exit # Invokes "exit ()" function, not "exit" builtin.
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<sect2>
|
|||
|
<title>Complex Functions and Function Complexities</title>
|
|||
|
|
|||
|
<para>Functions may process arguments passed to them and return
|
|||
|
an <link linkend="exitstatusref">exit status</link> to the script
|
|||
|
for further processing.</para>
|
|||
|
|
|||
|
<programlisting>function_name $arg1 $arg2</programlisting>
|
|||
|
|
|||
|
<para>The function refers to the passed arguments by position (as if they were
|
|||
|
<link linkend="posparamref">positional parameters</link>),
|
|||
|
that is, <varname>$1</varname>, <varname>$2</varname>, and
|
|||
|
so forth.</para>
|
|||
|
|
|||
|
<example id="ex60">
|
|||
|
<title>Function Taking Parameters</title>
|
|||
|
<programlisting>&ex60;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<note><para>In contrast to certain other programming languages,
|
|||
|
shell scripts normally pass only value parameters to functions.
|
|||
|
|
|||
|
<footnote><para><link linkend="ivrref">Indirect variable
|
|||
|
references</link> (see <xref linkend="ex78">) provide a clumsy
|
|||
|
sort of mechanism for passing variable pointers to functions.
|
|||
|
|
|||
|
<programlisting>&refparams;</programlisting>
|
|||
|
</para></footnote>
|
|||
|
|
|||
|
Variable names (which are actually pointers), if passed as
|
|||
|
parameters to functions, will be treated as string literals
|
|||
|
and cannot be dereferenced. <emphasis>Functions interpret their
|
|||
|
arguments literally.</emphasis></para></note>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term>exit status</term>
|
|||
|
<listitem>
|
|||
|
<para>Functions return a value, called an <firstterm>exit
|
|||
|
status</firstterm>. The exit status may be explicitly
|
|||
|
specified by a <command>return</command> statement,
|
|||
|
otherwise it is the exit status of the last command
|
|||
|
in the function (<returnvalue>0</returnvalue> if
|
|||
|
successful, and a non-zero error code if not). This
|
|||
|
<link linkend="exitstatusref">exit status</link>
|
|||
|
may be used in the script by referencing it as
|
|||
|
<link linkend="xstatvarref">$?</link>. This mechanism
|
|||
|
effectively permits script functions to have a <quote>return
|
|||
|
value</quote> similar to C functions.</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><command>return</command></term>
|
|||
|
<indexterm>
|
|||
|
<primary>return</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>command</primary>
|
|||
|
<secondary>return</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>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 integer 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.
|
|||
|
}
|
|||
|
|
|||
|
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>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><replaceable>redirecting the stdin of a
|
|||
|
function</replaceable></term>
|
|||
|
<indexterm>
|
|||
|
<primary>redirection</primary>
|
|||
|
<secondary>stdin</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>A function is essentially a <link
|
|||
|
linkend="codeblockref">code block</link>, which means its
|
|||
|
<filename>stdin</filename> can be redirected (as in <xref
|
|||
|
linkend="ex8">).</para>
|
|||
|
|
|||
|
<example id="realname">
|
|||
|
<title>Real name from username</title>
|
|||
|
<programlisting>&realname;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>There is an alternative, and perhaps less confusing
|
|||
|
method of redirecting a function's
|
|||
|
<filename>stdin</filename>. This involves redirecting the
|
|||
|
<filename>stdin</filename> to an embedded bracketed code
|
|||
|
block within the function.
|
|||
|
|
|||
|
<programlisting># Instead of:
|
|||
|
Function ()
|
|||
|
{
|
|||
|
...
|
|||
|
} < file
|
|||
|
|
|||
|
# Try this:
|
|||
|
Function ()
|
|||
|
{
|
|||
|
{
|
|||
|
...
|
|||
|
} < file
|
|||
|
}
|
|||
|
|
|||
|
# Similarly,
|
|||
|
|
|||
|
Function () # This works.
|
|||
|
{
|
|||
|
{
|
|||
|
echo $*
|
|||
|
} | tr a b
|
|||
|
}
|
|||
|
|
|||
|
Function () # This doesn't work.
|
|||
|
{
|
|||
|
echo $*
|
|||
|
} | tr a b # A nested code block is mandatory here.
|
|||
|
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- Complex Functions and Function Complexities -->
|
|||
|
|
|||
|
|
|||
|
<sect2>
|
|||
|
<title>Local Variables and Recursion</title>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term><anchor id="localref"><replaceable>local variables</replaceable></term>
|
|||
|
<indexterm>
|
|||
|
<primary>variable</primary>
|
|||
|
<secondary>local</secondary>
|
|||
|
</indexterm>
|
|||
|
<listitem>
|
|||
|
<para>A variable declared as <firstterm>local</firstterm>
|
|||
|
is one that is visible only within the <link
|
|||
|
linkend="codeblockref">block of code</link> in
|
|||
|
which it appears. In a function, a <emphasis>local
|
|||
|
variable</emphasis> has meaning only within that function
|
|||
|
block.</para>
|
|||
|
|
|||
|
<example id="ex62">
|
|||
|
<title>Local variable visibility</title>
|
|||
|
<programlisting>&ex62;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Local variables permit recursion (a recursive function
|
|||
|
is one that calls itself), but this practice generally
|
|||
|
involves much computational overhead and is definitely
|
|||
|
<emphasis>not</emphasis> recommended in a shell script.
|
|||
|
|
|||
|
<footnote><para>Too many levels of recursion may crash a
|
|||
|
script with a segfault.
|
|||
|
<programlisting>#!/bin/bash
|
|||
|
|
|||
|
recursive_function ()
|
|||
|
{
|
|||
|
(( $1 < $2 )) && f $(( $1 + 1 )) $2;
|
|||
|
}
|
|||
|
|
|||
|
recursive_function 1 50000 # Segfaults.
|
|||
|
|
|||
|
# Recursion this deep might cause even a C program to segfault,
|
|||
|
# by using up all the memory allotted to the stack.
|
|||
|
|
|||
|
# Thanks, S.C.
|
|||
|
|
|||
|
exit 0 # This script will not exit normally.</programlisting>
|
|||
|
</para></footnote>
|
|||
|
|
|||
|
</para>
|
|||
|
|
|||
|
<example id="ex63">
|
|||
|
<title>Recursion, using a local variable</title>
|
|||
|
<programlisting>&ex63;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>See also <xref linkend="primes"> for an example of
|
|||
|
recursion in a script. Be aware that recursion is
|
|||
|
resource-intensive and executes slowly, especially in
|
|||
|
a script.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
</sect2> <!-- Local Variables and Recursion -->
|
|||
|
|
|||
|
</sect1> <!-- Functions -->
|
|||
|
|
|||
|
|
|||
|
<sect1 id="aliases">
|
|||
|
<title>Aliases</title>
|
|||
|
|
|||
|
<para><anchor id="aliasref"></para>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>alias</primary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para>A bash <emphasis>alias</emphasis> is essentially nothing more than
|
|||
|
a keyboard shortcut, an abbreviation, a means of avoiding
|
|||
|
typing a long command sequence. If, for example, we include
|
|||
|
<command>alias lm="ls -l | more"</command> in the <link
|
|||
|
linkend="filesref"><filename>~/.bashrc</filename> file</link>,
|
|||
|
then each <userinput>lm</userinput> typed at the command
|
|||
|
line will automatically be replaced by a <command>ls -l |
|
|||
|
more</command>. This can save a great deal of typing at the
|
|||
|
command line and avoid having to remember complex combinations of
|
|||
|
commands and options. Setting <command>alias rm="rm -i"</command>
|
|||
|
(interactive mode delete) may save a good deal of grief, since
|
|||
|
it can prevent inadvertently losing important files.</para>
|
|||
|
|
|||
|
<para>In a script, aliases have very limited usefulness. It would be
|
|||
|
quite nice if aliases could assume some of the functionality
|
|||
|
of the C preprocessor, such as macro expansion, but
|
|||
|
unfortunately Bash does not expand arguments within the
|
|||
|
alias body. 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. 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>
|
|||
|
|
|||
|
<note><para>The <command>unalias</command> command removes a previously
|
|||
|
set <emphasis>alias</emphasis>.</para></note>
|
|||
|
|
|||
|
<example id="unal">
|
|||
|
<title><command>unalias</command>: Setting and unsetting an alias</title>
|
|||
|
<programlisting>&unal;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<screen><prompt>bash$ </prompt><userinput>./unalias.sh</userinput>
|
|||
|
<computeroutput>
|
|||
|
total 6
|
|||
|
drwxrwxr-x 2 bozo bozo 3072 Feb 6 14:04 .
|
|||
|
drwxr-xr-x 40 bozo bozo 2048 Feb 6 14:04 ..
|
|||
|
-rwxr-xr-x 1 bozo bozo 199 Feb 6 14:04 unalias.sh
|
|||
|
|
|||
|
./unalias.sh: llm: command not found
|
|||
|
</computeroutput></screen>
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- Aliases -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="list-cons">
|
|||
|
<title>List Constructs</title>
|
|||
|
|
|||
|
<para><anchor id="listconsref"></para>
|
|||
|
|
|||
|
<indexterm>
|
|||
|
<primary>&&</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>&&</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>AND</primary>
|
|||
|
<secondary>list</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>||</primary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>special character</primary>
|
|||
|
<secondary>||</secondary>
|
|||
|
</indexterm>
|
|||
|
<indexterm>
|
|||
|
<primary>OR</primary>
|
|||
|
<secondary>list</secondary>
|
|||
|
</indexterm>
|
|||
|
|
|||
|
<para>The <quote>and list</quote> and <quote>or list</quote>
|
|||
|
constructs provide a means of processing a number of commands
|
|||
|
consecutively. These can effectively replace complex
|
|||
|
nested <command>if</command>/<command>then</command> or even
|
|||
|
<command>case</command> statements.</para>
|
|||
|
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term>and list</term>
|
|||
|
<listitem>
|
|||
|
<para><programlisting>command-1 && command-2 && command-3 && ... command-n</programlisting>
|
|||
|
Each command executes in turn provided that
|
|||
|
the previous command has given a return value of
|
|||
|
<returnvalue>true</returnvalue> (zero). At the first
|
|||
|
<returnvalue>false</returnvalue> (non-zero) return, the
|
|||
|
command chain terminates (the first command returning
|
|||
|
<returnvalue>false</returnvalue> is the last one to
|
|||
|
execute).</para>
|
|||
|
|
|||
|
<example id="ex64">
|
|||
|
<title>Using an <quote>and list</quote> to test for command-line arguments</title>
|
|||
|
<programlisting>&ex64;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="andlist2">
|
|||
|
<title>Another command-line arg test using an <quote>and list</quote></title>
|
|||
|
<programlisting>&andlist2;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term>or list</term>
|
|||
|
<listitem>
|
|||
|
<para><programlisting>command-1 || command-2 || command-3 || ... command-n</programlisting>
|
|||
|
Each command executes in turn for as long as the previous
|
|||
|
command returns <returnvalue>false</returnvalue>. At
|
|||
|
the first <returnvalue>true</returnvalue> return, the
|
|||
|
command chain terminates (the first command returning
|
|||
|
<returnvalue>true</returnvalue> is the last one to
|
|||
|
execute). This is obviously the inverse of the <quote>and
|
|||
|
list</quote>.</para>
|
|||
|
|
|||
|
<example id="ex65">
|
|||
|
<title>Using <quote>or lists</quote> in combination with an <quote>and list</quote></title>
|
|||
|
<programlisting>&ex65;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<caution><para>If the first command in an <quote>or list</quote>
|
|||
|
returns <returnvalue>true</returnvalue>, it
|
|||
|
<replaceable>will</replaceable> execute.</para></caution>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<important><para>The <link linkend="exitstatusref">exit
|
|||
|
status</link> of an <userinput>and list</userinput> or an
|
|||
|
<userinput>or list</userinput> is the exit status of the last
|
|||
|
command executed.</para></important>
|
|||
|
|
|||
|
<para>Clever combinations of <quote>and</quote> and <quote>or</quote>
|
|||
|
lists are possible, but the logic may easily become convoluted and
|
|||
|
require extensive debugging.
|
|||
|
<programlisting>false && true || echo false # false
|
|||
|
|
|||
|
# Same result as
|
|||
|
( false && true ) || echo false # false
|
|||
|
# But *not*
|
|||
|
false && ( true || echo false ) # (nothing echoed)
|
|||
|
|
|||
|
# Note left-to-right grouping and evaluation of statements,
|
|||
|
# since the logic operators "&&" and "||" have equal precedence.
|
|||
|
|
|||
|
# It's best to avoid such complexities, unless you know what you're doing.
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- List Constructs -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="arrays">
|
|||
|
<title>Arrays</title>
|
|||
|
|
|||
|
<para><anchor id="arrayref"></para>
|
|||
|
|
|||
|
<para>Newer versions of <command>bash</command> support one-dimensional
|
|||
|
arrays. Arrays may be declared with the <userinput>variable[xx]</userinput>
|
|||
|
notation or explicitly by a <userinput>declare -a variable</userinput>
|
|||
|
statement. To dereference (find the contents of) an array variable, use
|
|||
|
<firstterm>curly bracket</firstterm> notation, that is, <userinput>${variable[xx]}</userinput>.</para>
|
|||
|
|
|||
|
<example id="ex66">
|
|||
|
<title>Simple array usage</title>
|
|||
|
<programlisting>&ex66;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Arrays variables have a syntax all their own, and even
|
|||
|
standard Bash operators have special options adapted for array
|
|||
|
use.</para>
|
|||
|
|
|||
|
<example id="ex67">
|
|||
|
<title>Some special properties of arrays</title>
|
|||
|
<programlisting>&ex67;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>As seen in the previous example, either
|
|||
|
<command>${array_name[@]}</command> or
|
|||
|
<command>${array_name[*]}</command> refers to
|
|||
|
<emphasis>all</emphasis> the elements of the array.
|
|||
|
Similarly, to get a count of the number of elements in an
|
|||
|
array, use either <command>${#array_name[@]}</command>
|
|||
|
or <command>${#array_name[*]}</command>.
|
|||
|
<command>${#array_name}</command> is the length (number of
|
|||
|
characters) of <command>${array_name[0]}</command>, the first
|
|||
|
element of the array.</para>
|
|||
|
|
|||
|
<example id="emptyarray">
|
|||
|
<title>Of empty arrays and empty elements</title>
|
|||
|
<programlisting>&emptyarray;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>The relationship of <command>${array_name[@]}</command>
|
|||
|
and <command>${array_name[*]}</command> is analogous to that
|
|||
|
between <link linkend="appref">$@ and $*</link>. This powerful
|
|||
|
array notation has a number of uses.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<programlisting># Copying an array.
|
|||
|
array2=( "${array1[@]}" )
|
|||
|
|
|||
|
# Adding an element to an array.
|
|||
|
array=( "${array[@]}" "new element" )
|
|||
|
# or
|
|||
|
array[${#array[*]}]="new element"
|
|||
|
|
|||
|
# Thanks, S.C.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>--</para>
|
|||
|
|
|||
|
<para>Arrays permit deploying old familiar algorithms as shell scripts.
|
|||
|
Whether this is necessarily a good idea is left to the reader to
|
|||
|
decide.</para>
|
|||
|
|
|||
|
<example id="bubble">
|
|||
|
<title>An old friend:
|
|||
|
<emphasis>The Bubble Sort</emphasis></title>
|
|||
|
<programlisting>&bubble;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>--</para>
|
|||
|
|
|||
|
<para>Arrays enable implementing a shell script version of the <emphasis>Sieve of
|
|||
|
Erastosthenes</emphasis>. Of course, a resource-intensive application of this
|
|||
|
nature should really be written in a compiled language, such as C. It
|
|||
|
runs excruciatingly slowly as a script.</para>
|
|||
|
|
|||
|
<example id="ex68">
|
|||
|
<title>Complex array application:
|
|||
|
<emphasis>Sieve of Erastosthenes</emphasis></title>
|
|||
|
<programlisting>&ex68;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Compare this array-based prime number generator with with an
|
|||
|
alternative that does not use arrays, <xref
|
|||
|
linkend="primes">.</para>
|
|||
|
|
|||
|
<para>--</para>
|
|||
|
|
|||
|
<para>Fancy manipulation of array <quote>subscripts</quote> may require
|
|||
|
intermediate variables. For projects involving this, again consider
|
|||
|
using a more powerful programming language, such as Perl or C.</para>
|
|||
|
|
|||
|
<example id="qfunction">
|
|||
|
<title>Complex array application:
|
|||
|
<emphasis>Exploring a weird mathematical series</emphasis></title>
|
|||
|
<programlisting>&qfunction;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>--</para>
|
|||
|
|
|||
|
<para>Bash supports only one-dimensional arrays, however a little
|
|||
|
trickery permits simulating multi-dimensional ones.</para>
|
|||
|
|
|||
|
<example id="twodim">
|
|||
|
<title>Simulating a two-dimensional array, then tilting it</title>
|
|||
|
<programlisting>&twodim;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</sect1> <!-- Arrays -->
|
|||
|
|
|||
|
<sect1 id="files">
|
|||
|
<title>Files</title>
|
|||
|
|
|||
|
<para><anchor id="filesref"></para>
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para><filename>/etc/profile</filename></para>
|
|||
|
<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>
|
|||
|
<listitem>
|
|||
|
<para><filename>/etc/bashrc</filename></para>
|
|||
|
<para>systemwide functions and and <link
|
|||
|
linkend="aliasref">aliases</link> for Bash</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para><filename><varname>$HOME</varname>/.bash_profile</filename></para>
|
|||
|
<para>user-specific Bash environmental default settings,
|
|||
|
found in each user's home directory (the local counterpart
|
|||
|
to <filename>/etc/profile</filename>)</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para><filename><varname>$HOME</varname>/.bashrc</filename></para>
|
|||
|
<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>
|
|||
|
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
<para>These are the <emphasis>startup files</emphasis> for Bash. They
|
|||
|
contain the aliases and environmental variables made available
|
|||
|
to Bash running as a user shell and to all Bash scripts invoked
|
|||
|
after system initialization.</para>
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para><filename><varname>$HOME</varname>/.bash_logout</filename></para>
|
|||
|
<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>
|
|||
|
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
</sect1> <!-- Files -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="devproc">
|
|||
|
<title>/dev and /proc</title>
|
|||
|
|
|||
|
<para><anchor id="devprocref"></para>
|
|||
|
|
|||
|
<para>A Linux or UNIX machine typically has two special-purpose
|
|||
|
directories, <filename class="directory">/dev</filename> and
|
|||
|
<filename class="directory">/proc</filename>. The <filename
|
|||
|
class="directory">/dev</filename> directory contains entries
|
|||
|
for the physical <emphasis>devices</emphasis> that may or may
|
|||
|
not be present in the hardware.
|
|||
|
|
|||
|
<footnote>
|
|||
|
<para>The entries in <filename class="directory">/dev</filename>
|
|||
|
provide mount points for physical and virtual devices. These
|
|||
|
entries use very little drive space.</para>
|
|||
|
|
|||
|
<para>Some devices, such as
|
|||
|
<filename>/dev/null</filename>, <filename>/dev/zero</filename>,
|
|||
|
and <filename>/dev/urandom</filename> are virtual. They
|
|||
|
are not actual physical devices and exist only in
|
|||
|
software.</para>
|
|||
|
</footnote>
|
|||
|
|
|||
|
The <filename class="directory">/proc</filename> directory
|
|||
|
is actually a pseudo-filesystem. The files in the <filename
|
|||
|
class="directory">/proc</filename> directory mirror currently
|
|||
|
running system and kernel <emphasis>processes</emphasis> and
|
|||
|
contain information and statistics about them.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>cat /proc/devices</userinput>
|
|||
|
<computeroutput>Character devices:
|
|||
|
1 mem
|
|||
|
2 pty
|
|||
|
3 ttyp
|
|||
|
4 ttyS
|
|||
|
5 cua
|
|||
|
7 vcs
|
|||
|
10 misc
|
|||
|
14 sound
|
|||
|
29 fb
|
|||
|
36 netlink
|
|||
|
128 ptm
|
|||
|
136 pts
|
|||
|
162 raw
|
|||
|
254 pcmcia
|
|||
|
|
|||
|
Block devices:
|
|||
|
1 ramdisk
|
|||
|
2 fd
|
|||
|
3 ide0
|
|||
|
9 md</computeroutput>
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>cat /dev/sndstat | grep Audio</userinput>
|
|||
|
<computeroutput>Audio devices:
|
|||
|
0: ESS ES1688 AudioDrive (rev 11) (3.01)</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<note><para>As of the 2.3 (and 2.4) kernel,
|
|||
|
<filename>/dev/sndstat</filename> has been deprecated.</para></note>
|
|||
|
|
|||
|
<para><anchor id="loopbackref">The <filename
|
|||
|
class="directory">/dev</filename> directory
|
|||
|
contains <emphasis>loopback</emphasis> devices, such as
|
|||
|
<filename>/dev/loop0</filename>. A loopback device is a gimmick
|
|||
|
allows an ordinary file to be accessed as if it were a block
|
|||
|
device.
|
|||
|
|
|||
|
<footnote><para>A <emphasis>block device</emphasis> reads and/or
|
|||
|
writes data in chunks, or blocks, in contrast to a
|
|||
|
<emphasis>character device</emphasis>, which acesses data
|
|||
|
in character units. Examples of block devices are a hard
|
|||
|
drive and CD ROM drive. An example of a character device is
|
|||
|
a keyboard.</para></footnote>
|
|||
|
|
|||
|
This enables mounting an entire filesystem within a
|
|||
|
single large file. See <xref linkend="createfs"> and <xref
|
|||
|
linkend="isomountref">.</para>
|
|||
|
|
|||
|
|
|||
|
<para>Shell scripts may extract data from certain of the files in
|
|||
|
<filename class="directory">/dev</filename> and <filename
|
|||
|
class="directory">/proc</filename>.
|
|||
|
|
|||
|
<footnote><para>Certain system commands, such as
|
|||
|
<link linkend="procinforef">procinfo</link>,
|
|||
|
<link linkend="freeref">free</link>, and <link
|
|||
|
linkend="uptimeref">uptime</link> do this as
|
|||
|
well.</para></footnote> </para>
|
|||
|
|
|||
|
|
|||
|
<para><programlisting>kernel_version=$( awk '{ print $3 }' /proc/version )</programlisting></para>
|
|||
|
|
|||
|
<para><programlisting>CPU=$( awk '/model name/ {print $4}' < /proc/cpuinfo )
|
|||
|
|
|||
|
if [ $CPU = Pentium ]
|
|||
|
then
|
|||
|
run_some_commands
|
|||
|
...
|
|||
|
else
|
|||
|
run_different_commands
|
|||
|
...
|
|||
|
fi</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<para>A few of the pseudo-devices in <filename
|
|||
|
class="directory">/dev</filename> have
|
|||
|
other specialized uses, such as <link
|
|||
|
linkend="zerosref"><filename>/dev/zero</filename></link>.</para>
|
|||
|
|
|||
|
<para>The <filename class="directory">/proc</filename> directory
|
|||
|
contains subdirectories with unusual numerical
|
|||
|
names. Every one of these names maps to the <link
|
|||
|
linkend="ppidref">process ID</link> of a currently running
|
|||
|
process. Within each of these subdirectories, there are
|
|||
|
a number of files that hold useful information about the
|
|||
|
corresponding process. The <filename>stat</filename> and
|
|||
|
<filename>status</filename> files keep running statistics
|
|||
|
on the process, the <filename>cmdline</filename> file holds
|
|||
|
the command-line arguments the process was invoked with, and
|
|||
|
the <filename>exe</filename> file is a symbolic link to the
|
|||
|
complete path name of the invoking process. There are a few
|
|||
|
more such files, but these seem to be the most interesting
|
|||
|
from a scripting standpoint.</para>
|
|||
|
|
|||
|
<example id="pidid">
|
|||
|
<title>Finding the process associated with a PID</title>
|
|||
|
<programlisting>&pidid;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="constat">
|
|||
|
<title>On-line connect status</title>
|
|||
|
<programlisting>&constat;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<warning><para>In general, it is dangerous to
|
|||
|
<emphasis>write</emphasis> to the files in <filename
|
|||
|
class="directory">/proc</filename>, as this can corrupt the
|
|||
|
filesystem or crash the machine.</para></warning>
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- /dev and /proc -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="zeros">
|
|||
|
<title>Of Zeros and Nulls</title>
|
|||
|
|
|||
|
<para><anchor id="zerosref"></para>
|
|||
|
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term>Uses of <filename>/dev/null</filename></term>
|
|||
|
<listitem>
|
|||
|
<para>Think of <filename>/dev/null</filename> as a <quote>black
|
|||
|
hole</quote>. It is the nearest equivalent to a
|
|||
|
write-only file. Everything written to it disappears
|
|||
|
forever. Attempts to read or output from it result in
|
|||
|
nothing. Nevertheless, <filename>/dev/null</filename>
|
|||
|
can be quite useful from both the command line and in
|
|||
|
scripts.</para>
|
|||
|
|
|||
|
<para>Suppressing <filename>stdout</filename> or
|
|||
|
<filename>stderr</filename> (from <xref linkend="ex74">):
|
|||
|
<programlisting>rm $badname 2>/dev/null
|
|||
|
# So error messages [stderr] deep-sixed.</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 log file
|
|||
|
(especially good for dealing with those nasty
|
|||
|
<quote>cookies</quote> sent by Web commercial sites):</para>
|
|||
|
|
|||
|
<example id="cookies">
|
|||
|
<title>Hiding the cookie jar</title>
|
|||
|
<programlisting>if [ -f ~/.netscape/cookies ] # Remove, if exists.
|
|||
|
then
|
|||
|
rm -f ~/.netscape/cookies
|
|||
|
fi
|
|||
|
|
|||
|
ln -s /dev/null ~/.netscape/cookies
|
|||
|
# All cookies now get sent to a black hole, rather than saved to disk.</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
<varlistentry>
|
|||
|
<term>Uses of <filename>/dev/zero</filename></term>
|
|||
|
<listitem>
|
|||
|
<para>Like <filename>/dev/null</filename>,
|
|||
|
<filename>/dev/zero</filename> is a pseudo file,
|
|||
|
but it actually contains nulls (numerical zeros, not
|
|||
|
the ASCII kind). Output written to it disappears, and
|
|||
|
it is fairly difficult to actually read the nulls in
|
|||
|
<filename>/dev/zero</filename>, though it can be done
|
|||
|
with <command>od</command> or a hex editor. The chief
|
|||
|
use for <filename>/dev/zero</filename> is in creating an
|
|||
|
initialized dummy file of specified length intended as a
|
|||
|
temporary swap file.</para>
|
|||
|
|
|||
|
<example id="ex73">
|
|||
|
<title>Setting up a swapfile using <filename>/dev/zero</filename></title>
|
|||
|
<programlisting>&ex73;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Another application of <filename>/dev/zero</filename>
|
|||
|
is to <quote>zero out</quote> a file of a designated size
|
|||
|
for a special purpose, such as mounting a filesystem on
|
|||
|
a <link linkend="loopbackref">loopback device</link>.
|
|||
|
See <xref linkend="createfs">.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
|
|||
|
</variablelist>
|
|||
|
</sect1> <!-- Zeros and Nulls -->
|
|||
|
|
|||
|
<sect1 id="debugging">
|
|||
|
<title>Debugging</title>
|
|||
|
<para>The Bash shell contains no debugger, nor even any
|
|||
|
debugging-specific commands or constructs. Syntax errors or
|
|||
|
outright typos in the script generate cryptic error messages that
|
|||
|
are often of no help in debugging a non-functional script.</para>
|
|||
|
|
|||
|
<example id="ex74">
|
|||
|
<title>test23, a buggy script</title>
|
|||
|
<programlisting>&ex74;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Output from script:
|
|||
|
<screen><computeroutput>./test23: [37: command not found</computeroutput></screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>What's wrong with the above script (hint: after the <command>if</command>)?</para>
|
|||
|
|
|||
|
|
|||
|
<para>What if the script executes, but does not work as expected? This is the
|
|||
|
all too familiar logic error.</para>
|
|||
|
|
|||
|
<example id="ex75">
|
|||
|
<title>test24, another buggy script</title>
|
|||
|
<programlisting>&ex75;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Try to find out what's wrong with <xref linkend="ex75">
|
|||
|
by uncommenting the <userinput>echo "$badname"</userinput> line. Echo
|
|||
|
statements are useful for seeing whether what you expect is
|
|||
|
actually what you get.</para>
|
|||
|
|
|||
|
<para>In this particular case, <userinput>rm "$badname"</userinput>
|
|||
|
will not give the desired results because
|
|||
|
<varname>$badname</varname> should not be quoted. Placing it
|
|||
|
in quotes ensures that <command>rm</command> has only one
|
|||
|
argument (it will match only one filename). A partial fix
|
|||
|
is to remove to quotes from <varname>$badname</varname> and
|
|||
|
to reset <varname>$IFS</varname> to contain only a newline,
|
|||
|
<userinput>IFS=$'\n'</userinput>. However, there are simpler
|
|||
|
ways of going about it.
|
|||
|
<programlisting># Correct methods of deleting filenames containing spaces.
|
|||
|
rm *\ *
|
|||
|
rm *" "*
|
|||
|
rm *' '*
|
|||
|
# Thank you. S.C.</programlisting>
|
|||
|
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Summarizing the symptoms of a buggy script,
|
|||
|
<orderedlist>
|
|||
|
<listitem>
|
|||
|
<para>It bombs with an error message <errorname>syntax error</errorname>, or</para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para>It runs, but does not work as expected
|
|||
|
(<errorname>logic error</errorname>)</para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para>It runs, works as expected, but has nasty side effects
|
|||
|
(<errorname>logic bomb</errorname>).</para>
|
|||
|
</listitem>
|
|||
|
</orderedlist>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Tools for debugging non-working scripts include
|
|||
|
<orderedlist>
|
|||
|
<listitem>
|
|||
|
<para>echo statements at critical points in the script to trace the variables,
|
|||
|
and otherwise give a snapshot of what is going on.</para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para>using the <command>tee</command> 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><userinput>sh -x scriptname</userinput> echoes the result each
|
|||
|
command, but in an abbreviated manner. This is the equivalent of
|
|||
|
inserting <userinput>set -x</userinput> or
|
|||
|
<userinput>set -o xtrace</userinput> in the script.</para>
|
|||
|
|
|||
|
<para>Inserting <userinput>set -u</userinput> or
|
|||
|
<userinput>set -o nounset</userinput> in the script runs it, but
|
|||
|
gives an <errorname>unbound variable</errorname> error message
|
|||
|
at each attempt to use an undeclared variable.</para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>trapping at exit</para>
|
|||
|
|
|||
|
<para>The <command>exit</command> command in a script triggers a
|
|||
|
signal <returnvalue>0</returnvalue>, terminating the
|
|||
|
process, that is, the script itself.
|
|||
|
|
|||
|
<footnote><para>By convention, <replaceable>signal
|
|||
|
0</replaceable> is assigned to <link
|
|||
|
linkend="exitcommandref">exit</link>. </para></footnote>
|
|||
|
|
|||
|
It is often useful to trap the
|
|||
|
<command>exit</command>, forcing a <quote>printout</quote>
|
|||
|
of variables, for example. The <command>trap</command>
|
|||
|
must be the first command in the script.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
</orderedlist>
|
|||
|
</para>
|
|||
|
<variablelist>
|
|||
|
<varlistentry>
|
|||
|
<term><command>trap</command></term>
|
|||
|
<listitem>
|
|||
|
<para>Specifies an action on receipt of a signal; also useful for debugging.
|
|||
|
<note><para><anchor id="signald">A
|
|||
|
<emphasis>signal</emphasis> is simply a message
|
|||
|
sent to a process, either by the kernel or another
|
|||
|
process, telling it to take some specified action
|
|||
|
(usually to terminate). For example, hitting a
|
|||
|
<keycombo><keycap>Control</keycap><keycap>C</keycap></keycombo>,
|
|||
|
sends a user interrupt, an INT signal, to a running
|
|||
|
program.</para></note>
|
|||
|
|
|||
|
<programlisting>trap '' 2
|
|||
|
# Ignore interrupt 2 (Control-C), with no action specified.
|
|||
|
|
|||
|
trap 'echo "Control-C disabled."' 2
|
|||
|
# Message when Control-C pressed.</programlisting>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</varlistentry>
|
|||
|
</variablelist>
|
|||
|
|
|||
|
<example id="ex76">
|
|||
|
<title>Trapping at exit</title>
|
|||
|
<programlisting>&ex76;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="online">
|
|||
|
<title>Cleaning up after Control-C</title>
|
|||
|
<programlisting>&online;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<note>
|
|||
|
<para>The <option>DEBUG</option> argument to
|
|||
|
<command>trap</command> causes a specified action to execute
|
|||
|
after every command in a script. This permits tracing variables,
|
|||
|
for example.
|
|||
|
|
|||
|
<example id="vartrace">
|
|||
|
<title>Tracing a variable</title>
|
|||
|
<programlisting>&vartrace;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</para>
|
|||
|
</note>
|
|||
|
|
|||
|
|
|||
|
<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>
|
|||
|
|
|||
|
</sect1> <!-- Debugging -->
|
|||
|
|
|||
|
<sect1 id="options">
|
|||
|
<title>Options</title>
|
|||
|
|
|||
|
<para><anchor id="optionsref"></para>
|
|||
|
|
|||
|
<para>Options are settings that change shell and/or script
|
|||
|
behavior.</para>
|
|||
|
|
|||
|
<para>The <link linkend="setref">set</link> command
|
|||
|
enables options within a script. At the point in the script
|
|||
|
where you want the options to take effect, use <command>set
|
|||
|
-o option-name</command> or, in short form, <command>set
|
|||
|
-option-abbrev</command>. These two forms are equivalent.</para>
|
|||
|
|
|||
|
<para><programlisting>
|
|||
|
#!/bin/bash
|
|||
|
|
|||
|
set -o verbose
|
|||
|
# Echoes all commands before executing.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
<para><programlisting>
|
|||
|
#!/bin/bash
|
|||
|
|
|||
|
set -v
|
|||
|
# Exact same effect as above.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
<note><para>To <emphasis>disable</emphasis> an option within a script,
|
|||
|
use <command>set +o option-name</command> or <command>set
|
|||
|
+option-abbrev</command>.</para></note>
|
|||
|
|
|||
|
<para><programlisting>
|
|||
|
#!/bin/bash
|
|||
|
|
|||
|
set -o verbose
|
|||
|
# Command echoing on.
|
|||
|
command
|
|||
|
...
|
|||
|
command
|
|||
|
|
|||
|
set +o verbose
|
|||
|
# Command echoing off.
|
|||
|
command
|
|||
|
# Not echoed.
|
|||
|
|
|||
|
|
|||
|
set -v
|
|||
|
# Command echoing on.
|
|||
|
command
|
|||
|
...
|
|||
|
command
|
|||
|
|
|||
|
set +v
|
|||
|
# Command echoing off.
|
|||
|
command
|
|||
|
|
|||
|
exit 0
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>An alternate method of enabling options in a script is
|
|||
|
to specify them immediately following the
|
|||
|
<replaceable>#!</replaceable> script header.</para>
|
|||
|
|
|||
|
<para><programlisting>
|
|||
|
#!/bin/bash -x
|
|||
|
#
|
|||
|
# Body of script follows.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>It is also possible to enable script options from the command
|
|||
|
line. Some options that will not work with
|
|||
|
<command>set</command> are available this way. Among these
|
|||
|
are <replaceable>-i</replaceable>, force script to run
|
|||
|
interactive.</para>
|
|||
|
|
|||
|
<para><userinput>bash -v script-name</userinput></para>
|
|||
|
|
|||
|
<para><userinput>bash -o verbose script-name</userinput></para>
|
|||
|
|
|||
|
|
|||
|
<para>The following is a listing of some useful options. They may be
|
|||
|
specified in either abbreviated form or by complete name.</para>
|
|||
|
|
|||
|
<table>
|
|||
|
<title>bash options</title>
|
|||
|
<tgroup cols="3">
|
|||
|
<thead>
|
|||
|
<row>
|
|||
|
<entry>Abbreviation</entry>
|
|||
|
<entry>Name</entry>
|
|||
|
<entry>Effect</entry>
|
|||
|
</row>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<row>
|
|||
|
<entry><anchor id="noclobberref"><option>-C</option></entry>
|
|||
|
<entry>noclobber</entry>
|
|||
|
<entry>Prevent overwriting of files by redirection (may be
|
|||
|
overridden by <token>>|</token>)</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-D</option></entry>
|
|||
|
<entry>(none)</entry>
|
|||
|
<entry>List double-quoted strings prefixed by <token>$</token>,
|
|||
|
but do not execute commands in script</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-a</option></entry>
|
|||
|
<entry>allexport</entry>
|
|||
|
<entry>Export all defined variables</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-b</option></entry>
|
|||
|
<entry>notify</entry>
|
|||
|
<entry>Notify when jobs running in background terminate (not of
|
|||
|
much use in a script)</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-c ...</option></entry>
|
|||
|
<entry>(none)</entry>
|
|||
|
<entry>Read commands from <command>...</command></entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-f</option></entry>
|
|||
|
<entry>noglob</entry>
|
|||
|
<entry>Filename expansion (globbing) disabled</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-i</option></entry>
|
|||
|
<entry>interactive</entry>
|
|||
|
<entry>Script runs in <emphasis>interactive</emphasis> mode</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-p</option></entry>
|
|||
|
<entry>privileged</entry>
|
|||
|
<entry>Script runs as <quote>suid</quote> (caution!)</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-r</option></entry>
|
|||
|
<entry>restricted</entry>
|
|||
|
<entry>Script runs in <emphasis>restricted</emphasis>
|
|||
|
mode (see <xref linkend="restricted-sh">).</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-u</option></entry>
|
|||
|
<entry>nounset</entry>
|
|||
|
<entry>Attempt to use undefined variable
|
|||
|
outputs error message, and forces an exit</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-v</option></entry>
|
|||
|
<entry>verbose</entry>
|
|||
|
<entry>Print each command to <filename>stdout</filename> before executing it</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-x</option></entry>
|
|||
|
<entry>xtrace</entry>
|
|||
|
<entry>Similar to <option>-v</option>, but expands commands</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-e</option></entry>
|
|||
|
<entry>errexit</entry>
|
|||
|
<entry>Abort script at first error (when a command exits with
|
|||
|
non-zero status)</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>-n</option></entry>
|
|||
|
<entry>noexec</entry>
|
|||
|
<entry>Read commands in script, but do not execute them</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>-</option></entry>
|
|||
|
<entry>(none)</entry>
|
|||
|
<entry>End of options flag. All other arguments
|
|||
|
are <link linkend="posparamref">positional
|
|||
|
parameters</link>.</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>--</option></entry>
|
|||
|
<entry>(none)</entry>
|
|||
|
<entry>Unset positional parameters.
|
|||
|
If arguments given (<varname>-- arg1 arg2</varname>),
|
|||
|
positional parameters set to arguments.</entry>
|
|||
|
</row>
|
|||
|
</tbody>
|
|||
|
</tgroup>
|
|||
|
</table>
|
|||
|
</sect1> <!-- Options -->
|
|||
|
|
|||
|
<sect1 id="gotchas">
|
|||
|
<title>Gotchas</title>
|
|||
|
|
|||
|
<epigraph>
|
|||
|
<attribution>Puccini</attribution>
|
|||
|
<para>Turandot: Gli enigmi sono tre, la morte una!</para>
|
|||
|
<para>Caleph: No, no! Gli enigmi sono tre, una la vita!</para>
|
|||
|
</epigraph>
|
|||
|
|
|||
|
<para>Assigning reserved words or characters to variable names.
|
|||
|
<programlisting>case=value0
|
|||
|
# Causes problems.
|
|||
|
23skidoo=value1
|
|||
|
# Also problems. Variable names starting with a digit are reserved by the shell.
|
|||
|
# Try _23skidoo=value1. Starting variables with an underscore is o.k.
|
|||
|
xyz((!*=value2
|
|||
|
# Causes even worse problems.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Using a hyphen or other reserved characters in a variable name.
|
|||
|
<programlisting>var-1=23
|
|||
|
# Use 'var_1' instead.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para><anchor id="wsbad">Using <link
|
|||
|
linkend="whitespaceref">whitespace</link> inappropriately
|
|||
|
(in contrast to other programming languages, Bash can be quite
|
|||
|
finicky about whitespace).
|
|||
|
|
|||
|
<programlisting>var1 = 23 # 'var1=23' is correct.
|
|||
|
# On line above, Bash attempts to execute command "var1"
|
|||
|
# with the arguments "=" and "23".
|
|||
|
|
|||
|
let c = $a - $b # 'let c=$a-$b' or 'let "c = $a - $b"' are correct.
|
|||
|
|
|||
|
if [ $a -le 5] # if [ $a -le 5 ] is correct.
|
|||
|
# if [ "$a" -le 5 ] is even better.
|
|||
|
# [[ $a -le 5 ]] also works.</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Assuming uninitialized variables (variables before a value is
|
|||
|
assigned to them) are <quote>zeroed out</quote>. An
|
|||
|
uninitialized variable has a value of <quote>null</quote>,
|
|||
|
<emphasis>not</emphasis> zero.</para>
|
|||
|
|
|||
|
<para>Mixing up <emphasis>=</emphasis> and <emphasis>-eq</emphasis> in
|
|||
|
a test. Remember, <emphasis>=</emphasis> is for comparing literal
|
|||
|
variables and <emphasis>-eq</emphasis> for integers.
|
|||
|
|
|||
|
<programlisting>if [ "$a" = 273 ] # Is $a an integer or string?
|
|||
|
if [ "$a" -eq 273 ] # If $a is an integer.
|
|||
|
|
|||
|
# Sometimes you can mix up -eq and = without adverse consequences.
|
|||
|
# However...
|
|||
|
|
|||
|
|
|||
|
a=273.0 # Not an integer.
|
|||
|
|
|||
|
if [ "$a" = 273 ]
|
|||
|
then
|
|||
|
echo "Comparison works."
|
|||
|
else
|
|||
|
echo "Comparison does not work."
|
|||
|
fi # Comparison does not work.
|
|||
|
|
|||
|
# Same with a=" 273" and a="0273".
|
|||
|
|
|||
|
|
|||
|
# Likewise, problems trying to use "-eq" with non-integer values.
|
|||
|
|
|||
|
if [ "$a" -eq 273.0 ]
|
|||
|
then
|
|||
|
echo "a = $a'
|
|||
|
fi # Aborts with an error message.
|
|||
|
# test.sh: [: 273.0: integer expression expected</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para>Sometimes variables within <quote>test</quote> brackets
|
|||
|
([ ]) need to be quoted (double quotes). Failure to do so may
|
|||
|
cause unexpected behavior. See <xref linkend="strtest">, <xref
|
|||
|
linkend="redir2">, and <xref linkend="arglist">.</para>
|
|||
|
|
|||
|
<para>Commands issued from a script may fail to execute because
|
|||
|
the script owner lacks execute permission for them. If a user
|
|||
|
cannot invoke a command from the command line, then putting it
|
|||
|
into a script will likewise fail. Try changing the attributes of
|
|||
|
the command in question, perhaps even setting the suid bit
|
|||
|
(as root, of course).</para>
|
|||
|
|
|||
|
|
|||
|
<para>Attempting to use <command>-</command> as a redirection
|
|||
|
operator (which it is not) will usually result in an unpleasant
|
|||
|
surprise.
|
|||
|
<programlisting>command1 2> - | command2 # Trying to redirect error output of command1 into a pipe...
|
|||
|
# ...will not work.
|
|||
|
|
|||
|
command1 2>& - | command2 # Also futile.
|
|||
|
|
|||
|
Thanks, S.C.</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<para>Using Bash <link linkend="bash2ref">version 2</link>
|
|||
|
functionality in a script headed with
|
|||
|
<userinput>#!/bin/bash</userinput> may cause a bailout
|
|||
|
with error messages. Older Linux machines may have version
|
|||
|
1.x of Bash as the default installation (<command>echo
|
|||
|
$BASH_VERSION</command>). Try changing the header of the script
|
|||
|
to <userinput>#!/bin/bash2</userinput>.</para>
|
|||
|
|
|||
|
<para>Using Bash-specific functionality in a Bourne shell script
|
|||
|
(<userinput>#!/bin/sh</userinput>) on a non-Linux machine
|
|||
|
may cause unexpected behavior. A Linux system usually aliases
|
|||
|
<command>sh</command> to <command>bash</command>, but this does
|
|||
|
not necessarily hold true for a generic UNIX machine.</para>
|
|||
|
|
|||
|
<para>A script with DOS-type newlines (<replaceable>\r\n</replaceable>)
|
|||
|
will fail to execute, since <userinput>#!/bin/bash\r\n</userinput>
|
|||
|
is not recognized, <emphasis>not</emphasis> the same as the
|
|||
|
expected <userinput>#!/bin/bash\n</userinput>. The fix is to
|
|||
|
convert the script to UNIX-style newlines.</para>
|
|||
|
|
|||
|
<para>A shell script headed by <userinput>#!/bin/sh</userinput>
|
|||
|
may not run in full Bash-compatibility mode. Some Bash-specific
|
|||
|
functions might be disabled. Scripts that need complete
|
|||
|
access to all the Bash-specific extensions should start with
|
|||
|
<userinput>#!/bin/bash</userinput>.</para>
|
|||
|
|
|||
|
<para>A script may not <command>export</command> variables back
|
|||
|
to its <link linkend="forkref">parent process</link>, the shell,
|
|||
|
or to the environment. Just as we learned in biology, a child
|
|||
|
process can inherit from a parent, but not vice versa.
|
|||
|
<programlisting>WHATEVER=/home/bozo
|
|||
|
export WHATEVER
|
|||
|
exit 0</programlisting>
|
|||
|
<screen><prompt>bash$ </prompt><command>echo $WHATEVER</command>
|
|||
|
<computeroutput>
|
|||
|
|
|||
|
</computeroutput>
|
|||
|
<prompt>bash$ </prompt></screen>
|
|||
|
Sure enough, back at the command prompt, $WHATEVER remains unset.
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Setting and manipulating variables in a subshell, then attempting
|
|||
|
to use those same variables outside the scope of the subshell will
|
|||
|
result an unpleasant surprise.</para>
|
|||
|
|
|||
|
<example id="subpit">
|
|||
|
<title>Subshell Pitfalls</title>
|
|||
|
<programlisting>&subpit;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Using <quote>suid</quote> commands in scripts is risky,
|
|||
|
as it may compromise system security.
|
|||
|
<footnote><para>Setting the <emphasis>suid</emphasis> permission on
|
|||
|
a script has no effect.</para></footnote>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Using shell scripts for CGI programming may be problematic. Shell
|
|||
|
script variables are not <quote>typesafe</quote>, and this can cause
|
|||
|
undesirable behavior as far as CGI is concerned. Moreover, it is
|
|||
|
difficult to <quote>hacker-proof</quote> shell scripts.</para>
|
|||
|
|
|||
|
<epigraph>
|
|||
|
<attribution>A.J. Lamb and H.W. Petrie</attribution>
|
|||
|
<para>Danger is near thee --</para>
|
|||
|
<para>Beware, beware, beware, beware.</para>
|
|||
|
<para>Many brave hearts are asleep in the deep.</para>
|
|||
|
<para>So beware --</para>
|
|||
|
<para>Beware.</para>
|
|||
|
</epigraph>
|
|||
|
|
|||
|
</sect1> <!-- Gotchas -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="scrstyle">
|
|||
|
<title>Scripting With Style</title>
|
|||
|
|
|||
|
<para>Get into the habit of writing shell scripts in a structured and
|
|||
|
systematic manner. Even <quote>on-the-fly</quote> and
|
|||
|
<quote>written on the back of an envelope</quote> scripts will
|
|||
|
benefit if you take a few minutes to plan and organize your
|
|||
|
thoughts before sitting down and coding.</para>
|
|||
|
|
|||
|
<para>Herewith are a few stylistic guidelines. This is not
|
|||
|
intended as an <emphasis>Official Shell Scripting
|
|||
|
Stylesheet</emphasis>.</para>
|
|||
|
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Comment your code. This makes it easier for others to
|
|||
|
understand (and appreciate), and easier for you to maintain.
|
|||
|
<programlisting>PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}"
|
|||
|
# It made perfect sense when you wrote it last year, but now it's a complete mystery.
|
|||
|
# (From Antek Sawicki's "pw.sh" script.)</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Add descriptive headers to your scripts and functions.
|
|||
|
<programlisting>#!/bin/bash
|
|||
|
|
|||
|
#************************************************#
|
|||
|
# xyz.sh
|
|||
|
# written by Bozo Bozeman
|
|||
|
# July 05, 2001
|
|||
|
|
|||
|
# Clean up project files.
|
|||
|
#************************************************#
|
|||
|
|
|||
|
BADDIR=65 # No such directory.
|
|||
|
projectdir=/home/bozo/projects # Directory to clean up.
|
|||
|
|
|||
|
#-------------------------------------------------------#
|
|||
|
# cleanup_pfiles ()
|
|||
|
# Removes all files in designated directory.
|
|||
|
# Parameter: $target_directory
|
|||
|
# Returns: 0 on success, $BADDIR if something went wrong.
|
|||
|
#-------------------------------------------------------#
|
|||
|
cleanup_pfiles ()
|
|||
|
{
|
|||
|
if [ ! -d "$1" ] # Test if target directory exists.
|
|||
|
then
|
|||
|
echo "$1 is not a directory."
|
|||
|
return $BADDIR
|
|||
|
fi
|
|||
|
|
|||
|
rm -f "$1"/*
|
|||
|
return 0 # Success.
|
|||
|
}
|
|||
|
|
|||
|
cleanup_pfiles $projectdir
|
|||
|
|
|||
|
exit 0</programlisting>
|
|||
|
|
|||
|
Be sure to put the <emphasis>#!/bin/bash</emphasis> at the
|
|||
|
beginning of the first line of the script, preceding any
|
|||
|
comment headers.</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>Avoid using <quote>magic numbers</quote>,
|
|||
|
|
|||
|
<footnote><para>In this context, <quote> magic
|
|||
|
numbers</quote> have an entirely different meaning than
|
|||
|
the <link linkend="magnumref">magic numbers</link> used
|
|||
|
to designate file types.</para></footnote>
|
|||
|
|
|||
|
that is, <quote>hard-wired</quote> literal constants. Use
|
|||
|
meaningful variable names instead. This makes the script
|
|||
|
easier to understand and permits making changes and updates
|
|||
|
without breaking the application.
|
|||
|
|
|||
|
<programlisting>if [ -f /var/log/messages ]
|
|||
|
then
|
|||
|
...
|
|||
|
fi
|
|||
|
# A year later, you decide to change the script to check /var/log/syslog.
|
|||
|
# It is now necessary to manually change the script, instance by instance,
|
|||
|
# and hope nothing breaks.
|
|||
|
|
|||
|
# A better way:
|
|||
|
LOGFILE=/var/log/messages # Only line that needs to be changed.
|
|||
|
if [ -f $LOGFILE ]
|
|||
|
then
|
|||
|
...
|
|||
|
fi</programlisting>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Choose descriptive names for variables.
|
|||
|
<programlisting>fl=`ls -al $dirname` # Cryptic.
|
|||
|
file_listing=`ls -al $dirname` # Better.
|
|||
|
|
|||
|
|
|||
|
MAXVAL=10 # All caps used for a script constant.
|
|||
|
while [ "$index" -le "$MAXVAL" ]
|
|||
|
...
|
|||
|
|
|||
|
|
|||
|
E_NOTFOUND=75 # Uppercase for an errorcode,
|
|||
|
# and name begins with "E_".
|
|||
|
if [ ! -e "$filename" ]
|
|||
|
then
|
|||
|
echo "File $filename not found."
|
|||
|
exit $E_NOTFOUND
|
|||
|
fi
|
|||
|
|
|||
|
|
|||
|
MAIL_DIRECTORY=/var/spool/mail/bozo # Uppercase for an environmental variable.
|
|||
|
export MAIL_DIRECTORY
|
|||
|
|
|||
|
|
|||
|
_uservariable=23 # Permissable, but not recommended.
|
|||
|
# It's better for user-defined variables not to start with an underscore.
|
|||
|
# Leave that for system variables.</programlisting>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>Use <link linkend="exitcommandref">exit codes</link>
|
|||
|
in a systematic and meaningful way.
|
|||
|
|
|||
|
<programlisting>E_WRONG_ARGS=65
|
|||
|
...
|
|||
|
...
|
|||
|
exit $E_WRONG_ARGS</programlisting>
|
|||
|
See also <xref linkend="exitcodes">.</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>Break complex scripts into simpler modules. Use functions
|
|||
|
where appropriate. See <xref linkend="ex79">.</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>Don't use a complex construct where a simpler one will do.
|
|||
|
<programlisting>COMMAND
|
|||
|
if [ $? -eq 0 ]
|
|||
|
...
|
|||
|
# Redundant and non-intuitive.
|
|||
|
|
|||
|
if COMMAND
|
|||
|
...
|
|||
|
# More concise (if perhaps not quite as legible).</programlisting>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
|
|||
|
</sect1> <!-- Scripting With Style -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="miscellany">
|
|||
|
<title>Miscellany</title>
|
|||
|
|
|||
|
<epigraph>
|
|||
|
<attribution>Tom Duff</attribution>
|
|||
|
<para>Nobody really knows what the Bourne shell's grammar is. Even
|
|||
|
examination of the source code is little help.
|
|||
|
</para>
|
|||
|
</epigraph>
|
|||
|
|
|||
|
<sect2>
|
|||
|
<title>Interactive and non-interactive shells and scripts</title>
|
|||
|
|
|||
|
<para>An <emphasis>interactive</emphasis> shell reads commands from
|
|||
|
user input on a <filename>tty</filename>. Among other things,
|
|||
|
such a shell reads startup files on activation, displays
|
|||
|
a prompt, and enables job control by default. The user can
|
|||
|
<emphasis>interact</emphasis> with the shell.</para>
|
|||
|
|
|||
|
<para>A shell running a script is always a non-interactive
|
|||
|
shell. All the same, the script can still access its
|
|||
|
<filename>tty</filename>. It is even possible to emulate an
|
|||
|
interactive shell in a script.
|
|||
|
|
|||
|
<programlisting>#!/bin/bash
|
|||
|
MY_PROMPT='$ '
|
|||
|
while :
|
|||
|
do
|
|||
|
echo -n "$MY_PROMPT"
|
|||
|
read line
|
|||
|
eval "$line"
|
|||
|
done
|
|||
|
|
|||
|
exit 0
|
|||
|
|
|||
|
# This example script, and much of the above explanation supplied by
|
|||
|
# Stephane Chazelas (thanks again).</programlisting></para>
|
|||
|
|
|||
|
<para>Let us consider an <emphasis>interactive</emphasis> script
|
|||
|
to be one that requires input from the user, usually with
|
|||
|
<link linkend="readref">read</link> statements (see <xref
|
|||
|
linkend="ex36">). <quote>Real life</quote> is actually a
|
|||
|
bit messier than that. For now, assume an interactive script
|
|||
|
is bound to a tty, a script that a user has invoked from the
|
|||
|
console or an xterm.</para>
|
|||
|
|
|||
|
<para>Init and startup scripts are necessarily non-interactive,
|
|||
|
since they must run without human intervention. Many
|
|||
|
administrative and system maintenance scripts are likewise
|
|||
|
non-interactive. Unvarying repetitive tasks cry out for
|
|||
|
automation by non-interactive scripts.</para>
|
|||
|
|
|||
|
<para>Non-interactive scripts can run in the background, but
|
|||
|
interactive ones hang, waiting for input that never comes.
|
|||
|
Handle that difficulty by having an <command>expect</command>
|
|||
|
script or embedded <link linkend="heredocref">here
|
|||
|
document</link> feed input to an interactive script running
|
|||
|
as a background job. In the simplest case, redirect a
|
|||
|
file to supply input to a <command>read</command> statement
|
|||
|
(<command>read variable <file</command>). These particular
|
|||
|
workarounds make possible general purpose scripts that run
|
|||
|
in either interactive or non-interactive modes.</para>
|
|||
|
|
|||
|
<para>If a script needs to test whether it is running in an
|
|||
|
interactive shell, it is simply a matter of finding
|
|||
|
whether the <emphasis>prompt</emphasis> variable, <link
|
|||
|
linkend="ps1ref">$PS1</link> is set. (If the user is being
|
|||
|
prompted for input, then the script needs to display a prompt.)
|
|||
|
|
|||
|
<programlisting>if [ -z $PS1 ] # no prompt?
|
|||
|
then
|
|||
|
# non-interactive
|
|||
|
...
|
|||
|
else
|
|||
|
# interactive
|
|||
|
...
|
|||
|
fi</programlisting>
|
|||
|
|
|||
|
<anchor id="iitest">Alternatively, the script can test
|
|||
|
for the presence of option <quote>i</quote> in the <link
|
|||
|
linkend="flpref">$-</link> flag.
|
|||
|
|
|||
|
<programlisting>case $- in
|
|||
|
*i*) # interactive shell
|
|||
|
;;
|
|||
|
*) # non-interactive shell
|
|||
|
;;
|
|||
|
# (Thanks to "UNIX F.A.Q.", 1993)</programlisting></para>
|
|||
|
|
|||
|
|
|||
|
<note><para>Scripts may be forced to run in interactive
|
|||
|
mode with the <token>-i</token> option or with a
|
|||
|
<emphasis>#!/bin/bash -i</emphasis> header. Be aware that this
|
|||
|
can cause erratic script behavior or show error messages even
|
|||
|
when no error is present.</para></note>
|
|||
|
|
|||
|
|
|||
|
</sect2> <!-- Interactive and non-interactive scripts -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect2>
|
|||
|
<title>Tests and Comparisons</title>
|
|||
|
|
|||
|
<para>For tests, the <link linkend="dblbrackets">[[ ]]</link>
|
|||
|
construct may be more appropriate than <userinput>[
|
|||
|
]</userinput>. Likewise, arithmetic comparisons might benefit
|
|||
|
from the <link linkend="dblparens">(( ))</link> construct.
|
|||
|
|
|||
|
<programlisting>a=8
|
|||
|
|
|||
|
# All of the comparisons below are equivalent.
|
|||
|
test "$a" -lt 16 && echo "yes, $a < 16" # "and list"
|
|||
|
/bin/test "$a" -lt 16 && echo "yes, $a < 16"
|
|||
|
[ "$a" -lt 16 ] && echo "yes, $a < 16"
|
|||
|
[[ $a -lt 16 ]] && echo "yes, $a < 16" # Quoting variables within
|
|||
|
(( a < 16 )) && echo "yes, $a < 16" # [[ ]] and (( )) not necessary.
|
|||
|
|
|||
|
city="New York"
|
|||
|
# Again, all of the comparisons below are equivalent.
|
|||
|
test "$city" \< Paris && echo "Yes, Paris is greater than $city" # Greater ASCII order.
|
|||
|
/bin/test "$city" \< Paris && echo "Yes, Paris is greater than $city"
|
|||
|
[ "$city" \< Paris ] && echo "Yes, Paris is greater than $city"
|
|||
|
[[ $city < Paris ]] && echo "Yes, Paris is greater than $city" # Need not quote $city.
|
|||
|
|
|||
|
# Thank you, S.C.</programlisting></para>
|
|||
|
|
|||
|
</sect2> <!-- Tests and Comparisons -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect2>
|
|||
|
<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. 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 awk or Perl.</para>
|
|||
|
|
|||
|
<para>Try to write your scripts in a structured, coherent form, so
|
|||
|
they can be reorganized and tightened up as necessary. Some of the
|
|||
|
optimization techniques applicable to high-level languages may work
|
|||
|
for scripts, but others, such as loop unrolling, are mostly
|
|||
|
irrelevant. Above all, use common sense.</para>
|
|||
|
|
|||
|
</sect2> <!-- Optimizations -->
|
|||
|
|
|||
|
|
|||
|
<sect2>
|
|||
|
<title>Assorted Tips</title>
|
|||
|
|
|||
|
<itemizedlist>
|
|||
|
|
|||
|
<listitem>
|
|||
|
|
|||
|
<para>To keep a record of which user scripts have run
|
|||
|
during a particular sesssion or over a number of sessions,
|
|||
|
add the following lines to each script you want to keep track
|
|||
|
of. This will keep a continuing file record of the script
|
|||
|
names and invocation times. </para>
|
|||
|
|
|||
|
<para>
|
|||
|
<programlisting># Append (>>) following to end of each script tracked.
|
|||
|
|
|||
|
date>> $SAVE_FILE #Date and time.
|
|||
|
echo $0>> $SAVE_FILE #Script name.
|
|||
|
echo>> $SAVE_FILE #Blank line as separator.
|
|||
|
|
|||
|
# Of course, SAVE_FILE defined and exported as environmental variable in ~/.bashrc
|
|||
|
# (something like ~/.scripts-run)</programlisting>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>A shell script may act as an embedded command inside
|
|||
|
another shell script, a <emphasis>Tcl</emphasis> or
|
|||
|
<emphasis>wish</emphasis> script, or even a Makefile. It can
|
|||
|
be invoked as as an external shell command in a C program
|
|||
|
using the <replaceable>system()</replaceable> call, i.e.,
|
|||
|
<replaceable>system("script_name");</replaceable>.</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>Put together a file of your favorite and most useful
|
|||
|
definitions and functions, then <quote>include</quote>
|
|||
|
this file in scripts as necessary with either the <link
|
|||
|
linkend="dotref">dot</link> (<command>.</command>) or <link
|
|||
|
linkend="sourceref">source</link> command.</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>Using the double parentheses construct, it is possible
|
|||
|
to use C-like syntax for setting and incrementing variables
|
|||
|
and in <link linkend="forloopref">for</link> and <link
|
|||
|
linkend="whileloopref">while</link> loops. See <xref
|
|||
|
linkend="forloopc"> and <xref linkend="whloopc">.</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
<listitem>
|
|||
|
<para>It would be nice to be able to invoke X-Windows widgets
|
|||
|
from a shell script. There happen to exist
|
|||
|
several packages that purport to do so, namely
|
|||
|
<emphasis>Xscript</emphasis>, <emphasis>Xmenu</emphasis>,
|
|||
|
and <emphasis>widtools</emphasis>. The first two of
|
|||
|
these no longer seem to be maintained. Fortunately, it is
|
|||
|
still possible to obtain <emphasis>widtools</emphasis> <ulink
|
|||
|
url="http://www.batse.msfc.nasa.gov/~mallozzi/home/software/xforms/src/widtools-2.0.tgz">here</ulink>.
|
|||
|
</para>
|
|||
|
|
|||
|
<caution><para>The <emphasis>widtools</emphasis> (widget tools)
|
|||
|
package requires the <emphasis>XForms</emphasis> library to
|
|||
|
be installed. Additionally, the <filename>Makefile</filename>
|
|||
|
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>For more effective scripting with widgets, try
|
|||
|
<emphasis>Tk</emphasis> or <emphasis>wish</emphasis>
|
|||
|
(<emphasis>Tcl</emphasis> derivatives),
|
|||
|
<emphasis>PerlTk</emphasis> (Perl with Tk extensions),
|
|||
|
<emphasis>tksh</emphasis> (ksh with Tk extensions),
|
|||
|
<emphasis>XForms4Perl</emphasis> (Perl with XForms
|
|||
|
extensions), <emphasis>Gtk-Perl</emphasis> (Perl with Gtk
|
|||
|
extensions), or <emphasis>PyQt</emphasis> (Python with
|
|||
|
Qt extensions).</para>
|
|||
|
|
|||
|
</listitem>
|
|||
|
|
|||
|
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
</sect2> <!-- Assorted Tips -->
|
|||
|
|
|||
|
</sect1> <!-- miscellany -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<sect1 id="bash2">
|
|||
|
<title>Bash, version 2</title>
|
|||
|
|
|||
|
<para><anchor id="bash2ref"></para>
|
|||
|
|
|||
|
<para>The current version of <emphasis>Bash</emphasis>, the one
|
|||
|
you have running on your machine, is actually version 2. This
|
|||
|
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>
|
|||
|
|
|||
|
<example id="ex78">
|
|||
|
<title>Indirect variable references - the new way</title>
|
|||
|
<programlisting>&ex78;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ex79">
|
|||
|
<title>Using arrays and other miscellaneous trickery
|
|||
|
to deal four random hands from a deck of cards</title>
|
|||
|
<programlisting>&ex79;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</sect1> <!-- Bash, version 2 -->
|
|||
|
</chapter> <!-- Tutorial / Reference -->
|
|||
|
|
|||
|
|
|||
|
<chapter id="credits">
|
|||
|
<title>Credits</title>
|
|||
|
|
|||
|
<para><ulink url="mailto:feloy@free.fr">Philippe Martin</ulink>
|
|||
|
translated this document into DocBook/SGML. While not on
|
|||
|
the job at a small French company as a software developer,
|
|||
|
he enjoys working on GNU/Linux documentation and software,
|
|||
|
reading literature, playing music, and for his peace of mind
|
|||
|
making merry with friends. You may run across him somewhere
|
|||
|
in France or in the Basque Country, or email him at <ulink
|
|||
|
url="mailto:feloy@free.fr">feloy@free.fr</ulink>.</para>
|
|||
|
|
|||
|
<para>Philippe Martin also pointed out that positional parameters
|
|||
|
past $9 are possible using {bracket} notation, see <xref
|
|||
|
linkend="ex17">.</para>
|
|||
|
|
|||
|
<para><ulink url="mailto:stephane_chazelas@yahoo.fr">Stephane
|
|||
|
Chazelas</ulink> sent a long list of corrections, additions, and
|
|||
|
example scripts. More than a contributor, he has, in effect, taken
|
|||
|
on the role of <command>editor</command> for this document. Merci
|
|||
|
beaucoup !</para>
|
|||
|
|
|||
|
<para>I would like to especially thank <emphasis>Patrick
|
|||
|
Callahan</emphasis>, <emphasis>Mike Novak</emphasis>, and
|
|||
|
<emphasis>Pal Domokos</emphasis> for catching bugs, pointing out
|
|||
|
ambiguities, and for suggesting clarifications and changes.
|
|||
|
Their lively discussion of shell scripting and general
|
|||
|
documentation issues inspired me to try to make this document
|
|||
|
more readable.</para>
|
|||
|
|
|||
|
<para>I'm grateful to Jim Van Zandt for pointing out errors and
|
|||
|
omissions in version 0.2 of this document. He also contributed
|
|||
|
an instructive example script.</para>
|
|||
|
|
|||
|
<para>Many thanks to <ulink
|
|||
|
url="mailto:mikaku@arrakis.es">Jordi Sanfeliu</ulink>
|
|||
|
for giving permission to use his fine tree script (<xref
|
|||
|
linkend="tree">).</para>
|
|||
|
|
|||
|
<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>Emmanuel Rouat suggested corrections and additions on
|
|||
|
<link linkend="commandsubref">command substitution</link> and
|
|||
|
<link linkend="aliasref">aliases</link>. He also contributed
|
|||
|
a very nice sample <filename>.bashrc</filename> file (<xref
|
|||
|
linkend="sample-bashrc">).</para>
|
|||
|
|
|||
|
<para><ulink url="mailto:heiner.steven@odn.de">Heiner Steven</ulink>
|
|||
|
kindly gave permission to use his base conversion script, <xref
|
|||
|
linkend="base">. He also made a number of corrections and many
|
|||
|
helpful suggestions. Special thanks.</para>
|
|||
|
|
|||
|
<para>Florian Wisser enlightened me on some of the fine points of
|
|||
|
testing strings (see <xref linkend="strtest">), and on other
|
|||
|
matters.</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>Others making helpful suggestions and pointing out errors
|
|||
|
were Gabor Kiss, Leopold Toetsch, and Nick Drage (script
|
|||
|
ideas!).</para>
|
|||
|
|
|||
|
<para>My gratitude to <ulink url="mailto:chet@po.cwru.edu">Chet
|
|||
|
Ramey</ulink> for writing <command>Bash</command>, an elegant
|
|||
|
and powerful scripting tool.</para>
|
|||
|
|
|||
|
<para>Thanks most of all to my wife, Anita, for her encouragement and
|
|||
|
emotional support.</para>
|
|||
|
|
|||
|
</chapter> <!-- Credits -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<chapter id="endnotes">
|
|||
|
<title>End Notes</title>
|
|||
|
|
|||
|
|
|||
|
<sect1 id="authorsnote">
|
|||
|
<title>Author's Note</title>
|
|||
|
|
|||
|
|
|||
|
<para>How did I come to write a Bash scripting book? It's a strange
|
|||
|
tale. It seems that a couple of years back, I needed to learn
|
|||
|
shell scripting, and what better way to do that than to read
|
|||
|
a good book on the subject. I was looking to buy a tutorial
|
|||
|
and reference covering all aspects of scripting. In fact,
|
|||
|
I was looking for this very book, or something much like
|
|||
|
it. Unfortunately, it didn't exist, so if I wanted it, I had to
|
|||
|
write it. And so, here we are, folks.</para>
|
|||
|
|
|||
|
<para>This reminds me of the apocryphal story about the mad
|
|||
|
professor. Crazy as a loon, the fellow was. At the sight of a
|
|||
|
book, any book, at the library, at a bookstore, anywhere, he
|
|||
|
would become totally obsessed with the idea that he could have
|
|||
|
written it, should have written it, and done a better job of it to
|
|||
|
boot. He would thereupon rush home and proceed to do just that,
|
|||
|
write a book with the 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 driven by it, and I can't
|
|||
|
help admiring the old coot...</para>
|
|||
|
|
|||
|
</sect1> <!-- Author's Note -->
|
|||
|
|
|||
|
<sect1 id="toolsused">
|
|||
|
<title>Tools Used to Produce This Book</title>
|
|||
|
|
|||
|
<orderedlist 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://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><emphasis>DocBook, The Definitive Guide</emphasis>, by Norman
|
|||
|
Walsh and Leonard Muellner (O'Reilly, ISBN 1-56592-580-7). This is
|
|||
|
the standard reference for anyone attempting to write a document in
|
|||
|
Docbook SGML format.</para>
|
|||
|
</listitem>
|
|||
|
|
|||
|
</orderedlist>
|
|||
|
|
|||
|
</sect1> <!-- Tools Used -->
|
|||
|
|
|||
|
|
|||
|
</chapter> <!-- End Notes -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<bibliography id="biblio">
|
|||
|
<anchor id="biblioref">
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Dale</firstname><surname>Dougherty</surname></author>
|
|||
|
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Sed and Awk</title>
|
|||
|
<edition>2nd edition</edition>
|
|||
|
<publisher>
|
|||
|
<publishername>O'Reilly and Associates</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1997</year>
|
|||
|
</copyright>
|
|||
|
<isbn>1-156592-225-5</isbn>
|
|||
|
<abstract><para>
|
|||
|
To unfold the full power of shell scripting, you need at least a passing
|
|||
|
familiarity with <command>sed</command> and
|
|||
|
<command>awk</command>. This is the standard tutorial. It
|
|||
|
includes an excellent introduction to <quote>regular expressions</quote>. Read this
|
|||
|
book.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Aeleen</firstname><surname>Frisch</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Essential System Administration</title>
|
|||
|
<edition>2nd edition</edition>
|
|||
|
<publisher>
|
|||
|
<publishername>O'Reilly and Associates</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1995</year>
|
|||
|
</copyright>
|
|||
|
<isbn>1-56592-127-5</isbn>
|
|||
|
<abstract><para>This excellent sys admin manual has a decent introduction to shell
|
|||
|
scripting for sys administrators and does a nice job of explaining the
|
|||
|
startup and initialization scripts. The book is long overdue for a third
|
|||
|
edition (are you listening, Tim O'Reilly?).</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Stephen</firstname><surname>Kochan</surname></author>
|
|||
|
<author><firstname>Patrick</firstname><surname>Woods</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Unix Shell Programming</title>
|
|||
|
<publisher>
|
|||
|
<publishername>Hayden</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1990</year>
|
|||
|
</copyright>
|
|||
|
<isbn>067248448X</isbn>
|
|||
|
<abstract><para>The standard reference, though a bit dated by now.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Neil</firstname><surname>Matthew</surname></author>
|
|||
|
<author><firstname>Richard</firstname><surname>Stones</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Beginning Linux Programming</title>
|
|||
|
<publisher>
|
|||
|
<publishername>Wrox Press</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1996</year>
|
|||
|
</copyright>
|
|||
|
<isbn>1874416680</isbn>
|
|||
|
<abstract><para>Good in-depth coverage of various programming
|
|||
|
languages available for Linux, including a fairly strong chapter
|
|||
|
on shell scripting.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Herbert</firstname><surname>Mayer</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Advanced C Programming on the IBM PC</title>
|
|||
|
<publisher>
|
|||
|
<publishername>Windcrest Books</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1989</year>
|
|||
|
</copyright>
|
|||
|
<isbn>0830693637</isbn>
|
|||
|
<abstract><para>Excellent coverage of algorithms and general
|
|||
|
programming practices.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>David</firstname><surname>Medinets</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Unix Shell Programming Tools</title>
|
|||
|
<publisher>
|
|||
|
<publishername>McGraw-Hill</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1999</year>
|
|||
|
</copyright>
|
|||
|
<isbn>0070397333</isbn>
|
|||
|
<abstract><para>Good info on shell scripting, with examples, and a short
|
|||
|
intro to Tcl and Perl.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Cameron</firstname><surname>Newham</surname></author>
|
|||
|
<author><firstname>Bill</firstname><surname>Rosenblatt</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Learning the Bash Shell</title>
|
|||
|
<edition>2nd edition</edition>
|
|||
|
<publisher>
|
|||
|
<publishername>O'Reilly and Associates</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1998</year>
|
|||
|
</copyright>
|
|||
|
<isbn>1-56592-347-2</isbn>
|
|||
|
<abstract><para>This is a valiant effort at a decent shell primer, but somewhat deficient
|
|||
|
in coverage on programming topics and lacking sufficient examples.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Anatole</firstname><surname>Olczak</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Bourne Shell Quick Reference Guide</title>
|
|||
|
<publisher>
|
|||
|
<publishername>ASP, Inc.</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1991</year>
|
|||
|
</copyright>
|
|||
|
<isbn>093573922X</isbn>
|
|||
|
<abstract><para>A very handy pocket reference, despite lacking
|
|||
|
coverage of Bash-specific features.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Jerry</firstname><surname>Peek</surname></author>
|
|||
|
<author><firstname>Tim</firstname><surname>O'Reilly</surname></author>
|
|||
|
<author><firstname>Mike</firstname><surname>Loukides</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Unix Power Tools</title>
|
|||
|
<edition>2nd edition</edition>
|
|||
|
<publisher>
|
|||
|
<publishername>O'Reilly and Associates</publishername>
|
|||
|
</publisher>
|
|||
|
<publisher>
|
|||
|
<publishername>Random House</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1997</year>
|
|||
|
</copyright>
|
|||
|
<isbn>1-56592-260-3</isbn>
|
|||
|
<abstract><para>Contains a couple of sections of very informative
|
|||
|
in-depth articles on shell programming, but falls short of being
|
|||
|
a tutorial. It reproduces much of the regular expressions tutorial
|
|||
|
from the Dougherty and Robbins book, above.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Arnold</firstname><surname>Robbins</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Bash Reference Card</title>
|
|||
|
<publisher>
|
|||
|
<publishername>SSC</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1998</year>
|
|||
|
</copyright>
|
|||
|
<isbn>1-58731-010-5</isbn>
|
|||
|
<abstract>
|
|||
|
<para>Excellent Bash pocket reference (don't leave home
|
|||
|
without it). A bargain at $4.95, but
|
|||
|
also available for free download <ulink
|
|||
|
url="http://www.ssc.com/ssc/bash/">on-line</ulink> in pdf
|
|||
|
format.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<authorgroup>
|
|||
|
<author><firstname>Ellen</firstname><surname>Siever</surname></author>
|
|||
|
<author><surname>and the Staff of O'Reilly and Associates</surname></author>
|
|||
|
</authorgroup>
|
|||
|
<title>Linux in a Nutshell</title>
|
|||
|
<edition>2nd edition</edition>
|
|||
|
<publisher>
|
|||
|
<publishername>O'Reilly and Associates</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>1999</year>
|
|||
|
</copyright>
|
|||
|
<isbn>1-56592-585-8</isbn>
|
|||
|
<abstract><para>The all-around best Linux command reference, even has a Bash section.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<title>The UNIX CD Bookshelf</title>
|
|||
|
<edition>2nd edition</edition>
|
|||
|
<publisher>
|
|||
|
<publishername>O'Reilly and Associates</publishername>
|
|||
|
</publisher>
|
|||
|
<copyright>
|
|||
|
<year>2000</year>
|
|||
|
</copyright>
|
|||
|
<isbn>1-56592-815-6</isbn>
|
|||
|
<abstract><para>An array of six UNIX books on CD ROM, including
|
|||
|
<emphasis>UNIX Power Tools</emphasis>, <emphasis>Sed
|
|||
|
and Awk</emphasis>, and <emphasis>Learning the Korn
|
|||
|
Shell</emphasis>. A complete set of all the UNIX references
|
|||
|
and tutorials you would ever need at about $70. Buy this one,
|
|||
|
even if it means going into debt and not paying the rent.</para>
|
|||
|
<para>Unfortunately, out of print at present.</para>
|
|||
|
<para>*</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>The O'Reilly books on Perl. (Actually, any O'Reilly books.)</para>
|
|||
|
<para>-----------------------------------------------------------------------</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Ben Okopnik's well-written <emphasis>introductory Bash
|
|||
|
scripting</emphasis> articles in issues 53, 54, 55, 57, and 59
|
|||
|
of the <ulink url="http://www.linuxgazette.com">Linux Gazette
|
|||
|
</ulink>, and his explanation of <quote>The Deep, Dark Secrets
|
|||
|
of Bash</quote> in issue 56.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract><para>Chet Ramey's <emphasis>bash - The GNU Shell</emphasis>,
|
|||
|
a two-part series published in issues 3 and 4 of the <ulink
|
|||
|
url="http://www.linuxjournal.com">Linux Journal</ulink>,
|
|||
|
July-August 1994.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Mike G's <ulink
|
|||
|
url="http://www.linuxdoc.org/HOWTO/Bash-Prog-Intro-HOWTO.html">Bash-Programming-Intro
|
|||
|
HOWTO</ulink>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Richard's <ulink url="http://www.injunea.demon.co.uk/index.htm">UNIX
|
|||
|
Scripting Universe</ulink>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Chet Ramey's <ulink
|
|||
|
url="ftp://ftp.cwru.edu/pub/bash/FAQ">Bash F.A.Q.</ulink></para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Example shell scripts at <ulink
|
|||
|
url="http://alge.anart.no/linux/scripts/">Lucc's Shell Scripts
|
|||
|
</ulink>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Example shell scripts at <ulink
|
|||
|
url="http://www.oase-shareware.org/shell/scripts">SHELLdorado
|
|||
|
</ulink>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Example shell scripts at <ulink
|
|||
|
url="http://clri6f.gsi.de/gnu/bash-2.01/examples/scripts.noah/">Noah
|
|||
|
Friedman's script site</ulink>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Example shell scripts at <ulink
|
|||
|
url="http://sourceforge.net/snippet/browse.php?by=lang&lang=7">
|
|||
|
SourceForge Snippet Library - shell scrips</ulink>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Giles Orr's <ulink
|
|||
|
url="http://www.linuxdoc.org/HOWTO/Bash-Prompt-HOWTO.html">Bash-Prompt
|
|||
|
HOWTO</ulink>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>The <ulink
|
|||
|
url="http://www.cornerstonemag.com/sed/sedfaq.html">sed
|
|||
|
F.A.Q.</ulink></para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Carlos Duarte's instructive <ulink
|
|||
|
url="http://www.dbnet.ece.ntua.gr/~george/sed/sedtut_1.html"><quote>Do
|
|||
|
It With Sed</quote></ulink> tutorial.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>The GNU <command>gawk</command> <ulink
|
|||
|
url="http://sunsite.ualberta.ca/Documentation/Gnu/gawk-3.0.6/gawk.html">
|
|||
|
reference manual</ulink> (<command>gawk</command> is the extended
|
|||
|
GNU version of <command>awk</command> available on Linux and
|
|||
|
BSD systems).</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Trent Fisher's <ulink
|
|||
|
url="http://www.cs.pdx.edu/~trent/gnu/groff/groff.html">groff
|
|||
|
tutorial</ulink>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>Mark Komarinski's <ulink
|
|||
|
url="http://www.linuxdoc.org/HOWTO/Printing-Usage-HOWTO.html">Printing-Usage
|
|||
|
HOWTO</ulink>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>There is some nice material on I/O redirection (<xref
|
|||
|
linkend="io-redirection">) 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>Rick Hohensee has written a virtual machine plus assembler,
|
|||
|
entirely as shell scripts. See his <ulink
|
|||
|
url="http://linux01.gwdg.de/~rhohen/H3sm.html">H3sm site</ulink>
|
|||
|
or <ulink url="ftp://linux01.gwdg.de/pub/linux/clienux/interim">ftp
|
|||
|
site</ulink>.</para>
|
|||
|
<para>-------------------------------------------------------------------------</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>The excellent "Bash Reference Manual", by Chet Ramey and Brian Fox,
|
|||
|
distributed as part of the "bash-2-doc" package (available as an rpm).
|
|||
|
See especially the instructive example scripts in this package.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
<biblioentry>
|
|||
|
<abstract>
|
|||
|
<para>The man pages for <command>bash</command> and
|
|||
|
<command>bash2</command>, <command>date</command>,
|
|||
|
<command>expect</command>, <command>expr</command>,
|
|||
|
<command>find</command>, <command>grep</command>,
|
|||
|
<command>gzip</command>, <command>ln</command>,
|
|||
|
<command>patch</command>, <command>tar</command>,
|
|||
|
<command>tr</command>, <command>bc</command>,
|
|||
|
<command>xargs</command>. The texinfo documentation
|
|||
|
on <command>bash</command>, <command>dd</command>,
|
|||
|
<command>gawk</command>, and <command>sed</command>.</para>
|
|||
|
</abstract>
|
|||
|
</biblioentry>
|
|||
|
|
|||
|
|
|||
|
</bibliography>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<appendix id="contributed-scripts">
|
|||
|
<title>Contributed Scripts</title>
|
|||
|
|
|||
|
<para>These scripts, while not fitting into the text of this document, do
|
|||
|
illustrate some interesting shell programming techniques. They are useful,
|
|||
|
too. Have fun analyzing and running them.</para>
|
|||
|
|
|||
|
<example id="manview">
|
|||
|
<title><command>manview</command>: A script for viewing formatted man pages
|
|||
|
</title>
|
|||
|
<programlisting>&manview;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="mailformat">
|
|||
|
<title><command>mailformat</command>: Formatting an e-mail message</title>
|
|||
|
<programlisting>&mailformat;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="rn">
|
|||
|
<title><command>rn</command>: A simple-minded file rename utility</title>
|
|||
|
<para>This script is a modification of <xref
|
|||
|
linkend="lowercase">.</para>
|
|||
|
<programlisting>&rn;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="encryptedpw">
|
|||
|
<title><command>encryptedpw</command>: A script for uploading to an ftp site,
|
|||
|
using a locally encrypted password</title>
|
|||
|
<programlisting>&encryptedpw;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="copycd">
|
|||
|
<title><command>copy-cd</command>: A script for copying a data CD</title>
|
|||
|
<programlisting>©cd;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>+</para>
|
|||
|
|
|||
|
<para>The following two scripts are by Mark Moraes of the University
|
|||
|
of Toronto. See the enclosed file <quote>Moraes-COPYRIGHT</quote>
|
|||
|
for permissions and restrictions.</para>
|
|||
|
|
|||
|
<example id="behead">
|
|||
|
<title><command>behead</command>: A script for removing mail and news message headers
|
|||
|
</title>
|
|||
|
<programlisting>&behead;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<example id="ftpget">
|
|||
|
<title><command>ftpget</command>: A script for downloading files via ftp
|
|||
|
</title>
|
|||
|
<programlisting>&ftpget;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>+</para>
|
|||
|
|
|||
|
<para>Antek Sawicki contributed the following script, which makes very
|
|||
|
clever use of the parameter substitution operators discussed in
|
|||
|
<xref linkend="Parameter-Substitution">.</para>
|
|||
|
|
|||
|
<example id="pw">
|
|||
|
<title><command>password</command>: A script for generating random
|
|||
|
8-character passwords</title>
|
|||
|
<programlisting>&pw;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>+</para>
|
|||
|
|
|||
|
<para>James R. Van Zandt contributed this script, which uses named pipes
|
|||
|
and, in his words, <quote>really exercises quoting and escaping</quote>.
|
|||
|
</para>
|
|||
|
|
|||
|
<example id="fifo">
|
|||
|
<title><command>fifo</command>: A script for making daily backups, using
|
|||
|
named pipes</title>
|
|||
|
<programlisting>&fifo;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>+</para>
|
|||
|
|
|||
|
<para>Stephane Chazelas contributed the following script to
|
|||
|
demonstrate that generating prime numbers does not require
|
|||
|
arrays.</para>
|
|||
|
|
|||
|
<example id="primes">
|
|||
|
<title>Generating prime numbers using the modulo operator</title>
|
|||
|
<programlisting>ℙ</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>+</para>
|
|||
|
|
|||
|
<para>Jordi Sanfeliu gave permission to use his elegant
|
|||
|
<emphasis>tree</emphasis> script.</para>
|
|||
|
|
|||
|
<example id="tree">
|
|||
|
<title><command>tree</command>: A script for displaying a directory
|
|||
|
tree</title>
|
|||
|
<programlisting>&tree;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Noah Friedman gave permission to use his <emphasis>string
|
|||
|
function</emphasis> script, which essentially reproduces some of the
|
|||
|
C-library string manipulation functions.</para>
|
|||
|
|
|||
|
<example id="string">
|
|||
|
<title><command>string functions</command>: C-like string functions</title>
|
|||
|
<programlisting>&string;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>Stephane Chazelas demonstrates object-oriented programming a
|
|||
|
Bash script.</para>
|
|||
|
|
|||
|
<example id="objoriented">
|
|||
|
<title>Object-oriented database</title>
|
|||
|
<programlisting>&objoriented;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</appendix>
|
|||
|
<!-- End Contributed Scripts appendix -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<appendix id="sedawk">
|
|||
|
<title>A Sed and Awk Micro-Primer</title>
|
|||
|
|
|||
|
<para><anchor id="sedref"></para>
|
|||
|
|
|||
|
<para>This is a very brief introduction to the <command>sed</command>
|
|||
|
and <command>awk</command> text processing utilities. We will
|
|||
|
deal with only a few basic commands here, but that will suffice
|
|||
|
for understanding simple sed and awk constructs within shell
|
|||
|
scripts.</para>
|
|||
|
|
|||
|
|
|||
|
<para><command>sed</command>: a non-interactive text file editor</para>
|
|||
|
|
|||
|
<para><command>awk</command>: a field-oriented pattern processing
|
|||
|
language with a C-like syntax</para>
|
|||
|
|
|||
|
<para>For all their differences, the two utilities share a similar
|
|||
|
invocation syntax, both use <link linkend="regexref">regular
|
|||
|
expressions </link>, both read input by default
|
|||
|
from <filename>stdin</filename>, and both output to
|
|||
|
<filename>stdout</filename>. These are well-behaved UNIX tools,
|
|||
|
and they work together well. The output from one can be piped
|
|||
|
into the other, and their combined capabilities give shell
|
|||
|
scripts some of the power of Perl.</para>
|
|||
|
|
|||
|
<note><para>One important difference between the utilities is
|
|||
|
that while shell scripts can easily pass arguments to sed, it
|
|||
|
is more complicated for awk (see <xref linkend="coltotaler">
|
|||
|
and <xref linkend="coltotaler2">).
|
|||
|
</para></note>
|
|||
|
|
|||
|
<sect1>
|
|||
|
<title>Sed</title>
|
|||
|
|
|||
|
<para>Sed is a non-interactive line editor. It receives text
|
|||
|
input, whether from <filename>stdin</filename> or from a
|
|||
|
file, performs certain operations on specified lines of
|
|||
|
the input, one line at a time, then outputs the result to
|
|||
|
<filename>stdout</filename> or to a file. Within a shell script,
|
|||
|
sed is usually one of several tool components in a pipe.</para>
|
|||
|
|
|||
|
<para>Sed determines which lines of its input that it will
|
|||
|
operate on from the <emphasis>address range</emphasis> passed
|
|||
|
to it.
|
|||
|
<footnote><para>If no address range is specified, the default
|
|||
|
is <emphasis>all</emphasis> lines.</para></footnote>
|
|||
|
Specify this address range either by line number or by a
|
|||
|
pattern to match. For example, <replaceable>3d</replaceable>
|
|||
|
signals sed to delete line 3 of the input, and
|
|||
|
<replaceable>/windows/d</replaceable> tells sed that
|
|||
|
you want every line of the input containing a match to
|
|||
|
<quote>windows</quote> deleted.</para>
|
|||
|
|
|||
|
<para>Of all the operations in the sed toolkit, we will focus
|
|||
|
primarily on the three most commonly used
|
|||
|
ones. These are <command>p</command>rinting (to
|
|||
|
<filename>stdout</filename>), <command>d</command>eletion,
|
|||
|
and <command>s</command>ubstitution.</para>
|
|||
|
|
|||
|
|
|||
|
<table>
|
|||
|
<title>Basic sed operators</title>
|
|||
|
<tgroup cols="3">
|
|||
|
<thead>
|
|||
|
<row>
|
|||
|
<entry>Operator</entry>
|
|||
|
<entry>Name</entry>
|
|||
|
<entry>Effect</entry>
|
|||
|
</row>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<row>
|
|||
|
<entry><option>[address-range]/p</option></entry>
|
|||
|
<entry>print</entry>
|
|||
|
<entry>Print [specified address range]</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>[address-range]/d</option></entry>
|
|||
|
<entry>delete</entry>
|
|||
|
<entry>Delete [specified address range]</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>s/pattern1/pattern2/</option></entry>
|
|||
|
<entry>substitute</entry>
|
|||
|
<entry>Substitute pattern2 for first instance of pattern1 in a line</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>[address-range]/s/pattern1/pattern2/</option></entry>
|
|||
|
<entry>substitute</entry>
|
|||
|
<entry>Substitute pattern2 for first instance of pattern1 in a
|
|||
|
line, over <replaceable>address-range</replaceable></entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>[address-range]/y/pattern1/pattern2/</option></entry>
|
|||
|
<entry>transform</entry>
|
|||
|
<entry>replace any character in pattern1 with the
|
|||
|
corresponding character in pattern2, over
|
|||
|
<replaceable>address-range</replaceable> (equivalent of
|
|||
|
<command>tr</command>)</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>g</option></entry>
|
|||
|
<entry>global</entry>
|
|||
|
<entry>Operate on <emphasis>every</emphasis> pattern match
|
|||
|
within each matched line of input</entry>
|
|||
|
</row>
|
|||
|
</tbody>
|
|||
|
</tgroup>
|
|||
|
</table>
|
|||
|
|
|||
|
<note><para>Unless the <option>g</option>
|
|||
|
(<emphasis>global</emphasis>) operator is appended to a
|
|||
|
<emphasis>substitute</emphasis> command, the substitution
|
|||
|
operates only on the first instance of a pattern match within
|
|||
|
each line.</para></note>
|
|||
|
|
|||
|
<para>From the command line and in a shell script, a sed operation may
|
|||
|
require quoting and certain options.</para>
|
|||
|
|
|||
|
<para><programlisting>sed -e '/^$/d'
|
|||
|
# 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.)
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
<note><para>Both sed and awk use the <option>-e</option> option
|
|||
|
to specify that the following string is an instruction or set
|
|||
|
of instructions. If there is only a single instruction contained
|
|||
|
in the string, then this option may be omitted.</para></note>
|
|||
|
|
|||
|
<para><programlisting>sed -n '/xzy/p'
|
|||
|
# The -n option tells sed to print only those lines matching the pattern.
|
|||
|
# Otherwise all input lines would print.
|
|||
|
# The -e option not necessary here since there is only a single editing instruction.
|
|||
|
</programlisting></para>
|
|||
|
|
|||
|
<table>
|
|||
|
<title>Examples</title>
|
|||
|
<tgroup cols="2">
|
|||
|
<thead>
|
|||
|
<row>
|
|||
|
<entry>Notation</entry>
|
|||
|
<entry>Effect</entry>
|
|||
|
</row>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<row>
|
|||
|
<entry><option>8d</option></entry>
|
|||
|
<entry>Delete 8th line of input.</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>/^$/d</option></entry>
|
|||
|
<entry>Delete all blank lines.</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>1,/^$/d</option></entry>
|
|||
|
<entry>Delete from beginning of input up to, and including
|
|||
|
first blank line.</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>/Jones/p</option></entry>
|
|||
|
<entry>Print only lines containing <quote>Jones</quote> (with
|
|||
|
<token>-n</token> option).</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>s/Windows/Linux/</option></entry>
|
|||
|
<entry>Substitute <quote>Linux</quote> for first instance
|
|||
|
of<quote>Windows</quote> found in each input line.</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>s/BSOD/stability/g</option></entry>
|
|||
|
<entry>Substitute <quote>stability</quote> for every instance
|
|||
|
of<quote>BSOD</quote> found in each input line.</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>s/ *$//</option></entry>
|
|||
|
<entry>Delete all spaces at the end of every line.</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>s/00*/0/g</option></entry>
|
|||
|
<entry>Compress all consecutive sequences of zeroes into
|
|||
|
a single zero.</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>/GUI/d</option></entry>
|
|||
|
<entry>Delete all lines containing <quote>GUI</quote>.</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>s/GUI//g</option></entry>
|
|||
|
<entry>Delete all instances of <quote>GUI</quote>, leaving the
|
|||
|
remainder of each line intact.</entry>
|
|||
|
</row>
|
|||
|
</tbody>
|
|||
|
</tgroup>
|
|||
|
</table>
|
|||
|
|
|||
|
<note><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 <userinput>The most important parts of any application are
|
|||
|
its GUI and sound effects</userinput> results in
|
|||
|
<screen><computeroutput>The most important parts of any application are its and sound effects</computeroutput></screen></para></note>
|
|||
|
|
|||
|
<tip><para>A quick way to double-space a text file is <userinput>sed G
|
|||
|
filename</userinput>.</para></tip>
|
|||
|
|
|||
|
<para>For illustrative examples of sed within shell scripts, see:
|
|||
|
<orderedlist>
|
|||
|
<listitem><para><xref linkend="ex3"></para></listitem>
|
|||
|
<listitem><para><xref linkend="ex4"></para></listitem>
|
|||
|
<listitem><para><xref linkend="ex57"></para></listitem>
|
|||
|
<listitem><para><xref linkend="rn"></para></listitem>
|
|||
|
<listitem><para><xref linkend="grp"></para></listitem>
|
|||
|
<listitem><para><xref linkend="col"></para></listitem>
|
|||
|
<listitem><para><xref linkend="behead"></para></listitem>
|
|||
|
<listitem><para><xref linkend="tree"></para></listitem>
|
|||
|
<listitem><para><xref linkend="stripc"></para></listitem>
|
|||
|
<listitem><para><xref linkend="findstring"></para></listitem>
|
|||
|
<listitem><para><xref linkend="base"></para></listitem>
|
|||
|
<listitem><para><xref linkend="mailformat"></para></listitem>
|
|||
|
<listitem><para><xref linkend="rnd"></para></listitem>
|
|||
|
</orderedlist>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>For a more extensive treatment of sed, check the appropriate
|
|||
|
references in the <xref linkend="biblio">.</para>
|
|||
|
|
|||
|
</sect1>
|
|||
|
<!-- End sed primer -->
|
|||
|
|
|||
|
|
|||
|
<sect1 id="awk">
|
|||
|
<title>Awk</title>
|
|||
|
|
|||
|
<para><anchor id="awkref">Awk</para>
|
|||
|
|
|||
|
<para><command>Awk</command> is a full-featured text processing
|
|||
|
language with a syntax reminiscent of <command>C</command>. While
|
|||
|
it possesses an extensive set of operators and capabilities,
|
|||
|
we will cover only a couple of these here - the ones most useful
|
|||
|
for shell scripting.</para>
|
|||
|
|
|||
|
<para>Awk breaks each line of input passed to it into
|
|||
|
<emphasis>fields</emphasis>. By default, a field is
|
|||
|
a string of consecutive characters separated by <link
|
|||
|
linkend="whitespaceref">whitespace</link>, though there are
|
|||
|
options for changing the delimiter. Awk parses and operates on each
|
|||
|
separate field. This makes awk ideal for handling structured text
|
|||
|
files, especially tables, data organized into consistent chunks,
|
|||
|
such as rows and columns.</para>
|
|||
|
|
|||
|
<para>Strong quoting (single quotes) and curly brackets enclose
|
|||
|
segments of awk code within a shell script.</para>
|
|||
|
|
|||
|
<para><programlisting>awk '{print $3}'
|
|||
|
# Prints field #3 to stdout.
|
|||
|
|
|||
|
awk '{print $1 $5 $6}'
|
|||
|
# Prints fields #1, #5, and #6.</programlisting></para>
|
|||
|
|
|||
|
<para>We have just seen the awk <command>print</command> command
|
|||
|
in action. The only other feature of awk we need to deal with
|
|||
|
here is variables. Awk handles variables similarly to shell
|
|||
|
scripts, though a bit more flexibly.</para>
|
|||
|
|
|||
|
<para><programlisting>{ total += ${column_number} }</programlisting>
|
|||
|
This adds the value of <emphasis>column_number</emphasis> to
|
|||
|
the running total of <quote>total</quote>. Finally, to print
|
|||
|
<quote>total</quote>, there needs to be an <command>END</command>
|
|||
|
command to terminate the processing.
|
|||
|
<programlisting>END { print total }</programlisting></para>
|
|||
|
|
|||
|
<para>Corresponding to the <command>END</command>, there is a
|
|||
|
<command>BEGIN</command>, for a code block to be performed before awk
|
|||
|
starts processing its input.</para>
|
|||
|
|
|||
|
<para>For examples of awk within shell scripts, see:
|
|||
|
<orderedlist>
|
|||
|
<listitem><para><xref linkend="ex44"></para></listitem>
|
|||
|
<listitem><para><xref linkend="redir4"></para></listitem>
|
|||
|
<listitem><para><xref linkend="stripc"></para></listitem>
|
|||
|
<listitem><para><xref linkend="coltotaler"></para></listitem>
|
|||
|
<listitem><para><xref linkend="coltotaler2"></para></listitem>
|
|||
|
<listitem><para><xref linkend="coltotaler3"></para></listitem>
|
|||
|
<listitem><para><xref linkend="pidid"></para></listitem>
|
|||
|
<listitem><para><xref linkend="constat"></para></listitem>
|
|||
|
<listitem><para><xref linkend="fileinfo"></para></listitem>
|
|||
|
<listitem><para><xref linkend="seedingrandom"></para></listitem>
|
|||
|
</orderedlist>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>That's all the awk we'll cover here, folks, but there's lots
|
|||
|
more to learn. See the appropriate references in the <xref
|
|||
|
linkend="biblio">.</para>
|
|||
|
|
|||
|
|
|||
|
</sect1>
|
|||
|
<!-- End awk primer -->
|
|||
|
|
|||
|
</appendix>
|
|||
|
<!-- End sed/awk appendix -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<appendix id="exitcodes">
|
|||
|
<title>Exit Codes With Special Meanings</title>
|
|||
|
|
|||
|
<para><anchor id="exitcodesref"></para>
|
|||
|
|
|||
|
<table>
|
|||
|
<title><quote>Reserved</quote> Exit Codes</title>
|
|||
|
<tgroup cols="4">
|
|||
|
<thead>
|
|||
|
<row>
|
|||
|
<entry>Exit Code Number</entry>
|
|||
|
<entry>Meaning</entry>
|
|||
|
<entry>Example</entry>
|
|||
|
<entry>Comments</entry>
|
|||
|
</row>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<row>
|
|||
|
<entry><option>1</option></entry>
|
|||
|
<entry>catchall for general errors</entry>
|
|||
|
<entry>let "var1 = 1/0"</entry>
|
|||
|
<entry>miscellaneous errors, such as <quote>divide by
|
|||
|
zero</quote></entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>2</option></entry>
|
|||
|
<entry>misuse of shell builtins, according to Bash documentation</entry>
|
|||
|
<entry></entry>
|
|||
|
<entry>Seldom seen, usually defaults to exit code 1</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>126</option></entry>
|
|||
|
<entry>command invoked cannot execute</entry>
|
|||
|
<entry></entry>
|
|||
|
<entry>permission problem or command is not an executable</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>127</option></entry>
|
|||
|
<entry><quote>command not found</quote></entry>
|
|||
|
<entry></entry>
|
|||
|
<entry>possible problem with <varname>$PATH</varname> or a typo</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>128</option></entry>
|
|||
|
<entry>invalid argument to <link linkend="exitcommandref">exit</link></entry>
|
|||
|
<entry>exit 3.14159</entry>
|
|||
|
<entry><command>exit</command> takes only integer args in the
|
|||
|
range 0 - 255</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>128+n</option></entry>
|
|||
|
<entry>fatal error signal <quote>n</quote></entry>
|
|||
|
<entry><command>kill -9</command> <varname>$PPID</varname>of script</entry>
|
|||
|
<entry><userinput>$?</userinput> returns 137 (128 + 9)</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>130</option></entry>
|
|||
|
<entry>script terminated by Control-C</entry>
|
|||
|
<entry></entry>
|
|||
|
<entry>Control-C is fatal error signal 2, (130 = 128 + 2,
|
|||
|
see above)</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>255</option></entry>
|
|||
|
<entry>exit status out of range</entry>
|
|||
|
<entry>exit -1</entry>
|
|||
|
<entry><command>exit</command> takes only integer args in the
|
|||
|
range 0 - 255</entry>
|
|||
|
</row>
|
|||
|
</tbody>
|
|||
|
</tgroup>
|
|||
|
</table>
|
|||
|
|
|||
|
<para>According to the table, exit codes 1 - 2, 126 - 165, and 255 have
|
|||
|
special meanings, and should therefore be avoided
|
|||
|
as user-specified exit parameters. Ending a script with
|
|||
|
<command>exit 127</command> would certainly cause confusion
|
|||
|
when troubleshooting (is the error a <quote>command not
|
|||
|
found</quote> or a user-defined one?). However, many scripts use
|
|||
|
an <command>exit 1</command> as a general bailout upon error.
|
|||
|
Since exit code <returnvalue>1</returnvalue> signifies so many
|
|||
|
possible errors, this might not add any additional ambiguity,
|
|||
|
but, on the other hand, it probably would not be very informative
|
|||
|
either.</para>
|
|||
|
|
|||
|
<para>There has been an attempt to systematize exit status numbers
|
|||
|
(see <filename
|
|||
|
class="headerfile">/usr/include/sysexits.h</filename>), but this
|
|||
|
is intended mostly for C and C++ programmers. It would be well
|
|||
|
to support a similar standard for scripts. The author of this
|
|||
|
document proposes restricting user-defined exit codes to the
|
|||
|
range 64 - 113 (in addition to <returnvalue>0</returnvalue>,
|
|||
|
for success), to conform with the C/C++ standard. This would
|
|||
|
still leave 50 valid codes, and make troubleshooting scripts
|
|||
|
more straightforward.</para>
|
|||
|
|
|||
|
<para>All user-defined exit codes in the accompanying examples
|
|||
|
to this document now conform to this standard, except
|
|||
|
where overriding circumstances exist, as in <xref
|
|||
|
linkend="tmdin">.</para>
|
|||
|
|
|||
|
<note><para>Issuing a <link linkend="xstatvarref">$?</link> from
|
|||
|
the command line after a shell script exits gives results
|
|||
|
consistent with the table above only from the Bash or
|
|||
|
<emphasis>sh</emphasis> prompt. Running the C-shell or
|
|||
|
<emphasis>tcsh</emphasis> may give different values in some
|
|||
|
cases.</para></note>
|
|||
|
|
|||
|
|
|||
|
</appendix>
|
|||
|
<!-- End Reserved Exit Code appendix -->
|
|||
|
|
|||
|
|
|||
|
<appendix id="ioredirintro">
|
|||
|
<title>A Detailed Introduction to I/O and I/O Redirection</title>
|
|||
|
|
|||
|
<para><emphasis>written by Stephane Chazelas, and revised by the
|
|||
|
document author</emphasis></para>
|
|||
|
|
|||
|
<para>A command expects the first three <link linkend="fdref">file
|
|||
|
descriptors</link> to be available. The first, <emphasis>fd
|
|||
|
0</emphasis> (standard input, <filename>stdin</filename>),
|
|||
|
is for reading. The other two (<emphasis>fd 1</emphasis>,
|
|||
|
<filename>stdout</filename> and <emphasis>fd 2</emphasis>,
|
|||
|
<filename>stderr</filename>) are for writing.</para>
|
|||
|
|
|||
|
<para>There is a <filename>stdin</filename>, <filename>stdout</filename>,
|
|||
|
and a <filename>stderr</filename> associated with each command.
|
|||
|
<userinput>ls 2>&1</userinput> means temporarily connecting the
|
|||
|
<filename>stderr</filename> of the <command>ls</command> command to the
|
|||
|
same <quote>resource</quote> as the shell's
|
|||
|
<filename>stdout</filename>.</para>
|
|||
|
|
|||
|
<para>By convention, a command reads its input from fd 0
|
|||
|
(<filename>stdin</filename>), prints normal output to fd
|
|||
|
1 (<filename>stdout</filename>), and error ouput to fd 2
|
|||
|
(<filename>stderr</filename>). If one of those three fd's is
|
|||
|
not open, you may encounter problems:</para>
|
|||
|
|
|||
|
<screen>
|
|||
|
<prompt>bash$ </prompt><userinput>cat /etc/passwd >&-</userinput>
|
|||
|
<computeroutput>cat: standard output: Bad file descriptor</computeroutput>
|
|||
|
</screen>
|
|||
|
|
|||
|
<para>For example, when <command>xterm</command> runs, it first
|
|||
|
initializes itself. Before running the user's shell,
|
|||
|
<command>xterm</command> opens the terminal device
|
|||
|
(/dev/pts/<n> or something similar) three times.</para>
|
|||
|
|
|||
|
<para>At this point, Bash inherits these three file descriptors,
|
|||
|
and each command (child process) run by Bash inherits
|
|||
|
them in turn, except when you redirect the command. <link
|
|||
|
linkend="ioredirref">Redirection</link> means reassigning
|
|||
|
one of the file descriptors to another file (or a pipe, or
|
|||
|
anything permissable). File descriptors may be reassigned
|
|||
|
locally (for a command, a command group, a subshell, a <link
|
|||
|
linkend="redirref">while or if or case or for loop</link>...),
|
|||
|
or globally, for the remainder of the shell (using <link
|
|||
|
linkend="execref">exec</link>).</para>
|
|||
|
|
|||
|
<para><userinput>ls > /dev/null</userinput> means
|
|||
|
running <command>ls</command> with its fd 1 connected to
|
|||
|
<filename>/dev/null</filename>.</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen>
|
|||
|
<prompt>bash$ </prompt><userinput>lsof -a -p $$ -d0,1,2</userinput>
|
|||
|
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
|
|||
|
bash 363 bozo 0u CHR 136,1 3 /dev/pts/1
|
|||
|
bash 363 bozo 1u CHR 136,1 3 /dev/pts/1
|
|||
|
bash 363 bozo 2u CHR 136,1 3 /dev/pts/1</computeroutput>
|
|||
|
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>exec 2> /dev/null</userinput>
|
|||
|
<prompt>bash$ </prompt><userinput>lsof -a -p $$ -d0,1,2</userinput>
|
|||
|
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
|
|||
|
bash 371 bozo 0u CHR 136,1 3 /dev/pts/1
|
|||
|
bash 371 bozo 1u CHR 136,1 3 /dev/pts/1
|
|||
|
bash 371 bozo 2w CHR 1,3 120 /dev/null</computeroutput>
|
|||
|
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>bash -c 'lsof -a -p $$ -d0,1,2' | cat</userinput>
|
|||
|
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
|
|||
|
lsof 379 root 0u CHR 136,1 3 /dev/pts/1
|
|||
|
lsof 379 root 1w FIFO 0,0 7118 pipe
|
|||
|
lsof 379 root 2u CHR 136,1 3 /dev/pts/1</computeroutput>
|
|||
|
|
|||
|
|
|||
|
<prompt>bash$ </prompt><userinput>echo "$(bash -c 'lsof -a -p $$ -d0,1,2' 2>&1)"</userinput>
|
|||
|
<computeroutput>COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
|
|||
|
lsof 426 root 0u CHR 136,1 3 /dev/pts/1
|
|||
|
lsof 426 root 1w FIFO 0,0 7520 pipe
|
|||
|
lsof 426 root 2w FIFO 0,0 7520 pipe</computeroutput>
|
|||
|
</screen>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>This works for different types of redirection.</para>
|
|||
|
|
|||
|
<para><userinput>Exercise:</userinput> analyze the following script.
|
|||
|
|
|||
|
<programlisting>#! /usr/bin/env bash
|
|||
|
|
|||
|
mkfifo /tmp/fifo1 /tmp/fifo2
|
|||
|
while read a; do echo "FIFO1: $a"; done < /tmp/fifo1 &
|
|||
|
exec 7> /tmp/fifo1
|
|||
|
exec 8> >(while read a; do echo "FD8: $a, to fd7"; done >&7)
|
|||
|
|
|||
|
exec 3>&1
|
|||
|
(
|
|||
|
(
|
|||
|
(
|
|||
|
while read a; do echo "FIFO2: $a"; done < /tmp/fifo2 | tee /dev/stderr | tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 >&7 &
|
|||
|
exec 3> /tmp/fifo2
|
|||
|
|
|||
|
echo 1st, to stdout
|
|||
|
sleep 1
|
|||
|
echo 2nd, to stderr >&2
|
|||
|
sleep 1
|
|||
|
echo 3rd, to fd 3 >&3
|
|||
|
sleep 1
|
|||
|
echo 4th, to fd 4 >&4
|
|||
|
sleep 1
|
|||
|
echo 5th, to fd 5 >&5
|
|||
|
sleep 1
|
|||
|
echo 6th, through a pipe | sed 's/.*/PIPE: &, to fd 5/' >&5
|
|||
|
sleep 1
|
|||
|
echo 7th, to fd 6 >&6
|
|||
|
sleep 1
|
|||
|
echo 8th, to fd 7 >&7
|
|||
|
sleep 1
|
|||
|
echo 9th, to fd 8 >&8
|
|||
|
|
|||
|
) 4>&1 >&3 3>&- | while read a; do echo "FD4: $a"; done 1>&3 5>&- 6>&-
|
|||
|
) 5>&1 >&3 | while read a; do echo "FD5: $a"; done 1>&3 6>&-
|
|||
|
) 6>&1 >&3 | while read a; do echo "FD6: $a"; done 3>&-
|
|||
|
|
|||
|
rm -f /tmp/fifo1 /tmp/fifo2
|
|||
|
|
|||
|
|
|||
|
# For each command and subshell, figure out which fd points to what.
|
|||
|
|
|||
|
exit 0</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
</appendix>
|
|||
|
<!-- A Detailed Introduction to I/O and I/O Redirection -->
|
|||
|
|
|||
|
|
|||
|
<appendix id="localization">
|
|||
|
<title>Localization</title>
|
|||
|
|
|||
|
<para>Localization is an undocumented Bash feature.</para>
|
|||
|
|
|||
|
<para>A localized shell script echoes its text output in the
|
|||
|
language defined as the system's locale. A Linux user in Berlin,
|
|||
|
Germany, would get script output in German, whereas his cousin
|
|||
|
in Berlin, Maryland, would get output from the same script in
|
|||
|
English.</para>
|
|||
|
|
|||
|
<para>To create a localized script, use the following template to
|
|||
|
write all messages to the user (error messages, prompts,
|
|||
|
etc.).</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<programlisting>#!/bin/bash
|
|||
|
# localized.sh
|
|||
|
|
|||
|
E_CDERROR=65
|
|||
|
|
|||
|
error()
|
|||
|
{
|
|||
|
printf "$@" >&2
|
|||
|
exit $E_CDERROR
|
|||
|
}
|
|||
|
|
|||
|
cd $var || error $"Can't cd to %s." "$var"
|
|||
|
read -p $"Enter the value: " var
|
|||
|
# ...</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>bash -D localized.sh</userinput>
|
|||
|
<computeroutput>"Can't cd to %s."
|
|||
|
"Enter the value: "</computeroutput></screen>
|
|||
|
|
|||
|
This lists all the localized text. (The <option>-D</option>
|
|||
|
option lists double-quoted strings prefixed by a <token>$</token>,
|
|||
|
without executing the script.)</para>
|
|||
|
|
|||
|
<para>
|
|||
|
<screen><prompt>bash$ </prompt><userinput>bash --dump-po-strings localized.sh</userinput>
|
|||
|
<computeroutput>#: a:6
|
|||
|
msgid "Can't cd to %s."
|
|||
|
msgstr ""
|
|||
|
#: a:7
|
|||
|
msgid "Enter the value: "
|
|||
|
msgstr ""</computeroutput></screen>
|
|||
|
|
|||
|
The <option>--dump-po-strings</option> option to Bash
|
|||
|
resembles the <option>-D</option> option, but uses <link
|
|||
|
linkend="gettextref">gettext</link> <quote>po</quote> format.
|
|||
|
|
|||
|
</para>
|
|||
|
|
|||
|
|
|||
|
<para>Now, build a <filename>language.po</filename>
|
|||
|
file for each language that the script will be translated
|
|||
|
into, specifying the <replaceable>msgstr</replaceable>. As an
|
|||
|
example:</para>
|
|||
|
|
|||
|
<para>fr.po:
|
|||
|
|
|||
|
<programlisting>#: a:6
|
|||
|
msgid "Can't cd to %s."
|
|||
|
msgstr "Impossible de se positionner dans le r<>pertoire %s."
|
|||
|
#: a:7
|
|||
|
msgid "Enter the value: "
|
|||
|
msgstr "Entrez la valeur : "</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>Then, run <command>msgfmt</command>.</para>
|
|||
|
<para><userinput>msgfmt -o localized.sh.mo fr.po</userinput></para>
|
|||
|
|
|||
|
<para>Place the resulting <filename>localized.sh.mo</filename> file in the
|
|||
|
<filename class="directory">/usr/local/share/locale/fr/LC_MESSAGES</filename>
|
|||
|
directory, and at the beginning of the script, insert the lines:
|
|||
|
|
|||
|
<programlisting>TEXTDOMAINDIR=/usr/local/share/locale
|
|||
|
TEXTDOMAIN=localized.sh</programlisting>
|
|||
|
</para>
|
|||
|
|
|||
|
<para>If a user on a French system runs the script, she will get
|
|||
|
French messages.</para>
|
|||
|
|
|||
|
<note>
|
|||
|
<para>With older versions of Bash or other shells, localization requires
|
|||
|
<link linkend="gettextref">gettext</link>, using the
|
|||
|
<option>-s</option> option. In this case, the script becomes:</para>
|
|||
|
|
|||
|
<para><anchor id="gettextexample">
|
|||
|
<programlisting>#!/bin/bash
|
|||
|
# localized.sh
|
|||
|
|
|||
|
E_CDERROR=65
|
|||
|
|
|||
|
error() {
|
|||
|
local format=$1
|
|||
|
shift
|
|||
|
printf "$(gettext -s "$format")" "$@" >&2
|
|||
|
exit $E_CDERROR
|
|||
|
}
|
|||
|
cd $var || error "Can't cd to %s." "$var"
|
|||
|
read -p "$(gettext -s "Enter the value: ")" var
|
|||
|
# ...</programlisting>
|
|||
|
</para>
|
|||
|
</note>
|
|||
|
|
|||
|
<para>The <varname>TEXTDOMAIN</varname> and
|
|||
|
<varname>TEXTDOMAINDIR</varname> variables need to be exported
|
|||
|
to the environment.</para>
|
|||
|
|
|||
|
<para>---</para>
|
|||
|
|
|||
|
<para>This appendix written by Stephane Chazelas.</para>
|
|||
|
|
|||
|
</appendix>
|
|||
|
<!-- Localization -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<appendix id="sample-bashrc">
|
|||
|
<title>A Sample <filename>.bashrc</filename> File</title>
|
|||
|
|
|||
|
<para>The <filename>~/.bashrc</filename> file determines the
|
|||
|
behavior of interactive shells. A good look at this file can
|
|||
|
lead to a better understanding of Bash.</para>
|
|||
|
|
|||
|
<para>Emmanuel Rouat contributed the following very elaborate
|
|||
|
<filename>.bashrc</filename> file, written for a Linux system.
|
|||
|
Study this file carefully, and feel free to reuse code snippets
|
|||
|
and functions from it in your own <filename>.bashrc</filename>
|
|||
|
file and even in your scripts.</para>
|
|||
|
|
|||
|
|
|||
|
<example id="bashrc">
|
|||
|
<title>Sample <filename>.bashrc</filename> file</title>
|
|||
|
<programlisting>&bashrc;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
</appendix>
|
|||
|
<!-- End Sample .bashrc File appendix -->
|
|||
|
|
|||
|
|
|||
|
<appendix id="dosbatch">
|
|||
|
<title>Converting DOS Batch Files to Shell Scripts</title>
|
|||
|
|
|||
|
<para>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 script 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 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
|
|||
|
<command>CALL</command>)</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>LP1</option></entry>
|
|||
|
<entry><filename>/dev/lp0</filename></entry>
|
|||
|
<entry>first printer device</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>COM1</option></entry>
|
|||
|
<entry><filename>/dev/ttyS0</filename></entry>
|
|||
|
<entry>first serial port</entry>
|
|||
|
</row>
|
|||
|
</tbody>
|
|||
|
</tgroup>
|
|||
|
</table>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<para>Batch files usually contain DOS commands. These must be
|
|||
|
translated into their UNIX equivalents in order to convert a
|
|||
|
batch file into a shell script.</para>
|
|||
|
|
|||
|
<table>
|
|||
|
<title>DOS Commands and Their UNIX Equivalents</title>
|
|||
|
<tgroup cols="3">
|
|||
|
<thead>
|
|||
|
<row>
|
|||
|
<entry>DOS Command</entry>
|
|||
|
<entry>UNIX Equivalent</entry>
|
|||
|
<entry>Effect</entry>
|
|||
|
</row>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<row>
|
|||
|
<entry><option>ASSIGN</option></entry>
|
|||
|
<entry>ln</entry>
|
|||
|
<entry>link file or directory</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>ATTRIB</option></entry>
|
|||
|
<entry>chmod</entry>
|
|||
|
<entry>change file permissions</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>CD</option></entry>
|
|||
|
<entry>cd</entry>
|
|||
|
<entry>change directory</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>CHDIR</option></entry>
|
|||
|
<entry>cd</entry>
|
|||
|
<entry>change directory</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>CLS</option></entry>
|
|||
|
<entry>clear</entry>
|
|||
|
<entry>clear screen</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>COMP</option></entry>
|
|||
|
<entry>cmp or diff</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>DIR</option></entry>
|
|||
|
<entry>ls -l</entry>
|
|||
|
<entry>directory listing</entry>
|
|||
|
</row>
|
|||
|
<row>
|
|||
|
<entry><option>EXIT</option></entry>
|
|||
|
<entry>exit</entry>
|
|||
|
<entry>exit current process</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 Bash (and <emphasis>sh</emphasis>)
|
|||
|
operators and commands have many more options and
|
|||
|
enhancements than their batch file and DOS equivalents.
|
|||
|
Many batch file scripts rely on auxiliary utilities, such as
|
|||
|
<command>ask.com</command>, a crippled counterpart to <link
|
|||
|
linkend="readref">read</link>.</para>
|
|||
|
|
|||
|
<para>DOS supports a very limited and incompatible subset of
|
|||
|
filename <link linkend="globbingref">wildcard expansion</link>,
|
|||
|
recognizing only the <token>*</token> and <token>?</token>
|
|||
|
characters.</para>
|
|||
|
</note>
|
|||
|
|
|||
|
<para>Converting a DOS batch file into a shell script is usually
|
|||
|
straightforward, and the result ofttimes reads better than the
|
|||
|
original.</para>
|
|||
|
|
|||
|
<example id="VIEWDAT">
|
|||
|
<title>VIEWDATA.BAT: DOS Batch File</title>
|
|||
|
<programlisting>&VIEWDAT;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
<para>The script conversion is somewhat of an improvement.</para>
|
|||
|
|
|||
|
<example id="viewdata">
|
|||
|
<title>viewdata.sh: Shell Script Conversion of VIEWDATA.BAT</title>
|
|||
|
<programlisting>&viewdata;</programlisting>
|
|||
|
</example>
|
|||
|
|
|||
|
|
|||
|
<para>Ted Davis' <ulink url="http://www.maem.umr.edu/~batch/">Shell
|
|||
|
Scripts on the PC</ulink> site has a set of comprehensive
|
|||
|
tutorials on the old-fashioned art of batch file
|
|||
|
programming. Certain of his ingenious techniques could conceivably
|
|||
|
have relevance for shell scripts.</para>
|
|||
|
|
|||
|
|
|||
|
</appendix>
|
|||
|
<!-- End DOS Batch File Conversion appendix -->
|
|||
|
|
|||
|
|
|||
|
<appendix id="copyright">
|
|||
|
<title>Copyright</title>
|
|||
|
<para>The <quote>Advanced Bash-Scripting Guide</quote> is copyright,
|
|||
|
(c) 2000, by Mendel Cooper. This document may only be distributed
|
|||
|
subject to the terms and conditions set forth in the <ulink
|
|||
|
url="http://www.linuxdoc.org/manifesto.html">LDP License</ulink>
|
|||
|
These are very liberal terms, and they should not hinder any
|
|||
|
legitimate distribution or use of this document. The author
|
|||
|
especially encourages the use of this document, or portions thereof,
|
|||
|
for instructional purposes.</para>
|
|||
|
|
|||
|
<para>Hyun Jin Cha has done a <ulink
|
|||
|
url="http://kldp.org/HOWTO/html/Adv-Bash-Scr-HOWTO/index.html">Korean
|
|||
|
translation</ulink> of this document. If you wish to translate it
|
|||
|
into another language, please feel free to do so, subject to the
|
|||
|
terms stated above. The author would appreciate being notified of
|
|||
|
such efforts.</para>
|
|||
|
|
|||
|
<para>If this document is incorporated into a printed book, the author
|
|||
|
requests a courtesy copy. This is a request, not a
|
|||
|
requirement.</para>
|
|||
|
|
|||
|
</appendix>
|
|||
|
<!-- End Copyright appendix -->
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<!-- Uncomment line below to generate index. -->
|
|||
|
&doc-index;
|
|||
|
|
|||
|
</book>
|
|||
|
<!--
|
|||
|
</article>
|
|||
|
-->
|
|||
|
<!-- Keep this comment at the end of the file
|
|||
|
Local variables:
|
|||
|
mode: sgml
|
|||
|
sgml-indent-step:2
|
|||
|
sgml-indent-data:t
|
|||
|
End:
|
|||
|
-->
|
|||
|
|