- Testing Passwords
Write a script to check and validate passwords. The object
is to flag "weak" or easily guessed password
A trial password will be input to the script as a
command-line parameter. To be considered acceptable,
a password must meet the following minimum qualifications:
Minimum length of 8 characters
Must contain at least one numeric character
Must contain at least one of the following
non-alphabetic characters: @,
#, $, %,
&, *, +,
Do a dictionary check on every sequence of at least
four consecutive alphabetic characters in the password under
test. This will eliminate passwords containing embedded
"words" found in a standard dictionary.
Enable the script to check all the passwords on your
system. These do not reside in
This exercise tests mastery of Regular Expressions.
- Cross Reference
Write a script that generates a
(concordance) on a target file.
The output will be a listing of all word occurrences in
the target file, along with the line numbers in which
each word occurs. Traditionally, linked
list constructs would be used in such
applications. Therefore, you should investigate arrays in the course of
this exercise. Example 16-12 is probably
not a good place to start.
- Square Root
Write a script to calculate square roots of numbers
using Newton's Method.
The algorithm for this, expressed as a snippet of Bash
# (Isaac) Newton's Method for speedy extraction
#+ of square roots.
guess = $argument
# $argument is the number to find the square root of.
# $guess is each successive calculated "guess" -- or trial solution --
#+ of the square root.
# Our first "guess" at a square root is the argument itself.
oldguess = 0
# $oldguess is the previous $guess.
tolerance = .000001
# To how close a tolerance we wish to calculate.
loopcnt = 0
# Let's keep track of how many times through the loop.
# Some arguments will require more loop iterations than others.
while [ ABS( $guess $oldguess ) -gt $tolerance ]
# ^^^^^^^^^^^^^^^^^^^^^^^ Fix up syntax, of course.
# "ABS" is a (floating point) function to find the absolute value
#+ of the difference between the two terms.
# So, as long as difference between current and previous
#+ trial solution (guess) exceeds the tolerance, keep looping.
oldguess = $guess # Update $oldguess to previous $guess.
guess = ( $oldguess + ( $argument / $oldguess ) ) / 2.0
# = 1/2 ( ($oldguess **2 + $argument) / $oldguess )
# equivalent to:
# = 1/2 ( $oldguess + $argument / $oldguess )
# that is, "averaging out" the trial solution and
#+ the proportion of argument deviation
#+ (in effect, splitting the error in half).
# This converges on an accurate solution
#+ with surprisingly few loop iterations . . .
#+ for arguments > $tolerance, of course.
(( loopcnt++ )) # Update loop counter.
It's a simple enough recipe, and
seems at first glance easy enough to
convert into a working Bash script. The problem, though,
is that Bash has no native
support for floating point numbers. So, the script
writer needs to use bc or
possibly awk to convert the
numbers and do the calculations. It could get rather messy
. . .
- Logging File Accesses
Log all accesses to the files in /etc during the course of
a single day. This information should include the filename,
user name, and access time. If any alterations to the
files take place, that will be flagged. Write this data
as tabular (tab-separated) formatted records in a logfile.
- Monitoring Processes
Write a script to continually monitor all running
processes and to keep track of how many child processes each
parent spawns. If a process spawns more than five children,
then the script sends an e-mail to the system administrator
(or root) with all relevant
information, including the time, PID of the parent, PIDs
of the children, etc. The script appends a report to a log
file every ten minutes.
- Strip Comments
Strip all comments from a shell script whose name
is specified on the command-line. Note that the initial
#! line must not be
- Strip HTML Tags
Strip all the HTML tags from a specified HTML file, then
reformat it into lines between 60 and 75 characters
in length. Reset paragraph and block spacing, as
appropriate, and convert HTML tables to their approximate
- XML Conversion
Convert an XML file to both HTML and text format.
Optional: A script that converts Docbook/SGML to XML.
- Chasing Spammers
Write a script that analyzes a spam e-mail by doing
DNS lookups on the IP addresses in the headers to identify
the relay hosts as well as the originating ISP. The
script will forward the unaltered spam message to the
responsible ISPs. Of course, it will be necessary to
filter out your own ISP's IP address,
so you don't end up complaining about yourself.
As necessary, use the appropriate network analysis commands.
For some ideas, see Example 16-41 and Example A-28.
Optional: Write a script that searches through a list of
e-mail messages and deletes the spam according to specified
- Creating man pages
Write a script that automates the process of creating
Given a text file which contains information to be
formatted into a man page, the
script will read the file, then invoke the appropriate
groff commands to
output the corresponding man page
to stdout. The text file contains
blocks of information under the standard man
page headings, i.e., NAME, SYNOPSIS,
Example A-39 is an instructive first step.
- Hex Dump
Do a hex(adecimal) dump on a binary file
specified as an argument to the script. The output should
be in neat tabular fields,
with the first field showing the address, each of the
next 8 fields a 4-byte hex number, and the final field
the ASCII equivalent of the previous 8 fields.
The obvious followup to this is to extend the hex
dump script into a disassembler. Using a lookup table,
or some other clever gimmick, convert the hex values into
80x86 op codes.
- Emulating a Shift Register
Using Example 27-15 as an inspiration,
write a script that emulates a 64-bit shift register as
an array. Implement
functions to load the register,
shift left, shift
right, and rotate
it. Finally, write a function that interprets the register
contents as eight 8-bit ASCII characters.
- Calculating Determinants
Write a script that calculates
by recursively expanding the
minors. Use a 4 x 4 determinant as
a test case.
- Hidden Words
Write a "word-find" puzzle generator,
a script that hides 10 input words in a 10 x 10 array
of random letters. The words may be hidden across, down,
Optional: Write a script that solves
word-find puzzles. To keep this from becoming too difficult,
the solution script will find only horizontal and vertical
words. (Hint: Treat each row and column as a string, and
search for substrings.)
Anagram 4-letter input. For example, the
anagrams of word are:
do or rod row word. You may use
/usr/share/dict/linux.words as the
- Word Ladders
A "word ladder" is a sequence of words,
with each successive word in the sequence differing from
the previous one by a single letter.
For example, to "ladder" from
mark --> park --> part --> past --> vast --> vase
^ ^ ^ ^ ^
Write a script that solves word ladder puzzles. Given
a starting and an ending word, the script will list all
intermediate steps in the "ladder." Note
that all words in the sequence must
be legitimate dictionary words.
- Fog Index
The "fog index" of a passage of text
estimates its reading difficulty, as a number corresponding
roughly to a school grade level. For example, a passage
with a fog index of 12 should be comprehensible to anyone
with 12 years of schooling.
The Gunning version of the fog index uses the following
Choose a section of the text at least
100 words in length.
Count the number of sentences (a portion of
a sentence truncated by the boundary of the text section
counts as one).
Find the average number of words per
AVE_WDS_SEN = TOTAL_WORDS / SENTENCES
Count the number of "difficult"
words in the segment -- those containing at least
3 syllables. Divide this quantity by total words to
get the proportion of difficult words.
PRO_DIFF_WORDS = LONG_WORDS / TOTAL_WORDS
The Gunning fog index is the sum of the above two
quantities, multiplied by 0.4, then rounded to the
G_FOG_INDEX = int ( 0.4 * ( AVE_WDS_SEN + PRO_DIFF_WORDS ) )
Step 4 is by far the most difficult portion of the
exercise. There exist various algorithms for estimating
the syllable count of a word. A rule-of-thumb formula
might consider the number of letters in a word and the
A strict interpretation of the Gunning fog index does
not count compound words and proper nouns as
"difficult" words, but this would enormously
complicate the script.
- Calculating PI using Buffon's Needle
The Eighteenth Century French mathematician de Buffon
came up with a novel experiment. Repeatedly drop a needle
of length n onto a wooden floor
composed of long and narrow parallel boards. The cracks
separating the equal-width floorboards are a fixed distance
d apart. Keep track of the
total drops and the number of times the needle intersects
a crack on the floor. The ratio of these two quantities
turns out to be a fractional multiple of PI.
In the spirit of Example 16-50, write a
script that runs a Monte Carlo simulation of
Buffon's Needle. To simplify matters,
set the needle length equal to the distance between the
cracks, n = d.
Hint: there are actually two critical variables:
the distance from the center of the needle to the nearest
crack, and the inclination angle of the needle to that crack.
You may use bc to handle
- Playfair Cipher
Implement the Playfair (Wheatstone) Cipher in a
The Playfair Cipher encrypts text by substitution
of digrams (2-letter groupings).
It is traditional to use a 5 x 5 letter scrambled-alphabet
key square for the encryption and
C O D E S
A B F G H
I K L M N
P Q R T U
V W X Y Z
Each letter of the alphabet appears once, except "I" also represents
"J". The arbitrarily chosen key word, "CODES" comes first, then all
the rest of the alphabet, in order from left to right, skipping letters
To encrypt, separate the plaintext message into digrams (2-letter
groups). If a group has two identical letters, delete the second, and
form a new group. If there is a single letter left over at the end,
insert a "null" character, typically an "X."
THIS IS A TOP SECRET MESSAGE
TH IS IS AT OP SE CR ET ME SA GE
For each digram, there are three possibilities.
1) Both letters will be on the same row of the key square:
For each letter, substitute the one immediately to the right, in that
row. If necessary, wrap around left to the beginning of the row.
2) Both letters will be in the same column of the key square:
For each letter, substitute the one immediately below it, in that
row. If necessary, wrap around to the top of the column.
3) Both letters will form the corners of a rectangle within the key square:
For each letter, substitute the one on the other corner the rectangle
which lies on the same row.
The "TH" digram falls under case #3.
T U (Rectangle with "T" and "H" at corners)
T --> U
H --> G
The "SE" digram falls under case #1.
C O D E S (Row containing "S" and "E")
S --> C (wraps around left to beginning of row)
E --> S
To decrypt encrypted text, reverse the above procedure under cases #1
and #2 (move in opposite direction for substitution). Under case #3,
just take the remaining two corners of the rectangle.
Helen Fouche Gaines' classic work, ELEMENTARY CRYPTANALYSIS (1939), gives a
fairly detailed description of the Playfair Cipher and its solution methods.
This script will have three main sections
Generating the key square,
based on a user-input keyword.
Encrypting a plaintext
The script will make extensive use of arrays and functions.
You may use Example A-56 as an