Easily find issues by searching: #<Issue ID>
Example: #1832
Easily find members by searching in: <username>, <first name> and <last name>.
Example: Search smith, will return results smith and adamsmith
These scripts, while not fitting into the text of this document, do illustrate some interesting shell programming techniques. Some are useful, too. Have fun analyzing and running them.
Example A-1. mailformat: Formatting an e-mail message
#!/bin/bash # mail-format.sh (ver. 1.1): Format e-mail messages. # Gets rid of carets, tabs, and also folds excessively long lines. # ================================================================= # Standard Check for Script Argument(s) ARGS=1 E_BADARGS=65 E_NOFILE=66 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. then file_name=$1 else echo "File \"$1\" does not exist." exit $E_NOFILE fi # ================================================================= MAXWIDTH=70 # Width to fold excessively long lines to. # --------------------------------- # A variable can hold a sed script. sedscript='s/^>// s/^ *>// s/^ *// s/ *//' # --------------------------------- # Delete carets and tabs at beginning of lines, #+ then fold lines to $MAXWIDTH characters. sed "$sedscript" $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 MS Windows utility with similar functionality. # # An nice set of text processing utilities and an efficient #+ scripting language provide an alternative to bloated executables. exit
Example A-2. rn: A simple-minded file renaming utility
This script is a modification of Example 16-22.
#! /bin/bash # rn.sh # Very simpleminded filename "rename" utility (based on "lowercase.sh"). # # The "ren" utility, by Vladimir Lanin ([email protected]), #+ does a much better job of this. ARGS=2 E_BADARGS=85 ONE=1 # For getting singular/plural right (see below). if [ $# -ne "$ARGS" ] then echo "Usage: `basename $0` old-pattern new-pattern" # As in "rn gif jpg", which renames all gif files in working directory to jpg. exit $E_BADARGS fi number=0 # Keeps track of how many files actually renamed. for filename in *$1* #Traverse all matching files in directory. do if [ -f "$filename" ] # If finds match... then fname=`basename $filename` # Strip off path. n=`echo $fname | sed -e "s/$1/$2/"` # Substitute new for old in filename. mv $fname $n # Rename. let "number += 1" fi done if [ "$number" -eq "$ONE" ] # For correct grammar. then echo "$number file renamed." else echo "$number files renamed." fi exit $? # Exercises: # --------- # What types of files will this not work on? # How can this be fixed?
Example A-3. blank-rename: Renames filenames containing blanks
This is an even simpler-minded version of previous script.
#! /bin/bash # blank-rename.sh # # Substitutes underscores for blanks in all the filenames in a directory. ONE=1 # For getting singular/plural right (see below). number=0 # Keeps track of how many files actually renamed. FOUND=0 # Successful return value. for filename in * #Traverse all files in directory. do echo "$filename" | grep -q " " # Check whether filename if [ $? -eq $FOUND ] #+ contains space(s). then fname=$filename # Yes, this filename needs work. n=`echo $fname | sed -e "s/ /_/g"` # Substitute underscore for blank. mv "$fname" "$n" # Do the actual renaming. let "number += 1" fi done if [ "$number" -eq "$ONE" ] # For correct grammar. then echo "$number file renamed." else echo "$number files renamed." fi exit 0
Example A-4. encryptedpw: Uploading to an ftp site, using a locally encrypted password
#!/bin/bash # Example "ex72.sh" modified to use encrypted password. # Note that this is still rather insecure, #+ since the decrypted password is sent in the clear. # Use something like "ssh" if this is a concern. E_BADARGS=85 if [ -z "$1" ] then echo "Usage: `basename $0` filename" exit $E_BADARGS fi Username=bozo # Change to suit. pword=/home/bozo/secret/password_encrypted.file # File containing encrypted password. Filename=`basename $1` # Strips pathname out of file name. Server="XXX" Directory="YYY" # Change above to actual server name & directory. Password=`cruft <$pword` # Decrypt password. # Uses the author's own "cruft" file encryption package, #+ based on the classic "onetime pad" algorithm, #+ and obtainable from: #+ Primary-site: ftp://ibiblio.org/pub/Linux/utils/file #+ cruft-0.2.tar.gz [16k] ftp -n $Server <<End-Of-Session user $Username $Password binary bell cd $Directory put $Filename bye End-Of-Session # -n option to "ftp" disables auto-logon. # Note that "bell" rings 'bell' after each file transfer. exit 0
Example A-5. copy-cd: Copying a data CD
#!/bin/bash # copy-cd.sh: copying a data CD CDROM=/dev/cdrom # CD ROM device OF=/home/bozo/projects/cdimage.iso # output file # /xxxx/xxxxxxxx/ Change to suit your system. BLOCKSIZE=2048 # SPEED=10 # If unspecified, uses max spd. # DEVICE=/dev/cdrom older version. DEVICE="1,0,0" echo; echo "Insert source CD, but do *not* mount it." echo "Press ENTER when ready. " read ready # Wait for input, $ready not used. echo; echo "Copying the source CD to $OF." echo "This may take a while. Please be patient." dd if=$CDROM of=$OF bs=$BLOCKSIZE # Raw device copy. echo; echo "Remove data CD." echo "Insert blank CDR." echo "Press ENTER when ready. " read ready # Wait for input, $ready not used. echo "Copying $OF to CDR." # cdrecord -v -isosize speed=$SPEED dev=$DEVICE $OF # Old version. wodim -v -isosize dev=$DEVICE $OF # Uses Joerg Schilling's "cdrecord" package (see its docs). # http://www.fokus.gmd.de/nthp/employees/schilling/cdrecord.html # Newer Linux distros may use "wodim" rather than "cdrecord" ... echo; echo "Done copying $OF to CDR on device $CDROM." echo "Do you want to erase the image file (y/n)? " # Probably a huge file. read answer case "$answer" in [yY]) rm -f $OF echo "$OF erased." ;; *) echo "$OF not erased.";; esac echo # Exercise: # Change the above "case" statement to also accept "yes" and "Yes" as input. exit 0
Example A-6. Collatz series
#!/bin/bash # collatz.sh # The notorious "hailstone" or Collatz series. # ------------------------------------------- # 1) Get the integer "seed" from the command-line. # 2) NUMBER <-- seed # 3) Print NUMBER. # 4) If NUMBER is even, divide by 2, or # 5)+ if odd, multiply by 3 and add 1. # 6) NUMBER <-- result # 7) Loop back to step 3 (for specified number of iterations). # # The theory is that every such sequence, #+ no matter how large the initial value, #+ eventually settles down to repeating "4,2,1..." cycles, #+ even after fluctuating through a wide range of values. # # This is an instance of an "iterate," #+ an operation that feeds its output back into its input. # Sometimes the result is a "chaotic" series. MAX_ITERATIONS=200 # For large seed numbers (>32000), try increasing MAX_ITERATIONS. h=${1:-$$} # Seed. # Use $PID as seed, #+ if not specified as command-line arg. echo echo "C($h) -*- $MAX_ITERATIONS Iterations" echo for ((i=1; i<=MAX_ITERATIONS; i++)) do # echo -n "$h " # ^^^ # tab # printf does it better ... COLWIDTH=%7d printf $COLWIDTH $h let "remainder = h % 2" if [ "$remainder" -eq 0 ] # Even? then let "h /= 2" # Divide by 2. else let "h = h*3 + 1" # Multiply by 3 and add 1. fi COLUMNS=10 # Output 10 values per line. let "line_break = i % $COLUMNS" if [ "$line_break" -eq 0 ] then echo fi done echo # For more information on this strange mathematical function, #+ see _Computers, Pattern, Chaos, and Beauty_, by Pickover, p. 185 ff., #+ as listed in the bibliography. exit 0
Example A-7. days-between: Days between two dates
#!/bin/bash # days-between.sh: Number of days between two dates. # Usage: ./days-between.sh [M]M/[D]D/YYYY [M]M/[D]D/YYYY # # Note: Script modified to account for changes in Bash, v. 2.05b +, #+ that closed the loophole permitting large negative #+ integer return values. ARGS=2 # Two command-line parameters expected. E_PARAM_ERR=85 # Param error. REFYR=1600 # Reference year. CENTURY=100 DIY=365 ADJ_DIY=367 # Adjusted for leap year + fraction. MIY=12 DIM=31 LEAPCYCLE=4 MAXRETVAL=255 # Largest permissible #+ positive return value from a function. diff= # Declare global variable for date difference. value= # Declare global variable for absolute value. day= # Declare globals for day, month, year. month= year= Param_Error () # Command-line parameters wrong. { echo "Usage: `basename $0` [M]M/[D]D/YYYY [M]M/[D]D/YYYY" echo " (date must be after 1/3/1600)" exit $E_PARAM_ERR } Parse_Date () # Parse date from command-line params. { month=${1%%/**} dm=${1%/**} # Day and month. day=${dm#*/} let "year = `basename $1`" # Not a filename, but works just the same. } 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: Implement more rigorous date checking. } strip_leading_zero () # Better to strip possible leading zero(s) { #+ from day and/or month return ${1#0} #+ since otherwise Bash will interpret them } #+ as octal values (POSIX.2, sect 2.9.2.1). day_index () # Gauss' Formula: { # Days from March 1, 1600 to date passed as param. # ^^^^^^^^^^^^^ day=$1 month=$2 year=$3 let "month = $month - 2" if [ "$month" -le 0 ] then let "month += 12" let "year -= 1" fi let "year -= $REFYR" let "indexyr = $year / $CENTURY" 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://weblogs.asp.net/pgreborio/archive/2005/01/06/347968.aspx echo $Days } calculate_difference () # Difference between two day indices. { let "diff = $1 - $2" # Global variable. } abs () # Absolute value { # Uses global "value" variable. if [ "$1" -lt 0 ] # If negative then #+ then let "value = 0 - $1" #+ change sign, else #+ else let "value = $1" #+ leave it alone. fi } if [ $# -ne "$ARGS" ] # Require two command-line params. then Param_Error fi Parse_Date $1 check_date $day $month $year # See if valid date. strip_leading_zero $day # Remove any leading zeroes day=$? #+ on day and/or month. strip_leading_zero $month month=$? let "date1 = `day_index $day $month $year`" Parse_Date $2 check_date $day $month $year strip_leading_zero $day day=$? strip_leading_zero $month month=$? date2=$(day_index $day $month $year) # Command substitution. calculate_difference $date1 $date2 abs $diff # Make sure it's positive. diff=$value echo $diff exit 0 # Exercise: # -------- # If given only one command-line parameter, have the script #+ use today's date as the second. # Compare this script with #+ the implementation of Gauss' Formula in a C program at #+ http://buschencrew.hypermart.net/software/datedif
Example A-8. Making a dictionary
About AquaClusters Privacy Policy Support Version - 19.0.2-4 AquaFold, Inc Copyright © 2007-2017