This commit is contained in:
gferg 2006-10-11 16:39:10 +00:00
parent 38ee11bee1
commit fb665c619a
23 changed files with 1319 additions and 175 deletions

View File

@ -6,8 +6,146 @@
http://personal.riverusers.com/~thegrendel/Change.log
------------------------------------------------------------------------
Intermediate release.
Working toward version 4.0, Winterberry release.
Version 4.1, Waxberry release.
10/08/06
1) In the "Starting Off With a Sha-Bang" chapter:
Added Sven Mascheck's note to the footnote on magic numbers in 4.2 BSD.
(Thanks, Sven.)
2) In "Special Characters" chapter:
At "$$" entry, in footnote, added definition of a "process."
3) In "Here Strings" section of "Here Documents" chapter:
Added short intro example.
Thank you, Sebastian Kaminski, for the suggestion.
4) In "Functions" chapter:
Added note about single-line functions, with warning that a semicolon
must terminate the final command in such a function.
Embedded Christopher Head's function definition snippet in S.C.'s
inline example.
5) "System and Administrative Commands" chapter:
At "stat" entry, added in-line example script showing setting of
file-descriptive variables.
(Thank you, Joël Bourquard, for the suggestion.)
At "netstat" entry, added note about "netstat -lptu."
6) In "Communications Commands" section of "External Commands" chapter:
At "rsync" entry, changed final paragraph to a "note."
7) In "Text Processing" section of "External Commands" Chapter:
At "tail" entry, noted that "tail -$LINES" is now deprecated,
and corrected examples.
Also cleaned up "head" references and examples, as above.
At "tr" entry, in sidebar, removed misleading statement about mandatory
quoting of letter ranges within brackets.
(Thank you, Omair Eshkenazi, for pointing this out.)
At "nl" entry, changed "cat -n" reference to "cat -b" for clarity.
(Thank you, Omair Eshkenazi, for pointing this out.)
8) In "Special Variable Types" section of "Introduction to Variables and
Added short definition of "child process" to note about exporting
variable to child processes.
At "shift" entry, added paragraph and short in-line example code
listing on passing a numerical parameter indicating how many positions
to shift.
9) In "Subshells" chapter:
Added definition of "subshell" in a sidebar box.
Added in-line example, showing subshell with "ps."
Added footnote that "exec" does not fork off a subprocess/subshell.
At "dedicated environment" inline example, noted that the "exit"
only terminates the subshell, not the parent process.
Removed "note" markers from paragraph about variables in a subshell
not being visible outside the subshell.
Added note, with example, about use of "$BASH_SUBSHELL" --
but _not_ "$SHLVL" to indicate level of nesting within a subshell.
10) In "Loops and Branches" chapter:
Corrected minor grammar error in "findstring.sh" example.
Added footnote defining "iteration."
Added (needed!) spaces in definitions of "while" and "until" loops.
Noted that "while loop" uses previously-discussed "test brackets,"
and can use double-brackets construct.
11) In "Internal Commands and Builtins" chapter:
At "unset" entry, added string test to "unset.sh" example.
At "exit" entry, added note that this command may also terminate
a subshell.
At "exit" entry, added footnote that this command *only* terminates
the process it is running within.
At footnote to "hash" entry, gave a couple of synonyms for "algorithm."
12) In "Internal Variables" section of "Variables Revisited" chapter:
At "$SHLVL" entry, added note that this variable not affected
by subshells.
At "$!" entry, added Matthew Sage's "hanging job" example (thank you!).
13) In "/proc" section of "/dev and /proc" chapter:
Added "cat /proc/acpi/battery/BAT0/info" to introductory usage
examples.
Added note about controlling peripherals by sending commands to /proc.
14) In "Miscellaneous Commands" section of "External Commands" chapter:
At "mkfifo" entry, added Omair Eshkenazi's example script (thanks!).
15) In "Time/Date Commands" section of "External Commands" chapter:
At "batch" entry, added short definition of "batch processing."
16) In "Manipulating Strings" section of "Variables Revisited" chapter:
At "${string%substring}" entry, added Rory Winston's usage example
(thanks!).
17) In "Colorizing Scripts" section of "Miscellany" chapter:
Modified "Draw-box.sh" example per suggestions of Jim Angstadt
(thanks!).
18) In "Of Zeroes and Nulls" chapter
Added comments to "ex73.sh" and "ramdisk.sh" example scripts.
19) In "Contributed Scripts" appendix:
In "days-between.sh" example,
Corrected Gauss' Formula comment (reference date is March 1,
1600, *not* January 1).
Corrected broken link in above comment.
(Thank you, Nick Alexeev, for the pointers.)
Added "nightly-backup.sh" example.
(Thank you, Richard Neill.)
20) In the "Sed and Awk Micro-primer" appendix:
Added note about other "sed" delimiters, such as "%" ...
(Thank you, Omair Eshkenazi.)
21) In "Analyzing Scripts" section of "Exercises" appendix:
Added Rory Winston's one-liner script (thanks!).
22) In "Writing Scripts" section of "Exercises" appendix:
In EASY section, added "Self-reproducing" script.
In DIFFICULT section,
added "Cross Reference" script.
added "Square Roots" script.
23) In "Bibliography" section:
At reference and URL for Col Needham's original IBDB scripts,
Noted that the link no longer works.
(Thank you, Colin Brace, for pointing this out.)
24) In "Assorted Tips" section of "Miscellany" chapter:
Added "pseudo-code" entry.
25) In "Copyright" chapter:
Added footnote stating author's intention to commit the book
to the Public Domain in 2014.
26) Miscellaneous:
Added footnote defining "deprecate."
Version 4.0, Winterberry release.
06/18/06
1) "System and Administrative Commands" chapter:
Added "gnome-mount" entry.

