This commit is contained in:
gferg 2008-05-09 18:58:34 +00:00
parent 8456bfd681
commit 8b4da601ad
16 changed files with 1545 additions and 316 deletions

View File

@ -7,17 +7,89 @@
================================================================== ==================================================================
Current version = 5.2 Current version = 5.3
http://personal.riverusers.com/~thegrendel/abs-guide-5.2.tar.bz2 http://personal.riverusers.com/~thegrendel/abs-guide-5.3.tar.bz2
http://personal.riverusers.com/~thegrendel/abs-guide.pdf http://personal.riverusers.com/~thegrendel/abs-guide.pdf
------------------------------------------------------------------ --------------------------------------------------------------------
News: Version 5.2 release. . . . News: "Petals Around the Rose" (petals.sh) example script added.
New example scripts. "Crossword Puzzle Solver" (cw-solver.sh) example script added.
New section on version 3.2 update to Bash. "Perquackey" type game (qky.sh) example script added.
More on !#/bin/env bash. ====================================================================
More coherent definition of "recursion."
================================================================== Version 5.3, Goldenberry release
05/11/08
1) In "Special Variable Types" section of "Introduction to Variables and
Fixed exit-status error in second "shift-past.sh" example.
(Thank you, E. Choroba!)
At "#" entry, added "quoted" to "escaped" for "#" in non-comment lines.
Added a number of missing "Ctl-?" entries. Now, the entire alphabet
is complete <g>.
At "Ctl-N" entry, added footnote about history buffer.
2) In "Tests" chapter:
In "Test Constructs" section:
At [[ double brackets ]] construct, added discussion and example on
arithmetic evaluation of octal and hex constants within [[ ... ]].
(Thank you, Moritz Gronbach!)
Consolidated entire [[ ... ]] topic into a single <sidebar>.
3) In "Text Processing" section of "External Commands" Chapter:
Added "cw-solver.sh" (crossword puzzle solver) example script.
4) In "System and Administrative Commands" chapter:
At "lockfile" entry:
Updated in-line example per suggestion of E. Choroba.
Added info to footnote defining "semaphore."
5) In "Internal Commands and Builtins" chapter:
At "read" entry, appended Antonio Macchi's suggestions to
"arrow-detect.sh" example.
6) In "Quoting Variables" section of "Quoting" chapter:
Added simple in-line example.
7) In "Debugging" chapter:
Changed note defining 'signal' into a sidebar and removed superfluous
comma.
8) In "Gotchas" chapter:
Added item about unintended consequences of preserving whitespace
within a variable. (Thank you, Claus Tirel, for inspiring me to do
this.)
9) In "Assorted Tips" section of "Miscellany" chapter:
At return value trickery discussion,
added Caution about only one "echo" statement in a function.
10) In "Operator Precedence" section "Miscellany" chapter:
Fixed an error in the table (!= is not a "combination assignment"
operator.
11) In "Contributed Scripts" appendix:
Added "Petals Around the Rose" example script.
(Thank you, Serghey Rodin!)
Modified "basics-reviewed.bash" script, per contribution
of Cliff Bamford. (Many thanks!)
In "basics-reviewed.bash" script, fixed two typos.
Added very long and complex "qky.sh" (Perquackey-type game) script.
12) In "Exit Codes With Special Meanings" appendix:
Added footnote about previously unused exit codes
in the 64-78 range now allocated.
(Thank you, Greg Metcalfe, for pointing this out.)
13) In "Bibliography" section:
Added reference/link to Penguin Pete's site.
14) In "Exercise" appendix:
Added humorous preface.
15) Cleanups/fixups to main text, appendices, and script examples where
appropriate.
Version 5.2, Silverberry release Version 5.2, Silverberry release
03/16/08 03/16/08

View File

