This commit is contained in:
gferg 2009-03-24 18:46:05 +00:00
parent 9f7c335603
commit 67d2a75d13
18 changed files with 2042 additions and 174 deletions

View File

@ -7,19 +7,152 @@
==================================================================
Current version = 5.6
Dated 01/26/09
Current version = 6.0.05
Dated 03/24/09
http://bash.neuralshortcircuit.com/abs-guide-latest.tar.bz2
http://bash.neuralshortcircuit.com/abs-guide.pdf
--------------------------------------------------------------------
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.
News: Major update, version 6.0.
Coverage of version 4 of Bash.
====================================================================
Intermediate release
Working toward Version 6.1, Buffaloberry release
1) In "Internal Commands and Builtins" chapter
At "eval" entry, reworded intro and added material to first example.
2) In "External Commands" chapter:
In "Math Commands" section:
At "dc" entry, added two short usage example, including a
somewhat cryptic one (Golden Ratio calculation).
3) In "Internal Variables" section of "Variables Revisited" chapter:
At "$DIRSTACK" entry, added footnote defining "stack."
4) In "Bash, versions 2, 3, and 4" chapter:
In "Bash, version 4" section,
Corrected a typo in Substring Extraction entry example script.
5) In "Bibliography" section:
Added entry for Wikipedia article on "dc."
Version 6.0, Thimbleberry release
March 23, 2009
1) Changed the title of Chapter 1.
2) Updated "copy-cd.sh" and "ex40.sh" examples
to reflect changes in cdrtools.
3) In "Special Characters" chapter:
Added another instance in the "brace expansion" example.
4) In "Testing and Branching" section of "Loops and Branches" chapter:
Clarified outline of "case" construct.
5) In "Internal Commands and Builtins" chapter:
At "eval" entry, added "arr-choice.sh" example script.
(Thank you, Antonio Macchi!)
At "read" entry, added "-u" option.
6) In "Internal Variables" section of "Variables Revisited" chapter:
Added $BASHPID variable (new to Bash 4+).
At "$$" entry, noted that within a subshell, PID of script returned
by $$.
7) In "Arrays" chapter:
Added material to "array-function.sh" example script.
8) In "Variables Revisited" chapter:
In "Indirect References" section:
Fixed comment in "ind-ref.sh" example, thanks to Jakob Bohm.
9) In "External Commands" chapter:
In "File and Archiving Commands" section:
Added "pax" entry.
10) In "I/O Redirection" chapter:
Added a couple of new instances on stderr redirection.
Added comments on a couple of new operators added in ver. 4 of Bash
that are still not functional.
11) In "Bash, versions 2, 3, and 4" chapter (new title!):
In Version 3 section, more on quoting "=~" operator.
Added instances in "brace expansion" example.
Added a section for version 4 of Bash.
Added "fetch_address.sh" and "fetch_address-2.sh" examples
to illustrate associative arrays.
Added "cas4.sh" example to illustrate enhancements to case construct.
Added discussion of the new "coproc" command, with illustrative
examples.
Added discussion of the new "mapfile" command, with an illustrative
example.
Briefly mentioned a couple of the changes to "read" options.
Listed the new -l and -c options to "declare" builtin,
with a short illustrated inline script.
Listed new upper/lowercase operators for parameter substitution,
with example.
Listed the new "brace expansion" options.
Discussed change in the treatment of positional parameters
in substring extraction.
Discussed the new ** globbing operator and "globstar" shell option.
Discussed the new "command_not_found_handle ()" error-handling
function, with in-line example.
Added an "editorial" sidebar. It is certain to generate controversy.
12) In "System Resources" subsection of "System and Administrative
At "ulimit" entry, added footnote about -f, -c behavior in POSIX
mode and newly-added options (ver. 4+ of Bash).
13) In "Process Substitution" chapter:
Added "wr-ps.bash" while-read loop example.
(Thank you, Tomas Pospisek!)
14) In "Gotchas" chapter:
Samuli Kaipiainen supplied a corrected explanation for piping-to-grep
misbehavior.
15) In the "Portability Issues" section of the "Miscellany" chapter:
Added entries to list of features in Bash missing in traditional "sh."
16) In "Options" chapter:
Added entries for "globstar" and "checkjobs" in the table.
17) In "Subshells" chapter:
Added a few comments and a short in-line example.
18) In "Contributed Scripts" appendix:
Added "fifteen.sh" (Fifteen Puzzle) example script.
(Thank you, Antonio Macchi!)
Added "hanoi2.bash" -- graphic version of "hanoi.bash."
Added "hanoi2a.bash" -- alternate graphic version of "hanoi.bash."
Had to remove "obj-oriented.sh" example because it only works
with obsolete versions of Bash.
Removed "ftpget.sh" script.
19) In "Download and Mirror Sites" appendix:
Fixed a typo in the ABS Guide download URL.
20) In "Bibliography" section:
Added Shell Script Games entry.
Added Bash Hackers Wiki entry.
Added mirror site for the official Bash FAQ.
Added Greg's WIKI: Bash FAQ entry.
Added joyent site.
21) Updated the Index with references to new material.
22) Numberous syntactical and stylistic fixes.
Version 5.6, Worcesterberry release
01/26/09