View File

@ -2,6 +2,7 @@
# Draw-box.sh: Drawing a box using ASCII characters.
# Script by Stefano Palmeri, with minor editing by document author.
# Minor edits suggested by Jim Angstadt.
# Used in the "ABS Guide" with permission.
@ -118,9 +119,9 @@ for (( c=$2; count<=$BOX_WIDTH; c++)); do
done
plot_char $1 $2 $CORNER_CHAR # Draw box angles.
plot_char $1 `expr $2 + $BOX_WIDTH` +
plot_char `expr $1 + $BOX_HEIGHT` $2 +
plot_char `expr $1 + $BOX_HEIGHT` `expr $2 + $BOX_WIDTH` +
plot_char $1 `expr $2 + $BOX_WIDTH` $CORNER_CHAR
plot_char `expr $1 + $BOX_HEIGHT` $2 $CORNER_CHAR
plot_char `expr $1 + $BOX_HEIGHT` `expr $2 + $BOX_WIDTH` $CORNER_CHAR
echo -ne "\E[0m" # Restore old colors.

View File

@ -30,7 +30,7 @@ ex71.sh (line 7)
ex71a.sh (line 8)
ex71b.sh (line 22)
logevents.sh (lines 29, 36-39, 44, 53, 55, 60, 64)
m4.sh (line 8)
m4.sh (line 8: "\&amp;" --> &)
pw.sh (comment in line 4)
read-r.sh (lines 5, 6, 19, 26)
rnd.sh (comments in lines 38, 55, 64)
@ -61,4 +61,7 @@ hash-example.sh (comment in line 3: < --> &lt;, > --> &gt;)
quote-fetch.sh (comment in line 26: &amp; --> &)
ftpget.sh (comment in line 28)
whx.sh (comment in line 259)
nightly-backup.sh (comment in line 4)
In-line code block at beginning of "I/O Redirection" chapter, line 41.
In-line code block at "mkfifo" entro in "Miscellaneous Commands" section of
"External Filters, Programs and Commands" chapter.

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,7 @@ PMULTIPLIER=4.0 # Scaling factor to approximate PI.
get_random ()
{
SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }')
SEED=$(head -n 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.

View File

@ -61,7 +61,7 @@ strip_leading_zero () # Better to strip possible leading zero(s)
day_index () # Gauss' Formula:
{ # Days from Jan. 3, 1600 to date passed as param.
{ # Days from Mar. 1, 1600 to date passed as param.
day=$1
month=$2
@ -80,7 +80,7 @@ day_index () # Gauss' Formula:
let "Days = $DIY*$year + $year/$LEAPCYCLE - $indexyr + $indexyr/$LEAPCYCLE + $ADJ_DIY*$month/$MIY + $day - $DIM"
# For an in-depth explanation of this algorithm, see
#+ http://home.t-online.de/home/berndt.schwerdtfeger/cal.htm
#+ http://weblogs.asp.net/pgreborio/archive/2005/01/06/347968.aspx
echo $Days

View File

@ -67,8 +67,8 @@ fi # Doublecheck if in right directory, before messing with log file.
tail -$lines messages > mesg.temp # Saves last section of message log file.
mv mesg.temp messages # Becomes new log directory.
tail -n $lines messages > mesg.temp # Saves last section of message log file.
mv mesg.temp messages # Becomes new log directory.
# cat /dev/null > messages

View File

@ -4,6 +4,8 @@ var0=0
LIMIT=10
while [ "$var0" -lt "$LIMIT" ]
# ^ ^
# Spaces, because these are "test-brackets" . . .
do
echo -n "$var0 " # -n suppresses newline.
# ^ Space, to separate printed out numbers.

View File

@ -12,7 +12,7 @@ LINES=5
( date; uname -a ) >>logfile
# Time and machine name
echo --------------------------------------------------------------------- >>logfile
tail -$LINES /var/log/messages | xargs | fmt -s >>logfile
tail -n $LINES /var/log/messages | xargs | fmt -s >>logfile
echo >>logfile
echo >>logfile
@ -25,7 +25,7 @@ exit 0
#+ may give xargs indigestion.
#
# He suggests the following substitution for line 15:
# tail -$LINES /var/log/messages | tr -d "\"'" | xargs | fmt -s >>logfile
# tail -n $LINES /var/log/messages | tr -d "\"'" | xargs | fmt -s >>logfile

View File

@ -5,8 +5,8 @@ lines=35 # Allow 35 lines for the header (very generous).
for File in * # Test all the files in $PWD.
do
search1=`head -$lines $File | grep begin | wc -w`
search2=`tail -$lines $File | grep end | wc -w`
search1=`head -n $lines $File | grep begin | wc -w`
search2=`tail -n $lines $File | grep end | wc -w`
# Uuencoded files have a "begin" near the beginning,
#+ and an "end" near the end.
if [ "$search1" -gt 0 ]

View File

@ -37,11 +37,22 @@ then
fi
######################################################################
echo "Creating swap file of size $blocks blocks (KB)."
dd if=/dev/zero of=$FILE bs=$BLOCKSIZE count=$blocks # Zero out file.
mkswap $FILE $blocks # Designate it a swap file.
swapon $FILE # Activate swap file.
# Note that if one or more of these commands fails,
#+ then it could cause nasty problems.
######################################################################
# Exercise:
# Rewrite the above block of code so that if it does not execute
#+ successfully, then:
# 1) an error message is echoed to stderr,
# 2) all temporary files are cleaned up, and
# 3) the script exits in an orderly fashion with an
#+ appropriate error code.
echo "Swap file created and activated."

View File

@ -18,5 +18,5 @@ exit 0
# Exercise (easy):
# ---------------
# Convert this script to taking command-line parameters
# Convert this script to take command-line parameters
#+ for $directory and $fstring.

View File

@ -287,8 +287,8 @@ while [ $COL -lt $WINNING_POS ]; do
done
# Define old type and position of the "randomized horse".
HORSE_TYPE=`cat horse_${MOVE_HORSE}_position | tail -1`
COL=$(expr `cat horse_${MOVE_HORSE}_position | head -1`)
HORSE_TYPE=`cat horse_${MOVE_HORSE}_position | tail -n 1`
COL=$(expr `cat horse_${MOVE_HORSE}_position | head -n 1`)
ADD_POS=1
# Check if the current position is an handicap position.
@ -317,7 +317,7 @@ while [ $COL -lt $WINNING_POS ]; do
echo -ne '\E[30;42m'
# Move the cursor to new horse position.
tput cup `expr $MOVE_HORSE + 5` `cat horse_${MOVE_HORSE}_position | head -1`
tput cup `expr $MOVE_HORSE + 5` `cat horse_${MOVE_HORSE}_position | head -n 1`
# Draw the horse.
$DRAW_HORSE
@ -351,7 +351,7 @@ echo -ne '\E[30;42m'
echo -en '\E[5m'
# Make the winning horse blink.
tput cup `expr $MOVE_HORSE + 5` `cat horse_${MOVE_HORSE}_position | head -1`
tput cup `expr $MOVE_HORSE + 5` `cat horse_${MOVE_HORSE}_position | head -n 1`
$DRAW_HORSE
# Disable blinking text.

View File

@ -1,6 +1,6 @@
#!/bin/bash
# hypotenuse.sh: Returns the "hypotenuse" of a right triangle.
# ( square root of sum of squares of the "legs")
# (square root of sum of squares of the "legs")
ARGS=2 # Script needs sides of triangle passed.
E_BADARGS=65 # Wrong number of arguments.
@ -13,11 +13,16 @@ fi
AWKSCRIPT=' { printf( "%3.7f\n", sqrt($1*$1 + $2*$2) ) } '
# command(s) / parameters passed to awk
# command(s) / parameters passed to awk
# Now, pipe the parameters to awk.
echo -n "Hypotenuse of $1 and $2 = "
echo $1 $2 | awk "$AWKSCRIPT"
echo -n "Hypotenuse of $1 and $2 = "
echo $1 $2 | awk "$AWKSCRIPT"
# ^^^^^^^^^^^^
# An echo-and-pipe is an easy way of passing shell parameters to awk.
exit 0
# Exercise: Rewrite this script using 'bc' rather than awk.
# Which method is more intuitive?

View File

@ -5,7 +5,7 @@
string=abcdA01
echo "len($string)" | m4 # 7
echo "substr($string,4)" | m4 # A01
echo "regexp($string,[0-1][0-1],\&amp;Z)" | m4 # 01Z
echo "regexp($string,[0-1][0-1],\&amp;Z)" | m4 # 01Z
# Arithmetic
echo "incr(22)" | m4 # 23

View File

@ -3,7 +3,7 @@
#+ and slightly modified and commented by ABS Guide author.
# Used in ABS Guide with permission. (Thank you!)
# This script will not run under Bash version < 3.0.
# This script will not run under Bash versions < 3.0.
E_MISSING_ARG=67

View File

@ -0,0 +1,359 @@
#!/bin/bash
# nightly-backup.sh
# http://www.richardneill.org/source.php#nightly-backup-rsync
# Copyright (c) 2005 Richard Neill &lt;backup@richardneill.org&gt;.
# This is Free Software licensed under the GNU GPL.
# ==> Included in ABS Guide with script author's kind permission.
# ==> (Thanks!)
# This does a backup from the host computer to a locally connected
#+ firewire HDD using rsync and ssh.
# It then rotates the backups.
# Run it via cron every night at 5am.
# This only backs up the home directory.
# If ownerships (other than the user's) should be preserved,
#+ then run the rsync process as root (and re-instate the -o).
# We save every day for 7 days, then every week for 4 weeks,
#+ then every month for 3 months.
# See: http://www.mikerubel.org/computers/rsync_snapshots/
#+ for more explanation of the theory.
# Save as: $HOME/bin/nightly-backup_firewire-hdd.sh
# Known bugs:
# ----------
# i) Ideally, we want to exclude ~/.tmp and the browser caches.
# ii) If the user is sitting at the computer at 5am,
#+ and files are modified while the rsync is occurring,
#+ then the BACKUP_JUSTINCASE branch gets triggered.
# To some extent, this is a
#+ feature, but it also causes a "disk-space leak".
##### BEGIN CONFIGURATION SECTION ############################################
LOCAL_USER=rjn # User whose home directory should be backed up.
MOUNT_POINT=/backup # Mountpoint of backup drive.
# NO trailing slash!
# This must be unique (eg using a udev symlink)
SOURCE_DIR=/home/$LOCAL_USER # NO trailing slash - it DOES matter to rsync.
BACKUP_DEST_DIR=$MOUNT_POINT/backup/`hostname -s`.${LOCAL_USER}.nightly_backup
DRY_RUN=false #If true, invoke rsync with -n, to do a dry run.
# Comment out or set to false for normal use.
VERBOSE=false # If true, make rsync verbose.
# Comment out or set to false otherwise.
COMPRESS=false # If true, compress.
# Good for internet, bad on LAN.
# Comment out or set to false otherwise.
### Exit Codes ###
E_VARS_NOT_SET=64
E_COMMANDLINE=65
E_MOUNT_FAIL=70
E_NOSOURCEDIR=71
E_UNMOUNTED=72
E_BACKUP=73
##### END CONFIGURATION SECTION ##############################################
# Check that all the important variables have been set:
if [ -z "$LOCAL_USER" ] ||
[ -z "$SOURCE_DIR" ] ||
[ -z "$MOUNT_POINT" ] ||
[ -z "$BACKUP_DEST_DIR" ]
then
echo 'One of the variables is not set! Edit the file: $0. BACKUP FAILED.'
exit $E_VARS_NOT_SET
fi
if [ "$#" != 0 ] # If command-line param(s) . . .
then # Here document(ation).
cat <<-ENDOFTEXT
Automatic Nightly backup run from cron.
Read the source for more details: $0
The backup directory is $BACKUP_DEST_DIR .
It will be created if necessary; initialisation is no longer required.
WARNING: Contents of $BACKUP_DEST_DIR are rotated.
Directories named 'backup.\$i' will eventually be DELETED.
We keep backups from every day for 7 days (1-8),
then every week for 4 weeks (9-12),
then every month for 3 months (13-15).
You may wish to add this to your crontab using 'crontab -e'
# Back up files: $SOURCE_DIR to $BACKUP_DEST_DIR
#+ every night at 3:15 am
15 03 * * * /home/$LOCAL_USER/bin/nightly-backup_firewire-hdd.sh
Don't forget to verify the backups are working,
especially if you don't read cron's mail!"
ENDOFTEXT
exit $E_COMMANDLINE
fi
# Parse the options.
# ==================
if [ "$DRY_RUN" == "true" ]; then
DRY_RUN="-n"
echo "WARNING:"
echo "THIS IS A 'DRY RUN'!"
echo "No data will actually be transferred!"
else
DRY_RUN=""
fi
if [ "$VERBOSE" == "true" ]; then
VERBOSE="-v"
else
VERBOSE=""
fi
if [ "$COMPRESS" == "true" ]; then
COMPRESS="-z"
else
COMPRESS=""
fi
# Every week (actually of 8 days) and every month,
#+ extra backups are preserved.
DAY_OF_MONTH=`date +%d` # Day of month (01..31).
if [ $DAY_OF_MONTH = 01 ]; then # First of month.
MONTHSTART=true
elif [ $DAY_OF_MONTH = 08 \
-o $DAY_OF_MONTH = 16 \
-o $DAY_OF_MONTH = 24 ]; then
# Day 8,16,24 (use 8, not 7 to better handle 31-day months)
WEEKSTART=true
fi
# Check that the HDD is mounted.
# At least, check that *something* is mounted here!
# We can use something unique to the device, rather than just guessing
#+ the scsi-id by having an appropriate udev rule in
#+ /etc/udev/rules.d/10-rules.local
#+ and by putting a relevant entry in /etc/fstab.
# Eg: this udev rule:
# BUS="scsi", KERNEL="sd*", SYSFS{vendor}="WDC WD16",
# SYSFS{model}="00JB-00GVA0 ", NAME="%k", SYMLINK="lacie_1394d%n"
if mount | grep $MOUNT_POINT >/dev/null; then
echo "Mount point $MOUNT_POINT is indeed mounted. OK"
else
echo -n "Attempting to mount $MOUNT_POINT..."
# If it isn't mounted, try to mount it.
sudo mount $MOUNT_POINT 2>/dev/null
if mount | grep $MOUNT_POINT >/dev/null; then
UNMOUNT_LATER=TRUE
echo "OK"
# Note: Ensure that this is also unmounted
#+ if we exit prematurely with failure.
else
echo "FAILED"
echo -e "Nothing is mounted at $MOUNT_POINT. BACKUP FAILED!"
exit $E_MOUNT_FAIL
fi
fi
# Check that source dir exists and is readable.
if [ ! -r $SOURCE_DIR ] ; then
echo "$SOURCE_DIR does not exist, or cannot be read. BACKUP FAILED."
exit $E_NOSOURCEDIR
fi
# Check that the backup directory structure is as it should be.
# If not, create it.
# Create the subdirectories.
# Note that backup.0 will be created as needed by rsync.
for ((i=1;i<=15;i++)); do
if [ ! -d $BACKUP_DEST_DIR/backup.$i ]; then
if /bin/mkdir -p $BACKUP_DEST_DIR/backup.$i ; then
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ No [ ] test brackets. Why?
echo "Warning: directory $BACKUP_DEST_DIR/backup.$i is missing,"
echo "or was not initialised. (Re-)creating it."
else
echo "ERROR: directory $BACKUP_DEST_DIR/backup.$i"
echo "is missing and could not be created."
if [ "$UNMOUNT_LATER" == "TRUE" ]; then
# Before we exit, unmount the mount point if necessary.
cd
sudo umount $MOUNT_POINT &&
echo "Unmounted $MOUNT_POINT again. Giving up."
fi
exit $E_UNMOUNTED
fi
fi
done
# Set the permission to 700 for security
#+ on an otherwise permissive multi-user system.
if ! /bin/chmod 700 $BACKUP_DEST_DIR ; then
echo "ERROR: Could not set permissions on $BACKUP_DEST_DIR to 700."
if [ "$UNMOUNT_LATER" == "TRUE" ]; then
# Before we exit, unmount the mount point if necessary.
cd ; sudo umount $MOUNT_POINT && echo "Unmounted $MOUNT_POINT again. Giving up."
fi
exit $E_UNMOUNTED
fi
# Create the symlink: current -> backup.1 if required.
# A failure here is not critical.
cd $BACKUP_DEST_DIR
if [ ! -h current ] ; then
if ! /bin/ln -s backup.1 current ; then
echo "WARNING: could not create symlink current -> backup.1"
fi
fi
# Now, do the rsync.
echo "Now doing backup with rsync..."
echo "Source dir: $SOURCE_DIR"
echo -e "Backup destination dir: $BACKUP_DEST_DIR\n"
/usr/bin/rsync $DRY_RUN $VERBOSE -a -S --delete --modify-window=60 \
--link-dest=../backup.1 $SOURCE_DIR $BACKUP_DEST_DIR/backup.0/
# Only warn, rather than exit if the rsync failed,
#+ since it may only be a minor problem.
# E.g., if one file is not readable, rsync will fail.
# This shouldn't prevent the rotation.
# Not using, e.g., `date +%a` since these directories
#+ are just full of links and don't consume *that much* space.
if [ $? != 0 ]; then
BACKUP_JUSTINCASE=backup.`date +%F_%T`.justincase
echo "WARNING: the rsync process did not entirely succeed."
echo "Something might be wrong. Saving an extra copy at: $BACKUP_JUSTINCASE"
echo "WARNING: if this occurs regularly, a LOT of space will be consumed,"
echo "even though these are just hard-links!"
fi
# Save a readme in the backup parent directory.
# Save another one in the recent subdirectory.
echo "Backup of $SOURCE_DIR on `hostname` was last run on \
`date`" > $BACKUP_DEST_DIR/README.txt
echo "This backup of $SOURCE_DIR on `hostname` was created on \
`date`" > $BACKUP_DEST_DIR/backup.0/README.txt
# If we are not in a dry run, rotate the backups.
[ -z "$DRY_RUN" ] &&
# Check how full the backup disk is.
# Warn if 90%. if 98% or more, we'll probably fail, so give up.
# (Note: df can output to more than one line.)
# We test this here, rather than before
#+ so that rsync may possibly have a chance.
DISK_FULL_PERCENT=`/bin/df $BACKUP_DEST_DIR |
tr "\n" ' ' | awk '{print $12}' | grep -oE [0-9]+ `
echo "Disk space check on backup partition \
$MOUNT_POINT $DISK_FULL_PERCENT% full."
if [ $DISK_FULL_PERCENT -gt 90 ]; then
echo "Warning: Disk is greater than 90% full."
fi
if [ $DISK_FULL_PERCENT -gt 98 ]; then
echo "Error: Disk is full! Giving up."
if [ "$UNMOUNT_LATER" == "TRUE" ]; then
# Before we exit, unmount the mount point if necessary.
cd; sudo umount $MOUNT_POINT &&
echo "Unmounted $MOUNT_POINT again. Giving up."
fi
exit $E_UNMOUNTED
fi
# Create an extra backup.
# If this copy fails, give up.
if [ -n "$BACKUP_JUSTINCASE" ]; then
if ! /bin/cp -al $BACKUP_DEST_DIR/backup.0 $BACKUP_DEST_DIR/$BACKUP_JUSTINCASE
then
echo "ERROR: Failed to create extra copy \
$BACKUP_DEST_DIR/$BACKUP_JUSTINCASE"
if [ "$UNMOUNT_LATER" == "TRUE" ]; then
# Before we exit, unmount the mount point if necessary.
cd ;sudo umount $MOUNT_POINT &&
echo "Unmounted $MOUNT_POINT again. Giving up."
fi
exit $E_UNMOUNTED
fi
fi
# At start of month, rotate the oldest 8.
if [ "$MONTHSTART" == "true" ]; then
echo -e "\nStart of month. \
Removing oldest backup: $BACKUP_DEST_DIR/backup.15" &&
/bin/rm -rf $BACKUP_DEST_DIR/backup.15 &&
echo "Rotating monthly,weekly backups: \
$BACKUP_DEST_DIR/backup.[8-14] -> $BACKUP_DEST_DIR/backup.[9-15]" &&
/bin/mv $BACKUP_DEST_DIR/backup.14 $BACKUP_DEST_DIR/backup.15 &&
/bin/mv $BACKUP_DEST_DIR/backup.13 $BACKUP_DEST_DIR/backup.14 &&
/bin/mv $BACKUP_DEST_DIR/backup.12 $BACKUP_DEST_DIR/backup.13 &&
/bin/mv $BACKUP_DEST_DIR/backup.11 $BACKUP_DEST_DIR/backup.12 &&
/bin/mv $BACKUP_DEST_DIR/backup.10 $BACKUP_DEST_DIR/backup.11 &&
/bin/mv $BACKUP_DEST_DIR/backup.9 $BACKUP_DEST_DIR/backup.10 &&
/bin/mv $BACKUP_DEST_DIR/backup.8 $BACKUP_DEST_DIR/backup.9
# At start of week, rotate the second-oldest 4.
elif [ "$WEEKSTART" == "true" ]; then
echo -e "\nStart of week. \
Removing oldest weekly backup: $BACKUP_DEST_DIR/backup.12" &&
/bin/rm -rf $BACKUP_DEST_DIR/backup.12 &&
echo "Rotating weekly backups: \
$BACKUP_DEST_DIR/backup.[8-11] -> $BACKUP_DEST_DIR/backup.[9-12]" &&
/bin/mv $BACKUP_DEST_DIR/backup.11 $BACKUP_DEST_DIR/backup.12 &&
/bin/mv $BACKUP_DEST_DIR/backup.10 $BACKUP_DEST_DIR/backup.11 &&
/bin/mv $BACKUP_DEST_DIR/backup.9 $BACKUP_DEST_DIR/backup.10 &&
/bin/mv $BACKUP_DEST_DIR/backup.8 $BACKUP_DEST_DIR/backup.9
else
echo -e "\nRemoving oldest daily backup: $BACKUP_DEST_DIR/backup.8" &&
/bin/rm -rf $BACKUP_DEST_DIR/backup.8
fi &&
# Every day, rotate the newest 8.
echo "Rotating daily backups: \
$BACKUP_DEST_DIR/backup.[1-7] -> $BACKUP_DEST_DIR/backup.[2-8]" &&
/bin/mv $BACKUP_DEST_DIR/backup.7 $BACKUP_DEST_DIR/backup.8 &&
/bin/mv $BACKUP_DEST_DIR/backup.6 $BACKUP_DEST_DIR/backup.7 &&
/bin/mv $BACKUP_DEST_DIR/backup.5 $BACKUP_DEST_DIR/backup.6 &&
/bin/mv $BACKUP_DEST_DIR/backup.4 $BACKUP_DEST_DIR/backup.5 &&
/bin/mv $BACKUP_DEST_DIR/backup.3 $BACKUP_DEST_DIR/backup.4 &&
/bin/mv $BACKUP_DEST_DIR/backup.2 $BACKUP_DEST_DIR/backup.3 &&
/bin/mv $BACKUP_DEST_DIR/backup.1 $BACKUP_DEST_DIR/backup.2 &&
/bin/mv $BACKUP_DEST_DIR/backup.0 $BACKUP_DEST_DIR/backup.1 &&
SUCCESS=true
if [ "$UNMOUNT_LATER" == "TRUE" ]; then
# Unmount the mount point if it wasn't mounted to begin with.
cd ; sudo umount $MOUNT_POINT && echo "Unmounted $MOUNT_POINT again."
fi
if [ "$SUCCESS" == "true" ]; then
echo 'SUCCESS!'
exit 0
fi
# Should have already exited if backup worked.
echo 'BACKUP FAILED! Is this just a dry run? Is the disk full?) '
exit $E_BACKUP

View File

@ -28,7 +28,7 @@ echo
while [ $TRUE ] #Endless loop.
do
tail -$CHECK_LINES $LOGFILE> $TEMPFILE
tail -n $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.
search=`grep $KEYWORD $TEMPFILE`
@ -77,7 +77,7 @@ done
CHECK_INTERVAL=1
while ! tail -1 "$LOGFILE" | grep -q "$KEYWORD"
while ! tail -n 1 "$LOGFILE" | grep -q "$KEYWORD"
do echo -n .
sleep $CHECK_INTERVAL
done

View File

@ -32,12 +32,16 @@ then #+ so no error if this script is run
mkdir $MOUNTPT #+ multiple times.
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 # Enables ordinary user to access ramdisk.
# However, must be root to unmount it.
##############################################################################
# Need to test whether above commands succeed. Could cause problems otherwise.
# Exercise: modify this script to make it safer.
echo "\"$MOUNTPT\" now available for use."
# The ramdisk is now accessible for storing files, even by an ordinary user.

View File

@ -8,6 +8,7 @@ set -- $variable
first_param=$1
second_param=$2
shift; shift # Shift past first two positional params.
# shift 2 also works.
remaining_params="$*"
echo

View File

@ -3,21 +3,30 @@
echo
echo "We are outside the subshell."
echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL"
# Bash, version 3, adds the new $BASH_SUBSHELL variable.
echo
echo; echo
outer_variable=Outer
global_variable=
# Define global variable for "storage" of
#+ value of subshell variable.
(
echo "We are inside the subshell."
echo "Subshell level INSIDE subshell = $BASH_SUBSHELL"
inner_variable=Inner
echo "From subshell, \"inner_variable\" = $inner_variable"
echo "From subshell, \"outer\" = $outer_variable"
echo "From inside subshell, \"inner_variable\" = $inner_variable"
echo "From inside subshell, \"outer\" = $outer_variable"
global_variable="$inner_variable" # Will this allow "exporting"
#+ a subshell variable?
)
echo
echo; echo
echo "We are outside the subshell."
echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL"
echo
@ -29,10 +38,18 @@ else
fi
echo "From main body of shell, \"inner_variable\" = $inner_variable"
# $inner_variable will show as uninitialized
# $inner_variable will show as blank (uninitialized)
#+ because variables defined in a subshell are "local variables".
# Is there any remedy for this?
# Is there a remedy for this?
echo "global_variable = "$global_variable"" # Why doesn't this work?
echo
exit 0
# Question:
# --------
# Once having exited a subshell,
#+ is there any way to reenter that very same subshell
#+ to modify or access the subshell variables?

View File

@ -8,4 +8,9 @@ unset variable # Unset.
# Same effect as: variable=
echo "(unset) variable = $variable" # $variable is null.
if [ -z "$variable" ] # Try a string-length test.
then
echo "\$variable has zero length."
fi
exit 0

View File

@ -57,4 +57,4 @@ exit 0
# 1) Add 'sed' commands to filter out other punctuation,
#+ such as semicolons.
# 2) Modify the script to also filter out multiple spaces and
# other whitespace.
#+ other whitespace.