This commit is contained in:
gferg 2002-04-01 16:04:17 +00:00
parent 1d623d704e
commit 112d2a3d5c
56 changed files with 1819 additions and 456 deletions

View File

@ -2,7 +2,183 @@ RELEASE HISTORY
------- -------
Change log
Version 1.0.X interim release
Version 1.2
03/31/02
1) In "Operators" subsection of "Operations and Related Topics" chapter:
Fixed comment in in-line example (thanks, Marcus Bergöf).
Added "gcd.sh" example at "%" (modulo) operator.
2) In "Numerical Constants" subsection of "Operations and Related Topics"
chapter:
Fixed up and enhanced "numbers.sh" example (thanks, Rich Bartell).
3) In "arithops.sh" example, fixed comment to refer to correct operation
(thanks, Marcus Bergöf).
4) In "Command Substitution" chapter:
Added excerpts from /etc/rc.d/rc.sysinit as examples of setting
a variable to the contents of a file using "var=`cat filename`
construction.
Added "csubloop.sh" example of setting a variable from the output of a
loop.
5) In "Basic Commands" section of "External Commands and Filters" chapter:
Added info on "-f" option at "mv" and "rm".
Added "-s" option at "cat".
6) In "Text Processing Commands" sect. of "External Commands and Filters" chapt.:
Added more info for "nl".
Rewrote "groff" as a separate entry, and added "col" and "tbl"/"eqn"
as subentries.
Added much more info on "tr".
Added more options to "grep".
7) In "Complex Commands" section of "External Commands" chapter:
Added more info at "xargs".
Added caution when using "*" with "expr" in arithmetic operation.
8) In "Miscellaneous Commands" section of "External Commands" chapter:
Added more info on "jot/seq".
Added "Linux Journal" reference at "m4".
9) In "File and Archiving Commands" section of "External Commands and Filters"
chapter:
Added "mimencode/mmencode".
More info on "cksum"/"md5sum".
Added "wstrings.sh" example at "strings" entry.
10) In "Communications Commands" section of "External Commands" chapter:
Added "mail", with "self-mailer.sh" illustrative example.
11) In "Time/Date Commands" section of "External Commands" chapter:
Added discussion of "-u" option to "date".
12) In "Special Variable Types" section of "Introduction to Variables" chapter:
Improved link to "bracket" notation.
Added note that "shift" command also applies to function parameters.
13) In "Internal Variables" section of "Variables Revisited" chapter:
Added info on "$@" special variable, with new in-line example.
Corrected "$DIRSTACK" listing (thanks again, Nick Drage).
At "$TMOUT", added "t-out.sh", another example of timed input (thanks,
syngin seven).
Added commentary to "am-i-root.sh" example.
14) Changed document subtitle.
15) In "Command Substitution" chapter:
Corrected word-splitting example in "caution" (thanks, Tony Richardson).
Added "stupid-script-tricks.sh" example of setting a variable to the
contents of a binary file (which has no useful applications).
16) In "Internal Commands and Builtins" chapter:
Clarified "ex43.sh" example (thanks, Tony Richardson).
Clarified explanation and example of "echo" eating linefeeds in a
command fed to it.
More info on "keywords" topic.
17) In "Special Characters" chapter:
Added in-line example of embedding Ctl-H's in a variable.
More info on '-' as an option to certain commands.
Added "background-loop.sh" example at "&" (run command in background).
18) In "Bash, version 2" chapter:
Added "resistor-inventory.sh" example of database using indirect variable
referencing.
19) Changed name of example "rot13_2.sh" to "rot14.sh" because otherwise SGML
conversion seems to experience namespace confusion.
20) In "Quoting" chapter:
Added header notes to "\" escape usage listing.
Added in-line example on behavior of "\".
Slight revisions to "escaped.sh" example.
21) In "Internal Variables" section of "Variables Revisited" Chapter:
Added usage example for "$GROUPS".
22) In "Gotchas" chapter:
Added mixing up integer and string comparison operators.
23) In "While Loops" subsection of "Loops and Branches" chapter:
Added clarifying statement as to when "while loops" are used.
Added "userlist.sh" example of command substitution in generating
"[list]" in "for loop".
24) In "System and Administrative Commands" chapter:
Added "rmmod".
added "sudo".
Added commentary on "debugfs".
25) In "Exercises" Appendix:
Reorganization into two distinct subsections.
Added a sample script to annotate.
Added a script code snippet to fix up.
Added a few more script writing problems, including the very difficult
"Playfair Cipher".
26) Simplified "wf.sh" example.
27) In "Starting off with a Sha-Bang" chapter:
Fixed typo in "ex2.sh" example script (thanks, David Kimbro for
bringing this to my attention).
28) In "Arrays" chapter:
Rewrote confusing language in introductory paragraph.
Added "stackex.sh" example for emulating data structures.
Added in-line example of loading an array with the contents of a text
file.
29) In "Tests" chapter:
Clarification of why semicolon needed when "if" and "then" are on same
line.
Added material to "ex10.sh" example.
30) In "Here Documents" chapter:
Modified "ex69.sh" example, per message from Jess Thrysoee relaying to me
clarification from Bram Moolenaar.
31) In "I/O Redirection" chapter:
Fixed comment on in-line example on closing file descriptors.
(Thanks, Matthieu Lucotte)
Made the data file for redirection examples, "names.data", visible.
32) In "Assorted Tips" section of "Miscellany" chapter:
Added repeated piping of the output of a filter back to that same filter.
Added alternative method of having a function return a value to the body
of the script, with "multiplication.sh" example showing how.
Added method of having a function "return" multiple values,
with illustrative "sum-product.sh" example.
Added "tolower()" function to function library.
Added methods of passing an array to a function, and returning an array
from a function to the main body of a script (with example
"array-function.sh").
33) In "Contributed Scripts" appendix:
Added "collatz.sh" example.
Added "life.sh" example (Conway's "Game of Life").
34) In "Exit Codes" appendix:
Added footnote with more information about out of range exit codes
(thanks for tweaking my curiosity about this, Akira Huang).
35) In "Sed Micro-Primer" appendix:
Added use of backslash as newline.
Added example of operation(s) over an address range.
36) In "Bibliography" section:
Added Pickover entry.
37) Clarifications in "Copyright" appendix.
38) Various minor edits to various example scripts.
Version 1.1 release
01/06/02
1) Fix up comments in "weirdvars.sh" example.
@ -629,7 +805,7 @@ In "External Filters, Programs, and Commands" section:
Added four sites for example shell scripts.
Added reference to Rick Hohensee's shell-scripted virtual machine + assembler.
17) Added "mail-format.sh" to "Contributed Scripts" section.
17) Added "mail-format.sh" to "Contributed Scripts" appendix.
18) In "Tests" section:
Clearer definition of what "test" actually means.
@ -793,7 +969,7 @@ In "External Filters, Programs, and Commands" section:
* Descriptive names for variables added.
62) Added "copy-cd.sh", a script for copying data CDs, to "Contributed
Scripts" section.
Scripts" appendix.
63) In "Loops" section, separated "Loop Control Commands" ("break" and "continue")
into a separate subsection.
@ -1192,7 +1368,7 @@ In "External Filters, Programs, and Commands" section:
Added using "[[ ]]" and "(( ))" in comparisons.
Corrections in discussion of interactive shells, plus
illustrative example.
In "Contributed Scripts" section:
In "Contributed Scripts" appendix:
Added "primes.sh" to demonstrate that arrays are not need to
generate prime numbers.
Added comments to "manview.sh"
@ -1246,7 +1422,7 @@ Comments: Another major improvement. The HOWTO is nearly book length,
Changes from version 0.2:
1) Fixed:
Renamed Example A-2 in Appendix A (Contributed Scripts) to
Renamed Example A-2 in Appendix A (Contributed Scripts appendix) to
"encryptedpw". It had previously been named "manview", duplicating
the title of Example A-1.
@ -1299,20 +1475,20 @@ In "External Filters, Programs, and Commands" section:
21) Added "su" to "System and Administrative Commands" section.
22) Added Jim Van Zandt's "daily backup" example script
to "Contrib-Scripts" section.
to "Contrib-Scripts" appendix.
23) Enhanced example 66 (ex66.sh) on arrays with more methods of initializing
array variables.
24) Corrected "Siever" entry in bibliography.
25) Added Jordi Sanfeliu's "tree" script to "Contrib-Scripts" section.
25) Added Jordi Sanfeliu's "tree" script to "Contrib-Scripts" appendix.
26) Added Robbins' "Bash Reference Card" to bibliography.
27) Added reference to Duarte's sed tutorial in bibliography.
28) Added "rn.sh", file rename utility to "Contrib-Scripts" section.
28) Added "rn.sh", file rename utility to "Contrib-Scripts" appendix.
29) Added "initializing multiple variables on same line" to ex9.sh.
@ -1625,7 +1801,7 @@ Other changes
subsection 'Optimizations'
subsection 'Assorted Tips'
56) Contrib script section added
56) Contrib script section added.
4 scripts so far.
57) Expanded 'Credits' section.

File diff suppressed because it is too large Load Diff

View File

@ -20,12 +20,10 @@ exit 0
ROOTUSER_NAME=root
username=`id -nu`
username=`id -nu` # Or... username=`whoami`
if [ "$username" = "$ROOTUSER_NAME" ]
then
echo "Rooty, toot, toot. You are root."
else
echo "You are just a regular fella."
fi
exit 0

View File

@ -16,7 +16,7 @@ echo -n "$n "
: $[ n = $n + 1 ]
# ":" necessary because otherwise Bash attempts
#+ to interpret "$((n = $n + 1))" as a command.
#+ to interpret "$[ n = $n + 1 ]" as a command.
# Works even if "n" was initialized as a string.
echo -n "$n "

View File

@ -17,7 +17,7 @@ assert () # If condition false,
if [ ! $1 ]
then
echo "Assertion failed: \"$1\""
echo "File $0, line $lineno"
echo "File \"$0\", line $lineno"
exit $E_ASSERT_FAILED
# else
# return
@ -38,6 +38,8 @@ assert "$condition" $LINENO
# Some commands.
# ...
echo "You will never see this statement echo."
# ...
# Some more commands.
exit 0

View File

@ -18,7 +18,7 @@ else
done
fi
# ==> Exercise for the reader: Add error checking and other options.
# ==> 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?

View File

@ -3,29 +3,32 @@
# Recall the algorithm for a bubble sort. In this particular version...
# With each successive pass through the array to be sorted,
# compare two adjacent elements, and swap them if out of order.
# At the end of the first pass, the "heaviest" element has sunk to bottom.
# At the end of the second pass, the next "heaviest" one has sunk next to bottom.
# And so forth.
# This means that each successive pass needs to traverse less of the array.
# You will therefore notice a speeding up in the printing of the later passes.
# With each successive pass through the array to be sorted,
#+ compare two adjacent elements, and swap them if out of order.
# At the end of the first pass, the "heaviest" element has sunk to bottom.
# At the end of the second pass, the next "heaviest" one has sunk next to bottom.
# And so forth.
# This means that each successive pass needs to traverse less of the array.
# You will therefore notice a speeding up in the printing of the later passes.
exchange()
{
# Swaps two members of the array.
local temp=${Countries[$1]} # Temporary storage for element getting swapped out.
local temp=${Countries[$1]} # Temporary storage
#+ for element getting swapped out.
Countries[$1]=${Countries[$2]}
Countries[$2]=$temp
return
}
declare -a Countries # Declare array, optional here since it's initialized below.
declare -a Countries # Declare array,
#+ optional here since it's initialized below.
Countries=(Netherlands Ukraine Zaire Turkey Russia Yemen Syria Brazil Argentina Nicaragua Japan Mexico Venezuela Greece England Israel Peru Canada Oman Denmark Wales France Kenya Qatar Liechtenstein Hungary)
# Couldn't think of one starting with X (darn!).
Countries=(Netherlands Ukraine Zaire Turkey Russia Yemen Syria Brazil Argentina Nicaragua Japan Mexico Venezuela Greece England Israel Peru Canada Oman Denmark Wales France Kenya Xanadu Qatar Liechtenstein Hungary)
# "Xanadu" is the mythical place where, according to Coleridge,
#+ Kubla Khan did a pleasure dome decree.
clear # Clear the screen to start with.
@ -44,11 +47,12 @@ do
while [ "$index" -lt "$comparisons" ] # Beginning of inner loop
do
if [ ${Countries[$index]} \> ${Countries[`expr $index + 1`]} ]
# If out of order...
# Recalling that \> is ASCII comparison operator.
# If out of order...
# Recalling that \> is ASCII comparison operator
#+ within single brackets.
# if [[ ${Countries[$index]} > ${Countries[`expr $index + 1`]} ]]
# also works.
# if [[ ${Countries[$index]} > ${Countries[`expr $index + 1`]} ]]
#+ also works.
then
exchange $index `expr $index + 1` # Swap.
fi
@ -56,8 +60,8 @@ do
done # End of inner loop
let "comparisons -= 1" # Since "heaviest" element bubbles to bottom,
# we need do one less comparison each pass.
let "comparisons -= 1" # Since "heaviest" element bubbles to bottom,
#+ we need do one less comparison each pass.
echo
echo "$count: ${Countries[@]}" # Print resultant array at end of each pass.
@ -65,7 +69,6 @@ echo
let "count += 1" # Increment pass count.
done # End of outer loop
# All done.
# All done.
exit 0

View File

@ -48,6 +48,7 @@ exit 0
# As it stands, this script must be terminated with a Control-C.
# Exercises for the reader:
# Exercises:
# ---------
# Improve the script so it exits on a "q" keystroke.
# Make the script more user-friendly in other ways.

View File

@ -22,7 +22,7 @@ done
echo; echo
# Exercise for the reader:
# Exercise:
# Come up with a meaningful use for "continue N" in a script.
exit 0

View File

@ -43,7 +43,7 @@ esac
echo
# Exercise for the reader:
# Exercise:
# Change the above "case" statement to also accept "yes" and "Yes" as input.
exit 0

View File

@ -45,7 +45,8 @@ check_date () # Checks for invalid date(s) passed.
[ "$day" -gt "$DIM" ] || [ "$month" -gt "$MIY" ] || [ "$year" -lt "$REFYR" ] && Param_Error
# Exit script on bad value(s).
# Uses "or-list / and-list".
# Exercise for the reader: Implement more rigorous date checking.
#
# Exercise: Implement more rigorous date checking.
}

View File

@ -4,16 +4,18 @@
echo; echo
echo "\v\v\v\v" # Prints \v\v\v\v
# Must use the -e option with 'echo' to print escaped characters.
# Use the -e option with 'echo' to print escaped characters.
echo -e "\v\v\v\v" # Prints 4 vertical tabs.
echo -e "\042" # Prints " (quote, octal ASCII character 42).
# The $'\X' construct makes the -e option unnecessary.
echo $'\n' # Newline.
echo $'\a' # Alert (beep).
# Bash, version 2 and later, permits using the $'\xxx' construct.
echo $'\n'
echo $'\a'
# Version 2 and later of Bash permits using the $'\xxx' construct.
echo $'\t \042 \t' # Quote (") framed by tabs.
# Assigning ASCII characters to a variable.
# ----------------------------------------
quote=$'\042' # " assigned to a variable.
@ -22,7 +24,7 @@ echo "$quote This is a quoted string, $quote and this lies outside the quotes."
echo
# Concatenating ASCII chars in a variable.
triple_underline=$'\137\137\137' # 137 is octal ASCII code for "_".
triple_underline=$'\137\137\137' # 137 is octal ASCII code for '_'.
echo "$triple_underline UNDERLINE $triple_underline"
ABC=$'\101\102\103\010' # 101, 102, 103 are octal A, B, C.
@ -32,6 +34,7 @@ echo; echo
escape=$'\033' # 033 is octal for escape.
echo "\"escape\" echoes as $escape"
# no visible output.
echo; echo

