From 1023b2f15b7f193b8ac82cae939d7f4069b7318a Mon Sep 17 00:00:00 2001 From: gferg <> Date: Mon, 12 May 2003 14:45:05 +0000 Subject: [PATCH] updated --- LDP/guide/docbook/abs-guide/Change.log | 74 ++++ LDP/guide/docbook/abs-guide/README | 2 + LDP/guide/docbook/abs-guide/abs-guide.sgml | 438 +++++++++++++++---- LDP/guide/docbook/abs-guide/bashrc | 334 +++++++++----- LDP/guide/docbook/abs-guide/blot-out.sh | 2 +- LDP/guide/docbook/abs-guide/cvt.sh | 8 +- LDP/guide/docbook/abs-guide/empty-array.sh | 104 ++++- LDP/guide/docbook/abs-guide/ex41.sh | 6 + LDP/guide/docbook/abs-guide/self-document.sh | 2 +- LDP/guide/docbook/abs-guide/tree.sh | 2 +- 10 files changed, 772 insertions(+), 200 deletions(-) diff --git a/LDP/guide/docbook/abs-guide/Change.log b/LDP/guide/docbook/abs-guide/Change.log index 42775ccd..d189b322 100644 --- a/LDP/guide/docbook/abs-guide/Change.log +++ b/LDP/guide/docbook/abs-guide/Change.log @@ -3,6 +3,80 @@ RELEASE HISTORY Change log +Version 1.8 [Cleanups & revisions] +Working toward 'BREADFRUIT' release + + +1) Revised "self-document.sh" to remove unnecessary 'cat.' + +2) In "cvt.sh" example, quoted target file name and added exercise. + +3) Updated Jordi Sanfeliu's e-mail address in "Credits" chapter and in + "tree.sh" example script. + +4) In "blot-out.sh" script, updated the Peter Gutmann URL. + +5) In "Miscellaneous" subsection of "System and Administrative Commands" + chapter" + Added "watch" command. + +6) In the introduction, in reason not to use shell scripts, + Removed misleading reference to Open Source (thank you, Peter Lietz, for + pointing this out). + +7) In "Quoting" chapter: + Added footnote about problem double quoting "!" and "\!". + (Thanks, Wayne Pollock.) + +8) In "Internal Commands" chapter: + Added caution about 'cd //' problem. (Thanks, Wayne Pollock.) + Added short example of "$!" usage. (Thanks, Jacques Lederer.) + +9) In "Arrays" chapter: + Replaced "empty-array.sh" with an extended version. + Added note that Bash treats variables as arrays, even if not declared as + such. + Added example of nested arrays. + Added example of copying and concatenating arrays. + (All the above thanks to Michael Zick.) + +10) In "Tests" chapter: + Fixed up "Tests Constructs" section link (finally!). + +11) In "Command Substitution" chapter: + Added mention of $(<$file) construct. + +12) In "Functions" chapter: + Added material to nested functions in-line examples. + +13) In the "Portability Issues" section of the "Miscellany" chapter: + Added short list of Bash-specific features. + +14) In "File and Archiving Commands" section of "External Commands" Chapter: + Added "dos2unix" utility. + +15) In "Gotchas" chapter: + Added short in-line example of using an uninitialized variable. + Added in-line example showing DOS-formatted script failing to run. + +16) In "Contributed Scripts" appendix: + Added Michael Zick's "directory-info.sh" script. + +17) In "Bibliography" section: + Updated "The UNIX CD Bookshelf" reference. + Added Eric Pement's sed resources page. + Removed outdated "Sed F.A.Q." reference. + Updated Frisch entry. + Updated Shelldorado and Giles Orr entries. + +18) Updated sample .bashrc file (Appendix G). + +19) A few minor error corrections and clean ups at various places in the + text. + + + + Version 1.7 (minor update) 'COCONUT' release 01/05/03 diff --git a/LDP/guide/docbook/abs-guide/README b/LDP/guide/docbook/abs-guide/README index b84ba810..824fca76 100644 --- a/LDP/guide/docbook/abs-guide/README +++ b/LDP/guide/docbook/abs-guide/README @@ -17,6 +17,8 @@ read-r.sh rnd.sh rot13.sh here-function.sh +directory-info.sh (lines 273 and 353) +bashrc (comments on lines 596 and 618) have the "<" and ">" in place of angle brackets (< and >), or & in place of the ampersand (&). This is necessary for the Docbook SGML diff --git a/LDP/guide/docbook/abs-guide/abs-guide.sgml b/LDP/guide/docbook/abs-guide/abs-guide.sgml index 82ceac12..04053def 100644 --- a/LDP/guide/docbook/abs-guide/abs-guide.sgml +++ b/LDP/guide/docbook/abs-guide/abs-guide.sgml @@ -268,6 +268,8 @@ Uncomment line below to generate index. + + @@ -277,20 +279,20 @@ Uncomment line below to generate index. Advanced Bash-Scripting Guide - An in-depth exploration of the gentle art of shell scripting + An in-depth exploration of the art of shell scripting Mendel Cooper - Brindle-Phlogiston Associates +
thegrendel@theriver.com
- 1.7 - 05 January 2003 + 1.8 + 10 May 2003 @@ -395,6 +397,14 @@ Uncomment line below to generate index. more script. + + 1.8 + 10 May 2003 + mc + 'BREADFRUIT' release: a number of bugfixes, more scripts + and material. + + @@ -402,7 +412,7 @@ Uncomment line below to generate index. This tutorial assumes no previous knowledge of scripting or programming, but progresses rapidly toward an - intermediate/advanced level of instruction ...all + 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 @@ -415,7 +425,7 @@ Uncomment line below to generate index. linkend="bzipref">bzip2-ed tarball including both the SGML source and rendered HTML, may be downloaded from + url="http://personal.riverusers.com/~thegrendel/abs-guide-1.8.tar.bz2"> the author's home site. See the change log for a revision history. @@ -456,7 +466,7 @@ Uncomment line below to generate index. A working knowledge of shell scripting is essential to anyone - wishing to become reasonably adept at system administration, + wishing to become reasonably proficient at system administration, even if they do not anticipate ever having to actually write a script. Consider that as a Linux machine boots up, it executes the shell scripts in /etc/rc.d @@ -510,7 +520,7 @@ Uncomment line below to generate index. cross-platform portability required (use C instead) complex applications, where structured programming is - a necessity (need typechecking of variables, function + a necessity (need type-checking of variables, function prototypes, etc.) mission-critical applications upon which you are betting the @@ -539,8 +549,9 @@ Uncomment line below to generate index. need to use libraries or interface with legacy code - proprietary, closed-source applications (shell scripts are - necessarily Open Source) + proprietary, closed-source applications (shell scripts put the + source code right out in the open for all the world to see) + @@ -562,19 +573,19 @@ Uncomment line below to generate index. and even a few from the updated ksh93 have been merged into Bash. - and the C Shell and its variants. (Note that C Shell programming + and the C Shell and its variants. (Note that C Shell programming is not recommended due to certain inherent problems, as pointed out in an October, 1993 Usenet - post by Tom Christiansen). + post by Tom Christiansen.) What follows is a tutorial on shell scripting. It relies heavily on examples to illustrate various features of the shell. - As far as possible, the example scripts have been tested, - and some of them may even be useful in real life. The - reader should use the actual examples in the source archive - (something-or-other.sh), + The example scripts work -- they've been tested -- and some + of them are even useful in real life. The reader can play with + the actual working code of the examples in the source archive + (scriptname.sh), By convention, user-written shell scripts that are Bourne shell compliant generally take a name with a @@ -585,13 +596,13 @@ Uncomment line below to generate index. give them execute permission (chmod u+rx scriptname), then run them to see what happens. Should the source archive not be available, then cut-and-paste from - the HTML, pdf, or text rendered versions. Be aware that some of + the HTML, pdf, or text rendered versions. Be aware that some of the scripts below introduce features before they are explained, and this may require the reader to temporarily skip ahead for enlightenment. - Unless otherwise noted, the book author wrote the example - scripts that follow. + Unless otherwise noted, the author of this book wrote the + example scripts that follow. @@ -906,9 +917,9 @@ fi Of course, an escaped # in an echo statement does not begin a comment. Likewise, a - # appears in certain - parameter substitution constructs and in numerical constant expressions. + # appears in certain parameter + substitution constructs and in + numerical constant expressions. echo "The # here does not begin a comment." echo 'The # here does not begin a comment.' @@ -2884,6 +2895,7 @@ arch=$(uname -m) Bash Variables Are Untyped + Unlike many other programming languages, Bash does not segregate its variables by type. Essentially, Bash variables are character strings, but, depending on context, Bash @@ -2946,10 +2958,11 @@ arch=$(uname -m) any other process. Every time a shell starts, it creates shell variables that - correspond to its own environmental variables. Updating or - adding new shell variables causes the shell to update its - environment, and all the shell's child processes (the commands - it executes) inherit this environment. + correspond to its own environmental variables. Updating + or adding new environmental variables causes the shell + to update its environment, and all the shell's child + processes (the commands it executes) inherit this + environment. @@ -3185,8 +3198,45 @@ fi enclose it in double quotes (" "). This preserves all special characters within the variable name, except $, ` (backquote), - and \ (escape). Keeping $ - as a special character permits referencing a quoted variable + and \ (escape). + + + + Encapsulating ! within double + quotes gives an error when used from the command + line. Apparently this is interpreted as a history command. Within a script, + though, this problem does not occur. + + Of more concern is the inconsistent behavior of + \ within double quotes. + + +bash$ echo hello\! +hello! + + +bash$ echo "hello\!" +hello\! + + + + +bash$ echo -e x\ty +xty + + +bash$ echo -e "x\ty" +x y + + + (Thank you, Wayne Pollock, for pointing this out.) + + + + + Keeping $ as a special character within + double quotes permits referencing a quoted variable ("$variable"), that is, replacing the variable with its value (see , above). @@ -3750,7 +3800,9 @@ echo "exit status of \"! true\" = $?" # 1 if/then construct. - <anchor id="testconstructs1">Test Constructs + Test Constructs + + @@ -3993,8 +4045,8 @@ fi The [[ ]] construct - is the shell equivalent of [ ]. This is the - extended test command, adopted from + is the more versatile Bash version of [ ]. This + is the extended test command, adopted from ksh88. No filename expansion or word splitting takes place @@ -6468,7 +6520,28 @@ echo "$@" # 3 4 5 last job background + PID (process id) of last job run in background + + + LOG=$0.log + +COMMAND1="sleep 100" + +echo "Logging PIDs background commands for script: $0" >> "$LOG" +# So they can be monitored, and killed as necessary. +echo >> "$LOG" + +# Logging commands. + +echo -n "PID of \"$COMMAND1\": " >> "$LOG" +${COMMAND1} & +echo $! >> "$LOG" +# PID of "sleep 100": 1506 + +# Thank you, Jacques Lederer, for suggesting this. + + @@ -8791,6 +8864,19 @@ done linkend="oldpwd">$OLDPWD, the previous working directory. + + + The cd command does not function + as expected when presented with two forward slashes. + + +bash$ cd // +bash$ pwd +// + + The output should, of course, be /. + This is a problem both from the command line and in a script. + @@ -10914,11 +11000,17 @@ find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \ sleep 3 # Pauses 3 seconds. + The sleep command defaults to seconds, but minute, hours, or days may also be specified. sleep 3 h # Pauses 3 hours! + + The watch command may + be a better choice than sleep for running + commands at timed intervals. + @@ -13142,6 +13234,9 @@ gzip -cd patchXX.gz | patch -p0 &fileintegrity; + See also for a creative use of + the md5sum command. + @@ -13348,6 +13443,23 @@ echo "tempfile name = $tempfile" + + dos2unix + + dos2unix + + + command + file converter + + + This utility, written by Benjamin Lin and collaborators, + converts DOS-formatted text files (lines terminated by + CR-LF) to UNIX format (lines terminated by LF only), + and vice-versa. + + + ptx @@ -17609,6 +17721,24 @@ print "even when I don't know where to find Perl.\n"; + + watch + + watch + + + command + periodic + + + Run a command repeatedly, at specified time intervals. + The default is two-second intervals, but this may be changed + with the option. + watch -n 5 tail /var/log/messages +# Shows tail end of system log, /var/log/messages, every five seconds. + + + strip @@ -17849,7 +17979,11 @@ echo "$dir_listing" # quoted variable1=`<file1` # Set "variable1" to contents of "file1". variable2=`cat file2` # Set "variable2" to contents of "file2". -# Be aware that the variables may contain embedded whitespace, +# Note 1: +# Removes newlines. +# +# Note 2: +# The variables may contain embedded whitespace, #+ or even (horrors), control characters. @@ -17951,8 +18085,11 @@ echo $greeting The $(COMMAND) form has superseded backticks for command substitution. - output=$(sed -n /"$1"/p $file) -# From "grp.sh" example. + output=$(sed -n /"$1"/p $file) # From "grp.sh" example. + +# Setting a variable to the contents of a text file. +File_contents1=$(cat $file1) +File_contents2=$(<$file2) # Bash permits this also. @@ -18003,7 +18140,7 @@ echo $greeting arithmetic expansion - z=`expr $z + 3` # 'expr' does the expansion. + z=`expr $z + 3` # The 'expr' command performs the expansion. @@ -18026,12 +18163,13 @@ echo $greeting convenient let construction. z=$(($z+3)) -# $((EXPRESSION)) is arithmetic expansion. # Not to be confused with - # command substitution. +# $((EXPRESSION)) is arithmetic expansion. # Not to be confused with + #+ command substitution. let z=z+3 -let "z += 3" #If quotes, then spaces and special operators allowed. -# 'let' is actually arithmetic evaluation, rather than expansion. +let "z += 3" # Quotes permit the use of spaces and special operators. +# The 'let' operator actually performs arithmetic evaluation, +#+ rather than expansion. All the above are equivalent. You may use whichever one rings your chimes. @@ -19767,9 +19905,12 @@ route -n | The function definition must precede the first call to it. There is no method of declaring the function, as, for example, in C. - # f1 + f1 # Will give an error message, since function "f1" not yet defined. +declare -f f1 # This doesn't help either. +f1 # Still an error message. + # However... @@ -19784,11 +19925,11 @@ f2 () echo "Function \"f2\"." } -f1 # Function "f2" is not actually called until this point, - # although it is referenced before its definition. - # This is permissable. +f1 # Function "f2" is not actually called until this point, + #+ although it is referenced before its definition. + # This is permissable. -# Thanks, S.C. + # Thanks, S.C. It is even possible to nest a function within another function, @@ -19803,14 +19944,16 @@ f1 # Function "f2" is not actually called until this point, } -# f2 -# Gives an error message. +f2 # Gives an error message. + # Even a preceding "declare -f f2" wouldn't help. -f1 # Does nothing, since calling "f1" does not automatically call "f2". -f2 # Now, it's all right to call "f2", - # since its definition has been made visible by calling "f1". +echo -# Thanks, S.C. +f1 # Does nothing, since calling "f1" does not automatically call "f2". +f2 # Now, it's all right to call "f2", + #+ since its definition has been made visible by calling "f1". + + # Thanks, S.C. Function declarations can appear in unlikely places, even where a @@ -20419,6 +20562,25 @@ false && ( true || echo false ) # (nothing echoed) &ex66; + + Bash permits array operations on variables, even if + the variables are not explicitly declared as arrays. + string=abcABC123ABCabc +echo ${string[@]} # abcABC123ABCabc +echo ${string[*]} # abcABC123ABCabc +echo ${string[0]} # abcABC123ABCabc +echo ${string[1]} # No output! + # Why? +echo ${#string[@]} # 1 + # One element in the array. + # The string itself. + +# Thank you, Michael Zick, for pointing this out. + Once again this demonstrates that Bash + variables are untyped. + + + Formatting a poem &poem; @@ -20522,7 +20684,15 @@ element_count=${#array1[*]} echo $element_count # 8 + + Clever scripting makes it possible to add array operations. + + Copying and concatenating arrays + ©array; + + + -- Arrays permit deploying old familiar algorithms as shell scripts. Whether this is necessarily a good idea is left to the reader to @@ -20536,6 +20706,28 @@ echo $element_count # 8 -- + Is it possible to nest arrays within arrays? + #!/bin/bash +# Nested array. + +# Michael Zick provided this example. + +AnArray=( $(ls --inode --ignore-backups --almost-all \ + --directory --full-time --color=none --time=status \ + --sort=time -l ${PWD} ) ) # Commands and options. + +# Spaces are significant . . . and don't quote anything in the above. + +SubArray=( ${AnArray[@]:11:1} ${AnArray[@]:6:5} ) +# Array has two elements, each of which is in turn an array. + +echo "Current directory and date of last status change:" +echo "${SubArray[@]}" + +exit 0 + + -- + Arrays enable implementing a shell script version of the Sieve of Eratosthenes. Of course, a resource-intensive application of this nature should really be written in a compiled language, such as C. It @@ -21296,6 +21488,7 @@ trap 'echo "Control-C disabled."' 2 + It is also possible to enable script options from the command line. Some options that will not work with set are available this way. Among these @@ -21471,9 +21664,9 @@ do_something do_something Using whitespace inappropriately - (in contrast to other programming languages, Bash can be quite - finicky about whitespace). + linkend="whitespaceref">whitespace inappropriately. + In contrast to other programming languages, Bash can be quite + finicky about whitespace. var1 = 23 # 'var1=23' is correct. # On line above, Bash attempts to execute command "var1" @@ -21486,10 +21679,18 @@ if [ $a -le 5] # if [ $a -le 5 ] is correct. # [[ $a -le 5 ]] also works. - Assuming uninitialized variables (variables before a value is + + Assuming uninitialized variables (variables before a value is assigned to them) are zeroed out. An uninitialized variable has a value of null, - not zero. + not zero. + + #!/bin/bash + +echo "uninitialized_var = $uninitialized_var" +# uninitialized_var = + + Mixing up = and -eq in a test. Remember, = is for comparing literal @@ -21593,11 +21794,27 @@ fi sh to bash, but this does not necessarily hold true for a generic UNIX machine. - A script with DOS-type newlines (\r\n) + + A script with DOS-type newlines (\r\n) will fail to execute, since #!/bin/bash\r\n is not recognized, not the same as the expected #!/bin/bash\n. The fix is to - convert the script to UNIX-style newlines. + convert the script to UNIX-style newlines. + #!/bin/bash + +echo "Here" + +unix2dos $0 # Script changes itself to DOS format. +chmod 755 $0 # Change back to execute permission. + # The 'unix2dos' command removes execute permission. + +./$0 # Script tries to run itself again. + # But it won't work as a DOS file. + +echo "There" + +exit 0 + A shell script headed by #!/bin/sh may not run in full Bash-compatibility mode. Some Bash-specific @@ -21654,6 +21871,9 @@ exit 0 undesirable behavior as far as CGI is concerned. Moreover, it is difficult to cracker-proof shell scripts. + Bash does not handle the double slash + (//) string correctly. + Bash scripts written for Linux or BSD systems may need fixups to run on a commercial UNIX machine. Such scripts often employ GNU commands and filters which have greater @@ -22796,12 +23016,46 @@ fi features to the latest versions of Bash. On a commercial UNIX machine, scripts using GNU-specific - features of standard commands may not work. This has become - less of a problem in the last few years, as the GNU utilities - have pretty much displaced their proprietary counterparts even - on big-iron UNIX. Caldera's recent release of - the source to many of the original UNIX utilities will only - accelerate the trend. + features of standard commands may not work. This has become less + of a problem in the last few years, as the GNU utilities have + pretty much displaced their proprietary counterparts even on + big-iron UNIX. Caldera's release of the source + to many of the original UNIX utilities will only accelerate + the trend. + + Bash has certain features that the traditional Bourne shell + lacks. Among these are: + + + + + Certain extended invocation options + + + + Command substitution using + $( ) notation + + + + Certain string manipulation + operations + + + + Process substitution + + + + Bash-specific builtins + + + + + + See the Bash + F.A.Q. for a complete listing. @@ -23035,7 +23289,7 @@ fi an instructive example script. Many thanks to Jordi Sanfeliu + url="mailto:mikaku@fiwix.org">Jordi Sanfeliu for giving permission to use his fine tree script (). @@ -23075,6 +23329,10 @@ fi linkend="cutref">cut and pidof. + Michael Zick extended the empty + array example to demonstrate some surprising array + properties. He also provided other examples of this. + Marc-Jano Knopp sent corrections on DOS batch files. Hyun Jin Cha found several typos in the document in the @@ -23162,18 +23420,18 @@ fi AeleenFrisch Essential System Administration - 2nd edition + 3rd edition O'Reilly and Associates - 1995 + 2002 - 1-56592-127-5 + 0-596-00343-9 This excellent sys admin manual has a decent introduction to shell scripting for sys administrators and does a nice job of explaining the - startup and initialization scripts. The book is long overdue for a third - edition (are you listening, Tim O'Reilly?). + startup and initialization scripts. The long overdue third edition of this + classic has finally been released. * @@ -23459,21 +23717,20 @@ fi The UNIX CD Bookshelf - 2nd edition + 3rd edition O'Reilly and Associates - 2000 + 2003 - 1-56592-815-6 - An array of six UNIX books on CD ROM, including + 0-596-00392-7 + An array of seven UNIX books on CD ROM, including UNIX Power Tools, Sed and Awk, and Learning the Korn Shell. A complete set of all the UNIX references - and tutorials you would ever need at about $70. Buy this one, + and tutorials you would ever need at about $130. Buy this one, even if it means going into debt and not paying the rent. - Unfortunately, out of print at present. * @@ -23545,8 +23802,7 @@ fi Example shell scripts at SHELLdorado - . + url="http://www.shelldorado.com">SHELLdorado . @@ -23577,19 +23833,11 @@ fi Giles Orr's Bash-Prompt + url="http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/">Bash-Prompt HOWTO. - - - The sed F.A.Q. / - Do It With Sed. - - - Very nice sed, @@ -23599,6 +23847,14 @@ fi + + + Eric Pement's + sed resources page. + + + + The GNU gawk &string; + Michael Zick's complex array example uses the md5sum check sum command to encode directory + information. + + + Directory information + &directoryinfo; + + + Stephane Chazelas demonstrates object-oriented programming in a Bash script. diff --git a/LDP/guide/docbook/abs-guide/bashrc b/LDP/guide/docbook/abs-guide/bashrc index f1fe23fe..662bf00c 100644 --- a/LDP/guide/docbook/abs-guide/bashrc +++ b/LDP/guide/docbook/abs-guide/bashrc @@ -1,19 +1,26 @@ #=============================================================== # -# PERSONAL $HOME/.bashrc FILE for bash-2.05 (or later) +# PERSONAL $HOME/.bashrc FILE for bash-2.05a (or later) +# +# Last modified: Tue Apr 15 20:32:34 CEST 2003 # # This file is read (normally) by interactive shells only. # Here is the place to define your aliases, functions and # other interactive features like your prompt. # -# This file was designed (originally) for Solaris. +# This file was designed (originally) for Solaris but based +# on Redhat's default .bashrc file # --> Modified for Linux. +# The majority of the code you'll find here is based on code found +# on Usenet (or internet). # This bashrc file is a bit overcrowded - remember it is just -# just an example. Tailor it to your needs +# just an example. Tailor it to your needs +# # #=============================================================== # --> Comments added by HOWTO author. +# --> And then edited again by ER :-) #----------------------------------- # Source global definitions (if any) @@ -25,38 +32,69 @@ fi #------------------------------------------------------------- # Automatic setting of $DISPLAY (if not set already) -# This works for linux and solaris - your mileage may vary.... +# This works for linux - your mileage may vary.... +# The problem is that different types of terminals give +# different answers to 'who am i'...... +# I have not found a 'universal' method yet #------------------------------------------------------------- +function get_xserver () +{ + case $TERM in + xterm ) + XSERVER=$(who am i | awk '{print $NF}' | tr -d ')''(' ) + XSERVER=${XSERVER%%:*} + ;; + aterm | rxvt) + # find some code that works here..... + ;; + esac +} + if [ -z ${DISPLAY:=""} ]; then - DISPLAY=$(who am i) - DISPLAY=${DISPLAY%%\!*} - if [ -n "$DISPLAY" ]; then - export DISPLAY=$DISPLAY:0.0 - else - export DISPLAY=":0.0" # fallback + get_xserver + if [[ -z ${XSERVER} || ${XSERVER} == $(hostname) || ${XSERVER} == "unix" ]]; then + DISPLAY=":0.0" # Display on local host + else + DISPLAY=${XSERVER}:0.0 # Display on remote host fi fi +export DISPLAY + #--------------- # Some settings #--------------- +ulimit -S -c 0 # Don't want any coredumps set -o notify set -o noclobber set -o ignoreeof set -o nounset #set -o xtrace # useful for debuging +# Enable options: shopt -s cdspell shopt -s cdable_vars shopt -s checkhash shopt -s checkwinsize shopt -s mailwarn shopt -s sourcepath -shopt -s no_empty_cmd_completion -shopt -s histappend histreedit -shopt -s extglob # useful for programmable completion +shopt -s no_empty_cmd_completion # bash>=2.04 only +shopt -s cmdhist +shopt -s histappend histreedit histverify +shopt -s extglob # necessary for programmable completion + +# Disable options: +shopt -u mailwarn +unset MAILCHECK # I don't want my shell to warn me of incoming mail + + +export TIMEFORMAT=$'\nreal %3R\tuser %3U\tsys %3S\tpcpu %P\n' +export HISTIGNORE="&:bg:fg:ll:h" +export HOSTFILE=$HOME/.hosts # Put a list of remote hosts in ~/.hosts + + #----------------------- # Greeting, motd etc... @@ -75,26 +113,37 @@ NC='\e[0m' # No Color # Looks best on a black background..... echo -e "${CYAN}This is BASH ${RED}${BASH_VERSION%.*}${CYAN} - DISPLAY on ${RED}$DISPLAY${NC}\n" date -if [ -x /usr/games/fortune ]; then +if [ -x /usr/games/fortune ]; then /usr/games/fortune -s # makes our day a bit more fun.... :-) fi -function _exit() # function to run upon exit of shell +function _exit() # function to run upon exit of shell { echo -e "${RED}Hasta la vista, baby${NC}" } -trap _exit 0 +trap _exit EXIT #--------------- -# Shell prompt +# Shell Prompt #--------------- +if [[ "${DISPLAY#$HOST}" != ":0.0" && "${DISPLAY}" != ":0" ]]; then + HILIT=${red} # remote machine: prompt will be partly red +else + HILIT=${cyan} # local machine: prompt will be partly cyan +fi + +# --> Replace instances of \W with \w in prompt functions below +#+ --> to get display of full path name. + function fastprompt() { unset PROMPT_COMMAND case $TERM in *term | rxvt ) - PS1="[\h] \W > \[\033]0;[\u@\h] \w\007\]" ;; + PS1="${HILIT}[\h]$NC \W > \[\033]0;\${TERM} [\u@\h] \w\007\]" ;; + linux ) + PS1="${HILIT}[\h]$NC \W > " ;; *) PS1="[\h] \W > " ;; esac @@ -105,17 +154,16 @@ function powerprompt() _powerprompt() { LOAD=$(uptime|sed -e "s/.*: \([^,]*\).*/\1/" -e "s/ //g") - TIME=$(date +%H:%M) } PROMPT_COMMAND=_powerprompt case $TERM in *term | rxvt ) - PS1="${cyan}[\$TIME \$LOAD]$NC\n[\h \#] \W > \[\033]0;[\u@\h] \w\007\]" ;; + PS1="${HILIT}[\A \$LOAD]$NC\n[\h \#] \W > \[\033]0;\${TERM} [\u@\h] \w\007\]" ;; linux ) - PS1="${cyan}[\$TIME - \$LOAD]$NC\n[\h \#] \w > " ;; + PS1="${HILIT}[\A - \$LOAD]$NC\n[\h \#] \w > " ;; * ) - PS1="[\$TIME - \$LOAD]\n[\h \#] \w > " ;; + PS1="[\A - \$LOAD]\n[\h \#] \w > " ;; esac } @@ -144,6 +192,7 @@ alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' # -> Prevents accidentally clobbering files. +alias mkdir='mkdir -p' alias h='history' alias j='jobs -l' @@ -151,23 +200,23 @@ alias r='rlogin' alias which='type -all' alias ..='cd ..' alias path='echo -e ${PATH//:/\\n}' -alias print='/usr/bin/lp -o nobanner -d $LPDEST' # Assumes LPDEST is defined +alias print='/usr/bin/lp -o nobanner -d $LPDEST' # Assumes LPDEST is defined alias pjet='enscript -h -G -fCourier9 -d $LPDEST' # Pretty-print using enscript -alias background='xv -root -quit -max -rmode 5' # put a picture in the background -alias vi='vim' -alias du='du -h' -alias df='df -kh' +alias background='xv -root -quit -max -rmode 5' # Put a picture in the background +alias du='du -kh' +alias df='df -kTh' # The 'ls' family (this assumes you use the GNU ls) +alias la='ls -Al' # show hidden files alias ls='ls -hF --color' # add colors for filetype recognition -alias lx='ls -lXB' # sort by extension -alias lk='ls -lSr' # sort by size -alias la='ls -Al' # show hidden files -alias lr='ls -lR' # recursice ls -alias lt='ls -ltr' # sort by date -alias lm='ls -al |more' # pipe through 'more' -alias tree='tree -Cs' # nice alternative to 'ls' - +alias lx='ls -lXB' # sort by extension +alias lk='ls -lSr' # sort by size +alias lc='ls -lcr' # sort by change time +alias lu='ls -lur' # sort by access time +alias lr='ls -lR' # recursive ls +alias lt='ls -ltr' # sort by date +alias lm='ls -al |more' # pipe through 'more' +alias tree='tree -Csu' # nice alternative to 'ls' # tailoring 'less' alias more='less' @@ -190,10 +239,11 @@ alias kk='ll' function xtitle () { - case $TERM in + case "$TERM" in *term | rxvt) echo -n -e "\033]0;$*\007" ;; - *) ;; + *) + ;; esac } @@ -202,21 +252,22 @@ alias top='xtitle Processes on $HOST && top' alias make='xtitle Making $(basename $PWD) ; make' alias ncftp="xtitle ncFTP ; ncftp" -# .. and functions +# .. and functions function man () { - xtitle The $(basename $1|tr -d .[:digit:]) manual - man -a "$*" + for i ; do + xtitle The $(basename $1|tr -d .[:digit:]) manual + command man -F -a "$i" + done } function ll(){ ls -l "$@"| egrep "^d" ; ls -lXB "$@" 2>&-| egrep -v "^d|total "; } -function xemacs() { { command xemacs -private $* 2>&- & } && disown ;} function te() # wrapper around xemacs/gnuserv { if [ "$(gnuclient -batch -eval t 2>&-)" == "t" ]; then gnuclient -q "$@"; else - ( xemacs "$@" & ); + ( xemacs "$@" &); fi } @@ -224,18 +275,33 @@ function te() # wrapper around xemacs/gnuserv # File & strings related functions: #----------------------------------- -function ff() { find . -name '*'$1'*' ; } # find a file -function fe() { find . -name '*'$1'*' -exec $2 {} \; ; } # find a file and run $2 on it -function fstr() # find a string in a set of files +# Find a file with a pattern in name: +function ff() { find . -type f -iname '*'$*'*' -ls ; } +# Find a file with pattern $1 in name and Execute $2 on it: +function fe() { find . -type f -iname '*'$1'*' -exec "${2:-file}" {} \; ; } +# find pattern in a set of filesand highlight them: +function fstr() { - if [ "$#" -gt 2 ]; then - echo "Usage: fstr \"pattern\" [files] " + OPTIND=1 + local case="" + local usage="fstr: find string in files. +Usage: fstr [-i] \"pattern\" [\"filename pattern\"] " + while getopts :it opt + do + case "$opt" in + i) case="-i " ;; + *) echo "$usage"; return;; + esac + done + shift $(( $OPTIND - 1 )) + if [ "$#" -lt 1 ]; then + echo "$usage" return; fi - SMSO=$(tput smso) - RMSO=$(tput rmso) - find . -type f -name "${2:-*}" -print | xargs grep -sin "$1" | \ -sed "s/$1/$SMSO$1$RMSO/gI" + local SMSO=$(tput smso) + local RMSO=$(tput rmso) + find . -type f -name "${2:-*}" -print0 | xargs -0 grep -sn ${case} "$1" 2>&- | \ +sed "s/$1/${SMSO}\0${RMSO}/gI" | more } function cuttail() # cut last n lines in file, 10 by default @@ -266,11 +332,12 @@ function lowercase() # move filenames to lowercase function swap() # swap 2 filenames around { local TMPFILE=tmp.$$ - mv $1 $TMPFILE - mv $2 $1 - mv $TMPFILE $2 + mv "$1" $TMPFILE + mv "$2" "$1" + mv $TMPFILE "$2" } + #----------------------------------- # Process/system related functions: #----------------------------------- @@ -283,16 +350,16 @@ function pp() { my_ps f | awk '!/awk/ && $0~var' var=${1:-".*"} ; } function killps() # kill by process name { local pid pname sig="-TERM" # default signal - if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then - echo "Usage: killps [-SIGNAL] pattern" - return; + if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then + echo "Usage: killps [-SIGNAL] pattern" + return; fi if [ $# = 2 ]; then sig=$1 ; fi for pid in $(my_ps| awk '!/awk/ && $0~pat { print $1 }' pat=${!#} ) ; do - pname=$(my_ps | awk '$1~var { print $5 }' var=$pid ) - if ask "Kill process $pid <$pname> with signal $sig?" - then kill $sig $pid - fi + pname=$(my_ps | awk '$1~var { print $5 }' var=$pid ) + if ask "Kill process $pid <$pname> with signal $sig?" + then kill $sig $pid + fi done } @@ -316,7 +383,6 @@ function ii() # get current host related info echo } - # Misc utilities: function repeat() # repeat n times command @@ -328,7 +394,6 @@ function repeat() # repeat n times command done } - function ask() { echo -n "$@" '[y/n] ' ; read ans @@ -341,8 +406,9 @@ function ask() #========================================================================= # # PROGRAMMABLE COMPLETION - ONLY SINCE BASH-2.04 -# (Most are taken from the bash 2.05 documentation) -# You will in fact need bash-2.05 for some features +# Most are taken from the bash 2.05 documentation and from Ian McDonalds +# 'Bash completion' package (http://www.caliban.org/bash/index.shtml#completion) +# You will in fact need bash-2.05a for some features # #========================================================================= @@ -352,11 +418,9 @@ if [ "${BASH_VERSION%.*}" \< "2.05" ]; then fi shopt -s extglob # necessary -set +o nounset # otherwise some completions will fail +set +o nounset # otherwise some completions will fail complete -A hostname rsh rcp telnet rlogin r ftp ping disk -complete -A command nohup exec eval trace gdb -complete -A command command type which complete -A export printenv complete -A variable export local readonly unset complete -A enabled builtin @@ -372,40 +436,57 @@ complete -A job -P '%' fg jobs disown complete -A directory mkdir rmdir complete -A directory -o default cd -complete -f -d -X '*.gz' gzip -complete -f -d -X '*.bz2' bzip2 -complete -f -o default -X '!*.gz' gunzip -complete -f -o default -X '!*.bz2' bunzip2 -complete -f -o default -X '!*.pl' perl perl5 +# Compression +complete -f -o default -X '*.+(zip|ZIP)' zip +complete -f -o default -X '!*.+(zip|ZIP)' unzip +complete -f -o default -X '*.+(z|Z)' compress +complete -f -o default -X '!*.+(z|Z)' uncompress +complete -f -o default -X '*.+(gz|GZ)' gzip +complete -f -o default -X '!*.+(gz|GZ)' gunzip +complete -f -o default -X '*.+(bz2|BZ2)' bzip2 +complete -f -o default -X '!*.+(bz2|BZ2)' bunzip2 +# Postscript,pdf,dvi..... complete -f -o default -X '!*.ps' gs ghostview ps2pdf ps2ascii complete -f -o default -X '!*.dvi' dvips dvipdf xdvi dviselect dvitype -complete -f -o default -X '!*.pdf' acroread pdf2ps -complete -f -o default -X '!*.+(pdf|ps)' gv +complete -f -o default -X '!*.pdf' acroread pdf2ps +complete -f -o default -X '!*.+(pdf|ps)' gv complete -f -o default -X '!*.texi*' makeinfo texi2dvi texi2html texi2pdf -complete -f -o default -X '!*.tex' tex latex slitex -complete -f -o default -X '!*.lyx' lyx -complete -f -o default -X '!*.+(jpg|gif|xpm|png|bmp)' xv gimp -complete -f -o default -X '!*.mp3' mpg123 -complete -f -o default -X '!*.ogg' ogg123 +complete -f -o default -X '!*.tex' tex latex slitex +complete -f -o default -X '!*.lyx' lyx +complete -f -o default -X '!*.+(htm*|HTM*)' lynx html2ps +# Multimedia +complete -f -o default -X '!*.+(jp*g|gif|xpm|png|bmp)' xv gimp +complete -f -o default -X '!*.+(mp3|MP3)' mpg123 mpg321 +complete -f -o default -X '!*.+(ogg|OGG)' ogg123 + +complete -f -o default -X '!*.pl' perl perl5 + # This is a 'universal' completion function - it works when commands have -# a so-called 'long options' mode , ie: 'ls --all' instead of 'ls -a' -_universal_func () +# a so-called 'long options' mode , ie: 'ls --all' instead of 'ls -a' + +_get_longopts () +{ + $1 --help | sed -e '/--/!d' -e 's/.*--\([^[:space:].,]*\).*/--\1/'| \ +grep ^"$2" |sort -u ; +} + +_longopts_func () { - case "$2" in + case "${2:-*}" in -*) ;; *) return ;; esac case "$1" in - \~*) eval cmd=$1 ;; + \~*) eval cmd="$1" ;; *) cmd="$1" ;; esac - COMPREPLY=( $("$cmd" --help | sed -e '/--/!d' -e 's/.*--\([^ ]*\).*/--\1/'| \ -grep ^"$2" |sort -u) ) + COMPREPLY=( $(_get_longopts ${1} ${2} ) ) } -complete -o default -F _universal_func ldd wget bash id info +complete -o default -F _longopts_func configure bash +complete -o default -F _longopts_func wget id info a2ps ls recode _make_targets () @@ -459,22 +540,6 @@ _make_targets () complete -F _make_targets -X '+($*|*.[cho])' make gmake pmake -_configure_func () -{ - case "$2" in - -*) ;; - *) return ;; - esac - - case "$1" in - \~*) eval cmd=$1 ;; - *) cmd="$1" ;; - esac - - COMPREPLY=( $("$cmd" --help | awk '{if ($1 ~ /--.*/) print $1}' | grep ^"$2" | sort -u) ) -} - -complete -F _configure_func configure # cvs(1) completion _cvs () @@ -485,17 +550,16 @@ _cvs () prev=${COMP_WORDS[COMP_CWORD-1]} if [ $COMP_CWORD -eq 1 ] || [ "${prev:0:1}" = "-" ]; then - COMPREPLY=( $( compgen -W 'add admin checkout commit diff \ - export history import log rdiff release remove rtag status \ - tag update' $cur )) + COMPREPLY=( $( compgen -W 'add admin checkout commit diff \ + export history import log rdiff release remove rtag status \ + tag update' $cur )) else - COMPREPLY=( $( compgen -f $cur )) + COMPREPLY=( $( compgen -f $cur )) fi return 0 } complete -F _cvs cvs - _killall () { local cur prev @@ -514,6 +578,60 @@ _killall () complete -F _killall killall killps + +# A meta-command completion function for commands like sudo(8), which need to +# first complete on a command, then complete according to that command's own +# completion definition - currently not quite foolproof (e.g. mount and umount +# don't work properly), but still quite useful - By Ian McDonald, modified by me. + +_my_command() +{ + local cur func cline cspec + + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + + if [ $COMP_CWORD = 1 ]; then + COMPREPLY=( $( compgen -c $cur ) ) + elif complete -p ${COMP_WORDS[1]} &>/dev/null; then + cspec=$( complete -p ${COMP_WORDS[1]} ) + if [ "${cspec%%-F *}" != "${cspec}" ]; then + # complete -F <function> + # + # COMP_CWORD and COMP_WORDS() are not read-only, + # so we can set them before handing off to regular + # completion routine + + # set current token number to 1 less than now + COMP_CWORD=$(( $COMP_CWORD - 1 )) + # get function name + func=${cspec#*-F } + func=${func%% *} + # get current command line minus initial command + cline="${COMP_LINE#$1 }" + # split current command line tokens into array + COMP_WORDS=( $cline ) + $func $cline + elif [ "${cspec#*-[abcdefgjkvu]}" != "" ]; then + # complete -[abcdefgjkvu] + #func=$( echo $cspec | sed -e 's/^.*\(-[abcdefgjkvu]\).*$/\1/' ) + func=$( echo $cspec | sed -e 's/^complete//' -e 's/[^ ]*$//' ) + COMPREPLY=( $( eval compgen $func $cur ) ) + elif [ "${cspec#*-A}" != "$cspec" ]; then + # complete -A <type> + func=${cspec#*-A } + func=${func%% *} + COMPREPLY=( $( compgen -A $func $cur ) ) + fi + else + COMPREPLY=( $( compgen -f $cur ) ) + fi +} + + +complete -o default -F _my_command nohup exec eval trace truss strace sotruss gdb +complete -o default -F _my_command command type which man nice + # Local Variables: # mode:shell-script # sh-shell:bash diff --git a/LDP/guide/docbook/abs-guide/blot-out.sh b/LDP/guide/docbook/abs-guide/blot-out.sh index 86fa8f6c..c42cddfd 100644 --- a/LDP/guide/docbook/abs-guide/blot-out.sh +++ b/LDP/guide/docbook/abs-guide/blot-out.sh @@ -81,7 +81,7 @@ echo "File \"$file\" blotted out and deleted."; echo # For an in-depth analysis on the topic of file deletion and security, #+ see Peter Gutmann's paper, #+ "Secure Deletion of Data From Magnetic and Solid-State Memory". -# http://www.cs.auckland.ac.nz/~pgut001/secure_del.html +# http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html exit 0 diff --git a/LDP/guide/docbook/abs-guide/cvt.sh b/LDP/guide/docbook/abs-guide/cvt.sh index ded645f5..fa7bf615 100644 --- a/LDP/guide/docbook/abs-guide/cvt.sh +++ b/LDP/guide/docbook/abs-guide/cvt.sh @@ -24,10 +24,16 @@ do filename=${file%.*c} # Strip ".mac" suffix off filename #+ ('.*c' matches everything #+ between '.' and 'c', inclusive). - $OPERATION $file > $filename.$SUFFIX + $OPERATION $file > "$filename.$SUFFIX" # Redirect conversion to new filename. rm -f $file # Delete original files after converting. echo "$filename.$SUFFIX" # Log what is happening to stdout. done exit 0 + +# Exercise: +# -------- +# As it stands, this script converts *all* the files in the current +#+ working directory. +# Modify it to work *only* on files with a ".mac" suffix. diff --git a/LDP/guide/docbook/abs-guide/empty-array.sh b/LDP/guide/docbook/abs-guide/empty-array.sh index 54979fdc..4e3d346c 100644 --- a/LDP/guide/docbook/abs-guide/empty-array.sh +++ b/LDP/guide/docbook/abs-guide/empty-array.sh @@ -1,6 +1,10 @@ #!/bin/bash # empty-array.sh +# Thanks to Stephane Chazelas for the original example, +#+ and to Michael Zick for extending it. + + # An empty array is not the same as an array with empty elements. array0=( first second third ) @@ -8,7 +12,9 @@ array1=( '' ) # "array1" has one empty element. array2=( ) # No elements... "array2" is empty. echo - +ListArray() +{ +echo echo "Elements in array0: ${array0[@]}" echo "Elements in array1: ${array1[@]}" echo "Elements in array2: ${array2[@]}" @@ -20,7 +26,101 @@ echo echo "Number of elements in array0 = ${#array0[*]}" # 3 echo "Number of elements in array1 = ${#array1[*]}" # 1 (surprise!) echo "Number of elements in array2 = ${#array2[*]}" # 0 +} +# =================================================================== + +ListArray + +# Try extending those arrays + +# Adding an element to an array. +array0=( "${array0[@]}" "new1" ) +array1=( "${array1[@]}" "new1" ) +array2=( "${array2[@]}" "new1" ) + +ListArray + +# or +array0[${#array0[*]}]="new2" +array1[${#array1[*]}]="new2" +array2[${#array2[*]}]="new2" + +ListArray + +# When extended as above; arrays are 'stacks' +# The above is the 'push' +# The stack 'height' is: +height=${#array2[@]} echo +echo "Stack height for array2 = $height" -exit 0 # Thanks, S.C. +# The 'pop' is: +unset array2[${#array2[@]}-1] # Arrays are zero based +height=${#array2[@]} +echo +echo "POP" +echo "New stack height for array2 = $height" + +ListArray + +# List only 2nd and 3rd elements of array0 +from=1 # Zero based numbering +to=2 # +declare -a array3=( ${array0[@]:1:2} ) +echo +echo "Elements in array3: ${array3[@]}" + +# Works like a string (array of characters) +# Try some other "string" forms + +# Replacement +declare -a array4=( ${array0[@]/second/2nd} ) +echo +echo "Elements in array4: ${array4[@]}" + +# Replace all matching wildcarded string +declare -a array5=( ${array0[@]//new?/old} ) +echo +echo "Elements in array5: ${array5[@]}" + +# Just when you are getting the feel for this... +declare -a array6=( ${array0[@]#*new} ) +echo # This one might surprise you +echo "Elements in array6: ${array6[@]}" + +declare -a array7=( ${array0[@]#new1} ) +echo # After array6 this should not be a surprise +echo "Elements in array7: ${array7[@]}" + +# Which looks a lot like... +declare -a array8=( ${array0[@]/new1/} ) +echo +echo "Elements in array8: ${array8[@]}" + +# So what can one say about this? + +# 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, that +#+ element disappears in the resulting assignment. + +# Question, are those strings hard or soft quotes? + +zap='new*' +declare -a array9=( ${array0[@]/$zap/} ) +echo +echo "Elements in array9: ${array9[@]}" + +# Just when you thought you where still in Kansas... +declare -a array10=( ${array0[@]#$zap} ) +echo +echo "Elements in array10: ${array10[@]}" + +# Compare array7 with array10 +# Compare array8 with array9 + +# Answer, must be soft quotes. + +exit 0 diff --git a/LDP/guide/docbook/abs-guide/ex41.sh b/LDP/guide/docbook/abs-guide/ex41.sh index 07f489bc..466312f0 100644 --- a/LDP/guide/docbook/abs-guide/ex41.sh +++ b/LDP/guide/docbook/abs-guide/ex41.sh @@ -17,3 +17,9 @@ echo >>logfile echo >>logfile exit 0 + +# Exercise: +# -------- +# Modify this script to track changes in /var/log/messages at intervals +#+ of 20 minutes. +# Hint: Use the "watch" command. diff --git a/LDP/guide/docbook/abs-guide/self-document.sh b/LDP/guide/docbook/abs-guide/self-document.sh index dfa40be6..ac904654 100644 --- a/LDP/guide/docbook/abs-guide/self-document.sh +++ b/LDP/guide/docbook/abs-guide/self-document.sh @@ -7,7 +7,7 @@ DOC_REQUEST=70 if [ "$1" = "-h" -o "$1" = "--help" ] # Request help. then echo; echo "Usage: $0 [directory-name]"; echo - cat "$0" | sed --silent -e '/DOCUMENTATIONXX$/,/^DOCUMENTATION/p' | + sed --silent -e '/DOCUMENTATIONXX$/,/^DOCUMENTATION/p' "$0" | sed -e '/DOCUMENTATIONXX/d'; exit $DOC_REQUEST; fi : << DOCUMENTATIONXX diff --git a/LDP/guide/docbook/abs-guide/tree.sh b/LDP/guide/docbook/abs-guide/tree.sh index 83e93e57..6fbacba0 100644 --- a/LDP/guide/docbook/abs-guide/tree.sh +++ b/LDP/guide/docbook/abs-guide/tree.sh @@ -1,6 +1,6 @@ #!/bin/sh # @(#) tree 1.1 30/11/95 by Jordi Sanfeliu -# email: mikaku@arrakis.es +# email: mikaku@fiwix.org # # Initial version: 1.0 30/11/95 # Next version : 1.1 24/02/97 Now, with symbolic links