From 2295811a63563c0fb2cbff24cabd6588d44c91e8 Mon Sep 17 00:00:00 2001 From: gferg <> Date: Tue, 29 Sep 2009 15:08:03 +0000 Subject: [PATCH] updated --- LDP/guide/docbook/abs-guide/Change.log | 144 ++- LDP/guide/docbook/abs-guide/INDEX00.sgml | 80 +- LDP/guide/docbook/abs-guide/README | 3 + LDP/guide/docbook/abs-guide/TABEXP.sgml | 165 ++++ LDP/guide/docbook/abs-guide/UseGetOpt-2 | 27 + LDP/guide/docbook/abs-guide/UseGetOpt-2.sh | 94 ++ LDP/guide/docbook/abs-guide/abs-guide.sgml | 935 ++++++++++++++---- LDP/guide/docbook/abs-guide/col-totaler2.sh | 5 +- LDP/guide/docbook/abs-guide/encryptedpw.sh | 2 +- LDP/guide/docbook/abs-guide/ex33.sh | 45 +- LDP/guide/docbook/abs-guide/ex43.sh | 9 + LDP/guide/docbook/abs-guide/ex63.sh | 6 +- LDP/guide/docbook/abs-guide/ex67.sh | 3 +- LDP/guide/docbook/abs-guide/ex68.sh | 2 +- LDP/guide/docbook/abs-guide/ex71c.sh | 21 + LDP/guide/docbook/abs-guide/file-info.sh | 2 +- LDP/guide/docbook/abs-guide/hanoi2.bash | 28 +- LDP/guide/docbook/abs-guide/ind-ref.sh | 8 +- LDP/guide/docbook/abs-guide/ktour.sh | 4 +- LDP/guide/docbook/abs-guide/readpipe.sh | 12 +- .../docbook/abs-guide/show-all-colors.sh | 51 + LDP/guide/docbook/abs-guide/symlinks.sh | 2 +- LDP/guide/docbook/abs-guide/test-suite.sh | 39 + LDP/guide/docbook/abs-guide/unset.sh | 11 +- LDP/guide/docbook/abs-guide/wr-ps.bash | 4 +- LDP/howto/docbook/HOWTO-INDEX/howtoChap.sgml | 2 +- LDP/howto/docbook/HOWTO-INDEX/miscSect.sgml | 2 +- 27 files changed, 1428 insertions(+), 278 deletions(-) create mode 100644 LDP/guide/docbook/abs-guide/TABEXP.sgml create mode 100644 LDP/guide/docbook/abs-guide/UseGetOpt-2 create mode 100755 LDP/guide/docbook/abs-guide/UseGetOpt-2.sh create mode 100644 LDP/guide/docbook/abs-guide/show-all-colors.sh create mode 100644 LDP/guide/docbook/abs-guide/test-suite.sh diff --git a/LDP/guide/docbook/abs-guide/Change.log b/LDP/guide/docbook/abs-guide/Change.log index 10376e4e..a57267a4 100644 --- a/LDP/guide/docbook/abs-guide/Change.log +++ b/LDP/guide/docbook/abs-guide/Change.log @@ -7,36 +7,146 @@ ================================================================== - Current version = 6.0.05 - Dated 03/24/09 + Current version = 6.1 + Dated 09/30/09 http://bash.neuralshortcircuit.com/abs-guide-latest.tar.bz2 http://bash.neuralshortcircuit.com/abs-guide.pdf -------------------------------------------------------------------- - News: Major update, version 6.0. - Coverage of version 4 of Bash. + News: Version 6.1 released! ==================================================================== -Intermediate release -Working toward Version 6.1, Buffaloberry release +Version 6.1, Buffaloberry release +September 30, 2009 -1) In "Internal Commands and Builtins" chapter +1) In "Shell Programming!" chapter, + Added new sidebar to the intro text. + +2) In Quoting Variables section of "Quoting" chapter, + Revised double-quoting footnote about apparent inconsistent + behavior of "\" ... + (Thank you, Daniel Barclay for the heads-up!) + +3) In "Special Characters" chapter: + Added $[ ... ] integer expansion entry. + At "&>" entry, added usage examples. + +4) In "Tests" chapter: + In "Other Comparison Operators" section: + Expanded "compound comparison" section to include rihad's caution + about -a and -o operators not "short-circuiting." + At "[" entry, added footnote defining "token." + +5) In "Internal Commands and Builtins" chapter, At "eval" entry, reworded intro and added material to first example. + Subsequently rewrote first example once again, per suggestion by + Gerrit. (Thanks!) + Removed "eval.example" script, since it was misleading and confusing, + per the suggestion of Nathan Coulter. + Added footnote per Nathan Coulter to introductory paragraph. (Thanks!) -2) In "External Commands" chapter: +6) In "External Commands" chapter: In "Math Commands" section: - At "dc" entry, added two short usage example, including a - somewhat cryptic one (Golden Ratio calculation). + At "dc" entry, added two short usage example, including a + somewhat cryptic one (Golden Ratio calculation). + Fixed typo (extra quoe at close) at inline "dc" example. + (Thank you, Daniel Scott Matthews!) + In "File and Archiving Commands" section: + Added entry for "openssl," with usage examples. + Added entry for "getfact" and "setfacl," with usage examples. + Added two footnotes to "sum, cksum, md5sum, sha1sum" entry. + In "External Commands" section: + In "ex33.sh" example, changed "NO_ARGS=86" to "NO_ARGS=0" + per alert from Gerrit. (Thanks!) -3) In "Internal Variables" section of "Variables Revisited" chapter: - At "$DIRSTACK" entry, added footnote defining "stack." +7) In "Variables Revisited" chapter: + In "Parameter Substitution" section, + Fixed typos at "${var%Pattern}, ${var%%Pattern}" entry. + (Thank you, Donald White, for pointing this out!) + At "${parameter-default}" entry, added snippet from + revised "hanoi2.bash" script to usage example. + In "Internal Variables" section, + At "$DIRSTACK" entry, added footnote defining "stack." + In "Indirect References" section, + Added a sidebar explaining the actual process of constructing + an indirect reference. + At "unset" entry, added note linking to ${parameter:-default} + parameter substitution construct. + (Thank you, Timothy Redaelli, for pointing out the ambiguity + here.) + In "Internal Variables" section, + Added $CDPATH entry. -4) In "Bash, versions 2, 3, and 4" chapter: - In "Bash, version 4" section, - Corrected a typo in Substring Extraction entry example script. +8) In "Command Substitution" chapter: + Enhanced "setting a variable to the contents of a file" + in-line example. -5) In "Bibliography" section: - Added entry for Wikipedia article on "dc." +9) In "Functions" chapter: + At "exit status" entry, added statement relating function exit status + to that of ordinary commands. + +10) In "Bash, versions 2, 3, and 4" chapter: + In "Bash, version 4" section, + Corrected a typo in Substring Extraction entry example script. + Removed quoting of matched variable with =~ operator. + (Thank you, Thomas Güttler, for pointing this out.) + +11) In the "Miscellany" chapter: + In the "Portability Issues" section, + Added Larry Wall epigraph. + In the "Interactive and non-interactive shells and scripts" section, + Added John Lange's examples using "if [ -t 0 ]" ... + Added a new sub-subsection with a "test-suite.sh" script. + +12) In "Process Substitution" chapter: + Added instances to first usage example. + Stylistic cleanups. + +13) In "Exit and Exit Status" chapter, + Added discussion of exit status of a _pipe_, + including effect of prefixing the pipe with ! ... + +14) In "Arrays Chapter, + Fixed comment in "ex68.sh" example -- 1 is not a prime. + Thank you, Gordon Hopper, for pointing this out. + Fixed error in comment "ex67.sh" example. + (Thank you Grigory Romanenkov, for pointing this out.) + +15) In "Here Documents" chapter: + Added cautionary note about the use of ! as a limit string. + At quoting/escaping the limit string discussion, added Allen + Halsey's explanation. (Thank you!) + +16) In "Bash, versions 2, 3, and 4" chapter: + At "coproc" entry, fixed examples and added commentary, + courtesy of George Dimitriu. (Thanks!) + +17) In "Endnotes" chapter: + In "Where to Go For Help" section, + Added "CI-300 printer manual" epigraph. + +18) In "Bibliography" section: + Added entry for Wikipedia article on "dc." + Added entry for Philip Patterson's "logforbash" script. + +19) Changed several instances of "print $9" to "print $8" in embedded + awk scripts. (Thank you, Michal Nagy, for the heads up.) + +20) Added a new appendix: "An Introduction to Programmable Completion." + Added the following support scripts: + "UseGetOpt-2.sh" and "UseGetOpt-2" + +21) In "Contributed Scripts" appendix: + Fixed up "hanoi2.bash" script so it doesn't crash with error + if no params. + (Thank you, Stephen Solomon, for the heads up!) + Added "show-all-colors.sh" example script, + courtesy of Chetankumar Phulpagare. + +22) Updated download URL. + +23) Cleanups/fixups to main text, appendices, and script examples where + appropriate. diff --git a/LDP/guide/docbook/abs-guide/INDEX00.sgml b/LDP/guide/docbook/abs-guide/INDEX00.sgml index 6bbf44c0..3e25d532 100644 --- a/LDP/guide/docbook/abs-guide/INDEX00.sgml +++ b/LDP/guide/docbook/abs-guide/INDEX00.sgml @@ -278,7 +278,7 @@ ! Negation operator, inverts exit status of a test or command + linkend="negcond">exit status of a test or command != not-equal-to @@ -357,7 +357,14 @@ " ... " (double quotes) weak - quoting + quoting + + Double-quoting + the backslash (\) + character + + , @@ -417,7 +424,6 @@ - [[ ... ]] Double brackets, extended test construct @@ -436,6 +442,11 @@ using backquotes notation + $[ ... ] + Integer expansion + (deprecated) + + ${ ... } Variable manipulation / evaluation @@ -1053,6 +1064,7 @@ + Checksum Child processes Colon, : , equivalent to the true Bash @@ -1060,6 +1072,8 @@ Colorizing scripts + Cycling through the background colors, example script Table of color escape sequences @@ -1095,7 +1109,8 @@ Setting variable from loop output - Word splitting + Word + splitting Comment headers, @@ -1278,8 +1293,17 @@ Double parentheses (( ... )) arithmetic expansion/evaluation construct + Double quotes - " ... " weak quoting + " ... " weak quoting + + Double-quoting + the backslash (\) + character + + + Double-spacing a text file, using sed @@ -1304,6 +1328,8 @@ Contraction of else and if else + Encrypting files, using openssl esac, keyword terminating case construct Environmental @@ -1365,6 +1391,8 @@ Exit codes with special meanings Out of range + Pipe + exit status Specified by a function return @@ -1461,6 +1489,9 @@ + + File encryption + find {} @@ -1683,6 +1714,8 @@ Limit string + ! as a + limit string Closing limit string may not be indented Dash option @@ -2035,6 +2068,8 @@ $OLDPWD Previous working directory + openssl encryption + utility Operator Definition @@ -2042,7 +2077,6 @@ Precedence - Options, passed to shell or script on command line or by set command @@ -2129,8 +2163,6 @@ same file with a Bash script Embedded in a Bash script - Using eval - with Perquackey-type @@ -2155,6 +2187,8 @@ Comments embedded within + Exit status + of a pipe Pipefail, set -o pipefail option to indicate exit status @@ -2194,6 +2228,10 @@ indenting DOS-type newlines (\r\n) crash a script + Double-quoting + the backslash (\) + character eval, risk of using Execute permission @@ -2285,6 +2323,10 @@ Setting path and umask + A test suite + script (Bash versus classic Bourne + shell) Using whatis @@ -2382,6 +2424,8 @@ subshell + Programmable completion + (tab expansion) Prompt @@ -2951,6 +2995,7 @@ * * * + Tab completion Table lookup, script example tail, echo @@ -3155,6 +3200,9 @@ Pseudo-code rcs + Redirecting a test + to /dev/null to suppress output Running scripts in sequence without user intervention, using run-parts @@ -3179,6 +3227,9 @@ Testing a variable to see if it contains only digits + Testing whether + a command exists, using type Tracking script usage @@ -3195,6 +3246,9 @@ $TMOUT, Timeout interval + Token, a symbol that may + expand to a keyword or + command tput, terminal-control command @@ -3436,6 +3490,16 @@ Will not match dot files + + Word splitting + + Definition + Resulting from command + substitution + + Wrapper, shell * * * diff --git a/LDP/guide/docbook/abs-guide/README b/LDP/guide/docbook/abs-guide/README index a2a9ed51..66bb1077 100644 --- a/LDP/guide/docbook/abs-guide/README +++ b/LDP/guide/docbook/abs-guide/README @@ -119,3 +119,6 @@ paragraph-spac3.sh sw.sh line 5 (comment) + +UseGetOpt.sh: line 4 (comment) +UseGetOpt-2.sh: line 11 (comment) diff --git a/LDP/guide/docbook/abs-guide/TABEXP.sgml b/LDP/guide/docbook/abs-guide/TABEXP.sgml new file mode 100644 index 00000000..3ac6e77a --- /dev/null +++ b/LDP/guide/docbook/abs-guide/TABEXP.sgml @@ -0,0 +1,165 @@ +An Introduction to Programmable Completion + + The programmable completion feature in + Bash permits typing a partial command, then pressing the + [Tab] key to auto-complete the command sequence. + + This works only from the command + line, of course, and not within a + script. + + If multiple completions are possible, then [Tab] + lists them all. Let's see how it works. + + + +bash$ xtra[Tab] +xtraceroute xtrapin xtrapproto + xtraceroute.real xtrapinfo xtrapreset + xtrapchar xtrapout xtrapstats + + +bash$ xtrac[Tab] +xtraceroute xtraceroute.real + + +bash$ xtraceroute.r[Tab] +xtraceroute.real + + + + Tab completion also works for variables and path names. + + + +bash$ echo $BASH[Tab] +$BASH $BASH_COMPLETION $BASH_SUBSHELL + $BASH_ARGC $BASH_COMPLETION_DIR $BASH_VERSINFO + $BASH_ARGV $BASH_LINENO $BASH_VERSION + $BASH_COMMAND $BASH_SOURCE + + +bash$ echo /usr/local/[Tab] +bin/ etc/ include/ libexec/ sbin/ src/ + doc/ games/ lib/ man/ share/ + + + + + + + The Bash complete and + compgen builtins make it + possible for tab completion to + recognize partial parameters and + options to commands. In a very simple case, + we can use complete from the command-line to + specify a short list of acceptable parameters. + + + +bash$ touch sample_command +bash$ touch file1.txt file2.txt file2.doc file30.txt file4.zzz +bash$ chmod +x sample_command +bash$ complete -f -X '!*.txt' sample_command + + +bash$ ./sample[Tab][Tab] +sample_command +file1.txt file2.txt file30.txt + + + The option to + complete specifies filenames, + and the filter pattern. + + + + For anything more complex, we could write a script that + specifies a list of acceptable command-line parameters. + The compgen builtin expands a list of + arguments to generate + completion matches. + + Let us take a modified version + of the UseGetOpt.sh script as an example + command. This script accepts a number of command-line parameters, + preceded by either a single or double dash. And here is the + corresponding completion script, by + convention given a filename corresponding to its associated + command. + + + Completion script for + <firstterm>UseGetOpt.sh</firstterm> + &usegetoptex; + + + Now, let's try it. + + +bash$ source UseGetOpt-2 + +bash$ ./UseGetOpt-2.sh -[Tab] +-- --aoption --debug --file --help --log --test + -a -d -f -h -l -t + + +bash$ ./UseGetOpt-2.sh --[Tab] +-- --aoption --debug --file --help --log --test + + + + + We begin by sourcing the completion + script. This sets the command-line parameters. + Normally the default parameter completion files reside + in either the /etc/profile.d + directory or in /etc/bash_completion. These autoload on + system startup. So, after writing a useful completion script, you + might wish to move it (as root, of course) + to one of these directories. + + + In the first instance, hitting [Tab] after + a single dash, the output is all the possible parameters preceded by + one or more dashes. Hitting [Tab] + after two dashes gives the possible parameters + preceded by two or more dashes. + + + Now, just what is the point of having to jump through flaming + hoops to enable command-line tab completion? It saves + keystrokes. + It has been extensively documented that + programmers are willing to put in long hours of effort in + order to save ten minutes of unnecessary + labor. This is known as + optimization. + + + + -- + + Resources: + + Bash + programmable completion project + + Mitch Frazier's Linux Journal article, More + on Using the Bash Complete Command + + Steve's excellent two-part article, An Introduction to Bash + Completion: + + Part + 1 and + + Part 2 + diff --git a/LDP/guide/docbook/abs-guide/UseGetOpt-2 b/LDP/guide/docbook/abs-guide/UseGetOpt-2 new file mode 100644 index 00000000..333af4b4 --- /dev/null +++ b/LDP/guide/docbook/abs-guide/UseGetOpt-2 @@ -0,0 +1,27 @@ +# file: UseGetOpt-2 +# UseGetOpt-2.sh parameter-completion + +_UseGetOpt-2 () # By convention, the function name +{ #+ starts with an underscore. + local cur + # Pointer to current completion word. + # By convention, it's named "cur" but this isn't strictly necessary. + + COMPREPLY=() # Array variable storing the possible completions. + cur=${COMP_WORDS[COMP_CWORD]} + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W '-a -d -f -l -t -h --aoption --debug \ + --file --log --test --help --' -- $cur ) );; +# Generate the completion matches and load them into $COMPREPLY array. +# xx) May add more cases here. +# yy) +# zz) + esac + + return 0 +} + +complete -F _UseGetOpt-2 -o filenames ./UseGetOpt-2.sh +# ^^ ^^^^^^^^^^^^ Invokes the function _UseGetOpt-2. diff --git a/LDP/guide/docbook/abs-guide/UseGetOpt-2.sh b/LDP/guide/docbook/abs-guide/UseGetOpt-2.sh new file mode 100755 index 00000000..53975fe3 --- /dev/null +++ b/LDP/guide/docbook/abs-guide/UseGetOpt-2.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# UseGetOpt-2.sh +# Modified version of the script for illustrating tab-expansion +#+ of command-line options. +# See the "Introduction to Tab Expansion" appendix. + +# Possible options: -a -d -f -l -t -h +#+ --aoption, --debug --file --log --test -- help -- + +# Author of original script: 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}'" + } + + 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}" + + + 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 + +# } + +exit diff --git a/LDP/guide/docbook/abs-guide/abs-guide.sgml b/LDP/guide/docbook/abs-guide/abs-guide.sgml index 5fd693c5..1909607f 100644 --- a/LDP/guide/docbook/abs-guide/abs-guide.sgml +++ b/LDP/guide/docbook/abs-guide/abs-guide.sgml @@ -2,6 +2,7 @@ + @@ -319,7 +320,6 @@ - @@ -330,12 +330,15 @@ + + + @@ -368,6 +371,7 @@ + @@ -390,21 +394,14 @@ - 6.0.05 - 24 March 2009 + 6.1 + 30 September 2009 978-1-4357-5219-1 - - 5.5 - 23 Nov 2008 - mc - 'FARKLEBERRY' release: Minor Update. - - 5.6 26 Jan 2009 @@ -416,7 +413,14 @@ 6.0 23 Mar 2009 mc - 'THIMBLEBERRY' release: Minor Update. + 'THIMBLEBERRY' release: Major Update. + + + + 6.1 + 30 Sep 2009 + mc + 'BUFFALOBERRY' release: Minor Update. @@ -511,6 +515,20 @@ their use. Most short scripts work right the first time, and debugging even the longer ones is straightforward. + + +
+ + + In the 1970s, the BASIC language enabled anyone reasonably computer proficient + to write programs on an early generation of microcomputers. Decades later, the Bash + scripting language enables anyone with a rudimentary knowledge of Linux or UNIX to do the same + on much more powerful machines. + +
+
+ + A shell script is a quick-and-dirty method of prototyping a complex application. Getting even a limited subset of the functionality to work in a script is often a useful @@ -653,10 +671,10 @@ give them execute permission (chmod u+rx scriptname), then run them to see what happens. Should the source + url="http://bash.webofcrafts.net/abs-guide-latest.tar.bz2">source archive not be available, then cut-and-paste from the HTML or - pdf + pdf rendered versions. Be aware that some of the scripts presented here introduce features before they are explained, and this may require the reader to temporarily skip ahead for enlightenment. @@ -1053,7 +1071,7 @@ fi linkend="whitespaceref">whitespace at the beginning of a line. - # A tab precedes this comment. + # A tab precedes this comment. Comments may even be embedded @@ -1941,8 +1959,8 @@ echo $var2 # 23skidoo Definition: A process is a currently - executing program, sometimes referred to as a - job. + executing command (or program), sometimes referred + to as a job. of the script in which it appears. @@ -2278,6 +2296,35 @@ echo ${Array[1]} + $[ ... ] + + $[ ] + + + special character + integer expansion + + + integer arithmetic (obsolete) + + + integer expansion + + Evaluate integer expression between + $[ ]. + a=3 +b=7 + +echo $[$a+$b] # 10 +echo $[$a*$b] # 21 + + Note that this usage is deprecated, + and has been replaced by the + (( ... )) construct. + + + + (( )) (( )) @@ -2351,6 +2398,42 @@ echo ${Array[1]} stderr of command to filename. + + + + + + This is useful for suppressing output when + testing for a condition. For example, let us + test whether a certain command exists. + + + + +bash$ type bogus_command &>/dev/null + + + +bash$ echo $? +1 + + + + Or in a script: + + command_test () { type "$1" &>/dev/null; } +# ^ + +cmd=rmdir # Legitimate command. +command_test $cmd; echo $? # 0 + + +cmd=bogus_command # Illegitimate command +command_test $cmd; echo $? # 1 + + + + command >&2 redirects stdout of command @@ -4149,6 +4232,7 @@ $ sh shift-past.sh 1 2 3 4 5 + Encapsulating ! within double quotes gives an error when used from the command line. This is interpreted as a Of more concern is the apparently - inconsistent behavior of \ within double - quotes. + inconsistent behavior of \ + within double quotes, and especially following an + echo -e command. bash$ echo hello\! hello! - bash$ echo "hello\!" hello\! +bash$ echo \ +> +bash$ echo "\" +> +bash$ echo \a +a +bash$ echo "\a" +\a + + +bash$ echo x\ty +xty +bash$ echo "x\ty" +x\ty bash$ echo -e x\ty xty - bash$ echo -e "x\ty" x y - What happens is that double quotes normally - escape the \ escape - character, so that it echoes literally. However, the - option to echo - changes that. It causes the \t to be - interpreted as a tab. + Double quotes following an echo + sometimes escape + \. Moreover, the + option to echo + causes the \t to be interpreted as a + tab. (Thank you, Wayne Pollock, for pointing this out, and Geoff - Lee for explaining it.) + Lee and Daniel Barclay for explaining it.) @@ -4197,9 +4294,12 @@ $ sh shift-past.sh 1 2 3 4 5 Use double quotes to prevent word splitting. - Word splitting, in this context, - means dividing a character string into a number of separate and - discrete arguments. + + Word + splitting, in this context, means dividing + a character string into separate and discrete + arguments. + An argument enclosed in double quotes presents itself as a single word, even if it contains whitespace separators. @@ -4702,6 +4802,7 @@ bar' # Escape character \ taken literally because of strong quoting. 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 or @@ -4778,8 +4879,14 @@ COMMAND_LAST In those instances when there is no return terminating the function. + - After a script terminates, a $? from the + Following the execution of a pipe, a $? + gives the exit status of the last command executed. + + + After a script terminates, a $? from the command-line gives the exit status of the script, that is, the last command executed in the script, which is, by convention, 0 on success or an integer in the @@ -4817,6 +4924,18 @@ true # No error this time, but no negation either. # It just repeats the previous command (true). + +# =========================================================== # +# Preceding a _pipe_ with ! inverts the exit status returned. +ls | bogus_command # bash: bogus_command: command not found +echo $? # 127 + +! ls | bogus_command # bash: bogus_command: command not found +echo $? # 0 +# Note that the ! does not change the execution of the pipe. +# Only the exit status changes. +# =========================================================== # + # Thanks, Stéphane Chazelas and Kristopher Newsome. @@ -5080,7 +5199,17 @@ fi The if test condition-true construct is the exact equivalent of if [ condition-true ]. - As it happens, the left bracket, [ , is a token + As it happens, the left bracket, [ , is a + token + + A + token is a symbol or short + string with a special meaning attached to it (a meta-meaning). In Bash, + certain tokens, such as [ and . (dot-command), may expand to + keywords and commands. + which invokes the test command. The closing right bracket, ] , in an if/test should not therefore be strictly necessary, however newer versions of Bash @@ -5389,12 +5518,17 @@ fi -t - file (descriptor) is + + file (descriptor) is associated with a terminal device - This test option may be used to check whether the - stdin ([ -t 0 ]) - or stdout ([ -t 1 ]) + + This test option may be used + to check whether the stdin + [ -t 0 ] or + stdout [ -t 1 ] in a given script is a terminal. + @@ -5798,9 +5932,32 @@ fi # $String is null. The -o and -a operators work with the test command or occur within single test brackets. - if [ "$exp1" -a "$exp2" ] + if [ "$expr1" -a "$expr2" ] +then + echo "Both expr1 and expr2 are true." +else + echo "Either expr1 or expr2 is false." +fi + + But, as rihad points out: +[ 1 -eq 1 ] && [ -n "`echo true 1>&2`" ] # true +[ 1 -eq 2 ] && [ -n "`echo true 1>&2`" ] # (no output) +# ^^^^^^^ False condition. So far, everything as expected. + +# However ... +[ 1 -eq 2 -a -n "`echo true 1>&2`" ] # true +# ^^^^^^^ False condition. So, why "true" output? + +# Is it because both condition clauses within brackets evaluate? +[[ 1 -eq 2 && -n "`echo true 1>&2`" ]] # (no output) +# No, that's not it. + +# Apparently && and || "short-circuit" while -a and -o do not. + + + Refer to , , and to see compound comparison operators in action. @@ -6605,10 +6762,10 @@ echo "t2 = $t2 a = $a" # t2 = 5 a = 9 Beyond the Basics + Variables Revisited - Used properly, variables can add power and flexibility to scripts. This requires learning their subtleties and nuances. @@ -6793,6 +6950,52 @@ done + + + $CDPATH + + $CDPATH + + + variable + $CDPATH + + + cd path + + + cd + path + + A colon-separated list of search paths + available to the cd + command, similar in function to the $PATH variable for binaries. + The $CDPATH variable may be set in the + local ~/.bashrc + file. + + + +bash$ cd bash-doc +bash: cd: bash-doc: No such file or directory + + +bash$ CDPATH=/usr/share/doc +bash$ cd bash-doc +/usr/share/doc/bash-doc + + +bash$ echo $PWD +/usr/share/doc/bash-doc + + + + + + + $DIRSTACK @@ -8137,17 +8340,19 @@ possibly_hanging_job & { Underscore variable #!/bin/bash -echo $_ # /bin/bash - # Just called /bin/bash to run the script. +echo $_ # /bin/bash + # Just called /bin/bash to run the script. + # Note that this will vary according to + #+ how the script is invoked. -du >/dev/null # So no output from command. -echo $_ # du +du >/dev/null # So no output from command. +echo $_ # du -ls -al >/dev/null # So no output from command. -echo $_ # -al (last argument) +ls -al >/dev/null # So no output from command. +echo $_ # -al (last argument) : -echo $_ # : +echo $_ # : @@ -8890,7 +9095,8 @@ echo "New \$PATH = $PATH" echo ${username-`whoami`} # Echoes the result of `whoami`, if variable $username is still unset. - ${parameter-default} + ${parameter-default} and ${parameter:-default} are almost equivalent. The extra : makes a difference only when parameter @@ -8907,8 +9113,18 @@ echo ${username-`whoami`} filename=${1:-$DEFAULT_FILENAME} # If not otherwise specified, the following command block operates #+ on the file "generic.data". -# -# Commands follow. +# Begin-Command-Block +# ... +# ... +# ... +# End-Command-Block + + + +# From "hanoi2.bash" example: +DISKS=${1:-E_NOPARAM} # Must specify how many disks. +# Set $DISKS to $1 command-line-parameter, +#+ or to $E_NOPARAM if that is unset. See also , - {$var%Pattern} + ${var%Pattern} Remove from $var the shortest part of $Pattern that matches @@ -9149,7 +9365,7 @@ echo "${filename##*.}" # data $var. - {$var%%Pattern} + ${var%%Pattern} Remove from $var the longest part of $Pattern that matches @@ -9562,9 +9778,21 @@ bar # Prints nothing. &indref; - Of what practical use is indirect - referencing of variables? It gives Bash a little of the - functionality of pointers + + + Indirect referencing in Bash + is a multi-step process. First, take the name of a variable: + varname. Then, reference it: + $varname. Then, reference the reference: + $$varname. Then, escape + the first $: \$$varname. + Finally, force a reevaluation of the expression and assign it: + eval newvar=\$$varname. + + + Of what practical use is indirect referencing of + variables? It gives Bash a little of the functionality + of pointers in C, for instance, in table lookup. And, it also has some other very interesting applications. . . . @@ -10798,7 +11026,7 @@ echo $textfile_listing2 Command substitution may - result in word splitting. + result in word splitting. COMMAND `echo a b` # 2 args: a and b COMMAND "`echo a b`" # 1 arg: "a b" @@ -10889,9 +11117,11 @@ variable2=`cat file2` # Set "variable2" to contents of "file2". # This, however, forks a new process, #+ so the line of code executes slower than the above version. -# Note: -# The variables may contain embedded whitespace, -#+ or even (horrors), control characters. +# Note that the variables may contain embedded whitespace, +#+ or even (horrors), control characters. + +# It is not necessary to explicitly assign a variable. +echo "` <$0`" # Echoes the script itself to stdout. @@ -11025,13 +11255,13 @@ File_contents2=$(<$file2) # Bash permits this also.word_count=` wc -w \`ls -l | awk '{print $9}'\` ` + word_count=` wc -w \`echo * | awk '{print $8}'\` ` - word_count=$( wc -w $(ls -l | awk '{print $9}') ) + word_count=$( wc -w $(echo * | awk '{print $8}') ) Or, for something a bit more elaborate . . . @@ -11269,6 +11499,8 @@ let "z += 3" # Quotes permit the use of spaces in variable assignment. column comm command + compgen + complete compress coproc cp @@ -11331,6 +11563,7 @@ let "z += 3" # Quotes permit the use of spaces in variable assignment. fsck ftp fuser + getfacl getopt getopts gettext @@ -11442,6 +11675,7 @@ let "z += 3" # Quotes permit the use of spaces in variable assignment. nslookup objdump od + openssl passwd paste patch @@ -11500,6 +11734,7 @@ let "z += 3" # Quotes permit the use of spaces in variable assignment. seq service set + setfacl setquota setserial setterm @@ -11631,6 +11866,10 @@ let "z += 3" # Quotes permit the use of spaces in variable assignment. set, literally built in. This is either for performance reasons -- builtins execute faster than external commands, which usually require forking off + As Nathan Coulter points out, "while forking a + process is a low-cost operation, executing a new program in + the newly-forked child process adds more + overhead." a separate process -- or because a particular builtin needs direct access to the shell internals. @@ -11659,7 +11898,7 @@ let "z += 3" # Quotes permit the use of spaces in variable assignment. that are subtle and hard to track down. - A script that forks off multiple instances of itself + A script that spawns multiple instances of itself &spawnscr; @@ -12011,6 +12250,7 @@ echo; echo "Keypress was "\"$keypress\""." + Piping output to a read, using echo to set variables -bash$ command_string=xterm -bash$ eval $command_string -Filesystem 1K-blocks Used Available Use% Mounted on - /dev/sda5 1904920 590204 1217952 33% / - /dev/sda9 5409672 892396 4517276 17% /home - /dev/sda1 18431244 13244376 5186868 72% /media/hd - /dev/sda7 10142384 7812496 1814676 82% /usr - /dev/sda8 1138428 258964 821632 24% /var - - - -bash$ process=xterm -bash$ show_process="eval ps ax | grep $process" -bash$ $show_process -1867 tty1 S 0:02 xterm - 2779 tty1 S 0:00 xterm - 2886 pts/1 S 0:00 grep xterm +bash$ command_string="ps ax" +bash$ process="ps ax" +bash$ eval "$command_string" | grep "$process" +26973 pts/3 R+ 0:00 grep --color ps ax + 26974 pts/3 R+ 0:00 ps ax @@ -12337,15 +12565,6 @@ eval eval echo $a # d &rot14; - Rory Winston contributed the following instance of how - useful eval can be. - - - - Using <firstterm>eval</firstterm> to force variable - substitution in a <firstterm>Perl</firstterm> script - &evalex; - The eval command occurs in the older version of indirect @@ -12469,6 +12688,12 @@ eval eval echo $a # d &uns; + In most contexts, an undeclared + variable and one that has been unset + are equivalent. However, the + ${parameter:-default} parameter substitution + construct can distinguish between the two. + @@ -12639,7 +12864,7 @@ eval eval echo $a # d packaged in a while loop, which processes the options and arguments one at a time, then increments the implicit - $OPTIND variable to step to the + $OPTIND variable to point to the next. @@ -12649,7 +12874,7 @@ eval eval echo $a # d The arguments passed from the command-line to the script must be preceded by a - minus (). It is the + dash (). It is the prefixed that lets getopts recognize command-line arguments as options. @@ -13074,6 +13299,10 @@ done + The type command can be useful + for testing whether a + certain command exists. + @@ -17172,6 +17401,66 @@ file $DIRECTORY/* | fgrep $KEYWORD + + getfacl + setfacl + + getfacl + + + command + getfacl + + + setfacl + + + command + setfacl + + + These commands retrieve or + set the file + access control + list -- the owner, + group, and file permissions. + + + bash$ getfacl * +# file: test1.txt + # owner: bozo + # group: bozgrp + user::rw- + group::rw- + other::r-- + + # file: test2.txt + # owner: bozo + # group: bozgrp + user::rw- + group::rw- + other::r-- + + + +bash$ setfacl -m u:bozo:rw yearly_budget.csv +bash$ getfacl yearly_budget.csv +# file: yearly_budget.csv + # owner: accountant + # group: budgetgrp + user::rw- + user:bozo:rw- + user:accountant:rw- + group::rw- + mask::rw- + other::r-- + + + + + + + readlink @@ -17618,18 +17907,30 @@ gzip -cd patchXX.gz | patch -p0 sha1sum - These are utilities for generating checksums. A - checksum is a number mathematically - calculated from the contents of a file, for the purpose - of checking its integrity. A script might refer to a list - of checksums for security purposes, such as ensuring - that the contents of key system files have not been - altered or corrupted. For security applications, use the - md5sum (message - digest 5 - checksum) command, or better yet, - the newer sha1sum (Secure Hash - Algorithm). + These are utilities for + generating checksums. A + checksum is a number + + The checksum may be expressed as a + hexadecimal number, or to some + other base. + + mathematically calculated from the contents of a file, + for the purpose of checking its integrity. A script might + refer to a list of checksums for security purposes, such + as ensuring that the contents of key system files have not + been altered or corrupted. For security applications, use + the md5sum (message + digest 5 + checksum) command, or better yet, the + newer sha1sum (Secure Hash Algorithm). + + For even better + security, use the sha256sum, + sha512, and + sha1pass + commands. + @@ -17699,32 +18000,6 @@ gzip -cd patchXX.gz | patch -p0 - - shred - - shred - - - command - secure delete - - - - Securely erase a file by overwriting it multiple times with - random bit patterns before deleting it. This command has - the same effect as , but does it - in a more thorough and elegant manner. - - This is one of the GNU - fileutils. - - Advanced forensic technology may still be able to - recover the contents of a file, even after application of - shred. - - - - @@ -17833,6 +18108,92 @@ gzip -cd patchXX.gz | patch -p0 + + + + openssl + + openssl + + + command + SSL + + + This is an Open Source implementation of + Secure Sockets Layer encryption. + + # To encrypt a file: +openssl aes-128-ecb -salt -in file.txt -out file.encrypted \ +-pass pass:my_password +# ^^^^^^^^^^^ User-selected password. +# aes-128-ecb is the encryption method chosen. + +# To decrypt an openssl-encrypted file: +openssl aes-128-ecb -d -salt -in file.encrypted -out file.txt \ +-pass pass:my_password +# ^^^^^^^^^^^ User-selected password. + + Piping + openssl to/from tar makes it possible to encrypt + an entire directory tree. + + # To encrypt a directory: + +sourcedir="/home/bozo/testfiles" +encrfile="encr-dir.tar.gz" +password=my_secret_password + +tar czvf - "$sourcedir" | +openssl des3 -salt -out "$encrfile" -pass pass:"$password" +# ^^^^ Uses des3 encryption. +# Writes encrypted file "encr-dir.tar.gz" in current working directory. + +# To decrypt the resulting tarball: +openssl des3 -d -salt -in "$encrfile" -pass pass:"$password" | +tar -xzv +# Decrypts and unpacks into current working directory. + + + + Of course, openssl has many other uses, + such as obtaining signed certificates + for Web sites. See the info + page. + + + + + + + + shred + + shred + + + command + secure delete + + + + Securely erase a file by overwriting it multiple times with + random bit patterns before deleting it. This command has + the same effect as , but does it + in a more thorough and elegant manner. + + This is one of the GNU + fileutils. + + Advanced forensic technology may still be able to + recover the contents of a file, even after application of + shred. + + + + + @@ -19203,7 +19564,7 @@ LIMIT_STRING echo "7 8 * p" | dc # 56 -# Pushes 7, then 8 onto the stack, +# Pushes 7, then 8 onto the stack, #+ multiplies ("*" operator), then prints the result ("p" operator). @@ -19223,7 +19584,7 @@ LIMIT_STRING their mastery of this powerful, but arcane utility. - bash$ echo "16i[q]sa[ln0=aln100%Pln100/snlbx]sbA0D68736142snlbxq" | dc" + bash$ echo "16i[q]sa[ln0=aln100%Pln100/snlbx]sbA0D68736142snlbxq" | dc Bash @@ -20235,9 +20596,9 @@ esac - + @@ -24853,7 +25214,13 @@ done Quoting or escaping the limit string at the head of a here document disables parameter substitution within its - body. + body. The reason for this is that quoting/escaping the + limit string effectively escapes the $, + `, and \ special characters, and causes them to + be interpreted literally. (Thank you, Allen Halsey, for pointing + this out.) Parameter substitution turned off @@ -25010,6 +25377,36 @@ echo "This line had better not echo." # Follows an 'exit' command. + + Some people very cleverly use a + single ! as a limit string. But, that's not + necessarily a good idea. + # This works. +cat <<! +Hello! +! Three more exclamations !!! +! + + +# But . . . +cat <<! +Hello! +Single exclamation point follows! +! +! +# Crashes with an error message. + + +# However, the following will work. +cat <<EOF +Hello! +Single exclamation point follows! +! +EOF +# It's safer to use a multi-character limit string. + + + For those tasks too complex for a here document, consider using the @@ -25892,8 +26289,9 @@ echo "$var1" # 76 substitution comes in. Process substitution feeds the - output of a process (or processes) into the - stdin of another process. + output of a process (or + processes) into the stdin of another + process. <anchor id="commandsparens1">Template @@ -25929,8 +26327,24 @@ echo "$var1" # 76 bash$ echo <(true) /dev/fd/63 - +bash$ echo >(true) <(true) +/dev/fd/63 /dev/fd/62 + + + +bash$ wc <(cat /usr/share/dict/linux.words) + 483523 483523 4992010 /dev/fd/63 + +bash$ grep script /usr/share/dict/linux.words | wc + 262 262 3601 + +bash$ wc <(grep script /usr/share/dict/linux.words) + 262 262 3601 /dev/fd/63 + + + + Bash creates a pipe with two file descriptors, --fIn and fOut--. The stdin @@ -25939,7 +26353,8 @@ echo "$var1" # 76 then Bash passes a /dev/fd/fIn argument to echo. On systems lacking /dev/fd/<n> files, Bash may use - temporary files. (Thanks, S.C.) + temporary files. (Thanks, S.C.) + Process substitution can compare the output of two @@ -25960,9 +26375,10 @@ echo "$var1" # 76 - Using process substitution to compare the contents - of two directories (to see which filenames are in one, - but not the other): + Process substitution can compare the contents + of two directories -- to see which filenames are in one, + but not the other. + diff <(ls $first_directory) <(ls $second_directory) @@ -26391,14 +26807,15 @@ exit $? exit status Functions return a value, called an exit - status. The exit status may be explicitly - specified by a return statement, - otherwise it is the exit status of the last command - in the function (0 if - successful, and a non-zero error code if not). This - exit status - may be used in the script by referencing it as - $?. This mechanism + status. This is analogous to the exit status returned by a + command. The exit status may be explicitly specified + by a return statement, otherwise it + is the exit status of the last command in the function + (0 if successful, and a non-zero + error code if not). This exit + status may be used in the script by referencing it + as $?. This mechanism effectively permits script functions to have a return value similar to C functions. @@ -29405,28 +29822,59 @@ exit 0 interactive shell, it is simply a matter of finding whether the prompt variable, $PS1 is set. (If the user is being - prompted for input, then the script needs to display a prompt.) + prompted for input, then the script needs to display a + prompt.) - if [ -z $PS1 ] # no prompt? + if [ -z $PS1 ] # no prompt? then # non-interactive ... else # interactive ... -fi +fi - Alternatively, the script can test + Alternatively, the script can test for the presence of option i in the $- flag. + linkend="flpref">$- flag. - case $- in + case $- in *i*) # interactive shell ;; *) # non-interactive shell ;; # (Courtesy of "UNIX F.A.Q.," 1993) + However, John Lange describes + an alternative method, using the -t + test operator. + + # Test for a terminal! + +fd=0 # stdin + +# As we recall, the -t test option checks whether the stdin, [ -t 0 ], +#+ or stdout, [ -t 1 ], in a given script is running in a terminal. +if [ -t "$fd" ] +then + echo interactive +else + echo non-interactive +fi + + +# But, as John points out: +# if [ -t 0 ] works ... when you're logged in locally +# but fails when you invoke the command remotely via ssh. +# So for a true test you also have to test for a socket. + +if [[ -t "$fd" || -S /dev/stdin ]] +then + echo interactive +else + echo non-interactive +fi Scripts may be forced to run in interactive mode with the -i option or with a @@ -29910,8 +30358,8 @@ test "$city" \< Paris && echo "Yes, Paris is greater than $city" See also , , and . - + linkend="homework">, , and . There is, however, a major problem with all this. ANSI escape sequences are emphatically @@ -30796,6 +31244,11 @@ echo "User entered: "$answer"" Portability Issues + + It is easier to port a shell than a shell script. + --Larry Wall + + This book deals specifically with Bash scripting on a GNU/Linux system. All the same, users of sh and ksh will find much of value here. @@ -30895,6 +31348,24 @@ echo "User entered: "$answer"" See the Bash F.A.Q. for a complete listing. + + A Test Suite + + Let us illustrate some of the + incompatibilities between Bash and the classic + Bourne shell. Download and install the Heirloom + Bourne Shell and run the following + script, first using Bash, then the classic + sh. + + + Test Suite + &testsuite; + + + + @@ -31086,9 +31557,8 @@ variable="This is a fine mess." echo "$variable" # Regex matching with =~ operator within [[ double brackets ]]. -if [[ "$variable" =~ "T.........fin*es*" ]] -# ^ ^ -# NOTE: Quoting not necessary, as of version 3.2 of Bash. +if [[ "$variable" =~ T.........fin*es* ]] +# NOTE: As of version 3.2 of Bash, expression to match no longer quoted. then echo "match found" # match found @@ -31311,6 +31781,13 @@ echo $a # 6 shell. Coprocs can be named. The input and output file descriptors and the PID of the coprocess are available to the calling shell in variables with coproc-specific names. + + George Dimitriu explains, + "... coproc ... is a feature used in Bash process substitution, + which now is made publicly available." + This means it can be explicitly invoked in a script, rather than + just being a behind-the-scenes mechanism used by Bash. + See http://linux010.blogspot.com/2008/12/bash-process-substitution.html. @@ -31321,14 +31798,18 @@ echo $a # 6 #!/bin/bash4 # A coprocess communicates with a while-read loop. -coproc cat $0 -while read -u ${COPROC[0]} line # ${COPROC[0]} is the -do #+ file descriptor of the coprocess. + +coproc { cat mx_data.txt; sleep 2; } +# ^^^^^^^ +# Try running this without "sleep 2" and see what happens. + +while read -u ${COPROC[0]} line # ${COPROC[0]} is the +do #+ file descriptor of the coprocess. echo "$line" | sed -e 's/line/NOT-ORIGINAL-TEXT/' done -kill $COPROC_PID # No longer need the coprocess, - #+ so kill its PID. +kill $COPROC_PID # No longer need the coprocess, + #+ so kill its PID. But, be careful! @@ -31377,7 +31858,30 @@ coproc cpname { for i in {0..10}; do echo "index = $i"; done; } read -u ${cpname[0]} echo $REPLY # index = 0 echo ${COPROC[0]} #+ No output ... the coprocess timed out - # after the first loop iteration. +# after the first loop iteration. + + + +# However, George Dimitriu has a partial fix. + +coproc cpname { for i in {0..10}; do echo "index = $i"; done; sleep 1; +echo hi > myo; cat - >> myo; } +# ^^^^^ This is a *named* coprocess. + +echo "I am main"$'\04' >&${cpname[1]} +myfd=${cpname[0]} +echo myfd=$myfd + +### while read -u $myfd +### do +### echo $REPLY; +### done + +echo $cpname_PID + +# Run this with and without the commented-out while-loop, and it is +#+ apparent that each process, the executing shell and the coprocess, +#+ waits for the other to finish writing in its own write-enabled pipe. @@ -31622,10 +32126,13 @@ bad_command arg1 arg2 Note to Chet Ramey: Please add only essential features in future Bash releases -- perhaps for-each - loops and support for multi-dimensional arrays. Most - Bash users won't need, won't use, and likely won't greatly - appreciate complex features like built-in debuggers, - Perl interfaces, and bolt-on rocket boosters. + loops and support for multi-dimensional arrays. + And while you're at it, consider fixing + the notorious piped read + problem. + Most Bash users won't need, won't use, and likely won't greatly + appreciate complex features like built-in + debuggers, Perl interfaces, and bolt-on rocket boosters. @@ -31701,7 +32208,7 @@ bad_command arg1 arg2 Those who can, do. Those who can't . . . get an MCSE. This book is somewhat of a departure from his other major work, - + HOW-2 Meet Women: The Shy Man's Guide to Relationships. He has also written the Software-Building @@ -31719,7 +32226,7 @@ bad_command arg1 arg2 Scrabble® adjudicator, the yawl word gaming list package, and the Quacky + url="http://bash.webofcrafts.net/qky.README.html">Quacky anagramming gaming package. He got off to a rather shaky start in the computer game -- programming FORTRAN IV on a CDC 3800 -- and is not the least bit nostalgic for those days. @@ -31763,6 +32270,12 @@ bad_command arg1 arg2 your purposes. + + ... sophisticated in mechanism but possibly agile + operating under noises being extremely suppressed ... +--CI-300 printer manual + + @@ -31949,24 +32462,25 @@ bad_command arg1 arg2 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, + Bjön Eriksson, John MacDonald, John Lange, 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, Chetankumar Phulpagare, Benno + Schulenberg, Tedman Eng, Jochen DeSmet, Juan Nicolas Ruiz, Oliver Beckstein, Achmed Darwish, Dotan Barak, Richard Neill, Albert Siersema, Omair Eshkenazi, Geoff Lee, JuanJo Ciarlante, - Cliff Bamford, Nathan Coulter, Antonio Macchi, Tomas Pospisek, - Andreas Kühne, Pádraig Brady, and David Lawyer - (himself an author of four HOWTOs). + Cliff Bamford, Nathan Coulter, George Dimitriu, Antonio Macchi, + Tomas Pospisek, Andreas Kühne, Pádraig Brady, and + David Lawyer (himself an author of four HOWTOs). My gratitude to Chet Ramey and Brian Fox for writing Bash, @@ -31984,6 +32498,10 @@ bad_command arg1 arg2 all the good people fighting the good fight to keep Open Source software free and open. + Belated thanks to my fourth grade teacher, Miss Spencer, + for emotional support and for convincing me that maybe, just + maybe I wasn't a total loss. + Thanks most of all to my wife, Anita, for her encouragement, inspiration, and emotional support. @@ -32814,6 +33332,14 @@ bad_command arg1 arg2 + + + Philip Patterson's logforbash + logging/debugging script. + + + Of historical interest are Colin Needham's @@ -33299,6 +33825,18 @@ bad_command arg1 arg2 &usegetopt; + + The version of the + <firstterm>UseGetOpt.sh</firstterm> example used in the <link + linkend="tabexpansion">Tab Expansion appendix</link> + &usegetopt2; + + + + Cycling through all the possible color backgrounds + &showallc; + + To end this section, a review of the basics . . . and more. @@ -35198,6 +35736,15 @@ exit 0 + + + &TABEXP; + + + + + + Localization @@ -37491,6 +38038,11 @@ thegrendel@theriver.com 23 Mar 2009 THIMBLEBERRY release: Major update. + + + 30 Sep 2009 + BUFFALOBERRY release: Minor update. + @@ -37507,15 +38059,15 @@ thegrendel@theriver.com bzip2-ed tarball including both the SGML source and rendered HTML, may be downloaded from the author's + url="http://bash.webofcrafts.net/abs-guide-latest.tar.bz2">author's home site). A + url="http://bash.webofcrafts.net/abs-guide.pdf"> pdf version is also available. The change + url="http://bash.webofcrafts.net/Change.log">change log gives a detailed revision history. The ABS Guide even has @@ -37528,7 +38080,7 @@ thegrendel@theriver.com which maintains many other Guides and HOWTOs as well. Many thanks to Ronny Bangsund for donating server space to host + url="http://bash.webofcrafts.net/">server space to host this project. @@ -37577,10 +38129,9 @@ thegrendel@theriver.com Guide is copyright 2000, by Mendel Cooper. - The ISBN of the print - edition of this book is - 978-1-4357-5219-1. + A printed edition of a substantively rewritten + version of the book will be released in fall of + 2010. The author also asserts copyright on all previous versions of this document. The author intends that this book be released diff --git a/LDP/guide/docbook/abs-guide/col-totaler2.sh b/LDP/guide/docbook/abs-guide/col-totaler2.sh index 7e82599d..f5343748 100644 --- a/LDP/guide/docbook/abs-guide/col-totaler2.sh +++ b/LDP/guide/docbook/abs-guide/col-totaler2.sh @@ -28,7 +28,7 @@ column_number=$2 # Which column to total up. # Begin awk script. -# ------------------------------------------------ +# ------------------------------------------------- awk " { total += \$${column_number} # Indirect reference @@ -38,7 +38,8 @@ END { } " "$filename" -# ------------------------------------------------ +# Note that awk doesn't need an eval preceding \$$. +# ------------------------------------------------- # End awk script. # Indirect variable reference avoids the hassles diff --git a/LDP/guide/docbook/abs-guide/encryptedpw.sh b/LDP/guide/docbook/abs-guide/encryptedpw.sh index dc568f80..76c7373d 100644 --- a/LDP/guide/docbook/abs-guide/encryptedpw.sh +++ b/LDP/guide/docbook/abs-guide/encryptedpw.sh @@ -6,7 +6,7 @@ #+ since the decrypted password is sent in the clear. # Use something like "ssh" if this is a concern. -E_BADARGS=65 +E_BADARGS=85 if [ -z "$1" ] then diff --git a/LDP/guide/docbook/abs-guide/ex33.sh b/LDP/guide/docbook/abs-guide/ex33.sh index 5c815b6f..e136110d 100644 --- a/LDP/guide/docbook/abs-guide/ex33.sh +++ b/LDP/guide/docbook/abs-guide/ex33.sh @@ -1,34 +1,36 @@ #!/bin/bash -# Exercising getopts and OPTIND -# Script modified 10/09/03 at the suggestion of Bill Gradwohl. +# ex33.sh: Exercising getopts and OPTIND +# Script modified 10/09/03 at the suggestion of Bill Gradwohl. # Here we observe how 'getopts' processes command-line arguments to script. # The arguments are parsed as "options" (flags) and associated arguments. -# Try invoking this script with -# 'scriptname -mn' -# 'scriptname -oq qOption' (qOption can be some arbitrary string.) -# 'scriptname -qXXX -r' +# Try invoking this script with: +# 'scriptname -mn' +# 'scriptname -oq qOption' (qOption can be some arbitrary string.) +# 'scriptname -qXXX -r' # -# 'scriptname -qr' - Unexpected result, takes "r" as the argument to option "q" -# 'scriptname -q -r' - Unexpected result, same as above -# 'scriptname -mnop -mnop' - Unexpected result -# (OPTIND is unreliable at stating where an option came from). +# 'scriptname -qr' +#+ - Unexpected result, takes "r" as the argument to option "q" +# 'scriptname -q -r' +#+ - Unexpected result, same as above +# 'scriptname -mnop -mnop' - Unexpected result +# (OPTIND is unreliable at stating where an option came from.) # # If an option expects an argument ("flag:"), then it will grab #+ whatever is next on the command-line. NO_ARGS=0 -E_OPTERROR=65 +E_OPTERROR=85 -if [ $# -eq "$NO_ARGS" ] # Script invoked with no command-line args? +if [ $# -eq "$NO_ARGS" ] # Script invoked with no command-line args? then echo "Usage: `basename $0` options (-mnopqrs)" - exit $E_OPTERROR # Exit and explain usage, if no argument(s) given. + exit $E_OPTERROR # Exit and explain usage. + # Usage: scriptname -options + # Note: dash (-) necessary fi -# Usage: scriptname -options -# Note: dash (-) necessary while getopts ":mnopq:rs" Option @@ -38,22 +40,23 @@ do n | o ) echo "Scenario #2: option -$Option- [OPTIND=${OPTIND}]";; p ) echo "Scenario #3: option -p- [OPTIND=${OPTIND}]";; q ) echo "Scenario #4: option -q-\ - with argument \"$OPTARG\" [OPTIND=${OPTIND}]";; + with argument \"$OPTARG\" [OPTIND=${OPTIND}]";; # Note that option 'q' must have an associated argument, #+ otherwise it falls through to the default. r | s ) echo "Scenario #5: option -$Option-";; - * ) echo "Unimplemented option chosen.";; # DEFAULT + * ) echo "Unimplemented option chosen.";; # Default. esac done shift $(($OPTIND - 1)) # Decrements the argument pointer so it points to next argument. -# $1 now references the first non option item supplied on the command-line +# $1 now references the first non-option item supplied on the command-line #+ if one exists. -exit 0 +exit $? # As Bill Gradwohl states, # "The getopts mechanism allows one to specify: scriptname -mnop -mnop -#+ but there is no reliable way to differentiate what came from where -#+ by using OPTIND." +#+ but there is no reliable way to differentiate what came +#+ from where by using OPTIND." +# There are, however, workarounds. diff --git a/LDP/guide/docbook/abs-guide/ex43.sh b/LDP/guide/docbook/abs-guide/ex43.sh index 8638d84c..325028a3 100644 --- a/LDP/guide/docbook/abs-guide/ex43.sh +++ b/LDP/guide/docbook/abs-guide/ex43.sh @@ -18,6 +18,15 @@ echo echo "===========================================================" echo +eval "`seq 3 | sed -e 's/.*/echo var&=ABCDEFGHIJ/'`" +# var1=ABCDEFGHIJ +# var2=ABCDEFGHIJ +# var3=ABCDEFGHIJ + +echo +echo "===========================================================" +echo + # Now, showing how to do something useful with "eval" . . . # (Thank you, E. Choroba!) diff --git a/LDP/guide/docbook/abs-guide/ex63.sh b/LDP/guide/docbook/abs-guide/ex63.sh index b6512765..256aac41 100644 --- a/LDP/guide/docbook/abs-guide/ex63.sh +++ b/LDP/guide/docbook/abs-guide/ex63.sh @@ -10,8 +10,8 @@ MAX_ARG=5 -E_WRONG_ARGS=65 -E_RANGE_ERR=66 +E_WRONG_ARGS=85 +E_RANGE_ERR=86 if [ -z "$1" ] @@ -22,7 +22,7 @@ fi if [ "$1" -gt $MAX_ARG ] then - echo "Out of range (5 is maximum)." + echo "Out of range ($MAX_ARG is maximum)." # Let's get real now. # If you want greater range than this, #+ rewrite it in a Real Programming Language. diff --git a/LDP/guide/docbook/abs-guide/ex67.sh b/LDP/guide/docbook/abs-guide/ex67.sh index 9490cc1d..904c2b92 100644 --- a/LDP/guide/docbook/abs-guide/ex67.sh +++ b/LDP/guide/docbook/abs-guide/ex67.sh @@ -30,8 +30,7 @@ do # List all the elements in the array. # ${colors[index]} also works because it's within ${ ... } brackets. let "index = $index + 1" # Or: - # index+=1 - # if running Bash, version 3.1 or later. + # ((index++)) done # Each array element listed on a separate line. # If this is not desired, use echo -n "${colors[$index]} " diff --git a/LDP/guide/docbook/abs-guide/ex68.sh b/LDP/guide/docbook/abs-guide/ex68.sh index 7d517566..4046cd09 100644 --- a/LDP/guide/docbook/abs-guide/ex68.sh +++ b/LDP/guide/docbook/abs-guide/ex68.sh @@ -62,7 +62,7 @@ sift () # Sift out the non-primes. { let i=$LOWER_LIMIT+1 -# We know 1 is prime, so let's start with 2. +# Let's start with 2. until [ "$i" -gt "$UPPER_LIMIT" ] do diff --git a/LDP/guide/docbook/abs-guide/ex71c.sh b/LDP/guide/docbook/abs-guide/ex71c.sh index 3c7ae23f..ed2657c9 100644 --- a/LDP/guide/docbook/abs-guide/ex71c.sh +++ b/LDP/guide/docbook/abs-guide/ex71c.sh @@ -17,4 +17,25 @@ Endofmessage # cat <<"Endofmessage" # cat <<\Endofmessage + + +# And, likewise: + +cat <<"SpecialCharTest" + +Directory listing would follow +if limit string were not quoted. +`ls -l` + +Arithmetic expansion would take place +if limit string were not quoted. +$((5 + 3)) + +A a single backslash would echo +if limit string were not quoted. +\\ + +SpecialCharTest + + exit diff --git a/LDP/guide/docbook/abs-guide/file-info.sh b/LDP/guide/docbook/abs-guide/file-info.sh index b65867b0..d706ed93 100644 --- a/LDP/guide/docbook/abs-guide/file-info.sh +++ b/LDP/guide/docbook/abs-guide/file-info.sh @@ -20,7 +20,7 @@ do continue # On to next. fi - ls -l $file | awk '{ print $9 " file size: " $5 }' # Print 2 fields. + ls -l $file | awk '{ print $8 " file size: " $5 }' # Print 2 fields. whatis `basename $file` # File info. # Note that the whatis database needs to have been set up for this to work. # To do this, as root run /usr/bin/makewhatis. diff --git a/LDP/guide/docbook/abs-guide/hanoi2.bash b/LDP/guide/docbook/abs-guide/hanoi2.bash index 75cfde4d..bbabe851 100644 --- a/LDP/guide/docbook/abs-guide/hanoi2.bash +++ b/LDP/guide/docbook/abs-guide/hanoi2.bash @@ -5,38 +5,41 @@ # http://hanoi.kernelthread.com # hanoi2.bash -# Version 2: modded for ASCII-graphic display. +# Version 2.00: modded for ASCII-graphic display. +# Version 2.01: fixed no command-line param bug. # Uses code contributed by Antonio Macchi, #+ with heavy editing by ABS Guide author. -# This variant also falls under the original copyright, see above. +# This variant falls under the original copyright, see above. # Used in ABS Guide with Amit Singh's permission (thanks!). -# Variables # +### Variables && sanity check ### + E_NOPARAM=86 -E_BADPARAM=87 # Illegal no. of disks passed to script. +E_BADPARAM=87 # Illegal no. of disks passed to script. E_NOEXIT=88 -DISKS=$1 + +DISKS=${1:-E_NOPARAM} # Must specify how many disks. Moves=0 MWIDTH=7 MARGIN=2 -# Arbitrary "magic" constants, work okay for relatively small # of disks. +# Arbitrary "magic" constants; work okay for relatively small # of disks. # BASEWIDTH=51 # Original code. -let "basewidth = $MWIDTH * $DISKS + $MARGIN" # "Base" beneath rods. +let "basewidth = $MWIDTH * $DISKS + $MARGIN" # "Base" beneath rods. # Above "algorithm" could likely stand improvement. -# Display variables. +### Display variables ### let "disks1 = $DISKS - 1" let "spaces1 = $DISKS" let "spaces2 = 2 * $DISKS" -let "lastmove_t = $DISKS - 1" # Final move? +let "lastmove_t = $DISKS - 1" # Final move? declare -a Rod1 Rod2 Rod3 -################# +### ######################### ### function repeat { # $1=char $2=number of repetitions @@ -131,6 +134,7 @@ then # Last move? If yes, then display final position. fi } + # From here down, almost the same as original (hanoi.bash) script. dohanoi() { # Recursive function. @@ -152,6 +156,7 @@ dohanoi() { # Recursive function. esac } + setup_arrays () { local dim n elem @@ -179,7 +184,7 @@ case $# in 1) disks=$1 dohanoi $1 1 3 2 -# Total moves = 2^n - 1, where n = # of disks. +# Total moves = 2^n - 1, where n = number of disks. echo exit 0; ;; @@ -190,6 +195,7 @@ case $# in esac ;; *) + clear echo "usage: $0 N" echo " Where \"N\" is the number of disks." exit $E_NOPARAM; diff --git a/LDP/guide/docbook/abs-guide/ind-ref.sh b/LDP/guide/docbook/abs-guide/ind-ref.sh index c235faad..6dd91db7 100644 --- a/LDP/guide/docbook/abs-guide/ind-ref.sh +++ b/LDP/guide/docbook/abs-guide/ind-ref.sh @@ -11,7 +11,8 @@ echo "\$var = $var" # $var = 23 echo "\$\$var = $$var" # $$var = 4570var # Not useful ... -# \$\$ expanded to PID of process being executed, +# \$\$ expanded to PID of the script +# -- refer to the entry on the $$ variable -- #+ and "var" is echoed as plain text. # (Thank you, Jakob Bohm, for pointing this out.) @@ -71,7 +72,8 @@ echo # (Thanks, Stephane Chazelas, for clearing up the above behavior.) -# Another method is the ${!t} notation, discussed in "Bash, version 2" section. -# See also ex78.sh. +# A more straightforward method is the ${!t} notation, discussed in the +#+ "Bash, version 2" section. +# See also ex78.sh. exit 0 diff --git a/LDP/guide/docbook/abs-guide/ktour.sh b/LDP/guide/docbook/abs-guide/ktour.sh index 9b67a7df..ebd5783a 100644 --- a/LDP/guide/docbook/abs-guide/ktour.sh +++ b/LDP/guide/docbook/abs-guide/ktour.sh @@ -4,7 +4,7 @@ # author: mendel cooper # reldate: 12 Jan 2009 # license: public domain -# (Not much sense in GPLing something that's pretty much in the common +# (Not much sense GPLing something that's pretty much in the common #+ domain anyhow.) ################################################################### @@ -17,7 +17,7 @@ # Could it be that he has a habit of partying into the wee hours # #+ of the morning? # # Possibly he leaves pizza crusts in the bed, empty beer bottles # -#+ all over the floor, and clogs the plumbing. ... # +#+ all over the floor, and clogs the plumbing. . . . # # # # ------------------------------------------------------------- # # # diff --git a/LDP/guide/docbook/abs-guide/readpipe.sh b/LDP/guide/docbook/abs-guide/readpipe.sh index d2e41429..9f48d24b 100644 --- a/LDP/guide/docbook/abs-guide/readpipe.sh +++ b/LDP/guide/docbook/abs-guide/readpipe.sh @@ -9,7 +9,10 @@ do echo "{$line}" last=$line done -printf "\nAll done, last:$last\n" + +echo +echo "++++++++++++++++++++++" +printf "\nAll done, last: $last\n" exit 0 # End of code. # (Partial) output of script follows. @@ -27,9 +30,10 @@ exit 0 # End of code. {echo "{$line}"} {last=$line} {done} -{printf "nAll done, last:$lastn"} +{printf "nAll done, last: $lastn"} -All done, last:(null) +All done, last: (null) -The variable (last) is set within the subshell but unset outside. +The variable (last) is set within the loop/subshell +but its value does not persist outside the loop. diff --git a/LDP/guide/docbook/abs-guide/show-all-colors.sh b/LDP/guide/docbook/abs-guide/show-all-colors.sh new file mode 100644 index 00000000..b0230e12 --- /dev/null +++ b/LDP/guide/docbook/abs-guide/show-all-colors.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# show-all-colors.sh +# Displays all 256 possible background colors, using ANSI escape sequences. +# Author: Chetankumar Phulpagare +# Used in ABS Guide with permission. + +T1=8 +T2=6 +T3=36 +offset=0 + +for num1 in {0..7} +do { + for num2 in {0,1} + do { + shownum=`echo "$offset + $T1 * ${num2} + $num1" | bc` + echo -en "\E[0;48;5;${shownum}m color ${shownum} \E[0m" + } + done + echo + } +done + +offset=16 +for num1 in {0..5} +do { + for num2 in {0..5} + do { + for num3 in {0..5} + do { + shownum=`echo "$offset + $T2 * ${num3} \ + + $num2 + $T3 * ${num1}" | bc` + echo -en "\E[0;48;5;${shownum}m color ${shownum} \E[0m" + } + done + echo + } + done +} +done + +offset=232 +for num1 in {0..23} +do { + shownum=`expr $offset + $num1` + echo -en "\E[0;48;5;${shownum}m ${shownum}\E[0m" +} +done + +echo diff --git a/LDP/guide/docbook/abs-guide/symlinks.sh b/LDP/guide/docbook/abs-guide/symlinks.sh index e1bfff5b..44060aac 100644 --- a/LDP/guide/docbook/abs-guide/symlinks.sh +++ b/LDP/guide/docbook/abs-guide/symlinks.sh @@ -30,7 +30,7 @@ done | sort # Otherwise file list is unsorted. # As Dominik 'Aeneas' Schnitzer points out, #+ failing to quote $( find $directory -type l ) #+ will choke on filenames with embedded whitespace. -# Even this will only pick up the first field of each argument. +# containing whitespace. exit 0 diff --git a/LDP/guide/docbook/abs-guide/test-suite.sh b/LDP/guide/docbook/abs-guide/test-suite.sh new file mode 100644 index 00000000..ffc6e116 --- /dev/null +++ b/LDP/guide/docbook/abs-guide/test-suite.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# test-suite.sh +# A partial Bash compatibility test suite. + + +# Double brackets (test) +String="Double brackets supported?" +echo -n "Double brackets test: " +if [[ "$String" = "Double brackets supported?" ]] +then + echo "PASS" +else + echo "FAIL" +fi + + +# Double brackets and regex matching +String="Regex matching supported?" +echo -n "Regex matching: " +if [[ "$String" =~ R.....matching* ]] +then + echo "PASS" +else + echo "FAIL" +fi + + +# Arrays +test_arr=FAIL +Array=( If supports arrays will print PASS ) +test_arr=${Array[5]} +echo "Array test: $test_arr" + + +# Completing this script is an exercise for the reader. +# Add to the above similar tests for double parentheses, +#+ brace expansion, $() command substitution, etc. + +exit $? diff --git a/LDP/guide/docbook/abs-guide/unset.sh b/LDP/guide/docbook/abs-guide/unset.sh index be9174a4..6bbe6e33 100644 --- a/LDP/guide/docbook/abs-guide/unset.sh +++ b/LDP/guide/docbook/abs-guide/unset.sh @@ -1,14 +1,15 @@ #!/bin/bash # unset.sh: Unsetting a variable. -variable=hello # Initialized. +variable=hello # Initialized. echo "variable = $variable" -unset variable # Unset. - # Same effect as: variable= -echo "(unset) variable = $variable" # $variable is null. +unset variable # Unset. + # In this particular context, + #+ same effect as: variable= +echo "(unset) variable = $variable" # $variable is null. -if [ -z "$variable" ] # Try a string-length test. +if [ -z "$variable" ] # Try a string-length test. then echo "\$variable has zero length." fi diff --git a/LDP/guide/docbook/abs-guide/wr-ps.bash b/LDP/guide/docbook/abs-guide/wr-ps.bash index ada8f8f4..d2fd8a3b 100644 --- a/LDP/guide/docbook/abs-guide/wr-ps.bash +++ b/LDP/guide/docbook/abs-guide/wr-ps.bash @@ -26,7 +26,7 @@ done < <( echo "random input" ) # ^ ^ echo "\$global (using process substitution) = $global" -# random input +# Random input # $global (using process substitution) = 3D: Available outside the loop. @@ -60,6 +60,6 @@ do # It does *not* run in a subshell, so ... done < <( cat $0 ) echo "OUTPUT = " -echo ${outloop[*]} # ... the entire script echoes. +echo ${outloop[*]} # ... the entire script echoes. exit $? diff --git a/LDP/howto/docbook/HOWTO-INDEX/howtoChap.sgml b/LDP/howto/docbook/HOWTO-INDEX/howtoChap.sgml index b83c2de5..c7f578ba 100644 --- a/LDP/howto/docbook/HOWTO-INDEX/howtoChap.sgml +++ b/LDP/howto/docbook/HOWTO-INDEX/howtoChap.sgml @@ -1215,7 +1215,7 @@ DVD drive. Ecology-HOWTO, Linux Ecology HOWTO -Updated: Jun 2007. +Updated: Aug 2009. Discusses ways to make computers less harmful to our environment and to solve some ecological issues. It explains how to use Linux to save power and consumables like paper and ink. Since it does not diff --git a/LDP/howto/docbook/HOWTO-INDEX/miscSect.sgml b/LDP/howto/docbook/HOWTO-INDEX/miscSect.sgml index 6dddd733..4f4918fe 100644 --- a/LDP/howto/docbook/HOWTO-INDEX/miscSect.sgml +++ b/LDP/howto/docbook/HOWTO-INDEX/miscSect.sgml @@ -375,7 +375,7 @@ Yes, Linux DOES make coffee, and it tastes good. Ecology-HOWTO, Linux Ecology HOWTO -Updated: Jun 2007. +Updated: Aug 2009. Discusses ways to make computers less harmful to our environment and to solve some ecological issues. It explains how to use Linux to save power and consumables like paper and ink. Since it does not