Skip to content

Commit d94a884

Browse files
committed
chapter: I/O Redirection Detailed
1 parent 35367bc commit d94a884

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

index.ptree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ pages/bibliography.poly.pm
120120
pages/awk_micro_primer.poly.pm
121121
pages/parsing_pathnames.poly.pm
122122
pages/exit_codes.poly.pm
123+
pages/io_redirection_de.poly.pm
123124
}
124125

125126
}

pages/io_redirection_de.poly.pm

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#lang pollen
2+
3+
◊page-init{}
4+
◊define-meta[page-title]{I/O Redirection Detailed}
5+
◊define-meta[page-description]{A Detailed Introduction to I/O and I/O Redirection}
6+
7+
written by Stéphane Chazelas, and revised by the document author
8+
9+
A command expects the first three file descriptors to be
10+
available. The first, ◊code{fd 0} (standard input, stdin), is for
11+
reading. The other two (◊code{fd 1}, stdout and ◊code{fd 2}, stderr) are for
12+
writing.
13+
14+
There is a stdin, stdout, and a stderr associated with each
15+
command. ◊command{ls 2>&1} means temporarily connecting the stderr of
16+
the ◊command{ls} command to the same "resource" as the shell's stdout.
17+
18+
By convention, a command reads its input from ◊code{fd 0} (stdin),
19+
prints normal output to ◊code{fd 1} (stdout), and error ouput to
20+
◊code{fd 2} (stderr). If one of those three fd's is not open, you may
21+
encounter problems:
22+
23+
◊example{
24+
bash$ cat /etc/passwd >&-
25+
cat: standard output: Bad file descriptor
26+
}
27+
28+
For example, when ◊command{xterm} runs, it first initializes
29+
itself. Before running the user's shell, ◊command{xterm} opens the
30+
terminal device (◊fname{/dev/pts/<n>} or something similar) three
31+
times.
32+
33+
At this point, Bash inherits these three file descriptors, and each
34+
command (child process) run by Bash inherits them in turn, except when
35+
you redirect the command. Redirection means reassigning one of the
36+
file descriptors to another file (or a pipe, or anything
37+
permissible). File descriptors may be reassigned locally (for a
38+
command, a command group, a subshell, a while or if or case or for
39+
loop...), or globally, for the remainder of the shell (using
40+
◊command{exec}).
41+
42+
◊command{ls > /dev/null} means running ◊command{ls} with its ◊code{fd
43+
1} connected to ◊fname{/dev/null}.
44+
45+
◊example{
46+
bash$ lsof -a -p $$ -d0,1,2
47+
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
48+
bash 363 bozo 0u CHR 136,1 3 /dev/pts/1
49+
bash 363 bozo 1u CHR 136,1 3 /dev/pts/1
50+
bash 363 bozo 2u CHR 136,1 3 /dev/pts/1
51+
52+
53+
bash$ exec 2> /dev/null
54+
bash$ lsof -a -p $$ -d0,1,2
55+
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
56+
bash 371 bozo 0u CHR 136,1 3 /dev/pts/1
57+
bash 371 bozo 1u CHR 136,1 3 /dev/pts/1
58+
bash 371 bozo 2w CHR 1,3 120 /dev/null
59+
60+
61+
bash$ bash -c 'lsof -a -p $$ -d0,1,2' | cat
62+
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
63+
lsof 379 root 0u CHR 136,1 3 /dev/pts/1
64+
lsof 379 root 1w FIFO 0,0 7118 pipe
65+
lsof 379 root 2u CHR 136,1 3 /dev/pts/1
66+
67+
68+
bash$ echo "$(bash -c 'lsof -a -p $$ -d0,1,2' 2>&1)"
69+
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
70+
lsof 426 root 0u CHR 136,1 3 /dev/pts/1
71+
lsof 426 root 1w FIFO 0,0 7520 pipe
72+
lsof 426 root 2w FIFO 0,0 7520 pipe
73+
}
74+
75+
This works for different types of redirection.
76+
77+
Exercise: Analyze the following script.
78+
79+
◊example{
80+
#! /usr/bin/env bash
81+
82+
mkfifo /tmp/fifo1 /tmp/fifo2
83+
while read a; do echo "FIFO1: $a"; done < /tmp/fifo1 & exec 7> /tmp/fifo1
84+
exec 8> >(while read a; do echo "FD8: $a, to fd7"; done >&7)
85+
86+
exec 3>&1
87+
(
88+
(
89+
(
90+
while read a; do echo "FIFO2: $a"; done < /tmp/fifo2 | tee /dev/stderr \
91+
| tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 >&7 & exec 3> /tmp/fifo2
92+
93+
echo 1st, to stdout
94+
sleep 1
95+
echo 2nd, to stderr >&2
96+
sleep 1
97+
echo 3rd, to fd 3 >&3
98+
sleep 1
99+
echo 4th, to fd 4 >&4
100+
sleep 1
101+
echo 5th, to fd 5 >&5
102+
sleep 1
103+
echo 6th, through a pipe | sed 's/.*/PIPE: &, to fd 5/' >&5
104+
sleep 1
105+
echo 7th, to fd 6 >&6
106+
sleep 1
107+
echo 8th, to fd 7 >&7
108+
sleep 1
109+
echo 9th, to fd 8 >&8
110+
111+
) 4>&1 >&3 3>&- | while read a; do echo "FD4: $a"; done 1>&3 5>&- 6>&-
112+
) 5>&1 >&3 | while read a; do echo "FD5: $a"; done 1>&3 6>&-
113+
) 6>&1 >&3 | while read a; do echo "FD6: $a"; done 3>&-
114+
115+
rm -f /tmp/fifo1 /tmp/fifo2
116+
117+
118+
# For each command and subshell, figure out which fd points to what.
119+
# Good luck!
120+
121+
exit 0
122+
}

0 commit comments

Comments
 (0)