This commit is contained in:
gferg 2003-01-06 21:25:36 +00:00
parent ace4f1934b
commit 03ddc10f2d
8 changed files with 275 additions and 47 deletions

View File

@ -3,6 +3,59 @@ RELEASE HISTORY
Change log
Version 1.7 (minor update)
'COCONUT' release
01/05/03
1) In "Special Variable Types" section of "Introduction to Variables and
Parameters" chapter:
Added note about "$*" and "$@" special variables, and updated "ex17.sh"
example to reflect this.
2) In "Manipulating Strings" subsection of "Variables Revisited" chapter:
Added "paragraph-space.sh" example.
3) In "Loop Control" section of "Loops and Branches" chapter:
Added "continue-n.example" to illustrate use of "continue N" construct.
(Thank you, Albert Reiner.)
4) In "Internal Commands" chapter:
Added section to "read-redir.sh" example to show setting "$IFS" within a
loop. (Thanks, Dim Segebart.)
Added Rory Winston's example of "eval" usage.
5) In "List Constructs" chapter:
Deleted erroneous comment in "ex65.sh."
(Thank you, Francisco de Jesus Orozco Ruiz.)
6) In "File Test" section of "Tests" chapter:
Added "broken-link.sh" example.
7) In "Internal Variables" section of "Variables Revisited" chapter:
Added comment on $PIPESTATUS.
8) In "RANDOM" section of "Variables Revisited" chapter:
Added the 'jipe' techniques for generating random numbers within a
specified range.
Added "pick-card.sh" example. Thank you once more, jipe.
9) In "Miscellaneous Commands" section of "External Commands" Chapter:
Amended discussion of "tee" command.
10) In "System and Administrative Commands" chapter:
Expanded "ulimit" discussion to include "fork bomb" scenario.
11) In "Aliases" chapter:
Slightly revised "alias.sh" example.
12) In "Bibliography" section and as a footnote in "Debugging" chapter:
Added reference to Rocky Bernstein's Bash debugger.
13) Various minor fixups on example scripts.
Version 1.6 (minor update)
'POMEGRANATE' release
09/29/02

View File

