This commit is contained in:
gferg 2002-07-22 15:12:57 +00:00
parent 77c6f1f451
commit 9a5932bc1e
10 changed files with 565 additions and 0 deletions

View File

@ -0,0 +1,23 @@
#!/bin/bash
# agram.sh: Playing games with anagrams.
# Find anagrams of...
LETTERSET=etaoinshrdlu
anagram "$LETTERSET" | # Find all anagrams of the letterset...
grep '.......' | # With at least 7 letters,
grep '^is' | # starting with 'is'
grep -v 's$' | # no plurals
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.2.tar.gz
exit 0 # End of code.
bash$ sh agram.sh
islander
isolate
isolead
isotheral

View File

@ -0,0 +1,119 @@
#!/bin/bash
# cannon.sh: Approximating PI by firing cannonballs.
# This is a very simple instance of a "Monte Carlo" simulation,
#+ a mathematical model of a real-life event,
#+ using pseudorandom numbers to emulate random chance.
# Consider a perfectly square plot of land, 10000 units on a side.
# This land has a perfectly circular lake in its center,
#+ with a diameter of 10000 units.
# The plot is actually all water, except for the four corners.
# (Think of it as a square with an inscribed circle.)
#
# Let us fire solid iron cannonballs from an old-style cannon
#+ at the square of land.
# All the shots impact somewhere on the plot of land,
#+ either in the lake or on the dry corners.
# Since the lake takes up most of the land area,
#+ most of the shots will SPLASH! into the water.
# Just a few shots will THUD! into solid ground
#+ in the far corners of the land.
#
# If we take enough random, unaimed shots at the plot of land,
#+ Then the ratio of SPLASHES to total shots will approximate
#+ the value of PI/4
# Exercise: Explain why.
#
# Theoretically, the more shots taken, the better the fit.
# However, a shell script, as opposed to a compiled language
#+ with floating-point math built in, requires a few compromises.
# This tends to make the simulation less accurate, unfortunately.
DIMENSION=10000 # Length of each side of the plot of land.
# Also sets ceiling for random integers generated.
MAXSHOTS=1000 # Fire this many shots.
# 10000 or more would be better, but would take too long.
PMULTIPLIER=4.0 # Scaling factor to approximate PI.
get_random ()
{
SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }')
RANDOM=$SEED # From "seeding-random.sh"
#+ example script.
let "rnum = $RANDOM % $DIMENSION" # Range less than 10000.
echo $rnum
}
distance= # Declare global variable.
hypotenuse () # Calculate hypotenuse of a right triangle.
{ # From "alt-bc.sh" example.
distance=$(bc -l << EOF
scale = 0
sqrt ( $1 * $1 + $2 * $2 )
EOF
)
# Setting "scale" to zero rounds down result to integer value,
#+ a necessary compromise in this script.
# This diminshes the accuracy of the simulation, unfortunately.
}
# main() {
# Initialize variables.
shots=0
splashes=0
thuds=0
Pi=0
while [ "$shots" -lt "$MAXSHOTS" ] # Main loop.
do
xCoord=$(get_random) # Get random X and Y coords.
yCoord=$(get_random)
hypotenuse $xCoord $yCoord # Hypotenuse of right-triangle =
#+ distance.
((shots++))
printf "#%4d " $shots
printf "Xc = %4d " $xCoord
printf "Yc = %4d " $yCoord
printf "Distance = %5d " $distance # Distance from center
#+ of lake.
if [ "$distance" -le "$DIMENSION" ]
then
echo -n "SPLASH! "
((splashes++))
else
echo -n "THUD! "
((thuds++))
fi
Pi=$(echo "scale=9; $PMULTIPLIER*$splashes/$shots" | bc)
# Multiply ratio by 4.0.
echo -n "PI ~ $Pi"
echo
done
echo
echo "After $shots shots, PI looks like approximately $Pi."
# Tends to run a bit high...
# Probably due to round-off error and imperfect randomness of $RANDOM.
echo
# }
exit 0
# One might well wonder whether a shell script is appropriate for
#+ an application as complex and computation-intensive as a simulation.
#
# There are at least two justifications.
# 1) As a proof of concept: to show it can be done.
# 2) To prototype and test the algorithms before rewriting
#+ it in a compiled high-level language.

View File

@ -0,0 +1,63 @@
#!/bin/bash
# color-echo.sh: Echoing text messages in color.
# Modify this script for your own purposes.
# It's easier than hand-coding color.
black='\E[30;47m'
red='\E[31;47m'
green='\E[32;47m'
yellow='\E[33;47m'
blue='\E[34;47m'
magenta='\E[35;47m'
cyan='\E[36;47m'
white='\E[37;47m'
alias Reset="tput sgr0" # Reset text attributes to normal
#+ without clearing screen.
cecho () # Color-echo.
# Argument $1 = message
# Argument $1 = color
{
local default_msg="No message passed."
# Doesn't really need to be a local variable.
message=${1:-$default_msg} # Defaults to default message.
color=${2:-$black} # Defaults to black, if not specified.
echo -e "$color"
echo "$message"
Reset # Reset to normal.
return
}
# Now, let's try it out.
# ----------------------------------------------------
cecho "Feeling blue..." $blue
cecho "Magenta looks more like purple." $magenta
cecho "Green with envy." $green
cecho "Seeing red?" $red
cecho "Cyan, more familiarly known as aqua." $cyan
cecho "No color passed (defaults to black)."
# Missing $color argument.
cecho "\"Empty\" color passed (defaults to black)." ""
# Empty $color argument.
cecho
# Missing $message and $color arguments.
cecho "" ""
# Empty $message and $color arguments.
# ----------------------------------------------------
echo
exit 0
# Exercises:
# ---------
# 1) Add the "bold" attribute to the 'cecho ()' function.
# 2) Add options for colored backgrounds.

View File

@ -0,0 +1,75 @@
#!/bin/bash
# ex30a.sh: "Colorized" version of ex30.sh.
# Crude address database
clear # Clear the screen.
echo -n " "
echo -e '\E[37;44m'"\033[1mContact List\033[0m"
# White on blue background
echo; echo
echo -e "\033[1mChoose one of the following persons:\033[0m"
# Bold
tput sgr0
echo "(Enter only the first letter of name.)"
echo
echo -en '\E[47;34m'"\033[1mE\033[0m" # Blue
tput sgr0 # Reset colors to "normal."
echo "vans, Roland" # "[E]vans, Roland"
echo -en '\E[47;35m'"\033[1mJ\033[0m" # Magenta
tput sgr0
echo "ones, Mildred"
echo -en '\E[47;32m'"\033[1mS\033[0m" # Green
tput sgr0
echo "mith, Julie"
echo -en '\E[47;31m'"\033[1mZ\033[0m" # Red
tput sgr0
echo "ane, Morris"
echo
read person
case "$person" in
# Note variable is quoted.
"E" | "e" )
# Accept upper or lowercase input.
echo
echo "Roland Evans"
echo "4321 Floppy Dr."
echo "Hardscrabble, CO 80753"
echo "(303) 734-9874"
echo "(303) 734-9892 fax"
echo "revans@zzy.net"
echo "Business partner & old friend"
;;
"J" | "j" )
echo
echo "Mildred Jones"
echo "249 E. 7th St., Apt. 19"
echo "New York, NY 10009"
echo "(212) 533-2814"
echo "(212) 533-9972 fax"
echo "milliej@loisaida.com"
echo "Girlfriend"
echo "Birthday: Feb. 11"
;;
# Add info for Smith & Zane later.
* )
# Default option.
# Empty input (hitting RETURN) fits here, too.
echo
echo "Not yet in database."
;;
esac
tput sgr0 # Reset colors to "normal."
echo
exit 0

View File

@ -0,0 +1,25 @@
#!/bin/bash
# poem.sh
# Lines of the poem (single stanza).
Line[1]="I do not know which to prefer,"
Line[2]="The beauty of inflections"
Line[3]="Or the beauty of innuendoes,"
Line[4]="The blackbird whistling"
Line[5]="Or just after."
# Attribution.
Attrib[1]=" Wallace Stevens"
Attrib[2]="\"Thirteen Ways of Looking at a Blackbird\""
for index in 1 2 3 4 5 # Five lines.
do
printf " %s\n" "${Line[index]}"
done
for index in 1 2 # Two attribution lines.
do
printf " %s\n" "${Attrib[index]}"
done
exit 0

View File

@ -0,0 +1,40 @@
#!/bin/bash
# self-source.sh: a script sourcing itself "recursively."
# From "Stupid Script Tricks," Volume II.
MAXPASSCNT=100 # Maximum number of execution passes.
echo -n "$pass_count "
# At first execution pass, this just echoes two blank spaces,
#+ since $pass_count still uninitialized.
let "pass_count += 1"
# Assumes the uninitialized variable $pass_count
#+ can be incremented the first time around.
# This works with Bash and pdksh, but
#+ it relies on non-portable (and possibly dangerous) behavior.
# Better would be to set $pass_count to 0 if non-initialized.
while [ "$pass_count" -le $MAXPASSCNT ]
do
. $0 # Script "sources" itself, rather than calling itself.
# ./$0 (which would be true recursion) doesn't work here.
done
# What occurs here is not actually recursion,
#+ since the script effectively "expands" itself
#+ (generates a new section of code)
#+ with each pass throught the 'while' loop',
# with each 'source' in line 20.
#
# Of course, the script interprets each newly 'sourced' "#!" line
#+ as a comment, and not as the start of a new script.
echo
exit 0 # The net effect is counting from 1 to 100.
# Very impressive.
# Exercise:
# --------
# Write a script that uses this trick to do something useful.

View File

