This commit is contained in:
gferg 2004-04-28 12:08:07 +00:00
parent f83b4dd12e
commit 254dc68d71
28 changed files with 3046 additions and 2550 deletions

View File

@ -6,8 +6,96 @@
http://personal.riverusers.com/~thegrendel/Change.log
------------------------------------------------------------------------
Release.
Version 2.6 'SALAL' release, 03/15/04
Version 2.7
Mulberry release, 04/18/04
1) In the "Starting Off With a Sha-Bang" chapter:
Added "ex1a.sh" example as a bridge between "ex1.sh" and "ex2.sh"
examples.
Added a few explanatory notes.
Minor revisions to comments in "ex1.sh" and "ex2.sh" examples.
Added "$" to variable name in script prolog note.
Minor revisions to "Why Shell Programming?" section.
2) In "Special Characters" chapter:
In in-line example at "Control-K" entry, expanded explanation of
effect of a vertical tab.
(Thank you, Lee Maschmeyer.)
Minor rewording at "`" (backticks), "\" (escape), and other entries.
3) In "Quoting" chapter:
Slight rewording of note about certain programs expanding special
characters in a quoted string.
Dropped word "apparently" from footnote on quoting "!" character.
4) In "/dev" section of "/dev and /proc" chapter:
Added short explanation of Bash's treatment of /dev/tcp/host/port
pseudo-device files.
Added footnote defining a socket.
Added use of /dev/sda1 in mounting a USB flash drive.
Added examples of getting the time from a remote network
and downloading a URL -- using /dev/tcp.
(Thank you, Mark.)
5) In "/proc" section of "/dev and /proc" chapter:
Added "cat /proc/apm" to list of 'proc' examples.
Redid first parsing example.
6) In the "Portability Issues" section of the "Miscellany" chapter:
Added discussion of using !#/bin/sh to run scripts.
(Thank you, Ian D. Allen.)
7) In "Assorted Tips" section of "Miscellany" chapter:
Added redirecting stderr to stdout in "if-grep" test.
(Thank you, Chris Martin.)
Added tip about setting PATH and umask at beginning of script.
(Thank you, Ian D. Allen.)
8) In "System and Administrative Commands" chapter:
At "ifconfig" entry, added "ifconfig -a" output example.
At "hostname" entry, added note about "domainname" and similar
commands.
At "netstat" entry, added screen output example.
9) In "Text Processing" section of "External Commands" Chapter:
Added comment (suggested modification) to "wf.sh" example.
(Thanks, Arun Giridhar.)
At "grep" entry, added method of searching for two different patterns,
with usage example.
10) In "Internal Commands and Builtins" chapter:
Expanded "ex43.sh" example.
11) In "Comparison Operators" section of "Tests" chapter:
Changed section title.
Added brief intro paragraph.
At "==" entry, added note and embedded pre-existing example within it.
12) In "Regular Expressions" chapter:
In "Brief Introduction to Regular Expression" Section:
Added sidebar with example of testing an RE.
In "Globbing" Section:
Fixed typo in footnote 1.
(Thanks (Asheesh Soni.)
13) In "Copyright" chapter:
Added URL for French translation.
14) In "Contributed Scripts" appendix:
Replaced "tree.sh" script with a simplified version,
revised by Rick Boivie.
15) Added "To Do List" appendix.
16) Changed all "process id" references to "process ID" to avoid
confusion.
17) Minor cleanups and fixups to various scripts.
Version 2.6
'SALAL' release, 03/15/04
1) In "Exit and Exit Status" chapter,
Added comment to inline example discussing negation of a 'true' command.
@ -172,7 +260,7 @@ Version 2.5
Noted that GNU tools allow extended REs if escaped.
Removed brackets from RE character sets where unnecessary and
misleading.
In "Globbing Section":
In "Globbing" Section:
Corrected note about 'echo' performing wildcard expansion.
(Thanks, Paulo Marcel Coelho Aragao, for all of the above.)
Broke 'echo' filename expansion examples out of main "screen" block.
@ -483,7 +571,7 @@ Comments: Major release.
in the environment (exported).
(Thank you, Mr. Fred.)
9) In "Comparison Operations" section of "Tests" chapter:
9) In "Comparison Operators" section of "Tests" chapter:
Corrected typos in "str-test.sh" example.
(Thank you, Bill Gradwohl.)
@ -2378,7 +2466,7 @@ In "External Filters, Programs, and Commands" section:
to Produce This Book".
89) Added footnote about shell script naming conventions to "Why Shell
Programming?" section.
Programming?" section of Chapter 1.
90) Changed all <errorcode> tags to the more appropriate <returnvalue>.