@ -264,6 +264,11 @@ Uncomment line below to generate index.
<!ENTITY colorecho SYSTEM "color-echo.sh">
<!ENTITY selfsource SYSTEM "self-source.sh">
<!ENTITY arrowdetect SYSTEM "arrow-detect.sh">
<!ENTITY paragraphspace SYSTEM "paragraph-space.sh">
<!ENTITY brokenlink SYSTEM "broken-link.sh">
<!ENTITY continuenex SYSTEM "continue-n.example">
<!ENTITY pickcard SYSTEM "pick-card.sh">
<!ENTITY evalex SYSTEM "eval.example">
<!ENTITY namesdata SYSTEM "names.data">
<!ENTITY gen0data SYSTEM "gen0">
<!ENTITY bashrc SYSTEM "bashrc">
@ -284,8 +289,8 @@ Uncomment line below to generate index.
</affiliation>
</author>
<releaseinfo>1.6</releaseinfo>
<pubdate>29 September 2002</pubdate>
<releaseinfo>1.7</releaseinfo>
<pubdate>05 January 2003</pubdate>
<revhistory>
@ -382,6 +387,14 @@ Uncomment line below to generate index.
more script added.</revremark>
</revision>
<revision>
<revnumber>1.7</revnumber>
<date>05 January 2003</date>
<authorinitials>mc</authorinitials>
<revremark>'COCONUT' release: a couple of bugfixes, more material, one
more script.</revremark>
</revision>
</revhistory>
@ -402,7 +415,7 @@ Uncomment line below to generate index.
linkend="bzipref">bzip2-ed</link> <quote>tarball</quote>
including both the SGML source and
rendered HTML, may be downloaded from <ulink
url="http://personal.riverusers.com/~thegrendel/abs-guide-1.6.tar.bz2">
url="http://personal.riverusers.com/~thegrendel/abs-guide-1.7.tar.bz2">
the author's home site</ulink>. See the <ulink
url="http://personal.riverusers.com/~thegrendel/Change.log">change
log</ulink> for a revision history.</para>
@ -442,7 +455,7 @@ Uncomment line below to generate index.
<title>Why Shell Programming?</title>
<para>A working knowledge of shell scripting is essential to everyone
<para>A working knowledge of shell scripting is essential to anyone
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
@ -532,7 +545,7 @@ Uncomment line below to generate index.
</itemizedlist></para>
<para>If any of the above applies, consider a more powerful scripting
language, perhaps Perl, Tcl, Python, or possibly a high-level
language, perhaps Perl, Tcl, Python, Ruby, or possibly a high-level
compiled language such as C, C++, or Java. Even then, prototyping
the application as a shell script might still be a useful
development step.</para>
@ -553,7 +566,7 @@ Uncomment line below to generate index.
is not recommended due to certain inherent problems, as pointed out
in an October, 1993 <ulink
url="http://www.etext.org/Quartz/computer/unix/csh.harmful.gz">Usenet
posting</ulink> by Tom Christiansen).
post</ulink> by Tom Christiansen).
</para>
<para>What follows is a tutorial on shell scripting. It relies
@ -704,8 +717,8 @@ exit $WHATEVER # Doesn't matter. The script will not exit here.</programlisting
Using <userinput>#!/bin/sh</userinput>, the default Bourne Shell
in most commercial variants of UNIX, makes the script <link
linkend="portabilityissues">portable</link> to non-Linux machines,
though you may have to sacrifice a few Bash-specific features
(the script will conform to the
though you may have to sacrifice a few Bash-specific features.
The script will, however, conform to the
<acronym>POSIX</acronym>
<footnote><para><emphasis role="strong">P</emphasis>ortable
<emphasis role="strong">O</emphasis>perating
@ -713,36 +726,39 @@ exit $WHATEVER # Doesn't matter. The script will not exit here.</programlisting
role="bold">I</emphasis>nterface, an attempt to
standardize UNI<emphasis role="strong">X</emphasis>-like
OSes.</para></footnote>
<command>sh</command> standard).</para>
<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>
be correct, otherwise an error message -- usually <quote>Command
not found</quote> -- will be the only result of running the
script.</para>
<para><token>#!</token> can be omitted if the script consists only
of a set of generic system commands, using no internal
shell directives. The second example, above, requires the
initial <token>#!</token>, since the variable assignment line,
<userinput>lines=50</userinput>, uses a shell-specific construct.
Note that <userinput>#!/bin/sh</userinput> invokes the default
Note again 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
<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.
number of parameters.</para>
<programlisting>if [ $# -ne Number_of_expected args ]
<para><programlisting>if [ $# -ne Number_of_expected args ]
then
echo "Usage: `basename $0` whatever"
exit $WRONG_ARGS
fi</programlisting>
</para></important>
</para>
</important>
<sect1 id="invoking">
@ -755,7 +771,7 @@ fi</programlisting>
script may therefore fail to execute.</para></footnote>
or alternatively <userinput>bash scriptname</userinput>. (Not
recommended is using <userinput>sh &lt;scriptname</userinput>,
recommended is using <userinput>sh &lt;scriptname&gt;</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
@ -2994,6 +3010,9 @@ arch=$(uname -m)</programlisting></para>
After $9, the arguments must be enclosed in brackets,
for example, ${10}, ${11}, ${12}.</para>
<para>The special variables <link linkend="appref">$* and $@</link>
denote <emphasis>all</emphasis> the positional parameters.</para>
<example id="ex17">
<title>Positional Parameters</title>
<programlisting>&ex17;</programlisting>
@ -4252,9 +4271,14 @@ home=/home/bozo
</varlistentry>
</variablelist>
<example id="brokenlink">
<title>Testing for broken links</title>
<programlisting>&brokenlink;</programlisting>
</example>
<para><xref linkend="cookies">, <xref linkend="bingrep">,
<xref linkend="fileinfo">, <xref linkend="ramdisk">, and <xref
linkend="mailformat"> illustrate uses of the file test
linkend="mailformat"> also illustrate uses of the file test
operators.</para>
@ -5844,7 +5868,8 @@ echo "Last command argument processed = $last_cmd_arg"
<secondary>pipe</secondary>
</indexterm>
<listitem>
<para>Exit status of last executed <link
<para>Exit status of last executed
<emphasis>foreground</emphasis> <link
linkend="piperef">pipe</link>. Interestingly enough,
this does not give the same result as the <link
linkend="exitstatusref">exit status</link> of the last
@ -5867,6 +5892,36 @@ echo "Last command argument processed = $last_cmd_arg"
</screen>
</para>
<caution>
<para>
The <varname>$PIPESTATUS</varname> variable
may contain an erroneous <errorcode>0</errorcode> value
in a login shell.
</para>
<para>
<screen>
<prompt>tcsh% </prompt><userinput>bash</userinput>
<prompt>bash$ </prompt><userinput>who | grep nobody | sort</userinput>
<prompt>bash$ </prompt><userinput>echo ${PIPESTATUS[*]}</userinput>
<computeroutput>0</computeroutput>
</screen>
</para>
<para>
The above lines contained in a script would produce the expected
<computeroutput>0 1 0</computeroutput> output.
</para>
<para>
Thank you, Wayne Pollock for pointing this out and supplying the
above example.
</para>
</caution>
</listitem>
</varlistentry>
@ -6547,7 +6602,8 @@ echo $_ # :</programlisting></example>
<secondary>expr</secondary>
</indexterm>
<listitem><para>
<listitem>
<para>
<programlisting>stringZ=abcABC123ABCabc
echo ${#stringZ} # 15
@ -6555,10 +6611,16 @@ echo `expr length $stringZ` # 15
echo `expr "$stringZ" : '.*'` # 15</programlisting>
</para>
</listitem>
</varlistentry>
</variablelist>
<example id="paragraphspace">
<title>Inserting a blank line between paragraphs in a text file</title>
<programlisting>&paragraphspace;</programlisting>
</example>
<variablelist id="lengthsubstring">
<title>Length of Matching Substring at Beginning of String</title>
@ -7600,10 +7662,37 @@ echo "number = $number" # number = 0
<programlisting>&ex21;</programlisting>
</example>
<para>Just how random is RANDOM? The best way to test this is
<example id="pickcard">
<title>Picking a random card from a deck</title>
<programlisting>&pickcard;</programlisting>
</example>
<note>
<para>
<emphasis>Jipe</emphasis> points out another set of techniques
for generating random numbers within a range.
</para>
<para>
<programlisting># Generate random number between 6 and 30.
rnumber=$((RANDOM%25+6))
# Generate random number in the same 6 - 30 range,
#+ but the number must be evenly divisible by 3.
rnumber=$(((RANDOM%30/3+1)*3))
# Exercise: Try to figure out the pattern here.</programlisting>
</para>
</note>
<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>
<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>
@ -8139,6 +8228,11 @@ echo "number = $number" # number = 0
<programlisting>&continuelevels;</programlisting>
</example>
<example id="continuenex">
<title>Using <quote>continue N</quote> in an actual task</title>
<programlisting>&continuenex;</programlisting>
</example>
<caution><para>The <command>continue N</command> construct is
difficult to understand and tricky to use in any meaningful
context. It is probably best avoided.</para></caution>
@ -8860,6 +8954,17 @@ done</programlisting></para>
<programlisting>&rot14;</programlisting>
</example>
<para>Rory Winston contributed the following instance of how
useful <command>eval</command> can be.</para>
<example id="evalex">
<title>Using <command>eval</command> to force variable
substitution in a Perl script</title>
<programlisting>&evalex;</programlisting>
</example>
<caution><para>The <command>eval</command> command can be
risky, and normally should be avoided when there
exists a reasonable alternative. An <userinput>eval
@ -14495,8 +14600,8 @@ LIMIT_STRING
<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
plumber's <quote>tee,</quote> it permits <quote>siponing
off</quote> <emphasis>to a file </emphasis>the output of a command
or commands within a pipe, but without affecting the result. This is
useful for printing an ongoing process to a file or paper, perhaps to
keep track of it for debugging purposes.</para>
@ -17248,16 +17353,45 @@ then
<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).
<para>Sets an <emphasis>upper limit</emphasis> on use
of system resources. Usually invoked with the
<option>-f</option> option, which sets a limit on file size
(<command>ulimit -f 1000</command> limits files to 1 meg
maximum). The <option>-t</option> option limits the coredump
size (<command>ulimit -c 0</command> eliminates coredumps).
Normally, the value of <command>ulimit</command>
would be set in <filename>/etc/profile</filename>
and/or <filename>~/.bash_profile</filename> (see <xref
linkend="files">).</para>
<important>
<para>Judicious use of <command>ulimit</command> can
protect a system against the dreaded <emphasis>fork
bomb</emphasis>.</para>
<para>
<programlisting>#!/bin/bash
while 1 # Endless loop.
do
$0 & # This script invokes itself . . .
#+ forks an infinite number of times . . .
#+ until the system freezes up because all resources exhausted.
done # This is the notorious <quote>sorcerer's appentice</quote> scenario.
exit 0 # Will not exit here, because this script will never terminate.</programlisting>
</para>
<para>A <command>ulimit -Hu XX</command> (where
<emphasis>XX</emphasis> is the user process limit) in
<filename>/etc/profile</filename> would abort
this script when it exceeds the preset limit.
</para>
</important>
</listitem>
</varlistentry>
@ -20256,9 +20390,10 @@ false && ( true || echo false ) # (nothing echoed)
# Thanks, S.C.</programlisting>
</para>
<para>See <xref linkend="daysbetween"> for an illustration of using
an <userinput>and / or list</userinput> to test variables.</para>
<para>See <xref linkend="daysbetween"> and <xref
linkend="brokenlink"> for illustrations of using an <userinput>and
/ or list</userinput> to test variables.</para>
</chapter> <!-- List Constructs -->
@ -20857,9 +20992,16 @@ ln -s /dev/null ~/.netscape/cookies
<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>
debugging-specific commands or constructs.
<footnote><para>Rocky Bernstein's
<ulink
url="http://bashdb.sourceforge.net"> Bash debugger</ulink>
partially makes up for this lack.</para></footnote>
Syntax errors or outright typos in the script generate cryptic
error messages that are often of no help in debugging a
non-functional script.</para>
<example id="ex74">
<title>A buggy script</title>
@ -22946,8 +23088,9 @@ fi</programlisting>
were Gabor Kiss, Leopold Toetsch, Peter Tillier, Marcus Berglof,
Tony Richardson, Nick Drage (script ideas!), Rich Bartell, Jess
Thrysoee, Adam Lazur, Bram Moolenaar, Baris Cicek, Greg Keraunen,
Keith Matthews, Sandro Magi, and David Lawyer (himself an author
of 4 HOWTOs).</para>
Keith Matthews, Sandro Magi, Albert Reiner, Dim Segebart, Rory
Winston, Lee Bigelow, Wayne Pollock, <quote>jipe</quote>, and
David Lawyer (himself an author of 4 HOWTOs).</para>
<para>My gratitude to <ulink url="mailto:chet@po.cwru.edu">Chet
Ramey</ulink> and Brian Fox for writing <command>Bash</command>,
@ -23499,6 +23642,15 @@ fi</programlisting>
Hohensee</ulink> has written the <ulink
url="ftp://ftp.gwdg.de/pub/linux/install/clienux/interim/osimpa.tgz">
osimpa</ulink> i386 assembler entirely as Bash scripts.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Rocky Bernstein is in the process of developing a
<quote>full-fledged</quote> <ulink
url="http://bashdb.sourceforge.net"> debugger</ulink> for
Bash.</para>
<para>---</para>
</abstract>
</biblioentry>

View File

@ -55,20 +55,19 @@ do
alias rrr="ls -l"
echo "Trying aliased \"rrr\" within \"while\" loop:"
rrr /usr/X11R6/bin/mk* #* Alias will not expand here either.
# alias.sh: line 57: rrr: command not found
let count+=1
done
echo; echo
alias xyz="cat $1" # Try a positional parameter in an alias.
xyz # Assumes you invoke the script
#+ with a filename as a parameter.
alias xyz='cat $0' # Script lists itself.
# Note strong quotes.
xyz
# This seems to work,
#+ although the Bash documentation suggests that it shouldn't.
#
# However, as Steve Jacobson points out,
#+ the "$1" parameter expands immediately upon declaration of the alias,
#+ so, in the strictest sense, this is not an example
#+ of parameterizing an alias.
#+ the "$0" parameter expands immediately upon declaration of the alias.
exit 0

View File

@ -26,8 +26,9 @@ echo "QUOTATION MARKS"
echo $'\t \042 \t' # Quote (") framed by tabs.
# It also works with hexadecimal values, in an $'\xhhh' construct.
echo $'\t \x022 \t' # Quote (") framed by tabs.
echo $'\t \x22 \t' # Quote (") framed by tabs.
# Thank you, Greg Keraunen, for pointing this out.
# Earlier Bash versions allowed '\x022'.
echo "==============="
echo

View File

@ -36,8 +36,12 @@ then
echo "Parameter #10 is ${10}"
fi
echo "-----------------------------------"
echo "All the command-line parameters are: "$*""
if [ $# -lt "$MINPARAMS" ]
then
echo
echo "Give me at least $MINPARAMS command-line arguments!"
fi

View File

@ -21,7 +21,6 @@ Cowardly refusing to delete a nonexistent file."
[ ! -f "$file" ] || (rm -f $file; echo "File \"$file\" deleted.")
# OR LIST, to delete file if present.
# ( command1 ; command2 ) is, in effect, an AND LIST variant.
# Note logic inversion above.
# AND LIST executes on true, OR LIST on false.

View File

@ -17,6 +17,9 @@ then
fi
cmp $1 $2 &> /dev/null # /dev/null buries the output of the "cmp" command.
# cmp -s $1 $2 has same result ("-s" silent flag to "cmp")
# Thank you Anders Gustavsson for pointing this out.
#
# Also works with 'diff', i.e., diff $1 $2 &> /dev/null
if [ $? -eq 0 ] # Test exit status of "cmp" command.

View File

@ -37,4 +37,21 @@ done &lt;/etc/passwd # I/O redirection.
IFS=$OIFS # Restore originial $IFS.
# This code snippet also by Heiner Steven.
# Setting the $IFS variable within the loop itself
#+ eliminates the need for storing the original $IFS
#+ in a temporary variable.
# Thanks, Dim Segebart, for pointing this out.
echo "------------------------------------------------"
echo "List of all users:"
while IFS=: read name passwd uid gid fullname ignore
do
echo "$name ($fullname)"
done &lt;/etc/passwd # I/O redirection.
echo
echo "\$IFS still $IFS"
exit 0