View File

@ -11,9 +11,23 @@
<!-- Characters and symbols -->
<para><command>^ </command> (caret)
<link linkend="beglineref">Beginning-of-line</link>, in a <link
linkend="regexref">Regular Expression</link></para>
<itemizedlist>
<listitem>
<para>
<link linkend="beglineref">Beginning-of-line</link>,
in a <link linkend="regexref">Regular Expression</link>
</para>
</listitem>
<listitem>
<para><command>^</command></para>
<para><command>^^</command></para>
<para><link linkend="casemodparamsub">Uppercase
conversion</link> in <firstterm>parameter
substitution</firstterm></para>
</listitem>
</itemizedlist>
</para>
<para><command>~ </command> <firstterm>Tilde</firstterm>
<itemizedlist>
@ -233,9 +247,8 @@
command</para></listitem>
<listitem><para><command>;; </command>
<link linkend="doublesemicolon">Double-semicolon</link>, terminator in a
<link linkend="caseesac1">case</link> option</para></listitem>
<link linkend="caseesac1">case</link> option</para>
<listitem>
<para>Required when ...</para>
<para><link linkend="needsemicolon"><firstterm>do</firstterm>
keyword is on the first line of
@ -245,6 +258,11 @@
code block</link></para>
</listitem>
<listitem><para><command>;;&</command> <command>;&</command>
<link linkend="ncterm">Terminators</link> in
a <firstterm>case</firstterm> option (<link
linkend="bash4ref">version 4+</link> of Bash).</para></listitem>
</itemizedlist></para>
<para><command>: </command>
@ -342,7 +360,19 @@
quoting</link></para>
<para><command>,</command>
<link linkend="commaop">Comma operator</link></para>
<itemizedlist>
<listitem><para>
<link linkend="commaop">Comma operator</link>
</para></listitem>
<listitem>
<para><command>,</command></para>
<para><command>,,</command></para>
<para><link linkend="casemodparamsub">Lowercase
conversion</link> in <firstterm>parameter
substitution</firstterm></para>
</listitem>
</itemizedlist>
</para>
<!-- ********************** -->
@ -618,6 +648,12 @@
arithmetic operator
</para></listitem>
<listitem><para>
<command> ** </command>
Extended <firstterm>globbing</firstterm>
<link linkend="globstarref">file-match operator</link>
</para></listitem>
</itemizedlist>
</para>
<!-- ********************** -->
@ -769,6 +805,8 @@
<para><link linkend="arrayref">Arrays</link></para>
<itemizedlist>
<listitem><para><link linkend="assocarr">Associative arrays</link>
</para></listitem>
<listitem><para><link linkend="arrayref">Bracket notation</link>
</para></listitem>
<listitem><para><link linkend="arrayappend0">Concatenating</link>,
@ -881,6 +919,8 @@
Version 2</link></para></listitem>
<listitem><para><link linkend="bash3ref">
Version 3</link></para></listitem>
<listitem><para><link linkend="bash4ref">
Version 4</link></para></listitem>
</itemizedlist></para>
<!-- ********************** -->
@ -931,6 +971,10 @@
<listitem><para><link
linkend="braceexpref33">Extended</link>,
<replaceable>{a..z}</replaceable></para></listitem>
<listitem><para>With <link
linkend="braceexpref4">increment and
zero-padding</link> (new feature in Bash, <link linkend="bash4ref">version
4</link>)</para></listitem>
</itemizedlist></para>
<!-- ********************** -->
@ -1029,6 +1073,10 @@
<para><link linkend="bash-options">Command-line options</link></para>
<para><link linkend="cnfh">command_not_found_handle ()</link>
<firstterm>builtin</firstterm> error-handling function
(<link linkend="bash4ref">version 4+</link> of Bash)</para>
<para><link linkend="commandsubref">Command substitution</link>
<itemizedlist>
<listitem>
@ -1100,6 +1148,7 @@
</itemizedlist></para>
<!-- ***************************************************************** -->
<para><link linkend="coprocref">Coprocesses</link></para>
<para><link linkend="cronref">cron</link>, scheduling
<firstterm>daemon</firstterm></para>
<para><link linkend="cstyle"><firstterm>C</firstterm>-style syntax
@ -1167,8 +1216,11 @@
<para><link linkend="declare1ref">declare</link> builtin</para>
<itemizedlist>
<listitem><para><link
linkend="declareopsref1">options</link></para></listitem>
<listitem>
<para><link linkend="declareopsref1">options</link></para>
<para><link linkend="declarecasemod">case-modification</link>
options (<link linkend="bash4ref">version 4+</link> of Bash)
</para></listitem>
</itemizedlist>
<para><link linkend="defparam">Default parameters</link></para>
@ -1285,6 +1337,9 @@
references</link></para></listitem>
<listitem><para><link linkend="evalrisk">Risk of
using</link></para></listitem>
<listitem><para><link linkend="arrchoice0">Using
<firstterm>eval</firstterm> to select among
variables</link></para></listitem>
</itemizedlist></para>
<para><link linkend="dblbraev">Evaluation of
@ -1496,6 +1551,8 @@
linkend="cryptoquote">Crypto-Quotes</link></para></listitem>
<listitem><para><link
linkend="cards">Dealing a deck of cards</link></para></listitem>
<listitem><para><link
linkend="fifteen">Fifteen Puzzle</link></para></listitem>
<listitem><para><link
linkend="horserace">Horse race</link></para></listitem>
<listitem><para><link
@ -1517,7 +1574,12 @@
linkend="bashpodder">Podcasting</link></para></listitem>
<listitem><para><link linkend="poem">Poem</link></para></listitem>
<listitem><para><link
linkend="hanoi">Towers of Hanoi</link></para></listitem>
linkend="hanoi">Towers of Hanoi</link></para>
<para><link linkend="hanoi2">Graphic
version</link></para>
<para><link linkend="hanoi2a">Alternate graphic
version</link></para>
</listitem>
</itemizedlist></para>
<para><link linkend="getopty">getopt</link>,
@ -1549,6 +1611,9 @@
<filename>dot files</filename></link></para></listitem>
</itemizedlist></para>
<para><link linkend="goldenratio">Golden Ratio</link>
(<firstterm>Phi</firstterm>)</para>
<para><link linkend="ge0ref"> -ge </link>,
<firstterm>greater-than or equal</firstterm>
<link linkend="icomparison1">integer comparison</link> test</para>
@ -1608,6 +1673,8 @@
<para><link
linkend="herestringsref"><firstterm>Here</firstterm>
strings</link></para>
<para>Calculating the <link linkend="goldenratio">Golden
Ratio</link></para>
<para><link linkend="hspre">Prepending text</link></para>
<para><link linkend="hsread">Using
<firstterm>read</firstterm></link></para>
@ -1911,6 +1978,8 @@
</itemizedlist>
</para>
<para><link linkend="mapfileref">mapfile</link> builtin,
loads an array with a text file</para>
<para><link linkend="mathc">Math commands</link></para>
<para><link linkend="metameaningref">Meta-meaning</link></para>
@ -2019,6 +2088,11 @@
<firstterm>parameter</firstterm></link></para>
</listitem>
<listitem><para><link linkend="casemodparamsub">
<firstterm>Case modification</firstterm></link>
(<link linkend="bash4ref">version 4+</link> of
Bash).</para></listitem>
<listitem><para><link linkend="pw0"><firstterm>Script
example</firstterm></link></para></listitem>
<listitem><para><link linkend="parsubtab"><command>Table</command></link>
@ -2161,7 +2235,9 @@
<para><link linkend="pipeloop"><firstterm>echo</firstterm>
to a loop</link></para>
<para><link linkend="badread0"><firstterm>echo</firstterm>
to <firstterm>read</firstterm></link></para>
to <firstterm>read</firstterm></link> (however, this problem
<link linkend="goodread0">can be circumvented</link>)</para>
<para><link linkend="ptailgrep"><firstterm>tail</firstterm>
<option>-f</option> to <firstterm>grep</firstterm></link></para>
</listitem>
@ -2180,6 +2256,9 @@
<listitem><para><link linkend="varsubsh">Variables in a
<firstterm>subshell</firstterm></link>, <firstterm>scope</firstterm>
limited</para></listitem>
<listitem><para><link
linkend="badread0">Subshell in <firstterm>while-read</firstterm>
loop</link></para></listitem>
<listitem><para><link linkend="wsbad">Whitespace</link>,
misuse of</para></listitem>
@ -2297,6 +2376,10 @@
command</link></para></listitem>
<listitem><para><link
linkend="commandsparens1">Template</link></para></listitem>
<listitem><para><link
linkend="goodread0"><firstterm>while-read</firstterm> loop
without a
<firstterm>subshell</firstterm></link></para></listitem>
</itemizedlist></para>
<!-- *************************************************************** -->
<para>Prompt
@ -2427,6 +2510,8 @@
construct</para></listitem>
</itemizedlist></para>
<para><link linkend="readlineref">readline</link> library</para>
<para><link linkend="recursionref">Recursion</link>
<itemizedlist>
<listitem><para><link
@ -2713,9 +2798,15 @@
</itemizedlist></para>
<para><link linkend="scharlist1">Special characters</link></para>
<para>Stack, emulating a push-down, <link
linkend="stackex0"><firstterm>example
script</firstterm></link></para>
<para>Stack
<itemizedlist>
<listitem><para><link
linkend="stackdefref">Definition</link></para></listitem>
<listitem><para>Emulating a <firstterm>push-down stack</firstterm>,
<link linkend="stackex0">example script</link></para></listitem>
</itemizedlist></para>
<para>Standard Deviation, <link linkend="stddev">example script</link></para>
<para><link linkend="filesref1">Startup files</link>, Bash</para>
@ -3089,7 +3180,12 @@
<listitem><para><link linkend="intparam">Testing a variable</link>
to see if it contains only digits</para></listitem>
<listitem><para><link
linkend="trackingscr">Tracking script usage</link></para></listitem>
linkend="trackingscr">Tracking script
usage</link></para></listitem>
<listitem><para><link
linkend="goodread0"><firstterm>while-read</firstterm> loop
without a
<firstterm>subshell</firstterm></link></para></listitem>
<listitem><para><link
linkend="widgetref">Widgets</link>, invoking from a
script</para></listitem>
@ -3288,9 +3384,14 @@
conditions</link></para></listitem>
<listitem><para><link linkend="whilenobrackets">Omitting
<firstterm>test</firstterm> brackets</link></para></listitem>
<listitem><para><link linkend="whilereadref2">
<firstterm>while read</firstterm></link>
construct</para></listitem>
<listitem>
<para><link linkend="whilereadref2">
<firstterm>while read</firstterm></link>
construct
</para>
<para><link linkend="goodread0">Avoiding a
<firstterm>subshell</firstterm></link></para>
</listitem>
</itemizedlist></para>
<para><link linkend="whitespaceref">Whitespace</link>,

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
#!/bin/bash
# arr-choice.sh
# Passing arguments to a function to select
#+ one particular variable out of a group.
arr0=( 10 11 12 13 14 15 )
arr1=( 20 21 22 23 24 25 )
arr2=( 30 31 32 33 34 35 )
# 0 1 2 3 4 5 Element number (zero-indexed)
choose_array ()
{
eval array_member=\${arr${array_number}[element_number]}
# ^ ^^^^^^^^^^^^
# Using eval to construct the name of a variable,
#+ in this particular case, an array name.
echo "Element $element_number of array $array_number is $array_member"
} # Function can be rewritten to take parameters.
array_number=0 # First array.
element_number=3
choose_array # 13
array_number=2 # Third array.
element_number=4
choose_array # 34
array_number=3 # Null array (arr3 not allocated).
element_number=4
choose_array # (null)
# Thank you, Antonio Macchi, for pointing this out.

View File

@ -51,4 +51,25 @@ echo "Passed array (within function) = ${passed_array[@]}"
echo
############################################
# And here is an even more explicit example:
ret_array ()
{
for element in {11..20}
do
echo "$element " # Echo individual elements
done #+ of what will be assembled into an array.
}
arr=( $(ret_array) ) # Assemble into array.
echo "Capturing array \"arr\" from function ret_array () ..."
echo "Third element of array \"arr\" is ${arr[2]}." # 13 (zero-indexed)
echo -n "Entire array is: "
echo ${arr[@]} # 11 12 13 14 15 16 17 18 19 20
echo
exit 0

View File

@ -74,10 +74,10 @@ declare -a ArrayVar
# The echo command is a built-in.
# The echo command is a builtin.
echo $VarSomething
# The printf command is a built-in.
# The printf command is a builtin.
# Translate %s as: String-Format
printf %s $VarSomething # No linebreak specified, none output.
echo # Default, only linebreak output.

View File

@ -2,7 +2,6 @@
# Strips off the header from a mail/News message i.e. till the first
# empty line.
# Author: Mark Moraes, University of Toronto
# See the included file "Moraes-COPYRIGHT" for copyright info.
# ==> These comments added by author of this document.
@ -19,7 +18,33 @@ else
done
fi
exit
# ==> Exercise: Add error checking and other options.
# ==>
# ==> Note that the small sed script repeats, except for the arg passed.
# ==> Does it make sense to embed it in a function? Why or why not?
/*
* Copyright University of Toronto 1988, 1989.
* Written by Mark Moraes
*
* Permission is granted to anyone to use this software for any purpose on
* any computer system, and to alter it and redistribute it freely, subject
* to the following restrictions:
*
* 1. The author and the University of Toronto are not responsible
* for the consequences of use of this software, no matter how awful,
* even if they arise from flaws in it.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Since few users ever read sources,
* credits must appear in the documentation.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software. Since few users
* ever read sources, credits must appear in the documentation.
*
* 4. This notice may not be removed or altered.
*/

