- •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 14. Command Substitution
Command substitution reassigns the output of a command [43] or even multiple commands; it literally plugs the command output into another context.
The classic form of command substitution uses backquotes (`...`). Commands within backquotes (backticks) generate command line text.
script_name=`basename $0`
echo "The name of this script is $script_name."
The output of commands can be used as arguments to another command, to set a variable, and even for generating the argument list in a for loop.
rm `cat filename` |
# "filename" contains a list of files to delete. |
|
# |
|
|
# S. C. points out that "arg list |
too long" error might result. |
|
# Better is |
xargs rm |
−− < filename |
# ( −− covers those |
cases where "filename" begins with a "−" ) |
textfile_listing=`ls *.txt`
# Variable contains names of all *.txt files in current working directory. echo $textfile_listing
textfile_listing2=$(ls *.txt) # The alternative form of command substitution. echo $textfile_listing
#Same result.
#A possible problem with putting a list of files into a single string
#is that a newline may creep in.
# |
|
|
|
|
# A safer way to assign a list of files to |
a parameter is with |
an array. |
||
# |
shopt −s nullglob |
# If no match, |
filename expands to |
nothing. |
#textfile_listing=( *.txt )
#Thanks, S.C.
Command substitution may result in word splitting.
COMMAND `echo a b` |
# 2 |
args: a |
and b |
|
COMMAND "`echo a b`" |
# 1 |
arg: "a b" |
||
COMMAND |
`echo` |
# no arg |
|
|
COMMAND |
"`echo`" |
# one empty arg |
# Thanks, S.C.
Word splitting resulting from command substitution may remove trailing newlines characters from the output of the reassigned command(s). This can cause unpleasant surprises.
Chapter 14. Command Substitution |
213 |
Advanced Bash−Scripting Guide
dir_listing=`ls −l` echo $dirlisting
# Expecting a nicely ordered |
directory |
listing, such as: |
||||||
# −rw−rw−r−− |
1 |
bozo |
30 |
May 13 |
17:15 1.txt |
|||
# |
−rw−rw−r−− |
1 |
bozo |
51 |
May |
15 |
20:57 |
t2.sh |
# |
−rwxr−xr−x |
1 |
bozo |
217 |
Mar |
5 |
21:13 |
wi.sh |
#However, what you get is:
#total 3 −rw−rw−r−− 1 bozo bozo 30 May 13 17:15 1.txt −rw−rw−r−− 1 bozo
#bozo 51 May 15 20:57 t2.sh −rwxr−xr−x 1 bozo bozo 217 Mar 5 21:13 wi.sh
#The newlines disappeared.
Even when there is no word splitting, command substitution can remove trailing newlines.
#cd "`pwd`" # This should always work.
#However...
mkdir 'dir with trailing newline
'
cd 'dir with trailing newline
'
cd "`pwd`" |
# |
Error message: |
# bash: cd: |
/tmp/file with trailing newline: No such file or directory |
|
cd "$PWD" |
# |
Works fine. |
old_tty_setting=$(stty −g) |
# Save old terminal setting. |
echo "Hit a key " |
|
stty −icanon −echo |
# Disable "canonical" mode for terminal. |
|
# Also, disable *local* echo. |
key=$(dd bs=1 count=1 2> /dev/null) # Using 'dd' to get a keypress. |
|
stty "$old_tty_setting" |
# Restore old setting. |
echo "You hit ${#key} key." |
# ${#variable} = number of characters in $variable |
# |
|
#Hit any key except RETURN, and the output is "You hit 1 key."
#Hit RETURN, and it's "You hit 0 key."
#The newline gets eaten in the command substitution.
Thanks, S.C.
Command substitution even permits setting a variable to the contents of a file, using either redirection or the cat command.
variable1=`<file1` |
# |
Set |
"variable1" |
to |
contents |
of |
"file1". |
variable2=`cat file2` |
# |
Set |
"variable2" |
to |
contents |
of |
"file2". |
# Be aware that the variables may contain embedded whitespace, #+ or even (horrors), control characters.
Chapter 14. Command Substitution |
214 |
Advanced Bash−Scripting Guide
Command substitution makes it possible to extend the toolset available to Bash. It is simply a matter of writing a program or script that outputs to stdout (like a well−behaved UNIX tool should) and assigning that output to a variable.
#include <stdio.h>
/* "Hello, world." C program */
int main()
{
printf( "Hello, world." ); return (0);
}
bash$ gcc −o hello hello.c
#!/bin/bash
# hello.sh
greeting=`./hello` echo $greeting
bash$ sh hello.sh
Hello, world.
The $(COMMAND) form has superseded backticks for command substitution.
output=$(sed −n /"$1"/p $file)
# From "grp.sh" example.
Examples of command substitution in shell scripts:
1.Example 10−7
2.Example 10−24
3.Example 9−22
4.Example 12−2
5.Example 12−15
6.Example 12−12
7.Example 12−32
8.Example 10−12
9.Example 10−9
10.Example 12−24
11.Example 16−5
12.Example A−12
13.Example 28−1
14.Example 12−28
15.Example 12−29
Chapter 14. Command Substitution |
215 |
Advanced Bash−Scripting Guide
16. Example 12−30
Chapter 14. Command Substitution |
216 |