View File

@ -8,7 +8,27 @@ then
echo "0 is true."
else
echo "0 is false."
fi
fi # 0 is true.
echo
echo "Testing \"1\""
if [ 1 ] # one
then
echo "1 is true."
else
echo "1 is false."
fi # 1 is true.
echo
echo "Testing \"-1\""
if [ -1 ] # minus one
then
echo "-1 is true."
else
echo "-1 is false."
fi # -1 is true.
echo
@ -18,7 +38,7 @@ then
echo "NULL is true."
else
echo "NULL is false."
fi
fi # NULL is false.
echo
@ -28,7 +48,7 @@ then
echo "Random string is true."
else
echo "Random string is false."
fi
fi # Random string is true.
echo
@ -39,7 +59,7 @@ then
echo "Uninitialized variable is true."
else
echo "Uninitialized variable is false."
fi
fi # Uninitialized variable is false.
echo
@ -49,11 +69,12 @@ then
echo "Uninitialized variable is true."
else
echo "Uninitialized variable is false."
fi
fi # Uninitialized variable is false.
echo
xyz= # Initialized, but set to null value.
xyz= # Initialized, but set to null value.
echo "Testing \"-n \$xyz\""
if [ -n "$xyz" ]
@ -61,7 +82,7 @@ then
echo "Null variable is true."
else
echo "Null variable is false."
fi
fi # Null variable is false.
echo
@ -75,7 +96,7 @@ then
echo "\"false\" is true." #+ and it tests true.
else
echo "\"false\" is false."
fi
fi # "false" is true.
echo
@ -85,7 +106,8 @@ then
echo "\"\$false\" is true."
else
echo "\"\$false\" is false."
fi # Now, we get the expected result.
fi # "$false" is false.
# Now, we get the expected result.
echo

View File

@ -3,9 +3,9 @@
filename=sys.log
cat /dev/null > $filename; echo "Creating / cleaning out file."
# Creates file if it does not already exist,
# and truncates it to zero length if it does.
# : > filename also works.
# Creates file if it does not already exist,
#+ and truncates it to zero length if it does.
# : > filename also works.
tail /var/log/messages > $filename
# /var/log/messages must have world read permission for this to work.

View File

@ -5,12 +5,18 @@ echo $a
b=$a
echo $b
# Now, getting a little bit fancier...
# Now, getting a little bit fancier (command substitution).
a=`echo Hello!` # Assigns result of 'echo' command to 'a'
echo $a
# Note that using an exclamation mark (!) in command substitution
#+ will not work from the command line,
#+ since this triggers the Bash "history mechanism".
a=`ls -l` # Assigns result of 'ls -l' command to 'a'
echo $a
echo $a # Unquoted, however, removes tabs and newlines.
echo
echo "$a" # The quoted variable preserves whitespace.
# (See the chapter on "Quoting.")
exit 0

View File

@ -1,9 +1,9 @@
#!/bin/bash
# Using 'shift' to step through all the positional parameters.
# Name this script something like shft,
# and invoke it with some parameters, for example
# ./shft a b c def 23 skidoo
# Name this script something like shft,
#+ and invoke it with some parameters, for example
# ./shft a b c def 23 skidoo
until [ -z "$1" ] # Until all parameters used up...
do
@ -11,6 +11,6 @@ do
shift
done
echo # Extra line feed.
echo # Extra line feed.
exit 0

View File

@ -36,12 +36,12 @@ fi
# * ) lines=$1;;
# esac
#
#* Skip ahead to "Loops" to understand this.
#* Skip ahead to "Loops" chapter to understand this.
cd $LOG_DIR
if [ `pwd` != "$LOG_DIR" ] # or if [ "$PWD" != "LOG_DIR" ]
if [ `pwd` != "$LOG_DIR" ] # or if [ "$PWD" != "$LOG_DIR" ]
# Not in /var/log?
then
echo "Can't change to $LOG_DIR."

View File

@ -7,8 +7,8 @@ do
echo -n "$a "
done
# The 'in list' missing, therefore the loop operates on '$@'
# (command-line argument list, including whitespace).
# The 'in list' missing, therefore the loop operates on '$@'
#+ (command-line argument list, including whitespace).
echo

View File

@ -6,7 +6,7 @@ previous=$var1
while echo "previous-variable = $previous"
echo
previous=$var1
[ "$var1" != end ] # Keeps track of what "var1" was previously.
[ "$var1" != end ] # Keeps track of what $var1 was previously.
# Four conditions on "while", but only last one controls loop.
# The *last* exit status is the one that counts.
do

View File

@ -19,7 +19,7 @@ do
echo -n "$a "
done
# Exercise for the reader:
# Exercise:
# Why does loop print up to 20?
echo; echo

View File

@ -10,7 +10,8 @@ case "$Keypress" in
* ) echo "Punctuation, whitespace, or other";;
esac # Allows ranges of characters in [square brackets].
# Exercise for the reader:
# Exercise:
# --------
# As the script stands, # it accepts a single keystroke, then terminates.
# Change the script so it accepts continuous input,
# reports on each keystroke, and terminates only when "X" is hit.

View File