View File

@ -0,0 +1,40 @@
#!/bin/bash4
test_char ()
{
case "$1" in
[[:print:]] ) echo "$1 is a printable character.";;& # |
# The ;;& terminator continues to the next pattern test. |
[[:alnum:]] ) echo "$1 is an alpha/numeric character.";;& # v
[[:alpha:]] ) echo "$1 is an alphabetic character.";;& # v
[[:lower:]] ) echo "$1 is a lowercase alphabetic character.";;&
[[:digit:]] ) echo "$1 is an numeric character.";& # |
# The ;& terminator executes the next statement ... # |
%%%@@@@@ ) echo "********************************";; # v
# ^^^^^^^^ ... even with a dummy pattern.
esac
}
echo
test_char 3
# 3 is a printable character.
# 3 is an alpha/numeric character.
# 3 is an numeric character.
# ********************************
echo
test_char m
# m is a printable character.
# m is an alpha/numeric character.
# m is an alphabetic character.
# m is a lowercase alphabetic character.
echo
test_char /
# / is a printable character.
echo
# The ;;& terminator can save complex if/then conditions.
# The ;& is somewhat less useful.

View File

@ -5,9 +5,9 @@ CDROM=/dev/cdrom # CD ROM device
OF=/home/bozo/projects/cdimage.iso # output file
# /xxxx/xxxxxxxx/ Change to suit your system.
BLOCKSIZE=2048
SPEED=10 # May use higher speed ...
DEVICE=/dev/cdrom
# DEVICE="0,0" on older versions of cdrecord.
# SPEED=10 # If unspecified, uses max spd.
# DEVICE=/dev/cdrom older version.
DEVICE="1,0,0"
echo; echo "Insert source CD, but do *not* mount it."
echo "Press ENTER when ready. "
@ -26,7 +26,8 @@ read ready # Wait for input, $ready not used.
echo "Copying $OF to CDR."
cdrecord -v -isosize speed=$SPEED dev=$DEVICE $OF
# cdrecord -v -isosize speed=$SPEED dev=$DEVICE $OF # Old version.
wodim -v -isosize dev=$DEVICE $OF
# Uses Joerg Schilling's "cdrecord" package (see its docs).
# http://www.fokus.gmd.de/nthp/employees/schilling/cdrecord.html
# Newer Linux distros may use "wodim" rather than "cdrecord" ...

