Previous | Table of Contents | Next |
Redirecting Two File Descriptors
You can redirect STDOUT and STDERR to a single file by using the general form for redirecting the output of one file descriptor to another:
n>&m
Here n and m are file descriptors (integers). If you let n=2 and m=1, you see that STDERR is redirected to STDOUT. By redirecting STDOUT to a file, you also redirect STDERR.
If m is a hyphen (-) instead of a number, the file corresponding to the file descriptor n is closed. When a file descriptor is closed, trying to read or write from it results in an error.
Reading Files, Another Look One of the most common uses of this form of redirection is for reading files one line at a time. You already looked at using a while loop to perform this task:
while read LINE do : # manipulate file here done < file
The main problem with this loop is that it is executed in a subshell, thus changes to the script environment, such as exporting variables and changing the current working directory, does not apply to the script after the while loop changes. As an example, consider the following script:
#!/bin/sh if [ -f "$1" ] ; then i=0 while read LINE do i=echo "$i + 1" | bc done < "$1" echo $i fi
This script tries to count the number of lines in the file specified to it as an argument. Executing this script on the file
$ cat dirs.txt /tmp /usr/local /opt/bin /var
produces the following output:
0
Although you are incrementing the value of $i using the command
i=echo "$i + 1" | bc
when the while loop exits, the value of $i is not preserved. In this case, you need to change a variables value inside the while loop and then use that value outside the loop. You can accomplish this by redirecting the STDIN prior to entering the loop and then restoring STDIN to the terminal after the while loop. The basic syntax is
exec n<&0 < file while read LINE do : # manipulate file here done exec 0<&n n<&-
Here n is an integer greater than 2, and file is the name of the file you want to read. Usually n is chosen as a small number such as 3, 4, or 5.
As an example, you can construct a shell version of the cat command:
#!/bin/sh if [ $# -ge 1 ] ; then for FILE in $@ do exec 5<&0 < "$i" while read LINE ; do echo $LINE ; done exec 0<&5 5<&- done fi
In this chapter, I formally introduced the concept of input and output. I covered the echo and printf commands that are used to produce messages from within shell scripts.
I also introduced output redirection, covering the methods of redirecting and appending the output of a command to a file. In addition, I discussed reading input for the first time. I also covered reading in files and reading input from users.
Finally, I introduced the concept of a file descriptor and showed several aspects of its use, including opening files for reading and writing, closing files, and redirecting the output of two file descriptors to one source.
In the subsequent chapters, I will expand on the material covered here, and you will see many more applications of both input and output redirection along with the use of file descriptors.
#!/bin/sh if [ $# -lt 2 ] ; then echo "ERROR: Insufficient arguments." ; exit 1 ; fi case "$1" in -o) : # convert the number stored in "$2" into octal ;; -x) : # convert the number stored in "$2" into hexadecimal ;; -e) : # convert the number stored in "$2" into scientific ⇒notation ;; *) echo "ERROR: Unknown conversion, $1!" ;; esac
Previous | Table of Contents | Next |