I/O 重定向

==================
默认情况下始终有3 个"文件"处于打开状态, stdin (键盘), stdout (屏幕), and stderr
(错误消息输出到屏幕上). 这3 个文件和其他打开的文件都可以被重定向. 对于重定向简单的
解释就是捕捉一个文件, 命令, 程序, 脚本, 或者甚至是脚本中的代码块(参见 Example 3-1
和 Example 3-2)的输出, 然后将这些输出作为输入发送到另一个文件, 命令, 程序, 或脚本
中.
每个打开的文件都会被分配一个文件描述符.[1]stdin, stdout, 和stderr 的文件描述符分别
是0, 1, 和 2. 对于正在打开的额外文件, 保留了描述符3 到9. 在某些时候将这些格外的文件
描述符分配给stdin, stdout, 或者是stderr 作为临时的副本链接是非常有用的. [2] 在经过
复杂的重定向和刷新之后需要把它们恢复成正常的样子 (参见 Example 16-1).
1 COMMAND_OUTPUT >
2 # 重定向stdout 到一个文件.
3 # 如果没有这个文件就创建, 否则就覆盖.
4
5 ls -lR > dir-tree.list
6 # 创建一个包含目录树列表的文件.
7
8 : > filename
9 # > 会把文件"filename"截断为0 长度.
10 # 如果文件不存在, 那么就创建一个0 长度的文件(与’touch’的效果相同).
11 # : 是一个占位符, 不产生任何输出.
12
13 > filename
14 # > 会把文件"filename"截断为0 长度.
15 # 如果文件不存在, 那么就创建一个0 长度的文件(与’touch’的效果相同).
16 # (与上边的": >"效果相同, 但是在某些shell 下可能不能工作.)
17
18 COMMAND_OUTPUT >>
19 # 重定向stdout 到一个文件.
20 # 如果文件不存在, 那么就创建它, 如果存在, 那么就追加到文件后边.
21
22
23 # 单行重定向命令(只会影响它们所在的行):
24 # ——————————————————————–
25
26 1>filename
27 # 重定向stdout 到文件"filename".
28 1>>filename
29 # 重定向并追加stdout 到文件"filename".
30 2>filename
31 # 重定向stderr 到文件"filename".
32 2>>filename
33 # 重定向并追加stderr 到文件"filename".
34 &>filename
35 # 将stdout 和stderr 都重定向到文件"filename".
36
37
#===========================================================
===================
38 # 重定向stdout, 一次一行.
39 LOGFILE=script.log
40
41 echo "This statement is sent to the log file, "$LOGFILE"." 1>$LOGFILE
42 echo "This statement is appended to "$LOGFILE"." 1>>$LOGFILE
43 echo "This statement is also appended to "$LOGFILE"." 1>>$LOGFILE
44 echo "This statement is echoed to stdout, and will not appear in "$LOGFILE"."
45 # 每行过后, 这些重定向命令会自动"reset".
46
47
48
49 # 重定向stderr, 一次一行.
50 ERRORFILE=script.errors
51
52 bad_command1 2>$ERRORFILE # 错误消息发到$ERRORFILE 中.
53 bad_command2 2>>$ERRORFILE # 错误消息添加到$ERRORFILE 中.
54 bad_command3 # 错误消息echo 到stderr,
55 #+ 并且不出现在$ERRORFILE 中.
56 # 每行过后, 这些重定向命令也会自动"reset".
57
#===========================================================
===================
58
59
60
61 2>&1
62 # 重定向stderr 到stdout.
63 # 得到的错误消息与stdout 一样, 发送到一个地方.
64
65 i>&j
66 # 重定向文件描述符i 到 j.
67 # 指向i 文件的所有输出都发送到j 中去.
68
69 >&j
70 # 默认的, 重定向文件描述符1(stdout)到 j.
71 # 所有传递到stdout 的输出都送到j 中去.
72
73 0< FILENAME
74 < FILENAME
75 # 从文件中接受输入.
76 # 与">"是成对命令, 并且通常都是结合使用.
77 #
78 # grep search-word <filename
79
80
81 [j]<>filename
82 # 为了读写"filename", 把文件"filename"打开, 并且分配文件描述符"j"给它.
83 # 如果文件"filename"不存在, 那么就创建它.
84 # 如果文件描述符"j"没指定, 那默认是fd 0, stdin.
85 #
86 # 这种应用通常是为了写到一个文件中指定的地方.
87 echo 1234567890 > File # 写字符串到"File".
88 exec 3<> File # 打开"File"并且给它分配fd 3.
89 read -n 4 <&3 # 只读4 个字符.
90 echo -n . >&3 # 写一个小数点.
91 exec 3>&- # 关闭fd 3.
92 cat File # ==> 1234.67890
93 # 随机存储.
94
95
96
97 |
98 # 管道.
99 # 通用目的的处理和命令链工具.
100 # 与">"很相似, 但是实际上更通用.
101 # 对于想将命令, 脚本, 文件和程序串连起来的时候很有用.
102 cat *.txt | sort | uniq > result-file
103 # 对所有的.txt 文件的输出进行排序, 并且删除重复行,
104 # 最后将结果保存到"result-file"中.
可以将输入输出重定向和(或)管道的多个实例结合到一起写在一行上.
1 command < input-file > output-file
2
3 command1 | command2 | command3 > output-file
参见 Example 12-28 和 Example A-15.
可以将多个输出流重定向到一个文件上.
1 ls -yz >> command.log 2>&1
2 # 将错误选项"yz"的结果放到文件"command.log"中.
3 # 因为stderr 被重定向到这个文件中,
4 #+ 所有的错误消息也就都指向那里了.
5
6 # 注意, 下边这个例子就不会给出相同的结果.
7 ls -yz 2>&1 >> command.log
8 # 输出一个错误消息, 但是并不写到文件中.
9
10 # 如果将stdout 和stderr 都重定向,
11 #+ 命令的顺序会有些不同.
关闭文件描述符
n<&- 关闭输入文件描述符n.
0<&-, <&- 关闭stdin.
n>&- 关闭输出文件描述符n.
1>&-, >&- 关闭stdout.
子进程继承了打开的文件描述符. 这就是为什么管道可以工作. 如果想阻止fd 被继承, 那么可
以关掉它.
1 # 只重定向stderr 到一个管道.
2
3 exec 3>&1 # 保存当前stdout 的"值".
4 ls -l 2>&1 >&3 3>&- | grep bad 3>&- # 对’grep’关闭fd 3(但不关闭’ls’).
5 # ^^^^ ^^^^
6 exec 3>&- # 现在对于剩余的脚本关闭它.
7
8 # Thanks, S.C.