View File

@ -6,8 +6,8 @@
SPEED=10 # May use higher speed if your hardware supports it.
IMAGEFILE=cdimage.iso
CONTENTSFILE=contents
DEVICE=/dev/cdrom
# DEVICE="0,0" For older versions of cdrecord
# DEVICE=/dev/cdrom For older versions of cdrecord
DEVICE="1,0,0"
DEFAULTDIR=/opt # This is the directory containing the data to be burned.
# Make sure it exists.
# Exercise: Add a test for this.
@ -41,8 +41,10 @@ echo "Creating ISO9660 file system image ($IMAGEFILE)."
# Burn the CDR.
echo "Burning the disk."
echo "Please be patient, this will take a while."
cdrecord -v -isosize speed=$SPEED dev=$DEVICE $IMAGEFILE
# In newer Linux distros, the "wodim" utility may assume the
wodim -v -isosize dev=$DEVICE $IMAGEFILE
# In newer Linux distros, the "wodim" utility assumes the
#+ functionality of "cdrecord."
exitcode=$?
echo "Exit code = $exitcode"
exit $?
exit $exitcode

View File

@ -29,7 +29,8 @@ Password="your.e-mail.address" # Change above to suit.
ftp -n $Server &lt;&lt;End-Of-Session
# -n option disables auto-logon
user anonymous "$Password"
user anonymous "$Password" # If this doesn't work, then try:
# quote user anonymous "$Password"
binary
bell # Ring 'bell' after each file transfer.
cd $Directory

View File

@ -0,0 +1,50 @@
#!/bin/bash4
# fetch_address-2.sh
# A more elaborate version of fetch_address.sh.
SUCCESS=0
E_DB=99 # Error code for missing entry.
declare -A address
# -A option declares associative array.
store_address ()
{
address[$1]="$2"
return $?
}
fetch_address ()
{
if [[ -z "${address[$1]}" ]]
then
echo "$1's address is not in database."
return $E_DB
fi
echo "$1's address is ${address[$1]}."
return $?
}
store_address "Charles Jones" "414 W. 10th Ave., Baltimore, MD 21236"
store_address "John Smith" "202 E. 3rd St., New York, NY 10009"
store_address "Wilma Wilson" "1854 Vermont Ave, Los Angeles, CA 90023"
# Exercise:
# Rewrite the above store_address calls to read data from a file,
#+ then assign field 1 to name, field 2 to address in the array.
# Each line in the file would have a format corresponding to the above.
# Use a while-read loop to read from file, sed or awk to parse the fields.
fetch_address "Charles Jones"
# Charles Jones's address is 414 W. 10th Ave., Baltimore, MD 21236.
fetch_address "Wilma Wilson"
# Wilma Wilson's address is 1854 Vermont Ave, Los Angeles, CA 90023.
fetch_address "John Smith"
# John Smith's address is 202 E. 3rd St., New York, NY 10009.
fetch_address "Bozo Bozeman"
# Bozo Bozeman's address is not in database.
exit $? # In this case, exit code = 99, since that is function return.

View File

@ -0,0 +1,17 @@
#!/bin/bash4
# fetch_address.sh
declare -A address
# -A option declares associative array.
address[Charles]="414 W. 10th Ave., Baltimore, MD 21236"
address[John]="202 E. 3rd St., New York, NY 10009"
address[Wilma]="1854 Vermont Ave, Los Angeles, CA 90023"
echo "Charles's address is ${address[Charles]}."
# Charles's address is 414 W. 10th Ave., Baltimore, MD 21236.
echo "Wilma's address is ${address[Wilma]}."
# Wilma's address is 1854 Vermont Ave, Los Angeles, CA 90023.
echo "John's address is ${address[John]}."
# John's address is 202 E. 3rd St., New York, NY 10009.

View File

@ -0,0 +1,173 @@
#!/bin/bash
# fifteen.sh
# Classic "Fifteen Puzzle"
# Author: Antonio Macchi
# Lightly edited and commented by ABS Guide author.
# Used in ABS Guide with permission. (Thanks!)
# The invention of the Fifteen Puzzle is attributed to either
#+ Sam Loyd or Noyes Palmer Chapman.
# The puzzle was wildly popular in the late 19th-century.
# Object: Rearrange the numbers so they read in order,
#+ from 1 - 15: ________________
# | 1 2 3 4 |
# | 5 6 7 8 |
# | 9 10 11 12 |
# | 13 14 15 |
# ----------------
#######################
# Constants #
SQUARES=16 #
FAIL=70 #
E_PREMATURE_EXIT=80 #
#######################
########
# Data #
########
Puzzle=( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 " " )
#############
# Functions #
#############
function swap
{
local tmp
tmp=${Puzzle[$1]}
Puzzle[$1]=${Puzzle[$2]}
Puzzle[$2]=$tmp
}
function Jumble
{ # Scramble the pieces at beginning of round.
local i pos1 pos2
for i in {1..100}
do
pos1=$(( $RANDOM % $SQUARES))
pos2=$(( $RANDOM % $SQUARES ))
swap $pos1 $pos2
done
}
function PrintPuzzle
{
local i1 i2 puzpos
puzpos=0
clear
echo "Enter quit to exit."; echo # Better that than Ctl-C.
echo ",----.----.----.----." # Top border.
for i1 in {1..4}
do
for i2 in {1..4}
do
printf "| %2s " "${Puzzle[$puzpos]}"
(( puzpos++ ))
done
echo "|" # Right-side border.
test $i1 = 4 || echo "+----+----+----+----+"
done
echo "'----'----'----'----'" # Bottom border.
}
function GetNum
{ # Test for valid input.
local puznum garbage
while true
do
echo "Moves: $moves" # Also counts invalid moves.
read -p "Number to move: " puznum garbage
if [ "$puznum" = "quit" ]; then echo; exit $E_PREMATURE_EXIT; fi
test -z "$puznum" -o -n "${puznum//[0-9]/}" && continue
test $puznum -gt 0 -a $puznum -lt $SQUARES && break
done
return $puznum
}
function GetPosFromNum
{ # $1 = puzzle-number
local puzpos
for puzpos in {0..15}
do
test "${Puzzle[$puzpos]}" = "$1" && break
done
return $puzpos
}
function Move
{ # $1=Puzzle-pos
test $1 -gt 3 && test "${Puzzle[$(( $1 - 4 ))]}" = " "\
&& swap $1 $(( $1 - 4 )) && return 0
test $(( $1%4 )) -ne 3 && test "${Puzzle[$(( $1 + 1 ))]}" = " "\
&& swap $1 $(( $1 + 1 )) && return 0
test $1 -lt 12 && test "${Puzzle[$(( $1 + 4 ))]}" = " "\
&& swap $1 $(( $1 + 4 )) && return 0
test $(( $1%4 )) -ne 0 && test "${Puzzle[$(( $1 - 1 ))]}" = " " &&\
swap $1 $(( $1 - 1 )) && return 0
return 1
}
function Solved
{
local pos
for pos in {0..14}
do
test "${Puzzle[$pos]}" = $(( $pos + 1 )) || return $FAIL
# Check whether number in each square = square number.
done
return 0 # Successful solution.
}
################### MAIN () ########################
moves=0
Jumble
while true # Loop continuously until puzzle solved.
do
echo; echo
PrintPuzzle
echo
while true
do
GetNum
puznum=$?
GetPosFromNum $puznum
puzpos=$?
((moves++))
Move $puzpos && break
done
Solved && break
done
echo;echo
PrintPuzzle
echo; echo "BRAVO!"; echo
exit 0
####################################################
# Exercise:
# --------
# Rewrite the script to display the letters A - O,
#+ rather than the numbers 1 - 15.

View File

