当前位置: 首页 > 文档资料 > Shell 中文文档 >

Appendix E. A Detailed Introduction to I/O and I/O Redirection

优质
小牛编辑
134浏览
2023-12-01

written by St閜hane Chazelas, and revisedby the document author

A command expects the first three filedescriptorsto be available. The first, fd0(standard input, stdin),is for reading. The other two (fd 1,stdoutand fd 2,stderr) are for writing.

There is a stdin, stdout,and a stderrassociated with each command.ls 2>&1means temporarily connecting thestderrof the lscommand to thesame "resource"as the shell'sstdout.

By convention, a command reads its input from fd 0(stdin), prints normal output to fd1 (stdout), and error ouput to fd 2(stderr). If one of those three fd's isnot open, you may encounter problems:

 
bash$ 


cat /etc/passwd >&-

 
cat: standard output: Bad file descriptor
       

For example, when xtermruns, it firstinitializes itself. Before running the user's shell,xtermopens the terminal device(/dev/pts/<n> or something similar) three times.

At this point, Bash inherits these three file descriptors,and each command (child process) run by Bash inheritsthem in turn, except when you redirect the command. Redirectionmeans reassigningone of the file descriptors to another file (or a pipe, oranything permissible). File descriptors may be reassignedlocally (for a command, a command group, a subshell, a while or if or case or for loop...),or globally, for the remainder of the shell (using exec).

ls > /dev/nullmeansrunning lswith its fd 1 connected to/dev/null.

 
bash$ 


lsof -a -p $$ -d0,1,2

 
COMMAND PID     USER   FD   TYPE DEVICE SIZE NODE NAME
 bash    363 bozo        0u   CHR  136,1         3 /dev/pts/1
 bash    363 bozo        1u   CHR  136,1         3 /dev/pts/1
 bash    363 bozo        2u   CHR  136,1         3 /dev/pts/1

bash$ exec 2> /dev/nullbash$ lsof -a -p $$ -d0,1,2COMMAND PID USER FD TYPE DEVICE SIZE NODE NAMEbash 371 bozo 0u CHR 136,1 3 /dev/pts/1bash 371 bozo 1u CHR 136,1 3 /dev/pts/1bash 371 bozo 2w CHR 1,3 120 /dev/null

bash$ bash -c 'lsof -a -p $$ -d0,1,2' | catCOMMAND PID USER FD TYPE DEVICE SIZE NODE NAMElsof 379 root 0u CHR 136,1 3 /dev/pts/1lsof 379 root 1w FIFO 0,0 7118 pipelsof 379 root 2u CHR 136,1 3 /dev/pts/1

bash$ echo "$(bash -c 'lsof -a -p $$ -d0,1,2' 2>&1)"COMMAND PID USER FD TYPE DEVICE SIZE NODE NAMElsof 426 root 0u CHR 136,1 3 /dev/pts/1lsof 426 root 1w FIFO 0,0 7520 pipelsof 426 root 2w FIFO 0,0 7520 pipe

This works for different types of redirection.

Exercise:Analyze the following script.

   1 #! /usr/bin/env bash
   2
   3 mkfifo /tmp/fifo1 /tmp/fifo2
   4 while read a; do echo "FIFO1: $a"; done < /tmp/fifo1 &
   5 exec 7> /tmp/fifo1
   6 exec 8> >(while read a; do echo "FD8: $a, to fd7"; done >&7)
   7
   8 exec 3>&1
   9 (
  10  (
  11   (
  12    while read a; do echo "FIFO2: $a"; done < /tmp/fifo2 | tee /dev/stderr | tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 >&7 &
  13    exec 3> /tmp/fifo2
  14
  15    echo 1st, to stdout
  16    sleep 1
  17    echo 2nd, to stderr >&2
  18    sleep 1
  19    echo 3rd, to fd 3 >&3
  20    sleep 1
  21    echo 4th, to fd 4 >&4
  22    sleep 1
  23    echo 5th, to fd 5 >&5
  24    sleep 1
  25    echo 6th, through a pipe | sed 's/.*/PIPE: &, to fd 5/' >&5
  26    sleep 1
  27    echo 7th, to fd 6 >&6
  28    sleep 1
  29    echo 8th, to fd 7 >&7
  30    sleep 1
  31    echo 9th, to fd 8 >&8
  32
  33   ) 4>&1 >&3 3>&- | while read a; do echo "FD4: $a"; done 1>&3 5>&- 6>&-
  34  ) 5>&1 >&3 | while read a; do echo "FD5: $a"; done 1>&3 6>&-
  35 ) 6>&1 >&3 | while read a; do echo "FD6: $a"; done 3>&-
  36
  37 rm -f /tmp/fifo1 /tmp/fifo2
  38
  39
  40 # For each command and subshell, figure out which fd points to what.
  41
  42 exit 0