@ -8,13 +8,13 @@
# invoked from the command line.
sed -e /^$/d "$1"
# The '-e' means an "editing" command follows (optional here).
# '^' is the beginning of line, '$' is the end.
# This match lines with nothing between the beginning and the end,
# blank lines.
# The 'd' is the delete command.
# The '-e' means an "editing" command follows (optional here).
# '^' is the beginning of line, '$' is the end.
# This match lines with nothing between the beginning and the end,
#+ blank lines.
# The 'd' is the delete command.
# Quoting the command-line arg permits
# whitespace and special characters in the filename.
# Quoting the command-line arg permits
#+ whitespace and special characters in the filename.
exit 0

View File

@ -58,8 +58,9 @@ esac
echo
# Exercise for the reader:
# Change the script so it accepts continuous input,
# instead of terminating after displaying just one address.
# Exercise:
# --------
# Change the script so it accepts continuous input,
#+ instead of terminating after displaying just one address.
exit 0

View File

@ -3,8 +3,8 @@
. data-file # Load a data file.
# Same effect as "source data-file", but more portable.
# The file "data-file" must be present in current working directory,
# since it is referred to by its 'basename'.
# The file "data-file" must be present in current working directory,
#+ since it is referred to by its 'basename'.
# Now, reference some data from that file.

View File

@ -1,17 +1,17 @@
#!/bin/bash
SPEED=2 # May use higher speed if supported.
SPEED=2 # May use higher speed if your hardware supports it.
IMAGEFILE=cdimage.iso
CONTENTSFILE=contents
DEFAULTDIR=/opt
DEFAULTDIR=/opt # Make sure this directory exists.
# Script to automate burning a CDR.
# Uses Joerg Schilling's "cdrecord" package.
# (http://www.fokus.gmd.de/nthp/employees/schilling/cdrecord.html)
# If this script invoked as an ordinary user, need to suid cdrecord
# (chmod u+s /usr/bin/cdrecord, as root).
# If this script invoked as an ordinary user, need to suid cdrecord
#+ (chmod u+s /usr/bin/cdrecord, as root).
if [ -z "$1" ]
then

View File

@ -1,11 +1,16 @@
#!/bin/bash
y=`eval ls -l` # Similar to y=`ls -l`
echo $y # but linefeeds removed.
y=`eval ls -l` # Similar to y=`ls -l`
echo $y # but linefeeds removed because "echoed" variable is unquoted.
echo
echo "$y" # Linefeeds preserved when variable is quoted.
y=`eval df` # Similar to y=`df`
echo $y # but linefeeds removed.
echo; echo
# Since LF's not preserved, it may make it easier to parse output.
y=`eval df` # Similar to y=`df`
echo $y # but linefeeds removed.
# When LF's not preserved, it may make it easier to parse output,
#+ using utilities such as "awk".
exit 0

View File

@ -1,15 +1,15 @@
#!/bin/bash
echo hello
echo $? # Exit status 0 returned because command successful.
echo $? # Exit status 0 returned because command executed successfully.
lskdf # Unrecognized command.
echo $? # Non-zero exit status returned.
echo $? # Non-zero exit status returned because command failed to execute.
echo
exit 113 # Will return 113 to shell.
# To verify this, type "echo $?" after script terminates.
# To verify this, type "echo $?" after script terminates.
# By convention, an 'exit 0' indicates success,
# while a non-zero exit value means an error or anomalous condition.
# By convention, an 'exit 0' indicates success,
#+ while a non-zero exit value means an error or anomalous condition.

View File

@ -4,8 +4,7 @@
# Range: 0 - 200
# It's crude, but it works.
# Extending the range and otherwise improving the script
# is left as an exercise for the reader.
# Extending the range and otherwise improving the script is left as an exercise.
# Usage: roman number-to-convert
@ -40,7 +39,8 @@ do
done
return $number
# Exercise for the reader:
# Exercise:
# --------
# Explain how this function works.
# Hint: division by successive subtraction.
}

View File

@ -1,7 +1,6 @@
#!/bin/bash
# Non-interactive use of 'vi' to edit a file.
# (Will not work with 'vim', for some reason.)
# Emulates 'sed'.
E_BADARGS=65
@ -25,7 +24,10 @@ ZZ
x23LimitStringx23
#----------End here document-----------#
# Note that ^[ above is a literal escape
# typed by Control-V Escape.
# Note that ^[ above is a literal escape
#+ typed by Control-V <Esc>.
# Bram Moolenaar points out that this may not work with 'vim',
#+ because of possible problems with terminal interaction.
exit 0

View File

@ -20,7 +20,7 @@ hello=$a
echo hello # Not a variable reference, just the string "hello".
echo $hello
echo ${hello} #Identical to above.
echo ${hello} # Identical to above.
echo "$hello"
echo "${hello}"
@ -28,14 +28,14 @@ echo "${hello}"
echo
hello="A B C D"
echo $hello
echo "$hello"
# Now, echo $hello and echo "$hello" give different results.
echo $hello # A B C D
echo "$hello" # A B C D
# As you see, echo $hello and echo "$hello" give different results.
# Quoting a variable preserves whitespace.
echo
echo '$hello'
echo '$hello' # $hello
# Variable referencing disabled by single quotes,
#+ which causes the "$" to be interpreted literally.
@ -67,7 +67,7 @@ numbers="one two three"
other_numbers="1 2 3"
# If whitespace within a variable, then quotes necessary.
echo "numbers = $numbers"
echo "other_numbers = $other_numbers"
echo "other_numbers = $other_numbers" # other_numbers = 1 2 3
echo
echo "uninitialized_variable = $uninitialized_variable"