@ -0,0 +1,202 @@
#! /bin/bash
# The Towers Of Hanoi
# Original script (hanoi.bash) copyright (C) 2000 Amit Singh.
# All Rights Reserved.
# http://hanoi.kernelthread.com
# hanoi2.bash
# Version 2: modded for ASCII-graphic display.
# Uses code contributed by Antonio Macchi,
#+ with heavy editing by ABS Guide author.
# This variant also falls under the original copyright, see above.
# Used in ABS Guide with Amit Singh's permission (thanks!).
# Variables #
E_NOPARAM=86
E_BADPARAM=87 # Illegal no. of disks passed to script.
E_NOEXIT=88
DISKS=$1
Moves=0
MWIDTH=7
MARGIN=2
# Arbitrary "magic" constants, work okay for relatively small # of disks.
# BASEWIDTH=51 # Original code.
let "basewidth = $MWIDTH * $DISKS + $MARGIN" # "Base" beneath rods.
# Above "algorithm" could likely stand improvement.
# Display variables.
let "disks1 = $DISKS - 1"
let "spaces1 = $DISKS"
let "spaces2 = 2 * $DISKS"
let "lastmove_t = $DISKS - 1" # Final move?
declare -a Rod1 Rod2 Rod3
#################
function repeat { # $1=char $2=number of repetitions
local n # Repeat-print a character.
for (( n=0; n<$2; n++ )); do
echo -n "$1"
done
}
function FromRod {
local rod summit weight sequence
while true; do
rod=$1
test ${rod/[^123]/} || continue
sequence=$(echo $(seq 0 $disks1 | tac))
for summit in $sequence; do
eval weight=\${Rod${rod}[$summit]}
test $weight -ne 0 &&
{ echo "$rod $summit $weight"; return; }
done
done
}
function ToRod { # $1=previous (FromRod) weight
local rod firstfree weight sequence
while true; do
rod=$2
test ${rod/[^123]} || continue
sequence=$(echo $(seq 0 $disks1 | tac))
for firstfree in $sequence; do
eval weight=\${Rod${rod}[$firstfree]}
test $weight -gt 0 && { (( firstfree++ )); break; }
done
test $weight -gt $1 -o $firstfree = 0 &&
{ echo "$rod $firstfree"; return; }
done
}
function PrintRods {
local disk rod empty fill sp sequence
repeat " " $spaces1
echo -n "|"
repeat " " $spaces2
echo -n "|"
repeat " " $spaces2
echo "|"
sequence=$(echo $(seq 0 $disks1 | tac))
for disk in $sequence; do
for rod in {1..3}; do
eval empty=$(( $DISKS - (Rod${rod}[$disk] / 2) ))
eval fill=\${Rod${rod}[$disk]}
repeat " " $empty
test $fill -gt 0 && repeat "*" $fill || echo -n "|"
repeat " " $empty
done
echo
done
repeat "=" $basewidth # Print "base" beneath rods.
echo
}
display ()
{
echo
PrintRods
# Get rod-number, summit and weight
first=( `FromRod $1` )
eval Rod${first[0]}[${first[1]}]=0
# Get rod-number and first-free position
second=( `ToRod ${first[2]} $2` )
eval Rod${second[0]}[${second[1]}]=${first[2]}
echo; echo; echo
if [ "${Rod3[lastmove_t]}" = 1 ]
then # Last move? If yes, then display final position.
echo "+ Final Position: $Moves moves"; echo
PrintRods
fi
}
# From here down, almost the same as original (hanoi.bash) script.
dohanoi() { # Recursive function.
case $1 in
0)
;;
*)
dohanoi "$(($1-1))" $2 $4 $3
if [ "$Moves" -ne 0 ]
then
echo "+ Position after move $Moves"
fi
((Moves++))
echo -n " Next move will be: "
echo $2 "-->" $3
display $2 $3
dohanoi "$(($1-1))" $4 $3 $2
;;
esac
}
setup_arrays ()
{
local dim n elem
let "dim1 = $1 - 1"
elem=$dim1
for n in $(seq 0 $dim1)
do
let "Rod1[$elem] = 2 * $n + 1"
Rod2[$n]=0
Rod3[$n]=0
((elem--))
done
}
### Main ###
setup_arrays $DISKS
echo; echo "+ Start Position"
case $# in
1) case $(($1>0)) in # Must have at least one disk.
1)
disks=$1
dohanoi $1 1 3 2
# Total moves = 2^n - 1, where n = # of disks.
echo
exit 0;
;;
*)
echo "$0: Illegal value for number of disks";
exit $E_BADPARAM;
;;
esac
;;
*)
echo "usage: $0 N"
echo " Where \"N\" is the number of disks."
exit $E_NOPARAM;
;;
esac
exit $E_NOEXIT # Shouldn't exit here.
# Note:
# Redirect script output to a file, otherwise it scrolls off display.

View File

