This commit is contained in:
gferg 2009-01-22 14:43:09 +00:00
parent 54b9f39293
commit dc5f74fc57
26 changed files with 1584 additions and 518 deletions

View File

@ -3,18 +3,80 @@
Release History
The latest version of this file is available on-line at
http://personal.riverusers.com/~thegrendel/Change.log
http://http://bash.neuralshortcircuit.com/Change.log
==================================================================
Current version = 5.5
Dated 11/23/08
http://personal.riverusers.com/~thegrendel/abs-guide-5.5.tar.bz2
http://personal.riverusers.com/~thegrendel/abs-guide.pdf
Current version = 5.6
Dated 01/26/09
http://bash.neuralshortcircuit.com/abs-guide-latest.tar.bz2
http://bash.neuralshortcircuit.com/abs-guide.pdf
--------------------------------------------------------------------
News: Mostly a bugfix release. A fair amount of new material added.
News: Added Knight's Tour script (ktour.sh),
Magic Square script (msquare.sh).
--------------------------------------------------------------------
Remarks: Gradually adding in-line definitions for technical terms,
usually as sidebars, less often as footnotes.
====================================================================
Version 5.6, Worcesterberry release
01/26/09
1) In "Special Characters" chapter:
At "#" (comments) entry, added example of comment embedded within a pipe.
At "semicolon" entry, slightly revised comments.
Corrected a typo in "filter" footnote ("rougly").
At "$IFS" entry, added sidebar defining the term "field."
2) In "Variables Revisited" chapter:
In "Manipulating Strings" section:
* Expanded first inline
"Substring Replacement example, thanks to the suggestion from
Zhiyi Liu. Also added explanatory footnote.
* Fixed minor typo in "rand-string.sh" example script.
(Thank you, Ethan Larson, for bringing it to my attention.)
3) In "Internal Commands and Builtins" chapter:
At "let" reference, inserted footnote that the command cannot be used
for setting string variables.
4) In "Regular Expressions" chapter:
Added example snippet of use of POSIX character classes
(excerpted from ktour.sh example).
5) In "Gotchas" chapter:
Added entry about misuse of "let" command to set string variables.
6) In "Contributed Scripts" appendix:
Added "ktour.sh" -- Knight's Tour -- example script.
Added "msquare.sh" -- Magic Square -- example script.
7) In "Bibliography" section:
Added http://bashcookbook.com entry.
Word usage cleanups in a couple of entries.
8) Moved the download and mirror site URLs from the title page
to the "Download and Mirror Sites" appendix (where they rightfully
belong!).
Removed http://personal.riverusers/~thegrendel/ URL.
In Download and Mirror Sites" appendix:
Gave Ronny Bangsund credit for graciously donating server space for
a mirror site.
Removed stale www.morethan.org URL.
Updated document author's e-mal.
9) Updated sample "bashrc" file (Appendix K).
10) Cleanups/fixups to main text, appendices, and script examples where
appropriate.
Version 5.5, Farkleberry release
11/28/08
@ -28,7 +90,7 @@ Version 5.5, Farkleberry release
In "Quoting Variables" subsection, simplified introductory
paragraph to eliminate confusion.
4 ) In "Special Characters" chapter:
4) In "Special Characters" chapter:
At "comma operator" entry, added discussion and usage example
for string concatenation.
(Thank you, Rory Winston!)

View File

@ -1378,6 +1378,9 @@
returns <firstterm>unsuccessful</firstterm> (1) <link
linkend="exitstatusref">exit status</link></para>
<para><link linkend="fieldref">Field</link>, a group of characters
that comprises an item of data</para>
<para><link linkend="filearchiv">Files / Archiving</link></para>
<para><link linkend="fdref">File descriptors</link></para>
@ -1495,8 +1498,12 @@
linkend="cards">Dealing a deck of cards</link></para></listitem>
<listitem><para><link
linkend="horserace">Horse race</link></para></listitem>
<listitem><para><link
linkend="ktour">Knight's Tour</link></para></listitem>
<listitem><para><link linkend="lifeslow"><quote>Life</quote>
game</link></para></listitem>
<listitem><para><link
linkend="msquare">Magic Squares</link></para></listitem>
<listitem><para><link linkend="musicscr">Music-playing
script</link></para></listitem>
<listitem><para><link linkend="nim">Nim</link></para></listitem>
@ -2071,6 +2078,9 @@
<listitem><para><link linkend="catabuse">Avoiding
unnecessary commands</link> in a
<firstterm>pipe</firstterm></para></listitem>
<listitem><para><link
linkend="comminpipe"><firstterm>Comments</firstterm> embedded
within</link></para></listitem>
<listitem><para><link linkend="pipefailref">Pipefail</link>,
<firstterm>set -o pipefail</firstterm>
option to indicate <link linkend="exitstatusref">exit status</link>
@ -2126,6 +2136,9 @@
within <firstterm>test</firstterm> brackets</para></listitem>
<listitem><para><link linkend="gnuref"><firstterm>GNU</firstterm>
command set</link>, in cross-platform scripts</para></listitem>
<listitem><para><firstterm>let</firstterm> misuse:
<link linkend="letbad">attempting to set string variables</link>
</para></listitem>
<listitem><para><link linkend="rvtcaution2">Multiple echo
statements</link> in a <link linkend="rvt">function whose
output is captured</link></para></listitem>

View File

