A file descriptor is a single-digit integer that is assigned to an
Taking explicit control of the file descriptors in a shell script is a rather infrequently used and somewhat complex feature. You might
You might need to maintain access to many open files for input and output at the same time. You might be trying to retrofit existing programs or tools that use file or socket descriptors. You might be trying to swap devices so that an application's input and output descriptors match some reasonably complex requirements.
In some cases, the simpler solution of common redirection will serve you well. In other cases, you might need to take direct control of the file descriptors that Qshell maintains and uses for the utilities it invokes.
File descriptors 3 through 9 are available for you to use as you wish. To use these file descriptors, you must use the redirection operators listed in Table 10.10. The
|
Operator |
Description |
|---|---|
|
[n] < |
Redirect input. |
|
[n] < &m |
Duplicate input. (Merge input streams.) |
|
[n] <&- |
Close input. |
|
[n] <<, [n] <<- |
Open a "here" document. |
|
[n] > |
Replace output. |
|
[n] > |
Replace output; ignore the
|
|
[n] >> |
Append output. |
|
[n] >& m |
Duplicate output (Merge output streams.) |
|
[n] >&- |
Close output. |
At least some of these should look familiar to you because Table 10.10 is a more complete version of Table 10.1. The file descriptor
Therefore, the following two tr commands are equivalent:
tr [:lower:] [:upper:] <goodoleboys.txt >upper.txt tr [:lower:] [:upper:] 0<goodoleboys.txt 1>upper.txt
One of the features added to V5R2 Qshell was the ulimit utility, which displays or sets system resources. The n option allows you to display or set the maximum number of file descriptors that a process can open, as in the following example:
ulimit -n 200 /home/jsmith $
To open and close files under file descriptors for the current Qshell session or running script, use the
Open file goodoleboys.txt for input as file descriptor 3:
exec 3<goodoleboys.txt
Open a file as input under file descriptor 9 that is named in positional parameter 1:
exec 9<
Open stdin (file descriptor 0) to file temp.txt:
exec < temp.txt
Close stdin (file descriptor 0):
exec <&-
Close stdout (file descriptor 1):
exec >&-
Close the file opened under file descriptor 3:
exec 3<&-
Open file descriptor 7, assigning it to stdout:
exec 7>&1
Notice that an ampersand, not a dollar sign, precedes the numeral 1. Both file descriptors 1 and 7 point to stdout. The two output streams are merged.
Assign stderr to wherever stdout is assigned. The two output streams are merged:
exec 2>&1
You can use the test utility to determine whether or not a file descriptor is open and associated with a terminal, as the following example shows:
if [ -t 0 ]
then
print "Enter name,age,phone."
fi
If stdin is assigned to the keyboard, Qshell displays the message "Enter name, age, phone." However, if stdin is redirected to another file or if input is coming from a pipe, Qshell does not output the prompting message.
To read from a file, use the read utility with the -u option. Follow the -u with the number of the file descriptor from which to read. You can separate the option and the file descriptor number, but you don't have to, so the following two commands are equivalent:
read -u 5 line read -u 5 line
There are two ways to write to a file descriptor: an easy way and an easier way. You need to know both
The easier way is to specify the file descriptor number in the -u (unit) option of the print utility:
print -u 3 $name
The easy method is to use a duplication redirection operator (>) with any Qshell command that
Since both methods work for print , the following two statements do the same thing:
print -u 7 $name print $name >&7
Each command writes the value in the variable name to the file opened under file descriptor 7.
In Figure 10.26, the first
exec
opens member TEMP in source physical file JSMITHS /QRPGSRC for output with file descriptor 3. The two
echo
commands write to the source member. The second
exec
|
|
exec 3>/qsys.lib/jsmith.lib/qrpgsrc.file/temp.mbr echo "line 1" >&3 ecbo "line 2" >&3 exec 3>&- cat /qsys.lib/jsmith.lib/qrpgsrc.file/temp.mbr line 1 line 2 /home/JSMITH $
|
|
In the following example, if the first parameter is missing, a message is sent to stderr in order to
if [ -z ]
then
print -u2 "Usage: $(basename
if [ -z $1 ] then print -u2 "Usage: $(basename $0) file ..." exit 1 fi
) file ..."
exit 1
fi
Without the redirection operator, the print statement would send the output to stdout.
Figure 10.27 builds an FTP script that will be used for logging into an FTP server and exchanging files. First, it reads file tkmjzzypokrtmmoos to get the
|
|
#!/bin/qsh
# get user id from text file tkmjzzypokrtmmoos
exec 3<tkmjzzypokrtmmoos
read -u 3 id
exec 3<&-
# get password from text file jnnoiiesokjlxrros
exec 3<jnnoiiesokjlxrros
read -u 3 pass
exec 3<&-
# build signon record for remote ftp
print $id $pass
# read ftp commands from model file ftpmodel.txt
exec 3<ftpmodel.txt
while read -u3 modelline
do
if [ "$modelline" = '*put' ] ; then
exec 4<ftpputlist.txt
while read -u4 dline
do
print put $dline
done
exec 4<&-
elif [ "$modelline" = '*get' ] ; then
exec 4<ftpgetlist.txt
while read -u4 dline
do
print get $dline
done
exec 4<&-
else
print $modelline
fi
done
exec 3<&-
# normal end
exit 0
|
|
Figure 10.28 shows the input files and the output produced by the script in Figure 10.27.
|
|
Input: tkmjzzypokrtmmoos myid Input: jnnoiiesokjlxrros mypass Input: ftpmodel.txt namefmt 1 lcd /home/mydir cd /home/yourdir *put *get quit Input: ftpgetlist.txt inputa inputb Input: ftpputlist.txt data1 data2 data3 data4 data5 Output: myid mypass namefmt 1 lcd /home/mydir cd /home/yourdir put data1 put data2 put data3 put data4 put data5 get inputa get inputb quit
|
|
Qshell
The following two examples of using
while
while read line do echo $line >> temp.txt done <goodoleboys.txt while read line do echo $line done <goodoleboys.txt >> temp.txt
The content of file goodoleboys.txt is appended to the output file temp.txt one line at a time. The first example redirects the output of the
echo
command, while the second redirects the output of the entire loop. The example that does the redirection of the entire loop is much faster because it only opens the output file once. The other example causes Qshell to process ten file-open
You may direct input and/or output by placing the redirection after the
done
end-of-loop
Figure 10.29 shows the use of redirection operators with
for
loops. The first loop numbers and lists the positional parameters. The second loop is identical to the first, except that the output of the loop is piped into the
|
|
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}
pos=0 for i do let pos=pos+1 echo $i \($pos\) done mydata.txt (1) yourdata.txt (2) hisdata.txt (3) herdata.txt (4) ourdata.txt (5) theirdata.txt (6) pos=0 for i do let pos=pos+1 echo $i \($pos\) done sort herdata.txt (4) hisdata.txt (3) mydata.txt (1) ourdata.txt (5) theirdata.txt (6) yourdata.txt (2)
|
|
The example in Figure 10.30 is identical to Figure 10.27, except that file descriptors are not used. Instead, stdin and stdout are redirected with each command, including the loops.
|
|
#!/bin/qsh
# get user id from text file tkmjzzypokrtmmoos
read id <tkmjzzypokrtmmoos
# get password from text file jnnoiiesokjlxrros
read pass <jnnoiiesokjlxrros
# build signon record for remote ftp
print $id $pass
# read ftp commands from model file ftpmodel.txt
while read modelline
do
if [ "$modelline" = '*put' ] ; then
while read dline
do
print put $dline
done <ftpputlist.txt
elif [ "$modelline" = '*get' ] ; then
while read dline
do
print get $dline
done <ftpgetlist.txt
else
print $modelline
fi
done <ftpmodel.txt
# normal end
exit 0
|
|