View File

@ -1,5 +1,6 @@
#!/bin/bash
# findstring.sh: Find a particular string in binaries in a specified directory.
# findstring.sh:
# Find a particular string in binaries in a specified directory.
directory=/usr/bin/
fstring="Free Software Foundation" # See which files come from the FSF.
@ -7,12 +8,15 @@ fstring="Free Software Foundation" # See which files come from the FSF.
for file in $( find $directory -type f -name '*' | sort )
do
strings -f $file | grep "$fstring" | sed -e "s%$directory%%"
# In the "sed" expression, it is necessary to substitute for the normal "/" delimiter
# because "/" happens to be one of the characters filtered out.
# Failure to do so gives an error message (try it).
# In the "sed" expression,
#+ it is necessary to substitute for the normal "/" delimiter
#+ because "/" happens to be one of the characters filtered out.
# Failure to do so gives an error message (try it).
done
exit 0
# Exercise for the reader (easy):
# Convert this script to taking command-line parameters for $directory and $fstring.
# Exercise (easy):
# ---------------
# Convert this script to taking command-line parameters
#+ for $directory and $fstring.

View File

@ -96,6 +96,7 @@ rm -f ${TMPFILE}
# ==> Finally, tempfile deleted (you may wish to copy it to a logfile).
# ==> Exercises for reader:
# ==> Exercises:
# ==> ---------
# ==> 1) Add error checking.
# ==> 2) Add bells & whistles.

View File

@ -28,7 +28,7 @@ echo
exit 0
# Exercises for reader:
# --------------------
# Exercises:
# ---------
# 1) Add newlines to output, if more than one match in any given file.
# 2) Add features.

View File

@ -3,12 +3,12 @@
# Strings
string=abcdA01
echo "len($string)" | m4 # 7
echo "substr($string,4)" | m4 # A01
echo "len($string)" | m4 # 7
echo "substr($string,4)" | m4 # A01
echo "regexp($string,[0-1][0-1],\&Z)" | m4 # 01Z
# Arithmetic
echo "incr(22)" | m4 # 23
echo "eval(99 / 3)" | m4 # 33
echo "incr(22)" | m4 # 23
echo "eval(99 / 3)" | m4 # 33
exit 0

View File

@ -3,6 +3,8 @@
# Gets rid of carets, tabs, also fold excessively long lines.
# =================================================================
# Standard Check for Script Argument(s)
ARGS=1
E_BADARGS=65
E_NOFILE=66
@ -20,9 +22,12 @@ else
echo "File \"$1\" does not exist."
exit $E_NOFILE
fi
# =================================================================
MAXWIDTH=70 # Width to fold long lines to.
# Delete carets and tabs at beginning of lines,
#+ then fold lines to $MAXWIDTH characters.
sed '
s/^>//
s/^ *>//
@ -31,7 +36,10 @@ s/ *//
' $1 | fold -s --width=$MAXWIDTH
# -s option to "fold" breaks lines at whitespace, if possible.
# This script was inspired by an article in a well-known trade journal
# extolling a 164K Windows utility with similar functionality.
# This script was inspired by an article in a well-known trade journal
#+ extolling a 164K Windows utility with similar functionality.
#
# An nice set of text processing utilities and an efficient
#+ scripting language makes unnecessary bloated executables.
exit 0

View File

@ -40,6 +40,7 @@ fi
exit 0
# Exercise for the reader (easy):
# Convert this to an interactive script,
# that is, have the script ask for input (two numbers).
# Exercise (easy):
# ---------------
# Convert this to an interactive script,
#+ that is, have the script ask for input (two numbers).

View File