@ -0,0 +1,216 @@
#! /bin/bash
# The Towers Of Hanoi
# Original script (hanoi.bash) copyright (C) 2000 Amit Singh.
# All Rights Reserved.
# http://hanoi.kernelthread.com
# hanoi2.bash
# Version 2: modded for ASCII-graphic display.
# Uses code contributed by Antonio Macchi,
#+ with heavy editing by ABS Guide author.
# This variant also falls under the original copyright, see above.
# Used in ABS Guide with Amit Singh's permission (thanks!).
# Variables #
E_NOPARAM=86
E_BADPARAM=87 # Illegal no. of disks passed to script.
E_NOEXIT=88
DELAY=2 # Interval, in seconds, between moves. Change, if desired.
DISKS=$1
Moves=0
MWIDTH=7
MARGIN=2
# Arbitrary "magic" constants, work okay for relatively small # of disks.
# BASEWIDTH=51 # Original code.
let "basewidth = $MWIDTH * $DISKS + $MARGIN" # "Base" beneath rods.
# Above "algorithm" could likely stand improvement.
# Display variables.
let "disks1 = $DISKS - 1"
let "spaces1 = $DISKS"
let "spaces2 = 2 * $DISKS"
let "lastmove_t = $DISKS - 1" # Final move?
declare -a Rod1 Rod2 Rod3
#################
function repeat { # $1=char $2=number of repetitions
local n # Repeat-print a character.
for (( n=0; n<$2; n++ )); do
echo -n "$1"
done
}
function FromRod {
local rod summit weight sequence
while true; do
rod=$1
test ${rod/[^123]/} || continue
sequence=$(echo $(seq 0 $disks1 | tac))
for summit in $sequence; do
eval weight=\${Rod${rod}[$summit]}
test $weight -ne 0 &&
{ echo "$rod $summit $weight"; return; }
done
done
}
function ToRod { # $1=previous (FromRod) weight
local rod firstfree weight sequence
while true; do
rod=$2
test ${rod/[^123]} || continue
sequence=$(echo $(seq 0 $disks1 | tac))
for firstfree in $sequence; do
eval weight=\${Rod${rod}[$firstfree]}
test $weight -gt 0 && { (( firstfree++ )); break; }
done
test $weight -gt $1 -o $firstfree = 0 &&
{ echo "$rod $firstfree"; return; }
done
}
function PrintRods {
local disk rod empty fill sp sequence
tput cup 5 0
repeat " " $spaces1
echo -n "|"
repeat " " $spaces2
echo -n "|"
repeat " " $spaces2
echo "|"
sequence=$(echo $(seq 0 $disks1 | tac))
for disk in $sequence; do
for rod in {1..3}; do
eval empty=$(( $DISKS - (Rod${rod}[$disk] / 2) ))
eval fill=\${Rod${rod}[$disk]}
repeat " " $empty
test $fill -gt 0 && repeat "*" $fill || echo -n "|"
repeat " " $empty
done
echo
done
repeat "=" $basewidth # Print "base" beneath rods.
echo
}
display ()
{
echo
PrintRods
# Get rod-number, summit and weight
first=( `FromRod $1` )
eval Rod${first[0]}[${first[1]}]=0
# Get rod-number and first-free position
second=( `ToRod ${first[2]} $2` )
eval Rod${second[0]}[${second[1]}]=${first[2]}
if [ "${Rod3[lastmove_t]}" = 1 ]
then # Last move? If yes, then display final position.
tput cup 0 0
echo; echo "+ Final Position: $Moves moves"
PrintRods
fi
sleep $DELAY
}
# From here down, almost the same as original (hanoi.bash) script.
dohanoi() { # Recursive function.
case $1 in
0)
;;
*)
dohanoi "$(($1-1))" $2 $4 $3
if [ "$Moves" -ne 0 ]
then
tput cup 0 0
echo; echo "+ Position after move $Moves"
fi
((Moves++))
echo -n " Next move will be: "
echo $2 "-->" $3
display $2 $3
dohanoi "$(($1-1))" $4 $3 $2
;;
esac
}
setup_arrays ()
{
local dim n elem
let "dim1 = $1 - 1"
elem=$dim1
for n in $(seq 0 $dim1)
do
let "Rod1[$elem] = 2 * $n + 1"
Rod2[$n]=0
Rod3[$n]=0
((elem--))
done
}
### Main ###
trap "tput cnorm" 0
tput civis
clear
setup_arrays $DISKS
tput cup 0 0
echo; echo "+ Start Position"
case $# in
1) case $(($1>0)) in # Must have at least one disk.
1)
disks=$1
dohanoi $1 1 3 2
# Total moves = 2^n - 1, where n = # of disks.
echo
exit 0;
;;
*)
echo "$0: Illegal value for number of disks";
exit $E_BADPARAM;
;;
esac
;;
*)
echo "usage: $0 N"
echo " Where \"N\" is the number of disks."
exit $E_NOPARAM;
;;
esac
exit $E_NOEXIT # Shouldn't exit here.
# Exercise:
# --------
# There is a minor bug in the script that causes the display of
#+ the next-to-last move to be skipped.
#+ Fix this.

View File

@ -10,8 +10,10 @@ echo "\$var = $var" # $var = 23
# So far, everything as expected. But ...
echo "\$\$var = $$var" # $$var = 4570var
# Not meaningful. The contents of a memory location pointed to?
# Not useful at this point.
# Not useful ...
# \$\$ expanded to PID of process being executed,
#+ and "var" is echoed as plain text.
# (Thank you, Jakob Bohm, for pointing this out.)
echo "\\\$\$var = \$$var" # \$$var = $23
# As expected. The first $ is escaped and pasted on to

View File

@ -0,0 +1,65 @@
#!/bin/bash
# wr-ps.bash: while-read loop with process substitution.
# This example contributed by Tomas Pospisek.
# (Heavily edited by the ABS Guide author.)
echo
echo "random input" | while read i
do
global=3D": Not available outside the loop."
# ... because it runs in a subshell.
done
echo "\$global (from outside the subprocess) = $global"
# $global (from outside the subprocess) =
echo; echo "--"; echo
while read i
do
echo $i
global=3D": Available outside the loop."
# ... because it does *not* run in a subshell.
done < <( echo "random input" )
# ^ ^
echo "\$global (using process substitution) = $global"
# random input
# $global (using process substitution) = 3D: Available outside the loop.
echo; echo "##########"; echo
# And likewise . . .
declare -a inloop
index=0
cat $0 | while read line
do
inloop[$index]="$line"
((index++))
# It runs in a subshell, so ...
done
echo "OUTPUT = "
echo ${inloop[*]} # ... nothing echoes.
echo; echo "--"; echo
declare -a outloop
index=0
while read line
do
outloop[$index]="$line"
((index++))
# It does *not* run in a subshell, so ...
done < <( cat $0 )
echo "OUTPUT = "
echo ${outloop[*]} # ... the entire script echoes.
exit $?