View File

@ -13,7 +13,8 @@ NEWFILENAME=$1.unx
CR='\015' # Carriage return.
# 015 is octal ASCII code for CR.
# Lines in a DOS text file end in a CR-LF.
# Lines in a DOS text file end in CR-LF.
# Lines in a UNIX text file end in LF only.
tr -d $CR &lt; $1 &gt; $NEWFILENAME
# Delete CR's and write to new file.

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
#!/bin/bash
# crypto-quote.sh: Encrypt quotes
# Will encrypt famous quotes in a simple monoalphabetic substitution.
# Will encrypt famous quotes in a simple monoalphabetic substitution.
# The result is similar to the "Crypto Quote" puzzles
#+ seen in the Op Ed pages of the Sunday paper.
@ -20,7 +20,7 @@ cat "$@" | tr "a-z" "A-Z" | tr "A-Z" "$key"
# Passes non-alphabetic characters through unchanged.
# Try this script with something like
# Try this script with something like:
# "Nothing so needs reforming as other people's habits."
# --Mark Twain
#

View File

@ -18,6 +18,7 @@ done`
echo "variable2 = $variable2" # variable2 = 0123456789
# It's possible to embed a loop within a variable declaration.
# Demonstrates that it's possible to embed a loop
#+ within a variable declaration.
exit 0

View File

@ -8,8 +8,8 @@
# An empty array is not the same as an array with empty elements.
array0=( first second third )
array1=( '' ) # "array1" has one empty element.
array2=( ) # No elements... "array2" is empty.
array1=( '' ) # "array1" consists of one empty element.
array2=( ) # No elements . . . "array2" is empty.
echo
ListArray()
@ -24,7 +24,7 @@ echo "Length of first element in array1 = ${#array1}"
echo "Length of first element in array2 = ${#array2}"
echo
echo "Number of elements in array0 = ${#array0[*]}" # 3
echo "Number of elements in array1 = ${#array1[*]}" # 1 (surprise!)
echo "Number of elements in array1 = ${#array1[*]}" # 1 (Surprise!)
echo "Number of elements in array2 = ${#array2[*]}" # 0
}
@ -32,7 +32,7 @@ echo "Number of elements in array2 = ${#array2[*]}" # 0
ListArray
# Try extending those arrays
# Try extending those arrays.
# Adding an element to an array.
array0=( "${array0[@]}" "new1" )
@ -56,44 +56,44 @@ echo
echo "Stack height for array2 = $height"
# The 'pop' is:
unset array2[${#array2[@]}-1] # Arrays are zero based
height=${#array2[@]}
unset array2[${#array2[@]}-1] # Arrays are zero-based,
height=${#array2[@]} #+ which means first element has index 0.
echo
echo "POP"
echo "New stack height for array2 = $height"
ListArray
# List only 2nd and 3rd elements of array0
from=1 # Zero based numbering
# List only 2nd and 3rd elements of array0.
from=1 # Zero-based numbering.
to=2 #
array3=( ${array0[@]:1:2} )
echo
echo "Elements in array3: ${array3[@]}"
# Works like a string (array of characters)
# Try some other "string" forms
# Works like a string (array of characters).
# Try some other "string" forms.
# Replacement
# Replacement:
array4=( ${array0[@]/second/2nd} )
echo
echo "Elements in array4: ${array4[@]}"
# Replace all matching wildcarded string
# Replace all matching wildcarded string.
array5=( ${array0[@]//new?/old} )
echo
echo "Elements in array5: ${array5[@]}"
# Just when you are getting the feel for this...
# Just when you are getting the feel for this . . .
array6=( ${array0[@]#*new} )
echo # This one might surprise you
echo # This one might surprise you.
echo "Elements in array6: ${array6[@]}"
array7=( ${array0[@]#new1} )
echo # After array6 this should not be a surprise
echo # After array6 this should not be a surprise.
echo "Elements in array7: ${array7[@]}"
# Which looks a lot like...
# Which looks a lot like . . .
array8=( ${array0[@]/new1/} )
echo
echo "Elements in array8: ${array8[@]}"
@ -102,9 +102,9 @@ echo "Elements in array8: ${array8[@]}"
# The string operations are performed on
#+ each of the elements in var[@] in succession.
# Therefore : BASH supports string vector operations
# If the result is a zero length string, that
#+ element disappears in the resulting assignment.
# Therefore : Bash supports string vector operations
#+ if the result is a zero length string,
#+ that element disappears in the resulting assignment.
# Question, are those strings hard or soft quotes?
@ -118,8 +118,8 @@ array10=( ${array0[@]#$zap} )
echo
echo "Elements in array10: ${array10[@]}"
# Compare array7 with array10
# Compare array8 with array9
# Compare array7 with array10.
# Compare array8 with array9.
# Answer: must be soft quotes.

View File

@ -1,4 +1,4 @@
# cleanup
# Cleanup
# Run as root, of course.
cd /var/log

View File

@ -39,5 +39,5 @@ zcat $1 | most
exit $? # Script returns exit status of pipe.
# Actually "exit $?" unnecessary, as the script will, in any case,
# Actually "exit $?" is unnecessary, as the script will, in any case,
# return the exit status of the last command executed.

View File

@ -42,7 +42,7 @@ echo "All the command-line parameters are: "$*""
if [ $# -lt "$MINPARAMS" ]
then
echo
echo "Give me at least $MINPARAMS command-line arguments!"
echo "This script needs at least $MINPARAMS command-line arguments!"
fi
echo

View File

@ -1,6 +1,14 @@
#!/bin/bash
# cleanup, version 2
# Run as root, of course.
# Cleanup, version 3
# Warning:
# -------
# This script uses quite a number of features that will be explained
#+ later on.
# By the time you've finished the first half of the book,
#+ there should be nothing mysterious about it.
LOG_DIR=/var/log
ROOT_UID=0 # Only users with $UID 0 have root privileges.
@ -9,6 +17,7 @@ E_XCD=66 # Can't change directory?
E_NOTROOT=67 # Non-root exit error.
# Run as root, of course.
if [ "$UID" -ne "$ROOT_UID" ]
then
echo "Must be root to run this script."

View File

@ -1,14 +1,15 @@
#!/bin/bash
# List the planets.
# Listing the planets.
for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto
do
echo $planet
echo $planet # Each planet on a separate line.
done
echo
for planet in "Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto"
# All planets on same line.
# Entire 'list' enclosed in quotes creates a single variable.
do
echo $planet

View File

@ -19,12 +19,12 @@ ls . | xargs -i -t cp ./{} $1
# {} is a placeholder for output text.
# This is similar to the use of a curly bracket pair in "find."
#
# List the files (ls),
# List the files in current directory (ls .),
#+ pass the output of "ls" as arguments to "xargs" (-i -t options),
#+ then copy (cp) these arguments ({}) to new directory ($1).
#
# The net result is the exact equivalent of
#+ cp * $1
#+ unless any of the filenames has "whitespace" characters.
#+ unless any of the filenames has embedded "whitespace" characters.
exit 0

View File

@ -13,4 +13,33 @@ echo $y #+ but linefeeds removed.
# When LF's not preserved, it may make it easier to parse output,
#+ using utilities such as "awk".
echo
echo "==========================================================="
echo
# Now, showing how to "expand" a variable using "eval" . . .
for i in 1 2 3 4 5; do
eval value=$i
# value=$i has same effect. The "eval" is not necessary here.
# A variable lacking a meta-meaning evaluates to itself --
#+ it can't expand to anything other than its literal self.
echo $value
done
echo
echo "---"
echo
for i in ls df; do
value=eval $i
# value=$i has an entirely different effect here.
# The "eval" evaluates the commands "ls" and "df" . . .
# The terms "ls" and "df" have a meta-meaning,
#+ since they are interpreted as commands,
#+ rather than just character strings.
echo $value
done
exit 0

View File

@ -11,7 +11,7 @@ $killppp # This variable is now a command.
# The following operations must be done as root user.
chmod 666 /dev/ttyS3 # Must be read+write permissions, or else?
chmod 666 /dev/ttyS3 # Must be read+write permissions, or else what?
# Since doing a SIGKILL on ppp changed the permissions on the serial port,
#+ we restore permissions to previous state.

View File

@ -1,6 +1,7 @@
#!/bin/bash
# Check some of the system's environmental variables.
# Check some of the system's environmental variables.
# This is good preventative maintenance.
# If, for example, $USER, the name of the person at the console, is not set,
#+ the machine will not recognize you.
@ -43,9 +44,12 @@ echo
#
# echo ${ZZXy23AB?} >/dev/null
# Compare these methods of checking whether a variable has been set
#+ with "set -u" . . .
echo "You will not see this message, because script terminated above."
echo "You will not see this message, because script already terminated."
HERE=0
exit $HERE # Will *not* exit here.
exit $HERE # Will NOT exit here.

View File

@ -4,7 +4,7 @@ wall &lt;&lt;zzz23EndOfMessagezzz23
E-mail your noontime orders for pizza to the system administrator.
(Add an extra dollar for anchovy or mushroom topping.)
# Additional message text goes here.
# Note: Comment lines printed by 'wall'.
# Note: 'wall' prints comment lines.
zzz23EndOfMessagezzz23
# Could have been done more efficiently by

View File

@ -8,6 +8,7 @@
badname=`ls | grep ' '`
# Try this:
# echo "$badname"
rm "$badname"

View File

@ -4,49 +4,51 @@
TRUE=1
LOGFILE=/var/log/messages
# Note that $LOGFILE must be readable (chmod 644 /var/log/messages).
# Note that $LOGFILE must be readable
#+ (as root, chmod 644 /var/log/messages).
TEMPFILE=temp.$$
# Create a "unique" temp file name, using process id of the script.
# Create a "unique" temp file name, using process id of the script.
KEYWORD=address
# At logon, the line "remote IP address xxx.xxx.xxx.xxx"
# appended to /var/log/messages.
# At logon, the line "remote IP address xxx.xxx.xxx.xxx"
# appended to /var/log/messages.
ONLINE=22
USER_INTERRUPT=13
CHECK_LINES=100
# How many lines in log file to check.
# How many lines in log file to check.
trap 'rm -f $TEMPFILE; exit $USER_INTERRUPT' TERM INT
# Cleans up the temp file if script interrupted by control-c.
# Cleans up the temp file if script interrupted by control-c.
echo
while [ $TRUE ] #Endless loop.
do
tail -$CHECK_LINES $LOGFILE> $TEMPFILE
# Saves last 100 lines of system log file as temp file.
# Necessary, since newer kernels generate many log messages at log on.
# Saves last 100 lines of system log file as temp file.
# Necessary, since newer kernels generate many log messages at log on.
search=`grep $KEYWORD $TEMPFILE`
# Checks for presence of the "IP address" phrase,
# indicating a successful logon.
# Checks for presence of the "IP address" phrase,
#+ indicating a successful logon.
if [ ! -z "$search" ] # Quotes necessary because of possible spaces.
if [ ! -z "$search" ] # Quotes necessary because of possible spaces.
then
echo "On-line"
rm -f $TEMPFILE # Clean up temp file.
rm -f $TEMPFILE # Clean up temp file.
exit $ONLINE
else
echo -n "." # -n option to echo suppresses newline,
# so you get continuous rows of dots.
echo -n "." # The -n option to echo suppresses newline,
#+ so you get continuous rows of dots.
fi
sleep 1
done
# Note: if you change the KEYWORD variable to "Exit",
# this script can be used while on-line to check for an unexpected logoff.
# Note: if you change the KEYWORD variable to "Exit",
#+ this script can be used while on-line
#+ to check for an unexpected logoff.
# Exercise: Change the script, as per the above note,
# Exercise: Change the script, per the above note,
# and prettify it.
exit 0
@ -61,7 +63,7 @@ while true
done
# Problem: Hitting Control-C to terminate this process may be insufficient.
# (Dots may keep on echoing.)
#+ (Dots may keep on echoing.)
# Exercise: Fix this.
@ -76,5 +78,5 @@ do echo -n .
done
echo "On-line"
# Exercise: Discuss the strengths and weaknesses
# of each of these various approaches.
# Exercise: Discuss the relative strengths and weaknesses
#! of each of these various approaches.

View File

@ -1,4 +1,9 @@
#!/bin/bash
# param-sub.sh
# Whether a variable has been declared
#+ affects triggering of the default option
#+ even if the variable is null.
username0=
# username0 has been declared, but is set to null.
@ -13,5 +18,6 @@ username2=
# username2 has been declared, but is set to null.
echo "username2 = ${username2:-`whoami`}"
# Will echo because of :- rather than just - in condition test.
# Compare to first instance, above.
exit 0

View File

@ -4,11 +4,12 @@
# Written by Rick Boivie, and used with permission.
# Modifications by document author.
MINARGS=1 # Script needs at least one argument.
MINARGS=1 # Script needs at least one argument.
DATAFILE=./phonebook
# A data file named "phonebook" must exist.
# A data file in current working directory
#+ named "phonebook" must exist.
PROGNAME=$0
E_NOARGS=70 # No arguments error.
E_NOARGS=70 # No arguments error.
if [ $# -lt $MINARGS ]; then
echo "Usage: "$PROGNAME" data"
@ -25,11 +26,11 @@ else
fi
exit 0 # Script exits here.
# It's o.k. to put non-hashmarked comments
#+ and data after this point.
# Therefore, it's o.k. to put
#+ non-hashmarked comments and data after this point.
# ------------------------------------------------------------------------
# Sample "phonebook" datafile:
Sample "phonebook" datafile:
John Doe 1555 Main St., Baltimore, MD 21228 (410) 222-3333
Mary Moe 9899 Jones Blvd., Warren, NH 03787 (603) 898-3232
@ -45,5 +46,5 @@ Sam Roe 956 E. 8th St., New York, NY 10009 (212) 444-5678
$bash pb.sh Roe Sam
Sam Roe 956 E. 8th St., New York, NY 10009 (212) 444-5678
# When more than one argument passed to script,
# When more than one argument is passed to this script,
#+ it prints *only* the line(s) containing all the arguments.

View File

@ -28,3 +28,7 @@ done
echo
exit 0
# Exercise:
# --------
# Modify this script to pretty-print a poem from a text data file.

View File

@ -1,15 +1,16 @@
#!/bin/bash
# May need to be invoked with #!/bin/bash2 on older machines.
#
# Random password generator for bash 2.x by Antek Sawicki &lt;tenox@tenox.tc&gt;,
# Random password generator for Bash 2.x by Antek Sawicki &lt;tenox@tenox.tc&gt;,
# who generously gave permission to the document author to use it here.
#
# ==> Comments added by document author ==>
MATRIX="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
# ==> Password will consist of alphanumeric characters.
LENGTH="8"
# ==> May change 'LENGTH' for longer password, of course.
# ==> May change 'LENGTH' for longer password.
while [ "${n:=1}" -le "$LENGTH" ]
@ -23,17 +24,17 @@ do
# ==> ${#MATRIX} returns length of array MATRIX.
# ==> $RANDOM%${#MATRIX} returns random number between 1
# ==> and length of MATRIX - 1.
# ==> and [length of MATRIX] - 1.
# ==> ${MATRIX:$(($RANDOM%${#MATRIX})):1}
# ==> returns expansion of MATRIX at random position, by length 1.
# ==> See {var:pos:len} parameter substitution in Section 3.3.1
# ==> and following examples.
# ==> See {var:pos:len} parameter substitution in Chapter 9.
# ==> and the associated examples.
# ==> PASS=... simply pastes this result onto previous PASS (concatenation).
# ==> To visualize this more clearly, uncomment the following line
# ==> echo "$PASS"
# echo "$PASS"
# ==> to see PASS being built up,
# ==> one character at a time, each iteration of the loop.
@ -41,6 +42,6 @@ do
# ==> Increment 'n' for next pass.
done
echo "$PASS" # ==> Or, redirect to file, as desired.
echo "$PASS" # ==> Or, redirect to a file, as desired.
exit 0

View File

@ -2,13 +2,13 @@
# ramdisk.sh
# A "ramdisk" is a segment of system RAM memory
#+ that acts as if it were a filesystem.
#+ which acts as if it were a filesystem.
# Its advantage is very fast access (read/write time).
# Disadvantages: volatility, loss of data on reboot or powerdown.
# less RAM available to system.
#+ less RAM available to system.
#
# What good is a ramdisk?
# Keeping a large dataset, such as a table or dictionary on ramdisk
# Of what use is a ramdisk?
# Keeping a large dataset, such as a table or dictionary on ramdisk,
#+ speeds up data lookup, since memory access is much faster than disk access.
@ -33,9 +33,10 @@ then #+ so no error if this script is run
fi
dd if=/dev/zero of=$DEVICE count=$SIZE bs=$BLOCKSIZE # Zero out RAM device.
# Why is this necessary?
mke2fs $DEVICE # Create an ext2 filesystem on it.
mount $DEVICE $MOUNTPT # Mount it.
chmod 777 $MOUNTPT # So ordinary user can access ramdisk.
chmod 777 $MOUNTPT # Enables ordinary user to access ramdisk.
# However, must be root to unmount it.
echo "\"$MOUNTPT\" now available for use."
@ -45,7 +46,11 @@ echo "\"$MOUNTPT\" now available for use."
#+ on reboot or power loss.
# Copy anything you want saved to a regular directory.
# After reboot, run this script again to set up ramdisk.
# After reboot, run this script to again set up ramdisk.
# Remounting /mnt/ramdisk without the other steps will not work.
# Suitably modified, this script can by invoked in /etc/rc.d/rc.local,
#+ to set up ramdisk automatically at bootup.
# That may be appropriate on, for example, a database server.
exit 0

View File

@ -56,9 +56,13 @@ print_result
# Keep in mind that RANDOM is a pseudorandom generator,
#+ and not a spectacularly good one at that.
# Randomness is a deep and complex subject.
# Sufficiently long "random" sequences may exhibit
#+ chaotic and other "non-random" behavior.
# Exercise (easy):
# ---------------
# Rewrite this script to flip a coin 1000 times.
# Choices are "HEADS" or "TAILS".
# Choices are "HEADS" and "TAILS".
exit 0

View File

@ -1,4 +1,5 @@
#!/bin/bash
# read-novar.sh
echo

View File

@ -1,74 +1,59 @@
#!/bin/sh
# @(#) tree 1.1 30/11/95 by Jordi Sanfeliu
# email: mikaku@fiwix.org
#
# Initial version: 1.0 30/11/95
# Next version : 1.1 24/02/97 Now, with symbolic links
# Patch by : Ian Kjos, to support unsearchable dirs
# email: beth13@mail.utexas.edu
#
# Tree is a tool for view the directory tree (obvious :-) )
#
#!/bin/bash
# tree.sh
# Written by Rick Boivie.
# Used with permission.
# This is a revised and simplified version of a script
# by Jordi Sanfeliu (and patched by Ian Kjos).
# This script replaces the earlier version used in
#+ previous releases of the Advanced Bash Scripting Guide.
# ==> 'Tree' script used here with the permission of its author, Jordi Sanfeliu.
# ==> Comments added by the author of this document.
# ==> Argument quoting added.
search () {
for dir in `echo *`
# ==> `echo *` lists all the files in current working directory, without line breaks.
# ==> Similar effect to for dir in *
# ==> but "dir in `echo *`" will not handle filenames with blanks.
do
if [ -d "$dir" ] ; then # ==> If it is a directory (-d)...
zz=0 # ==> Temp variable, keeping track of directory level.
while [ $zz != $deep ] # Keep track of inner nested loop.
do
echo -n "| " # ==> Display vertical connector symbol,
# ==> with 2 spaces & no line feed in order to indent.
zz=`expr $zz + 1` # ==> Increment zz.
done
if [ -L "$dir" ] ; then # ==> If directory is a symbolic link...
echo "+---$dir" `ls -l $dir | sed 's/^.*'$dir' //'`
# ==> Display horiz. connector and list directory name, but...
# ==> delete date/time part of long listing.
else
echo "+---$dir" # ==> Display horizontal connector symbol...
# ==> and print directory name.
if cd "$dir" ; then # ==> If can move to subdirectory...
deep=`expr $deep + 1` # ==> Increment depth.
search # with recursivity ;-)
# ==> Function calls itself.
numdirs=`expr $numdirs + 1` # ==> Increment directory count.
fi
fi
for dir in `echo *`
# ==> `echo *` lists all the files in current working directory,
#+ ==> without line breaks.
# ==> Similar effect to for dir in *
# ==> but "dir in `echo *`" will not handle filenames with blanks.
do
if [ -d "$dir" ] ; then # ==> If it is a directory (-d)...
zz=0 # ==> Temp variable, keeping track of directory level.
while [ $zz != $1 ] # Keep track of inner nested loop.
do
echo -n "| " # ==> Display vertical connector symbol,
# ==> with 2 spaces & no line feed in order to indent.
zz=`expr $zz + 1` # ==> Increment zz.
done
if [ -L "$dir" ] ; then # ==> If directory is a symbolic link...
echo "+---$dir" `ls -l $dir | sed 's/^.*'$dir' //'`
# ==> Display horiz. connector and list directory name, but...
# ==> delete date/time part of long listing.
else
echo "+---$dir" # ==> Display horizontal connector symbol...
# ==> and print directory name.
numdirs=`expr $numdirs + 1` # ==> Increment directory count.
if cd "$dir" ; then # ==> If can move to subdirectory...
search `expr $1 + 1` # with recursion ;-)
# ==> Function calls itself.
cd ..
fi
done
cd .. # ==> Up one directory level.
if [ "$deep" ] ; then # ==> If depth = 0 (returns TRUE)...
swfi=1 # ==> set flag showing that search is done.
fi
deep=`expr $deep - 1` # ==> Decrement depth.
fi
fi
done
}
# - Main -
if [ $# = 0 ] ; then
cd `pwd` # ==> No args to script, then use current working directory.
else
cd $1 # ==> Otherwise, move to indicated directory.
if [ $# != 0 ] ; then
cd $1 # move to indicated directory.
#else # stay in current directory
fi
echo "Initial directory = `pwd`"
swfi=0 # ==> Search finished flag.
deep=0 # ==> Depth of listing.
numdirs=0
zz=0
while [ "$swfi" != 1 ] # While flag not set...
do
search # ==> Call function after initializing variables.
done
echo "Initial directory = `pwd`"
numdirs=0
search 0
echo "Total directories = $numdirs"
exit 0
# ==> Challenge: try to figure out exactly how this script works.

View File

@ -33,14 +33,22 @@ sed -e 's/\.//g' -e 's/\,//g' -e 's/ /\
#+ change space between words to linefeed,
#+ then shift characters to lowercase, and
#+ finally prefix occurrence count and sort numerically.
# Arun Giridhar suggests modifying the above to:
# . . . | sort | uniq -c | sort +1 [-f] | sort +0 -nr
# This adds a secondary sort key, so instances of
#+ equal occurrence are sorted alphabetically.
# As he explains it:
# "This is effectively a radix sort, first on the
#+ least significant column
#+ (word or string, optionally case-insensitive)
#+ and last on the most significant column (frequency)."
########################################################
exit 0
# Exercises:
# ---------
# 1) Add 'sed' commands to filter out other punctuation,
#+ such as semicolons.
# 2) Modify to also filter out multiple spaces and other whitespace.
# 3) Add a secondary sort key, so that instances of equal occurrence
#+ are sorted alphabetically.
exit 0

File diff suppressed because it is too large Load Diff