diff --git a/LDP/guide/docbook/abs-guide/Change.log b/LDP/guide/docbook/abs-guide/Change.log index 111fd93d..90a5aa1b 100644 --- a/LDP/guide/docbook/abs-guide/Change.log +++ b/LDP/guide/docbook/abs-guide/Change.log @@ -7,16 +7,150 @@ ================================================================== - Current version = 5.3 - http://personal.riverusers.com/~thegrendel/abs-guide-5.3.tar.bz2 + Current version = 5.4 + http://personal.riverusers.com/~thegrendel/abs-guide-5.4.tar.bz2 http://personal.riverusers.com/~thegrendel/abs-guide.pdf -------------------------------------------------------------------- - News: "Petals Around the Rose" (petals.sh) example script added. - "Crossword Puzzle Solver" (cw-solver.sh) example script added. - "Perquackey" type game (qky.sh) example script added. + News: "music.sh" example script added. + "nim.sh" example script added. + "UseGetOpt.sh" script added. ==================================================================== +Version 5.4, Angleberry release +05/21/08 + +1) In "Tests" chapter: + In "Test Constructs" section: + Rewrote "arithmetic expansion" discussion and in-line example. + Removed "if-echo" construct example (too confusing). + In "File test Operators" section: + At "-b" entry, added short usage example. + Added a few lines to "arith-tests.sh" example. + In "Test Comparison Operators" section: + At "-z" entry, added short in-line example. + +2) In "Introduction to Variables and Parameters" chapter: + In "Variable Substitution" section, + Added in-line example to "warning" about unassigned variables. + Minor cleanups to introductory text. + In "Special Variable Types" section, + at discussion of "du" overflow, noted that this has been + fixed as of kernel 2.6.23. (Thank you, Mauro Giachero, + for pointing this out.) + +3) In "Loops and Branches" chapter: + Added in-line example of a function providing the [list] + for a "for" loop, using command substitution. + At "until" loops section, expanded "ex27.sh" example script. + +4) In "Functions" chapter: + Added comment to the effect that a function call is equivalent to a + command. + +5) In "Internal Commands and Builtins" chapter: + At footnote to "getopts" entry, fixed typo. + At "let" entry, added to "ex46.sh" example to include C-style + increment, decrement, and trinary operators. + +6) In "External Commands" chapter: + In "Text Processing" section: + At "recode" entry, fixed typo (removed extraneous ">"). + In "Math Commands" section: + At "factor" entry, added "primes2.sh" example script. + In "Time/Date Commands" section: + At "sleep" entry, fixed typo in usage example. + At "date" entry, fixup: + delete "generate six-digit random integers" && + add explanation in + In "File and Archiving Commands" section: + At "more/less" entry, added paragraph (with link) explaining that + "less" displays man page source. + At "diff3" entry, added listing for "merge." + In "Miscellaneous Commands" section: + At "tee" entry, fixed typo (siponing -> siphoning). + At "m4" entry, clarified footnote definition of "macro." + At "getopt" entry, added Peggy Russell's note about the necessity + of "eval." + At "yes" entry, + Added a use (of sorts) for parsed-variable + echoing capability. + Cleared up ambiguity about "yes" parsing variables (it doesn't). + Added simple emulation of "yes" in a script function. + In "Communications Commands" section: + Added "mailstats" command. + In "Terminal Commands" section: + Added "resize" entry. + At "tput" entry, added listing of some interesting options. + +7) In "Arrays" chapter: + Fixed error and typos in "array-strops.sh" example. + Added comment line to "ex67.sh" example about ${Array[$element]}. + (Thank you Juan Bellon, for the the heads-up on the above!) + Revisions and fixups to "empty-array.sh" example script + (Thank you, Nathan Coulter!) + +8) In "Variables Revisited" chapter: + In "Manipulating Strings" section: + Minor rewrites to clarify meaning ("strip" --> "delete" ... etc.) + In "Indirect References" section: + Complete rewrite of introduction for additional clarity. + Added material to "ind-ref.sh" example. + In "Typing Variables" section: + Added short in-line example to footnote. + +9) In the "Shell Wrappers" section of "Miscellany" chapter: + Fixed a typo in "ex3.sh" example ("This match lines ..." --> + "This matches lines ..."). + Added mention of Martin Matusiak's "undvd" shell wrapper script. + Added mention of Itzchak Rehberg's "Ext3Undel" package. + +10) In "Escaping" section of "Quoting" Chapter: + Minor fixups and clarifications. + +11) In "/dev" section of "/dev and /proc" chapter: + Added "music.sh" example script (plays music!). Thanks, Antonio Macchi!) + Added links / short explanations to pseudo-device listing. + +12) Slight stylistic revisions to "Credits" section "Endnotes" Chapter. + +13) In "Debugging" chapter: + Added explanations and references to listing of internal variables + new to version 3 of Bash. + +14) In "Restricted Shells" chapter: + Cleaned up markup tags (changed to ). + +15) In "Assorted Tips" section of "Miscellany" chapter: + Added "progress-bar.sh" example script. (Thanks, Dotan Barak!) + At "rcs" entry, correction: added space to "# $Id" in 2 places. + +16) In "Special Characters" chapter: + At "whitespace" entry, added link to "[:space:]" POSIX character + class. + +17) In "Contributed Scripts" appendix: + Added "maned.sh" -- man page editor example script. + Added "sd.sh" -- Standard Deviation example script. + Added "nim.sh" -- game of Nim example script. + Added Peggy Russell's "UseGetOpt.sh" example script (thanks!). + Slight fixup to "tohtml.sh" (more accurate conversion). + +18) In "Writing Scripts" section of "Exercises" appendix: + Added "Craps" exercise. + Added "Tic-tac-toe" exercise. + Added "Banner" exercise. + Added "Table of Logarithms" exercise. + +19) In "Bibliography" section: + Added entry+link to John Lion's _Commentary_ + (still da bestest UNIX reference). + +20) Cleanups/fixups to main text, appendices, and script examples where + appropriate . . . especially to older scripts. + + + Version 5.3, Goldenberry release 05/11/08 diff --git a/LDP/guide/docbook/abs-guide/INDEX00.sgml b/LDP/guide/docbook/abs-guide/INDEX00.sgml index fbc5cc1c..04e8a17e 100644 --- a/LDP/guide/docbook/abs-guide/INDEX00.sgml +++ b/LDP/guide/docbook/abs-guide/INDEX00.sgml @@ -446,6 +446,14 @@ new notation + + ${!#} + Final positional + parameter. + (This is an indirect reference to + $#.) + + ${!varprefix*} ${!varprefix@} @@ -688,6 +696,9 @@ -a Logical AND compound comparison test + Address database, script + example + Advanced Bash Scripting Guide, where to download @@ -707,6 +718,9 @@ argument + And logical + operator && + Angle brackets, escaped, \< . . . \> @@ -800,12 +814,13 @@ As return value from a function - Special properties, - example script - String operations, - example script + + Special properties, + example + script + String operations, + example + script unset deletes array elements @@ -1032,6 +1047,8 @@ + Communications and + hosts Compound comparison operators @@ -1210,8 +1227,10 @@ external echo command - elif, Contraction - of else and if + elif, + Contraction of else + and if + else esac, keyword terminating case construct Environmental @@ -1235,6 +1254,8 @@ Forces reevaluation of arguments + And indirect + references Risk of using @@ -1268,6 +1289,9 @@ Successful, 0 + /usr/include/sysexits.h, + system file listing C/C++ standard exit codes @@ -1316,9 +1340,19 @@ * * * + factor, decomposes an + integer into its prime factors + + Application: Generating + prime numbers + + false, returns unsuccessful (1) exit status + + Files / Archiving + File descriptors Closing @@ -1402,11 +1436,11 @@ return - + Multiple return values from a function, + example script Returning an array from a function - return range limits, workarounds @@ -1418,6 +1452,36 @@ * * * + Games and amusements + + Anagrams + Anagrams, again + Crossword puzzle + solver + Crypto-Quotes + Horse race + Life + game + Music-playing + script + Nim + Pachinko + Perquackey + Petals Around the Rose + Podcasting + Poem + Towers of Hanoi + + getopt, external command for parsing script command-line arguments @@ -1443,6 +1507,8 @@ -gt , greater-than integer comparison test + groff, + text markup and formatting language $GROUPS, Groups user belongs to gzip, compression utility @@ -1538,6 +1604,10 @@ * * * + $Id + parameter, in rcs (Revision Control + System) + if [ condition ]; then ... test construct @@ -1577,9 +1647,8 @@ Indirect referencing of variables New notation, introduced - in version 2 of Bash - - Example script + in version 2 of Bash ( example script) @@ -1620,8 +1689,15 @@ -le , less-than or equal integer comparison test + let, - setting and carrying out arithmetic operations on variables + setting and carrying out arithmetic operations on variables + + C-style + increment and decrement + operators + + Limit string, in a here document $LINENO, @@ -1775,7 +1851,9 @@ Makefile, file containing the list of dependencies used by make command - meta-meaning + Man page editor (script) + Math commands + Meta-meaning Modulo, arithmetic remainder operator @@ -1813,6 +1891,8 @@ Noclobber, option to Bash to prevent overwriting of files + NOT logical + operator, ! null variable assignment, avoiding @@ -1839,8 +1919,8 @@ linkend="setref">set command Or list - Or logical operator, - || + Or logical + operator, || * * * @@ -2101,7 +2181,11 @@ Prime numbers Generating primes - without using arrays + using the factor + command + Generating primes + using the modulo + operator Sieve of Eratosthenes @@ -2553,8 +2637,9 @@ Special characters Stack, emulating a push-down, Example + linkend="stackex0">example script + Standard Deviation, example script Startup files, Bash stdin @@ -2599,6 +2684,11 @@ linkend="strlen">equivalent of + + strings command, + find printable strings in a binary or data file + + Substring extraction ${string:position} @@ -2689,6 +2779,8 @@ * * * + Table lookup, script + example tail, echo to stdout lines at the (tail) end of a text file @@ -2697,13 +2789,14 @@ output of command(s) partway through a pipe - Terminals + Terminals setserial setterm stty + tput wall @@ -2813,6 +2906,12 @@ + + + Text and text file + processing + Time / Date + Timed input @@ -2879,14 +2978,16 @@ Prepending lines at head of a file + Progress + bar template Pseudo-code - Script as embedded - command rcs Running scripts in sequence without user intervention, using run-parts + Script as embedded + command Script portability $TMOUT, - Timeout interval + Timeout interval + tput, terminal-control + command tr, character translation filter @@ -2934,8 +3037,18 @@ Trap, specifying an action upon receipt of a signal - Trinary operator, - C-style + + Trinary operator, + C-style, + var>10?88:99 + + in + double-parentheses + construct + in let + construct + + true, returns successful (0) exit status @@ -3077,6 +3190,15 @@ while loop while [ condition ]; do + C-style syntax + + Calling a + function within + test brackets + Multiple + conditions + Omitting + test brackets while read construct @@ -3094,10 +3216,12 @@ document, error Preceding script comments - Quoting, - to preserve whitespace within strings - or variables + Quoting, + to preserve whitespace within strings + or variables + [:space:], + POSIX character class who, information about logged on users @@ -3129,7 +3253,11 @@ * * * - yes + yes + + Emulation + * * * diff --git a/LDP/guide/docbook/abs-guide/README b/LDP/guide/docbook/abs-guide/README index 7e4b52b9..36436037 100644 --- a/LDP/guide/docbook/abs-guide/README +++ b/LDP/guide/docbook/abs-guide/README @@ -93,12 +93,24 @@ tree2.sh: line 88 petals.sh - line 54 + line 56 + +realname.sh + line 26 qky.sh line 7 line 63 line 87 line 113 -(The unaltered, executable script can be downloaded from - http://personal.riverusers.com/~thegrendel/qky.sh) +(The unaltered, executable script can be downloaded. See: + http://personal.riverusers.com/~thegrendel/qky.README.html) + +maned.sh + line 6 (comment) + +progress-bar.sh + line 26 + line 30 +nim.sh + line 27 diff --git a/LDP/guide/docbook/abs-guide/UseGetOpt.sh b/LDP/guide/docbook/abs-guide/UseGetOpt.sh new file mode 100644 index 00000000..1d7922b8 --- /dev/null +++ b/LDP/guide/docbook/abs-guide/UseGetOpt.sh @@ -0,0 +1,123 @@ +#!/bin/bash +# UseGetOpt.sh + +# Author: Peggy Russell <prusselltechgroup@gmail.com> + +UseGetOpt () { + declare inputOptions + declare -r E_OPTERR=85 + declare -r ScriptName=${0##*/} + declare -r ShortOpts="adf:hlt" + declare -r LongOpts="aoption,debug,file:,help,log,test" + +DoSomething () { + echo "The function name is '${FUNCNAME}'" + # Recall that $FUNCNAME is an internal variable + #+ holding the name of the function it is in. + } + + inputOptions=$(getopt -o "${ShortOpts}" --long \ + "${LongOpts}" --name "${ScriptName}" -- "${@}") + + if [[ ($? -ne 0) || ($# -eq 0) ]]; then + echo "Usage: ${ScriptName} [-dhlt] {OPTION...}" + exit $E_OPTERR + fi + + eval set -- "${inputOptions}" + + # Only for educational purposes. Can be removed. + #----------------------------------------------- + echo "++ Test: Number of arguments: [$#]" + echo '++ Test: Looping through "$@"' + for a in "$@"; do + echo " ++ [$a]" + done + #----------------------------------------------- + + while true; do + case "${1}" in + --aoption | -a) # Argument found. + echo "Option [$1]" + ;; + + --debug | -d) # Enable informational messages. + echo "Option [$1] Debugging enabled" + ;; + + --file | -f) # Check for optional argument. + case "$2" in #+ Double colon is optional argument. + "") # Not there. + echo "Option [$1] Use default" + shift + ;; + + *) # Got it + echo "Option [$1] Using input [$2]" + shift + ;; + + esac + DoSomething + ;; + + --log | -l) # Enable Logging. + echo "Option [$1] Logging enabled" + ;; + + --test | -t) # Enable testing. + echo "Option [$1] Testing enabled" + ;; + + --help | -h) + echo "Option [$1] Display help" + break + ;; + + --) # Done! $# is argument number for "--", $@ is "--" + echo "Option [$1] Dash Dash" + break + ;; + + *) + echo "Major internal error!" + exit 8 + ;; + + esac + echo "Number of arguments: [$#]" + shift + done + + shift + # Only for educational purposes. Can be removed. + #---------------------------------------------------------------------- + echo "++ Test: Number of arguments after \"--\" is [$#] They are: [$@]" + echo '++ Test: Looping through "$@"' + for a in "$@"; do + echo " ++ [$a]" + done + #---------------------------------------------------------------------- + +} + +################################### M A I N ######################## +# If you remove "function UseGetOpt () {" and corresponding "}", +#+ you can uncomment the "exit 0" line below, and invoke this script +#+ with the various options from the command line. +#------------------------------------------------------------------- +# exit 0 + +echo "Test 1" +UseGetOpt -f myfile one "two three" four + +echo;echo "Test 2" +UseGetOpt -h + +echo;echo "Test 3 - Short Options" +UseGetOpt -adltf myfile anotherfile + +echo;echo "Test 4 - Long Options" +UseGetOpt --aoption --debug --log --test --file myfile anotherfile + +exit diff --git a/LDP/guide/docbook/abs-guide/abs-guide.sgml b/LDP/guide/docbook/abs-guide/abs-guide.sgml index 91927f75..cecff0fe 100644 --- a/LDP/guide/docbook/abs-guide/abs-guide.sgml +++ b/LDP/guide/docbook/abs-guide/abs-guide.sgml @@ -188,6 +188,7 @@ + @@ -298,6 +299,7 @@ + @@ -326,6 +328,7 @@ + @@ -342,6 +345,7 @@ + @@ -351,6 +355,9 @@ + + + @@ -372,19 +379,12 @@ - 5.3 - 11 May 2008 + 5.4 + 21 July 2008 - - 5.1 - 10 Nov 2007 - mc - 'LINGONBERRY' release: Minor Update. - - 5.2 16 Mar 2008 @@ -392,6 +392,20 @@ 'SILVERBERRY' release: Important Update. + + 5.3 + 05 May 2008 + mc + 'GOLDENBERRY' release: Minor Update. + + + + 5.4 + 21 July 2008 + mc + 'ANGLEBERRY' release: Major Update. + + @@ -400,7 +414,7 @@ This tutorial assumes no previous knowledge of scripting or programming, but progresses rapidly toward an intermediate/advanced level of instruction . . . all - the while sneaking in little snippets of UNIX wisdom and lore. It serves as a textbook, a manual for self-study, and a reference and source of knowledge on shell scripting techniques. The exercises @@ -415,7 +429,7 @@ + url="http://personal.riverusers.com/~thegrendel/abs-guide-5.4.tar.bz2"> The latest update of this document, as an archived, bzip2-ed tarball including both the SGML source and rendered HTML, may @@ -604,7 +618,7 @@ Bourne-Again shell and a pun on Stephen Bourne's now classic Bourne shell. Bash has become a de facto standard for shell - scripting on all flavors of UNIX. Most of the principles this + scripting on most flavors of UNIX. Most of the principles this book covers apply equally well to scripting with other shells, such as the Korn Shell, from which Bash derives some of its features, @@ -696,7 +710,7 @@ previously written scripts for increased effectiveness. - The + The sha-bang sha-bang @@ -711,8 +725,8 @@ bang (!). at the head of a script tells your system that this file is a set of commands to be fed - to the command interpreter indicated. The - #! is actually a two-byte + to the command interpreter indicated. The #! is + actually a two-byte Some flavors of UNIX (those based on 4.2 BSD) @@ -850,7 +864,7 @@ exit $WHATEVER # Doesn't matter. The script will not exit here. This tutorial encourages a modular approach to constructing a script. Make note of and collect boilerplate code snippets that might be useful - in future scripts. Eventually you can build quite an extensive + in future scripts. Eventually you will build quite an extensive library of nifty routines. As an example, the following script prolog tests whether the script has been invoked with the correct number of parameters. @@ -1010,7 +1024,7 @@ fi Comments Lines beginning with a # - (with the exception of + (with the exception of #!) are comments and will not be executed. @@ -1039,7 +1053,7 @@ fi in an echo statement does not begin a comment. Likewise, a # appears in certain - parameter substitution constructs and in and in numerical constant expressions. echo "The # here does not begin a comment." @@ -1405,7 +1419,7 @@ done if condition then : # Do nothing and branch ahead -else +else # Or else ... take-some-action fi @@ -1618,8 +1632,8 @@ fi - In a double - parentheses construct, the ? + In a double-parentheses + construct, the ? can serve as an element of a C-style trinary operator, ?:. @@ -1871,7 +1885,10 @@ echo "a = $a" # a = 123 array initialization - Array=(element1 element2 element3) + + + Array=(element1 element2 element3) + @@ -2472,7 +2489,7 @@ echo "variable = $variable" # variable = initial_value If one of the commands in the pipe aborts, this prematurely terminates execution of the pipe. Called a broken pipe, this - condition sends a SIGPIPE SIGPIPE signal. @@ -3277,8 +3294,9 @@ echo <Ctl-V><Ctl-J> When typing text on the console or in an xterm window, Ctl-W erases from the character under the cursor backwards to the first instance of - whitespace. In some settings, Ctl-W - erases backwards to first non-alphanumeric character. + whitespace. In + some settings, Ctl-W erases + backwards to first non-alphanumeric character. @@ -3340,8 +3358,14 @@ echo <Ctl-V><Ctl-J> to whitespace. - To preserve whitespace within a string or in a variable, - use quoting. + To preserve whitespace + within a string or in a variable, use quoting. + + UNIX filters + can target and operate on whitespace + using the POSIX character class + [:space:]. @@ -3359,8 +3383,8 @@ echo <Ctl-V><Ctl-J> Variables are how programming and scripting languages represent data. A variable is nothing more than a label, a name assigned to a - location or set of locations in computer memory holding an item - of data. + location or set of locations holding an item of data, in computer + memory. Variables appear in arithmetic operations and manipulation of quantities, and in string parsing. @@ -3369,9 +3393,10 @@ echo <Ctl-V><Ctl-J> Variable Substitution - The name of a variable is a placeholder for - its value, the data it holds. Referencing its - value is called variable substitution. + The name of a variable is a placeholder + for its value, the data it holds. + Referencing (retrieving) its value is called + variable substitution. @@ -3447,20 +3472,20 @@ echo <Ctl-V><Ctl-J> Enclosing a referenced value in - double quotes (" ") + double quotes (" ... ") does not interfere with variable substitution. This is called partial quoting, sometimes referred to as weak quoting. Using single quotes (' ') + id="snglquo">Using single quotes (' ... ') causes the variable name to be used literally, and no substitution will take place. This is full - quoting, sometimes referred to as strong - quoting. See for a + quoting, sometimes referred to as 'strong + quoting.' See for a detailed discussion. Note that $variable is actually a - simplified alternate form of - ${variable}. In contexts + simplified form of + ${variable}. In contexts where the $variable syntax causes an error, the longer form may work (see , below). @@ -3476,10 +3501,16 @@ echo <Ctl-V><Ctl-J> An uninitialized variable has a null value -- no assigned value at all - (not zero!). Using a variable before - assigning a value to it may cause problems. + (not zero!). - It is nevertheless possible to perform arithmetic operations + if [ -z "$unassigned" ] +then + echo "\$unassigned is NULL." +fi # $unassigned is NULL. + + Using a variable before + assigning a value to it may cause problems. + It is nevertheless possible to perform arithmetic operations on an uninitialized variable. echo "$uninitialized" # (blank line) @@ -3579,9 +3610,10 @@ arch=$(uname -m) Untyped variables are both a blessing and a curse. They permit - more flexibility in scripting (enough rope to hang yourself!) and - make it easier to grind out lines of code. However, they permit - subtle errors to creep in and encourage sloppy programming habits. + more flexibility in scripting and make it easier to grind out + lines of code (enough rope to hang yourself!). However, they + likewise permit subtle errors to creep in and encourage sloppy + programming habits. To lighten the burden of keeping track of variable types in a script, Bash does permit @@ -3642,6 +3674,7 @@ arch=$(uname -m) The space allotted to the environment is limited. Creating too many environmental variables or ones that use up excessive space may cause problems. + bash$ eval "`seq 10000 | sed -e 's/.*/export var&=ZZZZZZZZZZZZZZ/'`" @@ -3650,6 +3683,9 @@ arch=$(uname -m) bash: /usr/bin/du: Argument list too long + + Note: this error has been fixed, as of + kernel version 2.6.23. (Thank you, Stéphane Chazelas for the clarification, and for providing the above example.) @@ -3697,11 +3733,11 @@ arch=$(uname -m) $2 the second, $3 the third, and so forth. - The process calling the script sets the - $0 parameter. By convention, this - parameter is the name of the script. See the manpage (manual page) for - execv. + The process calling the + script sets the $0 parameter. By + convention, this parameter is the name of the script. See + the manpage (manual page) + for execv. After $9, the arguments must be enclosed @@ -3722,10 +3758,14 @@ arch=$(uname -m) script on the command line. This also requires indirect referencing. + args=$# # Number of args passed. lastarg=${!args} -# Or: lastarg=${!#} -# (Thanks, Chris Monson.) +# Note: This is an *indirect reference* to $args ... + + +# Or: lastarg=${!#} (Thanks, Chris Monson.) +# This is an *indirect reference* to the $# variable. # Note that lastarg=${!$#} doesn't work. @@ -4223,7 +4263,7 @@ echo 'Why can'\''t I write '"'"'s between single quotes' flash - means alert (beep or flash) + means alert (beep or flash) @@ -4233,13 +4273,14 @@ echo 'Why can'\''t I write '"'"'s between single quotes' escaped character - \0xx + \0nn octal ASCII translates to the octal ASCII - equivalent of 0xx + equivalent of 0nn, where + nn is a string of digits Escaped Characters @@ -4247,7 +4288,7 @@ echo 'Why can'\''t I write '"'"'s between single quotes' See for another example of the - $' ' string expansion + $' ... ' string-expansion construct. @@ -4265,8 +4306,8 @@ echo 'Why can'\''t I write '"'"'s between single quotes' quote gives the quote its literal meaning - echo "Hello" # Hello -echo "\"Hello\", he said." # "Hello", he said. + echo "Hello" # Hello +echo "\"Hello\" ... he said." # "Hello" ... he said. @@ -4284,7 +4325,8 @@ echo "\"Hello\", he said." # "Hello", he said. gives the dollar sign its literal meaning (variable name following \$ will not be referenced) - echo "\$variable01" # results in $variable01 + echo "\$variable01" # $variable01 +echo "The book cost \$7.98." # The book cost $7.98. @@ -4305,16 +4347,22 @@ echo "\"Hello\", he said." # "Hello", he said. # Whereas . . . echo "\" # Invokes secondary prompt from the command line. - # In a script, gives an error message. + # In a script, gives an error message. + +# However . . . + +echo '\' # Results in \ + The behavior of \ depends on whether - it is itself escaped, quoted, or appearing within command substitution or a here document. + it is escaped, strong-quoted, + weak-quoted, or appearing within + command substitution or a + here document. # Simple escaping and quoting echo \z # z @@ -4471,7 +4519,7 @@ bar' # Escape character \ taken literally because of strong quoting. Exit and Exit Status - ...there are dark corners in the Bourne shell, and people use all + ... there are dark corners in the Bourne shell, and people use all of them. --Chet Ramey @@ -4487,9 +4535,9 @@ bar' # Escape character \ taken literally because of strong quoting. exit - command may be used to terminate a script, just as in a - C program. It can also return a value, - which is available to the script's parent process. + command terminates a script, just as in a C + program. It can also return a value, which is available to the + script's parent process. Every command returns an @@ -4509,10 +4557,10 @@ bar' # Escape character \ taken literally because of strong quoting. A successful command returns a 0, while an unsuccessful one returns a non-zero - value that usually may be interpreted as an error - code. Well-behaved UNIX commands, programs, and utilities return a - 0 exit code upon successful completion, - though there are some exceptions. + value that usually may be interpreted as an error + code. Well-behaved UNIX commands, programs, and + utilities return a 0 exit code upon + successful completion, though there are some exceptions. Likewise, functions within a script and the script itself return an exit status. The last command executed in the function @@ -4649,6 +4697,9 @@ true then + + else + else if @@ -4697,17 +4748,46 @@ true Bash sees [[ $a -lt $b ]] as a single element, which returns an exit status. + + The (( ... )) and let ... constructs also return an - exit status of 0 if the arithmetic - expressions they evaluate expand to a non-zero value. These - arithmetic expansion - constructs may therefore be used to perform arithmetic - comparisons. + exit status, according to whether the arithmetic expressions + they evaluate expand to a non-zero value. These arithmetic-expansion constructs + may therefore be used to perform arithmetic comparisons. - let "1<2" returns 0 (as "1<2" expands to "1") -(( 0 && 1 )) returns 1 (as "0 && 1" expands to "0") + + (( 0 && 1 )) # Logical AND +echo $? # 1 *** +# And so ... +let "num = (( 0 && 1 ))" +echo $num # 0 +# But ... +let "num = (( 0 && 1 ))" +echo $? # 1 *** + + +(( 200 || 11 )) # Logical OR +echo $? # 0 *** +# ... +let "num = (( 200 || 11 ))" +echo $num # 1 +let "num = (( 200 || 11 ))" +echo $? # 0 *** + + +(( 200 | 11 )) # Bitwise OR +echo $? # 0 *** +# ... +let "num = (( 200 | 11 ))" +echo $num # 203 +let "num = (( 200 | 11 ))" +echo $? # 0 *** + +# The "let" construct returns the same exit status +#+ as the double-parentheses arithmetic expansion. @@ -4715,10 +4795,10 @@ true An if can test any command, not just - conditions enclosed within brackets. + conditions enclosed within brackets. - if cmp a b &> /dev/null # Suppress output. + if cmp a b &> /dev/null # Suppress output. then echo "Files a and b are identical." else echo "Files a and b differ." fi @@ -4749,22 +4829,8 @@ fi - An if/then construct can contain nested - comparisons and tests. - if echo "Next *if* is part of the comparison for the first *if*." - if [[ $comparison = "integer" ]] - then (( a < b )) - else - [[ $a < $b ]] - fi - -then - echo '$a is less than $b' -fi - - - This detailed if-test explanation + These last two examples courtesy of Stéphane Chazelas. @@ -4783,14 +4849,13 @@ fi Explain the behavior of , above. - if [ condition-true ] + if [ condition-true ] then command 1 command 2 ... -else - # Optional (may be left out if not needed). - # Adds default code block executing if original condition tests false. +else # Or else ... + # Adds default code block executing if original condition tests false. command 3 command 4 ... @@ -4815,7 +4880,7 @@ fi elif elif is a contraction - for else if. The effect is to nest an + for else if. The effect is to nest an inner if/then construct within an outer one. @@ -4859,7 +4924,7 @@ fi special character ] - + The if test condition-true construct is the exact equivalent of if [ condition-true ]. As it happens, the left bracket, [ , is a token @@ -5116,15 +5181,26 @@ to disapprove of strongly. -d file is a directory + -b - file is a block device (floppy, cdrom, etc.) - + + file is a block + device + device="/dev/sda2" # / (root directory) +if [ -b "$device" ] +then + echo "$device is a block device." +fi + +# /dev/sda2 is a block device. + + -c - file is a character - device (keyboard, modem, sound card, etc.) + file is a character + device -p @@ -5370,8 +5446,7 @@ to disapprove of strongly. <= - is less than or equal to (within double parentheses) + is less than or equal to (within double parentheses) (("$a" <= "$b")) @@ -5416,11 +5491,11 @@ to disapprove of strongly. The == comparison operator behaves differently within a double-brackets test than within single brackets. - [[ $a == z* ]] # True if $a starts with an "z" (pattern matching). -[[ $a == "z*" ]] # True if $a is equal to z* (literal matching). + [[ $a == z* ]] # True if $a starts with an "z" (regex pattern matching). +[[ $a == "z*" ]] # True if $a is equal to z* (literal matching). -[ $a == z* ] # File globbing and word splitting take place. -[ "$a" == "z*" ] # True if $a is equal to z* (literal matching). +[ $a == z* ] # File globbing and word splitting take place. +[ "$a" == "z*" ] # True if $a is equal to z* (literal matching). # Thanks, Stéphane Chazelas @@ -5444,8 +5519,8 @@ to disapprove of strongly. if [[ "$a" < "$b" ]] if [ "$a" \< "$b" ] Note that the < needs to be - escaped within a [ ] - construct. + escaped within a + [ ] construct. @@ -5462,37 +5537,47 @@ to disapprove of strongly. + + -z + + string is null, + that is, has zero length + String='' # Zero-length ("null") string variable. + +if [ -z "$String" ] +then + echo "\$String is null." +else + echo "\$String is NOT null." +fi # $String is null. + + + -n - string is not null. + string is not null. - The -n test absolutely + The -n test requires that the string be quoted within the test brackets. Using an unquoted string with - ! -z, or even just the + ! -z, or even just the unquoted string alone within test brackets (see ) normally works, however, this is an unsafe practice. Always quote a tested string. As S.C. points out, in a compound test, even quoting the string variable might not - suffice. [ -n "$string" -o "$a" = - "$b" ] may cause an error with some - versions of Bash if $string - is empty. The safe way is to append an extra - character to possibly empty variables, [ - "x$string" != x -o "x$a" = "x$b" ] + suffice. [ -n "$string" -o "$a" = "$b" ] + may cause an error with some versions of Bash if + $string is empty. The safe way + is to append an extra character to possibly empty variables, + [ "x$string" != x -o "x$a" = "x$b" ] (the x's cancel out). - - -z - string is null, - that is, has zero length - @@ -5535,13 +5620,17 @@ to disapprove of strongly. - These are similar to the Bash comparison operators + + These are similar to the Bash comparison operators && and ||, used within double brackets. [[ condition1 && condition2 ]] + + + The -o and -a operators - work with the test command or occur within - single test brackets. + work with the test command or + occur within single test brackets. if [ "$exp1" -a "$exp2" ] @@ -5552,23 +5641,24 @@ to disapprove of strongly. - Nested <firstterm>if/then</firstterm> Condition Tests + Nested <replaceable>if/then</replaceable> Condition Tests - Condition tests using the if/then + Condition tests using the if/then construct may be nested. The net result is equivalent to using the - && compound comparison operator above. + && compound + comparison operator. if [ condition1 ] then if [ condition2 ] then - do-something # But only if both "condition1" and "condition2" valid. + do-something # But only if both "condition1" AND "condition2" valid. fi fi - See for an example of nested - if/then condition tests. - + demonstrates a nested + if/then condition test. + @@ -5775,7 +5865,7 @@ fi # Bash, version 2.02, introduced the "**" exponentiation operator. -let "z=5**3" +let "z=5**3" # 5 * 5 * 5 echo "z = $z" # z = 125 @@ -6452,7 +6542,7 @@ done bash$ echo $BASH_VERSION -3.00.14(1)-release +3.2.25(1)-release @@ -6560,6 +6650,8 @@ echo "FUNCNAME = $FUNCNAME" # FUNCNAME = # Null value outside a function. + See also . + @@ -7065,10 +7157,10 @@ echo "Last command argument processed = $last_cmd_arg" Chet Ramey attributes the above output to the behavior of ls. If ls writes to a pipe whose output is not - read, then SIGPIPE kills it, and its exit status is - 141. Otherwise its - exit status is 0, + read, then SIGPIPE kills it, + and its exit status + is 141. Otherwise + its exit status is 0, as expected. This likewise is the case for tr. @@ -7450,7 +7542,7 @@ echo "Your favorite song is $song." user ID number - current user's user identification number, as + Current user's user identification number, as recorded in /etc/passwd @@ -7533,7 +7625,7 @@ echo "Your favorite song is $song." positional - positional parameters, passed from command + Positional parameters, passed from command line to script, passed to a function, or set to a variable (see and ) @@ -7558,7 +7650,7 @@ echo "Your favorite song is $song." positional number of - number of command line arguments + Number of command line arguments The words argument and parameter are often used interchangeably. In the context of this document, they @@ -8209,7 +8301,7 @@ echo `expr "$stringZ" : '.*\(......\)'` # ABCabc - Strips shortest match of + Deletes shortest match of $substring from front of $string. @@ -8225,15 +8317,15 @@ echo `expr "$stringZ" : '.*\(......\)'` # ABCabc - Strips longest match of + Deletes longest match of $substring from front of $string. stringZ=abcABC123ABCabc -# |----| -# |----------| +# |----| shortest +# |----------| longest echo ${stringZ#a*C} # 123ABCabc # Strip out shortest match between 'a' and 'C'. @@ -8253,7 +8345,7 @@ echo ${stringZ##a*C} # abc - Strips shortest match of + Deletes shortest match of $substring from back of $string. @@ -8287,15 +8379,15 @@ done ### This could be condensed into a "one-liner" if desired. - Strips longest match of + Deletes longest match of $substring from back of $string. stringZ=abcABC123ABCabc -# || -# |------------| +# || shortest +# |------------| longest echo ${stringZ%b*c} # abcABC123ABCa # Strip out shortest match between 'b' and 'c', from back of $stringZ. @@ -8319,7 +8411,7 @@ echo ${stringZ%%b*c} # a A simple emulation of getopt - using substring extraction constructs. + using substring-extraction constructs. Emulating <firstterm>getopt</firstterm> @@ -8444,13 +8536,15 @@ echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ - Further Discussion + Further Reference For more on string manipulation in scripts, refer to and the relevant section of the expr command listing. For script examples, - see: + linkend="exprref">expr command listing. + + Script examples: + @@ -8458,10 +8552,10 @@ echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ - + - + @@ -8949,13 +9043,26 @@ echo "a = $a" # a = xyz23 xyz24 linkend="builtinref">builtins, which are exact synonyms, permit modifying the properties of variables. This is a very weak form of the typing - In this context, + + + + In this context, typing a variable means to classify it and restrict its properties. For example, a variable declared or typed as an integer is no longer available for string - operations. + operations. + + declare -i intvar + +intvar=23 +echo "$intvar" # 23 +intvar=stringval +echo "$intvar" # 0 + + + available in certain programming languages. The declare command is specific to version 2 or later of Bash. The typeset command @@ -8965,14 +9072,21 @@ echo "a = $a" # a = xyz23 xyz24 <anchor id="declareopsref1">declare/typeset options - -r readonly - declare -r var1 + -r + readonly + (declare -r var1 works the same as readonly var1) - This is the rough equivalent of the C - const type qualifier. An - attempt to change the value of a readonly variable fails with an - error message. + This is the rough equivalent of the C + const type qualifier. An attempt + to change the value of a readonly + variable fails with an error message. + declare -r var1=1 +echo "var1 = $var1" # var1 = 1 + +(( var1++ )) # x.sh: line 4: var1: readonly variable + + @@ -9103,23 +9217,24 @@ bar # Prints nothing. - Assume that the value of a variable is the name of a second - variable. Is it somehow possible to retrieve the value - of this second variable from the first one? For example, - if a=letter_of_alphabet - and letter_of_alphabet=z, - can a reference to a return - z? This can indeed be done, and - it is called an indirect reference. - It uses the unusual eval var1=\$$var2 - notation. + We have seen that referencing + a variable, $var, fetches its + value. But, + what about the value of a value? What + about $$var? + + The actual notation is + \$$var, usually preceded by + an eval (and sometimes an + echo). This is called an + indirect reference. + Indirect Variable References &indref; - Of what practical use is indirect referencing of variables? It gives Bash a little of the functionality of pointers @@ -9127,12 +9242,12 @@ bar # Prints nothing. linkend="resistor">table lookup. And, it also has some other very interesting applications. . . . - - Nils Radtke shows how to build dynamic - variable names and evaluate their contents. This can be useful - when sourcing configuration files. - - #!/bin/bash + Nils Radtke shows how to build dynamic + variable names and evaluate their contents. This can be useful + when sourcing configuration + files. + + #!/bin/bash # --------------------------------------------- @@ -9206,7 +9321,7 @@ echo $? # 1 Bash does not support pointer arithmetic, and this severely limits the usefulness of indirect referencing. In fact, indirect - referencing in a scripting language is, at best, an ugly kludge. + referencing in a scripting language is, at best, an afterthought. @@ -9368,7 +9483,7 @@ echo $? # 1 - The Double Parentheses Construct + The Double-Parentheses Construct @@ -9377,7 +9492,7 @@ echo $? # 1 arithmetic expansion and evaluation. In its simplest form, a=$(( 5 + 3 )) would set a to 5 + 3, or - 8. However, this double parentheses + 8. However, this double-parentheses construct is also a mechanism for allowing C-style manipulation of variables in Bash, for example, (( var++ )). @@ -9392,7 +9507,7 @@ echo $? # 1 See also and . - + @@ -9590,7 +9705,7 @@ echo $? # 1 &userlist; - A final example of the [list] + Yet another example of the [list] resulting from command substitution. @@ -9599,6 +9714,25 @@ echo $? # 1 &findstring; + A final example of [list] + / command substitution, but this time + the command is a function. + + generate_list () +{ + echo "one two three" +} + +for word in $(generate_list) # Let "word" grab output of function. +do + echo "$word" +done + +# one +# two +# three + The output of a for loop may @@ -9686,7 +9820,7 @@ echo $? # 1 the test brackets used in an if/then test. In fact, a while loop can legally use the - more versatile double brackets + more versatile double-brackets construct (while [[ condition ]]). @@ -9733,7 +9867,7 @@ echo $? # 1 As with a for loop, a while loop may employ C-style syntax - by using the double parentheses construct (see also ). @@ -9791,12 +9925,29 @@ done linkend="readref">read command with a while loop, we get the handy while read construct, useful - for reading and parsing files. - cat $filename | # Supply input from a file. + for reading and parsing files. + + cat $filename | # Supply input from a file. while read line # As long as there is another line to read ... do ... -done +done + +# =========== Snippet from "sd.sh" example script ========== # + + while read value # Read one data point at a time. + do + rt=$(echo "scale=$SC; $rt + $value" | bc) + (( ct++ )) + done + + am=$(echo "scale=$SC; $rt / $ct" | bc) + + echo $am; return $ct # This function "returns" TWO values! + # Caution: This little trick will not work if $ct > 255! + # To handle a larger number of data points, + #+ simply comment out the "return $ct" above. +} <"$datafile" # Feed in data file. @@ -9833,8 +9984,9 @@ done This construct tests for a condition at the top of a loop, and keeps - looping as long as that condition is false (opposite of - while loop). + looping as long as that condition is + false (opposite of while + loop). until @@ -9845,8 +9997,9 @@ done Note that an until loop tests for the - terminating condition at the top of the loop, differing from a - similar construct in some programming languages. + terminating condition at the top + of the loop, differing from a similar construct in some + programming languages. As is the case with for loops, placing the do on the same line as @@ -10035,7 +10188,7 @@ done The case construct is the shell - scripting analog to switch in C/C++. + scripting analog to switch in C/C++. It permits branching to one of a number of code blocks, depending on condition tests. It serves as a kind of shorthand for multiple if/then/else @@ -10623,7 +10776,7 @@ File_contents2=$(<$file2) # Bash permits this also. -- ((...)) and $((...)) -- and also by the very - convenient let construction. + convenient let construction. z=$(($z+3)) @@ -10910,12 +11063,14 @@ let "z += 3" # Quotes permit the use of spaces in variable assignment. lzma m4 mail + mailstats mailto make MAKEDEV man mcookie md5sum + merge mesg mimencode mkbootdisk @@ -10978,6 +11133,7 @@ let "z += 3" # Quotes permit the use of spaces in variable assignment. recode renice reset + resize restore rev rlogin @@ -11190,17 +11346,18 @@ echo "This line uses the \"echo\" builtin." is a reserved word, token or operator. Keywords have a special meaning to the shell, and indeed are the building blocks of the shell's - syntax. As examples, for, - while, do, and - ! are keywords. Similar to a for, + while, do, + and ! are keywords. Similar to a builtin, a keyword is hard-coded into Bash, but unlike a builtin, a keyword is - not in itself a command, but a subunit of a larger - command structure. + not in itself a command, but a subunit of a command + construct. An exception to this is the time command, listed in the official - Bash documentation as a keyword. + linkend="timref">time command, listed in the + official Bash documentation as a keyword (reserved + word). @@ -11404,6 +11561,8 @@ cd $var || error $"Can't cd to %s." "$var" # Thanks, S.C. + See also . + @@ -11481,7 +11640,8 @@ echo; echo "Keypress was "\"$keypress\""." The option to read - permits timed input (see ). + permits timed input (see and ). The read command may also @@ -11543,7 +11703,8 @@ while read f; do It is possible to paste text into - the input field of a read. See read (but + not multiple lines!). See . @@ -11808,6 +11969,11 @@ eval eval echo $a # d &evalex; + The eval command occurs + in the older version of indirect + referencing. + eval var=\$$var + @@ -12070,11 +12236,11 @@ eval eval echo $a # d C programmers. It permits passing and concatenating multiple options - A option is an argument that acts as a - flag, switching script behaviors on or off. The - argument associated with a particular option indicates - the behavior that the option (flag) switches on or - off. + An option is an + argument that acts as a flag, switching script behaviors + on or off. The argument associated with a particular + option indicates the behavior that the option (flag) + switches on or off. and associated arguments to a script (for example scriptname -abc -e @@ -12115,14 +12281,16 @@ eval eval echo $a # d The getopts template - differs slightly from the standard while - loop, in that it lacks condition brackets. + differs slightly from the standard while loop, in that + it lacks condition brackets. - The getopts construct replaces - the deprecated getopt - external command. + The getopts construct is a highly + functional replacement for the traditional + getopt external + command. @@ -13511,7 +13679,7 @@ chmod 000 directory-name attributes. This is analogous to chmod above, but with different options and a different invocation syntax, and it works only on - an ext2 filesystem. + ext2/ext3 filesystems. One particularly interesting chattr option is . A chattr +i @@ -13644,6 +13812,11 @@ chmod 000 directory-name info pages usually contain more detailed descriptions than do the man pages. + There have been various attempts at + automating the writing of man + pages. For a script that makes a tentative first + step in that direction, see . + @@ -14135,11 +14308,17 @@ LRFDATE=`expr "$LRFDATE" : '[[:space:]]*\(.*\)[[:space:]]*$'` number of output options. For example gives the nanosecond portion of the current time. One interesting use for this is to - generate six-digit random integers. + generate random integers. date +%N | sed -e 's/000$//' -e 's/^0//' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# Strip off leading and trailing zeroes, if present. +# Strip off leading and trailing zeroes, if present. +# Length of generated integer depends on +#+ how many zeroes stripped off. + +# 115281032 +# 63408725 +# 394504284 There are many more options (try man @@ -14378,8 +14557,7 @@ OneYearAgo=$(date --date='1 year ago') seconds, doing nothing. It can be useful for timing or in processes running in the background, checking for a specific event every so often (polling), as in . sleep 3 # Pauses - 3 seconds. + linkend="online">. sleep 3 # Pauses 3 seconds. The sleep command defaults to @@ -14622,7 +14800,8 @@ OneYearAgo=$(date --date='1 year ago') The expand filter converts tabs to - spaces. It is often used in a pipe. + spaces. It is often used in a pipe. The unexpand filter converts spaces to tabs. This reverses the effect of expand. @@ -14793,9 +14972,9 @@ done lists the beginning of a file to stdout. - The default is 10 lines, but this can - be changed. - The command has a number of interesting options. + The default is 10 lines, but a different + number can be specified. The command has a number of + interesting options. Which files are scripts? @@ -14823,7 +15002,7 @@ done lists the (tail) end of a file to stdout. The default is 10 lines, but this can - be changed. + be changed with the option. Commonly used to keep track of changes to a system logfile, using the option, which outputs lines appended to the file. @@ -15661,7 +15840,7 @@ function write_utf8_string { Consider this a fancier version of iconv, above. This very versatile utility for converting a file to a different encoding scheme. - Note that recode> is not part of the + Note that recode is not part of the standard Linux installation. @@ -15796,6 +15975,8 @@ function write_utf8_string { &manview; + See also . + @@ -15875,11 +16056,11 @@ function write_utf8_string { - A tar czvf archive_name.tar.gz * + A tar czvf ArchiveName.tar.gz * will include dotfiles in directories below the current working directory. This is an undocumented GNU - tar feature. + tar feature. @@ -16533,8 +16714,8 @@ file $DIRECTORY/* | fgrep $KEYWORD slocate - The locate command searches for files using a - database stored for just that purpose. The + The locate command searches for + files using a database stored for just that purpose. The slocate command is the secure version of locate (which may be aliased to slocate). @@ -16678,6 +16859,8 @@ gzip -cd patchXX.gz | patch -p0 # From the Linux kernel docs "README", # by anonymous author (Alan Cox?). + + The diff command can also recursively compare directories (for the filenames @@ -16710,6 +16893,7 @@ gzip -cd patchXX.gz | patch -p0 diff3 + merge diff3 @@ -16717,6 +16901,14 @@ gzip -cd patchXX.gz | patch -p0 command diff3 + + merge + + + command + merge + + An extended version of diff that compares three files at a time. This command returns an exit value @@ -16733,6 +16925,15 @@ gzip -cd patchXX.gz | patch -p0 This is line 1 of "file-3" + + The merge + (3-way file merge) command is an interesting adjunct to + diff3. Its syntax is + merge Mergefile file1 file2. + The result is to output to Mergefile + the changes that lead from file1 + to file2. Consider this command + a stripped-down version of patch. @@ -17166,10 +17367,10 @@ gzip -cd patchXX.gz | patch -p0 utility. This is a symmetric block cipher, used to - encrypt files on a single system or local network, as opposed - to the public key cipher class, of which - pgp is a well-known - example. + encrypt files on a single system or local network, + as opposed to the public key + cipher class, of which pgp is a + well-known example. Politically motivated government regulations prohibiting the export of encryption software resulted @@ -17343,7 +17544,7 @@ echo "tempfile name = $tempfile" stdout . . . or of a script. - An interesting application of more + An interesting application of more is to test drive a command sequence, to forestall potentially unpleasant consequences. ls /home/bozo | awk '{print "rm -rf " $1}' | more @@ -17354,6 +17555,11 @@ echo "tempfile name = $tempfile" # Hand off to the shell to execute . . . ^^ + The less pager has the + interesting property of doing a formatted display of + man page source. See . + @@ -17366,9 +17572,9 @@ echo "tempfile name = $tempfile" Communications Commands - Certain of the following commands find use in chasing spammers, as well as in - network data transfer and analysis. + Certain of the following commands find use in + network data transfer and analysis, as well as in + chasing spammers. <anchor id="communinfo1">Information and Statistics @@ -17462,12 +17668,11 @@ echo "tempfile name = $tempfile" Domain Information Groper. Similar to - nslookup, dig does - an Internet name server lookup on a host. - May be run either interactively or noninteractively, i.e., - from within a script. + nslookup, dig does + an Internet name server lookup on a host. + May be run from the command line or from within a script. - Some interesting options to dig are + Some interesting options to dig are for setting a query timeout to N seconds, for continuing to query servers until a reply is received, and @@ -17557,10 +17762,11 @@ echo "tempfile name = $tempfile" - Broadcast an ICMP ECHO_REQUEST packet to - another machine, either on a local or remote network. This - is a diagnostic tool for testing network connections, - and it should be used with caution. + Broadcast an ICMP + ECHO_REQUEST packet to another machine, + either on a local or remote network. This is a + diagnostic tool for testing network connections, + and it should be used with caution. @@ -17575,14 +17781,14 @@ echo "tempfile name = $tempfile" - A successful ping returns an exit status of + A successful ping returns + an exit status of 0. This can be tested for in a script. HNAME=nastyspammer.com # HNAME=$HOST # Debug: test for localhost. -count=2 # Send only two pings. + count=2 # Send only two pings. if [[ `ping -c $count "$HNAME"` ]] then @@ -17632,9 +17838,9 @@ fi bash$ finger Login Name Tty Idle Login Time Office Office Phone - bozo Bozo Bozeman tty1 8 Jun 25 16:59 - bozo Bozo Bozeman ttyp0 Jun 25 16:59 - bozo Bozo Bozeman ttyp1 Jun 25 17:07 + bozo Bozo Bozeman tty1 8 Jun 25 16:59 (:0) + bozo Bozo Bozeman ttyp0 Jun 25 16:59 (:0.0) + bozo Bozo Bozeman ttyp1 Jun 25 17:07 (:0.0) @@ -17646,7 +17852,7 @@ fi On since Fri Aug 31 20:13 (MST) on pts/0 12 seconds idle On since Fri Aug 31 20:13 (MST) on pts/1 On since Fri Aug 31 20:31 (MST) on pts/2 1 hour 16 minutes idle - No mail. + Mail last read Tue Jul 3 10:08 2007 (MST) No Plan. @@ -18161,6 +18367,33 @@ wget -c ftp://ftp.xyz25.net/bozofiles/filename.tar.bz2 + + mailstats + + mailstats + + + command + statistics + + + Show mail statistics. This command + may be invoked only by root. + + + root# mailstats +Statistics from Tue Jan 1 20:32:08 2008 + M msgsfr bytes_from msgsto bytes_to msgsrej msgsdis msgsqur Mailer + 4 1682 24118K 0 0K 0 0 0 esmtp + 9 212 640K 1894 25131K 0 0 0 local + ===================================================================== + T 1894 24758K 1894 25131K 0 0 0 + C 414 0 + + + + + vacation @@ -18206,17 +18439,15 @@ wget -c ftp://ftp.xyz25.net/bozofiles/filename.tar.bz2 Initialize terminal and/or fetch information about it from - terminfo data. Various options permit - certain terminal operations. tput clear - is the equivalent of clear, - below. tput reset is the equivalent - of reset, - below. tput sgr0 also resets the - terminal, but without clearing the screen. + terminfo data. Various options permit + certain terminal operations: tput clear + is the equivalent of clear; + tput reset is the equivalent + of reset. bash$ tput longname -xterm terminal emulator (XFree86 4.0 Window System) +xterm terminal emulator (X Window System) @@ -18225,6 +18456,26 @@ wget -c ftp://ftp.xyz25.net/bozofiles/filename.tar.bz2 terminal. A clear to erase the terminal screen would normally precede this. + + + + Some interesting options to tput are: + + + , for high-intensity + text + , to underline text + in the terminal + , to render text in + reverse + , to reset the terminal + parameters (to normal), without clearing the + screen + + + + + Note that stty offers a more powerful command set for controlling a terminal. @@ -18299,6 +18550,32 @@ wget -c ftp://ftp.xyz25.net/bozofiles/filename.tar.bz2 + + + resize + + resize + + + command + resize + + + Echoes commands necessary to set $TERM + and $TERMCAP to duplicate the + size (dimensions) of the current + terminal. + + bash$ resize +set noglob; + setenv COLUMNS '80'; + setenv LINES '24'; + unset noglob; + + + + + script @@ -18344,6 +18621,11 @@ wget -c ftp://ftp.xyz25.net/bozofiles/filename.tar.bz2 + + Generating prime numbers + &primes2; + + @@ -18438,6 +18720,8 @@ LIMIT_STRING &cannon; + See also . + @@ -18459,7 +18743,7 @@ LIMIT_STRING programming language. Most persons avoid dc, since it - requires non-intuitive RPN input. Yet, it has its uses. + requires non-intuitive input. Yet, it has its uses. Converting a decimal number to hexadecimal @@ -18642,6 +18926,16 @@ done &ex33a; + + As Peggy Russell points out: + It is often necessary to include an eval to correctly process + whitespace and + quotes. + args=$(getopt -o a:bc:d -- "$@") +eval set -- "$args" + + See for a simplified emulation of getopt. @@ -18691,7 +18985,7 @@ done command feeds a continuous string of the character y followed by a line feed to stdout. A - controlc + controlC terminates the run. A different output string may be specified, as in yes different string, which would continually output @@ -18702,7 +18996,7 @@ done command line or in a script, the output of yes can be redirected or piped into a program expecting user input. In effect, this becomes a sort - of poor man's version of expect. + of poor man's version of expect. yes | fsck /dev/hda1 runs fsck non-interactively (careful!). @@ -18710,14 +19004,15 @@ done yes | rm -r dirname has same effect as rm -rf dirname (careful!). - Caution advised when piping yes - to a potentially dangerous system command, such - as fsck or fdisk. It might have unintended - consequences. + Caution advised when piping + yes to a potentially dangerous + system command, such as fsck + or fdisk. It might have + unintended consequences. - The yes command parses variables. + The yes command parses variables, + or more accurately, it echoes parsed variables. For example: bash$ yes $BASH_VERSION @@ -18729,9 +19024,37 @@ done . . . - This feature may not be particularly useful. + + + This particular feature may be used + to create a very large ASCII file on the fly: + bash$ yes $PATH > huge_file.txt +Ctl-C + + Hit Ctl-C very + quickly, or you just might get more than you + bargained for. . . . + + The yes + command may be emulated in a very simple script function. + + yes () +{ # Trivial emulation of "yes" ... + local DEFAULT_TEXT="yes" + while [ true ] # Endless loop. + do + if [ -z "$1" ] + then + echo "$DEFAULT_TEXT" + else # If argument ... + echo "$1" # ... expand and echo it. + fi + done # The only things missing are the +} #+ --help and --version options. + @@ -18749,6 +19072,9 @@ done stdout, using an ASCII character (default '#'). This may be redirected to a printer for hardcopy. + + Note that banner has been + dropped from many Linux distros. @@ -18833,7 +19159,7 @@ done [UNIX borrows an idea from the plumbing trade.] This is a redirection operator, but with a difference. Like the - plumber's tee, it permits siponing + plumber's tee, it permits siphoning off to a file the output of a command or commands within a pipe, but without affecting the result. This is useful for printing an ongoing process to a file or paper, perhaps to @@ -18849,12 +19175,12 @@ done - cat listfile* | sort | tee check.file | uniq > result.file + cat listfile* | sort | tee check.file | uniq > result.file +# ^^^^^^^^^^^^^^ ^^^^ + +# The file "check.file" contains the concatenated sorted "listfiles," +#+ before the duplicate lines are removed by 'uniq.' - (The file check.file contains - the concatenated sorted listfiles, - before the duplicate lines are removed by uniq.) @@ -18889,8 +19215,8 @@ done # This short script by Omair Eshkenazi. # Used in ABS Guide with permission (thanks!). -mkfifo pipe1 -mkfifo pipe2 +mkfifo pipe1 # Yes, pipes can be given names. +mkfifo pipe2 # Hence the designation "named pipe." (cut -d' ' -f1 | tr "a-z" "A-Z") >pipe2 <pipe1 & ls -l | tr -s ' ' | cut -d' ' -f3,9- | tee pipe1 | @@ -19213,7 +19539,7 @@ dd if=$filename conv=ucase > $filename.uppercase random000=$(mcookie) Of course, a script could use md5 for the same purpose. + linkend="md5sumref">md5sum for the same purpose. # Generate md5 checksum on the script itself. random001=`md5sum $0 | awk '{print $1}'` @@ -19263,13 +19589,14 @@ random001=`md5sum $0 | awk '{print $1}'` A hidden treasure, m4 is a - powerful macro processing filter, + powerful macro A macro is a symbolic constant that expands into a command string - or a set of operations on parameters. - virtually a complete language. Although - originally written as a pre-processor for - RatFor, m4 + or a set of operations on parameters. Simply put, + it's a shortcut or abbreviation. + processing filter, virtually a complete language. + Although originally written as a pre-processor + for RatFor, m4 turned out to be useful as a stand-alone utility. In fact, m4 combines some of the functionality of eval, @@ -19910,7 +20237,7 @@ sudo cp /root/secretfile /home/bozo/secret tty - Echoes the name of the current user's terminal. + Echoes the name (filename) of the current user's terminal. Note that each separate xterm window counts as a different terminal. bash$ tty @@ -22062,7 +22389,8 @@ mount -o loop /dev/loop0 /mnt # Mount it. fsck: a front end for checking a UNIX filesystem (may invoke other utilities). The actual - filesystem type generally defaults to ext2. + filesystem type generally defaults to + ext2. e2fsck: ext2 filesystem checker. @@ -23616,8 +23944,9 @@ echo a111b | gawk '/a1+b/' whitespace - [:space:] matches whitespace - characters (space and horizontal tab). + [:space:] + matches whitespace characters (space and horizontal + tab). @@ -23826,7 +24155,7 @@ echo a111b | gawk '/a1+b/' Here and now, boys. - --Aldous Huxley, Island + --Aldous Huxley, Island @@ -24075,8 +24404,8 @@ fi See also , , - and for more examples of self-documenting - scripts. + , and for more examples + of self-documenting scripts. @@ -24135,9 +24464,10 @@ echo "This line had better not echo." # Follows an 'exit' command.For those tasks too complex for a here - document, consider using the expect - scripting language, which is specifically tailored for feeding - input into interactive programs. + document, consider using the + expect scripting language, which was + specifically designed for feeding input into interactive + programs. @@ -24162,7 +24492,7 @@ if echo "$VAR" | grep -q txt # if [[ $VAR = *txt* ]] # Try: if grep -q "txt" <<< "$VAR" -then +then # ^^^ echo "$VAR contains the substring sequence \"txt\"" fi # Thank you, Sebastian Kaminski, for the suggestion. @@ -24746,8 +25076,9 @@ but is shown here for illustrative purposes. not visible outside the block of code in the subshell. They are not accessible to the parent process, to the shell - that launched the subshell. These are, in effect, local variables. + that launched the subshell. These are, in effect, + variables local to the + child process. Variable scope in a subshell @@ -24900,29 +25231,26 @@ fi - ... + Running a script or portion of a script in - restricted mode disables certain commands that - would otherwise be available. This is a security measure intended - to limit the privileges of the script user and to minimize possible - damage from running the script. + restricted mode disables certain commands + that would otherwise be available. This is a security measure + intended to limit the privileges of the script user and to + minimize possible damage from running the script. - - - - - ... + + + The following commands and actions are disabled: + + + Using cd to change the working directory. - - - - Changing the values of the $PATH, @@ -24931,58 +25259,40 @@ fi or $ENV environmental variables. - - - Reading or changing the $SHELLOPTS, shell environmental options. - - - Output redirection. - - - Invoking commands containing one or more - /'s. + /'s. - - - Invoking exec to substitute a different process for the shell. - - - Various other commands that would enable monkeying with or attempting to subvert the script for an unintended purpose. - - - Getting out of restricted mode within the script. - - + + Running a script in restricted mode @@ -25232,16 +25542,19 @@ x=x < <(:) A function may be compacted into a single line. - fun () { echo "This is a function"; echo; } + fun () { echo "This is a function"; echo; } +# ^ ^ In this case, however, a semicolon must follow the final command in the function. - fun () { echo "This is a function"; echo } # Error! + fun () { echo "This is a function"; echo } # Error! +# ^ Functions are called, triggered, simply by - invoking their names. + invoking their names. A function call is equivalent to + a command. Simple functions @@ -25602,7 +25915,8 @@ echo $days_in # 30 # ---------------------------------------------- - See also . + See also + and . Exercise: Using what we have just learned, extend the previous However, aliases do seem to expand positional parameters. Moreover, a script fails to expand an alias itself - within compound constructs, such as compound constructs, such as if/then statements, loops, and functions. An added limitation is that an alias will not expand recursively. Almost invariably, whatever we would like an alias @@ -25951,12 +26265,12 @@ drwxr-xr-x 40 bozo bozo 2048 Feb 6 14:04 .. list - The and list and or list - constructs provide a means of processing a number of commands - consecutively. These can effectively replace complex - nested if/then or even - case statements. - + The and list and or + list constructs provide a means of processing a + number of commands consecutively. These can effectively replace + complex nested if/then + or even case statements. + <anchor id="lcons1">Chaining together commands @@ -25965,12 +26279,12 @@ drwxr-xr-x 40 bozo bozo 2048 Feb 6 14:04 .. and list command-1 && command-2 && command-3 && ... command-n - Each command executes in turn provided that + Each command executes in turn, provided that the previous command has given a return value of - true (zero). At the first - false (non-zero) return, the + true (zero). At the first + false (non-zero) return, the command chain terminates (the first command returning - false is the last one to + false is the last one to execute). @@ -26018,9 +26332,9 @@ drwxr-xr-x 40 bozo bozo 2048 Feb 6 14:04 .. &ex65; - If the first command in an or list - returns true, it - will execute. + If the first command in an or + list returns true, + it will execute. @@ -26065,28 +26379,30 @@ done or list is the exit status of the last command executed. - Clever combinations of and and or - lists are possible, but the logic may easily become convoluted and - require close attention to operator - precedence rules, and possibly extensive debugging. - false && true || echo false # false + Clever combinations of and and + or lists are possible, but the logic may + easily become convoluted and require close attention to operator precedence rules, and + possibly extensive debugging. + + false && true || echo false # false # Same result as ( false && true ) || echo false # false -# But *not* +# But NOT false && ( true || echo false ) # (nothing echoed) # Note left-to-right grouping and evaluation of statements, #+ since the logic operators "&&" and "||" have equal precedence. -# It's best to avoid such complexities, unless you know what you're doing. +# It's usually best to avoid such complexities. # Thanks, S.C. See and for illustrations of using an and - / or list to test variables. + linkend="brokenlink"> for illustrations of using and + / or list constructs to test variables. @@ -26105,9 +26421,9 @@ false && ( true || echo false ) # (nothing echoed) variable[xx] notation. Alternatively, a script may introduce the entire array by an explicit declare -a variable statement. To - dereference (find the contents of) an array element, use + dereference (retrieve the contents of) an array element, use curly bracket notation, that is, - ${variable[xx]}. + ${element[xx]}. @@ -26118,7 +26434,7 @@ false && ( true || echo false ) # (nothing echoed) As we have seen, a convenient way of initializing an entire array - is the array=( element1 element2 ... elementN) + is the array=( element1 element2 ... elementN ) notation. @@ -26429,9 +26745,11 @@ exit 0 For more interesting scripts using arrays, see: + + @@ -26455,7 +26773,7 @@ exit 0 <filename class="directory">/dev</filename> The /dev directory - contains entries for the physical devices + contains entries for the physical devices that may or may not be present in the hardware. The entries in /dev @@ -26467,9 +26785,10 @@ exit 0 are not actual physical devices and exist only in software. - The hard drive partitions containing the mounted filesystem(s) - have entries in /dev, - as a simple df shows. + For example, the hard drive partitions containing + the mounted filesystem(s) have entries in /dev, as df shows. bash$ df Filesystem 1k-blocks Used Available Use% @@ -26488,14 +26807,16 @@ exit 0 that allows an ordinary file to be accessed as if it were a block device. - A block device reads - and/or writes data in chunks, or blocks, in contrast to a - character device, which acesses data - in character units. Examples of block devices are a hard - drive and CDROM drive. An example of a character device is - a keyboard. + A block + device reads and/or writes data in chunks, + or blocks, in contrast to a character device, + which acesses data in character + units. Examples of block devices are hard drives, CDROM + drives, and flash drives. Examples of character devices are + keyboards, modems, sound cards. - This enables mounting an entire filesystem within a + This permits mounting an entire filesystem within a single large file. See and . @@ -26505,9 +26826,11 @@ exit 0 linkend="zerosref">/dev/null, /dev/zero, /dev/urandom, - /dev/sda1, /dev/udp, - and /dev/tcp. - + /dev/sda1 (hard drive partition), + /dev/udp (User + Datagram Packet port), and /dev/tcp. + For instance: To mount a USB flash drive, @@ -26544,7 +26867,7 @@ exit 0 # Stream of characters and assorted gibberish # (There is a pre-recorded disk in the drive, -#+ and this is raw output -- a stream of ASCII and binary data.) +#+ and this is raw output -- a stream of ASCII and binary data.) # Here we see the wisdom of using 'head' to limit the output #+ to manageable proportions, rather than 'cat' or something similar. @@ -26594,10 +26917,16 @@ exit 0 - Using <filename>/dev/tcp</filename> for troubleshooting + Using <filename>/dev/tcp</filename> for + troubleshooting &devtcp; + + Playing music + &musicscr; + + @@ -27234,16 +27563,61 @@ trap 'echo "Control-C disabled."' 2 Version 3 of Bash adds the - following special variables for use by the debugger. + following internal + variables for use by the debugger. - $BASH_ARGC - $BASH_ARGV - $BASH_COMMAND - $BASH_EXECUTION_STRING - $BASH_LINENO - $BASH_SOURCE - $BASH_SUBSHELL + + + $BASH_ARGC + Number of command-line arguments passed to script, + similar to $#. + + + + $BASH_ARGV + Final command-line parameter passed to script, equivalent + ${!#}. + + + + $BASH_COMMAND + Command currently executing. + + + + $BASH_EXECUTION_STRING + The option string following the + option + to Bash. + + + + $BASH_LINENO + In a function, + indicates the line number of the function call. + + + + $BASH_REMATCH + Array variable associated with =~ + conditional regex + matching. + + + + $BASH_SOURCE + Same as $0. + + + + + $BASH_SUBSHELL + + @@ -27489,9 +27863,11 @@ trap 'echo "Control-C disabled."' 2 Gotchas - Puccini - Turandot: Gli enigmi sono tre, la morte una! - Caleph: No, no! Gli enigmi sono tre, una la vita! + Turandot: Gli enigmi sono tre, la morte + una! + Caleph: No, no! Gli enigmi sono tre, una la + vita! + --Puccini @@ -27977,7 +28353,7 @@ find $HOME -type f -atime +30 -size 100k | { Using shell scripts for CGI programming may be problematic. Shell - script variables are not typesafe, and this can cause + script variables are not typesafe, and this can cause undesirable behavior as far as CGI is concerned. Moreover, it is difficult to cracker-proof shell scripts. @@ -28003,12 +28379,12 @@ find $HOME -type f -atime +30 -size 100k | { - A.J. Lamb and H.W. Petrie Danger is near thee -- Beware, beware, beware, beware. Many brave hearts are asleep in the deep. So beware -- Beware. + --A.J. Lamb and H.W. Petrie @@ -28130,8 +28506,8 @@ while [ "$index" -le "$MAXVAL" ] ... -E_NOTFOUND=75 # Uppercase for an errorcode, - # +and name begins with "E_". +E_NOTFOUND=95 # Uppercase for an errorcode, + #+ and name prefixed with E_. if [ ! -e "$filename" ] then echo "File $filename not found." @@ -28139,13 +28515,13 @@ then fi -MAIL_DIRECTORY=/var/spool/mail/bozo # Uppercase for an environmental variable. -export MAIL_DIRECTORY +MAIL_DIRECTORY=/var/spool/mail/bozo # Uppercase for an environmental +export MAIL_DIRECTORY #+ variable. -GetAnswer () # Mixed case works well for a function. -{ - prompt=$1 +GetAnswer () # Mixed case works well for a +{ #+ function name, especially + prompt=$1 #+ when it improves legibility. echo -n $prompt read answer return $answer @@ -28175,8 +28551,9 @@ exit $E_WRONG_ARGS See also . - Ender suggests using the exit codes - in /usr/include/sysexits.h in shell + Ender suggests using the exit codes + in /usr/include/sysexits.h in shell scripts, though these are primarily intended for C and C++ programming. @@ -28239,11 +28616,11 @@ if COMMAND - Landon Noll ... reading the UNIX source code to the Bourne shell (/bin/sh). I was shocked at how much simple algorithms could be made cryptic, and therefore useless, by a poor choice of code style. I asked myself, Could someone be proud of this code? + --Landon Noll @@ -28460,7 +28837,7 @@ if [[ "$v1" -gt "$v2" ]] || [[ "$v1" -lt "$v2" ]] && [[ -e "$filename" ]] - A wrapper is a shell script that embeds + A wrapper is a shell script that embeds a system command or utility, that saves a set of parameters passed to that command. @@ -28494,14 +28871,15 @@ if [[ "$v1" -gt "$v2" ]] || [[ "$v1" -lt "$v2" ]] && [[ -e "$filename" ]] or awk 'commands'. Embedding such a script in a Bash script permits calling it more simply, - and makes it reusable. This also enables - combining the functionality of sed - and awk, for example reusable. This also + enables combining the functionality of sed + and awk, for example piping the output of a set of - sed commands to awk. - As a saved executable file, you can then repeatedly invoke it - in its original form or modified, without the inconvenience - of retyping it on the command line. + sed commands to + awk. As a saved executable file, + you can then repeatedly invoke it in its original form or + modified, without the inconvenience of retyping it on the + command line. <firstterm>shell wrapper</firstterm> @@ -28571,6 +28949,17 @@ if [[ "$v1" -gt "$v2" ]] || [[ "$v1" -lt "$v2" ]] && [[ -e "$filename" ]] + One interesting example of a complex shell wrapper is Martin + Matusiak's undvd + script, which provides an easy-to-use + command-line interface to the complex mencoder + utility. Another example is Itzchak Rehberg's Ext3Undel, + a set of scripts to recover deleted file on an + ext3 filesystem. + @@ -29161,6 +29550,17 @@ rm -rf *.zzy ## The "-rf" options to "rm" are very dangerous, while [ "$var1" != "end" ] #> while test "$var1" != "end" + + + + Dotan Barak contributes template code for a + progress bar in a script. + + + A Progress Bar + &progressbar; + + @@ -29329,7 +29729,7 @@ retval=`sum_and_product $first $second` # Assigns output of function. - Using the double parentheses + Using the double-parentheses construct, it is possible to use C-style syntax for setting and incrementing/decrementing variables and in for and co command in rcs does a parameter replacement of certain reserved key words, for example, replacing - #$Id$ in a script with something like: - #$Id$ + # $Id$ in a script with something like: + # $Id$ @@ -29739,6 +30139,16 @@ echo "User entered: "$answer"" $( ) notation + + The double brackets + extended test construct + + + + The double-parentheses + arithmetic-evaluation construct + + Certain string manipulation operations @@ -29748,6 +30158,11 @@ echo "User entered: "$answer"" Process substitution + + A Regular Expression matching + operator + + Bash-specific builtins @@ -29794,13 +30209,17 @@ echo "User entered: "$answer"" - The current version of Bash, the one - you have running on your machine, is version 2.xx.y or 3.xx.y. + + The current version of Bash, the one + you have running on your machine, is most likely version 2.xx.yy + or 3.xx.yy. bash$ echo $BASH_VERSION 3.2.25(1)-release - The version 2 update of the classic Bash scripting language added array - variables, + + + The version 2 update of the classic Bash scripting language + added array variables, Chet Ramey has promised associative arrays (a nifty Perl feature) in a future Bash release. As of version @@ -30101,7 +30520,7 @@ echo $a # 6 Author's Note - doce ut discas + doce ut discas (Teach, that you yourself may learn.) @@ -30315,10 +30734,10 @@ echo $a # 6 I would like to especially thank Patrick Callahan, Mike Novak, and Pal Domokos for catching bugs, pointing out - ambiguities, and for suggesting clarifications and changes. - Their lively discussion of shell scripting and general - documentation issues inspired me to try to make this document - more readable. + ambiguities, and for suggesting clarifications and changes in the + preliminary version (0.1) of this document. Their lively + discussion of shell scripting and general documentation issues + inspired me to try to make this document more readable. I'm grateful to Jim Van Zandt for pointing out errors and omissions in version 0.2 of this document. He also contributed @@ -30391,37 +30810,37 @@ echo $a # 6 Wayne Pollock, jipe, bojster, nyal, Hobbit, Ender, Little Monster (Alexis), Mark, - Patsie, Emilio Conti, Ian. D. Allen, Hans-Joerg - Diers, Arun Giridhar, Dennis Leeuw, Dan Jacobson, Aurelio Marinho - Jargas, Edward Scholtz, Jean Helou, Chris Martin, Lee Maschmeyer, - Bruno Haible, Wilbert Berendsen, Sebastien Godard, Bjön - Eriksson, John MacDonald, Joshua Tschida, Troy Engel, Manfred - Schwarb, Amit Singh, Bill Gradwohl, E. Choroba, David Lombard, - Jason Parker, Steve Parker, Bruce W. Clare, William Park, Vernia - Damiano, Mihai Maties, Mark Alexander, Jeremy Impson, Ken Fuchs, - Jared Martin, Frank Wang, Sylvain Fourmanoit, Matthew Sage, - Matthew Walker, Kenny Stauffer, Filip Moritz, Andrzej Stefanski, - Daniel Albers, Stefano Palmeri, Nils Radtke, Serghey Rodin, - Jeroen Domburg, Alfredo Pironti, Phil Braham, Bruno de Oliveira - Schneider, Stefano Falsetto, Chris Morgan, Walter Dnes, + Patsie, Peggy Russell, Emilio Conti, Ian. D. Allen, + Hans-Joerg Diers, Arun Giridhar, Dennis Leeuw, Dan Jacobson, + Aurelio Marinho Jargas, Edward Scholtz, Jean Helou, Chris Martin, + Lee Maschmeyer, Bruno Haible, Wilbert Berendsen, Sebastien Godard, + Bjön Eriksson, John MacDonald, Joshua Tschida, Troy Engel, + Manfred Schwarb, Amit Singh, Bill Gradwohl, E. Choroba, David + Lombard, Jason Parker, Steve Parker, Bruce W. Clare, William Park, + Vernia Damiano, Mihai Maties, Mark Alexander, Jeremy Impson, + Ken Fuchs, Jared Martin, Frank Wang, Sylvain Fourmanoit, Matthew + Sage, Matthew Walker, Kenny Stauffer, Filip Moritz, Andrzej + Stefanski, Daniel Albers, Stefano Palmeri, Nils Radtke, Serghey + Rodin, Jeroen Domburg, Alfredo Pironti, Phil Braham, Bruno de + Oliveira Schneider, Stefano Falsetto, Chris Morgan, Walter Dnes, Linc Fessenden, Michael Iatrou, Pharis Monalo, Jesse Gough, Fabian Kreutz, Mark Norman, Harald Koenig, Dan Stromberg, Peter Knowles, Francisco Lobo, Mariusz Gniazdowski, Sebastian Arming, Benno Schulenberg, Tedman Eng, Jochen DeSmet, Juan Nicolas Ruiz, - Oliver Beckstein, Achmed Darwish, Richard Neill, Albert Siersema, - Omair Eshkenazi, Geoff Lee, JuanJo Ciarlante, Cliff Bamford, - Nathan Coulter, Andreas Kühne, and David Lawyer (himself - an author of four HOWTOs). + Oliver Beckstein, Achmed Darwish, Dotan Barak, Richard Neill, + Albert Siersema, Omair Eshkenazi, Geoff Lee, JuanJo Ciarlante, + Cliff Bamford, Nathan Coulter, Antonio Macchi, Andreas Kühne, + and David Lawyer (himself an author of four HOWTOs). My gratitude to Chet Ramey and Brian Fox for writing Bash, and building into it elegant and powerful scripting - capabilities. + capabilities rivaling those of ksh. Very special thanks to the hard-working volunteers at the Linux Documentation Project. The LDP hosts a repository of Linux knowledge - and lore, and has, to a large extent, enabled the publication + and lore, and has, to a great extent, enabled the publication of this book. Thanks and appreciation to IBM, Red Hat, the all the good people fighting the good fight to keep Open Source software free and open. - Thanks most of all to my wife, Anita, for her encouragement and - emotional support. + Thanks most of all to my wife, Anita, for her encouragement, + inspiration, and emotional support. @@ -30444,15 +30863,15 @@ echo $a # 6 No liability for the contents of this document can be accepted. Use the concepts, examples and information at your own risk. There may be errors and inaccuracies that could cause - you to lose data or damage your system, so proceed with + you to lose data or harm your system, so proceed with appropriate caution. The author takes no responsibility - for any damage caused. + for any damages, incidental or otherwise. As it happens, it is highly unlikely that either you or - your system will suffer harm. In fact, the raison - d'etre of this book is to enable its readers - to analyze shell scripts and determine whether they have - unexpected consequences. + your system will suffer ill effects. In fact, the + raison d'etre of this book is to + enable its readers to analyze shell scripts and determine whether + they have unanticipated consequences. @@ -31246,6 +31665,15 @@ echo $a # 6 + + + John Lion's classic, + A Commentary on the Sixth Edition UNIX Operating + System. + + + The &insertionsort; + + Standard Deviation + &stddev; + + A <firstterm>pad</firstterm> file generator for shareware authors &padsw; + + A <firstterm>man page</firstterm> editor + &maned; + + Petals Around the Rose &petals; @@ -31620,11 +32058,22 @@ echo $a # 6 &qky; + + Nim + &nim; + + An all-purpose shell scripting homework assignment solution &homework; + + An alternate version of the + <link linkend="getoptsimple">getopt-simple.sh</link> script + &usegetopt; + + To end this section, a review of the basics . . . and more. @@ -32184,7 +32633,7 @@ echo $a # 6 * Where $substring is a - regular expression. + Regular Expression. @@ -32218,7 +32667,9 @@ echo $a # 6 - Range of characters within a Regular Expression + Range of + characters within a Regular + Expression @@ -32262,12 +32713,12 @@ echo $a # 6 - Array initialization + Array initialization - Execute command in subshell and assign result to - variable + Command substitution, + new style @@ -32283,7 +32734,7 @@ echo $a # 6 - Integer arithmetic + Integer arithmetic @@ -32310,11 +32761,11 @@ echo $a # 6 - "Weak" quoting + "Weak" quoting - "Strong" quoting + 'Strong' quoting @@ -32322,8 +32773,8 @@ echo $a # 6 - Execute command in subshell and assign result - to variable + Command + substitution, classic style @@ -32835,6 +33286,7 @@ awk '{print $0}' $filename 1 signifies so many possible errors, it is not particularly useful in debugging. + There has been an attempt to systematize exit status numbers (see /usr/include/sysexits.h), @@ -33753,16 +34205,18 @@ read -p "$(gettext -s "Enter the value: ")" var - Unfortunately, the Bash history tools find no use in scripting. - #!/bin/bash + Unfortunately, the Bash history tools find no use in + scripting. + + #!/bin/bash # history.sh -# Attempt to use 'history' command in a script. +# A (vain) attempt to use the 'history' command in a script. history # No output. var=$(history); echo "$var" # $var is empty. -# History commands do not work within a script. +# History commands disabled within a script. @@ -34242,7 +34696,7 @@ var=$(history); echo "$var" # $var is empty. of scripting. Think of them as a challenge, as an entertaining way to take you further along the stony path of UNIX wizardry. - On a small side street in a run-down section of Hoboken, New + On a dingy side street in a run-down section of Hoboken, New Jersey, there sits a nondescript squat two-story brick building with a inscription incised on a marble plate in its wall: Bash Scripting Hall of Fame. Inside, @@ -34550,7 +35004,10 @@ do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUMstdout or saving them to a file, along with the date and time the particular number set - was generated. + was generated. (If your script consistently generates + winning lottery numbers, then you can + retire on your earnings and leave shell scripting to those + of us who have to work for a living.) @@ -34586,6 +35043,14 @@ do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUM + + Banner + + Simulate the functionality of the deprecated banner command in a script. + + + Removing Inactive Accounts @@ -34602,10 +35067,10 @@ do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUMEnforcing Disk Quotas Write a script for a multi-user system that checks users' - disk usage. If a user surpasses the preset limit + disk usage. If a user surpasses a preset limit (100 MB, for example) in her /home/username directory, - then the script will automatically send her a warning + then the script automatically sends her a warning e-mail. The script will use the du and mail commands. As an option, @@ -34643,7 +35108,7 @@ do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUM~/TRASH directory for files older than 48 hours and permanently deletes them. (An better alternative might be to - have a second script handle this -- periodically invoked + have a second script handle this, periodically invoked by the cron daemon.) Extra credit: Write the script so it can handle files and directories Quadratic Equations - Solve a quadratic equation of the form + Solve a quadratic equation of the form Ax^2 + Bx + C = 0. Have a script take as arguments the coefficients, A, B, and C, @@ -34684,6 +35149,19 @@ do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUM + + Table of Logarithms + + Using the bc and printf commands, print out a + nicely-formatted table of eight-place natural logarithms + in the interval between 0.00 and 100.00, in steps of + .01. + Hint: bc requires the + option to load the math library. + + + Sum of Matching Numbers @@ -34692,7 +35170,7 @@ do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUM - Some examples of matching numbers are + Some examples of matching numbers are 42057, 74638, and 89515. @@ -34700,10 +35178,43 @@ do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUM Lucky Numbers - A "lucky number" is one whose individual digits add - up to 7, in successive additions. For example, 62431 is a - "lucky number" (6 + 2 + 4 + 3 + 1 = 16, 1 + 6 = 7). Find - all the "lucky numbers" between 1000 and 10000. + A lucky number is one whose + individual digits add up to 7, in successive additions. For + example, 62431 is a lucky number + (6 + 2 + 4 + 3 + 1 = 16, 1 + 6 = 7). Find all the + lucky numbers between 1000 and + 10000. + + + + + Craps + + Borrowing the ASCII graphics from , + write a script that plays the well-known gambling game of + craps. The script will accept bets + from one or more players, roll the dice, and keep track of + wins and losses, as well as of each player's bankroll. + + + + + Tic-tac-toe + + Write a script that plays the child's game of + tic-tac-toe against a human + player. The script will let the human choose whether + to take the first move. The script will follow + an optimal strategy, and therefore never lose. To simplify + matters, you may use ASCII graphics: + + o | x | + ---------- + | x | + ---------- + | o | + + Your move, human (row, column)? @@ -34988,8 +35499,9 @@ done Strip Comments Strip all comments from a shell script whose name - is specified on the command line. Note that the #! - line must not be stripped out. + is specified on the command line. Note that the #! line must not be stripped + out. @@ -35050,11 +35562,10 @@ done output the corresponding man page to stdout. The text file contains blocks of information under the standard man - page headings, i.e., NAME, - SYNOPSIS, DESCRIPTION, - etc. + page headings, i.e., NAME, SYNOPSIS, + DESCRIPTION, etc. - See . + is an instructive first step. @@ -35232,26 +35743,26 @@ mark --> park --> part --> past --> vast --> vase The Eighteenth Century French mathematician de Buffon - came up with a novel experiment. Repeatedly drop a - needle of length n onto a wooden floor + came up with a novel experiment. Repeatedly drop a needle + of length n onto a wooden floor composed of long and narrow parallel boards. The cracks separating the equal-width floorboards are a fixed distance - d apart. Keep track of the total drops and - the number of times the needle intersects a crack on the - floor. The ratio of these two quantities turns out to be - a fractional multiple of PI. + d apart. Keep track of the + total drops and the number of times the needle intersects + a crack on the floor. The ratio of these two quantities + turns out to be a fractional multiple of PI. In the spirit of , write a - script that runs a Monte Carlo simulation of Buffon's - Needle. To simplify matters, set the needle length - equal to the distance between the cracks, n = - d. + script that runs a Monte Carlo simulation of + Buffon's Needle. To simplify matters, + set the needle length equal to the distance between the + cracks, n = d. Hint: there are actually two critical variables: - the distance from the center of the needle to the crack - nearest to it, and the angle of the needle to that - crack. You may use bc to - handle the calculations. + the distance from the center of the needle to the nearest + crack, and the inclination angle of the needle to that crack. + You may use bc to handle + the calculations. @@ -35264,8 +35775,8 @@ mark --> park --> part --> past --> vast --> vase script. The Playfair Cipher encrypts text by substitution - of digrams (2-letter groupings). It is - traditional to use a 5 x 5 letter scrambled-alphabet + of digrams (2-letter groupings). + It is traditional to use a 5 x 5 letter scrambled-alphabet key square for the encryption and decryption. @@ -35290,23 +35801,26 @@ 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 +----------------------------------------------- + +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 +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. +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. @@ -35332,15 +35846,15 @@ just take the remaining two corners of the rectangle. Helen Fouche Gaines' classic work, ELEMENTARY CRYPTANALYSIS (1939), gives a -fairly detailed rundown on the Playfair Cipher and its solution methods. +fairly detailed description of the Playfair Cipher and its solution methods. This script will have three main sections - Generating the key square, + Generating the key square, based on a user-input keyword. - Encrypting a plaintext + Encrypting a plaintext message. Decrypting encrypted text. @@ -35358,9 +35872,9 @@ fairly detailed rundown on the Playfair Cipher and its solution methods.-- 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. + exercises. There are more appropriate ways to impress him with + your cleverness, such as submitting bugfixes and suggestions + for improving this book. @@ -35379,7 +35893,8 @@ fairly detailed rundown on the Playfair Cipher and its solution methods.Linux Documentation Project. + of the volunteers of the Linux + Documentation Project. Here is the e-mail to the LDP requesting permission to submit @@ -35661,6 +36176,11 @@ thegrendel@theriver.com 11 May 2008 GOLDENBERRY release: Minor update. + + + 21 Jul 2008 + ANGLEBERRY release: Minor update. + @@ -35672,12 +36192,12 @@ thegrendel@theriver.com Mirror Sites + url="http://thegrendel.150m.com/abs-guide-5.4.tar.bz2"> The latest update of this document, as an archived tarball including both the SGML source and rendered HTML, may be downloaded from the author's + url="http://personal.riverusers.com/~thegrendel/abs-guide-5.4.tar.bz2">author's home site. The main mirror site for this document is the A primer on CGI programming, using Bash. - Here's a simple CGI script to get you started. + Here is a simple CGI script to get you started. Print the server environment @@ -35739,15 +36259,15 @@ thegrendel@theriver.com 2000, by Mendel Cooper. The author also asserts copyright on all previous versions of this document. The author intends that this book be released - into the Public Domain after a period of 14 years, that is, in 2014. - In the early years of the American republic this was the duration - statutorily granted to a copyrighted work. + into the Public Domain after a period of 14 years from initial + publication, that is, in 2014. In the early years of the American + republic this was the duration statutorily granted to a + copyrighted work. This blanket copyright recognizes and protects the rights of all contributors to this document. - This document may only be distributed subject to the terms and conditions set forth in the Open Publication License (version 1.0 or later), +to use the materials within, or any portion thereof, in a patent or copyright +lawsuit against the Open Source community, its developers, its +distributors, or against any of its associated software or documentation +including, but not limited to, the Linux kernel, Open Office, Samba, +and Wine. You further waive the right to use any of the materials within +this book in testimony or depositions as a plaintiff's "expert witness" in +any lawsuit against the Open Source community, any of its developers, its +distributors, or any of its associated software or +documentation. These are very liberal terms, and they should not hinder any @@ -35881,10 +36402,10 @@ software or documentation. ASCII Table - In a book of this sort it is traditional to have an appendix - with an ASCII table. This book does not. Instead, here is a short - shell script that generates a complete ASCII table and writes it to - the file ASCII.txt. + In a book of this sort it is traditional to have an + ASCII table appendix. This book does not. Instead, here is a short + shell script that generates a complete ASCII table and writes it + to the file ASCII.txt. A script that generates an ASCII table diff --git a/LDP/guide/docbook/abs-guide/add-drive.sh b/LDP/guide/docbook/abs-guide/add-drive.sh index 37a68add..2bbeb4e9 100644 --- a/LDP/guide/docbook/abs-guide/add-drive.sh +++ b/LDP/guide/docbook/abs-guide/add-drive.sh @@ -38,4 +38,4 @@ chmod 777 $MOUNTPOINT # Makes new drive accessible to all users. # Add the following line to /etc/fstab. # /dev/hdb1 /mnt/newdisk ext2 defaults 1 1 -exit 0 +exit diff --git a/LDP/guide/docbook/abs-guide/allprofs.sh b/LDP/guide/docbook/abs-guide/allprofs.sh index aa4e6d7e..f9991ad1 100644 --- a/LDP/guide/docbook/abs-guide/allprofs.sh +++ b/LDP/guide/docbook/abs-guide/allprofs.sh @@ -1,5 +1,5 @@ #!/bin/bash -# allprofs.sh: print all user profiles +# allprofs.sh: Print all user profiles. # This script written by Heiner Steven, and modified by the document author. diff --git a/LDP/guide/docbook/abs-guide/arith-tests.sh b/LDP/guide/docbook/abs-guide/arith-tests.sh index a803b89a..8c79f47a 100644 --- a/LDP/guide/docbook/abs-guide/arith-tests.sh +++ b/LDP/guide/docbook/abs-guide/arith-tests.sh @@ -34,4 +34,16 @@ echo "Exit status of \"(( 1 / 0 ))\" is $?." # 1 # What would happen if it were removed? # Try removing it, then rerunning the script. +# ======================================= # + +# (( ... )) also useful in an if-then test. + +var1=5 +var2=4 + +if (( var1 > var2 )) +then #^ ^ Note: Not $var1, $var2. Why? + echo "$var1 is greater than $var2" +fi # 5 is greater than 4 + exit 0 diff --git a/LDP/guide/docbook/abs-guide/array-strops.sh b/LDP/guide/docbook/abs-guide/array-strops.sh index 5371a4c5..4ae3e765 100644 --- a/LDP/guide/docbook/abs-guide/array-strops.sh +++ b/LDP/guide/docbook/abs-guide/array-strops.sh @@ -1,10 +1,12 @@ #!/bin/bash # array-strops.sh: String operations on arrays. -# Script by Michael Zick. -# Used with permission. -# In general, any string operation in the ${name ... } notation -#+ can be applied to all string elements in an array +# Script by Michael Zick. +# Fixups: 05 May 08 +# Used in ABS Guide with permission. + +# In general, any string operation using the ${name ... } notation +#+ can be applied to all string elements in an array, #+ with the ${name[@] ... } or ${name[*] ...} notation. @@ -14,19 +16,20 @@ echo # Trailing Substring Extraction echo ${arrayZ[@]:0} # one two three four five five - # All elements. +# ^ All elements. echo ${arrayZ[@]:1} # two three four five five - # All elements following element[0]. +# ^ All elements following element[0]. echo ${arrayZ[@]:1:2} # two three - # Only the two elements after element[0]. +# ^ Only the two elements after element[0]. echo "-----------------------" -# Substring Removal -# Removes shortest match from front of string(s), -#+ where the substring is a regular expression. + +# Substring Removal + +# Removes shortest match from front of string(s). echo ${arrayZ[@]#f*r} # one two three five five # Applied to all elements of the array. @@ -51,54 +54,61 @@ echo "-----------------------" # Substring Replacement -# Replace first occurance of substring with replacement +# Replace first occurrence of substring with replacement. echo ${arrayZ[@]/fiv/XYZ} # one two three four XYZe XYZe - # Applied to all elements of the array. +# ^ ^^^ ^^^ Applied to all elements of the array. -# Replace all occurances of substring +# Replace all occurrences of substring. echo ${arrayZ[@]//iv/YY} # one two three four fYYe fYYe # Applied to all elements of the array. -# Delete all occurances of substring -# Not specifing a replacement means 'delete' +# Delete all occurrences of substring. +# Not specifing a replacement means 'delete.' echo ${arrayZ[@]//fi/} # one two three four ve ve - # Applied to all elements of the array. +# ^^ Applied to all elements of the array. -# Replace front-end occurances of substring +# Replace front-end occurrences of substring. echo ${arrayZ[@]/#fi/XY} # one two three four XYve XYve - # Applied to all elements of the array. +# ^ Applied to all elements of the array. -# Replace back-end occurances of substring +# Replace back-end occurrences of substring. echo ${arrayZ[@]/%ve/ZZ} # one two three four fiZZ fiZZ - # Applied to all elements of the array. +# ^ Applied to all elements of the array. echo ${arrayZ[@]/%o/XX} # one twXX three four five five - # Why? +# ^ Why? echo "-----------------------" -# Before reaching for awk (or anything else) -- -# Recall: -# $( ... ) is command substitution. -# Functions run as a sub-process. -# Functions write their output to stdout. -# Assignment reads the function's stdout. -# The name[@] notation specifies a "for-each" operation. - newstr() { echo -n "!!!" } echo ${arrayZ[@]/%e/$(newstr)} +# ^ ^^^^^^^^^ # on!!! two thre!!! four fiv!!! fiv!!! -# Q.E.D: The replacement action is an 'assignment.' +# Q.E.D: The replacement action is, in effect, an 'assignment.' + +echo "-----------------------" # Accessing the "For-Each" echo ${arrayZ[@]//*/$(newstr optional_arguments)} -# Now, if Bash would just pass the matched string as $0 +# !!! !!! !!! !!! !!! !!! + +# Now, if Bash would only pass the matched string #+ to the function being called . . . echo exit 0 + +# Before reaching for a Big Hammer -- awk, Perl, or anything else -- +# recall: +# $( ... ) is command substitution. +# A function runs as a sub-process. +# A function writes its output to stdout. +# Assignment, in conjunction with 'echo' and command substitution, +#+ can read a function's stdout. +# The name[@] notation specifies a "for-each" operation. +# Bash is more powerful than you think! diff --git a/LDP/guide/docbook/abs-guide/bashandperl.sh b/LDP/guide/docbook/abs-guide/bashandperl.sh index 718d8eaf..ce2dd49f 100644 --- a/LDP/guide/docbook/abs-guide/bashandperl.sh +++ b/LDP/guide/docbook/abs-guide/bashandperl.sh @@ -10,7 +10,8 @@ exit 0 # ======================================================= #!/usr/bin/perl -# This part of the script must be invoked with -x option. +# This part of the script must be invoked with +# perl -x bashandperl.sh print "Greetings from the Perl part of the script.\n"; # More Perl commands may follow here. diff --git a/LDP/guide/docbook/abs-guide/behead.sh b/LDP/guide/docbook/abs-guide/behead.sh index ab57c113..cff5b039 100644 --- a/LDP/guide/docbook/abs-guide/behead.sh +++ b/LDP/guide/docbook/abs-guide/behead.sh @@ -1,7 +1,8 @@ #! /bin/sh # Strips off the header from a mail/News message i.e. till the first -# empty line -# Mark Moraes, University of Toronto +# empty line. +# Author: Mark Moraes, University of Toronto +# See the included file "Moraes-COPYRIGHT" for copyright info. # ==> These comments added by author of this document. diff --git a/LDP/guide/docbook/abs-guide/brownian.sh b/LDP/guide/docbook/abs-guide/brownian.sh index 1428280e..155cdaa0 100644 --- a/LDP/guide/docbook/abs-guide/brownian.sh +++ b/LDP/guide/docbook/abs-guide/brownian.sh @@ -77,7 +77,7 @@ Move () { # Move one unit right / left, or stay put. Play () { # Single pass (inner loop). i=0 -while [ "$i" -lt "$ROWS" ] # One event per row. +while [ "$i" -lt "$ROWS" ] # One event per row. do Move ((i++)); diff --git a/LDP/guide/docbook/abs-guide/c-vars.sh b/LDP/guide/docbook/abs-guide/c-vars.sh index 31e2de3e..37a32b5b 100644 --- a/LDP/guide/docbook/abs-guide/c-vars.sh +++ b/LDP/guide/docbook/abs-guide/c-vars.sh @@ -1,31 +1,32 @@ #!/bin/bash -# Manipulating a variable, C-style, using the ((...)) construct. +# c-vars.sh +# Manipulating a variable, C-style, using the (( ... )) construct. echo (( a = 23 )) # Setting a value, C-style, #+ with spaces on both sides of the "=". -echo "a (initial value) = $a" +echo "a (initial value) = $a" # 23 (( a++ )) # Post-increment 'a', C-style. -echo "a (after a++) = $a" +echo "a (after a++) = $a" # 24 (( a-- )) # Post-decrement 'a', C-style. -echo "a (after a--) = $a" +echo "a (after a--) = $a" # 23 (( ++a )) # Pre-increment 'a', C-style. -echo "a (after ++a) = $a" +echo "a (after ++a) = $a" # 24 (( --a )) # Pre-decrement 'a', C-style. -echo "a (after --a) = $a" +echo "a (after --a) = $a" # 23 echo ######################################################## # Note that, as in C, pre- and post-decrement operators -#+ have slightly different side-effects. +#+ have different side-effects. n=1; let --n && echo "True" || echo "False" # False n=1; let n-- && echo "True" || echo "False" # True @@ -37,8 +38,8 @@ echo (( t = a<45?7:11 )) # C-style trinary operator. # ^ ^ ^ -echo "If a < 45, then t = 7, else t = 11." -echo "t = $t " # Yes! +echo "If a < 45, then t = 7, else t = 11." # a = 23 +echo "t = $t " # t = 7 echo @@ -48,12 +49,12 @@ echo # ----------------- # Chet Ramey seems to have snuck a bunch of undocumented C-style #+ constructs into Bash (actually adapted from ksh, pretty much). -# In the Bash docs, Ramey calls ((...)) shell arithmetic, +# In the Bash docs, Ramey calls (( ... )) shell arithmetic, #+ but it goes far beyond that. -# Sorry, Chet, the secret is now out. +# Sorry, Chet, the secret is out. -# See also "for" and "while" loops using the ((...)) construct. +# See also "for" and "while" loops using the (( ... )) construct. -# These work only with Bash, version 2.04 or later. +# These work only with version 2.04 or later of Bash. -exit 0 +exit diff --git a/LDP/guide/docbook/abs-guide/colm.sh b/LDP/guide/docbook/abs-guide/colm.sh index 07173b51..a043153f 100644 --- a/LDP/guide/docbook/abs-guide/colm.sh +++ b/LDP/guide/docbook/abs-guide/colm.sh @@ -1,9 +1,11 @@ #!/bin/bash -# This is a slight modification of the example file in the "column" man page. +# colms.sh +# A minor modification of the example file in the "column" man page. (printf "PERMISSIONS LINKS OWNER GROUP SIZE MONTH DAY HH:MM PROG-NAME\n" \ ; ls -l | sed 1d) | column -t +# ^^^^^^ ^^ # The "sed 1d" in the pipe deletes the first line of output, #+ which would be "total N", diff --git a/LDP/guide/docbook/abs-guide/connect-stat.sh b/LDP/guide/docbook/abs-guide/connect-stat.sh index 783afd66..c2928188 100644 --- a/LDP/guide/docbook/abs-guide/connect-stat.sh +++ b/LDP/guide/docbook/abs-guide/connect-stat.sh @@ -5,7 +5,9 @@ PROCFILENAME=status # Where to look. NOTCONNECTED=65 INTERVAL=2 # Update every 2 seconds. -pidno=$( ps ax | grep -v "ps ax" | grep -v grep | grep $PROCNAME | awk '{ print $1 }' ) +pidno=$( ps ax | grep -v "ps ax" | grep -v grep | grep $PROCNAME | +awk '{ print $1 }' ) + # Finding the process number of 'pppd', the 'ppp daemon'. # Have to filter out the process lines generated by the search itself. # diff --git a/LDP/guide/docbook/abs-guide/cw-solver.sh b/LDP/guide/docbook/abs-guide/cw-solver.sh index f048bf6e..cf3c22c6 100644 --- a/LDP/guide/docbook/abs-guide/cw-solver.sh +++ b/LDP/guide/docbook/abs-guide/cw-solver.sh @@ -1,5 +1,6 @@ #!/bin/bash # cw-solver.sh +# This is actually a wrapper around a one-liner (line 46). # Crossword puzzle and anagramming word game solver. # You know *some* of the letters in the word you're looking for, @@ -34,7 +35,7 @@ then #+ as a command-line argument . . . echo "The x's represent known letters," echo "and the periods are unknown letters (blanks)." echo "Letters and periods can be in any position." - echo "For example, try: cw-solver.sh w...i....n" + echo "For example, try: sh cw-solver.sh w...i....n" echo exit $E_NOPATT fi @@ -49,7 +50,7 @@ grep ^"$1"$ "$DICT" # Yes, only one line! # From _Stupid Grep Tricks_, vol. 1, #+ a book the ABS Guide author may yet get around -#+ to writing one of these days . . . +#+ to writing . . . one of these days . . . # =============================================== echo @@ -58,9 +59,8 @@ exit $? # Script terminates here. # If there are too many words generated, #+ redirect the output to a file. -cw-solver w...i....n +$ sh cw-solver.sh w...i....n -twichildren wellington workingman workingmen diff --git a/LDP/guide/docbook/abs-guide/empty-array.sh b/LDP/guide/docbook/abs-guide/empty-array.sh index 87d40263..145532c6 100644 --- a/LDP/guide/docbook/abs-guide/empty-array.sh +++ b/LDP/guide/docbook/abs-guide/empty-array.sh @@ -2,7 +2,8 @@ # empty-array.sh # Thanks to Stephane Chazelas for the original example, -#+ and to Michael Zick and Omair Eshkenazi for extending it. +#+ and to Michael Zick, Omair Eshkenazi, for extending it. +# And to Nathan Coulter for clarifications and corrections. # An empty array is not the same as an array with empty elements. @@ -12,6 +13,7 @@ array2=( ) # No elements . . . "array2" is empty. array3=( ) # What about this array? + echo ListArray() { @@ -54,8 +56,8 @@ array3[${#array3[*]}]="new2" ListArray -# When extended as above; arrays are 'stacks' -# The above is the 'push' +# When extended as above, arrays are 'stacks' ... +# Above is the 'push' ... # The stack 'height' is: height=${#array2[@]} echo @@ -71,7 +73,7 @@ echo "New stack height for array2 = $height" ListArray # List only 2nd and 3rd elements of array0. -from=1 # Zero-based numbering. +from=1 # Zero-based numbering. to=2 array3=( ${array0[@]:1:2} ) echo @@ -108,25 +110,47 @@ echo "Elements in array8: ${array8[@]}" # The string operations are performed on #+ each of the elements in var[@] in succession. -# Therefore : Bash supports string vector operations -#+ if the result is a zero length string, +# Therefore : Bash supports string vector operations. +# If the result is a zero length string, #+ that element disappears in the resulting assignment. +# However, if the expansion is in quotes, the null elements remain. + +# Michael Zick: Question, are those strings hard or soft quotes? +# Nathan Coulter: There is no such thing as "soft quotes." +# What's really happening is that +#+ the pattern matching happens after all the other expansions of [word] +#+ in cases like ${parameter#word}. -# Question, are those strings hard or soft quotes? zap='new*' array9=( ${array0[@]/$zap/} ) echo +echo "Number of elements in array9: ${#array9[@]}" +array9=( "${array0[@]/$zap/}" ) echo "Elements in array9: ${array9[@]}" +# This time the null elements remain. +echo "Number of elements in array9: ${#array9[@]}" -# Just when you thought you where still in Kansas . . . -array10=( ${array0[@]#$zap} ) + +# Just when you thought you were still in Kansas . . . +array10=( ${array0[@]#"$zap"} ) echo echo "Elements in array10: ${array10[@]}" +# But, the asterisk in zap won't be interpreted if quoted. +array10=( ${array0[@]#"$zap"} ) +echo +echo "Elements in array10: ${array10[@]}" +# Well, maybe we _are_ still in Kansas . . . +# (Revisions to above code block by Nathan Coulter.) -# Compare array7 with array10. -# Compare array8 with array9. -# Answer: must be soft quotes. +# Compare array7 with array10. +# Compare array8 with array9. -exit 0 +# Reiterating: No such thing as soft quotes! +# Nathan Coulter's explains: +# Pattern matching of 'word' in ${parameter#word} is done after +#+ parameter expansion and *before* quote removal. +# In the normal case, pattern matching is done *after* quote removal. + +exit diff --git a/LDP/guide/docbook/abs-guide/ex10.sh b/LDP/guide/docbook/abs-guide/ex10.sh index dd57b9bd..bfadd790 100644 --- a/LDP/guide/docbook/abs-guide/ex10.sh +++ b/LDP/guide/docbook/abs-guide/ex10.sh @@ -10,7 +10,7 @@ echo "Testing \"0\"" if [ 0 ] # zero then echo "0 is true." -else +else # Or else ... echo "0 is false." fi # 0 is true. diff --git a/LDP/guide/docbook/abs-guide/ex14.sh b/LDP/guide/docbook/abs-guide/ex14.sh index 77a42c4a..dd0f3836 100644 --- a/LDP/guide/docbook/abs-guide/ex14.sh +++ b/LDP/guide/docbook/abs-guide/ex14.sh @@ -1,18 +1,18 @@ #!/bin/bash # zmore -#View gzipped files with 'more' +# View gzipped files with 'more' filter. -NOARGS=65 -NOTFOUND=66 -NOTGZIP=67 +E_NOARGS=65 +E_NOTFOUND=66 +E_NOTGZIP=67 if [ $# -eq 0 ] # same effect as: if [ -z "$1" ] # $1 can exist, but be empty: zmore "" arg2 arg3 then echo "Usage: `basename $0` filename" >&2 # Error message to stderr. - exit $NOARGS + exit $E_NOARGS # Returns 65 as exit status of script (error code). fi @@ -20,24 +20,22 @@ filename=$1 if [ ! -f "$filename" ] # Quoting $filename allows for possible spaces. then - echo "File $filename not found!" >&2 - # Error message to stderr. - exit $NOTFOUND + echo "File $filename not found!" >&2 # Error message to stderr. + exit $E_NOTFOUND fi if [ ${filename##*.} != "gz" ] # Using bracket in variable substitution. then echo "File $1 is not a gzipped file!" - exit $NOTGZIP + exit $E_NOTGZIP fi zcat $1 | more -# Uses the filter 'more.' -# May substitute 'less', if desired. - +# Uses the 'more' filter. +# May substitute 'less' if desired. exit $? # Script returns exit status of pipe. -# Actually "exit $?" is unnecessary, as the script will, in any case, -# return the exit status of the last command executed. +# Actually "exit $?" is unnecessary, as the script will, in any case, +#+ return the exit status of the last command executed. diff --git a/LDP/guide/docbook/abs-guide/ex27.sh b/LDP/guide/docbook/abs-guide/ex27.sh index 4b3b727b..ca1ae001 100644 --- a/LDP/guide/docbook/abs-guide/ex27.sh +++ b/LDP/guide/docbook/abs-guide/ex27.sh @@ -12,4 +12,19 @@ do echo done +# ------------------------------------------- # + +# As with "for" and "while" loops, +#+ an "until" loop permits C-like test constructs. + +LIMIT=10 +var=0 + +until (( var > LIMIT )) +do # ^^ ^ ^ ^^ No brackets, no $ prefixing variables. + echo -n "$var " + (( var++ )) +done # 0 1 2 3 4 5 6 7 8 9 10 + + exit 0 diff --git a/LDP/guide/docbook/abs-guide/ex3.sh b/LDP/guide/docbook/abs-guide/ex3.sh index 954c995e..1ce265cc 100644 --- a/LDP/guide/docbook/abs-guide/ex3.sh +++ b/LDP/guide/docbook/abs-guide/ex3.sh @@ -1,11 +1,11 @@ #!/bin/bash -# This is a simple script that removes blank lines from a file. +# This simple script removes blank lines from a file. # No argument checking. # # You might wish to add something like: # -# E_NOARGS=65 +# E_NOARGS=85 # if [ -z "$1" ] # then # echo "Usage: `basename $0` target-file" @@ -13,14 +13,15 @@ # fi + +sed -e /^$/d "$1" # Same as # sed -e '/^$/d' filename # 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, +# '^' indicates the beginning of line, '$' the end. +# This matches lines with nothing between the beginning and the end -- #+ blank lines. # The 'd' is the delete command. @@ -30,4 +31,4 @@ sed -e /^$/d "$1" # Note that this script doesn't actually change the target file. # If you need to do that, redirect its output. -exit 0 +exit diff --git a/LDP/guide/docbook/abs-guide/ex4.sh b/LDP/guide/docbook/abs-guide/ex4.sh index d88fd341..dc9b462c 100644 --- a/LDP/guide/docbook/abs-guide/ex4.sh +++ b/LDP/guide/docbook/abs-guide/ex4.sh @@ -1,11 +1,12 @@ #!/bin/bash -# "subst", a script that substitutes one pattern for +# subst.sh: a script that substitutes one pattern for #+ another in a file, -#+ i.e., "subst Smith Jones letter.txt". +#+ i.e., "sh subst.sh Smith Jones letter.txt". +# Jones replaces Smith. ARGS=3 # Script requires 3 arguments. -E_BADARGS=65 # Wrong number of arguments passed to script. +E_BADARGS=85 # Wrong number of arguments passed to script. if [ $# -ne "$ARGS" ] # Test number of arguments to script (always a good idea). @@ -26,16 +27,15 @@ else fi -# Here is where the heavy work gets done. - # ----------------------------------------------- +# Here is where the heavy work gets done. sed -e "s/$old_pattern/$new_pattern/g" $file_name # ----------------------------------------------- # 's' is, of course, the substitute command in sed, #+ and /pattern/ invokes address matching. -# The "g", or global flag causes substitution for *every* +# The 'g,' or global flag causes substitution for EVERY #+ occurence of $old_pattern on each line, not just the first. -# Read the literature on 'sed' for an in-depth explanation. +# Read the 'sed' docs for an in-depth explanation. -exit 0 # Successful invocation of the script returns 0. +exit $? diff --git a/LDP/guide/docbook/abs-guide/ex46.sh b/LDP/guide/docbook/abs-guide/ex46.sh index eed53215..0d614ac1 100644 --- a/LDP/guide/docbook/abs-guide/ex46.sh +++ b/LDP/guide/docbook/abs-guide/ex46.sh @@ -24,6 +24,26 @@ let "a %= 8" # Equivalent to let "a = a % 8" echo "270 modulo 8 = $a (270 / 8 = 33, remainder $a)" # 6 + +# Does "let" permit C-style operators? +# Yes, just as the (( ... )) double-parentheses construct does. + +let a++ # C-style (post) increment. +echo "6++ = $a" # 6++ = 7 +let a-- # C-style decrement. +echo "7-- = $a" # 7-- = 6 +# Of course, ++a, etc., also allowed . . . echo -exit 0 + +# Trinary operator. + +# Note that $a is 6, see above. +let "t = a<7?7:11" # True +echo $t # 7 + +let a++ +let "t = a<7?7:11" # False +echo $t # 11 + +exit diff --git a/LDP/guide/docbook/abs-guide/ex61.sh b/LDP/guide/docbook/abs-guide/ex61.sh index 5447bc23..481e9acc 100644 --- a/LDP/guide/docbook/abs-guide/ex61.sh +++ b/LDP/guide/docbook/abs-guide/ex61.sh @@ -39,10 +39,12 @@ do done return $number - # Exercise: - # -------- - # Explain how this function works. - # Hint: division by successive subtraction. + # Exercises: + # --------- + # 1) Explain how this function works. + # Hint: division by successive subtraction. + # 2) Extend to range of the function. + # Hint: use "echo" and command-substitution capture. } @@ -63,7 +65,9 @@ num=$? to_roman $num 4 IV num=$? to_roman $num 1 I +# Successive calls to conversion function! +# Is this really necessary??? Can it be simplified? echo -exit 0 +exit diff --git a/LDP/guide/docbook/abs-guide/ex64.sh b/LDP/guide/docbook/abs-guide/ex64.sh index bb8b726e..c9dcb1e4 100644 --- a/LDP/guide/docbook/abs-guide/ex64.sh +++ b/LDP/guide/docbook/abs-guide/ex64.sh @@ -1,5 +1,5 @@ #!/bin/bash -# "and list" +# and list if [ ! -z "$1" ] && echo "Argument #1 = $1" && [ ! -z "$2" ] \ && echo "Argument #2 = $2" diff --git a/LDP/guide/docbook/abs-guide/ex65.sh b/LDP/guide/docbook/abs-guide/ex65.sh index f9c26b30..c00d2a4f 100644 --- a/LDP/guide/docbook/abs-guide/ex65.sh +++ b/LDP/guide/docbook/abs-guide/ex65.sh @@ -1,9 +1,9 @@ #!/bin/bash -# delete.sh, not-so-cunning file deletion utility. +# delete.sh, a not-so-cunning file deletion utility. # Usage: delete filename -E_BADARGS=65 +E_BADARGS=85 if [ -z "$1" ] then @@ -25,4 +25,4 @@ Cowardly refusing to delete a nonexistent file." # Note logic inversion above. # AND LIST executes on true, OR LIST on false. -exit 0 +exit $? diff --git a/LDP/guide/docbook/abs-guide/ex67.sh b/LDP/guide/docbook/abs-guide/ex67.sh index c208b1c8..9490cc1d 100644 --- a/LDP/guide/docbook/abs-guide/ex67.sh +++ b/LDP/guide/docbook/abs-guide/ex67.sh @@ -27,6 +27,7 @@ index=0 while [ "$index" -lt "$element_count" ] do # List all the elements in the array. echo ${colors[$index]} + # ${colors[index]} also works because it's within ${ ... } brackets. let "index = $index + 1" # Or: # index+=1 diff --git a/LDP/guide/docbook/abs-guide/ex68a.sh b/LDP/guide/docbook/abs-guide/ex68a.sh index bcd9e6b4..d47524f9 100644 --- a/LDP/guide/docbook/abs-guide/ex68a.sh +++ b/LDP/guide/docbook/abs-guide/ex68a.sh @@ -21,7 +21,7 @@ Primes[i=1]='' # 1 is not a prime. until (( ( i += 1 ) > (${UPPER_LIMIT}/i) )) # Need check only ith-way. do # Why? if ((${Primes[t=i*(i-1), i]})) - # Obscure, but instructive, use of numeric eval in subscript. + # Obscure, but instructive, use of arithmetic expansion in subscript. then until (( ( t += i ) > ${UPPER_LIMIT} )) do Primes[t]=; done diff --git a/LDP/guide/docbook/abs-guide/ex73.sh b/LDP/guide/docbook/abs-guide/ex73.sh index dae42094..b3e9e3ca 100644 --- a/LDP/guide/docbook/abs-guide/ex73.sh +++ b/LDP/guide/docbook/abs-guide/ex73.sh @@ -45,6 +45,7 @@ echo "Creating swap file of size $blocks blocks (KB)." dd if=/dev/zero of=$FILE bs=$BLOCKSIZE count=$blocks # Zero out file. mkswap $FILE $blocks # Designate it a swap file. swapon $FILE # Activate swap file. +retcode=$? # Everything worked? # Note that if one or more of these commands fails, #+ then it could cause nasty problems. ###################################################################### @@ -59,4 +60,4 @@ swapon $FILE # Activate swap file. echo "Swap file created and activated." -exit $SUCCESS +exit $retcode diff --git a/LDP/guide/docbook/abs-guide/ex77.sh b/LDP/guide/docbook/abs-guide/ex77.sh index 8fb6dd29..c38e0e92 100644 --- a/LDP/guide/docbook/abs-guide/ex77.sh +++ b/LDP/guide/docbook/abs-guide/ex77.sh @@ -8,9 +8,11 @@ echo $'Ringing bell 3 times \a \a \a' # May only ring once with certain terminals. + # Or ... + # May not ring at all, depending on terminal settings. echo $'Three form feeds \f \f \f' echo $'10 newlines \n\n\n\n\n\n\n\n\n\n' echo $'\102\141\163\150' # Bash - # Octal equivalent of characters. + # Octal equivalent of characters. -exit 0 +exit diff --git a/LDP/guide/docbook/abs-guide/ex78.sh b/LDP/guide/docbook/abs-guide/ex78.sh index e8ceb096..5b22270d 100644 --- a/LDP/guide/docbook/abs-guide/ex78.sh +++ b/LDP/guide/docbook/abs-guide/ex78.sh @@ -26,3 +26,5 @@ echo "Value of t changed to ${!t}" # 387 #+ would have been nice. Sigh. exit 0 + +# See also, ind-ref.sh example. diff --git a/LDP/guide/docbook/abs-guide/fifo.sh b/LDP/guide/docbook/abs-guide/fifo.sh index 6838df3c..f8cf1d27 100644 --- a/LDP/guide/docbook/abs-guide/fifo.sh +++ b/LDP/guide/docbook/abs-guide/fifo.sh @@ -11,7 +11,7 @@ # make sure /pipe really is a pipe and not a plain file rm -rf /pipe - mkfifo /pipe # ==> Create a "named pipe", named "/pipe". + mkfifo /pipe # ==> Create a "named pipe", named "/pipe" ... # ==> 'su xyz' runs commands as user "xyz". # ==> 'ssh' invokes secure shell (remote login client). diff --git a/LDP/guide/docbook/abs-guide/for-loopc.sh b/LDP/guide/docbook/abs-guide/for-loopc.sh index 9440a928..2ae5e74c 100644 --- a/LDP/guide/docbook/abs-guide/for-loopc.sh +++ b/LDP/guide/docbook/abs-guide/for-loopc.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Two ways to count up to 10. +# Multiple ways to count up to 10. echo @@ -13,6 +13,27 @@ echo; echo # +==========================================+ +# Using "seq" ... +for a in `seq 10` +do + echo -n "$a " +done + +echo; echo + +# +==========================================+ + +# Using brace expansion ... +# Bash, version 3+. +for a in {1..10} +do + echo -n "$a " +done + +echo; echo + +# +==========================================+ + # Now, let's do the same, using C-like syntax. LIMIT=10 @@ -28,8 +49,8 @@ echo; echo # Let's use the C "comma operator" to increment two variables simultaneously. -for ((a=1, b=1; a <= LIMIT ; a++, b++)) # The comma chains together operations. -do +for ((a=1, b=1; a <= LIMIT ; a++, b++)) +do # The comma chains together operations. echo -n "$a-$b " done diff --git a/LDP/guide/docbook/abs-guide/ftpget.sh b/LDP/guide/docbook/abs-guide/ftpget.sh index 709660e8..6b8b53ce 100644 --- a/LDP/guide/docbook/abs-guide/ftpget.sh +++ b/LDP/guide/docbook/abs-guide/ftpget.sh @@ -106,3 +106,6 @@ rm -f ${TMPFILE} # ==> --------- # ==> 1) Add error checking. # ==> 2) Add bells & whistles. + +# See the included file "Moraes-COPYRIGHT" for copyright info. +#+ on this script. diff --git a/LDP/guide/docbook/abs-guide/getopt-simple.sh b/LDP/guide/docbook/abs-guide/getopt-simple.sh index 0c4aa10c..868dc692 100644 --- a/LDP/guide/docbook/abs-guide/getopt-simple.sh +++ b/LDP/guide/docbook/abs-guide/getopt-simple.sh @@ -29,7 +29,7 @@ getopt_simple $* echo "test is '$test'" echo "test2 is '$test2'" -exit 0 +exit 0 # See also, UseGetOpt.sh, a modified versio of this script. --- @@ -42,3 +42,4 @@ Processing parameter of: '/test2=value2' Parameter: 'test2', value: 'value2' test is 'value1' test2 is 'value2' + diff --git a/LDP/guide/docbook/abs-guide/grp.sh b/LDP/guide/docbook/abs-guide/grp.sh index 0031f0ee..2023aaf7 100644 --- a/LDP/guide/docbook/abs-guide/grp.sh +++ b/LDP/guide/docbook/abs-guide/grp.sh @@ -1,7 +1,7 @@ #!/bin/bash -# grp.sh: Very crude reimplementation of 'grep'. +# grp.sh: Rudimentary reimplementation of grep. -E_BADARGS=65 +E_BADARGS=85 if [ -z "$1" ] # Check for argument to script. then @@ -18,7 +18,7 @@ do if [ ! -z "$output" ] # What happens if "$output" is not quoted? then echo -n "$file: " - echo $output + echo "$output" fi # sed -ne "/$1/s|^|${file}: |p" is equivalent to above. echo diff --git a/LDP/guide/docbook/abs-guide/hexconvert.sh b/LDP/guide/docbook/abs-guide/hexconvert.sh index fe2062a6..a16b15af 100644 --- a/LDP/guide/docbook/abs-guide/hexconvert.sh +++ b/LDP/guide/docbook/abs-guide/hexconvert.sh @@ -1,16 +1,14 @@ #!/bin/bash # hexconvert.sh: Convert a decimal number to hexadecimal. -E_NOARGS=65 # Command-line arg missing. +E_NOARGS=85 # Command-line arg missing. BASE=16 # Hexadecimal. if [ -z "$1" ] -then +then # Need a command line argument. echo "Usage: $0 number" exit $E_NOARGS - # Need a command line argument. -fi -# Exercise: add argument validity checking. +fi # Exercise: add argument validity checking. hexcvt () @@ -22,12 +20,12 @@ then fi echo ""$1" "$BASE" o p" | dc -# "o" sets radix (numerical base) of output. -# "p" prints the top of stack. -# See 'man dc' for other options. +# o sets radix (numerical base) of output. +# p prints the top of stack. +# For other options: 'man dc' ... return } hexcvt "$1" -exit 0 +exit diff --git a/LDP/guide/docbook/abs-guide/homework.sh b/LDP/guide/docbook/abs-guide/homework.sh index 78db4635..94c182d0 100644 --- a/LDP/guide/docbook/abs-guide/homework.sh +++ b/LDP/guide/docbook/abs-guide/homework.sh @@ -6,7 +6,7 @@ # License: Public Domain # This script may be turned in to your instructor -#+ in fulfillment of ALL Bash scripting homework assignments. +#+ in fulfillment of ALL shell scripting homework assignments. # It's sparsely commented, but you, the student, can easily remedy that. # The script author repudiates all responsibility! @@ -73,14 +73,14 @@ b_r for i in $(seq 0 $MAXL) do - p_l "${L[i]}" - if [[ "$i" -eq "$P1" || "$i" -eq "$P2" || "$i" -eq "$P3" ]] - then - cr - elif [[ "$i" -eq "$PP1" || "$i" -eq "$PP2" ]] - then - cr; cr -fi + p_l "${L[i]}" + if [[ "$i" -eq "$P1" || "$i" -eq "$P2" || "$i" -eq "$P3" ]] + then + cr + elif [[ "$i" -eq "$PP1" || "$i" -eq "$PP2" ]] + then + cr; cr + fi done restore @@ -90,6 +90,7 @@ echo exit $E_LZY -# An example of an obfuscated script that is difficult to understand, -#+ and frustrating to maintain. -# In your career as a sysadmin, you'll run into these all too often. +# A typical example of an obfuscated script that is difficult +#+ to understand, and frustrating to maintain. +# In your career as a sysadmin, you'll run into these critters +#+ all too often. diff --git a/LDP/guide/docbook/abs-guide/ifs.sh b/LDP/guide/docbook/abs-guide/ifs.sh index 7438760d..10871806 100644 --- a/LDP/guide/docbook/abs-guide/ifs.sh +++ b/LDP/guide/docbook/abs-guide/ifs.sh @@ -1,4 +1,6 @@ #!/bin/bash +# ifs.sh + # $IFS treats whitespace differently than other characters. output_args_one_per_line() diff --git a/LDP/guide/docbook/abs-guide/ind-ref.sh b/LDP/guide/docbook/abs-guide/ind-ref.sh index f7909d21..476558aa 100644 --- a/LDP/guide/docbook/abs-guide/ind-ref.sh +++ b/LDP/guide/docbook/abs-guide/ind-ref.sh @@ -2,6 +2,27 @@ # ind-ref.sh: Indirect variable referencing. # Accessing the contents of the contents of a variable. +# First, let's fool around a little. + +var=23 + +echo "\$var = $var" # $var = 23 +# So far, everything as expected. But ... + +echo "\$\$var = $$var" # $$var = 4570var +# Not meaningful. The contents of a memory location pointed to? +# Not useful at this point. + +echo "\\\$\$var = \$$var" # \$$var = $23 +# As expected. The first $ is escaped and pasted on to +#+ the value of var ($var = 23 ). +# Meaningful, but still not useful. + +# Now, let's start over and do it the right way. + +# ============================================== # + + a=letter_of_alphabet # Variable "a" holds the name of another variable. letter_of_alphabet=z @@ -11,8 +32,14 @@ echo echo "a = $a" # a = letter_of_alphabet # Indirect reference. -eval a=\$$a -echo "Now a = $a" # Now a = z + eval a=\$$a +# ^^^ Forcing an eval(uation), and ... +# ^ Escaping the first $ ... +# ------------------------------------------------------------------------ +# The 'eval' forces an update of $a, sets it to the updated value of \$$a. +# So, we see why 'eval' so often shows up in indirect reference notation. +# ------------------------------------------------------------------------ + echo "Now a = $a" # Now a = z echo @@ -36,6 +63,7 @@ echo "\"table_cell_3\" now $table_cell_3" echo -n "dereferenced \"t\" now "; eval echo \$$t # "eval" takes the two arguments "echo" and "\$$t" (set equal to $table_cell_3) + echo # (Thanks, Stephane Chazelas, for clearing up the above behavior.) diff --git a/LDP/guide/docbook/abs-guide/int-or-string.sh b/LDP/guide/docbook/abs-guide/int-or-string.sh index e8e26ab1..9a7f59bf 100644 --- a/LDP/guide/docbook/abs-guide/int-or-string.sh +++ b/LDP/guide/docbook/abs-guide/int-or-string.sh @@ -1,5 +1,5 @@ #!/bin/bash -# int-or-string.sh: Integer or string? +# int-or-string.sh a=2334 # Integer. let "a += 1" diff --git a/LDP/guide/docbook/abs-guide/life.sh b/LDP/guide/docbook/abs-guide/life.sh index c04c5a21..34fd51ce 100644 --- a/LDP/guide/docbook/abs-guide/life.sh +++ b/LDP/guide/docbook/abs-guide/life.sh @@ -1,27 +1,27 @@ #!/bin/bash # life.sh: "Life in the Slow Lane" -# Version 2: Patched by Daniel Albers -#+ to allow non-square grids as input. +# Version 0.2: Patched by Daniel Albers +#+ to allow non-square grids as input. # ##################################################################### # # This is the Bash script version of John Conway's "Game of Life". # # "Life" is a simple implementation of cellular automata. # # --------------------------------------------------------------------- # -# On a rectangular grid, let each "cell" be either "living" or "dead". # +# On a rectangular grid, let each "cell" be either "living" or "dead." # # Designate a living cell with a dot, and a dead one with a blank space.# # Begin with an arbitrarily drawn dot-and-blank grid, # #+ and let this be the starting generation, "generation 0." # # Determine each successive generation by the following rules: # -# 1) Each cell has 8 neighbors, the adjoining cells # -#+ left, right, top, bottom, and the 4 diagonals. # +# 1) Each cell has 8 neighbors, the adjoining cells # +#+ left, right, top, bottom, and the 4 diagonals. # # # # 123 # -# 4*5 The * is the cell in question. # +# 4*5 The * is the cell under consideration. # # 678 # # # # 2) A living cell with either 2 or 3 living neighbors remains alive. # SURVIVE=2 # -# 3) A dead cell with 3 living neighbors becomes alive (a "birth"). # +# 3) A dead cell with 3 living neighbors comes alive (a "birth"). # BIRTH=3 # # 4) All other cases result in a dead cell for the next generation. # # ##################################################################### # @@ -38,7 +38,7 @@ fi ############################################ # Abort script if "startfile" not specified #+ and -#+ "gen0" not present. +#+ default file "gen0" not present. E_NOSTARTFILE=68 @@ -52,11 +52,11 @@ fi ALIVE1=. DEAD1=_ - # Represent living and "dead" cells in the start-up file. + # Represent living and dead cells in the start-up file. # ---------------------------------------------------------- # # This script uses a 10 x 10 grid (may be increased, -#+ but a large grid will will cause very slow execution). +#+ but a large grid will slow execution). ROWS=10 COLS=10 # Change above two variables to match grid size, as desired. @@ -66,7 +66,7 @@ GENERATIONS=10 # How many generations to cycle through. # Adjust this upwards, #+ if you have time on your hands. -NONE_ALIVE=80 # Exit status on premature bailout, +NONE_ALIVE=85 # Exit status on premature bailout, #+ if no cells left alive. TRUE=0 FALSE=1 @@ -78,17 +78,16 @@ generation=0 # Initialize generation count. # ================================================================= +let "cells = $ROWS * $COLS" # How many cells. -let "cells = $ROWS * $COLS" - # How many cells. - -declare -a initial # Arrays containing "cells." +# Arrays containing "cells." +declare -a initial declare -a current display () { -alive=0 # How many cells "alive" at any given time. +alive=0 # How many cells alive at any given time. # Initially zero. declare -a arr @@ -161,13 +160,12 @@ return $TRUE # Valid coordinate. } -IsAlive () # Test whether cell is alive. - # Takes array, cell number, state of cell as arguments. -{ - GetCount "$1" $2 # Get alive cell count in neighborhood. +IsAlive () # Test whether cell is alive. + # Takes array, cell number, +{ #+ state of cell as arguments. + GetCount "$1" $2 # Get alive cell count in neighborhood. local nhbd=$? - if [ "$nhbd" -eq "$BIRTH" ] # Alive in any case. then return $ALIVE @@ -178,7 +176,7 @@ IsAlive () # Test whether cell is alive. return $ALIVE fi - return $DEAD # Default. + return $DEAD # Dead by default. } @@ -216,7 +214,7 @@ GetCount () # Count live cells in passed cell's neighborhood. let "t_bot = $bottom + $i" - let "row = $r" # Count center row of neighborhood. + let "row = $r" # Count center row. IsValid $t_cen $row # Valid cell position? if [ $? -eq "$TRUE" ] then @@ -280,7 +278,7 @@ do done -# let "generation += 1" # Increment generation count. +# let "generation += 1" # Increment generation count. # Why was the above line commented out? @@ -293,7 +291,7 @@ echo "Generation $generation - $alive alive" if [ "$alive" -eq 0 ] then echo - echo "Premature exit: no more cells alive!" + echo "Unexpected exit: no more cells alive!" exit $NONE_ALIVE # No point in continuing fi #+ if no live cells. @@ -328,7 +326,7 @@ echo "Generation $generation - $alive alive" # ------------------------------------------- -let "generation += 1" # Increment generation count. +let "generation += 1" # Bump generation count. echo # ------- Display second generation. ------- @@ -349,7 +347,7 @@ done echo -exit 0 # END +exit 0 # CEOF:EOF @@ -371,5 +369,4 @@ exit 0 # END #+ in the script for an altered grid size. # # Exercise: Optimize this script. -# It has some repetitive and redundant code, -#+ for example, lines 335-336. +# It has some redundant code. diff --git a/LDP/guide/docbook/abs-guide/mail-format.sh b/LDP/guide/docbook/abs-guide/mail-format.sh index 14e1a0de..7e812b83 100644 --- a/LDP/guide/docbook/abs-guide/mail-format.sh +++ b/LDP/guide/docbook/abs-guide/mail-format.sh @@ -47,4 +47,4 @@ sed "$sedscript" $1 | fold -s --width=$MAXWIDTH # An nice set of text processing utilities and an efficient #+ scripting language provide an alternative to bloated executables. -exit 0 +exit diff --git a/LDP/guide/docbook/abs-guide/maned.sh b/LDP/guide/docbook/abs-guide/maned.sh new file mode 100644 index 00000000..9bbfb32b --- /dev/null +++ b/LDP/guide/docbook/abs-guide/maned.sh @@ -0,0 +1,143 @@ +#!/bin/bash +# maned.sh +# A rudimentary man page editor + +# Version: 0.1 (Alpha, probably buggy) +# Author: Mendel Cooper <thegrendel@theriver.com> +# Reldate: 16 June 2008 +# License: GPL3 + + +savefile= # Global, used in multiple functions. +E_NOINPUT=90 # User input missing (error). May or may not be critical. + +# =========== Markup Tags ============ # +TopHeader=".TH" +NameHeader=".SH NAME" +SyntaxHeader=".SH SYNTAX" +SynopsisHeader=".SH SYNOPSIS" +InstallationHeader=".SH INSTALLATION" +DescHeader=".SH DESCRIPTION" +OptHeader=".SH OPTIONS" +FilesHeader=".SH FILES" +EnvHeader=".SH ENVIRONMENT" +AuthHeader=".SH AUTHOR" +BugsHeader=".SH BUGS" +SeeAlsoHeader=".SH SEE ALSO" +BOLD=".B" +# Add more tags, as needed. +# See groff docs for markup meanings. +# ==================================== # + +start () +{ +clear # Clear screen. +echo "ManEd" +echo "-----" +echo +echo "Simple man page creator" +echo "Author: Mendel Cooper" +echo; echo; echo +} + +progname () +{ + echo -n "Program name? " + read name + + echo -n "Manpage section? [Hit RETURN for default (\"1\") ] " + read section + if [ -z "$section" ] + then + section=1 # Most man pages are in section 1. + fi + + if [ -n "$name" ] + then + savefile=""$name"."$section"" # Filename suffix = section. + echo -n "$1 " >>$savefile + name1=$(echo "$name" | tr a-z A-Z) # Change to uppercase, + #+ per man page convention. + echo -n "$name1" >>$savefile + else + echo "Error! No input." # Mandatory input. + exit $E_NOINPUT # Critical! + fi + + echo -n " \"$section\"">>$savefile # Append, always append. + + echo -n "Version? " + read ver + echo -n " \"Version $ver \"">>$savefile + echo >>$savefile + + echo -n "Short description [0 - 5 words]? " + read sdesc + echo "$NameHeader">>$savefile + echo ""$BOLD" "$name"">>$savefile + echo "\- "$sdesc"">>$savefile + +} + +fill_in () +{ # This function more or less copied from "pad.sh" script. + echo -n "$2? " # Get user input. + read var # May paste (a single line only!) to fill in field. + + if [ -n "$var" ] + then + echo "$1 " >>$savefile + echo -n "$var" >>$savefile + else # Don't append empty field to file. + return $E_NOINPUT # Not critical here. + fi + + echo >>$savefile + +} + + +end () +{ +clear +echo -n "Would you like to view the saved man page (y/n)? " +read ans +if [ "$ans" = "n" -o "$ans" = "N" ]; then exit; fi +exec less "$savefile" # Exit script and hand off control to "less" ... + #+ ... which formats for viewing man page source. +} + + +# ---------------------------------------- # +start +progname "$TopHeader" +fill_in "$SynopsisHeader" "Synopsis" +fill_in "$DescHeader" "Long description" +# May paste in *single line* of text. +fill_in "$OptHeader" "Options" +fill_in "$FilesHeader" "Files" +fill_in "$AuthHeader" "Author" +fill_in "$BugsHeader" "Bugs" +fill_in "$SeeAlsoHeader" "See also" +# fill_in "$OtherHeader" ... as necessary. +end # ... exit not needed. +# ---------------------------------------- # + +# Note that the generated man page will usually +#+ require manual fine-tuning with a text editor. +# However, it's a distinct improvement upon +#+ writing man source from scratch +#+ or even editing a blank man page template. + +# The main deficiency of the script is that it permits +#+ pasting only a single text line into the input fields. +# This may be a long, cobbled-together line, which groff +# will automatically wrap and hyphenate. +# However, if you want multiple (newline-separated) paragraphs, +#+ these must be inserted by manual text editing on the +#+ script-generated man page. +# Exercise (difficult): Fix this! + +# This script is not nearly as elaborate as the +#+ full-featured "manedit" package (http://wolfpack.twu.net), +#+ but it's much easier to use. diff --git a/LDP/guide/docbook/abs-guide/manview.sh b/LDP/guide/docbook/abs-guide/manview.sh index 4792a782..ef0cd75e 100644 --- a/LDP/guide/docbook/abs-guide/manview.sh +++ b/LDP/guide/docbook/abs-guide/manview.sh @@ -5,7 +5,7 @@ # It lets you look at the intermediate results on the fly #+ while working on it. -E_WRONGARGS=65 +E_WRONGARGS=85 if [ -z "$1" ] then diff --git a/LDP/guide/docbook/abs-guide/match-string.sh b/LDP/guide/docbook/abs-guide/match-string.sh index 357ffbc2..954681ed 100644 --- a/LDP/guide/docbook/abs-guide/match-string.sh +++ b/LDP/guide/docbook/abs-guide/match-string.sh @@ -1,18 +1,18 @@ #!/bin/bash -# match-string.sh: simple string matching +# match-string.sh: Simple string matching. match_string () -{ +{ # Exact string match. MATCH=0 - NOMATCH=90 + E_NOMATCH=90 PARAMS=2 # Function requires 2 arguments. - BAD_PARAMS=91 + E_BAD_PARAMS=91 - [ $# -eq $PARAMS ] || return $BAD_PARAMS + [ $# -eq $PARAMS ] || return $E_BAD_PARAMS case "$1" in "$2") return $MATCH;; - * ) return $NOMATCH;; + * ) return $E_NOMATCH;; esac } diff --git a/LDP/guide/docbook/abs-guide/music.sh b/LDP/guide/docbook/abs-guide/music.sh new file mode 100644 index 00000000..aa8ac14a --- /dev/null +++ b/LDP/guide/docbook/abs-guide/music.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# music.sh + +# MUSIC WITHOUT EXTERNAL FILES + +# Author: Antonio Macchi +# Used in ABS Guide with permission + + +# /dev/dsp default = 8000 frames per second, 8 bits per frame (1 byte), +#+ 1 channel (mono) + +duration=2000 # If 8000 bytes = 1 second, then 2000 = 1/4 second. +volume=$'\xc0' # Max volume = \xff (or \x00). +mute=$'\x80' # No volume = \x80 (the middle). + +function mknote () # $1=Note Hz in bytes (e.g. A = 440Hz :: + #+ 8000 fps / 440 = 16 :: A = 16 bytes per second) +{ + for t in `seq 0 $duration` + do + test $(( $t % $1 )) = 0 && echo -n $volume || echo -n $mute + done + +} + +e=`mknote 49` +g=`mknote 41` +a=`mknote 36` +b=`mknote 32` +c=`mknote 30` +cis=`mknote 29` +d=`mknote 27` +e2=`mknote 24` +n=`mknote 32767` +# European notation. + +echo -n "$g$e2$d$c$d$c$a$g$n$g$e$n$g$e2$d$c$c$b$c$cis$n$cis$d \ +$n$g$e2$d$c$d$c$a$g$n$g$e$n$g$a$d$c$b$a$b$c" > /dev/dsp +# dsp = Digital Signal Processor + +exit $? # A "bonny" example of a shell script! diff --git a/LDP/guide/docbook/abs-guide/names.data b/LDP/guide/docbook/abs-guide/names.data index a51d6a53..30153574 100644 --- a/LDP/guide/docbook/abs-guide/names.data +++ b/LDP/guide/docbook/abs-guide/names.data @@ -13,7 +13,7 @@ Semmelweiss Smith Turing Venn -Wilson +Wilkinson Znosko-Borowski # This is a data file for diff --git a/LDP/guide/docbook/abs-guide/nim.sh b/LDP/guide/docbook/abs-guide/nim.sh new file mode 100644 index 00000000..e1b7236a --- /dev/null +++ b/LDP/guide/docbook/abs-guide/nim.sh @@ -0,0 +1,275 @@ +#!/bin/bash +# nim.sh: Game of Nim + +# Author: Mendel Cooper +# Reldate: 15 July 2008 +# License: GPL3 + +ROWS=5 # Five rows of pegs. +WON=91 # Exit codes to keep track of wins/losses. +LOST=92 # Possibly useful if running in batch mode. +QUIT=99 +peg_msg= # Peg/Pegs? +Rows=( 0 5 4 3 2 1 ) # Array holding play info. +# ${Rows[0]} holds total number of pegs, updated after each turn. +# Other array elements hold number of pegs in corresponding row. + +instructions () +{ + clear + tput bold + echo "Welcome to the game of Nim."; echo + echo -n "Do you need instructions? (y/n) "; read ans + + if [ "$ans" = "y" -o "$ans" = "Y" ]; then + clear + echo -e '\E[33;41m' # Yellow fg., over red bg.; bold. + cat <<INSTRUCTIONS + +Nim is a game with roots in the distant past. +This particular variant starts with five rows of pegs. + +1: | | | | | +2: | | | | +3: | | | +4: | | +5: | + +The number at the left identifies the row. + +The human player moves first, and alternates turns with the bot. +A turn consists of removing at least one peg from a single row. +It is permissable to remove ALL the pegs from a row. +For example, in row 2, above, the player can remove 1, 2, 3, or 4 pegs. +The player who removes the last peg loses. + +The strategy consists of trying to be the one who removes +the next-to-last peg(s), leaving the loser with the final peg. + +To exit the game early, hit ENTER during your turn. +INSTRUCTIONS + +echo; echo -n "Hit ENTER to begin game. "; read azx + + echo -e "\033[0m" # Restore display. + else tput sgr0; clear + fi + +clear + +} + + +tally_up () +{ + let "Rows[0] = ${Rows[1]} + ${Rows[2]} + ${Rows[3]} + ${Rows[4]} + \ + ${Rows[5]}" # Add up how many pegs remaining. +} + + +display () +{ + index=1 # Start with top row. + echo + + while [ "$index" -le "$ROWS" ] + do + p=${Rows[index]} + echo -n "$index: " # Show row number. + + # ------------------------------------------------ + # Two concurrent inner loops. + + indent=$index + while [ "$indent" -gt 0 ] + do + echo -n " " # Staggered rows. + ((indent--)) # Spacing between pegs. + done + + while [ "$p" -gt 0 ] + do + echo -n "| " + ((p--)) + done + # ----------------------------------------------- + + echo + ((index++)) + done + + tally_up + + rp=${Rows[0]} + + if [ "$rp" -eq 1 ] + then + peg_msg=peg + final_msg="Game over." + else # Game not yet over . . . + peg_msg=pegs + final_msg="" # . . . So "final message" is blank. + fi + + echo " $rp $peg_msg remaining." + echo " "$final_msg"" + + + echo +} + +player_move () +{ + + echo "Your move:" + + echo -n "Which row? " + while read idx + do # Validity check, etc. + + if [ -z "$idx" ] # Hitting return quits. + then + echo "Premature exit."; echo + tput sgr0 # Restore display. + exit $QUIT + fi + + if [ "$idx" -gt "$ROWS" -o "$idx" -lt 1 ] # Bounds check. + then + echo "Invalid row number!" + echo -n "Which row? " + else + break + fi + # TODO: + # Add check for non-numeric input. + # Also, script crashes on input outside of range of long double. + # Fix this. + + done + + echo -n "Remove how many? " + while read num + do # Validity check. + + if [ -z "$num" ] + then + echo "Premature exit."; echo + tput sgr0 # Restore display. + exit $QUIT + fi + + if [ "$num" -gt ${Rows[idx]} -o "$num" -lt 1 ] + then + echo "Cannot remove $num!" + echo -n "Remove how many? " + else + break + fi + done + # TODO: + # Add check for non-numeric input. + # Also, script crashes on input outside of range of long double. + # Fix this. + + let "Rows[idx] -= $num" + + display + tally_up + + if [ ${Rows[0]} -eq 1 ] + then + echo " Human wins!" + echo " Congratulations!" + tput sgr0 # Restore display. + echo + exit $WON + fi + + if [ ${Rows[0]} -eq 0 ] + then # Snatching defeat from the jaws of victory . . . + echo " Fool!" + echo " You just removed the last peg!" + echo " Bot wins!" + tput sgr0 # Restore display. + echo + exit $LOST + fi +} + + +bot_move () +{ + + row_b=0 + while [[ $row_b -eq 0 || ${Rows[row_b]} -eq 0 ]] + do + row_b=$RANDOM # Choose random row. + let "row_b %= $ROWS" + done + + + num_b=0 + r0=${Rows[row_b]} + + if [ "$r0" -eq 1 ] + then + num_b=1 + else + let "num_b = $r0 - 1" + # Leave only a single peg in the row. + fi # Not a very strong strategy, + #+ but probably a bit better than totally random. + + let "Rows[row_b] -= $num_b" + echo -n "Bot: " + echo "Removing from row $row_b ... " + + if [ "$num_b" -eq 1 ] + then + peg_msg=peg + else + peg_msg=pegs + fi + + echo " $num_b $peg_msg." + + display + tally_up + + if [ ${Rows[0]} -eq 1 ] + then + echo " Bot wins!" + tput sgr0 # Restore display. + exit $WON + fi + +} + + +# ================================================== # +instructions # If human player needs them . . . +tput bold # Bold characters for easier viewing. +display # Show game board. + +while [ true ] # Main loop. +do # Alternate human and bot turns. + player_move + bot_move +done +# ================================================== # + +# Exercise: +# -------- +# Improve the bot's strategy. +# There is, in fact, a Nim strategy that can force a win. +# See the Wikipedia article on Nim: http://en.wikipedia.org/wiki/Nim +# Recode the bot to use this strategy (rather difficult). + +# Curiosities: +# ----------- +# Nim played a prominent role in Alain Resnais' 1961 New Wave film, +#+ Last Year at Marienbad. +# +# In 1978, Leo Christopherson wrote an animated version of Nim, +#+ Android Nim, for the TRS-80 Model I. diff --git a/LDP/guide/docbook/abs-guide/numbers.sh b/LDP/guide/docbook/abs-guide/numbers.sh index 638ad817..1a734b97 100644 --- a/LDP/guide/docbook/abs-guide/numbers.sh +++ b/LDP/guide/docbook/abs-guide/numbers.sh @@ -57,4 +57,8 @@ let "bad_oct = 081" # bad_oct = 081: value too great for base (error token is "081") # Octal numbers use only digits in the range 0 - 7. -exit 0 # Thanks, Rich Bartell and Stephane Chazelas, for clarification. +exit $? # Thanks, Rich Bartell and Stephane Chazelas, for clarification. + +$ sh numbers.sh +$ echo $? +$ 1 diff --git a/LDP/guide/docbook/abs-guide/poem.sh b/LDP/guide/docbook/abs-guide/poem.sh index 6535525f..221f369a 100644 --- a/LDP/guide/docbook/abs-guide/poem.sh +++ b/LDP/guide/docbook/abs-guide/poem.sh @@ -15,6 +15,8 @@ Attrib[2]="\"Thirteen Ways of Looking at a Blackbird\"" echo +tput bold # Bold print. + for index in 1 2 3 4 5 # Five lines. do printf " %s\n" "${Line[index]}" @@ -25,6 +27,9 @@ do printf " %s\n" "${Attrib[index]}" done +tput sgr0 # Reset terminal. + # See 'tput' docs. + echo exit 0 diff --git a/LDP/guide/docbook/abs-guide/pr-asc.sh b/LDP/guide/docbook/abs-guide/pr-asc.sh index 2e74b42d..885c5977 100644 --- a/LDP/guide/docbook/abs-guide/pr-asc.sh +++ b/LDP/guide/docbook/abs-guide/pr-asc.sh @@ -2,7 +2,7 @@ # pr-ascii.sh: Prints a table of ASCII characters. START=33 # Range of printable ASCII characters (decimal). -END=125 +END=127 # Will not work for unprintable chars. (> 127). echo " Decimal Hex Character" # Header. echo " ------- --- ---------" diff --git a/LDP/guide/docbook/abs-guide/primes2.sh b/LDP/guide/docbook/abs-guide/primes2.sh new file mode 100644 index 00000000..66ac8bc9 --- /dev/null +++ b/LDP/guide/docbook/abs-guide/primes2.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# primes2.sh + +# Generating prime numbers the quick-and-easy way, +#+ without resorting to fancy algorithms. + +CEILING=10000 # 1 to 10000 +PRIME=0 +E_NOTPRIME= + +is_prime () +{ + local factors + factors=( $(factor $1) ) # Load output of `factor` into array. + +if [ -z "${factors[2]}" ] +# Third element of "factors" array: +#+ ${factors[2]} is 2nd factor of argument. +# If it is blank, then there is no 2nd factor, +#+ and the argument is therefore prime. +then + return $PRIME # 0 +else + return $E_NOTPRIME # null +fi +} + +echo +for n in $(seq $CEILING) +do + if is_prime $n + then + printf %5d $n + fi # ^ Five positions per number suffices. +done # For a higher $CEILING, adjust upward, as necessary. + +echo + +exit diff --git a/LDP/guide/docbook/abs-guide/progress-bar.sh b/LDP/guide/docbook/abs-guide/progress-bar.sh new file mode 100644 index 00000000..cde20cb0 --- /dev/null +++ b/LDP/guide/docbook/abs-guide/progress-bar.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# progress-bar.sh + +# Author: Dotan Barak (very minor revisions by ABS Guide author). +# Used in ABS Guide with permission (thanks!). + + +BAR_WIDTH=50 +BAR_CHAR_START="[" +BAR_CHAR_END="]" +BAR_CHAR_EMPTY="." +BAR_CHAR_FULL="=" +BRACKET_CHARS=2 +LIMIT=100 + +print_progress_bar() +{ + # Calculate how many characters will be full. + let "full_limit = ((($1 - $BRACKET_CHARS) * $2) / $LIMIT)" + + # Calculate how many characters will be empty. + let "empty_limit = ($1 - $BRACKET_CHARS) - ${full_limit}" + + # Prepare the bar. + bar_line="${BAR_CHAR_START}" + for ((j=0; j<full_limit; j++)); do + bar_line="${bar_line}${BAR_CHAR_FULL}" + done + + for ((j=0; j<empty_limit; j++)); do + bar_line="${bar_line}${BAR_CHAR_EMPTY}" + done + + bar_line="${bar_line}${BAR_CHAR_END}" + + printf "%3d%% %s" $2 ${bar_line} +} + +# Here is a sample of code that uses it. +MAX_PERCENT=100 +for ((i=0; i<=MAX_PERCENT; i++)); do + # + usleep 10000 + # ... Or run some other commands ... + # + print_progress_bar ${BAR_WIDTH} ${i} + echo -en "\r" +done + +echo "" + +exit diff --git a/LDP/guide/docbook/abs-guide/q-function.sh b/LDP/guide/docbook/abs-guide/q-function.sh index 25dde85a..d574b966 100644 --- a/LDP/guide/docbook/abs-guide/q-function.sh +++ b/LDP/guide/docbook/abs-guide/q-function.sh @@ -25,7 +25,7 @@ echo "Q-series [$LIMIT terms]:" echo -n "${Q[1]} " # Output first two terms. echo -n "${Q[2]} " -for ((n=3; n <= $LIMIT; n++)) # C-like loop expressions. +for ((n=3; n <= $LIMIT; n++)) # C-like loop expression. do # Q[n] = Q[n - Q[n-1]] + Q[n - Q[n-2]] for n>2 # Need to break the expression into intermediate terms, #+ since Bash doesn't handle complex array arithmetic very well. @@ -56,4 +56,4 @@ exit 0 # This is an iterative implementation of the Q-series. # The more intuitive recursive implementation is left as an exercise. # Warning: calculating this series recursively takes a VERY long time -#+ via a script. C/C++ would be more suitable. +#+ via a script. C/C++ would be orders of magnitude faster. diff --git a/LDP/guide/docbook/abs-guide/qky.sh b/LDP/guide/docbook/abs-guide/qky.sh index 67b10c5a..4bc168ee 100644 --- a/LDP/guide/docbook/abs-guide/qky.sh +++ b/LDP/guide/docbook/abs-guide/qky.sh @@ -460,3 +460,6 @@ exit $? # 5) Implement "vulnerable" mode of play. # 6) Improve save-to-file capability (and maybe make it optional). # 7) Fix bugs!!! + +# Reference for more info: +# http://personal.riverusers.com/~thegrendel/qky.README.html diff --git a/LDP/guide/docbook/abs-guide/realname.sh b/LDP/guide/docbook/abs-guide/realname.sh index bccb9603..77daedcc 100644 --- a/LDP/guide/docbook/abs-guide/realname.sh +++ b/LDP/guide/docbook/abs-guide/realname.sh @@ -16,12 +16,13 @@ then exit $E_WRONGARGS fi -file_excerpt () # Scan file for pattern, then print relevant portion of line. -{ -while read line # "while" does not necessarily need "[ condition ]" -do - echo "$line" | grep $1 | awk -F":" '{ print $5 }' # Have awk use ":" delimiter. -done +file_excerpt () # Scan file for pattern, +{ #+ then print relevant portion of line. + while read line # "while" does not necessarily need [ condition ] + do + echo "$line" | grep $1 | awk -F":" '{ print $5 }' + # Have awk use ":" delimiter. + done } <$file # Redirect into function's stdin. file_excerpt $pattern diff --git a/LDP/guide/docbook/abs-guide/resistor-inventory.sh b/LDP/guide/docbook/abs-guide/resistor-inventory.sh index 7e9c64b5..1a7cc915 100644 --- a/LDP/guide/docbook/abs-guide/resistor-inventory.sh +++ b/LDP/guide/docbook/abs-guide/resistor-inventory.sh @@ -1,6 +1,6 @@ #!/bin/bash # resistor-inventory.sh -# Simple database application using indirect variable referencing. +# Simple database / table-lookup application. # ============================================================== # # Data @@ -18,7 +18,7 @@ B1724_loc=24N B1724_inventory=243 B1725_value=10000 -B1725_powerdissip=.25 +B1725_powerdissip=.125 B1725_colorcode="brown-black-orange" B1725_loc=24N B1725_inventory=89 @@ -42,7 +42,9 @@ do echo echo "Catalog number $catalog_number:" - echo "There are ${!Inv} of [${!Val} ohm / ${!Pdissip} watt] resistors in stock." + # Now, retrieve value, using indirect referencing. + echo "There are ${!Inv} of [${!Val} ohm / ${!Pdissip} watt]\ + resistors in stock." # ^ ^ echo "These are located in bin # ${!Loc}." echo "Their color code is \"${!Ccode}\"." @@ -57,6 +59,7 @@ echo; echo # 2) Rewrite this script to use arrays, #+ rather than indirect variable referencing. # Which method is more straightforward and intuitive? +# Which method is easier to code? # Notes: diff --git a/LDP/guide/docbook/abs-guide/script-array.sh b/LDP/guide/docbook/abs-guide/script-array.sh index f9c36acf..adca9a54 100644 --- a/LDP/guide/docbook/abs-guide/script-array.sh +++ b/LDP/guide/docbook/abs-guide/script-array.sh @@ -14,6 +14,7 @@ for element in $(seq 0 $((${#script_contents[@]} - 1))) # Try changing it to seq 1. echo -n "${script_contents[$element]}" # List each field of this script on a single line. +# echo -n "${script_contents[element]}" also works because of ${ ... }. echo -n " -- " # Use " -- " as a field separator. done diff --git a/LDP/guide/docbook/abs-guide/sd.sh b/LDP/guide/docbook/abs-guide/sd.sh new file mode 100644 index 00000000..961bf89e --- /dev/null +++ b/LDP/guide/docbook/abs-guide/sd.sh @@ -0,0 +1,117 @@ +#!/bin/bash +# sd.sh: Standard Deviation + +# The Standard Deviation indicates how consistent a set of data is. +# It shows to what extent the individual data points deviate from the +#+ arithmetic mean, i.e., how much they "bounce around" (or cluster). +# It is essentially the average deviation-distance of the +#+ data points from the mean. + +# =========================================================== # +# To calculate the Standard Deviation: +# +# 1 Find the arithmetic mean (average) of all the data points. +# 2 Subtract each data point from the arithmetic mean, +# and square that difference. +# 3 Add all of the individual difference-squares in # 2. +# 4 Divide the sum in # 3 by the number of data points. +# This is known as the "variance." +# 5 The square root of # 4 gives the Standard Deviation. +# =========================================================== # + +count=0 # Number of data points; global. +SC=9 # Scale to be used by bc. Nine decimal places. +E_DATAFILE=90 # Data file error. + +# ----------------- Set data file --------------------- +if [ ! -z $1 ] # Specify filename as cmd-line arg? +then + datafile="$1" # ASCII text file, +else #+ one (numerical) data point per line! + datafile=sample.dat +fi # See example data file, below. + +if [ ! -e "$datafile" ] +then + echo "\""$datafile"\" does not exist!" + exit $E_DATAFILE +fi +# ----------------------------------------------------- + + +arith_mean () +{ + local rt=0 # Running total. + local am=0 # Arithmetic mean. + local ct=0 # Number of data points. + + while read value # Read one data point at a time. + do + rt=$(echo "scale=$SC; $rt + $value" | bc) + (( ct++ )) + done + + am=$(echo "scale=$SC; $rt / $ct" | bc) + + echo $am; return $ct # This function "returns" TWO values! + # Caution: This little trick will not work if $ct > 255! + # To handle a larger number of data points, + #+ simply comment out the "return $ct" above. +} <"$datafile" # Feed in data file. + +sd () +{ + mean1=$1 # Arithmetic mean (passed to function). + n=$2 # How many data points. + sum2=0 # Sum of squared differences ("variance"). + avg2=0 # Average of $sum2. + sdev=0 # Standard Deviation. + + while read value # Read one line at a time. + do + diff=$(echo "scale=$SC; $mean1 - $value" | bc) + # Difference between arith. mean and data point. + dif2=$(echo "scale=$SC; $diff * $diff" | bc) # Squared. + sum2=$(echo "scale=$SC; $sum2 + $dif2" | bc) # Sum of squares. + done + + avg2=$(echo "scale=$SC; $sum2 / $n" | bc) # Avg. of sum of squares. + sdev=$(echo "scale=$SC; sqrt($avg2)" | bc) # Square root = + echo $sdev # Standard Deviation. + +} <"$datafile" # Rewinds data file. + + +# ======================================================= # +mean=$(arith_mean); count=$? # Two returns from function! +std_dev=$(sd $mean $count) + +echo +echo "Number of data points in \""$datafile"\" = $count" +echo "Arithmetic mean (average) = $mean" +echo "Standard Deviation = $std_dev" +echo +# ======================================================= # + +exit + +# This script could stand some drastic streamlining, +# but not at the cost of reduced legibility, please. + + +# ++++++++++++++++++++++++++++++++++++++++ # +# A sample data file (sample1.dat): + +# 18.35 +# 19.0 +# 18.88 +# 18.91 +# 18.64 + + +# $ sh sd.sh sample1.dat + +# Number of data points in "sample1.dat" = 5 +# Arithmetic mean (average) = 18.756000000 +# Standard Deviation = .235338054 +# ++++++++++++++++++++++++++++++++++++++++ # diff --git a/LDP/guide/docbook/abs-guide/str-test.sh b/LDP/guide/docbook/abs-guide/str-test.sh index 3791e267..b814c6ea 100644 --- a/LDP/guide/docbook/abs-guide/str-test.sh +++ b/LDP/guide/docbook/abs-guide/str-test.sh @@ -4,24 +4,20 @@ # Using if [ ... ] - # If a string has not been initialized, it has no defined value. -# This state is called "null" (not the same as zero). +# This state is called "null" (not the same as zero!). -if [ -n $string1 ] # $string1 has not been declared or initialized. +if [ -n $string1 ] # string1 has not been declared or initialized. then echo "String \"string1\" is not null." else echo "String \"string1\" is null." -fi -# Wrong result. +fi # Wrong result. # Shows $string1 as not null, although it was not initialized. - echo - -# Lets try it again. +# Let's try it again. if [ -n "$string1" ] # This time, $string1 is quoted. then @@ -30,51 +26,43 @@ else echo "String \"string1\" is null." fi # Quote strings within test brackets! - echo - if [ $string1 ] # This time, $string1 stands naked. then echo "String \"string1\" is not null." else echo "String \"string1\" is null." -fi -# This works fine. -# The [ ] test operator alone detects whether the string is null. -# However it is good practice to quote it ("$string1"). +fi # This works fine. +# The [ ... ] test operator alone detects whether the string is null. +# However it is good practice to quote it (if [ "$string1" ]). # # As Stephane Chazelas points out, # if [ $string1 ] has one argument, "]" # if [ "$string1" ] has two arguments, the empty "$string1" and "]" - echo - string1=initialized -if [ $string1 ] # Again, $string1 stands naked. +if [ $string1 ] # Again, $string1 stands unquoted. then echo "String \"string1\" is not null." else echo "String \"string1\" is null." -fi -# Again, gives correct result. +fi # Again, gives correct result. # Still, it is better to quote it ("$string1"), because . . . string1="a = b" -if [ $string1 ] # Again, $string1 stands naked. +if [ $string1 ] # Again, $string1 stands unquoted. then echo "String \"string1\" is not null." else echo "String \"string1\" is null." -fi -# Not quoting "$string1" now gives wrong result! +fi # Not quoting "$string1" now gives wrong result! -exit 0 -# Thank you, also, Florian Wisser, for the "heads-up". +exit 0 # Thank you, also, Florian Wisser, for the "heads-up". diff --git a/LDP/guide/docbook/abs-guide/substring-extraction.sh b/LDP/guide/docbook/abs-guide/substring-extraction.sh index ab5457d8..1c7cfe59 100644 --- a/LDP/guide/docbook/abs-guide/substring-extraction.sh +++ b/LDP/guide/docbook/abs-guide/substring-extraction.sh @@ -5,8 +5,8 @@ String=23skidoo1 # 012345678 Bash # 123456789 awk # Note different string indexing system: -# Bash numbers first character of string as '0'. -# Awk numbers first character of string as '1'. +# Bash numbers first character of string as 0. +# Awk numbers first character of string as 1. echo ${String:2:4} # position 3 (0-1-2), 4 characters long # skid diff --git a/LDP/guide/docbook/abs-guide/tohtml.sh b/LDP/guide/docbook/abs-guide/tohtml.sh index 8ddba8f9..cd0853ba 100644 --- a/LDP/guide/docbook/abs-guide/tohtml.sh +++ b/LDP/guide/docbook/abs-guide/tohtml.sh @@ -1,5 +1,5 @@ #!/bin/bash -# tohtml.sh +# tohtml.sh [v. 0.2, reldate: 06/26/80, still buggy] # Convert a text file to HTML format. # Author: Mendel Cooper @@ -96,10 +96,10 @@ process_text () # =================================================== # Convert underscored phrase to italics. temp=$( echo "$line" | - sed -e 's/ _/ <i>/' -e 's/_ /<\/i> /' | - sed -e 's/^_/<i>/' -e 's/_$/<\/i>/' ) + sed -e 's/ _/ <i>/' -e 's/_/<\/i> /' | + sed -e 's/^_/<i>/' -e 's/_/<\/i>/' ) # Process only underscores prefixed by space, - #+ followed by space, or at beginning or end of line. + #+ or at beginning or end of line. # Do not convert underscores embedded within a word! line="$temp" # Slows script execution. Can be optimized? diff --git a/LDP/guide/docbook/abs-guide/vartrace.sh b/LDP/guide/docbook/abs-guide/vartrace.sh index 02b31c51..6b8b6a11 100644 --- a/LDP/guide/docbook/abs-guide/vartrace.sh +++ b/LDP/guide/docbook/abs-guide/vartrace.sh @@ -5,17 +5,17 @@ trap 'echo "VARIABLE-TRACE> \$variable = \"$variable\""' DEBUG variable=29 -echo "Just initialized \"\$variable\" to $variable." +echo " Just initialized \$variable to $variable." let "variable *= 3" -echo "Just multiplied \"\$variable\" by 3." +echo " Just multiplied \$variable by 3." -exit $? +exit # The "trap 'command1 . . . command2 . . .' DEBUG" construct is #+ more appropriate in the context of a complex script, -#+ where placing multiple "echo $variable" statements might be -#+ clumsy and time-consuming. +#+ where inserting multiple "echo $variable" statements might be +#+ awkward and time-consuming. # Thanks, Stephane Chazelas for the pointer. @@ -24,8 +24,8 @@ Output of script: VARIABLE-TRACE> $variable = "" VARIABLE-TRACE> $variable = "29" -Just initialized "$variable" to 29. + Just initialized $variable to 29. VARIABLE-TRACE> $variable = "29" VARIABLE-TRACE> $variable = "87" -Just multiplied "$variable" by 3. + Just multiplied $variable by 3. VARIABLE-TRACE> $variable = "87" diff --git a/LDP/guide/docbook/abs-guide/wipedir.sh b/LDP/guide/docbook/abs-guide/wipedir.sh index 7fa0fd92..90b8a28b 100644 --- a/LDP/guide/docbook/abs-guide/wipedir.sh +++ b/LDP/guide/docbook/abs-guide/wipedir.sh @@ -1,6 +1,6 @@ #!/bin/bash -E_WRONG_DIRECTORY=73 +E_WRONG_DIRECTORY=83 clear # Clear screen. @@ -23,15 +23,16 @@ rm .[A-Za-z0-9]* # Delete dotfiles. # (shopt -s dotglob; rm -f *) will also work. # Thanks, S.C. for pointing this out. -# Filenames may contain all characters in the 0 - 255 range, except "/". -# Deleting files beginning with weird characters is left as an exercise. - -# Various other operations here, as necessary. +# A filename (`basename`) may contain all characters in the 0 - 255 range, +#+ except "/". +# Deleting files beginning with weird characters, such as - +#+ is left as an exercise. echo echo "Done." echo "Old files deleted in $TargetDirectory." echo +# Various other operations here, as necessary. -exit 0 +exit $? diff --git a/LDP/guide/docbook/abs-guide/wstrings.sh b/LDP/guide/docbook/abs-guide/wstrings.sh index 71962db1..9e571592 100644 --- a/LDP/guide/docbook/abs-guide/wstrings.sh +++ b/LDP/guide/docbook/abs-guide/wstrings.sh @@ -28,9 +28,10 @@ fi MINSTRLEN=3 # Minimum string length. WORDFILE=/usr/share/dict/linux.words # Dictionary file. - # May specify a different - #+ word list file - #+ of one-word-per-line format. +# May specify a different word list file +#+ of one-word-per-line format. +# For example, the "yawl" word-list package, +# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \