diff --git a/LDP/guide/docbook/abs-guide/Change.log b/LDP/guide/docbook/abs-guide/Change.log index 343dee01..08f62162 100644 --- a/LDP/guide/docbook/abs-guide/Change.log +++ b/LDP/guide/docbook/abs-guide/Change.log @@ -2,7 +2,183 @@ RELEASE HISTORY ------- ------- Change log -Version 1.0.X interim release + +Version 1.2 +03/31/02 + +1) In "Operators" subsection of "Operations and Related Topics" chapter: + Fixed comment in in-line example (thanks, Marcus Bergöf). + Added "gcd.sh" example at "%" (modulo) operator. + +2) In "Numerical Constants" subsection of "Operations and Related Topics" + chapter: + Fixed up and enhanced "numbers.sh" example (thanks, Rich Bartell). + +3) In "arithops.sh" example, fixed comment to refer to correct operation + (thanks, Marcus Bergöf). + +4) In "Command Substitution" chapter: + Added excerpts from /etc/rc.d/rc.sysinit as examples of setting + a variable to the contents of a file using "var=`cat filename` + construction. + Added "csubloop.sh" example of setting a variable from the output of a + loop. + +5) In "Basic Commands" section of "External Commands and Filters" chapter: + Added info on "-f" option at "mv" and "rm". + Added "-s" option at "cat". + +6) In "Text Processing Commands" sect. of "External Commands and Filters" chapt.: + Added more info for "nl". + Rewrote "groff" as a separate entry, and added "col" and "tbl"/"eqn" + as subentries. + Added much more info on "tr". + Added more options to "grep". + +7) In "Complex Commands" section of "External Commands" chapter: + Added more info at "xargs". + Added caution when using "*" with "expr" in arithmetic operation. + +8) In "Miscellaneous Commands" section of "External Commands" chapter: + Added more info on "jot/seq". + Added "Linux Journal" reference at "m4". + +9) In "File and Archiving Commands" section of "External Commands and Filters" + chapter: + Added "mimencode/mmencode". + More info on "cksum"/"md5sum". + Added "wstrings.sh" example at "strings" entry. + +10) In "Communications Commands" section of "External Commands" chapter: + Added "mail", with "self-mailer.sh" illustrative example. + +11) In "Time/Date Commands" section of "External Commands" chapter: + Added discussion of "-u" option to "date". + +12) In "Special Variable Types" section of "Introduction to Variables" chapter: + Improved link to "bracket" notation. + Added note that "shift" command also applies to function parameters. + +13) In "Internal Variables" section of "Variables Revisited" chapter: + Added info on "$@" special variable, with new in-line example. + Corrected "$DIRSTACK" listing (thanks again, Nick Drage). + At "$TMOUT", added "t-out.sh", another example of timed input (thanks, + syngin seven). + Added commentary to "am-i-root.sh" example. + +14) Changed document subtitle. + +15) In "Command Substitution" chapter: + Corrected word-splitting example in "caution" (thanks, Tony Richardson). + Added "stupid-script-tricks.sh" example of setting a variable to the + contents of a binary file (which has no useful applications). + +16) In "Internal Commands and Builtins" chapter: + Clarified "ex43.sh" example (thanks, Tony Richardson). + Clarified explanation and example of "echo" eating linefeeds in a + command fed to it. + More info on "keywords" topic. + +17) In "Special Characters" chapter: + Added in-line example of embedding Ctl-H's in a variable. + More info on '-' as an option to certain commands. + Added "background-loop.sh" example at "&" (run command in background). + +18) In "Bash, version 2" chapter: + Added "resistor-inventory.sh" example of database using indirect variable + referencing. + +19) Changed name of example "rot13_2.sh" to "rot14.sh" because otherwise SGML + conversion seems to experience namespace confusion. + +20) In "Quoting" chapter: + Added header notes to "\" escape usage listing. + Added in-line example on behavior of "\". + Slight revisions to "escaped.sh" example. + +21) In "Internal Variables" section of "Variables Revisited" Chapter: + Added usage example for "$GROUPS". + +22) In "Gotchas" chapter: + Added mixing up integer and string comparison operators. + +23) In "While Loops" subsection of "Loops and Branches" chapter: + Added clarifying statement as to when "while loops" are used. + Added "userlist.sh" example of command substitution in generating + "[list]" in "for loop". + +24) In "System and Administrative Commands" chapter: + Added "rmmod". + added "sudo". + Added commentary on "debugfs". + +25) In "Exercises" Appendix: + Reorganization into two distinct subsections. + Added a sample script to annotate. + Added a script code snippet to fix up. + Added a few more script writing problems, including the very difficult + "Playfair Cipher". + +26) Simplified "wf.sh" example. + +27) In "Starting off with a Sha-Bang" chapter: + Fixed typo in "ex2.sh" example script (thanks, David Kimbro for + bringing this to my attention). + +28) In "Arrays" chapter: + Rewrote confusing language in introductory paragraph. + Added "stackex.sh" example for emulating data structures. + Added in-line example of loading an array with the contents of a text + file. + +29) In "Tests" chapter: + Clarification of why semicolon needed when "if" and "then" are on same + line. + Added material to "ex10.sh" example. + +30) In "Here Documents" chapter: + Modified "ex69.sh" example, per message from Jess Thrysoee relaying to me + clarification from Bram Moolenaar. + +31) In "I/O Redirection" chapter: + Fixed comment on in-line example on closing file descriptors. + (Thanks, Matthieu Lucotte) + Made the data file for redirection examples, "names.data", visible. + +32) In "Assorted Tips" section of "Miscellany" chapter: + Added repeated piping of the output of a filter back to that same filter. + Added alternative method of having a function return a value to the body + of the script, with "multiplication.sh" example showing how. + Added method of having a function "return" multiple values, + with illustrative "sum-product.sh" example. + Added "tolower()" function to function library. + Added methods of passing an array to a function, and returning an array + from a function to the main body of a script (with example + "array-function.sh"). + +33) In "Contributed Scripts" appendix: + Added "collatz.sh" example. + Added "life.sh" example (Conway's "Game of Life"). + +34) In "Exit Codes" appendix: + Added footnote with more information about out of range exit codes + (thanks for tweaking my curiosity about this, Akira Huang). + +35) In "Sed Micro-Primer" appendix: + Added use of backslash as newline. + Added example of operation(s) over an address range. + +36) In "Bibliography" section: + Added Pickover entry. + +37) Clarifications in "Copyright" appendix. + +38) Various minor edits to various example scripts. + + + +Version 1.1 release +01/06/02 1) Fix up comments in "weirdvars.sh" example. @@ -629,7 +805,7 @@ In "External Filters, Programs, and Commands" section: Added four sites for example shell scripts. Added reference to Rick Hohensee's shell-scripted virtual machine + assembler. -17) Added "mail-format.sh" to "Contributed Scripts" section. +17) Added "mail-format.sh" to "Contributed Scripts" appendix. 18) In "Tests" section: Clearer definition of what "test" actually means. @@ -793,7 +969,7 @@ In "External Filters, Programs, and Commands" section: * Descriptive names for variables added. 62) Added "copy-cd.sh", a script for copying data CDs, to "Contributed - Scripts" section. + Scripts" appendix. 63) In "Loops" section, separated "Loop Control Commands" ("break" and "continue") into a separate subsection. @@ -1192,7 +1368,7 @@ In "External Filters, Programs, and Commands" section: Added using "[[ ]]" and "(( ))" in comparisons. Corrections in discussion of interactive shells, plus illustrative example. - In "Contributed Scripts" section: + In "Contributed Scripts" appendix: Added "primes.sh" to demonstrate that arrays are not need to generate prime numbers. Added comments to "manview.sh" @@ -1246,7 +1422,7 @@ Comments: Another major improvement. The HOWTO is nearly book length, Changes from version 0.2: 1) Fixed: - Renamed Example A-2 in Appendix A (Contributed Scripts) to + Renamed Example A-2 in Appendix A (Contributed Scripts appendix) to "encryptedpw". It had previously been named "manview", duplicating the title of Example A-1. @@ -1299,20 +1475,20 @@ In "External Filters, Programs, and Commands" section: 21) Added "su" to "System and Administrative Commands" section. 22) Added Jim Van Zandt's "daily backup" example script - to "Contrib-Scripts" section. + to "Contrib-Scripts" appendix. 23) Enhanced example 66 (ex66.sh) on arrays with more methods of initializing array variables. 24) Corrected "Siever" entry in bibliography. -25) Added Jordi Sanfeliu's "tree" script to "Contrib-Scripts" section. +25) Added Jordi Sanfeliu's "tree" script to "Contrib-Scripts" appendix. 26) Added Robbins' "Bash Reference Card" to bibliography. 27) Added reference to Duarte's sed tutorial in bibliography. -28) Added "rn.sh", file rename utility to "Contrib-Scripts" section. +28) Added "rn.sh", file rename utility to "Contrib-Scripts" appendix. 29) Added "initializing multiple variables on same line" to ex9.sh. @@ -1625,7 +1801,7 @@ Other changes subsection 'Optimizations' subsection 'Assorted Tips' -56) Contrib script section added +56) Contrib script section added. 4 scripts so far. 57) Expanded 'Credits' section. diff --git a/LDP/guide/docbook/abs-guide/abs-guide.sgml b/LDP/guide/docbook/abs-guide/abs-guide.sgml index 13f79d8c..974aba8e 100644 --- a/LDP/guide/docbook/abs-guide/abs-guide.sgml +++ b/LDP/guide/docbook/abs-guide/abs-guide.sgml @@ -132,11 +132,11 @@ Uncomment line below to generate index. - + - + @@ -219,13 +219,30 @@ Uncomment line below to generate index. + + + + + + + + + + + + + + + + + ]> Advanced Bash-Scripting Guide - A complete guide to shell scripting + An in-depth exploration of the art of shell scripting @@ -237,8 +254,8 @@ Uncomment line below to generate index. - 1.1 - 06 January 2002 + 1.2 + 31 March 2002 @@ -296,6 +313,13 @@ Uncomment line below to generate index. Bugfixes, material and scripts added. + + 1.2 + 31 March 2002 + mc + More bugfixes, material and scripts added. + + @@ -309,13 +333,13 @@ Uncomment line below to generate index. self-study, and a reference and source of knowledge on shell scripting techniques. The exercises and heavily-commented examples invite active reader participation, under the premise - that the only way to really learn scripting is to write - scripts. + that the only way to really learn scripting is to + write scripts. The latest update of this document, as an archived tarball including both the SGML source and rendered HTML, may be downloaded from + url="http://personal.riverusers.com/~thegrendel/abs-guide-1.2.tar.gz"> the author's home site. See the change log for a revision history. @@ -603,10 +627,12 @@ exit $WHATEVER # Doesn't matter. The script will not exit here.POSIX - Portable - Operating System - Interface, an attempt to standardize - UNIX-like OSes. + Portable + Operating + System Interface, an attempt to + standardize UNIX-like + OSes. sh standard). Note that the path given at the sha-bang must @@ -1830,6 +1856,7 @@ echo "variable = $variable" # variable = initial_value + @@ -1864,6 +1891,7 @@ echo "variable = $variable" # variable = initial_value A command followed by an & will run in the background. + bash$ sleep 10 & [1] 850 @@ -1871,6 +1899,15 @@ echo "variable = $variable" # variable = initial_value + Within a script, commands and even loops may run in the + background. + + + Running a loop in the background + &bgloop; + + A command run in the background within a script may cause the script to hang, waiting for a keystroke. Fortunately, there is a stdout, such as tar, cat, etc. + + + bash$ echo "whatever" | cat - +whatever + + + Where a filename is expected, - redirects output to stdout (sometimes seen with @@ -2153,6 +2197,19 @@ echo $a # 28 Ctl-H Backspace. + + #!/bin/bash +# Embedding Ctl-H in a string. + +a="^H^H" # Two Ctl-H's (backspaces). +echo "abcdef" # abcdef +echo -n "abcdef$a " # abcd f +# Space at end ^ ^ Backspaces twice. +echo -n "abcdef$a" # abcdef +# No space at end Doesn't backspace (why?). + # Results may not be quite as expected. +echo; echo + @@ -2480,6 +2537,7 @@ arch=$(uname -m) parameter is the name of the script. See the manpage for execv. + After $9, the arguments must be enclosed in brackets, for example, ${10}, ${11}, ${12}. @@ -2529,6 +2587,7 @@ fi --- + shift @@ -2543,16 +2602,23 @@ fi $1 <--- $2, $2 <--- $3, $3 <--- $4, etc. The old $1 disappears, but - $0 does not change. If you use a - large number of positional parameters to a script, - shift lets you access those past - 10, although {bracket} notation also - permits this (see ). + $0 (the script name) + does not change. If you use a large number of + positional parameters to a script, shift + lets you access those past 10, although + {bracket} notation + also permits this. Using <command>shift</command> &ex19; + + The shift command also works on + parameters passed to a function. See . + @@ -2897,16 +2963,21 @@ echo "\"Hello\", he said." # "Hello", he said. - The behavior of \ depends on whether - it is itself escaped, quoted, or appearing within a + The behavior of \ depends on whether + it is itself escaped, quoted, or appearing within command substitution or a here document. - echo \z # z + # Simple escaping and quoting +echo \z # z echo \\z # \z echo '\z' # \z echo '\\z' # \\z echo "\z" # \z echo "\\z" # \z + + # Command substitution echo `echo \z` # z echo `echo \\z` # z echo `echo \\\z` # \z @@ -2916,6 +2987,7 @@ echo `echo \\\\\\\z` # \\z echo `echo "\z"` # \z echo `echo "\\z"` # \z + # Here document cat <<EOF \z EOF # \z @@ -2925,7 +2997,48 @@ cat <<EOF EOF # \z # These examples supplied by Stephane Chazelas. - + + + Elements of a string assigned to a variable may be escaped, but + the escape character alone may not be assigned to a variable. + variable=\ +echo "$variable" +# Will not work - gives an error message: +# test.sh: : command not found +# A "naked" escape cannot safely be assigned to a variable. +# +# What actually happens here is that the "\" escapes the newline and +#+ the effect is variable=echo "$variable" +#+ invalid variable assignment + +variable=\ +23skidoo +echo "$variable" # 23skidoo + # This works, since the second line + #+ is a valid variable assignment. + +variable=\ +# \^ escape followed by space +echo "$variable" # space + +variable=\\ +echo "$variable" # \ + +variable=\\\ +echo "$variable" +# Will not work - gives an error message: +# test.sh: \: command not found +# +# First escape escapes second one, but the third one is left "naked", +#+ with same result as first instance, above. + +variable=\\\\ +echo "$variable" # \\ + # Second and fourth escapes escaped. + # This is o.k. + + + @@ -3150,8 +3263,17 @@ else fi - Add a semicolon when 'if' and 'then' are on same line. + + When if and then + are on same line in a condition test, a semicolon must + terminate the if statement. Both + if and then are keywords. Keywords (or commands) + begin statements, and before a new statement on the same line + begins, the old one must terminate. + if [ -x "$filename" ]; then + <anchor id="elifref1">Else if and elif @@ -3890,7 +4012,7 @@ category=minerals # No spaces allowed after the "=". # = as a test operator if [ "$string1" = "$string2" ] -# if [ "Xstring1" = "Xstring2" ] is safer, +# if [ "X$string1" = "X$string2" ] is safer, # to prevent an error message should one of the variables be empty. # (The prepended "X" characters cancel out.) then @@ -4040,10 +4162,17 @@ echo "z = $z" # z = 125 This operator finds use in, among other things, generating numbers within a specific range (see and ) - and formatting program output (see ). It can even be used to generate prime - numbers, (see ). + linkend="ex21"> and ) and + formatting program output (see and + ). It can even be used to generate + prime numbers, (see ). Modulo turns + up surprisingly often in various numerical recipes. + + + Greatest common divisor + &gcd; + + @@ -4659,11 +4788,12 @@ done directory stack - contents of the directory stack (affected by - pushd and popd) This - builtin variable is the counterpart to the dirs command. + the top value in the directory stack + (affected by pushd and popd) This builtin + variable corresponds to the dirs + command, however dirs shows the entire + contents of the directory stack. @@ -4770,6 +4900,22 @@ echo "FUNCNAME = $FUNCNAME" # FUNCNAME = current user, as recorded in /etc/passwd. + + + +root# echo $GROUPS +0 + + +root# echo ${GROUPS[1]} +1 + + +root# echo ${GROUPS[5]} +6 + + + @@ -5369,11 +5515,11 @@ echo "Last command argument processed = $last_cmd_arg" of a timed read does work). Implementing timed input in a script is certainly - possible, but hardly seems worth the effort. One method is to - set up a timing loop to signal the script when it times out. - This also requires a signal handling routine to trap (see - ) the interrupt generated by the timing - loop (whew!). + possible, but may require complex machinations. One method + is to set up a timing loop to signal the script when it + times out. This also requires a signal handling routine to + trap (see ) the interrupt generated by + the timing loop (whew!). Timed Input @@ -5388,6 +5534,16 @@ echo "Last command argument processed = $last_cmd_arg" &timeout; + Perhaps the simplest method is using the + option to read. + + + Timed <command>read</command> + &tout; + + + @@ -5568,7 +5724,25 @@ echo "Last command argument processed = $last_cmd_arg" <command>arglist</command>: Listing arguments with $* and $@ &arglist; - + + + Following a shift, the + $@ holds the remaining command-line + parameters, lacking the previous $1, + which was lost. + #!/bin/bash +# Invoke with ./scriptname 1 2 3 4 5 + +echo "$@" # 1 2 3 4 5 +shift +echo "$@" # 2 3 4 5 +shift +echo "$@" # 3 4 5 + +# Each "shift" loses parameter $1. +# "$@" then contains the remaining parameters. + + The $@ special parameter finds use as a tool for filtering input into shell scripts. The @@ -5577,6 +5751,7 @@ echo "Last command argument processed = $last_cmd_arg" from files given as parameters to the script. See and . + The $* and $@ parameters sometimes display inconsistent and puzzling behavior, depending on the setting of &bingrep; + More of the same. - Here is yet another example of the [list] resulting - from command substitution. + + Listing all users on the system + &userlist; + + + A final example of the [list] resulting from command + substitution. Checking all the binaries in a directory for @@ -7022,12 +7203,13 @@ echo "number = $number" # number = 0 <programlisting>&forloopc;</programlisting> </example> - <para>See also <xref linkend="qfunction"> and <xref - linkend="twodim">.</para> + <para>See also <xref linkend="qfunction">, <xref + linkend="twodim">, and <xref linkend="collatz">.</para> <para>---</para> - <para>Now, for an example from <quote>real life</quote>.</para> + <para>Now, a <emphasis>for-loop</emphasis> used in a + <quote>real-life</quote> context.</para> <example id="ex24"> <title>Using <command>efax</command> in batch mode @@ -7055,9 +7237,13 @@ echo "number = $number" # number = 0 This construct tests for a condition at the top of a - loop, and keeps looping as long as that condition is - true (returns a 0 exit status). + loop, and keeps looping as long as that condition + is true (returns a 0 exit status). In contrast + to a for loop, a + while loop finds use in situations + where the number of loop repetitions is not known + beforehand. while @@ -7067,6 +7253,7 @@ echo "number = $number" # number = 0 done + As is the case with for/in loops, placing the do on the same line as the condition test requires a semicolon. @@ -7463,6 +7650,8 @@ esac &ex32; + See also . + @@ -7485,10 +7674,10 @@ esac A builtin - is a command contained within the Bash tool set, literally - built in. A builtin may be a synonym to - a system command of the same name, but Bash reimplements it - internally. + is a command contained within the Bash tool + set, literally built in. A builtin may + be a synonym to a system command of the same name, but Bash + reimplements it internally. This is either for performance reasons (builtins execute much faster than external commands, which usually @@ -7505,10 +7694,18 @@ esac operator. Keywords have a special meaning to the shell, and indeed are the building blocks of the shell's syntax. As examples, for, - while and + while, do, and ! are keywords. Similar to a - builtin, a keyword is hard-coded into - Bash. + builtin, a keyword is hard-coded into Bash, + but unlike a builtin, a keyword is not by itself a command, + but part of a larger command structure. + + An exception to this is the time command, listed in the official + Bash documentation as a keyword. + + + <anchor id="intio1">I/O @@ -7554,47 +7751,34 @@ fi linkend="base">. - Be aware that echo `command` + Be aware that echo `command` deletes any linefeeds that the output of command - generates. Since $IFS normally - contains \n as one of its set of whitespace characters, Bash - segments the output of command - at linefeeds into arguments to echo, - which then emits these arguments separated by - spaces. + generates. + + The $IFS (internal field + separator) variable normally contains + \n (linefeed) as one of its set of + whitespace + characters. Bash therefore splits the output of + command at linefeeds + into arguments to echo. Then + echo outputs these arguments, + separated by spaces. -bash$ printf '\n\n1\n2\n3\n\n\n\n' - - - - 1 - 2 - 3 - - - - -bash $ +bash$ ls -l /usr/share/apps/kjezz/sounds +-rw-r--r-- 1 root root 1407 Nov 7 2000 reflect.au + -rw-r--r-- 1 root root 362 Nov 7 2000 seconds.au -bash$ echo "`printf '\n\n1\n2\n3\n\n\n\n'`" - - - - 1 - 2 - 3 - -bash $ +bash$ echo `ls -l /usr/share/apps/kjezz/sounds` +total 40 -rw-r--r-- 1 root root 716 Nov 7 2000 reflect.au -rw-r--r-- 1 root root 362 Nov 7 2000 seconds.au - This command is a shell builtin, and not the same as @@ -7714,6 +7898,9 @@ echo; echo "Keypress was "\"$keypress\""." # Using these options is tricky, since they need to be in the correct order. + The option to read + permits timed input (see ). + The read command may also read its variable value from a file redirected to @@ -7841,16 +8028,17 @@ echo; echo "Keypress was "\"$keypress\""." stack and simultaneously changes the current working directory to dir-name - popd removes (pops) the top directory path - name off the directory stack and simultaneously changes the - current working directory to that directory popped from the stack. - + popd removes + (pops) the top directory path name off the directory stack + and simultaneously changes the current working directory + to that directory popped from the stack. dirs lists the contents of the directory - stack (counterpart to $DIRSTACK) A successful - pushd or popd will - automatically invoke dirs. + stack (compare this with the $DIRSTACK variable). + A successful pushd or + popd will automatically invoke + dirs. Scripts that require various changes to the current @@ -7923,9 +8111,9 @@ echo; echo "Keypress was "\"$keypress\""." &ex44; - + A version of <quote>rot13</quote> - &rot13_2; + &rot14; The eval command can be @@ -8988,12 +9176,13 @@ wait cat filename cat file.1 file.2 file.3 > file.123 - The - option to cat inserts consecutive - numbers before all lines of the target file(s). The - option numbers only the non-blank - lines. The option echoes nonprintable - characters, using ^ notation. + The option to cat + inserts consecutive numbers before all lines of the + target file(s). The option numbers + only the non-blank lines. The option + echoes nonprintable characters, using ^ + notation. The option squeezes multiple + consecutive blank lines into a single blank line. See also and . @@ -9071,6 +9260,12 @@ wait files to a directory, or even to rename a directory. For some examples of using mv in a script, see and . + + When used in a non-interactive script, + mv takes the + (force) option to bypass user + input. + @@ -9085,7 +9280,8 @@ wait Delete (remove) a file or files. The - forces removal of even readonly files. + option forces removal of even readonly files, and is useful + for bypassing user input in a script. When used with the recursive flag , this command removes files all the way @@ -9328,19 +9524,34 @@ find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \ xargs - A filter for feeding arguments to a command, and also a tool for - assembling the commands themselves. It breaks a data - stream into small enough chunks for filters and commands - to process. Consider it as a powerful replacement - for backquotes. In situations where backquotes fail - with a too many arguments + A filter for feeding arguments to a command, and also + a tool for assembling the commands themselves. It breaks + a data stream into small enough chunks for filters + and commands to process. Consider it as a powerful + replacement for backquotes. In situations where backquotes + fail with a too many arguments error, substituting xargs often works. Normally, xargs reads from stdin or from a pipe, but it can also be given the output of a file. - + The default command for xargs is - echo. + echo. This means that input + piped to xargs may have linefeeds and + other whitespace characters stripped out. + + +bash$ ls -l +total 0 + -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file1 + -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file2 + + +bash$ ls -l | xargs +total 0 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file1 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file2 + + + ls | xargs -p -l gzip gzips every file in current @@ -9424,6 +9635,16 @@ find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \ + + expr 5 \* 3 + + returns 15 + The multiplication operator + must be escaped when used in an arithmetic expression + with expr. + + + y=`expr $y + 1` @@ -9432,7 +9653,6 @@ find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \ y=$(($y+1)) This is an example of arithmetic expansion. - @@ -9505,6 +9725,21 @@ find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \ &ex51; + The option gives the UTC (Universal + Coordinated Time). + + + +bash$ date +Fri Mar 29 21:07:39 MST 2002 + + + +bash$ date -u +Sat Mar 30 04:07:42 UTC 2002 + + + @@ -10198,31 +10433,6 @@ done - - colrm - - colrm - - - command - colrm - - - Column removal filter. This removes columns (characters) - from a file and writes the file, lacking the range of - specified columns, back to stdout. - colrm 2 4 <filename removes the - second through fourth characters from each line of the - text file filename. - If the file contains tabs or nonprintable - characters, this may cause unpredictable - behavior. In such cases, consider using - expand and - unexpand in a pipe preceding - colrm. - - - paste @@ -10396,9 +10606,16 @@ done The option causes a case-insensitive search. + The option matches only whole + words. + The option lists only the files in which matches were found, but not the matching lines. + The (recursive) option searches files in + the current working directory and all subdirectories below + it. + The option lists the matching lines, together with line numbers. @@ -10694,18 +10911,45 @@ fi The option deletes a range of characters. - tr -d 0-9 <filename + echo "abcdef" # abcdef +echo "abcdef" | tr -d b-d # aef + + +tr -d 0-9 <filename # Deletes all digits from the file "filename". - The (or - ) option deletes all but the - first instance of a string of consecutive characters. - This option is useful for removing excess whitespace. + The (or + ) option deletes all but the + first instance of a string of consecutive characters. + This option is useful for removing excess whitespace. + + bash$ echo "XXXXX" | tr --squeeze-repeats 'X' X + The complement + option inverts the character set to + match. With this option, tr acts only + upon those characters not matching + the specified set. + + + bash$ echo "acfdeb123" | tr -c b-d + ++c+d+b++++ + + + + + Note that tr recognizes POSIX character classes. + + bash$ echo "abcd2ef1" | tr '[:alpha:]' - +----2--1 + + + <command>toupper</command>: Transforms a file to all uppercase. &ex49; @@ -10730,7 +10974,8 @@ fi Generating <quote>Crypto-Quote</quote> Puzzles &cryptoquote; - + + <command>tr</command> variants @@ -10811,6 +11056,25 @@ fi + + col + + col + + + command + reverse line feed + + + This deceptively named filter removes reverse line feeds + from an input stream. It also attempts to replace + whitespace with equivalent tabs. The chief use of + col is in filtering the output + from certain text processing utilities, such as + groff and tbl. + + + column @@ -10828,12 +11092,37 @@ fi Using <command>column</command> to format a directory listing - &col; + &colm; + + colrm + + colrm + + + command + colrm + + + Column removal filter. This removes columns (characters) + from a file and writes the file, lacking the range of + specified columns, back to stdout. + colrm 2 4 <filename removes the + second through fourth characters from each line of the + text file filename. + If the file contains tabs or nonprintable + characters, this may cause unpredictable + behavior. In such cases, consider using + expand and + unexpand in a pipe preceding + colrm. + + + nl @@ -10851,6 +11140,10 @@ fi filename omitted, operates on stdin. + The output of nl is very similar to + cat -n, however, by default + nl does not list blank lines. + <command>nl</command>: A self-numbering script. &lnum; @@ -10946,15 +11239,14 @@ fi - groff - gs TeX + gs - groff + TeX command - groff + TeX gs @@ -10963,27 +11255,66 @@ fi command Postscript + + + TeX and Postscript + are text markup languages used for preparing copy for + printing or formatted video display. + + TeX is Donald Knuth's elaborate + typsetting system. It is often convenient to write a + shell script encapsulating all the options and arguments + passed to one of these markup languages. + + Ghostscript + (gs) is a GPL-ed Postscript + interpreter. + + + + + + groff + tbl + eqn - TeX + groff command - TeX + groff + + + tbl + + + command + table + + + eqn + + + command + equation - Groff, TeX, and Postscript are text markup languages - used for preparing copy for printing or formatted video - display. + Yet another text markup and display formatting language + is groff. This is the enhanced GNU version + of the venerable UNIX roff/troff display + and typesetting package. Manpages + use groff (see ). - Manpages use - groff (see ). - Ghostscript (gs) - is a GPL Postscript interpreter. TeX - is Donald Knuth's elaborate typsetting system. It is - often convenient to write a shell script encapsulating - all the options and arguments passed to one of these - markup languages. + The tbl table processing utility + is considered part of groff, as its + function is to convert table markup into + groff commands. + + The eqn equation processing utility + is likewise part of groff, and + its function is to convert equation markup into + groff commands. @@ -11523,7 +11854,14 @@ fi with grep or sed. See and . + + + An <quote>improved</quote> <emphasis>strings</emphasis> + command + &wstrings; + + @@ -11630,6 +11968,20 @@ fi the contents of key system files have not been altered or corrupted. The md5sum command is the most appropriate of these in security applications. + + Note that cksum also shows the size, + in bytes, of the target file. + + + +bash$ cksum /boot/vmlinuz +1670054224 804083 /boot/vmlinuz + + +bash$ md5sum /boot/vmlinuz +0f43eccea8f09e0a0b2b5cf1dcf333ba /boot/vmlinuz + + @@ -11680,6 +12032,36 @@ fi + + mimencode + mmencode + + mimencode + + + command + mime + + + mmencode + + + command + encode + + + The mimencode and + mmencode commands process + multimedia-encoded e-mail attachments. Although + mail user agents (such as + pine or kmail) + normally handle this automatically, these particular + utilities permit manipulating such attachments manually + from the command line or in a batch by means of a shell + script. + + + crypt @@ -12222,6 +12604,30 @@ fi <anchor id="commmail1">Mail + + mail + + mail + + + command + mail + + + + Send an e-mail message to a user. + + This stripped-down command-line mail client + works fine as a command embedded in a script. + + + A script that mails itself + &selfmailer; + + + + + vacation @@ -12511,8 +12917,31 @@ LIMIT_STRING These utilities emit a sequence of integers, with a - user selected increment. This can be used to advantage in - a for loop. + user-selected increment. + + The normal separator character between each integer is a + newline, but this can be changed with the + option. + + +bash$ seq 5 +1 + 2 + 3 + 4 + 5 + + + +bash$ seq -s : 5 +1:2:3:4:5 + + + + + Both jot and seq + come in handy in a for + loop. Using <command>seq</command> to generate loop arguments @@ -12917,15 +13346,23 @@ echo -n "hello world" | dd cbs=1 conv=unblock 2> /dev/null A hidden treasure, m4 is a - powerful macro processor + powerful macro processing filter, A macro is a symbolic constant that expands into a command string or a set of operations on parameters. - utility, virtually a complete language. In - fact, m4 combines some of the + virtually a complete language. Although originally + written as a pre-processor for Fortran, + m4 turned out to be + useful as a stand-alone utility. In fact, + m4 combines some of the functionality of eval, tr, and awk. + linkend="awkref">awk, in addition to its extensive + macro expansion facilities. + + The April, 2002 issue of Linux + Journal has a very nice article on + m4 and its uses. Using m4 @@ -13179,11 +13616,37 @@ echo -n "hello world" | dd cbs=1 conv=unblock 2> /dev/null Runs a program or script as a - substitute user. - su rjones starts a shell as user - rjones. A naked su - defaults to root. See . + substitute user. + su rjones starts a shell as user + rjones. A naked su + defaults to root. See . + + + + + sudo + + sudo + + + command + sudo + + + Runs a command as root (or another user). This may + be used in a script, thus permitting a regular user to + run the script. + + #!/bin/bash + +# Some commands. +sudo cp /root/secretfile /home/bozo/secret +# Some more commands. + + The file /etc/sudoers holds + the names of users permitted to invoke + sudo. @@ -14848,14 +15311,23 @@ mount -o loop /dev/loop0 /mnt # Mount it. debugfs + Filesystem check, repair, and debug command set. + fsck: a front end for checking a UNIX filesystem (may invoke other utilities). The actual filesystem type generally defaults to ext2. + e2fsck: ext2 filesystem checker. - debugfs: ext2 filesystem debugger. + + debugfs: ext2 filesystem debugger. + One of the uses of this versatile, but dangerous command + is to (attempt to) recover deleted files. For advanced users + only! + All of these should be invoked as root, and they can damage or destroy a filesystem if misused. + @@ -15240,7 +15712,23 @@ then insmod - Force insertion of a kernel module. Must be invoked as root. + Force installation of a kernel module. Must be invoked + as root. + + + + + rmmod + + rmmod + + + command + rmmod + + + Force unloading of a kernel module. Must be invoked + as root. @@ -15497,28 +15985,8 @@ COMMAND `echo` # no arg COMMAND "`echo`" # one empty arg -# Thanks, S.C. +# Thanks, S.C. - - Word splitting resulting from command - substitution may remove trailing newlines characters - from the output of the reassigned command(s). This can - cause unpleasant surprises. - - dir_listing=`ls -l` -echo $dirlisting - -# Expecting a nicely ordered directory listing, such as: -# -rw-rw-r-- 1 bozo 30 May 13 17:15 1.txt -# -rw-rw-r-- 1 bozo 51 May 15 20:57 t2.sh -# -rwxr-xr-x 1 bozo 217 Mar 5 21:13 wi.sh - -# However, what you get is: -# total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo -# bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh - -# The newlines disappeared. - Even when there is no word splitting, command substitution can remove trailing newlines. @@ -15555,21 +16023,112 @@ echo "You hit ${#key} key." # ${#variable} = number of characters in $variable Thanks, S.C. - + + + + + Using echo to output an + unquoted variable set with command + substitution removes trailing newlines characters from + the output of the reassigned command(s). This can cause + unpleasant surprises. + + dir_listing=`ls -l` +echo $dir_listing # unquoted + +# Expecting a nicely ordered directory listing. + +# However, what you get is: +# total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo +# bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh + +# The newlines disappeared. + + +echo "$dir_listing" # quoted +# -rw-rw-r-- 1 bozo 30 May 13 17:15 1.txt +# -rw-rw-r-- 1 bozo 51 May 15 20:57 t2.sh +# -rwxr-xr-x 1 bozo 217 Mar 5 21:13 wi.sh + + + - Command substitution even permits setting a variable to the contents of a file, using either redirection or the cat command. + linkend="catref">cat command. + + variable1=`<file1` # Set "variable1" to contents of "file1". variable2=`cat file2` # Set "variable2" to contents of "file2". # Be aware that the variables may contain embedded whitespace, #+ or even (horrors), control characters. - + + + # Excerpts from system file, /etc/rc.d/rc.sysinit +#+ (on a Red Hat Linux installation) + + +if [ -f /fsckoptions ]; then + fsckoptions=`cat /fsckoptions` +... +fi +# +# +if [ -e "/proc/ide/${disk[$device]}/media" ] ; then + hdmedia=`cat /proc/ide/${disk[$device]}/media` +... +fi +# +# +if [ ! -n "`uname -r | grep -- "-"`" ]; then + ktag="`cat /proc/version`" +... +fi +# +# +if [ $usb = "1" ]; then + sleep 5 + mouseoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=02"` + kbdoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=01"` +... +fi + + + + Do not set a variable to the contents of a + long text file unless you have a very good + reason for doing so. Do not set a variable to the contents of a + binary file, even as a joke. + + + Stupid script tricks + &stupscr; + + + Notice that a buffer overrun + does not occur. This is one instance where an interpreted + language, such as Bash, provides more protection from + programmer mistakes than a compiled language. + + + + + Command substitution permits setting a variable to the + output of a loop. The + key to this is grabbing the output of an echo command within the + loop. + + + Generating a variable from a loop + &csubloop; + + + Command substitution makes it possible to extend the @@ -15913,7 +16472,8 @@ command1 | command2 | command3 > output-file # Redirecting only stderr to a pipe. exec 3>&1 # Save current "value" of stdout. -ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'ls' and 'grep'. +ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls'). +# ^^^^ ^^^^ exec 3>&- # Now close it for the remainder of the script. # Thanks, S.C. @@ -15991,12 +16551,17 @@ exec 3>&- # Now close it for the remainder of the s &redir5; + + Data file <quote>names.data</quote> for above examples + &namesdata; + + Redirecting the stdout of a code block has the effect of saving its output to a file. See . - Here documents - are a special case of redirected code blocks. + Here documents + are a special case of redirected code blocks. @@ -16548,7 +17113,7 @@ echo a111b | gawk '/a1+b/' - POSIX Character Classes + <anchor id="posixref">POSIX Character Classes [:class:] @@ -17387,6 +17952,10 @@ exit # Invokes "exit ()" function, not "exit" builtin. &ex60; + The shift + command works on arguments passed to functions (see ). + In contrast to certain other programming languages, shell scripts normally pass only value parameters to functions. @@ -17480,12 +18049,13 @@ fi The largest positive integer a function can return is - 256. The return command is closely - tied to the concept of exit + 256. The return command is closely tied + to the concept of exit status, which accounts for this particular - limitation. Fortunately, there are workarounds for those - situations requiring a large integer return value from - a function. + limitation. Fortunately, there are various workarounds for those situations + requiring a large integer return value from a + function. @@ -17530,8 +18100,8 @@ echo "return value = $Return_Val" #25701 See also . - Exercise for the reader: Using - what we have just learned, extend the previous Exercise: Using what we have + just learned, extend the previous Roman numerals example to accept arbitrarily large input. @@ -17913,11 +18483,14 @@ false && ( true || echo false ) # (nothing echoed) - Newer versions of bash support one-dimensional - arrays. Arrays may be declared with the variable[xx] - notation or explicitly by a declare -a variable - statement. To dereference (find the contents of) an array variable, use - curly bracket notation, that is, ${variable[xx]}. + Newer versions of Bash support one-dimensional arrays. + Array elements may be initialized with the + variable[xx] notation. Alternately, + a script may introduce the entire array by an explicit + declare -a variable statement. To + dereference (find the contents of) an array element, use + curly bracket notation, that is, + ${variable[xx]}. Simple array usage @@ -17929,7 +18502,7 @@ false && ( true || echo false ) # (nothing echoed) for array use. - array=( zero one two three four five ) + array=( zero one two three four five ) echo ${array[0]} # zero echo ${array:0} # zero @@ -17976,6 +18549,8 @@ echo ${#array} # 4 # Copying an array. array2=( "${array1[@]}" ) +# or +array2="${array1[@]}" # Adding an element to an array. array=( "${array[@]}" "new element" ) @@ -17985,7 +18560,42 @@ array[${#array[*]}]="new element" # Thanks, S.C. - -- + + + The array=( element1 element2 ... elementN ) + initialization operation, with the help of command substitution, makes it + possible to load the contents of a text file into an array. + + + #!/bin/bash + +filename=sample_file + +# cat sample_file +# +# 1 a b c +# 2 d e fg + + +declare -a array1 + +array1=( `cat "$filename" | tr '\n' ' '`) # Loads contents + # of $filename into array1. +# list file to stdout. +# change linefeeds in file to spaces. + +echo ${array1[@]} # List the array. +# 1 a b c 2 d e fg +# +# Each whitespace-separated "word" in the file +#+ has been assigned to an element of the array. + +element_count=${#array1[*]} +echo $element_count # 8 + + + Arrays permit deploying old familiar algorithms as shell scripts. Whether this is necessarily a good idea is left to the reader to @@ -18016,6 +18626,16 @@ array[${#array[*]}]="new element" -- + Arrays lend themselves, to some extent, to emulating data + structures for which Bash has no native support. + + + Emulating a push-down stack + &stackex; + + + -- + Fancy manipulation of array subscripts may require intermediate variables. For projects involving this, again consider using a more powerful programming language, such as Perl or C. @@ -18036,6 +18656,14 @@ array[${#array[*]}]="new element" &twodim; + A two-dimensional array is essentially equivalent to a + one-dimensional one, but with additional addressing modes for + referencing and manipulating the individual elements by + row and column position. + + For an even more elaborate example of simulating a + two-dimensional array, see . + @@ -18921,6 +19549,24 @@ fi # Aborts with an error message. + Mixing up integer and + string comparison operators. + #!/bin/bash +# bad-op.sh + +number=1 + +while [ "$number" < 5 ] # Wrong! Should be while [ "number" -lt 5 ] +do + echo -n "$number " + let "number += 1" +done + +# Attempt to run this bombs with the error message: +# bad-op.sh: 5: No such file or directory + + + Sometimes variables within test brackets ([ ]) need to be quoted (double quotes). Failure to do so may cause unexpected behavior. See , @@ -19681,6 +20352,81 @@ exit 0 + + + The 0 - 255 range for function return + values is a severe limitation. Global variables and other + workarounds are often problematic. An alternative method for + a function to communicate a value back to the main body of + the script is to have the function write to + stdout the return value, + and assign this to a variable. + + + Return value trickery + &multiplication; + + + The same technique also works for alphanumeric + strings. This means that a function can return + a non-numeric value. + + + capitalize_ichar () # Capitalizes initial character +{ #+ of argument string(s) passed. + + string0="$@" # Accepts multiple arguments. + + firstchar=${string0:0:1} # First character. + string1=${string0:1} # Rest of string(s). + + FirstChar=`echo "$firstchar" | tr a-z A-Z` + # Capitalize first character. + + echo "$FirstChar$string1" # Output to stdout. + +} + +newstring=`capitalize_ichar "each sentence should start with a capital letter."` +echo "$newstring" # Each sentence should start with a capital letter. + + + It is even possible for a function to return + multiple values with this method. + + + Even more return value trickery + &sumproduct; + + + + + + Next in our bag of trick are techniques for passing + an array to a + function, then + returning an array back to the main body of + the script. + + Passing an array involves loading the space-separated + elements of the array into a variable with command substitution. Getting + an array back as the return value from + a function uses the previously mentioned strategem of + echoing the array in the function, + then invoking command substitution and the ( + ... ) operator to assign it to an array. + + + Passing and returning arrays + &arrfunc; + + + For a more elaborate example of passing arrays to + functions, see . + + + Using the double parentheses construct, it is possible to use C-like syntax for setting and incrementing variables @@ -19689,6 +20435,20 @@ exit 0 linkend="forloopc"> and . + + A useful scripting technique is to + repeatedly feed the output of a filter + (by piping) back to the same filter, but + with a different set of arguments and/or options. Especially + suitable for this is tr. + + # From "wstrings.sh" example. + +wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \ +tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '` + + + The run-parts command is handy for running a set of command @@ -19826,6 +20586,12 @@ exit 0 &ex78; + + Simple database application, using indirect variable + referencing + &resistor; + + Using arrays and other miscellaneous trickery to deal four random hands from a deck of cards @@ -19914,9 +20680,9 @@ exit 0 Hardware A used IBM Thinkpad, model 760XL laptop (P166, 80 meg RAM) - running Red Hat 7.1. Sure, it's slow and has a funky keyboard, - but it beats the heck out of a No. 2 pencil and a Big Chief - tablet. + running Red Hat 7.1/7.2. Sure, it's slow and has a funky + keyboard, but it beats the heck out of a No. 2 pencil and a + Big Chief tablet. @@ -20033,9 +20799,10 @@ exit 0 these out. Others making helpful suggestions and pointing out errors - were Gabor Kiss, Leopold Toetsch, Peter Tillier, Nick Drage - (script ideas!), and David Lawyer (himself an author of 4 - HOWTOs). + were Gabor Kiss, Leopold Toetsch, Peter Tillier, Marcus Berglof, + Tony Richardson, Nick Drage (script ideas!), Rich Bartell, Jess + Thrysoee, Bram Moolenaar, and David Lawyer (himself an author + of 4 HOWTOs). My gratitude to Chet Ramey and Brian Fox for writing Bash, @@ -20236,6 +21003,24 @@ exit 0 + + + CliffordPickover + + Computers, Pattern, Chaos, and Beauty + + St. Martin's Press + + + 1990 + + 0-312-04123-3 + A treasure trove of ideas and recipes for + computer-based exploration of mathematical oddities. + * + + + ArnoldRobbins @@ -20586,12 +21371,30 @@ exit 0 ©cd; + + Collatz series + &collatz; + + - <command>days-between</command>: Calculate number of days between two dates + <command>days-between</command>: Calculate number of days + between two dates &daysbetween; - + + + <quote>Game of Life</quote> + &lifeslow; + + + + Data file for <quote>Game of Life</quote> + &gen0data; + + + + + +++ The following two scripts are by Mark Moraes of the University of Toronto. See the enclosed file Moraes-COPYRIGHT @@ -20876,12 +21679,33 @@ exit 0 - Substituting a zero-length string for another is equivalent + + Substituting a zero-length string for another is equivalent to deleting that string within a line of input. This leaves the remainder of the line intact. Applying s/GUI// - to the line The most important parts of any application are - its GUI and sound effects results in - The most important parts of any application are its and sound effects + to the line + The most important parts of any application are its GUI and sound effects + results in + The most important parts of any application are its and sound effects + + The backslash represents a newline as a + substitution character. In this special case, the replacement + expression continues on the next line. + s/^ */\ +/g + This substitution replaces line-beginning spaces with a + newline. The net result is to replace paragraph indents with + a blank line between paragraphs. + + An address range followed by one or more operations may require + open and closed curly brackets, with appropriate newlines. + /[0-9A-Za-z]/,/^$/{ +/^$/d +} + This deletes only the first of each set of consecutive blank + lines. That might be useful for single-spacing a text file, + but retaining the blank line(s) between paragraphs. + A quick way to double-space a text file is sed G filename. @@ -20902,6 +21726,7 @@ exit 0 + @@ -20915,7 +21740,7 @@ exit 0 Awk - Awk + Awk is a full-featured text processing language with a syntax reminiscent of C. While @@ -20972,6 +21797,8 @@ awk '{print $1 $5 $6}' $filename + + @@ -21051,7 +21878,7 @@ awk '{print $1 $5 $6}' $filename see above) - + exit status out of range exit -1 exit takes only integer args in the @@ -21061,17 +21888,22 @@ awk '{print $1 $5 $6}' $filename - According to the table, exit codes 1 - 2, 126 - 165, and 255 have - special meanings, and should therefore be avoided - as user-specified exit parameters. Ending a script with - exit 127 would certainly cause confusion - when troubleshooting (is the error a command not - found or a user-defined one?). However, many scripts use - an exit 1 as a general bailout upon error. - Since exit code 1 signifies so many - possible errors, this might not add any additional ambiguity, - but, on the other hand, it probably would not be very informative - either. + According to the table, exit codes 1 - 2, 126 - 165, and 255 + + Out of range exit values can result in + unpredictable exit codes. For example, + exit 3809 gives an exit code of + 225. + + have special meanings, and should therefore be avoided as + user-specified exit parameters. Ending a script with exit + 127 would certainly cause confusion when troubleshooting + (is the error a command not found or a + user-defined one?). However, many scripts use an exit + 1 as a general bailout upon error. Since exit code + 1 signifies so many possible errors, + this might not add any additional ambiguity, but, on the other + hand, it probably would not be very informative either. There has been an attempt to systematize exit status numbers (see + limited subset of the equivalent shell scripting ones. Batch file keywords / variables / operators, and their shell equivalents @@ -21868,6 +22700,93 @@ history Exercises + + Analyzing Scripts + + Examine the following script. Run it, then explain what it + does. Annotate the script, then rewrite it in a more compact + and elegant manner. + + + #!/bin/bash + +MAX=10000 + + + for((nr=1; nr<$MAX; nr++)) + do + + let "t1 = nr % 5" + if [ "$t1" -ne 3 ] + then + continue + fi + + let "t2 = nr % 7" + if [ "$t2" -ne 4 ] + then + continue + fi + + let "t3 = nr % 9" + if [ "$t3" -ne 5 ] + then + continue + fi + + break # What heppens when you comment out this line? Why? + + done + + echo "Number = $nr" + + +exit 0 + + + --- + + A reader sent in the following code snippet. + + while read LINE +do + echo $LINE +done < `tail -f /var/log/messages` + + He wished to write a script tracking changes to the system log + file, /var/log/messages. Unfortunately, + the above code block hangs and does nothing + useful. Why? Fix this so it does work (hint: + rather than redirecting the + stdin of the loop, try a pipe). + + + --- + + + Analyze , and reorganize it in a + simplified and more logical style. See how many of its variables + can be eliminated and try to optimize the script to speed up + its execution time. + + Alter the script so that it accepts any ordinary ASCII + text file as input for its initial generation. The + script will read the first $ROW*$COL + characters, and set the occurrences of vowels as + living cells. Hint: be sure to translate the + spaces in the input file to underscore characters. + + + + + + + + Writing Scripts + + + Write a script to carry out each of the following tasks. @@ -21901,6 +22820,37 @@ history + + Changing the line spacing of a text file + + + Write a script that reads each line of a target file, then + writes the line back to stdout, but with + an extra blank line following. This has the effect of + double-spacing the file. + + Include all necessary code to check whether the script + gets the necessary command line argument (a filename), + and whether the specified file exists. + + When the script runs correctly, modify it to + triple-space the target file. + + Finally, write a script to remove all blank lines from + the target file, single-spacing it. + + + + + + Backwards Listing + + Write a script that echoes itself to + stdout, but + backwards. + + + Primes @@ -21983,6 +22933,21 @@ history + + Quadratic Equations + + Solve a quadratic equation of the form + Ax^2 + Bx + C = 0. Have a script take + as arguments the coefficients, A, + B, and C, + and return the solutions to four decimal places. + + Hint: pipe the coefficients to bc, using the well-known formula, + x = ( -B +/- sqrt( B^2 - 4AC ) ) / 2A. + + + Lucky Numbers @@ -22073,6 +23038,24 @@ Smith,Tom,404 Polk Ave.,Los Angeles,CA,90003,(213) 879-5612 + + XML Conversion + + Convert an XML file to both HTML and text form. + + + + + Morse Code + + Convert a text file to Morse code. Each character of the + text file will be represented as a corresponding Morse + code group of dots and dashes (underscores), separated by + whitespace from the next. For example, script + ===> ... _._. ._. .. .__. _. + + + Hex Dump @@ -22084,6 +23067,20 @@ Smith,Tom,404 Polk Ave.,Los Angeles,CA,90003,(213) 879-5612 + + Emulating a Shift Register + + Using as an inspiration, + write a script that emulates a 64-bit shift register as + an array. Implement + functions to load the register, + shift left, and shift + right. Finally, write a function that + interprets the register contents as eight 8-bit ASCII + characters. + + + Determinant @@ -22112,39 +23109,149 @@ Smith,Tom,404 Polk Ave.,Los Angeles,CA,90003,(213) 879-5612 + + Playfair Cipher + + + Implement the Playfair (Wheatstone) Cipher in a + script. + The Playfair Cipher encrypts text by substitution + of each 2-letter digram + (grouping). Traditionally, one would use a 5 x 5 letter + scrambled alphabet code key square for the encryption + and decryption. + + 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, skipping letters already used. + +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. + +or + +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. + +or + +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. +G H +M N +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 Cryptoanalysis" (1939), gives a +fairly detailed rundown on 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 + message. + Decrypting encrypted + text. + + + The script will make extensive use of arrays and functions. + + + + + + -- Please do not send the author your solutions to these exercises. There are better ways to impress him with your cleverness, such as submitting bugfixes and suggestions for improving this book. + + + Copyright + The Advanced Bash-Scripting Guide is copyright, (c) 2000, by Mendel Cooper. This document may only be distributed subject to the terms and conditions set forth in the LDP License These are very liberal terms, and they should not hinder any legitimate distribution or use of this book. The author especially - encourages the use of this book, or portions thereof, for - instructional purposes. + encourages the use of this book for instructional purposes. + + Essentially, you may freely distribute this book in + unaltered electronic form. You must obtain + the author's permission to distribute a modified version + or derivative work. The purpose of this restriction is to + preserve the artistic integrity of this document and to prevent + forking. + + The commercial print rights to this book are available. Please + notify the + author if interested. + + --- Hyun Jin Cha has done a Korean - translation of an earlier version of this book. Spanish, - Portuguese, and French translations are underway. If you wish to - translate this document into another language, please feel free - to do so, subject to the terms stated above. The author would - appreciate being notified of such efforts. + translation of version 1.0.11 of this book. Spanish, + Portuguese, French, and Chinese translations are underway. If you + wish to translate this document into another language, please feel + free to do so, subject to the terms stated above. The author wishes + to be notified of such efforts. - If this document is printed as a hard-copy book, the author - requests a courtesy copy. This is a request, not a requirement. diff --git a/LDP/guide/docbook/abs-guide/am-i-root.sh b/LDP/guide/docbook/abs-guide/am-i-root.sh index caa9c235..3af8a96a 100644 --- a/LDP/guide/docbook/abs-guide/am-i-root.sh +++ b/LDP/guide/docbook/abs-guide/am-i-root.sh @@ -20,12 +20,10 @@ exit 0 ROOTUSER_NAME=root -username=`id -nu` +username=`id -nu` # Or... username=`whoami` if [ "$username" = "$ROOTUSER_NAME" ] then echo "Rooty, toot, toot. You are root." else echo "You are just a regular fella." fi - -exit 0 diff --git a/LDP/guide/docbook/abs-guide/arith-ops.sh b/LDP/guide/docbook/abs-guide/arith-ops.sh index 5d34dbd5..ac3220f7 100644 --- a/LDP/guide/docbook/abs-guide/arith-ops.sh +++ b/LDP/guide/docbook/abs-guide/arith-ops.sh @@ -16,7 +16,7 @@ echo -n "$n " : $[ n = $n + 1 ] # ":" necessary because otherwise Bash attempts -#+ to interpret "$((n = $n + 1))" as a command. +#+ to interpret "$[ n = $n + 1 ]" as a command. # Works even if "n" was initialized as a string. echo -n "$n " diff --git a/LDP/guide/docbook/abs-guide/assert.sh b/LDP/guide/docbook/abs-guide/assert.sh index 263af9f7..d834c789 100644 --- a/LDP/guide/docbook/abs-guide/assert.sh +++ b/LDP/guide/docbook/abs-guide/assert.sh @@ -17,7 +17,7 @@ assert () # If condition false, if [ ! $1 ] then echo "Assertion failed: \"$1\"" - echo "File $0, line $lineno" + echo "File \"$0\", line $lineno" exit $E_ASSERT_FAILED # else # return @@ -38,6 +38,8 @@ assert "$condition" $LINENO # Some commands. # ... +echo "You will never see this statement echo." +# ... # Some more commands. exit 0 diff --git a/LDP/guide/docbook/abs-guide/behead.sh b/LDP/guide/docbook/abs-guide/behead.sh index 4716761e..ab57c113 100644 --- a/LDP/guide/docbook/abs-guide/behead.sh +++ b/LDP/guide/docbook/abs-guide/behead.sh @@ -18,7 +18,7 @@ else done fi -# ==> Exercise for the reader: Add error checking and other options. +# ==> Exercise: Add error checking and other options. # ==> # ==> Note that the small sed script repeats, except for the arg passed. # ==> Does it make sense to embed it in a function? Why or why not? diff --git a/LDP/guide/docbook/abs-guide/bubble.sh b/LDP/guide/docbook/abs-guide/bubble.sh index b65e4fe3..816531e8 100644 --- a/LDP/guide/docbook/abs-guide/bubble.sh +++ b/LDP/guide/docbook/abs-guide/bubble.sh @@ -3,29 +3,32 @@ # Recall the algorithm for a bubble sort. In this particular version... -# With each successive pass through the array to be sorted, -# compare two adjacent elements, and swap them if out of order. -# At the end of the first pass, the "heaviest" element has sunk to bottom. -# At the end of the second pass, the next "heaviest" one has sunk next to bottom. -# And so forth. -# This means that each successive pass needs to traverse less of the array. -# You will therefore notice a speeding up in the printing of the later passes. +# With each successive pass through the array to be sorted, +#+ compare two adjacent elements, and swap them if out of order. +# At the end of the first pass, the "heaviest" element has sunk to bottom. +# At the end of the second pass, the next "heaviest" one has sunk next to bottom. +# And so forth. +# This means that each successive pass needs to traverse less of the array. +# You will therefore notice a speeding up in the printing of the later passes. exchange() { # Swaps two members of the array. - local temp=${Countries[$1]} # Temporary storage for element getting swapped out. + local temp=${Countries[$1]} # Temporary storage + #+ for element getting swapped out. Countries[$1]=${Countries[$2]} Countries[$2]=$temp return } -declare -a Countries # Declare array, optional here since it's initialized below. +declare -a Countries # Declare array, + #+ optional here since it's initialized below. -Countries=(Netherlands Ukraine Zaire Turkey Russia Yemen Syria Brazil Argentina Nicaragua Japan Mexico Venezuela Greece England Israel Peru Canada Oman Denmark Wales France Kenya Qatar Liechtenstein Hungary) -# Couldn't think of one starting with X (darn!). +Countries=(Netherlands Ukraine Zaire Turkey Russia Yemen Syria Brazil Argentina Nicaragua Japan Mexico Venezuela Greece England Israel Peru Canada Oman Denmark Wales France Kenya Xanadu Qatar Liechtenstein Hungary) +# "Xanadu" is the mythical place where, according to Coleridge, +#+ Kubla Khan did a pleasure dome decree. clear # Clear the screen to start with. @@ -44,11 +47,12 @@ do while [ "$index" -lt "$comparisons" ] # Beginning of inner loop do if [ ${Countries[$index]} \> ${Countries[`expr $index + 1`]} ] - # If out of order... - # Recalling that \> is ASCII comparison operator. + # If out of order... + # Recalling that \> is ASCII comparison operator + #+ within single brackets. - # if [[ ${Countries[$index]} > ${Countries[`expr $index + 1`]} ]] - # also works. + # if [[ ${Countries[$index]} > ${Countries[`expr $index + 1`]} ]] + #+ also works. then exchange $index `expr $index + 1` # Swap. fi @@ -56,8 +60,8 @@ do done # End of inner loop -let "comparisons -= 1" # Since "heaviest" element bubbles to bottom, - # we need do one less comparison each pass. +let "comparisons -= 1" # Since "heaviest" element bubbles to bottom, + #+ we need do one less comparison each pass. echo echo "$count: ${Countries[@]}" # Print resultant array at end of each pass. @@ -65,7 +69,6 @@ echo let "count += 1" # Increment pass count. done # End of outer loop - -# All done. + # All done. exit 0 diff --git a/LDP/guide/docbook/abs-guide/connect-stat.sh b/LDP/guide/docbook/abs-guide/connect-stat.sh index c8a86c62..783afd66 100644 --- a/LDP/guide/docbook/abs-guide/connect-stat.sh +++ b/LDP/guide/docbook/abs-guide/connect-stat.sh @@ -48,6 +48,7 @@ exit 0 # As it stands, this script must be terminated with a Control-C. -# Exercises for the reader: +# Exercises: +# --------- # Improve the script so it exits on a "q" keystroke. # Make the script more user-friendly in other ways. diff --git a/LDP/guide/docbook/abs-guide/continue-nlevel.sh b/LDP/guide/docbook/abs-guide/continue-nlevel.sh index bcd29f7d..eba9393a 100644 --- a/LDP/guide/docbook/abs-guide/continue-nlevel.sh +++ b/LDP/guide/docbook/abs-guide/continue-nlevel.sh @@ -22,7 +22,7 @@ done echo; echo -# Exercise for the reader: +# Exercise: # Come up with a meaningful use for "continue N" in a script. exit 0 diff --git a/LDP/guide/docbook/abs-guide/copy-cd.sh b/LDP/guide/docbook/abs-guide/copy-cd.sh index dbaaf0cb..1a1e52b9 100644 --- a/LDP/guide/docbook/abs-guide/copy-cd.sh +++ b/LDP/guide/docbook/abs-guide/copy-cd.sh @@ -43,7 +43,7 @@ esac echo -# Exercise for the reader: +# Exercise: # Change the above "case" statement to also accept "yes" and "Yes" as input. exit 0 diff --git a/LDP/guide/docbook/abs-guide/days-between.sh b/LDP/guide/docbook/abs-guide/days-between.sh index 3b73a0ba..743f74df 100644 --- a/LDP/guide/docbook/abs-guide/days-between.sh +++ b/LDP/guide/docbook/abs-guide/days-between.sh @@ -45,7 +45,8 @@ 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 for the reader: Implement more rigorous date checking. + # + # Exercise: Implement more rigorous date checking. } diff --git a/LDP/guide/docbook/abs-guide/escaped.sh b/LDP/guide/docbook/abs-guide/escaped.sh index 762e0dd5..76206a50 100644 --- a/LDP/guide/docbook/abs-guide/escaped.sh +++ b/LDP/guide/docbook/abs-guide/escaped.sh @@ -4,16 +4,18 @@ echo; echo echo "\v\v\v\v" # Prints \v\v\v\v -# Must use the -e option with 'echo' to print escaped characters. +# Use the -e option with 'echo' to print escaped characters. echo -e "\v\v\v\v" # Prints 4 vertical tabs. echo -e "\042" # Prints " (quote, octal ASCII character 42). +# The $'\X' construct makes the -e option unnecessary. +echo $'\n' # Newline. +echo $'\a' # Alert (beep). -# Bash, version 2 and later, permits using the $'\xxx' construct. -echo $'\n' -echo $'\a' +# Version 2 and later of Bash permits using the $'\xxx' construct. echo $'\t \042 \t' # Quote (") framed by tabs. + # Assigning ASCII characters to a variable. # ---------------------------------------- quote=$'\042' # " assigned to a variable. @@ -22,7 +24,7 @@ echo "$quote This is a quoted string, $quote and this lies outside the quotes." echo # Concatenating ASCII chars in a variable. -triple_underline=$'\137\137\137' # 137 is octal ASCII code for "_". +triple_underline=$'\137\137\137' # 137 is octal ASCII code for '_'. echo "$triple_underline UNDERLINE $triple_underline" ABC=$'\101\102\103\010' # 101, 102, 103 are octal A, B, C. @@ -32,6 +34,7 @@ echo; echo escape=$'\033' # 033 is octal for escape. echo "\"escape\" echoes as $escape" +# no visible output. echo; echo diff --git a/LDP/guide/docbook/abs-guide/ex10.sh b/LDP/guide/docbook/abs-guide/ex10.sh index 8586649c..563a45d6 100644 --- a/LDP/guide/docbook/abs-guide/ex10.sh +++ b/LDP/guide/docbook/abs-guide/ex10.sh @@ -8,7 +8,27 @@ then echo "0 is true." else echo "0 is false." -fi +fi # 0 is true. + +echo + +echo "Testing \"1\"" +if [ 1 ] # one +then + echo "1 is true." +else + echo "1 is false." +fi # 1 is true. + +echo + +echo "Testing \"-1\"" +if [ -1 ] # minus one +then + echo "-1 is true." +else + echo "-1 is false." +fi # -1 is true. echo @@ -18,7 +38,7 @@ then echo "NULL is true." else echo "NULL is false." -fi +fi # NULL is false. echo @@ -28,7 +48,7 @@ then echo "Random string is true." else echo "Random string is false." -fi +fi # Random string is true. echo @@ -39,7 +59,7 @@ then echo "Uninitialized variable is true." else echo "Uninitialized variable is false." -fi +fi # Uninitialized variable is false. echo @@ -49,11 +69,12 @@ then echo "Uninitialized variable is true." else echo "Uninitialized variable is false." -fi +fi # Uninitialized variable is false. echo -xyz= # Initialized, but set to null value. + +xyz= # Initialized, but set to null value. echo "Testing \"-n \$xyz\"" if [ -n "$xyz" ] @@ -61,7 +82,7 @@ then echo "Null variable is true." else echo "Null variable is false." -fi +fi # Null variable is false. echo @@ -75,7 +96,7 @@ then echo "\"false\" is true." #+ and it tests true. else echo "\"false\" is false." -fi +fi # "false" is true. echo @@ -85,7 +106,8 @@ then echo "\"\$false\" is true." else echo "\"\$false\" is false." -fi # Now, we get the expected result. +fi # "$false" is false. + # Now, we get the expected result. echo diff --git a/LDP/guide/docbook/abs-guide/ex12.sh b/LDP/guide/docbook/abs-guide/ex12.sh index 96f8e82f..af41aebf 100644 --- a/LDP/guide/docbook/abs-guide/ex12.sh +++ b/LDP/guide/docbook/abs-guide/ex12.sh @@ -3,9 +3,9 @@ filename=sys.log cat /dev/null > $filename; echo "Creating / cleaning out file." -# Creates file if it does not already exist, -# and truncates it to zero length if it does. -# : > filename also works. +# Creates file if it does not already exist, +#+ and truncates it to zero length if it does. +# : > filename also works. tail /var/log/messages > $filename # /var/log/messages must have world read permission for this to work. diff --git a/LDP/guide/docbook/abs-guide/ex16.sh b/LDP/guide/docbook/abs-guide/ex16.sh index 60de54a0..63e14aac 100644 --- a/LDP/guide/docbook/abs-guide/ex16.sh +++ b/LDP/guide/docbook/abs-guide/ex16.sh @@ -5,12 +5,18 @@ echo $a b=$a echo $b -# Now, getting a little bit fancier... +# Now, getting a little bit fancier (command substitution). a=`echo Hello!` # Assigns result of 'echo' command to 'a' echo $a +# Note that using an exclamation mark (!) in command substitution +#+ will not work from the command line, +#+ since this triggers the Bash "history mechanism". a=`ls -l` # Assigns result of 'ls -l' command to 'a' -echo $a +echo $a # Unquoted, however, removes tabs and newlines. +echo +echo "$a" # The quoted variable preserves whitespace. + # (See the chapter on "Quoting.") exit 0 diff --git a/LDP/guide/docbook/abs-guide/ex19.sh b/LDP/guide/docbook/abs-guide/ex19.sh index 59e8af84..0db002a1 100644 --- a/LDP/guide/docbook/abs-guide/ex19.sh +++ b/LDP/guide/docbook/abs-guide/ex19.sh @@ -1,9 +1,9 @@ #!/bin/bash # Using 'shift' to step through all the positional parameters. -# Name this script something like shft, -# and invoke it with some parameters, for example -# ./shft a b c def 23 skidoo +# Name this script something like shft, +#+ and invoke it with some parameters, for example +# ./shft a b c def 23 skidoo until [ -z "$1" ] # Until all parameters used up... do @@ -11,6 +11,6 @@ do shift done -echo # Extra line feed. +echo # Extra line feed. exit 0 diff --git a/LDP/guide/docbook/abs-guide/ex2.sh b/LDP/guide/docbook/abs-guide/ex2.sh index b78163bb..244a29e8 100644 --- a/LDP/guide/docbook/abs-guide/ex2.sh +++ b/LDP/guide/docbook/abs-guide/ex2.sh @@ -36,12 +36,12 @@ fi # * ) lines=$1;; # esac # -#* Skip ahead to "Loops" to understand this. +#* Skip ahead to "Loops" chapter to understand this. cd $LOG_DIR -if [ `pwd` != "$LOG_DIR" ] # or if [ "$PWD" != "LOG_DIR" ] +if [ `pwd` != "$LOG_DIR" ] # or if [ "$PWD" != "$LOG_DIR" ] # Not in /var/log? then echo "Can't change to $LOG_DIR." diff --git a/LDP/guide/docbook/abs-guide/ex23.sh b/LDP/guide/docbook/abs-guide/ex23.sh index 2c59f715..f9954aa8 100644 --- a/LDP/guide/docbook/abs-guide/ex23.sh +++ b/LDP/guide/docbook/abs-guide/ex23.sh @@ -7,8 +7,8 @@ do echo -n "$a " done -# The 'in list' missing, therefore the loop operates on '$@' -# (command-line argument list, including whitespace). +# The 'in list' missing, therefore the loop operates on '$@' +#+ (command-line argument list, including whitespace). echo diff --git a/LDP/guide/docbook/abs-guide/ex26a.sh b/LDP/guide/docbook/abs-guide/ex26a.sh index 17d4ad5b..c0a62b04 100644 --- a/LDP/guide/docbook/abs-guide/ex26a.sh +++ b/LDP/guide/docbook/abs-guide/ex26a.sh @@ -6,7 +6,7 @@ previous=$var1 while echo "previous-variable = $previous" echo previous=$var1 - [ "$var1" != end ] # Keeps track of what "var1" was previously. + [ "$var1" != end ] # Keeps track of what $var1 was previously. # Four conditions on "while", but only last one controls loop. # The *last* exit status is the one that counts. do diff --git a/LDP/guide/docbook/abs-guide/ex28.sh b/LDP/guide/docbook/abs-guide/ex28.sh index d2787788..5bbdb5c8 100644 --- a/LDP/guide/docbook/abs-guide/ex28.sh +++ b/LDP/guide/docbook/abs-guide/ex28.sh @@ -19,7 +19,7 @@ do echo -n "$a " done -# Exercise for the reader: +# Exercise: # Why does loop print up to 20? echo; echo diff --git a/LDP/guide/docbook/abs-guide/ex29.sh b/LDP/guide/docbook/abs-guide/ex29.sh index 24e17fc9..74507fe5 100644 --- a/LDP/guide/docbook/abs-guide/ex29.sh +++ b/LDP/guide/docbook/abs-guide/ex29.sh @@ -10,7 +10,8 @@ case "$Keypress" in * ) echo "Punctuation, whitespace, or other";; esac # Allows ranges of characters in [square brackets]. -# Exercise for the reader: +# Exercise: +# -------- # As the script stands, # it accepts a single keystroke, then terminates. # Change the script so it accepts continuous input, # reports on each keystroke, and terminates only when "X" is hit. diff --git a/LDP/guide/docbook/abs-guide/ex3.sh b/LDP/guide/docbook/abs-guide/ex3.sh index 63c17ce8..33ff8f3f 100644 --- a/LDP/guide/docbook/abs-guide/ex3.sh +++ b/LDP/guide/docbook/abs-guide/ex3.sh @@ -8,13 +8,13 @@ # invoked from the command line. sed -e /^$/d "$1" -# The '-e' means an "editing" command follows (optional here). -# '^' is the beginning of line, '$' is the end. -# This match lines with nothing between the beginning and the end, -# blank lines. -# The 'd' is the delete command. +# The '-e' means an "editing" command follows (optional here). +# '^' is the beginning of line, '$' is the end. +# This match lines with nothing between the beginning and the end, +#+ blank lines. +# The 'd' is the delete command. -# Quoting the command-line arg permits -# whitespace and special characters in the filename. +# Quoting the command-line arg permits +#+ whitespace and special characters in the filename. exit 0 diff --git a/LDP/guide/docbook/abs-guide/ex30.sh b/LDP/guide/docbook/abs-guide/ex30.sh index 37edf79c..8250031a 100644 --- a/LDP/guide/docbook/abs-guide/ex30.sh +++ b/LDP/guide/docbook/abs-guide/ex30.sh @@ -58,8 +58,9 @@ esac echo -# Exercise for the reader: -# Change the script so it accepts continuous input, -# instead of terminating after displaying just one address. +# Exercise: +# -------- +# Change the script so it accepts continuous input, +#+ instead of terminating after displaying just one address. exit 0 diff --git a/LDP/guide/docbook/abs-guide/ex38.sh b/LDP/guide/docbook/abs-guide/ex38.sh index d8928ab8..c547dd10 100644 --- a/LDP/guide/docbook/abs-guide/ex38.sh +++ b/LDP/guide/docbook/abs-guide/ex38.sh @@ -3,8 +3,8 @@ . data-file # Load a data file. # Same effect as "source data-file", but more portable. -# The file "data-file" must be present in current working directory, -# since it is referred to by its 'basename'. +# The file "data-file" must be present in current working directory, +#+ since it is referred to by its 'basename'. # Now, reference some data from that file. diff --git a/LDP/guide/docbook/abs-guide/ex40.sh b/LDP/guide/docbook/abs-guide/ex40.sh index 0526c572..c513db2e 100644 --- a/LDP/guide/docbook/abs-guide/ex40.sh +++ b/LDP/guide/docbook/abs-guide/ex40.sh @@ -1,17 +1,17 @@ #!/bin/bash -SPEED=2 # May use higher speed if supported. +SPEED=2 # May use higher speed if your hardware supports it. IMAGEFILE=cdimage.iso CONTENTSFILE=contents -DEFAULTDIR=/opt +DEFAULTDIR=/opt # Make sure this directory exists. # Script to automate burning a CDR. # Uses Joerg Schilling's "cdrecord" package. # (http://www.fokus.gmd.de/nthp/employees/schilling/cdrecord.html) -# If this script invoked as an ordinary user, need to suid cdrecord -# (chmod u+s /usr/bin/cdrecord, as root). +# If this script invoked as an ordinary user, need to suid cdrecord +#+ (chmod u+s /usr/bin/cdrecord, as root). if [ -z "$1" ] then diff --git a/LDP/guide/docbook/abs-guide/ex43.sh b/LDP/guide/docbook/abs-guide/ex43.sh index 0811029c..0ac7e10b 100644 --- a/LDP/guide/docbook/abs-guide/ex43.sh +++ b/LDP/guide/docbook/abs-guide/ex43.sh @@ -1,11 +1,16 @@ #!/bin/bash -y=`eval ls -l` # Similar to y=`ls -l` -echo $y # but linefeeds removed. +y=`eval ls -l` # Similar to y=`ls -l` +echo $y # but linefeeds removed because "echoed" variable is unquoted. +echo +echo "$y" # Linefeeds preserved when variable is quoted. -y=`eval df` # Similar to y=`df` -echo $y # but linefeeds removed. +echo; echo -# Since LF's not preserved, it may make it easier to parse output. +y=`eval df` # Similar to y=`df` +echo $y # but linefeeds removed. + +# When LF's not preserved, it may make it easier to parse output, +#+ using utilities such as "awk". exit 0 diff --git a/LDP/guide/docbook/abs-guide/ex5.sh b/LDP/guide/docbook/abs-guide/ex5.sh index 93fc008f..442df1e8 100644 --- a/LDP/guide/docbook/abs-guide/ex5.sh +++ b/LDP/guide/docbook/abs-guide/ex5.sh @@ -1,15 +1,15 @@ #!/bin/bash echo hello -echo $? # Exit status 0 returned because command successful. +echo $? # Exit status 0 returned because command executed successfully. lskdf # Unrecognized command. -echo $? # Non-zero exit status returned. +echo $? # Non-zero exit status returned because command failed to execute. echo exit 113 # Will return 113 to shell. -# To verify this, type "echo $?" after script terminates. + # To verify this, type "echo $?" after script terminates. -# By convention, an 'exit 0' indicates success, -# while a non-zero exit value means an error or anomalous condition. +# By convention, an 'exit 0' indicates success, +#+ while a non-zero exit value means an error or anomalous condition. diff --git a/LDP/guide/docbook/abs-guide/ex61.sh b/LDP/guide/docbook/abs-guide/ex61.sh index d53a85d3..5447bc23 100644 --- a/LDP/guide/docbook/abs-guide/ex61.sh +++ b/LDP/guide/docbook/abs-guide/ex61.sh @@ -4,8 +4,7 @@ # Range: 0 - 200 # It's crude, but it works. -# Extending the range and otherwise improving the script -# is left as an exercise for the reader. +# Extending the range and otherwise improving the script is left as an exercise. # Usage: roman number-to-convert @@ -40,7 +39,8 @@ do done return $number - # Exercise for the reader: + # Exercise: + # -------- # Explain how this function works. # Hint: division by successive subtraction. } diff --git a/LDP/guide/docbook/abs-guide/ex69.sh b/LDP/guide/docbook/abs-guide/ex69.sh index c54fa45a..1f146afb 100644 --- a/LDP/guide/docbook/abs-guide/ex69.sh +++ b/LDP/guide/docbook/abs-guide/ex69.sh @@ -1,7 +1,6 @@ #!/bin/bash # Non-interactive use of 'vi' to edit a file. -# (Will not work with 'vim', for some reason.) # Emulates 'sed'. E_BADARGS=65 @@ -25,7 +24,10 @@ ZZ x23LimitStringx23 #----------End here document-----------# -# Note that ^[ above is a literal escape -# typed by Control-V Escape. +# Note that ^[ above is a literal escape +#+ typed by Control-V <Esc>. + +# Bram Moolenaar points out that this may not work with 'vim', +#+ because of possible problems with terminal interaction. exit 0 diff --git a/LDP/guide/docbook/abs-guide/ex9.sh b/LDP/guide/docbook/abs-guide/ex9.sh index 30d511c7..a7a373f9 100644 --- a/LDP/guide/docbook/abs-guide/ex9.sh +++ b/LDP/guide/docbook/abs-guide/ex9.sh @@ -20,7 +20,7 @@ hello=$a echo hello # Not a variable reference, just the string "hello". echo $hello -echo ${hello} #Identical to above. +echo ${hello} # Identical to above. echo "$hello" echo "${hello}" @@ -28,14 +28,14 @@ echo "${hello}" echo hello="A B C D" -echo $hello -echo "$hello" -# Now, echo $hello and echo "$hello" give different results. +echo $hello # A B C D +echo "$hello" # A B C D +# As you see, echo $hello and echo "$hello" give different results. # Quoting a variable preserves whitespace. echo -echo '$hello' +echo '$hello' # $hello # Variable referencing disabled by single quotes, #+ which causes the "$" to be interpreted literally. @@ -67,7 +67,7 @@ numbers="one two three" other_numbers="1 2 3" # If whitespace within a variable, then quotes necessary. echo "numbers = $numbers" -echo "other_numbers = $other_numbers" +echo "other_numbers = $other_numbers" # other_numbers = 1 2 3 echo echo "uninitialized_variable = $uninitialized_variable" diff --git a/LDP/guide/docbook/abs-guide/findstring.sh b/LDP/guide/docbook/abs-guide/findstring.sh index b52bd701..82b6d949 100644 --- a/LDP/guide/docbook/abs-guide/findstring.sh +++ b/LDP/guide/docbook/abs-guide/findstring.sh @@ -1,5 +1,6 @@ #!/bin/bash -# findstring.sh: Find a particular string in binaries in a specified directory. +# findstring.sh: +# Find a particular string in binaries in a specified directory. directory=/usr/bin/ fstring="Free Software Foundation" # See which files come from the FSF. @@ -7,12 +8,15 @@ fstring="Free Software Foundation" # See which files come from the FSF. for file in $( find $directory -type f -name '*' | sort ) do strings -f $file | grep "$fstring" | sed -e "s%$directory%%" - # In the "sed" expression, it is necessary to substitute for the normal "/" delimiter - # because "/" happens to be one of the characters filtered out. - # Failure to do so gives an error message (try it). + # In the "sed" expression, + #+ it is necessary to substitute for the normal "/" delimiter + #+ because "/" happens to be one of the characters filtered out. + # Failure to do so gives an error message (try it). done exit 0 -# Exercise for the reader (easy): -# Convert this script to taking command-line parameters for $directory and $fstring. +# Exercise (easy): +# --------------- +# Convert this script to taking command-line parameters +#+ for $directory and $fstring. diff --git a/LDP/guide/docbook/abs-guide/ftpget.sh b/LDP/guide/docbook/abs-guide/ftpget.sh index c81b664f..81630197 100644 --- a/LDP/guide/docbook/abs-guide/ftpget.sh +++ b/LDP/guide/docbook/abs-guide/ftpget.sh @@ -96,6 +96,7 @@ rm -f ${TMPFILE} # ==> Finally, tempfile deleted (you may wish to copy it to a logfile). -# ==> Exercises for reader: +# ==> Exercises: +# ==> --------- # ==> 1) Add error checking. # ==> 2) Add bells & whistles. diff --git a/LDP/guide/docbook/abs-guide/grp.sh b/LDP/guide/docbook/abs-guide/grp.sh index 3b6d8dac..0031f0ee 100644 --- a/LDP/guide/docbook/abs-guide/grp.sh +++ b/LDP/guide/docbook/abs-guide/grp.sh @@ -28,7 +28,7 @@ echo exit 0 -# Exercises for reader: -# -------------------- +# Exercises: +# --------- # 1) Add newlines to output, if more than one match in any given file. # 2) Add features. diff --git a/LDP/guide/docbook/abs-guide/m4.sh b/LDP/guide/docbook/abs-guide/m4.sh index e4ebb5af..f7f1cb9d 100644 --- a/LDP/guide/docbook/abs-guide/m4.sh +++ b/LDP/guide/docbook/abs-guide/m4.sh @@ -3,12 +3,12 @@ # Strings string=abcdA01 -echo "len($string)" | m4 # 7 -echo "substr($string,4)" | m4 # A01 +echo "len($string)" | m4 # 7 +echo "substr($string,4)" | m4 # A01 echo "regexp($string,[0-1][0-1],\&Z)" | m4 # 01Z # Arithmetic -echo "incr(22)" | m4 # 23 -echo "eval(99 / 3)" | m4 # 33 +echo "incr(22)" | m4 # 23 +echo "eval(99 / 3)" | m4 # 33 exit 0 diff --git a/LDP/guide/docbook/abs-guide/mail-format.sh b/LDP/guide/docbook/abs-guide/mail-format.sh index b320d9c9..1e9c0189 100644 --- a/LDP/guide/docbook/abs-guide/mail-format.sh +++ b/LDP/guide/docbook/abs-guide/mail-format.sh @@ -3,6 +3,8 @@ # Gets rid of carets, tabs, also fold excessively long lines. +# ================================================================= +# Standard Check for Script Argument(s) ARGS=1 E_BADARGS=65 E_NOFILE=66 @@ -20,9 +22,12 @@ else echo "File \"$1\" does not exist." exit $E_NOFILE fi +# ================================================================= MAXWIDTH=70 # Width to fold long lines to. +# Delete carets and tabs at beginning of lines, +#+ then fold lines to $MAXWIDTH characters. sed ' s/^>// s/^ *>// @@ -31,7 +36,10 @@ s/ *// ' $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 Windows utility with similar functionality. +# This script was inspired by an article in a well-known trade journal +#+ extolling a 164K Windows utility with similar functionality. +# +# An nice set of text processing utilities and an efficient +#+ scripting language makes unnecessary bloated executables. exit 0 diff --git a/LDP/guide/docbook/abs-guide/max.sh b/LDP/guide/docbook/abs-guide/max.sh index d3b85770..6a0f1940 100644 --- a/LDP/guide/docbook/abs-guide/max.sh +++ b/LDP/guide/docbook/abs-guide/max.sh @@ -40,6 +40,7 @@ fi exit 0 -# Exercise for the reader (easy): -# Convert this to an interactive script, -# that is, have the script ask for input (two numbers). +# Exercise (easy): +# --------------- +# Convert this to an interactive script, +#+ that is, have the script ask for input (two numbers). diff --git a/LDP/guide/docbook/abs-guide/numbers.sh b/LDP/guide/docbook/abs-guide/numbers.sh index 64db4562..ae1f625f 100644 --- a/LDP/guide/docbook/abs-guide/numbers.sh +++ b/LDP/guide/docbook/abs-guide/numbers.sh @@ -2,35 +2,49 @@ # numbers.sh: Representation of numbers. # Decimal -let "d = 32" -echo "d = $d" +let "dec = 32" +echo "decimal number = $dec" # 32 # Nothing out of the ordinary here. # Octal: numbers preceded by '0' (zero) -let "o = 071" -echo "o = $o" +let "oct = 071" +echo "octal number = $oct" # 57 # Expresses result in decimal. # Hexadecimal: numbers preceded by '0x' or '0X' -let "h = 0x7a" -echo "h = $h" +let "hex = 0x7a" +echo "hexadecimal number = $hex" # 122 # Expresses result in decimal. # Other bases: BASE#NUMBER -# BASE between 2 and 36. -let "b = 32#77" -echo "b = $b" +# BASE between 2 and 64. + +let "bin = 2#111100111001101" +echo "binary number = $bin" # 31181 + +let "b32 = 32#77" +echo "base-32 number = $b32" # 231 + +let "b64 = 64#@_" +echo "base-64 number = $b64" # 4094 # -# This notation only works for a limited range (2 - 36) - # ... 10 digits + 26 alpha characters = 36. -let "c = 2#47" # Out of range error: -# numbers.sh: let: c = 2#47: value too great for base (error token is "2#47") -echo "c = $c" +# This notation only works for a limited range (2 - 64) +# 10 digits + 26 lowercase characters + 26 uppercase characters + @ + _ echo -echo $((36#zz)) $((2#10101010)) $((16#AF16)) +echo $((36#zz)) $((2#10101010)) $((16#AF16)) $((53#1aA)) + # 1295 170 44822 3375 + + +# Important note: +# Using a digit out of range of the specified base notation +#+ will give an error message. + +let "bad_oct = 081" +# numbers.sh: let: oct = 081: value too great for base (error token is "081") +# Octal numbers use only digits in the range of 0 - 7. exit 0 -# Thanks, S.C., for clarification. +# Thanks, Rich Bartell and Stephane Chazelas, for clarification. diff --git a/LDP/guide/docbook/abs-guide/online.sh b/LDP/guide/docbook/abs-guide/online.sh index 20f54c10..3c9e4943 100644 --- a/LDP/guide/docbook/abs-guide/online.sh +++ b/LDP/guide/docbook/abs-guide/online.sh @@ -73,5 +73,5 @@ do echo -n . done echo "On-line" -# Exercise: Consider the strengths and weaknesses -# of each of these approaches. +# Exercise: Discuss the strengths and weaknesses +# of each of these various approaches. diff --git a/LDP/guide/docbook/abs-guide/primes.sh b/LDP/guide/docbook/abs-guide/primes.sh index acc044eb..d6f4e0b0 100644 --- a/LDP/guide/docbook/abs-guide/primes.sh +++ b/LDP/guide/docbook/abs-guide/primes.sh @@ -1,11 +1,10 @@ #!/bin/bash # primes.sh: Generate prime numbers, without using arrays. +# Script contributed by Stephane Chazelas. # This does *not* use the classic "Sieve of Erastosthenes" algorithm, #+ but instead uses the more intuitive method of testing each candidate number #+ for factors (divisors), using the "%" modulo operator. -# -# Script contributed by Stephane Chazelas, LIMIT=1000 # Primes 2 - 1000 @@ -31,7 +30,7 @@ Primes() Primes $n $@ $n # Recursion outside loop. # Successively accumulate positional parameters. - # "$@" is the accumulating list of primes. + # "$@" is the accumulating list of primes. } Primes 1 diff --git a/LDP/guide/docbook/abs-guide/q-function.sh b/LDP/guide/docbook/abs-guide/q-function.sh index 148e6dff..49910394 100644 --- a/LDP/guide/docbook/abs-guide/q-function.sh +++ b/LDP/guide/docbook/abs-guide/q-function.sh @@ -53,6 +53,5 @@ echo exit 0 # This is an iterative implementation of the Q-series. -# The more intuitive recursive implementation -# is left as an exercise for the reader. +# The more intuitive recursive implementation is left as an exercise. # Warning: calculating this series recursively takes a *very* long time. diff --git a/LDP/guide/docbook/abs-guide/random-test.sh b/LDP/guide/docbook/abs-guide/random-test.sh index 796f0f35..c2d91bcb 100644 --- a/LDP/guide/docbook/abs-guide/random-test.sh +++ b/LDP/guide/docbook/abs-guide/random-test.sh @@ -57,7 +57,8 @@ print_result # Keep in mind that RANDOM is a pseudorandom generator, # and not a spectacularly good one at that. -# Exercise for the reader (easy): +# Exercise (easy): +# --------------- # Rewrite this script to flip a coin 1000 times. # Choices are "HEADS" or "TAILS". diff --git a/LDP/guide/docbook/abs-guide/random2.sh b/LDP/guide/docbook/abs-guide/random2.sh index 5b116990..b8bc2c16 100644 --- a/LDP/guide/docbook/abs-guide/random2.sh +++ b/LDP/guide/docbook/abs-guide/random2.sh @@ -12,14 +12,14 @@ echo | awk "$AWKSCRIPT" exit 0 -# Exercises for the reader: -# ------------------------- +# Exercises: +# --------- -# 1] Using a loop construct, print out 10 different random numbers. +# 1) Using a loop construct, print out 10 different random numbers. # (Hint: you must reseed the "srand()" function with a different seed # in each pass through the loop. What happens if you fail to do this?) -# 2] Using an integer multiplier as a scaling factor, generate random numbers +# 2) Using an integer multiplier as a scaling factor, generate random numbers # in the range between 10 and 100. -# 3] Same as exercise #2, above, but generate random integers this time. +# 3) Same as exercise #2, above, but generate random integers this time. diff --git a/LDP/guide/docbook/abs-guide/recurse.sh b/LDP/guide/docbook/abs-guide/recurse.sh index 56ef0848..95f184c7 100644 --- a/LDP/guide/docbook/abs-guide/recurse.sh +++ b/LDP/guide/docbook/abs-guide/recurse.sh @@ -19,6 +19,6 @@ fi # Each child script does the same, until #+ a generated $i equals $MAXVAL. # Using a "while" loop instead of an "if/then" test causes problems. -# Exercise for the reader: Explain why. +# Explain why. exit 0 diff --git a/LDP/guide/docbook/abs-guide/redir1.sh b/LDP/guide/docbook/abs-guide/redir1.sh index 38710e2e..2c1219e7 100644 --- a/LDP/guide/docbook/abs-guide/redir1.sh +++ b/LDP/guide/docbook/abs-guide/redir1.sh @@ -18,8 +18,9 @@ echo $a2 echo; echo; echo exec 0<&6 6<&- -# Now restore stdin from fd #6, where it had been saved, -# and close fd #6 ( 6<&- ) to free it for other processes to use. +# Now restore stdin from fd #6, where it had been saved, +#+ and close fd #6 ( 6<&- ) to free it for other processes to use. +# # <&6 6<&- also works. echo -n "Enter data " diff --git a/LDP/guide/docbook/abs-guide/redir2.sh b/LDP/guide/docbook/abs-guide/redir2.sh index f34e708f..b8299773 100644 --- a/LDP/guide/docbook/abs-guide/redir2.sh +++ b/LDP/guide/docbook/abs-guide/redir2.sh @@ -2,12 +2,12 @@ if [ -z "$1" ] then - Filename=names.data # Default, if no filename specified. + Filename=names.data # Default, if no filename specified. else Filename=$1 fi -# Filename=${1:-names.data} -# can replace the above test (parameter substitution). +#+ Filename=${1:-names.data} +# can replace the above test (parameter substitution). count=0 @@ -23,11 +23,12 @@ done <"$Filename" # Redirects stdin to file $Filename. echo; echo "$count names read"; echo -# Note that in some older shell scripting languages, -# the redirected loop would run as a subshell. +# Note that in some older shell scripting languages, +#+ the redirected loop would run as a subshell. # Therefore, $count would return 0, the initialized value outside the loop. -# Bash and ksh avoid starting a subshell whenever possible, -# so that this script, for example, runs correctly. +# Bash and ksh avoid starting a subshell whenever possible, +# +so that this script, for example, runs correctly. +# # Thanks to Heiner Steven for pointing this out. exit 0 diff --git a/LDP/guide/docbook/abs-guide/redir2a.sh b/LDP/guide/docbook/abs-guide/redir2a.sh index f4b7b15c..60ad38ae 100644 --- a/LDP/guide/docbook/abs-guide/redir2a.sh +++ b/LDP/guide/docbook/abs-guide/redir2a.sh @@ -2,10 +2,10 @@ # This is an alternate form of the preceding script. -# Suggested by Heiner Steven -# as a workaround in those situations when a redirect loop -# runs as a subshell, and therefore variables inside the loop -# do not keep their values upon loop termination. +# Suggested by Heiner Steven +#+ as a workaround in those situations when a redirect loop +#+ runs as a subshell, and therefore variables inside the loop +# +do not keep their values upon loop termination. if [ -z "$1" ] diff --git a/LDP/guide/docbook/abs-guide/redir4.sh b/LDP/guide/docbook/abs-guide/redir4.sh index 62eb7a1d..05e713db 100644 --- a/LDP/guide/docbook/abs-guide/redir4.sh +++ b/LDP/guide/docbook/abs-guide/redir4.sh @@ -7,10 +7,12 @@ else Filename=$1 fi -line_count=`wc $Filename | awk '{ print $1 }'` # Number of lines in target file. -# Very contrived and kludgy, nevertheless shows that -# it's possible to redirect stdin within a "for" loop... -# if you're clever enough. +line_count=`wc $Filename | awk '{ print $1 }'` +# Number of lines in target file. +# +# Very contrived and kludgy, nevertheless shows that +#+ it's possible to redirect stdin within a "for" loop... +#+ if you're clever enough. # # More concise is line_count=$(wc < "$Filename") diff --git a/LDP/guide/docbook/abs-guide/rfe.sh b/LDP/guide/docbook/abs-guide/rfe.sh index 89ee1b9d..8f48d61c 100644 --- a/LDP/guide/docbook/abs-guide/rfe.sh +++ b/LDP/guide/docbook/abs-guide/rfe.sh @@ -14,7 +14,7 @@ ARGS=2 E_BADARGS=65 -if [ $# -ne $ARGS ] +if [ $# -ne "$ARGS" ] then echo "Usage: `basename $0` old_file_suffix new_file_suffix" exit $E_BADARGS @@ -24,8 +24,8 @@ for filename in *.$1 # Traverse list of files ending with 1st argument. do mv $filename ${filename%$1}$2 - # Strip off part of filename matching 1st argument, - # then append 2nd argument. + # Strip off part of filename matching 1st argument, + #+ then append 2nd argument. done exit 0 diff --git a/LDP/guide/docbook/abs-guide/rn.sh b/LDP/guide/docbook/abs-guide/rn.sh index 9cb6b33b..0aab3127 100644 --- a/LDP/guide/docbook/abs-guide/rn.sh +++ b/LDP/guide/docbook/abs-guide/rn.sh @@ -2,8 +2,8 @@ # # Very simpleminded filename "rename" utility (based on "lowercase.sh"). # -# The "ren" utility, by Vladimir Lanin (lanin@csd2.nyu.edu), -# does a much better job of this. +# The "ren" utility, by Vladimir Lanin (lanin@csd2.nyu.edu), +#+ does a much better job of this. ARGS=2 @@ -41,6 +41,7 @@ fi exit 0 -# Exercise for reader: +# Exercise: +# -------- # What type of files will this not work on? -# How to fix this? +# How can this be fixed? diff --git a/LDP/guide/docbook/abs-guide/seeding-random.sh b/LDP/guide/docbook/abs-guide/seeding-random.sh index fcaa8697..d864b0b6 100644 --- a/LDP/guide/docbook/abs-guide/seeding-random.sh +++ b/LDP/guide/docbook/abs-guide/seeding-random.sh @@ -23,22 +23,25 @@ echo; echo RANDOM=1 # Same seed for RANDOM... random_numbers # ...reproduces the exact same number series. + # + # When is it useful to duplicate a "random" number series? echo; echo -RANDOM=2 # Trying again, but with a different seen... +RANDOM=2 # Trying again, but with a different seed... random_numbers # gives a different number series. echo; echo # RANDOM=$$ seeds RANDOM from process id of script. -# It is also possible to seed RANDOM from 'time' or 'date'. +# It is also possible to seed RANDOM from 'time' or 'date' commands. # Getting fancy... SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }') -# Pseudo-random output fetched from /dev/urandom (system pseudo-random "device"), -# then converted to line of printable (octal) numbers by "od", -# finally "awk" retrieves just one number for SEED. +# Pseudo-random output fetched +#+ from /dev/urandom (system pseudo-random device-file), +#+ then converted to line of printable (octal) numbers by "od", +#+ finally "awk" retrieves just one number for SEED. RANDOM=$SEED random_numbers diff --git a/LDP/guide/docbook/abs-guide/string.sh b/LDP/guide/docbook/abs-guide/string.sh index e8ff206e..c461f608 100644 --- a/LDP/guide/docbook/abs-guide/string.sh +++ b/LDP/guide/docbook/abs-guide/string.sh @@ -263,7 +263,8 @@ echo -# Exercise for reader: +# Exercise: +# -------- # Add code to test all the other string functions above. diff --git a/LDP/guide/docbook/abs-guide/strip-comments.sh b/LDP/guide/docbook/abs-guide/strip-comments.sh index 2b47f5ce..7d729479 100644 --- a/LDP/guide/docbook/abs-guide/strip-comments.sh +++ b/LDP/guide/docbook/abs-guide/strip-comments.sh @@ -37,9 +37,9 @@ sed ' # Easy to understand if you take several hours to learn sed fundamentals. -# Need to add one more line to the sed script to deal with -# case where line of code has a comment following it on same line. -# This is left as a non-trivial exercise for the reader. +# Need to add one more line to the sed script to deal with +#+ case where line of code has a comment following it on same line. +# This is left as a non-trivial exercise. # Also, the above code deletes lines with a "*/" or "/*", # not a desirable result. diff --git a/LDP/guide/docbook/abs-guide/timed-input.sh b/LDP/guide/docbook/abs-guide/timed-input.sh index 29cfe669..2ff4ff22 100644 --- a/LDP/guide/docbook/abs-guide/timed-input.sh +++ b/LDP/guide/docbook/abs-guide/timed-input.sh @@ -41,12 +41,12 @@ read answer PrintAnswer -# Admittedly, this is a kludgy implementation of timed input, -# but pretty much as good as can be done with Bash. -# (Challenge to reader: come up with something better.) +# Admittedly, this is a kludgy implementation of timed input, +#+ however the "-t" option to "read" simplifies this task. +# See "t-out.sh", below. -# If you need something a bit more elegant... -# consider writing the application in C or C++, -# using appropriate library functions, such as 'alarm' and 'setitimer'. +# If you need something really elegant... +#+ consider writing the application in C or C++, +#+ using appropriate library functions, such as 'alarm' and 'setitimer'. exit 0 diff --git a/LDP/guide/docbook/abs-guide/tree.sh b/LDP/guide/docbook/abs-guide/tree.sh index acffc639..83e93e57 100644 --- a/LDP/guide/docbook/abs-guide/tree.sh +++ b/LDP/guide/docbook/abs-guide/tree.sh @@ -71,4 +71,4 @@ done echo "Total directories = $numdirs" exit 0 -# ==> Challenge to reader: try to figure out exactly how this script works. +# ==> Challenge: try to figure out exactly how this script works. diff --git a/LDP/guide/docbook/abs-guide/twodim.sh b/LDP/guide/docbook/abs-guide/twodim.sh index 8642e21d..78e28474 100644 --- a/LDP/guide/docbook/abs-guide/twodim.sh +++ b/LDP/guide/docbook/abs-guide/twodim.sh @@ -119,12 +119,12 @@ rotate # Rotate it 45 degrees counterclockwise. # This is a rather contrived, not to mention kludgy simulation. # -# Exercise #1 for the reader: -# Rewrite the array loading and printing functions -# in a more intuitive and elegant fashion. +# Exercises: +# --------- +# 1) Rewrite the array loading and printing functions +# + in a more intuitive and elegant fashion. # -# Exercise #2: -# Figure out how the array rotation functions work. -# Hint: think about the implications of backwards-indexing an array. +# 2) Figure out how the array rotation functions work. +# Hint: think about the implications of backwards-indexing an array. exit 0 diff --git a/LDP/guide/docbook/abs-guide/wf.sh b/LDP/guide/docbook/abs-guide/wf.sh index de3fdc16..f284c354 100644 --- a/LDP/guide/docbook/abs-guide/wf.sh +++ b/LDP/guide/docbook/abs-guide/wf.sh @@ -7,16 +7,14 @@ ARGS=1 E_BADARGS=65 E_NOFILE=66 -if [ $# -ne $ARGS ] # Correct number of arguments passed to script? +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. +if [ ! -f "$1" ] # Check if file exists. then - file_name=$1 -else echo "File \"$1\" does not exist." exit $E_NOFILE fi @@ -24,7 +22,7 @@ fi ######################################################## -# main +# main () sed -e 's/\.//g' -e 's/ /\ /g' "$1" | tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr # ========================= @@ -36,7 +34,8 @@ sed -e 's/\.//g' -e 's/ /\ #+ finally prefix occurrence count and sort numerically. ######################################################## -# Exercises for the reader: +# Exercises: +# --------- # 1) Add 'sed' commands to filter out other punctuation, such as commas. # 2) Modify to also filter out multiple spaces and other whitespace. # 3) Add a secondary sort key, so that instances of equal occurrence