1、Linux Shell Bash 精彩脚本示例原文地址:http:/ shell 编程技术, 但是它们并不适合放入本文档的文本讲解中. 不过它们还是非常有用, 运行和分析它们都是很有意思的事. 译者: 这里留给那些有能力而且有多余时间的读者来详读, 个人认为翻译这些注释有点画蛇添足. 例子 A-1. mailformat: 格式化一个 e-mail 消息1 #!/bin/bash2 # mail-format.sh (ver. 1.1): Format e-mail messages.3 4 # Gets rid of carets, tabs, and also folds excessiv
2、ely long lines.5 6 # =7 # Standard Check for Script Argument(s)8 ARGS=19 E_BADARGS=6510 E_NOFILE=6611 12 if $# -ne $ARGS # Correct number of arguments passed to script?13 then14 echo “Usage: basename $0 filename“15 exit $E_BADARGS16 fi17 18 if -f “$1“ # Check if file exists.19 then20 file_name=$121
3、else22 echo “File “$1“ does not exist.“23 exit $E_NOFILE24 fi25 # =26 27 MAXWIDTH=70 # Width to fold excessively long lines to.28 29 # -30 # A variable can hold a sed script.31 sedscript=s/32 s/ */33 s/ */34 s/ */35 # -36 37 # Delete carets and tabs at beginning of lines,38 #+ then fold lines to $MA
4、XWIDTH characters.39 sed “$sedscript“ $1 | fold -s -width=$MAXWIDTH40 # -s option to “fold“41 #+ breaks lines at whitespace, if possible.42 43 44 # This script was inspired by an article in a well-known trade journal45 #+ extolling a 164K MS Windows utility with similar functionality.46 #47 # An nic
5、e set of text processing utilities and an efficient48 #+ scripting language provide an alternative to bloated executables.49 50 exit 0例子 A-2. rn: 一个非常简单的文件重命名工具这个脚本是 例子 12-19 的一个修改版 . 1 #! /bin/bash2 #3 # Very simpleminded filename “rename“ utility (based on “lowercase.sh“).4 #5 # The “ren“ utility,
6、 by Vladimir Lanin (lanincsd2.nyu.edu),6 #+ does a much better job of this.7 8 9 ARGS=210 E_BADARGS=6511 ONE=1 # For getting singular/plural right (see below).12 13 if $# -ne “$ARGS“ 14 then15 echo “Usage: basename $0 old-pattern new-pattern“16 # As in “rn gif jpg“, which renames all gif files in wo
7、rking directory to jpg.17 exit $E_BADARGS18 fi19 20 number=0 # Keeps track of how many files actually renamed.21 22 23 for filename in *$1* #Traverse all matching files in directory.24 do25 if -f “$filename“ # If finds match.26 then27 fname=basename $filename # Strip off path.28 n=echo $fname | sed
8、-e “s/$1/$2/“ # Substitute new for old in filename.29 mv $fname $n # Rename.30 let “number += 1“31 fi32 done 33 34 if “$number“ -eq “$ONE“ # For correct grammar.35 then36 echo “$number file renamed.“37 else 38 echo “$number files renamed.“39 fi 40 41 exit 042 43 44 # Exercises:45 # -46 # What type o
9、f files will this not work on?47 # How can this be fixed?48 #49 # Rewrite this script to process all the files in a directory50 #+ containing spaces in their names, and to rename them,51 #+ substituting an underscore for each space.例子 A-3. blank-rename: 重命名包含空白的文件名这是上一个脚本的简化版. 1 #! /bin/bash2 # blan
10、k-rename.sh3 #4 # Substitutes underscores for blanks in all the filenames in a directory.5 6 ONE=1 # For getting singular/plural right (see below).7 number=0 # Keeps track of how many files actually renamed.8 FOUND=0 # Successful return value.9 10 for filename in * #Traverse all files in directory.1
11、1 do12 echo “$filename“ | grep -q “ “ # Check whether filename13 if $? -eq $FOUND #+ contains space(s).14 then15 fname=$filename # Strip off path.16 n=echo $fname | sed -e “s/ /_/g“ # Substitute underscore for blank.17 mv “$fname“ “$n“ # Do the actual renaming.18 let “number += 1“19 fi20 done 21 22
12、if “$number“ -eq “$ONE“ # For correct grammar.23 then24 echo “$number file renamed.“25 else 26 echo “$number files renamed.“27 fi 28 29 exit 0例子 A-4. encryptedpw: 使用一个本地加密口令, 上传到一个 ftp 服务器. 1 #!/bin/bash2 3 # Example “ex72.sh“ modified to use encrypted password.4 5 # Note that this is still rather i
13、nsecure,6 #+ since the decrypted password is sent in the clear.7 # Use something like “ssh“ if this is a concern.8 9 E_BADARGS=6510 11 if -z “$1“ 12 then13 echo “Usage: basename $0 filename“14 exit $E_BADARGS15 fi 16 17 Username=bozo # Change to suit.18 pword=/home/bozo/secret/password_encrypted.fil
14、e19 # File containing encrypted password.20 21 Filename=basename $1 # Strips pathname out of file name.22 23 Server=“XXX“24 Directory=“YYY“ # Change above to actual server name i.56 57 58 59 60 input_name=“$1“61 echo62 echo “Name = $input_name“63 64 65 # Change all characters of name input to lowerc
15、ase.66 # -67 name=$( echo $input_name | tr A-Z a-z )68 # -69 # Just in case argument to script is mixed case.70 71 72 # Prefix of soundex code: first letter of name.73 # -74 75 76 char_pos=0 # Initialize character position. 77 prefix0=$name:$char_pos:178 prefix=echo $prefix0 | tr a-z A-Z79 # Upperca
16、se 1st letter of soundex.80 81 let “char_pos += 1“ # Bump character position to 2nd letter of name.82 name1=$name:$char_pos83 84 85 # + Exception Patch +86 # Now, we run both the input name and the name shifted one char to the right87 #+ through the value-assigning function.88 # If we get the same v
17、alue out, that means that the first two characters89 #+ of the name have the same value assigned, and that one should cancel.90 # However, we also need to test whether the first letter of the name91 #+ is a vowel or w or h, because otherwise this would bollix things up.92 93 char1=echo $prefix | tr
18、A-Z a-z # First letter of name, lowercased.94 95 assign_value $name96 s1=$value97 assign_value $name198 s2=$value99 assign_value $char1100 s3=$value101 s3=9$s3 # If first letter of name is a vowel102 #+ or w or h,103 #+ then its “value“ will be null (unset).104 #+ Therefore, set it to 9, an otherwis
19、e105 #+ unused value, which can be tested for.106 107 108 if “$s1“ -ne “$s2“ | “$s3“ -eq 9 109 then110 suffix=$s2111 else 112 suffix=$s2:$char_pos113 fi 114 # + end Exception Patch +115 116 117 padding=000 # Use at most 3 zeroes to pad.118 119 120 soun=$prefix$suffix$padding # Pad with zeroes.121 12
20、2 MAXLEN=4 # Truncate to maximum of 4 chars.123 soundex=$soun:0:$MAXLEN124 125 echo “Soundex = $soundex“126 127 echo128 129 # The soundex code is a method of indexing and classifying names130 #+ by grouping together the ones that sound alike.131 # The soundex code for a given name is the first lette
21、r of the name,132 #+ followed by a calculated three-number code.133 # Similar sounding names should have almost the same soundex codes.134 135 # Examples:136 # Smith and Smythe both have a “S-530“ soundex.137 # Harrison = H-625138 # Hargison = H-622139 # Harriman = H-655140 141 # This works out fair
22、ly well in practice, but there are numerous anomalies.142 #143 #144 # The U.S. Census and certain other governmental agencies use soundex,145 # as do genealogical researchers.146 #147 # For more information,148 #+ see the “National Archives and Records Administration home page“,149 #+ http:/www.nara
23、.gov/genealogy/soundex/soundex.html150 151 152 153 # Exercise:154 # -155 # Simplify the “Exception Patch“ section of this script.156 157 exit 0例子 A-10. “Game of Life“1 #!/bin/bash2 # life.sh: “Life in the Slow Lane“3 # Version 2: Patched by Daniel Albers4 #+ to allow non-square grids as input.5 6 #
24、# #7 # This is the Bash script version of John Conways “Game of Life“. #8 # “Life“ is a simple implementation of cellular automata. #9 # - #10 # On a rectangular grid, let each “cell“ be either “living“ or “dead“. #11 # Designate a living cell with a dot, and a dead one with a blank space.#12 # Begi
25、n with an arbitrarily drawn dot-and-blank grid, #13 #+ and let this be the starting generation, “generation 0“. #14 # Determine each successive generation by the following rules: #15 # 1) Each cell has 8 neighbors, the adjoining cells #16 #+ left, right, top, bottom, and the 4 diagonals. #17 # 123 #
26、18 # 4*5 #19 # 678 #20 # #21 # 2) A living cell with either 2 or 3 living neighbors remains alive. #22 # 3) A dead cell with 3 living neighbors becomes alive (a “birth“). #23 SURVIVE=2 #24 BIRTH=3 #25 # 4) All other cases result in a dead cell for the next generation. #26 # # #27 28 29 startfile=gen
27、0 # Read the starting generation from the file “gen0“.30 # Default, if no other file specified when invoking script.31 #32 if -n “$1“ # Specify another “generation 0“ file.33 then34 startfile=“$1“35 fi 36 37 #38 # Abort script if “startfile“ not specified39 #+ AND40 #+ “gen0“ not present.41 42 E_NOS
28、TARTFILE=6843 44 if ! -e “$startfile“ 45 then46 echo “Startfile “$startfile“ missing!“47 exit $E_NOSTARTFILE48 fi49 #50 51 52 ALIVE1=.53 DEAD1=_54 # Represent living and “dead“ cells in the start-up file.55 56 # - #57 # This script uses a 10 x 10 grid (may be increased,58 #+ but a large grid will wi
29、ll cause very slow execution).59 ROWS=1060 COLS=1061 # Change above two variables to match grid size, if necessary.62 # - #63 64 GENERATIONS=10 # How many generations to cycle through.65 # Adjust this upwards,66 #+ if you have time on your hands.67 68 NONE_ALIVE=80 # Exit status on premature bailout
30、,69 #+ if no cells left alive.70 TRUE=071 FALSE=172 ALIVE=073 DEAD=174 75 avar= # Global; holds current generation.76 generation=0 # Initialize generation count.77 78 # =79 80 81 let “cells = $ROWS * $COLS“82 # How many cells.83 84 declare -a initial # Arrays containing “cells“.85 declare -a current
31、86 87 display ()88 89 90 alive=0 # How many cells “alive“ at any given time.91 # Initially zero.92 93 declare -a arr94 arr=( echo “$1“ ) # Convert passed arg to array.95 96 element_count=$#arr*97 98 local i99 local rowcheck100 101 for (i=0; i$element_count; i+)102 do103 104 # Insert newline at end o
32、f each row.105 let “rowcheck = $i % COLS“106 if “$rowcheck“ -eq 0 107 then108 echo # Newline.109 echo -n “ “ # Indent.110 fi 111 112 cell=$arr113 114 if “$cell“ = . 115 then116 let “alive += 1“117 fi 118 119 echo -n “$cell“ | sed -e s/_/ /g120 # Print out array and change underscores to spaces.121 d
33、one 122 123 return124 125 126 127 IsValid () # Test whether cell coordinate valid.128 129 130 if -z “$1“ -o -z “$2“ # Mandatory arguments missing?131 then132 return $FALSE133 fi134 135 local row136 local lower_limit=0 # Disallow negative coordinate.137 local upper_limit138 local left139 local right1
34、40 141 let “upper_limit = $ROWS * $COLS - 1“ # Total number of cells.142 143 144 if “$1“ -lt “$lower_limit“ -o “$1“ -gt “$upper_limit“ 145 then146 return $FALSE # Out of array bounds.147 fi 148 149 row=$2150 let “left = $row * $COLS“ # Left limit.151 let “right = $left + $COLS - 1“ # Right limit.152
35、 153 if “$1“ -lt “$left“ -o “$1“ -gt “$right“ 154 then155 return $FALSE # Beyond row boundary.156 fi 157 158 return $TRUE # Valid coordinate.159 160 161 162 163 IsAlive () # Test whether cell is alive.164 # Takes array, cell number, state of cell as arguments.165 166 GetCount “$1“ $2 # Get alive cel
36、l count in neighborhood.167 local nhbd=$?168 169 170 if “$nhbd“ -eq “$BIRTH“ # Alive in any case.171 then172 return $ALIVE173 fi174 175 if “$3“ = “.“ -a “$nhbd“ -eq “$SURVIVE“ 176 then # Alive only if previously alive.177 return $ALIVE178 fi 179 180 return $DEAD # Default.181 182 183 184 185 GetCoun
37、t () # Count live cells in passed cells neighborhood.186 # Two arguments needed:187 # $1) variable holding array188 # $2) cell number189 190 local cell_number=$2191 local array192 local top193 local center194 local bottom195 local r196 local row197 local i198 local t_top199 local t_cen200 local t_bo
38、t201 local count=0202 local ROW_NHBD=3203 204 array=( echo “$1“ )205 206 let “top = $cell_number - $COLS - 1“ # Set up cell neighborhood.207 let “center = $cell_number - 1“208 let “bottom = $cell_number + $COLS - 1“209 let “r = $cell_number / $COLS“210 211 for (i=0; i$ROW_NHBD; i+) # Traverse from l
39、eft to right. 212 do213 let “t_top = $top + $i“214 let “t_cen = $center + $i“215 let “t_bot = $bottom + $i“216 217 218 let “row = $r“ # Count center row of neighborhood.219 IsValid $t_cen $row # Valid cell position?220 if $? -eq “$TRUE“ 221 then222 if $array$t_cen = “$ALIVE1“ # Is it alive?223 then
40、# Yes?224 let “count += 1“ # Increment count.225 fi226 fi 227 228 let “row = $r - 1“ # Count top row. 229 IsValid $t_top $row230 if $? -eq “$TRUE“ 231 then232 if $array$t_top = “$ALIVE1“ 233 then234 let “count += 1“235 fi236 fi 237 238 let “row = $r + 1“ # Count bottom row.239 IsValid $t_bot $row240
41、 if $? -eq “$TRUE“ 241 then242 if $array$t_bot = “$ALIVE1“ 243 then244 let “count += 1“245 fi246 fi 247 248 done 249 250 251 if $array$cell_number = “$ALIVE1“ 252 then253 let “count -= 1“ # Make sure value of tested cell itself254 fi #+ is not counted.255 256 257 return $count258 259 260 261 next_ge
42、n () # Update generation array.262 263 264 local array265 local i=0266 267 array=( echo “$1“ ) # Convert passed arg to array.268 269 while “$i“ -lt “$cells“ 270 do271 IsAlive “$1“ $i $array$i # Is cell alive?272 if $? -eq “$ALIVE“ 273 then # If alive, then274 array$i=. #+ represent the cell as a period.275 else 276 array$i=“_“ # Otherwise underscore277 fi #+ (which will later be c