(M)  s i s t e m a   o p e r a c i o n a l   m a g n u x   l i n u x ~/ · documentação · suporte · sobre

 

3.13. I/O Redirection

There are always three default "files" open, stdin (the keyboard), stdout (the screen), and stderr (error messages output to the screen). These, and any other open files, can be redirected. Redirection simply means capturing the output of a file, command, program, script, or even code block within a script (see Example 3-2 and Example 3-3) and sending it as input to another file, command, program, or script.

Each open file gets assigned a file descriptor. [1] The file descriptors for stdin, stdout, and stderr are 0, 1, and 2, respectively. For opening additional files, there remain descriptors 3 to 9. It is sometimes useful to assign one of these additional file descriptors to stdin, stdout, or stderr as a temporary duplicate link. [2] This simplifies restoration to normal after complex redirection and reshuffling (see Example 3-72).

    >
      # Redirect stdout to a file.
      # Creates the file if not present, otherwise overwrites it.

      ls -lR > dir-tree.list
      # Creates a file containing a listing of the directory tree.

    >>
      # Redirect stdout to a file.
      # Creates the file if not present, otherwise appends to it.

    2> &1
      # Redirects stderr to stdout.
      # Has the effect of making visible error messages that might otherwise not be seen.

    i> &j
      # Redirects file descriptor i to j
      # All output of file pointed to by i gets sent to file pointed to by j

    <
      # Accept input from a file.
      # Companion command to ">", and often used in combination with it.
      grep search-word <filename

    |
      # Pipe.
      # General purpose process and command chaining tool.
      # Similar to ">", but more general in effect.
      # Useful for chaining commands, scripts, files, and programs together.
      cat *.txt | sort | uniq > result-file
      # Sorts the output of all the .txt files and deletes duplicate lines,
      # finally saves results to "result-file".

Note: Multiple instances of input and output redirection and/or pipes can be combined in a single command line.

command < input-file > output-file

command1 | command2 | command3 > output-file

n<&-

close input file descriptor n

<&-

close stdin

n>&-

close output file descriptor n

>&-

close stdout

The exec <filename command redirects stdin to a file. From that point on, all stdin comes from that file, rather than its normal source (usually keyboard input). This provides a method of reading a file line by line and possibly parsing each line of input using sed and/or awk.

Example 3-72. Redirecting stdin using exec

#!/bin/bash
# Redirecting stdin using 'exec'.


exec 6<&0   # Link file descriptor #6 with stdin.

exec < data-file   # stdin replaced by file "data-file"

read a1   # Reads first line of file "data-file".
read a2   # Reads second line of file "data-file."

echo
echo "Following lines read from file."
echo "-------------------------------"
echo $a1
echo $a2

echo; echo; echo

exec 0<&6   # Now restore stdin from fd #6, where it had been saved.

echo -n "Enter data  "
read b1  # Now "read" functions as expected, reading from normal stdin.
echo "Input read from stdin."
echo "----------------------"
echo "b1 = $b1"

echo

exit

Blocks of code, such as while, until, and for loops, even if/then test blocks can also incorporate redirection of stdin. The < operator at the the end of the code block accomplishes this.

Example 3-73. Redirected while loop

#!/bin/bash

if [ -z $1 ]
then
  Filename=names.data  # Default, if no filename specified.
else
  Filename="$1"
fi  

while [ "$name" != Smith ]  # Why is variable $name in quotes?
do
  read name        # Reads from $Filename, rather than stdin.
  echo $name
done <$Filename   # Redirects stdin to file $Filename. 

exit 0

Example 3-74. Redirected until loop

#!/bin/bash
# Same as previous example, but with "until" loop.

if [ -z $1 ]
then
  Filename=names.data  # Default, if no filename specified.
else
  Filename="$1"
fi  

# while [ "$name" != Smith ]
until [ "$name" = Smith ]     # Change  !=  to =.
do
  read name        # Reads from $Filename, rather than stdin.
  echo $name
done <$Filename   # Redirects stdin to file $Filename. 

# Same results as with "while" loop in previous example.

exit 0

Example 3-75. Redirected for loop

#!/bin/bash

if [ -z $1 ]
then
  Filename=names.data  # Default, if no filename specified.
else
  Filename="$1"
fi  

line_count=`wc $Filename | awk '{ print $1 }'`  # Number of lines in target file.
# Very contrived and kludgy, nevertheless shows that
# it's possible to redirect stdin within a "for" loop...
# if you're clever enough.


for name in `seq $line_count`  # Recall that "seq" prints sequence of numbers.
# while [ "$name" != Smith ]   --   more complicated than a "while" loop   --
do
  read name        # Reads from $Filename, rather than stdin.
  echo $name
  if [ "$name" = Smith ]   # Need all this extra baggage here.
  then
    break
  fi  
done <$Filename   # Redirects stdin to file $Filename. 

exit 0

Example 3-76. Redirected if/then test

#!/bin/bash

if [ -z $1 ]
then
  Filename=names.data  # Default, if no filename specified.
else
  Filename="$1"
fi  

TRUE=1

if [ $TRUE ]
then
 read name
 echo $name
fi <$Filename
# Reads only first line of file.
# An if/then test has no way of iterating unless embedded in a loop.

exit 0

Clever use of I/O redirection permits parsing and stitching together snippets of files and command output. One possible application of this might be generating report and log files.

Note: Here documents are a special case of I/O redirection. See Section 3.24.

Notes

[1]

A file descriptor is simply a number that the operating system assigns to an open file to keep track of it. Consider it a simplified version of a file pointer. It is analogous to a file handle in C.

[2]

Using file descriptor 5 might cause problems. When Bash forks a child process, as with exec, the child inherits fd 5 (see Chet Ramey's archived e-mail, SUBJECT: RE: File descriptor 5 is held open). Best leave this particular fd alone.