@ -2,35 +2,49 @@
# numbers.sh: Representation of numbers.
# Decimal
let "d = 32"
echo "d = $d"
let "dec = 32"
echo "decimal number = $dec" # 32
# Nothing out of the ordinary here.
# Octal: numbers preceded by '0' (zero)
let "o = 071"
echo "o = $o"
let "oct = 071"
echo "octal number = $oct" # 57
# Expresses result in decimal.
# Hexadecimal: numbers preceded by '0x' or '0X'
let "h = 0x7a"
echo "h = $h"
let "hex = 0x7a"
echo "hexadecimal number = $hex" # 122
# Expresses result in decimal.
# Other bases: BASE#NUMBER
# BASE between 2 and 36.
let "b = 32#77"
echo "b = $b"
# BASE between 2 and 64.
let "bin = 2#111100111001101"
echo "binary number = $bin" # 31181
let "b32 = 32#77"
echo "base-32 number = $b32" # 231
let "b64 = 64#@_"
echo "base-64 number = $b64" # 4094
#
# This notation only works for a limited range (2 - 36)
# ... 10 digits + 26 alpha characters = 36.
let "c = 2#47" # Out of range error:
# numbers.sh: let: c = 2#47: value too great for base (error token is "2#47")
echo "c = $c"
# This notation only works for a limited range (2 - 64)
# 10 digits + 26 lowercase characters + 26 uppercase characters + @ + _
echo
echo $((36#zz)) $((2#10101010)) $((16#AF16))
echo $((36#zz)) $((2#10101010)) $((16#AF16)) $((53#1aA))
# 1295 170 44822 3375
# Important note:
# Using a digit out of range of the specified base notation
#+ will give an error message.
let "bad_oct = 081"
# numbers.sh: let: oct = 081: value too great for base (error token is "081")
# Octal numbers use only digits in the range of 0 - 7.
exit 0
# Thanks, S.C., for clarification.
# Thanks, Rich Bartell and Stephane Chazelas, for clarification.

View File

@ -73,5 +73,5 @@ do echo -n .
done
echo "On-line"
# Exercise: Consider the strengths and weaknesses
# of each of these approaches.
# Exercise: Discuss the strengths and weaknesses
# of each of these various approaches.

View File

@ -1,11 +1,10 @@
#!/bin/bash
# primes.sh: Generate prime numbers, without using arrays.
# Script contributed by Stephane Chazelas.
# This does *not* use the classic "Sieve of Erastosthenes" algorithm,
#+ but instead uses the more intuitive method of testing each candidate number
#+ for factors (divisors), using the "%" modulo operator.
#
# Script contributed by Stephane Chazelas,
LIMIT=1000 # Primes 2 - 1000
@ -31,7 +30,7 @@ Primes()
Primes $n $@ $n # Recursion outside loop.
# Successively accumulate positional parameters.
# "$@" is the accumulating list of primes.
# "$@" is the accumulating list of primes.
}
Primes 1

View File

@ -53,6 +53,5 @@ echo
exit 0
# This is an iterative implementation of the Q-series.
# The more intuitive recursive implementation
# is left as an exercise for the reader.
# The more intuitive recursive implementation is left as an exercise.
# Warning: calculating this series recursively takes a *very* long time.

View File

@ -57,7 +57,8 @@ print_result
# Keep in mind that RANDOM is a pseudorandom generator,
# and not a spectacularly good one at that.
# Exercise for the reader (easy):
# Exercise (easy):
# ---------------
# Rewrite this script to flip a coin 1000 times.
# Choices are "HEADS" or "TAILS".

View File

@ -12,14 +12,14 @@ echo | awk "$AWKSCRIPT"
exit 0
# Exercises for the reader:
# -------------------------
# Exercises:
# ---------
# 1] Using a loop construct, print out 10 different random numbers.
# 1) Using a loop construct, print out 10 different random numbers.
# (Hint: you must reseed the "srand()" function with a different seed
# in each pass through the loop. What happens if you fail to do this?)
# 2] Using an integer multiplier as a scaling factor, generate random numbers
# 2) Using an integer multiplier as a scaling factor, generate random numbers
# in the range between 10 and 100.
# 3] Same as exercise #2, above, but generate random integers this time.
# 3) Same as exercise #2, above, but generate random integers this time.

View File

@ -19,6 +19,6 @@ fi # Each child script does the same, until
#+ a generated $i equals $MAXVAL.
# Using a "while" loop instead of an "if/then" test causes problems.
# Exercise for the reader: Explain why.
# Explain why.
exit 0

View File

@ -18,8 +18,9 @@ echo $a2
echo; echo; echo
exec 0<&6 6<&-
# Now restore stdin from fd #6, where it had been saved,
# and close fd #6 ( 6<&- ) to free it for other processes to use.
# Now restore stdin from fd #6, where it had been saved,
#+ and close fd #6 ( 6<&- ) to free it for other processes to use.
#
# <&6 6<&- also works.
echo -n "Enter data "

View File

@ -2,12 +2,12 @@
if [ -z "$1" ]
then
Filename=names.data # Default, if no filename specified.
Filename=names.data # Default, if no filename specified.
else
Filename=$1
fi
# Filename=${1:-names.data}
# can replace the above test (parameter substitution).
#+ Filename=${1:-names.data}
# can replace the above test (parameter substitution).
count=0
@ -23,11 +23,12 @@ done <"$Filename" # Redirects stdin to file $Filename.
echo; echo "$count names read"; echo
# Note that in some older shell scripting languages,
# the redirected loop would run as a subshell.
# Note that in some older shell scripting languages,
#+ the redirected loop would run as a subshell.
# Therefore, $count would return 0, the initialized value outside the loop.
# Bash and ksh avoid starting a subshell whenever possible,
# so that this script, for example, runs correctly.
# Bash and ksh avoid starting a subshell whenever possible,
# +so that this script, for example, runs correctly.
#
# Thanks to Heiner Steven for pointing this out.
exit 0

View File

@ -2,10 +2,10 @@
# This is an alternate form of the preceding script.
# Suggested by Heiner Steven
# as a workaround in those situations when a redirect loop
# runs as a subshell, and therefore variables inside the loop
# do not keep their values upon loop termination.
# Suggested by Heiner Steven
#+ as a workaround in those situations when a redirect loop
#+ runs as a subshell, and therefore variables inside the loop
# +do not keep their values upon loop termination.
if [ -z "$1" ]

View File

@ -7,10 +7,12 @@ else
Filename=$1
fi
line_count=`wc $Filename | awk '{ print $1 }'` # Number of lines in target file.
# Very contrived and kludgy, nevertheless shows that
# it's possible to redirect stdin within a "for" loop...
# if you're clever enough.
line_count=`wc $Filename | awk '{ print $1 }'`
# Number of lines in target file.
#
# Very contrived and kludgy, nevertheless shows that
#+ it's possible to redirect stdin within a "for" loop...
#+ if you're clever enough.
#
# More concise is line_count=$(wc < "$Filename")

View File

@ -14,7 +14,7 @@
ARGS=2
E_BADARGS=65
if [ $# -ne $ARGS ]
if [ $# -ne "$ARGS" ]
then
echo "Usage: `basename $0` old_file_suffix new_file_suffix"
exit $E_BADARGS
@ -24,8 +24,8 @@ for filename in *.$1
# Traverse list of files ending with 1st argument.
do
mv $filename ${filename%$1}$2
# Strip off part of filename matching 1st argument,
# then append 2nd argument.
# Strip off part of filename matching 1st argument,
#+ then append 2nd argument.
done
exit 0

View File

@ -2,8 +2,8 @@
#
# Very simpleminded filename "rename" utility (based on "lowercase.sh").
#
# The "ren" utility, by Vladimir Lanin (lanin@csd2.nyu.edu),
# does a much better job of this.
# The "ren" utility, by Vladimir Lanin (lanin@csd2.nyu.edu),
#+ does a much better job of this.
ARGS=2
@ -41,6 +41,7 @@ fi
exit 0
# Exercise for reader:
# Exercise:
# --------
# What type of files will this not work on?
# How to fix this?
# How can this be fixed?

View File

@ -23,22 +23,25 @@ echo; echo
RANDOM=1 # Same seed for RANDOM...
random_numbers # ...reproduces the exact same number series.
#
# When is it useful to duplicate a "random" number series?
echo; echo
RANDOM=2 # Trying again, but with a different seen...
RANDOM=2 # Trying again, but with a different seed...
random_numbers # gives a different number series.
echo; echo
# RANDOM=$$ seeds RANDOM from process id of script.
# It is also possible to seed RANDOM from 'time' or 'date'.
# It is also possible to seed RANDOM from 'time' or 'date' commands.
# Getting fancy...
SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }')
# Pseudo-random output fetched from /dev/urandom (system pseudo-random "device"),
# then converted to line of printable (octal) numbers by "od",
# finally "awk" retrieves just one number for SEED.
# Pseudo-random output fetched
#+ from /dev/urandom (system pseudo-random device-file),
#+ then converted to line of printable (octal) numbers by "od",
#+ finally "awk" retrieves just one number for SEED.
RANDOM=$SEED
random_numbers

View File

@ -263,7 +263,8 @@ echo
# Exercise for reader:
# Exercise:
# --------
# Add code to test all the other string functions above.

View File

@ -37,9 +37,9 @@ sed '
# Easy to understand if you take several hours to learn sed fundamentals.
# Need to add one more line to the sed script to deal with
# case where line of code has a comment following it on same line.
# This is left as a non-trivial exercise for the reader.
# Need to add one more line to the sed script to deal with
#+ case where line of code has a comment following it on same line.
# This is left as a non-trivial exercise.
# Also, the above code deletes lines with a "*/" or "/*",
# not a desirable result.

View File

@ -41,12 +41,12 @@ read answer
PrintAnswer
# Admittedly, this is a kludgy implementation of timed input,
# but pretty much as good as can be done with Bash.
# (Challenge to reader: come up with something better.)
# Admittedly, this is a kludgy implementation of timed input,
#+ however the "-t" option to "read" simplifies this task.
# See "t-out.sh", below.
# If you need something a bit more elegant...
# consider writing the application in C or C++,
# using appropriate library functions, such as 'alarm' and 'setitimer'.
# If you need something really elegant...
#+ consider writing the application in C or C++,
#+ using appropriate library functions, such as 'alarm' and 'setitimer'.
exit 0

View File

@ -71,4 +71,4 @@ done
echo "Total directories = $numdirs"
exit 0
# ==> Challenge to reader: try to figure out exactly how this script works.
# ==> Challenge: try to figure out exactly how this script works.

View File

@ -119,12 +119,12 @@ rotate # Rotate it 45 degrees counterclockwise.
# This is a rather contrived, not to mention kludgy simulation.
#
# Exercise #1 for the reader:
# Rewrite the array loading and printing functions
# in a more intuitive and elegant fashion.
# Exercises:
# ---------
# 1) Rewrite the array loading and printing functions
# + in a more intuitive and elegant fashion.
#
# Exercise #2:
# Figure out how the array rotation functions work.
# Hint: think about the implications of backwards-indexing an array.
# 2) Figure out how the array rotation functions work.
# Hint: think about the implications of backwards-indexing an array.
exit 0

View File

@ -7,16 +7,14 @@ ARGS=1
E_BADARGS=65
E_NOFILE=66
if [ $# -ne $ARGS ] # Correct number of arguments passed to script?
if [ $# -ne "$ARGS" ] # Correct number of arguments passed to script?
then
echo "Usage: `basename $0` filename"
exit $E_BADARGS
fi
if [ -f "$1" ] # Check if file exists.
if [ ! -f "$1" ] # Check if file exists.
then
file_name=$1
else
echo "File \"$1\" does not exist."
exit $E_NOFILE
fi
@ -24,7 +22,7 @@ fi
########################################################
# main
# main ()
sed -e 's/\.//g' -e 's/ /\
/g' "$1" | tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr
# =========================
@ -36,7 +34,8 @@ sed -e 's/\.//g' -e 's/ /\
#+ finally prefix occurrence count and sort numerically.
########################################################
# Exercises for the reader:
# Exercises:
# ---------
# 1) Add 'sed' commands to filter out other punctuation, such as commas.
# 2) Modify to also filter out multiple spaces and other whitespace.
# 3) Add a secondary sort key, so that instances of equal occurrence