@ -698,6 +698,8 @@
<firstterm>unalias</firstterm></para></listitem> <firstterm>unalias</firstterm></para></listitem>
</itemizedlist></para> </itemizedlist></para>
<para><link linkend="agram2">Anagramming</link></para>
<para><link linkend="lcons1"><firstterm>And</firstterm> list</link> <para><link linkend="lcons1"><firstterm>And</firstterm> list</link>
<itemizedlist> <itemizedlist>
<listitem><para> <listitem><para>
@ -809,6 +811,8 @@
elements</link></para></listitem> elements</link></para></listitem>
</itemizedlist> </itemizedlist>
<para><link linkend="readarrow">Arrow keys</link>, detecting</para>
<para><link linkend="asciitable">ASCII table</link></para> <para><link linkend="asciitable">ASCII table</link></para>
<!-- ********************** --> <!-- ********************** -->
@ -880,6 +884,8 @@
<para><link linkend="biblio">Bibliography</link></para> <para><link linkend="biblio">Bibliography</link></para>
<para><link linkend="bisonref">Bison</link> utility</para> <para><link linkend="bisonref">Bison</link> utility</para>
<para><link linkend="bitwsops1">Bitwise operators</link></para> <para><link linkend="bitwsops1">Bitwise operators</link></para>
<para><link linkend="blockdevref">Block devices</link>, testing
for</para>
<para><link linkend="codeblockref">Blocks of code</link> <para><link linkend="codeblockref">Blocks of code</link>
<itemizedlist> <itemizedlist>
@ -969,6 +975,8 @@
</itemizedlist></para> </itemizedlist></para>
<para><link linkend="chardevref">Character devices</link>, testing
for</para>
<para><link linkend="childref">Child processes</link></para> <para><link linkend="childref">Child processes</link></para>
<para><link linkend="nullref">Colon</link>, <command>: </command>, <para><link linkend="nullref">Colon</link>, <command>: </command>,
equivalent to the <link linkend="trueref">true</link> Bash equivalent to the <link linkend="trueref">true</link> Bash
@ -1063,6 +1071,8 @@
<para><link linkend="cstyle"><firstterm>C</firstterm>-style syntax <para><link linkend="cstyle"><firstterm>C</firstterm>-style syntax
</link>, for handling variables</para> </link>, for handling variables</para>
<para><link linkend="cwsolver">Crossword puzzle solver</link></para>
<para>Curly brackets {} <para>Curly brackets {}
<itemizedlist> <itemizedlist>
<listitem><para><link linkend="curlybracketsref">in <listitem><para><link linkend="curlybracketsref">in
@ -1169,9 +1179,15 @@
(<command>table</command>)</para> (<command>table</command>)</para>
<para><link linkend="dotfilesref"><firstterm>dot files</firstterm></link>, <para><link linkend="dotfilesref"><firstterm>dot files</firstterm></link>,
<quote>hidden</quote> setup and configuration files</para> <quote>hidden</quote> setup and configuration files</para>
<para><link linkend="dblbrackets">Double brackets</link> <para><link linkend="dblbrackets">Double brackets</link>
<command>[[ ... ]]</command> <link linkend="ifthen">test</link> <command>[[ ... ]]</command> <link linkend="ifthen">test</link>
construct</para> construct</para>
<itemizedlist>
<listitem><para>and <link linkend="dblbraev">evaluation of
<firstterm>octal/hex</firstterm> constants</link></para></listitem>
</itemizedlist>
<para><link linkend="dblquo">Double quotes</link> <para><link linkend="dblquo">Double quotes</link>
<command>" ... "</command> <firstterm>weak</firstterm> quoting</para> <command>" ... "</command> <firstterm>weak</firstterm> quoting</para>
<para><link linkend="doublespace">Double-spacing a text <para><link linkend="doublespace">Double-spacing a text
@ -1223,6 +1239,10 @@
using</link></para></listitem> using</link></para></listitem>
</itemizedlist></para> </itemizedlist></para>
<para><link linkend="dblbraev">Evaluation of
<firstterm>octal/hex</firstterm> constants within
[[ ... ]]</link></para>
<para><link linkend="usingexecref">exec</link> command, <para><link linkend="usingexecref">exec</link> command,
using in <link linkend="ioredirref">redirection</link></para> using in <link linkend="ioredirref">redirection</link></para>
@ -1548,6 +1568,8 @@
loop</para> loop</para>
<para><link linkend="inittabref">Initialization table</link>, <para><link linkend="inittabref">Initialization table</link>,
<filename>/etc/inittab</filename></para> <filename>/etc/inittab</filename></para>
<para><link linkend="codeblockref">Inline group</link>,
i.e., code block</para>
<para><link linkend="iitest">Interactive script</link>, test for</para> <para><link linkend="iitest">Interactive script</link>, test for</para>
<para><link linkend="ioredirref">I/O redirection</link></para> <para><link linkend="ioredirref">I/O redirection</link></para>
@ -1897,6 +1919,12 @@
with</link></para></listitem> with</link></para></listitem>
</itemizedlist></para> </itemizedlist></para>
<para><link linkend="qky"><emphasis>Perquackey</emphasis>-type
anagramming game</link> (<emphasis>Quackey</emphasis> script)</para>
<para><link linkend="petals"><emphasis>Petals Around the
Rose</emphasis></link></para>
<para><link linkend="processiddef">PID</link>, <para><link linkend="processiddef">PID</link>,
<firstterm>Process ID</firstterm>, an identification <firstterm>Process ID</firstterm>, an identification
number assigned to a running process.</para> number assigned to a running process.</para>
@ -1965,6 +1993,9 @@
within <firstterm>test</firstterm> brackets</para></listitem> within <firstterm>test</firstterm> brackets</para></listitem>
<listitem><para><link linkend="gnuref"><firstterm>GNU</firstterm> <listitem><para><link linkend="gnuref"><firstterm>GNU</firstterm>
command set</link>, in cross-platform scripts</para></listitem> command set</link>, in cross-platform scripts</para></listitem>
<listitem><para><link linkend="rvtcaution2">Multiple echo
statements</link> in a <link linkend="rvt">function whose
output is captured</link></para></listitem>
<listitem><para><link linkend="nullvar"><firstterm>null</firstterm> <listitem><para><link linkend="nullvar"><firstterm>null</firstterm>
variable assignment</link></para></listitem> variable assignment</link></para></listitem>
<listitem> <listitem>
@ -1988,6 +2019,9 @@
<para><link linkend="ptailgrep"><firstterm>tail</firstterm> <para><link linkend="ptailgrep"><firstterm>tail</firstterm>
<option>-f</option> to <firstterm>grep</firstterm></link></para> <option>-f</option> to <firstterm>grep</firstterm></link></para>
</listitem> </listitem>
<listitem><para>Preserving <firstterm>whitespace</firstterm>
within a variable, <link linkend="varsplitting">unintended
consequences</link></para></listitem>
<listitem><para><link linkend="suidscr"><firstterm>suid</firstterm> <listitem><para><link linkend="suidscr"><firstterm>suid</firstterm>
commands inside a script</link></para></listitem> commands inside a script</link></para></listitem>
<listitem><para><link linkend="undocf">Undocumented <listitem><para><link linkend="undocf">Undocumented
@ -2125,6 +2159,9 @@
<para>* * *</para> <para>* * *</para>
<para><link linkend="qky">Quackey</link>, a
<emphasis>Perquackey</emphasis>-type anagramming game (script)</para>
<para>Question mark, <command>? </command> <para>Question mark, <command>? </command>
<itemizedlist> <itemizedlist>
<listitem><para><link linkend="quexregex">Character <listitem><para><link linkend="quexregex">Character
@ -2552,6 +2589,16 @@
<firstterm>script example</firstterm></para> <firstterm>script example</firstterm></para>
</listitem> </listitem>
<listitem>
<para><firstterm>strchr()</firstterm>, <link
linkend="substringindex2">equivalent of</link></para>
</listitem>
<listitem>
<para><firstterm>strlen()</firstterm>, <link
linkend="strlen">equivalent of</link></para>
</listitem>
<listitem> <listitem>
<para>Substring extraction</para> <para>Substring extraction</para>
<para><link linkend="substrextr01">${string:position}</link></para> <para><link linkend="substrextr01">${string:position}</link></para>
@ -2789,6 +2836,10 @@
<firstterm>return value</firstterm> from <firstterm>return value</firstterm> from
a function</link></para></listitem> a function</link></para></listitem>
<listitem><para><link linkend="captureretval">Capturing
the return value</link> of a function, using
<firstterm>echo</firstterm></para></listitem>
<listitem> <listitem>
<para>Comment blocks</para> <para>Comment blocks</para>
<para>Using <link linkend="cblock1"><firstterm>anonymous <para>Using <link linkend="cblock1"><firstterm>anonymous
@ -2980,7 +3031,7 @@
<para><link <para><link
linkend="failquote">within <firstterm>test</firstterm> linkend="failquote">within <firstterm>test</firstterm>
brackets</link></para> brackets</link></para>
<para><link linkend="quotingws">to preserve <para><link linkend="wsquo">to preserve
<firstterm>whitespace</firstterm></link></para> <firstterm>whitespace</firstterm></link></para>
</listitem> </listitem>
<listitem><para><link <listitem><para><link
@ -2999,10 +3050,13 @@
error message</para></listitem> error message</para></listitem>
<listitem><para><link linkend="uninitvar1">Uninitialized</link> <listitem><para><link linkend="uninitvar1">Uninitialized</link>
</para></listitem> </para></listitem>
<listitem><para><link linkend="varsplitting">Unquoted
variable</link>,
<firstterm>splitting</firstterm></para></listitem>
<listitem><para><link
linkend="unsetref">Unsetting</link></para></listitem>
<listitem><para><link <listitem><para><link
linkend="unsetref">Unsetting</link></para></listitem> linkend="bvuntyped">Untyped</link></para></listitem>
<listitem><para><link
linkend="bvuntyped">Untyped</link></para></listitem>
</itemizedlist></para> </itemizedlist></para>

View File

@ -70,7 +70,7 @@ hash-example.sh (comment in line 3: < --> &lt;, > --> &gt;)
quote-fetch.sh (comment in line 26: &amp; --> &) quote-fetch.sh (comment in line 26: &amp; --> &)
ftpget.sh (comment in line 28) ftpget.sh (comment in line 28)
whx.sh (comment in line 259) whx.sh (comment in line 259)
pad.sh, (comment in line 6, lines 26, 27, 28, 29, 30, 33, 34). pad.sh, (comments in line 6, lines 26, 27, 28, 29, 30, 33, 34).
nightly-backup.sh (comment in line 4) nightly-backup.sh (comment in line 4)
tohtml.sh: lines 22-33 tohtml.sh: lines 22-33
lines 35-36 lines 35-36
@ -91,3 +91,14 @@ insertion-sort.sh:
tree2.sh: tree2.sh:
line 38 (comment) line 38 (comment)
line 88 line 88
petals.sh
line 54
qky.sh
line 7
line 63
line 87
line 113
(The unaltered, executable script can be downloaded from
http://personal.riverusers.com/~thegrendel/qky.sh)

File diff suppressed because it is too large Load Diff

View File

@ -96,6 +96,29 @@ exit $OTHER
;; ;;
esac esac
exit $?
# ========================================= #
# Antonio Macchi has a simpler alternative.
#!/bin/bash
while true
do
read -sn1 a
test "$a" == `echo -en "\e"` || continue
read -sn1 a
test "$a" == "[" || continue
read -sn1 a
case "$a" in
A) echo "up";;
B) echo "down";;
C) echo "right";;
D) echo "left";;
esac
done
# ========================================= # # ========================================= #
# Exercise: # Exercise:

View File

@ -9,15 +9,16 @@
# #
# Edited for layout by M.C. # Edited for layout by M.C.
# (author of the "Advanced Bash Scripting Guide") # (author of the "Advanced Bash Scripting Guide")
# Fixes and updates (04/08) by Cliff Bamford.
# This script tested under Bash versions 2.04, 2.05a and 2.05b. # This script tested under Bash versions 2.04, 2.05a and 2.05b.
# It may not work with earlier versions. # It may not work with earlier versions.
# This demonstration script generates one --intentional-- # This demonstration script generates one --intentional--
#+ "command not found" error message. See line 394. #+ "command not found" error message. See line 436.
# The current Bash maintainer, Chet Ramey, has fixed the items noted # The current Bash maintainer, Chet Ramey, has fixed the items noted
#+ for an upcoming version of Bash. #+ for later versions of Bash.
@ -51,7 +52,7 @@ unset VarNull
# A variable name may be defined but empty (null contents). # A variable name may be defined but empty (null contents).
VarEmpty='' # Two, adjacent, single quotes. VarEmpty='' # Two, adjacent, single quotes.
# A variable name my be defined and non-empty # A variable name may be defined and non-empty.
VarSomething='Literal' VarSomething='Literal'
# A variable may contain: # A variable may contain:
@ -174,7 +175,7 @@ echo ${@} # Same as above
# Elements of a Bash-Array need not all be of the same type. # Elements of a Bash-Array need not all be of the same type.
### ###
# Elements of a Bash-Array may be undefined (null reference). # Elements of a Bash-Array may be undefined (null reference).
# That is, a Bash-Array my be "subscript sparse." # That is, a Bash-Array may be "subscript sparse."
### ###
# Elements of a Bash-Array may be defined and empty (null contents). # Elements of a Bash-Array may be defined and empty (null contents).
### ###
@ -196,102 +197,143 @@ echo ${@} # Same as above
# -- msz # -- msz
echo "========================================================="
# Lines 202 - 334 supplied by Cliff Bamford. (Thanks!)
# Demo --- Interaction with Arrays, quoting, IFS, echo, * and @ ---
#+ all affect how things work
ArrayVar[0]='zero' # 0 normal
ArrayVar[1]=one # 1 unquoted literal
ArrayVar[2]='two' # 2 normal
ArrayVar[3]='three' # 3 normal
ArrayVar[4]='I am four' # 4 normal with spaces
ArrayVar[5]='five' # 5 normal
unset ArrayVar[6] # 6 undefined
ArrayValue[7]='seven' # 7 normal
ArrayValue[8]='' # 8 defined but empty
ArrayValue[9]='nine' # 9 normal
# Demo time -- initialize the previously declared ArrayVar as a echo '--- Here is the array we are using for this test'
#+ sparse array.
# (The 'unset ... ' is just documentation here.)
unset ArrayVar[0] # Just for the record
ArrayVar[1]=one # Unquoted literal
ArrayVar[2]='' # Defined, and empty
unset ArrayVar[3] # Just for the record
ArrayVar[4]='four' # Quoted literal
# Translate the %q format as: Quoted-Respecting-IFS-Rules.
echo echo
echo '- - Outside of double-quotes - -' echo "ArrayVar[0]='zero' # 0 normal"
### echo "ArrayVar[1]=one # 1 unquoted literal"
printf %q ${ArrayVar[*]} # Glob-Pattern All-Elements-Of echo "ArrayVar[2]='two' # 2 normal"
echo "ArrayVar[3]='three' # 3 normal"
echo "ArrayVar[4]='I am four' # 4 normal with spaces"
echo "ArrayVar[5]='five' # 5 normal"
echo "unset ArrayVar[6] # 6 undefined"
echo "ArrayValue[7]='seven' # 7 normal"
echo "ArrayValue[8]='' # 8 defined but empty"
echo "ArrayValue[9]='nine' # 9 normal"
echo echo
echo 'echo command:'${ArrayVar[*]}
###
printf %q ${ArrayVar[@]} # All-Elements-Of
echo
echo 'echo command:'${ArrayVar[@]}
# The use of double-quotes may be translated as: Enable-Substitution.
# There are five cases recognized for the IFS setting.
echo
echo '- - Within double-quotes - Default IFS of space-tab-newline - -'
IFS=$'\x20'$'\x09'$'\x0A' # These three bytes,
#+ in exactly this order.
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of
echo
echo 'echo command:'"${ArrayVar[*]}"
###
printf %q "${ArrayVar[@]}" # All-Elements-Of
echo
echo 'echo command:'"${ArrayVar[@]}"
echo echo
echo '- - Within double-quotes - First character of IFS is ^ - -' echo '---Case0: No double-quotes, Default IFS of space,tab,newline ---'
# Any printing, non-whitespace character should do the same. IFS=$'\x20'$'\x09'$'\x0A' # In exactly this order.
IFS='^'$IFS # ^ + space tab newline echo 'Here is: printf %q {${ArrayVar[*]}'
### printf %q ${ArrayVar[*]}
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of
echo echo
echo 'echo command:'"${ArrayVar[*]}" echo 'Here is: printf %q {${ArrayVar[@]}'
### printf %q ${ArrayVar[@]}
printf %q "${ArrayVar[@]}" # All-Elements-Of
echo echo
echo 'echo command:'"${ArrayVar[@]}" echo 'Here is: echo ${ArrayVar[*]}'
echo ${ArrayVar[@]}
echo 'Here is: echo {${ArrayVar[@]}'
echo ${ArrayVar[@]}
echo echo
echo '- - Within double-quotes - Without whitespace in IFS - -' echo '---Case1: Within double-quotes - Default IFS of space-tab-
IFS='^:%!' newline ---'
### IFS=$'\x20'$'\x09'$'\x0A' # These three bytes,
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of echo 'Here is: printf %q "{${ArrayVar[*]}"'
printf %q "${ArrayVar[*]}"
echo echo
echo 'echo command:'"${ArrayVar[*]}" echo 'Here is: printf %q "{${ArrayVar[@]}"'
### printf %q "${ArrayVar[@]}"
printf %q "${ArrayVar[@]}" # All-Elements-Of
echo echo
echo 'echo command:'"${ArrayVar[@]}" echo 'Here is: echo "${ArrayVar[*]}"'
echo "${ArrayVar[@]}"
echo 'Here is: echo "{${ArrayVar[@]}"'
echo "${ArrayVar[@]}"
echo echo
echo '- - Within double-quotes - IFS set and empty - -' echo '---Case2: Within double-quotes - IFS is q'
IFS='q'
echo 'Here is: printf %q "{${ArrayVar[*]}"'
printf %q "${ArrayVar[*]}"
echo
echo 'Here is: printf %q "{${ArrayVar[@]}"'
printf %q "${ArrayVar[@]}"
echo
echo 'Here is: echo "${ArrayVar[*]}"'
echo "${ArrayVar[@]}"
echo 'Here is: echo "{${ArrayVar[@]}"'
echo "${ArrayVar[@]}"
echo
echo '---Case3: Within double-quotes - IFS is ^'
IFS='^'
echo 'Here is: printf %q "{${ArrayVar[*]}"'
printf %q "${ArrayVar[*]}"
echo
echo 'Here is: printf %q "{${ArrayVar[@]}"'
printf %q "${ArrayVar[@]}"
echo
echo 'Here is: echo "${ArrayVar[*]}"'
echo "${ArrayVar[@]}"
echo 'Here is: echo "{${ArrayVar[@]}"'
echo "${ArrayVar[@]}"
echo
echo '---Case4: Within double-quotes - IFS is ^ followed by
space,tab,newline'
IFS=$'^'$'\x20'$'\x09'$'\x0A' # ^ + space tab newline
echo 'Here is: printf %q "{${ArrayVar[*]}"'
printf %q "${ArrayVar[*]}"
echo
echo 'Here is: printf %q "{${ArrayVar[@]}"'
printf %q "${ArrayVar[@]}"
echo
echo 'Here is: echo "${ArrayVar[*]}"'
echo "${ArrayVar[@]}"
echo 'Here is: echo "{${ArrayVar[@]}"'
echo "${ArrayVar[@]}"
echo
echo '---Case6: Within double-quotes - IFS set and empty '
IFS='' IFS=''
### echo 'Here is: printf %q "{${ArrayVar[*]}"'
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of printf %q "${ArrayVar[*]}"
echo echo
echo 'echo command:'"${ArrayVar[*]}" echo 'Here is: printf %q "{${ArrayVar[@]}"'
### printf %q "${ArrayVar[@]}"
printf %q "${ArrayVar[@]}" # All-Elements-Of
echo echo
echo 'echo command:'"${ArrayVar[@]}" echo 'Here is: echo "${ArrayVar[*]}"'
echo "${ArrayVar[@]}"
echo 'Here is: echo "{${ArrayVar[@]}"'
echo "${ArrayVar[@]}"
echo echo
echo '- - Within double-quotes - IFS undefined - -' echo '---Case7: Within double-quotes - IFS is unset'
unset IFS unset IFS
### echo 'Here is: printf %q "{${ArrayVar[*]}"'
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of printf %q "${ArrayVar[*]}"
echo echo
echo 'echo command:'"${ArrayVar[*]}" echo 'Here is: printf %q "{${ArrayVar[@]}"'
### printf %q "${ArrayVar[@]}"
printf %q "${ArrayVar[@]}" # All-Elements-Of
echo echo
echo 'echo command:'"${ArrayVar[@]}" echo 'Here is: echo "${ArrayVar[*]}"'
echo "${ArrayVar[@]}"
echo 'Here is: echo "{${ArrayVar[@]}"'
echo "${ArrayVar[@]}"
echo
echo '---End of Cases---'
echo "========================================================="; echo
# Put IFS back to the default. # Put IFS back to the default.
@ -392,7 +434,7 @@ echo $_simple not defined # No variable by that name.
### ###
$(_simple) # Gives an error message: $(_simple) # Gives an error message:
# line 394: SimpleFunc: command not found # line 436: SimpleFunc: command not found
# --------------------------------------- # ---------------------------------------
echo echo
@ -784,8 +826,7 @@ echo ${ArrayVar[@]:1:2} # four - The only element with content.
# In versions 2.04, 2.05a and 2.05b, # In versions 2.04, 2.05a and 2.05b,
#+ Bash does not handle sparse arrays as expected using this notation. #+ Bash does not handle sparse arrays as expected using this notation.
# #
# The current Bash maintainer, Chet Ramey, has corrected this # The current Bash maintainer, Chet Ramey, has corrected this.
#+ for an upcoming version of Bash.
echo '- Non-sparse array -' echo '- Non-sparse array -'
@ -821,8 +862,8 @@ echo ${stringZ#123} # Unchanged (not a prefix).
echo ${stringZ#$(_abc)} # ABC123ABCabc echo ${stringZ#$(_abc)} # ABC123ABCabc
echo ${arrayZ[@]#abc} # Applied to each element. echo ${arrayZ[@]#abc} # Applied to each element.
# Fixed by Chet Ramey for an upcoming version of Bash.
# echo ${sparseZ[@]#abc} # Version-2.05b core dumps. # echo ${sparseZ[@]#abc} # Version-2.05b core dumps.
# Has since been fixed by Chet Ramey.
# The -it would be nice- First-Subscript-Of # The -it would be nice- First-Subscript-Of
# echo ${#sparseZ[@]#*} # This is NOT valid Bash. # echo ${#sparseZ[@]#*} # This is NOT valid Bash.
@ -833,8 +874,8 @@ echo ${stringZ##1*3} # Unchanged (not a prefix)
echo ${stringZ##a*C} # abc echo ${stringZ##a*C} # abc
echo ${arrayZ[@]##a*c} # ABCABC 123123 ABCABC echo ${arrayZ[@]##a*c} # ABCABC 123123 ABCABC
# Fixed by Chet Ramey for an upcoming version of Bash
# echo ${sparseZ[@]##a*c} # Version-2.05b core dumps. # echo ${sparseZ[@]##a*c} # Version-2.05b core dumps.
# Has since been fixed by Chet Ramey.
echo echo
echo '- - Suffix sub-element removal - -' echo '- - Suffix sub-element removal - -'
@ -846,8 +887,8 @@ echo ${stringZ%1*3} # Unchanged (not a suffix).
echo ${stringZ%$(_abc)} # abcABC123ABC echo ${stringZ%$(_abc)} # abcABC123ABC
echo ${arrayZ[@]%abc} # Applied to each element. echo ${arrayZ[@]%abc} # Applied to each element.
# Fixed by Chet Ramey for an upcoming version of Bash.
# echo ${sparseZ[@]%abc} # Version-2.05b core dumps. # echo ${sparseZ[@]%abc} # Version-2.05b core dumps.
# Has since been fixed by Chet Ramey.
# The -it would be nice- Last-Subscript-Of # The -it would be nice- Last-Subscript-Of
# echo ${#sparseZ[@]%*} # This is NOT valid Bash. # echo ${#sparseZ[@]%*} # This is NOT valid Bash.
@ -858,8 +899,8 @@ echo ${stringZ%%1*3} # Unchanged (not a suffix)
echo ${stringZ%%b*c} # a echo ${stringZ%%b*c} # a
echo ${arrayZ[@]%%b*c} # a ABCABC 123123 ABCABC a echo ${arrayZ[@]%%b*c} # a ABCABC 123123 ABCABC a
# Fixed by Chet Ramey for an upcoming version of Bash.
# echo ${sparseZ[@]%%b*c} # Version-2.05b core dumps. # echo ${sparseZ[@]%%b*c} # Version-2.05b core dumps.
# Has since been fixed by Chet Ramey.
echo echo
echo '- - Sub-element replacement - -' echo '- - Sub-element replacement - -'

View File

@ -23,19 +23,21 @@
#+ disregards such parameters as #+ disregards such parameters as
#+ board tilt-angle, rolling friction of the marbles, #+ board tilt-angle, rolling friction of the marbles,
#+ angles of impact, and elasticity of the pegs. #+ angles of impact, and elasticity of the pegs.
# How does this affect the accuracy of the simulation? # To what extent does this affect the accuracy of the simulation?
# ---------------------------------------------------------------- # ----------------------------------------------------------------
PASSES=500 # Number of particle interactions / marbles. PASSES=500 # Number of particle interactions / marbles.
ROWS=10 # Number of "collisions" (or horiz. peg rows). ROWS=10 # Number of "collisions" (or horiz. peg rows).
RANGE=3 # 0 - 2 output range from $RANDOM. RANGE=3 # 0 - 2 output range from $RANDOM.
POS=0 # Left/right position. POS=0 # Left/right position.
RANDOM=$$ # Seeds the random number generator from PID
#+ of script.
declare -a Slots # Array holding cumulative results of passes. declare -a Slots # Array holding cumulative results of passes.
NUMSLOTS=21 # Number of slots at bottom of board. NUMSLOTS=21 # Number of slots at bottom of board.
Initialize_Slots () { # Zero out all elements of array. Initialize_Slots () { # Zero out all elements of the array.
for i in $( seq $NUMSLOTS ) for i in $( seq $NUMSLOTS )
do do
Slots[$i]=0 Slots[$i]=0
@ -49,7 +51,7 @@ Show_Slots () {
echo -n " " echo -n " "
for i in $( seq $NUMSLOTS ) # Pretty-print array elements. for i in $( seq $NUMSLOTS ) # Pretty-print array elements.
do do
printf "%3d" ${Slots[$i]} # Three spaces per result. printf "%3d" ${Slots[$i]} # Allot three spaces per result.
done done
echo # Row of slots: echo # Row of slots:

View File

@ -32,7 +32,7 @@
# Theoretically, the more shots taken, the better the fit. # Theoretically, the more shots taken, the better the fit.
# However, a shell script, as opposed to a compiled language # However, a shell script, as opposed to a compiled language
#+ with floating-point math built in, requires a few compromises. #+ with floating-point math built in, requires a few compromises.
# This tends to lower the accuracy of the simulation, of course. # This tends to lower the accuracy of the simulation.
DIMENSION=10000 # Length of each side of the plot. DIMENSION=10000 # Length of each side of the plot.
@ -42,6 +42,8 @@ MAXSHOTS=1000 # Fire this many shots.
# 10000 or more would be better, but would take too long. # 10000 or more would be better, but would take too long.
PMULTIPLIER=4.0 # Scaling factor to approximate PI. PMULTIPLIER=4.0 # Scaling factor to approximate PI.
M_PI=3.141592654 # Actual value of PI, for comparison purposes.
get_random () get_random ()
{ {
SEED=$(head -n 1 /dev/urandom | od -N 1 | awk '{ print $2 }') SEED=$(head -n 1 /dev/urandom | od -N 1 | awk '{ print $2 }')
@ -61,7 +63,7 @@ EOF
) )
# Setting "scale" to zero rounds down result to integer value, # Setting "scale" to zero rounds down result to integer value,
#+ a necessary compromise in this script. #+ a necessary compromise in this script.
# This diminshes the accuracy of the simulation, unfortunately. # This diminshes the accuracy of the simulation.
} }
@ -72,6 +74,7 @@ shots=0
splashes=0 splashes=0
thuds=0 thuds=0
Pi=0 Pi=0
error=0
while [ "$shots" -lt "$MAXSHOTS" ] # Main loop. while [ "$shots" -lt "$MAXSHOTS" ] # Main loop.
do do
@ -107,9 +110,11 @@ do
done done
echo echo
echo "After $shots shots, PI looks like approximately $Pi." echo "After $shots shots, PI looks like approximately $Pi"
# Tends to run a bit high . . . # Tends to run a bit high . . .
# Probably due to round-off error and imperfect randomness of $RANDOM. # Probably due to round-off error and imperfect randomness of $RANDOM.
error=$(echo "scale=9; $Pi - $M_PI" | bc)
echo "Deviation from mathematical value of PI = $error"
echo echo
# } # }

View File

@ -0,0 +1,66 @@
#!/bin/bash
# cw-solver.sh
# Crossword puzzle and anagramming word game solver.
# You know *some* of the letters in the word you're looking for,
#+ so you need a list of all valid words
#+ with the known letters in given positions.
# For example: w...i....n
# 1???5????10
# w in position 1, 3 unknowns, i in the 5th, 4 unknowns, n at the end.
# (See comments at end of script.)
E_NOPATT=71
DICT=/usr/share/dict/word.lst
# ^^^^^^^^ Looks for word list here.
# ASCII word list, one word per line.
# If you happen to need an appropriate list,
#+ 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
if [ -z "$1" ] # If no word pattern specified
then #+ as a command-line argument . . .
echo #+ . . . then . . .
echo "Usage:" #+ Usage message.
echo
echo ""$0" \"pattern,\""
echo "where \"pattern\" is in the form"
echo "xxx..x.x..."
echo
echo "The x's represent known letters,"
echo "and the periods are unknown letters (blanks)."
echo "Letters and periods can be in any position."
echo "For example, try: cw-solver.sh w...i....n"
echo
exit $E_NOPATT
fi
echo
# ===============================================
# This is where all the work gets done.
grep ^"$1"$ "$DICT" # Yes, only one line!
# | |
# ^ is start-of-word regex anchor.
# $ is end-of-word regex anchor.
# From _Stupid Grep Tricks_, vol. 1,
#+ a book the ABS Guide author may yet get around
#+ to writing one of these days . . .
# ===============================================
echo
exit $? # Script terminates here.
# If there are too many words generated,
#+ redirect the output to a file.
cw-solver w...i....n
twichildren
wellington
workingman
workingmen

View File

@ -1,5 +1,8 @@
#!/bin/bash #!/bin/bash
# Creating a swapfile. # Creating a swap file.
# A swap file provides a temporary storage cache
#+ which helps speed up certain filesystem operations.
ROOT_UID=0 # Root has $UID 0. ROOT_UID=0 # Root has $UID 0.
E_WRONG_USER=65 # Not root? E_WRONG_USER=65 # Not root?

View File

@ -10,23 +10,24 @@
# On a rectangular grid, let each "cell" be either "living" or "dead". # # On a rectangular grid, let each "cell" be either "living" or "dead". #
# Designate a living cell with a dot, and a dead one with a blank space.# # Designate a living cell with a dot, and a dead one with a blank space.#
# Begin with an arbitrarily drawn dot-and-blank grid, # # Begin with an arbitrarily drawn dot-and-blank grid, #
#+ and let this be the starting generation, "generation 0". # #+ and let this be the starting generation, "generation 0." #
# Determine each successive generation by the following rules: # # Determine each successive generation by the following rules: #
# 1) Each cell has 8 neighbors, the adjoining cells # # 1) Each cell has 8 neighbors, the adjoining cells #
#+ left, right, top, bottom, and the 4 diagonals. # #+ left, right, top, bottom, and the 4 diagonals. #
# #
# 123 # # 123 #
# 4*5 # # 4*5 The * is the cell in question. #
# 678 # # 678 #
# # # #
# 2) A living cell with either 2 or 3 living neighbors remains alive. # # 2) A living cell with either 2 or 3 living neighbors remains alive. #
# 3) A dead cell with 3 living neighbors becomes alive (a "birth"). #
SURVIVE=2 # SURVIVE=2 #
# 3) A dead cell with 3 living neighbors becomes alive (a "birth"). #
BIRTH=3 # BIRTH=3 #
# 4) All other cases result in a dead cell for the next generation. # # 4) All other cases result in a dead cell for the next generation. #
# ##################################################################### # # ##################################################################### #
startfile=gen0 # Read the starting generation from the file "gen0". startfile=gen0 # Read the starting generation from the file "gen0" ...
# Default, if no other file specified when invoking script. # Default, if no other file specified when invoking script.
# #
if [ -n "$1" ] # Specify another "generation 0" file. if [ -n "$1" ] # Specify another "generation 0" file.
@ -36,7 +37,7 @@ fi
############################################ ############################################
# Abort script if "startfile" not specified # Abort script if "startfile" not specified
#+ AND #+ and
#+ "gen0" not present. #+ "gen0" not present.
E_NOSTARTFILE=68 E_NOSTARTFILE=68
@ -58,7 +59,7 @@ DEAD1=_
#+ but a large grid will will cause very slow execution). #+ but a large grid will will cause very slow execution).
ROWS=10 ROWS=10
COLS=10 COLS=10
# Change above two variables to match grid size, if necessary. # Change above two variables to match grid size, as desired.
# ---------------------------------------------------------- # # ---------------------------------------------------------- #
GENERATIONS=10 # How many generations to cycle through. GENERATIONS=10 # How many generations to cycle through.
@ -81,7 +82,7 @@ generation=0 # Initialize generation count.
let "cells = $ROWS * $COLS" let "cells = $ROWS * $COLS"
# How many cells. # How many cells.
declare -a initial # Arrays containing "cells". declare -a initial # Arrays containing "cells."
declare -a current declare -a current
display () display ()
@ -229,8 +230,8 @@ GetCount () # Count live cells in passed cell's neighborhood.
IsValid $t_top $row IsValid $t_top $row
if [ $? -eq "$TRUE" ] if [ $? -eq "$TRUE" ]
then then
if [ ${array[$t_top]} = "$ALIVE1" ] if [ ${array[$t_top]} = "$ALIVE1" ] # Redundancy here.
then then # Can be optimized?
let "count += 1" let "count += 1"
fi fi
fi fi
@ -274,7 +275,7 @@ do
array[$i]=. #+ represent the cell as a period. array[$i]=. #+ represent the cell as a period.
else else
array[$i]="_" # Otherwise underscore array[$i]="_" # Otherwise underscore
fi #+ (which will later be converted to space). fi #+ (will later be converted to space).
let "i += 1" let "i += 1"
done done
@ -368,3 +369,7 @@ exit 0 # END
#+ for the script to run. #+ for the script to run.
# This would make unnecessary any changes to variables # This would make unnecessary any changes to variables
#+ in the script for an altered grid size. #+ in the script for an altered grid size.
#
# Exercise: Optimize this script.
# It has some repetitive and redundant code,
#+ for example, lines 335-336.

View File

@ -80,7 +80,7 @@
<row> <row>
<entry><option>-e -f -t -x, etc.</option></entry> <entry><option>-e -f -t -x, etc.</option></entry>
<entry><firstterm>unary</firstterm> comparison</entry> <entry><firstterm>unary</firstterm> comparison</entry>
<entry><firstterm>files</firstterm></entry> <entry>file-test</entry>
</row> </row>
<row> <row>
<entry><option>&lt; -lt &gt; -gt &lt;= -le &gt;= -ge</option></entry> <entry><option>&lt; -lt &gt; -gt &lt;= -le &gt;= -ge</option></entry>
@ -90,10 +90,11 @@
<row> <row>
<entry><option>-nt -ot -ef</option></entry> <entry><option>-nt -ot -ef</option></entry>
<entry><firstterm>compound</firstterm> comparison</entry> <entry><firstterm>compound</firstterm> comparison</entry>
<entry><firstterm>files</firstterm></entry> <entry>file-test</entry>
</row> </row>
<row> <row>
<entry><option>== -eq != -ne</option></entry> <entry><option>== -eq <link linkend="notequal">!=</link>
-ne</option></entry>
<entry>equality / inequality</entry> <entry>equality / inequality</entry>
<entry>test operators, string and integer</entry> <entry>test operators, string and integer</entry>
</row> </row>
@ -152,7 +153,7 @@
<firstterm>test</firstterm>)</entry> <firstterm>test</firstterm>)</entry>
</row> </row>
<row> <row>
<entry><option>*= /= %= += -= &lt;&lt;= &gt;&gt;= &amp;= !=</option></entry> <entry><option>*= /= %= += -= &lt;&lt;= &gt;&gt;= &amp;=</option></entry>
<entry><link linkend="arithopscomb">combination <entry><link linkend="arithopscomb">combination
assignment</link></entry> assignment</link></entry>
<entry>times-equal, divide-equal, mod-equal, etc.</entry> <entry>times-equal, divide-equal, mod-equal, etc.</entry>

View File

@ -0,0 +1,194 @@
#!/bin/bash -i
# petals.sh
#########################################################################
# Petals Around the Rose #
# #
# Version 0.1 Created by Serghey Rodin #
# Version 0.2 Modded by ABS Guide Author #
# #
# License: GPL3 #
# Used in ABS Guide with permission. #
# ##################################################################### #
hits=0 # Correct guesses.
WIN=6 # Mastered the game.
ALMOST=5 # One short of mastery.
EXIT=exit # Give up early?
RANDOM=$$ # Seeds the random number generator from PID of script.
# Bones (ASCII graphics for dice)
bone1[1]="| |"
bone1[2]="| o |"
bone1[3]="| o |"
bone1[4]="| o o |"
bone1[5]="| o o |"
bone1[6]="| o o |"
bone2[1]="| o |"
bone2[2]="| |"
bone2[3]="| o |"
bone2[4]="| |"
bone2[5]="| o |"
bone2[6]="| o o |"
bone3[1]="| |"
bone3[2]="| o |"
bone3[3]="| o |"
bone3[4]="| o o |"
bone3[5]="| o o |"
bone3[6]="| o o |"
bone="+---------+"
# Functions
instructions () {
clear
echo -n "Do you need instructions? (y/n) "; read ans
if [ "$ans" = "y" -o "$ans" = "Y" ]; then
clear
echo -e '\E[34;47m' # Blue type.
# "cat document"
cat &lt;&lt;INSTRUCTIONSZZZ
The name of the game is Petals Around the Rose,
and that name is significant.
Five dice will roll and you must guess the "answer" for each roll.
It will be zero or an even number.
After your guess, you will be told the answer for the roll, but . . .
that's ALL the information you will get.
Six consecutive correct guesses admits you to the
Fellowship of the Rose.
INSTRUCTIONSZZZ
echo -e "\033[0m" # Turn off blue.
else clear
fi
}
fortune ()
{
RANGE=7
FLOOR=0
number=0
while [ "$number" -le $FLOOR ]
do
number=$RANDOM
let "number %= $RANGE" # 1 - 6.
done
return $number
}
throw () { # Calculate each individual die.
fortune; B1=$?
fortune; B2=$?
fortune; B3=$?
fortune; B4=$?
fortune; B5=$?
calc () { # Function embedded within a function!
case "$1" in
3 ) rose=2;;
5 ) rose=4;;
* ) rose=0;;
esac # Simplified algorithm.
# Doesn't really get to the heart of the matter.
return $rose
}
answer=0
calc "$B1"; answer=$(expr $answer + $(echo $?))
calc "$B2"; answer=$(expr $answer + $(echo $?))
calc "$B3"; answer=$(expr $answer + $(echo $?))
calc "$B4"; answer=$(expr $answer + $(echo $?))
calc "$B5"; answer=$(expr $answer + $(echo $?))
}
game ()
{ # Generate graphic display of dice throw.
throw
echo -e "\033[1m" # Bold.
echo -e "\n"
echo -e "$bone\t$bone\t$bone\t$bone\t$bone"
echo -e \
"${bone1[$B1]}\t${bone1[$B2]}\t${bone1[$B3]}\t${bone1[$B4]}\t${bone1[$B5]}"
echo -e \
"${bone2[$B1]}\t${bone2[$B2]}\t${bone2[$B3]}\t${bone2[$B4]}\t${bone2[$B5]}"
echo -e \
"${bone3[$B1]}\t${bone3[$B2]}\t${bone3[$B3]}\t${bone3[$B4]}\t${bone3[$B5]}"
echo -e "$bone\t$bone\t$bone\t$bone\t$bone"
echo -e "\n\n\t\t"
echo -e "\033[0m" # Turn off bold.
echo -n "There are how many petals around the rose? "
}
# ============================================================== #
instructions
while [ "$petal" != "$EXIT" ] # Main loop.
do
game
read petal
echo "$petal" | grep [0-9] >/dev/null # Filter response for digit.
# Otherwise just roll dice again.
if [ "$?" -eq 0 ] # If-loop #1.
then
if [ "$petal" == "$answer" ]; then # If-loop #2.
echo -e "\nCorrect. There are $petal petals around the rose.\n"
(( hits++ ))
if [ "$hits" -eq "$WIN" ]; then # If-loop #3.
echo -e '\E[31;47m' # Red type.
echo -e "\033[1m" # Bold.
echo "You have unraveled the mystery of the Rose Petals!"
echo "Welcome to the Fellowship of the Rose!!!"
echo "(You are herewith sworn to secrecy.)"; echo
echo -e "\033[0m" # Turn off red & bold.
break # Exit!
else echo "You have $hits correct so far."; echo
if [ "$hits" -eq "$ALMOST" ]; then
echo "Just one more gets you to the heart of the mystery!"; echo
fi
fi # Close if-loop #3.
else
echo -e "\nWrong. There are $answer petals around the rose.\n"
hits=0 # Reset number of correct guesses.
fi # Close if-loop #2.
echo -n "Hit ENTER for the next roll, or type \"exit\" to end. "
read
if [ "$REPLY" = "$EXIT" ]; then exit
fi
fi # Close if-loop #1.
clear
done # End of main (while) loop.
###
exit $?
# Resources:
# ---------
# 1) http://en.wikipedia.org/wiki/Petals_Around_the_Rose
# (Wikipedia entry.)
# 2) http://www.borrett.id.au/computing/petals-bg.htm
# (How Bill Gates coped with the Petals Around the Rose challenge.)

View File

@ -0,0 +1,462 @@
#!/bin/bash
# qky.sh
##############################################################
# QUACKEY: a somewhat simplified version of Perquackey [TM]. #
# #
# Author: Mendel Cooper &lt;thegrendel@theriver.com&gt; #
# version 0.1.02 03 May, 2008 #
# License: GPL3 #
##############################################################
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
# or
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
NONCONS=0 # Word not constructable from letter set.
CONS=1 # Constructable.
SUCCESS=0
NG=1
FAILURE=''
NULL=0 # Zero out value of letter (if found).
MINWLEN=3 # Minimum word length.
MAXCAT=5 # Maximum number of words in a given category.
PENALTY=200 # General-purpose penalty for unacceptable words.
total=
E_DUP=70 # Duplicate word error.
TIMEOUT=10 # Time for word input.
NVLET=10 # 10 letters for non-vulnerable.
VULET=13 # 13 letters for vulnerable (not yet implemented).
declare -a Words
declare -a Status
declare -a Score=( 0 0 0 0 0 0 0 0 0 0 0 )
letters=( a n s r t m l k p r b c i d s i d z e w u e t f
e y e r e f e g t g h h i t r s c i t i d i j a t a o l a
m n a n o v n w o s e l n o s p a q e e r a b r s a o d s
t g t i t l u e u v n e o x y m r k )
# Letter distribution table shamelessly borrowed from "Wordy" game,
#+ ca. 1992, written by a certain fine fellow named Mendel Cooper.
declare -a LS
numelements=${#letters[@]}
randseed="$1"
instructions ()
{
clear
echo "Welcome to QUACKEY, the anagramming word construction game."; echo
echo -n "Do you need instructions? (y/n) "; read ans
if [ "$ans" = "y" -o "$ans" = "Y" ]; then
clear
echo -e '\E[31;47m' # Red foreground. '\E[34;47m' for blue.
cat &lt;&lt;INSTRUCTION1
QUACKEY is a variant of Perquackey [TM].
The rules are the same, but the scoring is simplified
and plurals of previously played words are allowed.
"Vulnerable" play is not yet implemented,
but it is otherwise feature-complete.
As the game begins, the player gets 10 letters.
The object is to construct valid dictionary words
of at least 3-letter-length from the letterset.
Each word-length category
-- 3-letter, 4-letter, 5-letter, ... --
fills up with the fifth word entered,
and no further words in that category are accepted.
The penalty for too-short (two-letter), duplicate, unconstructable,
and invalid (not in dictionary) words is -200. The same penalty applies
to attempts to enter a word in a filled-up category.
INSTRUCTION1
echo -n "Hit ENTER for next page of instructions. "; read az1
cat &lt;&lt;INSTRUCTION2
The scoring mostly corresponds to classic Perquackey:
The first 3-letter word scores 60, plus 10 for each additional one.
The first 4-letter word scores 120, plus 20 for each additional one.
The first 5-letter word scores 200, plus 50 for each additional one.
The first 6-letter word scores 300, plus 100 for each additional one.
The first 7-letter word scores 500, plus 150 for each additional one.
The first 8-letter word scores 750, plus 250 for each additional one.
The first 9-letter word scores 1000, plus 500 for each additional one.
The first 10-letter word scores 2000, plus 2000 for each additional one.
Category completion bonuses are:
3-letter words 100
4-letter words 200
5-letter words 400
6-letter words 800
7-letter words 2000
8-letter words 10000
This is a simplification of the absurdly complicated Perquackey bonus
scoring system.
INSTRUCTION2
echo -n "Hit ENTER for final page of instructions. "; read az1
cat &lt;&lt;INSTRUCTION3
Hitting just ENTER for a word entry ends the game.
Individual word entry is timed to a maximum of 10 seconds.
*** Timing out on an entry ends the game. ***
Other than that, the game is untimed.
--------------------------------------------------
Game statistics are automatically saved to a file.
--------------------------------------------------
For competitive ("duplicate") play, a previous letterset
may be duplicated by repeating the script's random seed,
command-line parameter \$1.
For example, "qky 7633" specifies the letterset
c a d i f r h u s k ...
INSTRUCTION3
echo; echo -n "Hit ENTER to begin game. "; read az1
echo -e "\033[0m" # Turn off red.
else clear
fi
clear
}
seed_random ()
{ # Seed random number generator.
if [ -n "$randseed" ] # Can specify random seed.
then #+ for play in competitive mode.
# RANDOM="$randseed"
echo "RANDOM seed set to "$randseed""
else
randseed="$$" # Or get random seed from process ID.
echo "RANDOM seed not specified, set to Process ID of script ($$)."
fi
RANDOM="$randseed"
echo
}
get_letset ()
{
element=0
echo -n "Letterset:"
for lset in $(seq $NVLET)
do # Pick random letters to fill out letterset.
LS[element]="${letters[$((RANDOM%numelements))]}"
((element++))
done
echo
echo "${LS[@]}"
}
add_word ()
{
wrd="$1"
local idx=0
Status[0]=""
Status[3]=""
Status[4]=""
while [ "${Words[idx]}" != '' ]
do
if [ "${Words[idx]}" = "$wrd" ]
then
Status[3]="Duplicate-word-PENALTY"
let "Score[0]= 0 - $PENALTY"
let "Score[1]-=$PENALTY"
return $E_DUP
fi
((idx++))
done
Words[idx]="$wrd"
get_score
}
get_score()
{
local wlen=0
local score=0
local bonus=0
local first_word=0
local add_word=0
local numwords=0
wlen=${#wrd}
numwords=${Score[wlen]}
Score[2]=0
Status[4]="" # Initialize "bonus" to 0.
case "$wlen" in
3) first_word=60
add_word=10;;
4) first_word=120
add_word=20;;
5) first_word=200
add_word=50;;
6) first_word=300
add_word=100;;
7) first_word=500
add_word=150;;
8) first_word=750
add_word=250;;
9) first_word=1000
add_word=500;;
10) first_word=2000
add_word=2000;; # This category modified from original rules!
esac
((Score[wlen]++))
if [ ${Score[wlen]} -eq $MAXCAT ]
then # Category completion bonus scoring simplified!
case $wlen in
3 ) bonus=100;;
4 ) bonus=200;;
5 ) bonus=400;;
6 ) bonus=800;;
7 ) bonus=2000;;
8 ) bonus=10000;;
esac # Needn't worry about 9's and 10's.
Status[4]="Category-$wlen-completion***BONUS***"
Score[2]=$bonus
else
Status[4]="" # Erase it.
fi
let "score = $first_word + $add_word * $numwords"
if [ "$numwords" -eq 0 ]
then
Score[0]=$score
else
Score[0]=$add_word
fi # All this to distinguish last-word score
#+ from total running score.
let "Score[1] += ${Score[0]}"
let "Score[1] += ${Score[2]}"
}
get_word ()
{
local wrd=''
read -t $TIMEOUT wrd # Timed read.
echo $wrd
}
is_constructable ()
{ # This was the most complex and difficult-to-write function.
local -a local_LS=( "${LS[@]}" ) # Local copy of letter set.
local is_found=0
local idx=0
local pos
local strlen
local local_word=( "$1" )
strlen=${#local_word}
while [ "$idx" -lt "$strlen" ]
do
is_found=$(expr index "${local_LS[*]}" "${local_word:idx:1}")
if [ "$is_found" -eq "$NONCONS" ] # Not constructable!
then
echo "$FAILURE"; return
else
((pos = ($is_found - 1) / 2)) # Compensate for spaces betw. letters!
local_LS[pos]=$NULL # Zero out used letters.
((idx++)) # Bump index.
fi
done
echo "$SUCCESS"
return
}
is_valid ()
{ # Surprisingly easy to check if word in dictionary ...
fgrep -qw "$1" "$WLIST" # ... thanks to 'grep' ...
echo $?
}
check_word ()
{
if [ -z "$1" ]
then
return
fi
Status[1]=""
Status[2]=""
Status[3]=""
Status[4]=""
iscons=$(is_constructable "$1")
if [ "$iscons" ]
then
Status[1]="constructable"
v=$(is_valid "$1")
if [ "$v" -eq "$SUCCESS" ]
then
Status[2]="valid"
strlen=${#1}
if [ ${Score[strlen]} -eq "$MAXCAT" ] # Category full!
then
Status[3]="Category-$strlen-overflow-PENALTY"
return $NG
fi
case "$strlen" in
1 | 2 )
Status[3]="Two-letter-word-PENALTY"
return $NG;;
* )
Status[3]=""
return $SUCCESS;;
esac
else
Status[3]="Not-valid-PENALTY"
return $NG
fi
else
Status[3]="Not-constructable-PENALTY"
return $NG
fi
### FIXME: Streamline the above code.
}
display_words ()
{
local idx=0
local wlen0
clear
echo "Letterset: ${LS[@]}"
echo "Threes: Fours: Fives: Sixes: Sevens: Eights:"
echo "------------------------------------------------------------"
while [ "${Words[idx]}" != '' ]
do
wlen0=${#Words[idx]}
case "$wlen0" in
3) ;;
4) echo -n " " ;;
5) echo -n " " ;;
6) echo -n " " ;;
7) echo -n " " ;;
8) echo -n " " ;;
esac
echo "${Words[idx]}"
((idx++))
done
### FIXME: The word display is pretty crude.
}
play ()
{
word="Start game" # Dummy word, to start ...
while [ "$word" ] # If player just hits return (blank word),
do #+ then game ends.
echo "$word: "${Status[@]}""
echo -n "Last score: [${Score[0]}] TOTAL score: [${Score[1]}]: Next word: "
total=${Score[1]}
word=$(get_word)
check_word "$word"
if [ "$?" -eq "$SUCCESS" ]
then
add_word "$word"
else
let "Score[0]= 0 - $PENALTY"
let "Score[1]-=$PENALTY"
fi
display_words
done # Exit game.
### FIXME: The play () function calls too many other functions.
### This is perilously close to "spaghetti code" ...
}
end_of_game ()
{ # Save and display stats.
#######################Autosave##########################
savefile=qky.save.$$
# ^^ PID of script
echo `date` >> $savefile
echo "Letterset # $randseed (random seed) ">> $savefile
echo -n "Letterset: " >> $savefile
echo "${LS[@]}" >> $savefile
echo "---------" >> $savefile
echo "Words constructed:" >> $savefile
echo "${Words[@]}" >> $savefile
echo >> $savefile
echo "Score: $total" >> $savefile
echo "Statistics for this round saved in \""$savefile"\""
#########################################################
echo "Score for this round: $total"
echo "Words: ${Words[@]}"
}
# ---------#
instructions
seed_random
get_letset
play
end_of_game
# ---------#
exit $?
# TODO:
#
# 1) Clean up code!
# 2) Prettify the display_words () function (maybe with widgets?).
# 3) Improve the time-out ... maybe change to untimed entry,
#+ but with a time limit for the overall round.
# 4) An on-screen countdown timer would be nice.
# 5) Implement "vulnerable" mode of play.
# 6) Improve save-to-file capability (and maybe make it optional).
# 7) Fix bugs!!!

View File

@ -26,3 +26,6 @@ adr=${1:-`whoami`} # Default to current user, if not specified.
echo "At `date`, script \"`basename $0`\" mailed to "$adr"." echo "At `date`, script \"`basename $0`\" mailed to "$adr"."
exit 0 exit 0
# Note that the "mailx" command (in "send" mode) may be substituted
#+ for "mail" ... but with somewhat different options.

View File

@ -3,8 +3,9 @@
# TMOUT=3 Also works, as of newer versions of Bash. # TMOUT=3 Also works, as of newer versions of Bash.
TIMER_INTERRUPT=14
TIMELIMIT=3 # Three seconds in this instance. May be set to different value. TIMELIMIT=3 # Three seconds in this instance.
# May be set to different value.
PrintAnswer() PrintAnswer()
{ {
@ -13,28 +14,30 @@ PrintAnswer()
echo $answer echo $answer
else # Don't want to mix up the two instances. else # Don't want to mix up the two instances.
echo "Your favorite veggie is $answer" echo "Your favorite veggie is $answer"
kill $! # Kills no longer needed TimerOn function running in background. kill $! # Kills no-longer-needed TimerOn function
# $! is PID of last job running in background. #+ running in background.
# $! is PID of last job running in background.
fi fi
} }
TimerOn() TimerOn()
{ {
sleep $TIMELIMIT && kill -s 14 $$ & sleep $TIMELIMIT && kill -s 14 $$ &
# Waits 3 seconds, then sends sigalarm to script. # Waits 3 seconds, then sends sigalarm to script.
} }
Int14Vector() Int14Vector()
{ {
answer="TIMEOUT" answer="TIMEOUT"
PrintAnswer PrintAnswer
exit 14 exit $TIMER_INTERRUPT
} }
trap Int14Vector 14 # Timer interrupt (14) subverted for our purposes. trap Int14Vector $TIMER_INTERRUPT
# Timer interrupt (14) subverted for our purposes.
echo "What is your favorite vegetable " echo "What is your favorite vegetable "
TimerOn TimerOn
@ -42,12 +45,14 @@ read answer
PrintAnswer PrintAnswer
# Admittedly, this is a kludgy implementation of timed input, # Admittedly, this is a kludgy implementation of timed input.
#+ however the "-t" option to "read" simplifies this task. # However, the "-t" option to "read" simplifies this task.
# See "t-out.sh", below. # See the "t-out.sh" script.
# However, what about timing not just single user input,
#+ but an entire script?
# If you need something really elegant... # If you need something really elegant ...
#+ consider writing the application in C or C++, #+ consider writing the application in C or C++,
#+ using appropriate library functions, such as 'alarm' and 'setitimer'. #+ using appropriate library functions, such as 'alarm' and 'setitimer.'
exit 0 exit 0