@ -0,0 +1,157 @@
#!/bin/bash
# soundex.sh: Calculate "soundex" code for names
# =======================================================
# Soundex script
# by
# Mendel Cooper
# thegrendel@theriver.com
# 23 January, 2002
#
# Placed in the Public Domain.
#
# A slightly different version of this script appeared in
#+ Ed Schaefer's July, 2002 "Shell Corner" column
#+ in "Unix Review" on-line,
#+ http://www.unixreview.com/documents/uni1026336632258/
# =======================================================
ARGCOUNT=1 # Need name as argument.
E_WRONGARGS=70
if [ $# -ne "$ARGCOUNT" ]
then
echo "Usage: `basename $0` name"
exit $E_WRONGARGS
fi
assign_value () # Assigns numerical value
{ #+ to letters of name.
val1=bfpv # 'b,f,p,v' = 1
val2=cgjkqsxz # 'c,g,j,k,q,s,x,z' = 2
val3=dt # etc.
val4=l
val5=mn
val6=r
# Exceptionally clever use of 'tr' follows.
# Try to figure out what is going on here.
value=$( echo "$1" \
| tr -d wh \
| tr $val1 1 | tr $val2 2 | tr $val3 3 \
| tr $val4 4 | tr $val5 5 | tr $val6 6 \
| tr -s 123456 \
| tr -d aeiouy )
# Assign letter values.
# Remove duplicate numbers, except when separated by vowels.
# Ignore vowels, except as separators, so delete them last.
# Ignore 'w' and 'h', even as separators, so delete them first.
#
# The above command substitution lays more pipe than a plumber &lt;g&gt;.
}
input_name="$1"
echo
echo "Name = $input_name"
# Change all characters of name input to lowercase.
# ------------------------------------------------
name=$( echo $input_name | tr A-Z a-z )
# ------------------------------------------------
# Just in case argument to script is mixed case.
# Prefix of soundex code: first letter of name.
# --------------------------------------------
char_pos=0 # Initialize character position.
prefix0=${name:$char_pos:1}
prefix=`echo $prefix0 | tr a-z A-Z`
# Uppercase 1st letter of soundex.
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.
# 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
#+ is a vowel or 'w' or 'h', because otherwise this would bollix things up.
char1=`echo $prefix | tr A-Z a-z` # First letter of name, lowercased.
assign_value $name
s1=$value
assign_value $name1
s2=$value
assign_value $char1
s3=$value
s3=9$s3 # If first letter of name is a vowel
#+ or 'w' or 'h',
#+ then its "value" will be null (unset).
#+ Therefore, set it to 9, an otherwise
#+ unused value, which can be tested for.
if [[ "$s1" -ne "$s2" || "$s3" -eq 9 ]]
then
suffix=$s2
else
suffix=${s2:$char_pos}
fi
# ++++++++++++++++++++++ end Exception Patch +++++++++++++++++++++++++++++++++
padding=000 # Use at most 3 zeroes to pad.
soun=$prefix$suffix$padding # Pad with zeroes.
MAXLEN=4 # Truncate to maximum of 4 chars.
soundex=${soun:0:$MAXLEN}
echo "Soundex = $soundex"
echo
# The soundex code is a method of indexing and classifying names
#+ by grouping together the ones that sound alike.
# The soundex code for a given name is the first letter of the name,
#+ followed by a calculated three-number code.
# Similar sounding names should have almost the same soundex codes.
# Examples:
# Smith and Smythe both have a "S-530" soundex.
# Harrison = H-625
# Hargison = H-622
# Harriman = H-655
# This works out fairly well in practice, but there are numerous anomalies.
#
#
# The U.S. Census and certain other governmental agencies use soundex,
# as do genealogical researchers.
#
# For more information,
#+ see the "National Archives and Records Administration home page",
#+ http://www.nara.gov/genealogy/soundex/soundex.html
# Exercise:
# --------
# Simplify the "Exception Patch" section of this script.
exit 0

View File

@ -0,0 +1,23 @@
#!/bin/bash
# tempfile-name.sh: temp filename generator
BASE_STR=`mcookie` # 32-character magic cookie.
POS=11 # Arbitrary position in magic cookie string.
LEN=5 # Get $LEN consecutive characters.
prefix=temp # This is, after all, a "temp" file.
# For more "uniqueness," generate the filename prefix
#+ using the same method as the suffix, below.
suffix=${BASE_STR:POS:LEN}
# Extract a 5-character string, starting at position 11.
temp_filename=$prefix.$suffix
# Construct the filename.
echo "Temp filename = "$temp_filename""
# sh tempfile-name.sh
# Temp filename = temp.e19ea
exit 0

View File

@ -0,0 +1,24 @@
#!/bin/bash
# unit-conversion.sh
convert_units () # Takes as arguments the units to convert.
{
cf=$(units "$1" "$2" | sed --silent -e '1p' | awk '{print $2}')
# Strip off everything except the actual conversion factor.
echo "$cf"
}
Unit1=miles
Unit2=meters
cfactor=`convert_units $Unit1 $Unit2`
quantity=3.73
result=$(echo $quantity*$cfactor | bc)
echo "There are $result $Unit2 in $quantity $Unit1."
# What happens if you pass incompatible units,
#+ such as "acres" and "miles" to the function?
exit 0

View File

@ -0,0 +1,16 @@
#!/bin/bash
# usage-message.sh
: ${1?"Usage: $0 ARGUMENT"}
# Script exits here if command-line parameter absent,
#+ with following error message.
# usage-message.sh: 1: Usage: usage-message.sh ARGUMENT
echo "These two lines echo only if command-line parameter given."
echo "command line parameter = \"$1\""
exit 0 # Will exit here only if command-line parameter present.
# Check the exit status, both with and without command-line parameter.
# If command-line parameter present, then "$?" is 0.
# If not, then "$?" is 1.