- •Table of Contents
- •Chapter 1. Why Shell Programming?
- •2.1. Invoking the script
- •2.2. Preliminary Exercises
- •Part 2. Basics
- •Chapter 3. Exit and Exit Status
- •Chapter 4. Special Characters
- •Chapter 5. Introduction to Variables and Parameters
- •5.1. Variable Substitution
- •5.2. Variable Assignment
- •5.3. Bash Variables Are Untyped
- •5.4. Special Variable Types
- •Chapter 6. Quoting
- •Chapter 7. Tests
- •7.1. Test Constructs
- •7.2. File test operators
- •7.3. Comparison operators (binary)
- •7.4. Nested if/then Condition Tests
- •7.5. Testing Your Knowledge of Tests
- •Chapter 8. Operations and Related Topics
- •8.1. Operators
- •8.2. Numerical Constants
- •Part 3. Beyond the Basics
- •Chapter 9. Variables Revisited
- •9.1. Internal Variables
- •9.2. Manipulating Strings
- •9.2.1. Manipulating strings using awk
- •9.2.2. Further Discussion
- •9.3. Parameter Substitution
- •9.4. Typing variables: declare or typeset
- •9.5. Indirect References to Variables
- •9.6. $RANDOM: generate random integer
- •9.7. The Double Parentheses Construct
- •Chapter 10. Loops and Branches
- •10.1. Loops
- •10.2. Nested Loops
- •10.3. Loop Control
- •10.4. Testing and Branching
- •Chapter 11. Internal Commands and Builtins
- •11.1. Job Control Commands
- •Chapter 12. External Filters, Programs and Commands
- •12.1. Basic Commands
- •12.2. Complex Commands
- •12.3. Time / Date Commands
- •12.4. Text Processing Commands
- •12.5. File and Archiving Commands
- •12.6. Communications Commands
- •12.7. Terminal Control Commands
- •12.8. Math Commands
- •12.9. Miscellaneous Commands
- •Chapter 13. System and Administrative Commands
- •Chapter 14. Command Substitution
- •Chapter 15. Arithmetic Expansion
- •Chapter 16. I/O Redirection
- •16.1. Using exec
- •16.2. Redirecting Code Blocks
- •16.3. Applications
- •Chapter 17. Here Documents
- •Chapter 18. Recess Time
- •Part 4. Advanced Topics
- •Chapter 19. Regular Expressions
- •19.1. A Brief Introduction to Regular Expressions
- •19.2. Globbing
- •Chapter 20. Subshells
- •Chapter 21. Restricted Shells
- •Chapter 22. Process Substitution
- •Chapter 23. Functions
- •23.1. Complex Functions and Function Complexities
- •23.2. Local Variables
- •23.2.1. Local variables make recursion possible.
- •Chapter 24. Aliases
- •Chapter 25. List Constructs
- •Chapter 26. Arrays
- •Chapter 27. Files
- •Chapter 28. /dev and /proc
- •28.2. /proc
- •Chapter 29. Of Zeros and Nulls
- •Chapter 30. Debugging
- •Chapter 31. Options
- •Chapter 32. Gotchas
- •Chapter 33. Scripting With Style
- •33.1. Unofficial Shell Scripting Stylesheet
- •Chapter 34. Miscellany
- •34.2. Shell Wrappers
- •34.3. Tests and Comparisons: Alternatives
- •34.4. Optimizations
- •34.5. Assorted Tips
- •34.6. Oddities
- •34.7. Portability Issues
- •34.8. Shell Scripting Under Windows
- •Chapter 35. Bash, version 2
- •Chapter 36. Endnotes
- •36.1. Author's Note
- •36.2. About the Author
- •36.3. Tools Used to Produce This Book
- •36.3.1. Hardware
- •36.3.2. Software and Printware
- •36.4. Credits
- •Bibliography
- •Appendix A. Contributed Scripts
- •Appendix C. Exit Codes With Special Meanings
- •Appendix D. A Detailed Introduction to I/O and I/O Redirection
- •Appendix E. Localization
- •Appendix F. History Commands
- •Appendix G. A Sample .bashrc File
- •Appendix H. Converting DOS Batch Files to Shell Scripts
- •Appendix I. Exercises
- •Appendix J. Copyright
Chapter 34. Miscellany
Nobody really knows what the Bourne shell's grammar is. Even examination of the source code is little help.
Tom Duff
34.1. Interactive and non−interactive shells and scripts
An interactive shell reads commands from user input on a tty. Among other things, such a shell reads startup files on activation, displays a prompt, and enables job control by default. The user can interact with the shell.
A shell running a script is always a non−interactive shell. All the same, the script can still access its tty. It is even possible to emulate an interactive shell in a script.
#!/bin/bash MY_PROMPT='$ ' while :
do
echo −n "$MY_PROMPT" read line
eval "$line" done
exit 0
#This example script, and much of the above explanation supplied by
#Stephane Chazelas (thanks again).
Let us consider an interactive script to be one that requires input from the user, usually with read statements (see Example 11−2). "Real life" is actually a bit messier than that. For now, assume an interactive script is bound to a tty, a script that a user has invoked from the console or an xterm.
Init and startup scripts are necessarily non−interactive, since they must run without human intervention.
Many administrative and system maintenance scripts are likewise non−interactive. Unvarying repetitive tasks cry out for automation by non−interactive scripts.
Non−interactive scripts can run in the background, but interactive ones hang, waiting for input that never comes. Handle that difficulty by having an expect script or embedded here document feed input to an interactive script running as a background job. In the simplest case, redirect a file to supply input to a read statement (read variable <file). These particular workarounds make possible general purpose scripts that run in either interactive or non−interactive modes.
If a script needs to test whether it is running in an 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.)
if [ −z $PS1 ] # no prompt? then
Chapter 34. Miscellany |
299 |
Advanced Bash−Scripting Guide
# non−interactive
...
else
# interactive
...
fi
Alternatively, the script can test for the presence of option "i" in the $− flag. case $− in
*i*) |
# |
interactive shell |
;; |
|
|
*) |
# |
non−interactive shell |
;;
# (Thanks to "UNIX F.A.Q.", 1993)
Scripts may be forced to run in interactive mode with the −i option or with a #!/bin/bash −i header. Be aware that this can cause erratic script behavior or show error messages even when no error is present.
34.2. Shell Wrappers
A "wrapper" is a shell script that embeds a system command or utility, that saves a set of parameters passed to to that command. Wrapping a script around a complex command line simplifies invoking it. This is expecially useful with sed and awk.
A sed or awk script would normally be invoked from the command line by a sed −e 'commands' or awk 'commands'. Embedding such a script in a Bash script permits calling it more simply, and makes it "reusable". This also enables combining the functionality of sed and awk, for example piping the output of a set of sed commands to awk. As a saved executable file, you can then repeatedly invoke it in its original form or modified, without the inconvenience of retyping it on the command line.
Example 34−1. shell wrapper
#!/bin/bash
#This is a simple script that removes blank lines from a file.
#No argument checking.
#Same as
#sed −e '/^$/d' filename
#invoked from the command line.
sed −e /^$/d "$1"
#The '−e' means an "editing" command follows (optional here).
#'^' is the beginning of line, '$' is the end.
#This match lines with nothing between the beginning and the end,
#blank lines.
#The 'd' is the delete command.
#Quoting the command−line arg permits
#whitespace and special characters in the filename.
34.2. Shell Wrappers |
300 |
Advanced Bash−Scripting Guide
exit 0
Example 34−2. A slightly more complex shell wrapper
#!/bin/bash
#"subst", a script that substitutes one pattern for
#another in a file,
#i.e., "subst Smith Jones letter.txt".
ARGS=3
E_BADARGS=65 # Wrong number of arguments passed to script.
if [ $# −ne "$ARGS" ]
# Test number of arguments to script (always a good idea). then
echo "Usage: `basename $0` old−pattern new−pattern filename" exit $E_BADARGS
fi
old_pattern=$1 new_pattern=$2
if [ −f "$3" ] then
file_name=$3
else
echo "File \"$3\" does not exist." exit $E_BADARGS
fi
# Here is where the heavy work gets done.
sed −e "s/$old_pattern/$new_pattern/g" $file_name
#'s' is, of course, the substitute command in sed,
#and /pattern/ invokes address matching.
#The "g", or global flag causes substitution for *every*
#occurence of $old_pattern on each line, not just the first.
#Read the literature on 'sed' for a more in−depth explanation.
exit 0 # Successful invocation of the script returns 0.
Example 34−3. A shell wrapper around an awk script
#!/bin/bash
# Adds up a specified column (of numbers) in the target file.
ARGS=2
E_WRONGARGS=65
if [ $# −ne "$ARGS" ] # Check for proper no. of command line args. then
echo "Usage: `basename $0` filename column−number" exit $E_WRONGARGS
fi
filename=$1 column_number=$2
34.2. Shell Wrappers |
301 |
Advanced Bash−Scripting Guide
#Passing shell variables to the awk part of the script is a bit tricky.
#See the awk documentation for more details.
# A multi−line awk script is invoked by awk ' ..... '
#Begin awk script.
#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
awk '
{ total += $'"${column_number}"'
}
END {
print total
}
' "$filename"
#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
#End awk script.
#It may not be safe to pass shell variables to an embedded awk script,
#so Stephane Chazelas proposes the following alternative:
#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
#awk −v column_number="$column_number" '
#{ total += $column_number
#}
#END {
#print total
#}' "$filename"
#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
exit 0
For those scripts needing a single do−it−all tool, a Swiss army knife, there is Perl. Perl combines the capabilities of sed and awk, and throws in a large subset of C, to boot. It is modular and contains support for everything ranging from object−oriented programming up to and including the kitchen sink. Short Perl scripts lend themselves to embedding in shell scripts, and there may even be some substance to the claim that Perl can totally replace shell scripting (though the author of this document remains skeptical).
Example 34−4. Perl embedded in a Bash script
#!/bin/bash
# Shell commands may precede the Perl script.
echo "This precedes the embedded Perl script within \"$0\"."
echo "==============================================================="
perl −e 'print "This is an embedded Perl script.\n";'
# Like sed, Perl also uses the "−e" option.
echo "===============================================================" echo "However, the script may also contain shell and system commands."
exit 0
34.2. Shell Wrappers |
302 |