@ -54,7 +54,7 @@ cdll (lines 51-53, 59, 63-69, 82-83, 85, 463, 521, 567-568, 570,
580-586, 637, 656-658)
directory-info.sh (lines 36, 166, 273 and 353)
is-spammer.sh (comments on lines 4, 35, and 51)
bashrc (comments on lines 596 and 618)
bashrc (comment on line 4)
commentblock.sh (lines 4 and 23)
self-document.sh (line 14)
self-document2.sh (line 8)
@ -103,8 +103,8 @@ qky.sh
line 63
line 87
line 113
(The unaltered, executable script can be downloaded. See:
http://personal.riverusers.com/~thegrendel/qky.README.html)
(The unaltered, executable script can be downloaded.
See: http://bash.neuralshortcircuit.com/qky.README.html)
maned.sh
line 6 (comment)

View File

@ -358,6 +358,8 @@
<!ENTITY petals SYSTEM "petals.sh">
<!ENTITY qky SYSTEM "qky.sh">
<!ENTITY maned SYSTEM "maned.sh">
<!ENTITY ktour SYSTEM "ktour.sh">
<!ENTITY msquare SYSTEM "msquare.sh">
<!ENTITY nim SYSTEM "nim.sh">
<!ENTITY stddev SYSTEM "sd.sh">
<!ENTITY gen0data SYSTEM "gen0">
@ -377,26 +379,19 @@
<surname>Cooper</surname>
<affiliation>
<orgname></orgname>
<address><email>thegrendel@theriver.com</email></address>
<address><email>thegrendel.abs@gmail.com</email></address>
</affiliation>
</author>
<releaseinfo>5.5</releaseinfo>
<pubdate>23 November 2008</pubdate>
<releaseinfo>5.6</releaseinfo>
<pubdate>26 January 2009</pubdate>
<isbn>978-1-4357-5219-1</isbn>
<revhistory>
<revision>
<revnumber>5.3</revnumber>
<date>05 May 2008</date>
<authorinitials>mc</authorinitials>
<revremark>'GOLDENBERRY' release: Minor Update.</revremark>
</revision>
<revision>
<revnumber>5.4</revnumber>
<date>21 July 2008</date>
@ -411,6 +406,13 @@
<revremark>'FARKLEBERRY' release: Minor Update.</revremark>
</revision>
<revision>
<revnumber>5.6</revnumber>
<date>26 Jan 2009</date>
<authorinitials>mc</authorinitials>
<revremark>'WORCESTERBERRY' release: Minor Update.</revremark>
</revision>
</revhistory>
@ -430,22 +432,6 @@
<para>This book is suitable for classroom use as a general
introduction to programming concepts.</para>
<para><anchor id="where_tarball"></para>
<para><ulink
url="http://personal.riverusers.com/~thegrendel/abs-guide-5.5.tar.bz2">
The latest update of this document</ulink>, as an archived, <link
linkend="bzipref">bzip2-ed</link> <quote>tarball</quote>
including both the SGML source and rendered HTML, may
be downloaded from the author's home site. A <ulink
url="http://www.tldp.org/LDP/abs/abs-guide.pdf">pdf
version</ulink> is also available (<ulink
url="http://personal.riverusers.com/~thegrendel/abs-guide.pdf"> pdf mirror
site</ulink>). See the <ulink
url="http://personal.riverusers.com/~thegrendel/Change.log">change
log</ulink> for a revision history.</para>
</abstract>
</bookinfo>
@ -660,16 +646,17 @@
give them <firstterm>execute</firstterm> permission
(<userinput>chmod u+rx scriptname</userinput>),
then run them to see what happens. Should the source
archive not be available, then cut-and-paste from the <ulink
then run them to see what happens. Should the <ulink
url="http://bash.neuralshortcircuit.com/abs-guide-latest.tar.bz2">source
archive</ulink> not be available, then cut-and-paste from the <ulink
url="http://www.tldp.org/LDP/abs/abs-guide.html.tar.gz">HTML</ulink> or
<ulink url="http://www.tldp.org/LDP/abs/abs-guide.pdf">pdf</ulink>
<ulink url="http://bash.neuralshortcircuit.com/abs-guide.pdf">pdf</ulink>
rendered versions. Be aware that some of the scripts presented here
introduce features before they are explained, and this may require
the reader to temporarily skip ahead for enlightenment.</para>
<para>Unless otherwise noted, <ulink
url="mailto:thegrendel@theriver.com">the author</ulink> of this
url="mailto:thegrendel.abs@gmail.com">the author</ulink> of this
book wrote the example scripts that follow.</para>
<epigraph>
@ -1056,12 +1043,23 @@ fi</programlisting>
<para><programlisting>echo "A comment will follow." # Comment here.
# ^ Note whitespace before #</programlisting></para>
<para><anchor id="wsbcomm"></para>
<para>Comments may also follow <link
linkend="whitespaceref">whitespace</link> at the beginning
of a line.</para>
<para><anchor id="wsbcomm"> Comments may also follow <link
linkend="whitespaceref">whitespace</link> at the beginning
of a line.</para>
<para>
<programlisting># A tab precedes this comment.</programlisting>
</para>
<para><anchor id="comminpipe">Comments may even be embedded
within a <link linkend="piperef">pipe</link>.</para>
<para>
<programlisting>initial=( `cat "$startfile" | sed -e '/#/d' | tr -d '\n' |\
# Delete lines containing '#' comment character.
sed -e 's/\./\. /g' -e 's/_/_ /g'` )
# Excerpted from life.sh script</programlisting>
</para>
<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,
@ -1118,10 +1116,10 @@ echo $(( 2#101011 )) # Base conversion, not a comment.
<programlisting>echo hello; echo there
if [ -x "$filename" ]; then # Note that "if" and "then" need whitespace
#+ separation. Why?
if [ -x "$filename" ]; then # Note the space after the semicolon.
#+ ^^
echo "File $filename exists."; cp $filename $filename.bak
else
else # ^^
echo "File $filename not found."; touch $filename
fi; echo "File test complete."</programlisting>
</para>
@ -1522,7 +1520,8 @@ fi</programlisting>
<programlisting>: This is a comment that generates an error, ( if [ $x -eq 3] ).</programlisting>
</para>
<para>The <quote><token>:</token></quote> also serves as a field
<para>The <quote><token>:</token></quote> also serves as a <link
linkend="fieldref">field</link>
separator, in <link
linkend="datafilesref1"><filename>/etc/passwd</filename></link>,
and in the <link linkend="pathref">$PATH</link> variable.
@ -1890,12 +1889,12 @@ echo $var2 # 23skidoo</programlisting>
</para>
<para><anchor id="processref"></para>
<para>
Definition: A <firstterm>process</firstterm> is
an executing program, sometimes referred to as a
<firstterm>job</firstterm>.
</para>
</footnote>
of the script in which it appears.</para>
<userinput>Definition:</userinput> A
<firstterm>process</firstterm> is a currently
executing program, sometimes referred to as a
<firstterm>job</firstterm>. </para>
</footnote>
of the script in which it appears.</para>
</formalpara>
</listitem>
@ -2473,7 +2472,7 @@ cat *.lst | sort | uniq
<firstterm>philtre</firstterm> denoted a potion alleged
to have magical transformative powers, so does a UNIX
<firstterm>filter</firstterm> transform its target in
(rougly) analogous fashion. (The coder who comes up with a
(roughly) analogous fashion. (The coder who comes up with a
<quote>love philtre</quote> that runs on a Linux machine
will likely win accolades and honors.)</para></footnote>
</para>
@ -3376,7 +3375,9 @@ echo &lt;Ctl-V&gt;&lt;Ctl-J&gt;</programlisting></para>
<varlistentry>
<term><anchor id="whitespaceref">Whitespace</term>
<listitem>
<formalpara><title>functions as a separator, separating commands or variables.</title>
<formalpara>
<title>functions as a separator between commands and/or
variables.</title>
<para>Whitespace consists of either
<firstterm>spaces</firstterm>,
<firstterm>tabs</firstterm>, <firstterm>blank
@ -3398,8 +3399,19 @@ echo &lt;Ctl-V&gt;&lt;Ctl-J&gt;</programlisting></para>
sections.</para>
<para><link linkend="ifsref">$IFS</link>, the special variable
separating fields of input to certain commands, defaults
to whitespace.</para>
separating <firstterm>fields</firstterm> of input to certain
commands. It defaults to whitespace.</para>
<sidebar><para>
<anchor id="fieldref"><userinput>Definition:</userinput>
A <firstterm>field</firstterm> is a discrete chunk of data
expressed as a string of consecutive characters.
Separating each field from adjacent fields is either
<firstterm>whitespace</firstterm> or some other designated
character (often determined by the <token>$IFS</token>).
In some contexts, a field may be called a
<firstterm>record</firstterm>.
</para></sidebar>
<para><anchor id="quotingws"></para>
<para>To preserve <firstterm>whitespace</firstterm>
@ -3751,10 +3763,11 @@ arch=$(uname -m)</programlisting></para>
<emphasis><link linkend="forkref">Child processes</link>
cannot export variables back to the parent processes that
spawned them.</emphasis></para>
<para><anchor id="childref2">Definition: A <firstterm>child
process</firstterm> is a subprocess launched by another
process, its <link linkend="parentref">parent</link>.</para>
</note>
<para><anchor id="childref2"><userinput>Definition:</userinput>
A <firstterm>child process</firstterm> is a
subprocess launched by another process, its <link
linkend="parentref">parent</link>.</para>
</note>
</listitem>
@ -4876,7 +4889,7 @@ fi
# The very useful "if-grep" construct:
# -----------------------------------
if grep -q Bash file
then echo "File contains at least one occurrence of Bash."
then echo "File contains at least one occurrence of Bash."
fi
word=Linux
@ -4891,8 +4904,8 @@ fi
if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED
then echo "Command succeeded."
else echo "Command failed."
then echo "Command succeeded."
else echo "Command failed."
fi</programlisting>
</para>
</listitem>
@ -6894,8 +6907,9 @@ echo "FUNCNAME = $FUNCNAME" # FUNCNAME =
</indexterm>
<listitem><para>internal field separator</para>
<para>This variable determines how Bash recognizes fields, or word
boundaries, when it interprets character strings.</para>
<para>This variable determines how Bash recognizes <link
linkend="fieldref">fields</link>, or word boundaries,
when it interprets character strings.</para>
<para><anchor id="ifsws"></para>
<para>$IFS defaults to <link
@ -6982,13 +6996,13 @@ echo "FUNCNAME = $FUNCNAME" # FUNCNAME =
</indexterm>
<listitem>
<para>Often set in the <filename>.bashrc</filename> or
<filename>/etc/profile</filename> files, this
<para>Often set in the <link
linkend="sample-bashrc"<filename>.bashrc</filename></link>
or <filename>/etc/profile</filename> files, this
variable controls collation order in filename
expansion and pattern matching. If mishandled,
<varname>LC_COLLATE</varname> can cause unexpected results
in <link linkend="globbingref">filename
globbing</link>.</para>
<varname>LC_COLLATE</varname> can cause unexpected results in
<link linkend="globbingref">filename globbing</link>.</para>
<note><para>As of version 2.05 of Bash,
filename globbing no longer distinguishes between lowercase
@ -7138,8 +7152,9 @@ echo "Last command argument processed = $last_cmd_arg"
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>
and/or <link
linkend="sample-bashrc"><filename>~/.bashrc</filename></link>
(see <xref linkend="files">).</para>
<para><screen><prompt>bash$ </prompt><command>echo $PATH</command>
<computeroutput>/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin</computeroutput></screen>
@ -8540,9 +8555,17 @@ echo ${stringZ%%b*c} # a
</indexterm>
<listitem>
<para>Replace first match of
<para>
Replace first <firstterm>match</firstterm> of
<replaceable>$substring</replaceable> with
<replaceable>$replacement</replaceable>.</para>
<replaceable>$replacement</replaceable>.
<footnote><para>Note that
<replaceable>$substring</replaceable> and
<replaceable>$replacement</replaceable> may refer to
either <firstterm>literal strings</firstterm> or
<firstterm>variables</firstterm>, depending on
context. See the first usage example.</para></footnote>
</para>
</listitem>
</varlistentry>
@ -8563,15 +8586,30 @@ echo ${stringZ%%b*c} # a
<para>
<programlisting>stringZ=abcABC123ABCabc
echo ${stringZ/abc/xyz} # xyzABC123ABCabc
# Replaces first match of 'abc' with 'xyz'.
echo ${stringZ/abc/xyz} # xyzABC123ABCabc
# Replaces first match of 'abc' with 'xyz'.
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
# Replaces all matches of 'abc' with # 'xyz'.
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
# Replaces all matches of 'abc' with # 'xyz'.
echo ---------------
echo "$stringZ" # abcABC123ABCabc
echo ---------------
# The string itself is not altered!
# Can the match and replacement strings be parameterized?
match=abc
repl=000
echo ${stringZ/$match/$repl} # 000ABC123ABCabc
# ^ ^ ^^^
echo ${stringZ//$match/$repl} # 000ABC123ABC000
# Yes! ^ ^ ^^^ ^^^
echo
# What happens if no $replacement string is supplied?
echo ${stringZ/abc} # ABC123ABCabc
echo ${stringZ//abc} # ABC123ABC
echo ${stringZ/abc} # ABC123ABCabc
echo ${stringZ//abc} # ABC123ABC
# A simple deletion takes place.</programlisting>
</para>
@ -12036,9 +12074,16 @@ while read f; do
<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>
<para>The <command>let</command> command carries out
<firstterm>arithmetic</firstterm> operations on variables.
<footnote><para>Note that <firstterm>let</firstterm>
<link linkend="letbad">cannot be used
for setting <firstterm>string</firstterm>
variables.</link></para></footnote>
In many cases, it functions as a less complex version
of <link linkend="exprref">expr</link>.</para>
<example id="ex46">
<title>Letting <firstterm>let</firstterm> do arithmetic.</title>
@ -12167,7 +12212,8 @@ eval eval echo $a # d
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>
<link linkend="fieldref">fields</link> of the command
output.</para>
<example id="ex34">
<title>Using <firstterm>set</firstterm> with positional
@ -14997,8 +15043,9 @@ OneYearAgo=$(date --date='1 year ago')</programlisting></para>
<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
<para>A tool for extracting <link
linkend="fieldref">fields</link> from files. It is similar
to the <userinput>print $N</userinput> command set in <link
linkend="awkref">awk</link>, but more limited. It may be
simpler to use <firstterm>cut</firstterm> in a script than
<firstterm>awk</firstterm>. Particularly important are the
@ -15100,10 +15147,11 @@ done
<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>
with a common tagged <link linkend="fieldref">field</link>
(usually a numerical label), and writes the result to
<filename>stdout</filename>. The files to be joined should
be sorted according to the tagged field for the matchups
to work properly.</para>
<para><programlisting>File: 1.data
@ -15558,8 +15606,9 @@ Here is some text.</programlisting>
<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>
manipulating and/or extracting <link
linkend="fieldref">fields</link> (columns) in structured
text files. Its syntax is similar to C.</para>
</listitem>
</varlistentry>
@ -22823,7 +22872,8 @@ mount -o loop /dev/loop0 /mnt # Mount it.
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>
ls'</command> in a user's <link
linkend="sample-bashrc"><filename>~/.bashrc</filename></link>
effectively restricts which portion of the filesystem
she may run command <quote>XX</quote> on.</para>
@ -22856,12 +22906,14 @@ mount -o loop /dev/loop0 /mnt # Mount it.
<secondary>lockfile</secondary>
</indexterm>
<listitem>
<para>This utility is part of the <command>procmail</command>
<para>This utility is part of the <command>procmail</command>
package (<ulink url="http://www.procmail.org">www.procmail.org</ulink>).
It creates a <firstterm>lock file</firstterm>, a
<firstterm>semaphore</firstterm>
<firstterm>semaphore</firstterm> that controls access to
a file, device, or resource.</para>
<footnote><para><anchor id="semaphoreref">Definition:
<sidebar><para><anchor id="semaphoreref">
<userinput>Definition:</userinput>
A <firstterm>semaphore</firstterm> is a flag or
signal. (The usage originated in railroading, where a
colored flag, lantern, or striped movable arm
@ -22869,13 +22921,13 @@ mount -o loop /dev/loop0 /mnt # Mount it.
particular track was in use and therefore unavailable
for another train.) A UNIX process can check the
appropriate semaphore to determine whether a particular
resource is available/accessible.</para></footnote>
resource is available/accessible.</para></sidebar>
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 process (it is
<quote>busy</quote>), and this permits only restricted
access (or no access) to other processes.</para>
<para>The lock file serves as a flag that this particular
file, device, or resource is in use by a process (and
is therefore <quote>busy</quote>). The presence of a
lock file permits only restricted access (or no access)
to other processes.</para>
<para><programlisting>lockfile /home/bozo/lockfiles/$0.lock
# Creates a write-protected lockfile prefixed with the name of the script.
@ -22887,7 +22939,7 @@ lockfile /home/bozo/lockfiles/${0##*/}.lock
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.
<application>Firefox</application> is using its cache.
Scripts may check for the existence of a lock file created
by a certain process to check if that process is running.
Note that if a script attempts to create a lock file that
@ -24213,10 +24265,10 @@ echo a111b | gawk '/a1+b/'
<userinput>0-9A-Fa-f</userinput>.</para>
<important>
<para>POSIX character classes generally require quoting
or <link linkend="dblbrackets">double brackets</link>
([[ ]]).</para>
</important>
<para>
<screen><prompt>bash$ </prompt><userinput>grep [[:digit:]] test.file</userinput>
@ -24224,6 +24276,14 @@ echo a111b | gawk '/a1+b/'
</screen>
</para>
<para><programlisting># ...
if [[ $arow =~ [[:digit:]] ]] # Numerical input?
then # POSIX char class
if [[ $acol =~ [[:alpha:]] ]] # Number followed by a letter? Illegal!
# ...
# From ktour.sh example script.</programlisting>
</para>
<para>These character classes may even be used with <link
linkend="globbingref">globbing</link>, to a limited
extent.</para>
@ -24234,10 +24294,9 @@ echo a111b | gawk '/a1+b/'
</screen>
</para>
<para>To see POSIX character classes used in scripts, refer to
<para>POSIX character classes are used in
<xref linkend="ex49"> and <xref linkend="lowercase">.</para>
</important>
</listitem>
@ -24297,7 +24356,8 @@ echo a111b | gawk '/a1+b/'
<anchor id="wdotfilewc">There are important limitations on wild
card characters in globbing, however. Strings containing
<replaceable>*</replaceable> will not match filenames that
start with a dot, as, for example, <filename>.bashrc</filename>.
start with a dot, as, for example, <link
linkend="sample-bashrc"><filename>.bashrc</filename></link>.
<footnote>
<para>
@ -25230,7 +25290,8 @@ echo "$nr files totaling $totalSize bytes"</programlisting>
<firstterm>subshell</firstterm>.</para>
<sidebar>
<para>Definition: A <firstterm>subshell</firstterm> is a
<para><userinput>Definition:</userinput>
A <firstterm>subshell</firstterm> is a
<link linkend="childref2">child process</link> launched by a
shell (or <firstterm>shell script</firstterm>).</para>
</sidebar>
@ -25334,7 +25395,7 @@ but is shown here for illustrative purposes.</programlisting>
<sidebar>
<para><anchor id="scoperef"></para>
<para><emphasis>Definition:</emphasis> The
<para><userinput>Definition:</userinput> The
<firstterm>scope</firstterm> of a variable is the
context in which it has meaning, in which it has a
<firstterm>value</firstterm> that can be referenced. For
@ -26285,6 +26346,11 @@ Function () # This doesn't work.
# Thanks, S.C.</programlisting>
</para>
<note><para>Emmanuel Rouat's <link
linkend="sample-bashrc">sample <filename>bashrc</filename>
file</link> contains some instructive examples of
functions.</para></note>
</listitem>
</varlistentry>
@ -26483,7 +26549,7 @@ exit 0 # This script will not exit normally.
more than a keyboard shortcut, an abbreviation, a means of
avoiding typing a long command sequence. If, for example,
we include <command>alias lm="ls -l | more"</command> in
the <link linkend="filesref1"><filename>~/.bashrc</filename>
the <link linkend="sample-bashrc"><filename>~/.bashrc</filename>
file</link>, then each <userinput>lm</userinput>
<footnote><para> ... as the first word of a command string.
Obviously, an alias is only meaningful at the
@ -28358,6 +28424,14 @@ fi # Aborts with an error message.
</example>
</listitem>
<listitem>
<para><anchor id="letbad"></para>
<para>Attempting to use <link linkend="letref">let</link>
to set string variables.</para>
<para><programlisting>let "a = hello, you"
echo "$a" # 0</programlisting></para>
</listitem>
<listitem>
<para><anchor id="failquote"></para>
@ -28433,10 +28507,11 @@ fi
<listitem>
<para>Using Bash-specific functionality in a Bourne shell script
<para>Using Bash-specific functionality in a <link
linkend="bashdef">Bourne shell</link> script
(<userinput>#!/bin/sh</userinput>) on a non-Linux machine
<link linkend="binsh">may cause unexpected behavior</link>. A
Linux system usually aliases <command>sh</command> to
<link linkend="binsh">may cause unexpected behavior</link>.
A Linux system usually aliases <command>sh</command> to
<command>bash</command>, but this does not necessarily hold true
for a generic UNIX machine.</para> </listitem>
@ -30444,8 +30519,8 @@ echo "User entered: "$answer""</programlisting>
utilities has accelerated the trend.</para>
<para><anchor id="bashcompat"></para>
<para>Bash has certain features that the traditional Bourne shell
lacks. Among these are:
<para>Bash has certain features that the traditional <link
linkend="bashdef">Bourne shell</link> lacks. Among these are:
<itemizedlist>
@ -30888,7 +30963,8 @@ echo $a # 6</programlisting>
<title>About the Author</title>
<subtitle>Who is this guy anyhow?</subtitle>
<para>The author claims no credentials or special qualifications,
<para><anchor id="nocreds">The author claims no credentials or
special qualifications,
<footnote><para>In fact, he is a school dropout
and has no formal credentials or qualifications
whatsoever.</para></footnote>
@ -30896,7 +30972,7 @@ echo $a # 6</programlisting>
<footnote><para>Those who can, do. Those who can't . . . get an
MCSE.</para></footnote>
This book is somewhat of a departure from his other major work,
<ulink url="http://personal.riverusers.com/~thegrendel/hmw60.zip">
<ulink url="http://bash.neuralshortcircuit.com/hmw60.zip">
HOW-2 Meet Women: The Shy Man's Guide to
Relationships</ulink>. He has also written the <ulink
url="http://tldp.org/HOWTO/Software-Building-HOWTO.html">Software-Building
@ -30914,7 +30990,7 @@ echo $a # 6</programlisting>
Scrabble&reg; adjudicator, the <ulink
url="http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz">yawl</ulink>
word gaming list package, and the <ulink
url="http://personal.riverusers.com/~thegrendel/qky.README.html">Quacky</ulink>
url="http://bash.neuralshortcircuit.com/qky.README.html">Quacky</ulink>
anagramming gaming package. He got off to a rather shaky start in the
computer game -- programming FORTRAN IV on a CDC 3800 --
and is not the least bit nostalgic for those days.</para>
@ -30934,7 +31010,7 @@ echo $a # 6</programlisting>
<sect1 id="wherehelp">
<title>Where to Go For Help</title>
<para><ulink url="mailto:thegrendel@theriver.com">The author</ulink>
<para><ulink url="mailto:thegrendel.abs@gmail.com">The author</ulink>
will sometimes, if not too busy (and in a good mood),
answer general scripting questions.
<footnote><para>E-mails from certain spam-infested TLDs
@ -31130,6 +31206,7 @@ echo $a # 6</programlisting>
<para>Andreas Abraham sent in a long list of typographical
errors and other corrections. Special thanks!</para>
<para>Others contributing scripts, making helpful suggestions, and
pointing out errors were Gabor Kiss, Leopold Toetsch,
Peter Tillier, Marcus Berglof, Tony Richardson, Nick Drage
@ -31279,7 +31356,7 @@ echo $a # 6</programlisting>
familiarity with <link linkend="sedref"><firstterm>sed</firstterm>
and <firstterm>awk</firstterm></link>. This is the standard
tutorial. It includes an excellent introduction to
<quote>regular expressions.</quote> Recommended.</para>
<firstterm>Regular Expressions</firstterm>. Recommended.</para>
<para>*</para>
</abstract>
</biblioentry>
@ -31315,9 +31392,10 @@ echo $a # 6</programlisting>
<year>2002</year>
</copyright>
<isbn>0-596-00343-9</isbn>
<abstract><para>This excellent sys admin manual has a decent introduction to shell
scripting for sys administrators and does a thorough job of explaining the
startup and initialization scripts.</para>
<abstract><para>This excellent manual provides a decent introduction
to shell scripting from a sys admin point of view. It includes
comprehensive explanations of the startup and initialization
scripts in a UNIX system.</para>
<para>*</para>
<para><anchor id="kochanref"></para>
</abstract>
@ -31779,6 +31857,14 @@ echo $a # 6</programlisting>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para><ulink url="http://bashcookbook.com/bashinfo/">Examples</ulink>
from the <citetitle pubwork="book">The Bash Scripting
Cookbook</citetitle>, by Albing, Vossen, and Newham.</para>
</abstract>
</biblioentry>
<biblioentry>
<abstract>
<para>Example shell scripts at <ulink
@ -32417,6 +32503,17 @@ echo $a # 6</programlisting>
<programlisting>&homework;</programlisting>
</example>
<para<anchor id="ktour0"></para>
<example id="ktour">
<title>The Knight's Tour</title>
<programlisting>&ktour;</programlisting>
</example>
<example id="msquare">
<title>Magic Squares</title>
<programlisting>&msquare;</programlisting>
</example>
<example id="usegetopt">
<title>An alternate version of the
<link linkend="getoptsimple">getopt-simple.sh</link> script</title>
@ -33454,7 +33551,8 @@ pattern=BEGIN
a few of these here - the ones most useful in shell scripts.</para>
<para>Awk breaks each line of input passed to it into
<firstterm>fields</firstterm>. By default, a field
<anchor id="fieldref2">
<link linkend="fieldref">fields</link>. By default, a field
is a string of consecutive characters delimited by <link
linkend="whitespaceref">whitespace</link>, though there are options
for changing this. Awk parses and operates on each separate
@ -35082,16 +35180,20 @@ var=$(history); echo "$var" # $var is empty.
<para>
<literallayout>
On a dingy side street in a run-down section of Hoboken, New Jersey,
there sits a nondescript squat two-story brick building
with a inscription incised on a marble plate in its wall:
there sits a nondescript squat two-story brick building with an inscription
incised on a marble plate in its wall:
<computeroutput>Bash Scripting Hall of Fame</computeroutput>.
Inside, among various dusty uninteresting exhibits is a corroding,
cobweb-festooned brass plaque inscribed with a short, very short
list of those few persons who have successfully mastered the material
in the <firstterm>Advanced Bash Scripting Guide</firstterm>,
as evidenced by their performance on the following Exercise sections. . . .
in the <firstterm>Advanced Bash Scripting Guide</firstterm>, as evidenced by their performance
on the following Exercise sections.
(Alas, the author of the <firstterm>ABS Guide</firstterm> is not represented among the exhibits.
This is possibly due to malicious rumors about <link linkend="nocreds">lack of credentials</link> and
<link linkend="ktour0">deficient scripting skills</link>.)
</literallayout>
</para>
@ -35647,8 +35749,8 @@ do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUM</pro
with <firstterm>comma-separated values</firstterm>
(CSVs). Other applications often need to parse these
files.</para>
<para>Given a data file with comma-separated fields,
of the form:
<para>Given a data file with comma-separated <link
linkend="fieldref">fields</link>, of the form:
<programlisting>Jones,Bill,235 S. Williams St.,Denver,CO,80221,(303) 244-7989
Smith,Tom,404 Polk Ave.,Los Angeles,CA,90003,(213) 879-5612
...</programlisting>
@ -35990,13 +36092,13 @@ s c r i p t</programlisting></para>
<listitem>
<para>Do a hex(adecimal) dump on a binary file
specified as an argument. The output should be in neat
tabular fields, with the first field showing the address,
each of the next 8 fields a 4-byte hex number, and the final
field the ASCII equivalent of the previous 8 fields.</para>
<para>The obvious followup to this is to extend the hex dump
script into a disassembler. Using a lookup table, or some other
clever gimmick, convert the hex values into 80x86 op
codes.</para>
tabular <link linkend="fieldref">fields</link>, with the
first field showing the address, each of the next 8 fields a
4-byte hex number, and the final field the ASCII equivalent
of the previous 8 fields.</para> <para>The obvious
followup to this is to extend the hex dump script into a
disassembler. Using a lookup table, or some other clever
gimmick, convert the hex values into 80x86 op codes.</para>
</listitem>
</varlistentry>
@ -36600,6 +36702,11 @@ thegrendel@theriver.com</programlisting></para>
<entry>23 Nov 2008</entry>
<entry>FARKLEBERRY release: Minor update.</entry>
</row>
<row>
<entry><option>5.6</option></entry>
<entry>26 Jan 2009</entry>
<entry>WORCESTERBERRY release: Minor update.</entry>
</row>
</tbody>
</tgroup>
</table>
@ -36608,34 +36715,43 @@ thegrendel@theriver.com</programlisting></para>
</appendix> <!-- End Revision History appendix -->
<appendix id="mirrorsites">
<title>Mirror Sites</title>
<title>Download and Mirror Sites</title>
<para><ulink
url="http://thegrendel.150m.com/abs-guide-5.5.tar.bz2">
The latest update of this document</ulink>, as an archived
<quote>tarball</quote>
including both the SGML source and rendered HTML, may
be downloaded from the <ulink
url="http://personal.riverusers.com/~thegrendel/abs-guide-5.5.tar.bz2">author's
home site</ulink>.</para>
<para><anchor id="where_tarball"></para>
<para>The main mirror site for this document is the <ulink
<para>The latest update of this document, as an archived,
<link linkend="bzipref">bzip2-ed</link>
<quote>tarball</quote> including both the SGML source
and rendered HTML, may be downloaded from the <ulink
url="http://bash.neuralshortcircuit.com/abs-guidelatest.tar.bz2">author's
home site</ulink>).
A <ulink
url="http://bash.neuralshortcircuit.com/abs-guide.pdf">
pdf version</ulink> is also available.
The <ulink
url="http://bash.neuralshortcircuit.com/Change.log">change
log</ulink> gives a detailed revision history.
The <emphasis>ABS Guide</emphasis> even has <ulink
url="http://freshmeat.net/projects/advancedbashscriptingguide/">
its own <filename>freshmeat.net</filename> page</ulink> to keep
track of major updates, user comments, and popularity ratings
for the project.</para>
<para>The main hosting site for this document is the <ulink
url="http://www.tldp.org/LDP/abs/">Linux Documentation Project</ulink>,
which maintains many other Guides and HOWTOs as well.</para>
<para>Yet another mirror site for this document is
<ulink url="http://www.morethan.org">morethan.org</ulink>.</para>
<para>You can download the <emphasis>pdf</emphasis> version
<ulink
url="http://personal.riverusers.com/~thegrendel/abs-guide.pdf">
here</ulink>.</para>
<para>Many thanks to Ronny Bangsund for donating <ulink
url="http://bash.neuralshortcircuit.com/">server space</ulink> to host
this project.</para>
</appendix> <!-- Mirror Sites appendix -->
<appendix id="todolist">
<title>To Do List</title>
@ -36643,7 +36759,8 @@ thegrendel@theriver.com</programlisting></para>
<listitem>
<para>A comprehensive survey of <link
linkend="bashcompat">incompatibilities</link> between
Bash and the classic Bourne shell.</para>
Bash and the classic <link linkend="bashdef">Bourne
shell</link>.</para>
</listitem>
<listitem>
@ -36778,7 +36895,7 @@ distributors, or any of its associated software or documentation.</programlistin
<para>The commercial print and other rights to this book are
available. Please contact <ulink
url="mailto:thegrendel@theriver.com">the author</ulink> if
url="mailto:thegrendel.abs@gmail.com">the author</ulink> if
interested.</para>
<para>The author produced this book in a manner consistent with the

View File

@ -16,7 +16,7 @@ grep -v 'ed$' # no past tense verbs
# Uses "anagram" utility
#+ that is part of the author's "yawl" word list package.
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
# http://bash.neuralshortcircuit.com/yawl-0.3.2.tar.gz
exit 0 # End of code.

View File

@ -5,7 +5,7 @@
# Uses "anagram" utility
#+ that is part of the author's "yawl" word list package.
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
# http://bash.neuralshortcircuit.com/yawl-0.3.2.tar.gz
E_NOARGS=66
E_BADARG=67

View File

@ -16,7 +16,7 @@
# ==> Used in ABS Guide with the script author's permission.
# ==> Comments added by ABS Guide author.
NOARGS=65
NOARGS=85
PN=`basename "$0"` # Program name
VER=`echo '$Revision$' | cut -d' ' -f2` # ==> VER=1.2
@ -31,10 +31,10 @@ A number may be
hexadecimal (base 16) starting with 0x (i.e. 0xc)
decimal otherwise (i.e. 12)" >&2
exit $NOARGS
} # ==> Function to print usage message.
} # ==> Prints usage message.
Msg () {
for i # ==> in [list] missing.
for i # ==> in [list] missing. Why?
do echo "$PN: $i" >&2
done
}
@ -55,7 +55,7 @@ PrintBases () {
continue;;
esac
# Remove prefix, convert hex digits to uppercase (bc needs this)
# Remove prefix, convert hex digits to uppercase (bc needs this).
number=`echo "$i" | sed -e 's:^0[bBxX]::' | tr '[a-f]' '[A-F]'`
# ==> Uses ":" as sed separator, rather than "/".
@ -89,15 +89,15 @@ do
--) shift; break;;
-h) Usage;; # ==> Help message.
-*) Usage;;
*) break;; # first number
esac # ==> More error checking for illegal input might be useful.
*) break;; # First number
esac # ==> Error checking for illegal input might be appropriate.
shift
done
if [ $# -gt 0 ]
then
PrintBases "$@"
else # read from stdin
else # Read from stdin.
while read line
do
PrintBases $line
@ -105,4 +105,4 @@ else # read from stdin
fi
exit 0
exit

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ DICT=/usr/share/dict/word.lst
#+ download the author's "yawl" word list package.
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
# or
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
# http://bash.neuralshortcircuit.com/yawl-0.3.2.tar.gz
if [ -z "$1" ] # If no word pattern specified

View File

@ -144,6 +144,12 @@ echo $diff
exit 0
# Exercise:
# --------
# If given only one command-line parameter, have the script
#+ use today's date as the second.
# Compare this script with
#+ the implementation of Gauss' Formula in a C program at
#+ http://buschencrew.hypermart.net/software/datedif

View File

@ -2,7 +2,7 @@
# empty-array.sh
# Thanks to Stephane Chazelas for the original example,
#+ and to Michael Zick, Omair Eshkenazi, for extending it.
#+ and to Michael Zick and Omair Eshkenazi, for extending it.
# And to Nathan Coulter for clarifications and corrections.
@ -115,11 +115,12 @@ echo "Elements in array8: ${array8[@]}"
#+ that element disappears in the resulting assignment.
# However, if the expansion is in quotes, the null elements remain.
# Michael Zick: Question, are those strings hard or soft quotes?
# Nathan Coulter: There is no such thing as "soft quotes."
# What's really happening is that
#+ the pattern matching happens after all the other expansions of [word]
#+ in cases like ${parameter#word}.
# Michael Zick: Question, are those strings hard or soft quotes?
# Nathan Coulter: There is no such thing as "soft quotes."
#! What's really happening is that
#!+ the pattern matching happens after
#!+ all the other expansions of [word]
#!+ in cases like ${parameter#word}.
zap='new*'

View File

@ -1,28 +1,30 @@
#!/bin/bash
# Killing ppp to force a log-off.
# For dialup connection, of course.
# Script should be run as root user.
killppp="eval kill -9 `ps ax | awk '/ppp/ { print $1 }'`"
# -------- process ID of ppp -------
$killppp # This variable is now a command.
# The following operations must be done as root user.
chmod 666 /dev/ttyS3 # Restore read+write permissions, or else what?
# Since doing a SIGKILL on ppp changed the permissions on the serial port,
#+ we restore permissions to previous state.
rm /var/lock/LCK..ttyS3 # Remove the serial port lock file. Why?
# Note:
SERPORT=ttyS3
# Depending on the hardware and even the kernel version,
#+ the modem port on your machine may be different --
#+ /dev/ttyS1 or /dev/ttyS2.
exit 0
killppp="eval kill -9 `ps ax | awk '/ppp/ { print $1 }'`"
# -------- process ID of ppp -------
$killppp # This variable is now a command.
# The following operations must be done as root user.
chmod 666 /dev/$SERPORT # Restore r+w permissions, or else what?
# Since doing a SIGKILL on ppp changed the permissions on the serial port,
#+ we restore permissions to previous state.
rm /var/lock/LCK..$SERPORT # Remove the serial port lock file. Why?
exit $?
# Exercises:
# ---------

View File

@ -102,7 +102,7 @@ Optional environment variables
Additional documentation
Download the archived set of scripts
explaining and illustrating the function contained within this script.
http://personal.riverusers.com/mszick_clf.tar.bz2
http://bash.neuralshortcircuit.com/mszick_clf.tar.bz2
Study notes

View File

@ -0,0 +1,610 @@
#!/bin/bash
# ktour.sh
# author: mendel cooper
# reldate: 12 Jan 2009
# license: public domain
# (Not much sense in GPLing something that's pretty much in the common
#+ domain anyhow.)
###################################################################
# The Knight's Tour, a classic problem. #
# ===================================== #
# The knight must move onto every square of the chess board, #
# but cannot revisit any square he has already visited. #
# #
# And just why is Sir Knight unwelcome for a return visit? #
# Could it be that he has a habit of partying into the wee hours #
#+ of the morning? #
# Possibly he leaves pizza crusts in the bed, empty beer bottles #
#+ all over the floor, and clogs the plumbing. ... #
# #
# ------------------------------------------------------------- #
# #
# Usage: ktour.sh [start-square] [stupid] #
# #
# Note that start-square can be a square number #
#+ in the range 0 - 63 ... or #
# a square designator in conventional chess notation, #
# such as a1, f5, h3, etc. #
# #
# If start-square-number not supplied, #
#+ then starts on a random square somewhere on the board. #
# #
# "stupid" as second parameter sets the stupid strategy. #
# #
# Examples: #
# ktour.sh 23 starts on square #23 (h3) #
# ktour.sh g6 stupid starts on square #46, #
# using "stupid" (non-Warnsdorff) strategy. #
###################################################################
DEBUG= # Set this to echo debugging info to stdout.
SUCCESS=0
FAIL=99
BADMOVE=-999
FAILURE=1
LINELEN=21 # How many moves to display per line.
# ---------------------------------------- #
# Board array params
ROWS=8 # 8 x 8 board.
COLS=8
let "SQUARES = $ROWS * $COLS"
let "MAX = $SQUARES - 1"
MIN=0
# 64 squares on board, indexed from 0 to 63.
VISITED=1
UNVISITED=-1
UNVSYM="##"
# ---------------------------------------- #
# Global variables.
startpos= # Starting position (square #, 0 - 63).
currpos= # Current position.
movenum= # Move number.
CRITPOS=37 # Have to patch for f5 starting position!
declare -i board
# Use a one-dimensional array to simulate a two-dimensional one.
# This can make life difficult and result in ugly kludges; see below.
declare -i moves # Offsets from current knight position.
initialize_board ()
{
local idx
for idx in {0..63}
do
board[$idx]=$UNVISITED
done
}
print_board ()
{
local idx
echo " _____________________________________"
for row in {7..0} # Reverse order of rows ...
do #+ so it prints in chessboard order.
let "rownum = $row + 1" # Start numbering rows at 1.
echo -n "$rownum |" # Mark board edge with border and
for column in {0..7} #+ "algebraic notation."
do
let "idx = $ROWS*$row + $column"
if [ ${board[idx]} -eq $UNVISITED ]
then
echo -n "$UNVSYM " ##
else # Mark square with move number.
printf "%02d " "${board[idx]}"; echo -n " "
fi
done
echo -e -n "\b\b\b|" # \b is a backspace.
echo # -e enables echoing escaped chars.
done
echo " -------------------------------------"
echo " a b c d e f g h"
}
failure()
{ # Whine, then bail out.
echo
print_board
echo
echo " Waah!!! Ran out of squares to move to!"
echo -n " Knight's Tour attempt ended"
echo " on $(to_algebraic $currpos) [square #$currpos]"
echo " after just $movenum moves!"
echo
exit $FAIL
}
xlat_coords () # Translate x/y coordinates to board position
{ #+ (board-array element #).
# For user input of starting board position as x/y coords.
# This function not used in initial release of ktour.sh.
# May be used in an updated version, for compatibility with
#+ standard implementation of the Knight's Tour in C, Python, etc.
if [ -z "$1" -o -z "$2" ]
then
return $FAIL
fi
local xc=$1
local yc=$2
let "board_index = $xc * $ROWS + yc"
if [ $board_index -lt $MIN -o $board_index -gt $MAX ]
then
return $FAIL # Strayed off the board!
else
return $board_index
fi
}
to_algebraic () # Translate board position (board-array element #)
{ #+ to standard algebraic notation used by chess players.
if [ -z "$1" ]
then
return $FAIL
fi
local element_no=$1 # Numerical board position.
local col_arr=( a b c d e f g h )
local row_arr=( 1 2 3 4 5 6 7 8 )
let "row_no = $element_no / $ROWS"
let "col_no = $element_no % $ROWS"
t1=${col_arr[col_no]}; t2=${row_arr[row_no]}
local apos=$t1$t2 # Concatenate.
echo $apos
}
from_algebraic () # Translate standard algebraic chess notation
{ #+ to numerical board position (board-array element #).
# Or recognize numerical input & return it unchanged.
if [ -z "$1" ]
then
return $FAIL
fi # If no command-line arg, then will default to random start pos.
local ix
local ix_count=0
local b_index # Board index [0-63]
local alpos="$1"
arow=${alpos:0:1} # position = 0, length = 1
acol=${alpos:1:1}
if [[ $arow =~ [[:digit:]] ]] # Numerical input?
then # POSIX char class
if [[ $acol =~ [[:alpha:]] ]] # Number followed by a letter? Illegal!
then return $FAIL
else if [ $alpos -gt $MAX ] # Off board?
then return $FAIL
else return $alpos # Return digit(s) unchanged . . .
fi #+ if within range.
fi
fi
if [[ $acol -eq $MIN || $acol -gt $ROWS ]]
then # Outside of range 1 - 8?
return $FAIL
fi
for ix in a b c d e f g h
do # Convert column letter to column number.
if [ "$arow" = "$ix" ]
then
break
fi
((ix_count++)) # Find index count.
done
((acol--)) # Decrementing converts to zero-based array.
let "b_index = $ix_count + $acol * $ROWS"
if [ $b_index -gt $MAX ] # Off board?
then
return $FAIL
fi
return $b_index
}
generate_moves () # Calculate all valid knight moves,
{ #+ relative to current position ($1),
#+ and store in ${moves} array.
local kt_hop=1 # One square :: short leg of knight move.
local kt_skip=2 # Two squares :: long leg of knight move.
local valmov=0 # Valid moves.
local row_pos; let "row_pos = $1 % $COLS"
let "move1 = -$kt_skip + $ROWS" # 2 sideways to-the-left, 1 up
if [[ `expr $row_pos - $kt_skip` -lt $MIN ]] # An ugly, ugly kludge!
then # Can't move off board.
move1=$BADMOVE # Not even temporarily.
else
((valmov++))
fi
let "move2 = -$kt_hop + $kt_skip * $ROWS" # 1 sideways to-the-left, 2 up
if [[ `expr $row_pos - $kt_hop` -lt $MIN ]] # Kludge continued ...
then
move2=$BADMOVE
else
((valmov++))
fi
let "move3 = $kt_hop + $kt_skip * $ROWS" # 1 sideways to-the-right, 2 up
if [[ `expr $row_pos + $kt_hop` -ge $COLS ]]
then
move3=$BADMOVE
else
((valmov++))
fi
let "move4 = $kt_skip + $ROWS" # 2 sideways to-the-right, 1 up
if [[ `expr $row_pos + $kt_skip` -ge $COLS ]]
then
move4=$BADMOVE
else
((valmov++))
fi
let "move5 = $kt_skip - $ROWS" # 2 sideways to-the-right, 1 dn
if [[ `expr $row_pos + $kt_skip` -ge $COLS ]]
then
move5=$BADMOVE
else
((valmov++))
fi
let "move6 = $kt_hop - $kt_skip * $ROWS" # 1 sideways to-the-right, 2 dn
if [[ `expr $row_pos + $kt_hop` -ge $COLS ]]
then
move6=$BADMOVE
else
((valmov++))
fi
let "move7 = -$kt_hop - $kt_skip * $ROWS" # 1 sideways to-the-left, 2 dn
if [[ `expr $row_pos - $kt_hop` -lt $MIN ]]
then
move7=$BADMOVE
else
((valmov++))
fi
let "move8 = -$kt_skip - $ROWS" # 2 sideways to-the-left, 1 dn
if [[ `expr $row_pos - $kt_skip` -lt $MIN ]]
then
move8=$BADMOVE
else
((valmov++))
fi # There must be a better way to do this.
local m=( $valmov $move1 $move2 $move3 $move4 $move5 $move6 $move7 $move8 )
# ${moves[0]} = number of valid moves.
# ${moves[1]} ... ${moves[8]} = possible moves.
echo "${m[*]}" # Elements of array to stdout for capture in a var.
}
is_on_board () # Is position actually on the board?
{
if [[ "$1" -lt "$MIN" || "$1" -gt "$MAX" ]]
then
return $FAILURE
else
return $SUCCESS
fi
}
do_move () # Move the knight!
{
local valid_moves=0
local aapos
currposl="$1"
lmin=$ROWS
iex=0
squarel=
mpm=
mov=
declare -a p_moves
########################## DECIDE-MOVE #############################
if [ $startpos -ne $CRITPOS ]
then # CRITPOS = square #37
decide_move
else # Needs a special patch for startpos=37 !!!
decide_move_patched # Why this particular move and no other ???
fi
####################################################################
(( ++movenum )) # Increment move count.
let "square = $currposl + ${moves[iex]}"
################## DEBUG ###############
if [ "$DEBUG" ]
then debug # Echo debugging information.
fi
##############################################
if [[ "$square" -gt $MAX || "$square" -lt $MIN ||
${board[square]} -ne $UNVISITED ]]
then
(( --movenum )) # Decrement move count,
echo "RAN OUT OF SQUARES!!!" #+ since previous one was invalid.
return $FAIL
fi
board[square]=$movenum
currpos=$square # Update current position.
((valid_moves++)); # moves[0]=$valid_moves
aapos=$(to_algebraic $square)
echo -n "$aapos "
test $(( $Moves % $LINELEN )) -eq 0 && echo
# Print LINELEN=21 moves per line. A valid tour shows 3 complete lines.
return $valid_moves # Found a square to move to!
}
do_move_stupid() # Dingbat algorithm,
{ #+ courtesy of script author, *not* Warnsdorff.
local valid_moves=0
local movloc
local squareloc
local aapos
local cposloc="$1"
for movloc in {1..8}
do # Move to first-found unvisited square.
let "squareloc = $cposloc + ${moves[movloc]}"
is_on_board $squareloc
if [ $? -eq $SUCCESS ] && [ ${board[squareloc]} -eq $UNVISITED ]
then # Add conditions to above if-test to improve algorithm.
(( ++movenum ))
board[squareloc]=$movenum
currpos=$squareloc # Update current position.
((valid_moves++)); # moves[0]=$valid_moves
aapos=$(to_algebraic $squareloc)
echo -n "$aapos "
test $(( $Moves % $LINELEN )) -eq 0 && echo # Print 21 moves/line.
return $valid_moves # Found a square to move to!
fi
done
return $FAIL
# If no square found in all 8 loop iterations,
#+ then Knight's Tour attempt ends in failure.
# Dingbat algorithm will typically fail after about 30 - 40 moves,
#+ but executes _much_ faster than Warnsdorff's in do_move() function.
}
decide_move () # Which move will we make?
{ # But, fails on startpos=37 !!!
for mov in {1..8}
do
let "squarel = $currposl + ${moves[mov]}"
is_on_board $squarel
if [[ $? -eq $SUCCESS && ${board[squarel]} -eq $UNVISITED ]]
then # Find accessible square with least possible future moves.
# This is Warnsdorff's algorithm.
# What happens is that the knight wanders toward the outer edge
#+ of the board, then pretty much spirals inward.
# Given two or more possible moves with same value of
#+ least-possible-future-moves, this implementation chooses
#+ the _first_ of those moves.
# This means that there is not necessarily a unique solution
#+ for any given starting position.
possible_moves $squarel
mpm=$?
p_moves[mov]=$mpm
if [ $mpm -lt $lmin ] # If less than previous minimum ...
then # ^^
lmin=$mpm # Update minimum.
iex=$mov # Save index.
fi
fi
done
}
decide_move_patched () # Decide which move to make,
{ # ^^^^^^^ #+ but only if startpos=37 !!!
for mov in {1..8}
do
let "squarel = $currposl + ${moves[mov]}"
is_on_board $squarel
if [[ $? -eq $SUCCESS && ${board[squarel]} -eq $UNVISITED ]]
then
possible_moves $squarel
mpm=$?
p_moves[mov]=$mpm
if [ $mpm -le $lmin ] # If less-than-or equal to prev. minimum!
then # ^^
lmin=$mpm
iex=$mov
fi
fi
done # There has to be a better way to do this.
}
possible_moves () # Calculate number of possible moves,
{ #+ given the current position.
if [ -z "$1" ]
then
return $FAIL
fi
local curr_pos=$1
local valid_movl=0
local icx=0
local movl
local sq
declare -a movesloc
movesloc=( $(generate_moves $curr_pos) )
for movl in {1..8}
do
let "sq = $curr_pos + ${movesloc[movl]}"
is_on_board $sq
if [ $? -eq $SUCCESS ] && [ ${board[sq]} -eq $UNVISITED ]
then
((valid_movl++));
fi
done
return $valid_movl # Found a square to move to!
}
strategy ()
{
echo
if [ -n "$STUPID" ]
then
for Moves in {1..63}
do
cposl=$1
moves=( $(generate_moves $currpos) )
do_move_stupid "$currpos"
if [ $? -eq $FAIL ]
then
failure
fi
done
fi
# Don't need an "else" clause here,
#+ because Stupid Strategy will always fail and exit!
for Moves in {1..63}
do
cposl=$1
moves=( $(generate_moves $currpos) )
do_move "$currpos"
if [ $? -eq $FAIL ]
then
failure
fi
done
# Could have condensed above two do-loops into a single one,
echo #+ but this would have slowed execution.
print_board
echo
echo "Knight's Tour ends on $(to_algebraic $currpos) [square #$currpos]."
return $SUCCESS
}
debug ()
{ # Enable this by setting DEBUG=1 near beginning of script.
local n
echo "================================="
echo " At move number $movenum:"
echo " *** possible moves = $mpm ***"
# echo "### square = $square ###"
echo "lmin = $lmin"
echo "${moves[@]}"
for n in {1..8}
do
echo -n "($n):${p_moves[n]} "
done
echo
echo "iex = $iex :: moves[iex] = ${moves[iex]}"
echo "square = $square"
echo "================================="
echo
} # Gives pretty complete status after ea. move.
# =============================================================== #
# int main () {
from_algebraic "$1"
startpos=$?
if [ "$startpos" -eq "$FAIL" ] # Okay even if no $1.
then # ^^^^^^^^^^^ Okay even if input -lt 0.
echo "No starting square specified (or illegal input)."
let "startpos = $RANDOM % $SQUARES" # 0 - 63 permissable range.
fi
if [ "$2" = "stupid" ]
then
STUPID=1
echo -n " ### Stupid Strategy ###"
else
STUPID=''
echo -n " *** Warnsdorff's Algorithm ***"
fi
initialize_board
movenum=0
board[startpos]=$movenum # Mark each board square with move number.
currpos=$startpos
algpos=$(to_algebraic $startpos)
echo; echo "Starting from $algpos [square #$startpos] ..."; echo
echo -n "Moves:"
strategy "$currpos"
echo
exit 0 # return 0;
# } # End of main() pseudo-function.
# =============================================================== #
# Exercises:
# ---------
#
# 1) Extend this example to a 10 x 10 board or larger.
# 2) Improve the "stupid strategy" by modifying the
# do_move_stupid function.
# Hint: Prevent straying into corner squares in early moves
# (the exact opposite of Warnsdorff's algorithm!).
# 3) This script could stand considerable improvement and
# streamlining, especially in the poorly-written
# generate_moves() function
# and in the DECIDE-MOVE patch in the do_move() function.
# Must figure out why standard algorithm fails for startpos=37 ...
#+ but _not_ on any other, including symmetrical startpos=26.
# Possibly, when calculating possible moves, counts the move back
#+ to the originating square. If so, it might be a relatively easy fix.

View File

@ -42,7 +42,7 @@ fi
#+ and
#+ default file "gen0" not present.
E_NOSTARTFILE=68
E_NOSTARTFILE=86
if [ ! -e "$startfile" ]
then
@ -65,7 +65,7 @@ COLS=10
# ---------------------------------------------------------- #
GENERATIONS=10 # How many generations to cycle through.
# Adjust this upwards,
# Adjust this upwards
#+ if you have time on your hands.
NONE_ALIVE=85 # Exit status on premature bailout,
@ -120,7 +120,7 @@ do
fi
echo -n "$cell" | sed -e 's/_/ /g'
# Print out array and change underscores to spaces.
# Print out array, changing underscores to spaces.
done
return
@ -164,7 +164,7 @@ return $TRUE # Valid coordinate.
IsAlive () # Test whether cell is alive.
# Takes array, cell number,
# Takes array, cell number, and
{ #+ state of cell as arguments.
GetCount "$1" $2 # Get alive cell count in neighborhood.
local nhbd=$?
@ -179,7 +179,7 @@ IsAlive () # Test whether cell is alive.
return $ALIVE
fi
return $DEAD # Dead by default.
return $DEAD # Dead, by default.
}
@ -222,7 +222,7 @@ GetCount () # Count live cells in passed cell's neighborhood.
if [ $? -eq "$TRUE" ]
then
if [ ${array[$t_cen]} = "$ALIVE1" ] # Is it alive?
then # Yes?
then # If yes, then ...
let "count += 1" # Increment count.
fi
fi
@ -294,7 +294,7 @@ echo "Generation $generation - $alive alive"
if [ "$alive" -eq 0 ]
then
echo
echo "Unexpected exit: no more cells alive!"
echo "Premature exit: no more cells alive!"
exit $NONE_ALIVE # No point in continuing
fi #+ if no live cells.
@ -307,8 +307,8 @@ fi #+ if no live cells.
# Load initial array with contents of startup file.
initial=( `cat "$startfile" | sed -e '/#/d' | tr -d '\n' |\
sed -e 's/\./\. /g' -e 's/_/_ /g'` )
# Delete lines containing '#' comment character.
sed -e 's/\./\. /g' -e 's/_/_ /g'` )
# Remove linefeeds and insert space between elements.
clear # Clear screen.

View File

@ -3,7 +3,7 @@
# A rudimentary man page editor
# Version: 0.1 (Alpha, probably buggy)
# Author: Mendel Cooper &lt;thegrendel@theriver.com&gt;
# Author: Mendel Cooper &lt;thegrendel.abs@gmail.com&gt;
# Reldate: 16 June 2008
# License: GPL3

View File

@ -0,0 +1,112 @@
#!/bin/bash
# msquare.sh
# Magic Square generator (odd-order squares only!)
# Author: mendel cooper
# reldate: 19 Jan. 2009
# License: Public Domain
# A C-program by Kwon Young Shin inspired this script.
# See http://user.chollian.net/~brainstm/MagicSquare.htm ...
# Definition: A "magic square" is a two-dimensional array
# of integers in which all the rows, columns,
# and *long* diagonals add up to the same number.
# Being "square," the array has the same number
# of rows and columns.
# An example of a magic square of order 3 is:
# 8 1 6
# 3 5 7
# 4 9 2
# All the rows, columns, and long diagonals add up to 15.
# Globals
EVEN=2
MAXSIZE=31 # 31 rows x 31 cols.
E_usage=90 # Invocation error.
dimension=
declare -i square
usage_message ()
{
echo "Usage: $0 square-size"
echo " ... where \"square-size\" is an ODD integer"
echo " in the range 3 - 31."
# Actually works for squares up to order 159,
#+ but large squares will not display pretty-printed in a term window.
# Try increasing MAXSIZE, above.
exit $E_usage
}
calculate () # Here's where the actual work gets done.
{
local row col index dimadj j k cell_val=1
dimension=$1
let "dimadj = $dimension * 3"; let "dimadj /= 2" # x 1.5, then truncate.
for ((j=0; j < dimension; j++))
do
for ((k=0; k < dimension; k++))
do # Calculate indices, then convert to 1-dim. array index.
# Bash doesn't support multidimensional arrays. Pity.
let "col = $k - $j + $dimadj"; let "col %= $dimension"
let "row = $j * 2 - $k + $dimension"; let "row %= $dimension"
let "index = $row*($dimension) + $col"
square[$index]=cell_val; ((cell_val++))
done
done
} # Plain math, no visualization required.
print_square () # Output square, one row at a time.
{
local row col idx d1
let "d1 = $dimension - 1" # Adjust for zero-indexed array.
for row in $(seq 0 $d1)
do
for col in $(seq 0 $d1)
do
let "idx = $row * $dimension + $col"
printf "%3d " "${square[idx]}"; echo -n " "
done # Displays up to 13-order neatly in 80-column term window.
echo # Newline after each row.
done
}
#################################################
if [[ -z "$1" ]] || [[ "$1" -gt $MAXSIZE ]]
then
usage_message
fi
let "test_even = $1 % $EVEN"
if [ $test_even -eq 0 ]
then # Can't handle even-order squares.
usage_message
fi
calculate $1
print_square # echo "${square[@]}" # DEBUG
exit $?
#################################################
# Exercises:
# ---------
# 1) Add a function to calculate the sum of each row, column,
# and *long* diagonal. The sums must match.
# This is the "magic constant" of that particular order square.
# 2) Have the print_square function auto-calculate how much space
# to allot between square elements for optimized display.
# This might require parameterizing the "printf" line.
# 3) Add appropriate functions for generating magic squares
# with an *even* number of rows/columns.
# This is non-trivial(!).
# See the URL for Kwon Young Shin, above, for help.

View File

@ -15,13 +15,11 @@ volume=$'\xc0' # Max volume = \xff (or \x00).
mute=$'\x80' # No volume = \x80 (the middle).
function mknote () # $1=Note Hz in bytes (e.g. A = 440Hz ::
#+ 8000 fps / 440 = 16 :: A = 16 bytes per second)
{
{ #+ 8000 fps / 440 = 16 :: A = 16 bytes per second)
for t in `seq 0 $duration`
do
test $(( $t % $1 )) = 0 && echo -n $volume || echo -n $mute
done
}
e=`mknote 49`
@ -39,4 +37,4 @@ echo -n "$g$e2$d$c$d$c$a$g$n$g$e$n$g$e2$d$c$c$b$c$cis$n$cis$d \
$n$g$e2$d$c$d$c$a$g$n$g$e$n$g$a$d$c$b$a$b$c" > /dev/dsp
# dsp = Digital Signal Processor
exit $? # A "bonny" example of a shell script!
exit # A "bonny" example of a shell script!

View File

@ -1,16 +1,16 @@
#!/bin/bash
# pad.sh
######################################################
#######################################################
# PAD (xml) file creator
#+ Written by Mendel Cooper &lt;thegrendel@theriver.com&gt;.
#+ Written by Mendel Cooper &lt;thegrendel.abs@gmail.com&gt;.
#+ Released to the Public Domain.
#
# Generates a "PAD" descriptor file for shareware
#+ packages, according to the specifications
#+ of the ASP.
# http://www.asp-shareware.org/pad
######################################################
#######################################################
# Accepts (optional) save filename as a command-line argument.

View File

@ -1,5 +1,5 @@
#!/bin/bash
# poem.sh: Pretty-prints one of the document author's favorite poems.
# poem.sh: Pretty-prints one of the ABS Guide author's favorite poems.
# Lines of the poem (single stanza).
Line[1]="I do not know which to prefer,"

View File

@ -4,7 +4,7 @@
##############################################################
# QUACKEY: a somewhat simplified version of Perquackey [TM]. #
# #
# Author: Mendel Cooper &lt;thegrendel@theriver.com&gt; #
# Author: Mendel Cooper &lt;thegrendel.abs@gmail.com&gt; #
# version 0.1.02 03 May, 2008 #
# License: GPL3 #
##############################################################
@ -13,9 +13,9 @@ WLIST=/usr/share/dict/word.lst
# ^^^^^^^^ Word list file found here.
# ASCII word list, one word per line, UNIX format.
# A suggested list is the script author's "yawl" word list package.
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
# http://bash.neuralshortciruit.com/yawl-0.3.2.tar.gz
# or
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
NONCONS=0 # Word not constructable from letter set.
CONS=1 # Constructable.
@ -462,4 +462,4 @@ exit $?
# 7) Fix bugs!!!
# Reference for more info:
# http://personal.riverusers.com/~thegrendel/qky.README.html
# http://bash.neuralshortcircuit.com/qky.README.html

View File

@ -2,7 +2,7 @@
# quote-fetch.sh: Download a stock quote.
E_NOPARAMS=66
E_NOPARAMS=86
if [ -z "$1" ] # Must specify a stock (symbol) to fetch.
then echo "Usage: `basename $0` stock-symbol"

View File

@ -2,7 +2,7 @@
# rand-string.sh
# Generating an 8-character "random" string.
if [ "-n $1" ] # If command-line argument present,
if [ -n "$1" ] # If command-line argument present,
then #+ then set start-string to it.
str0="$1"
else # Else use PID of script as start-string.

View File

@ -5,8 +5,8 @@
# Soundex script
# by
# Mendel Cooper
# thegrendel@theriver.com
# 23 January, 2002
# thegrendel.abs@gmail.com
# reldate: 23 January, 2002
#
# Placed in the Public Domain.
#
@ -18,7 +18,7 @@
ARGCOUNT=1 # Need name as argument.
E_WRONGARGS=70
E_WRONGARGS=90
if [ $# -ne "$ARGCOUNT" ]
then
@ -82,9 +82,9 @@ let "char_pos += 1" # Bump character position to 2nd letter of name.
name1=${name:$char_pos}
# ++++++++++++++++++++++++++ Exception Patch +++++++++++++++++++++++++++++++++
# Now, we run both the input name and the name shifted one char to the right
#+ through the value-assigning function.
# ++++++++++++++++++++++++++ Exception Patch ++++++++++++++++++++++++++++++
# Now, we run both the input name and the name shifted one char
#+ to the right through the value-assigning function.
# If we get the same value out, that means that the first two characters
#+ of the name have the same value assigned, and that one should cancel.
# However, we also need to test whether the first letter of the name
@ -111,7 +111,7 @@ then
else
suffix=${s2:$char_pos}
fi
# ++++++++++++++++++++++ end Exception Patch +++++++++++++++++++++++++++++++++
# ++++++++++++++++++++++ end Exception Patch ++++++++++++++++++++++++++++++
padding=000 # Use at most 3 zeroes to pad.

View File

@ -23,7 +23,7 @@ IMGDIR="images" # Image directory
# Headers
HDR01='&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;'
HDR02='&lt;!-- Converted to HTML by ***tohtml.sh*** script --&gt;'
HDR03='&lt;!-- script author: M. Leo Cooper &lt;thegrendel@theriver.com&gt; --&gt;'
HDR03='&lt;!-- script author: M. Leo Cooper &lt;thegrendel.abs@gmail.com&gt; --&gt;'
HDR10='&lt;html&gt;'
HDR11='&lt;head&gt;'
HDR11a='&lt;/head&gt;'

View File

@ -9,8 +9,8 @@
# ===========================================================
# Standard Check for Script Argument(s)
ARGS=1
E_BADARGS=65
E_NOFILE=66
E_BADARGS=85
E_NOFILE=86
if [ $# -ne $ARGS ]
then
@ -31,7 +31,7 @@ WORDFILE=/usr/share/dict/linux.words # Dictionary file.
# May specify a different word list file
#+ of one-word-per-line format.
# For example, the "yawl" word-list package,
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
# http://bash.neuralshortcircuit.com/yawl-0.3.2.tar.gz
wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \