1. 理解输入和输出
1.1 标准文件描述符
Linux 系统将每个对象当作文件处理。这包括输入和输出进程。Linux 用文件描述符(file descriptor)来标识每个文件对象。文件描述符是一个非负整数,可以唯一标识会话中打开的文件。每个进程一次最多可以有九个文件描述符。Linux 标准文件描述符如下:
文件描述符 | 缩写 | 描述 |
---|---|---|
0 | STDIN | 标准输入 |
1 | STDOUT | 标准输出 |
2 | STDERR | 标准结果 |
-
STDIN
STDIN 文件描述符代表 shell 的标准输入。对终端界面来说,标准输入是键盘。shell 从 STDIN 文件描述符对应的键盘获得输入,在用户输入时处理每个字符。
在使用输入重定向符号(<)时,Linux 会用重定向指定的文件来替换标准输入文件描述符。它会读取文件并提取数据,就如同它是键盘上键入的。可以通过 STDIN 重定向符号强制 cat 命令接受来自另一个非 STDIN 文件的输入。
$ cat < testfile This is the first line. This is the second line. This is the third line. $
现在 cat 命令会用 testfile 文件中的行作为输入。
-
STDOUT
STDOUT 文件描述符代表 shell 的标准输出。在终端界面上,标准输出就是终端显示器。shell 的所有输出(包括 shell 中运行的程序和脚本)会被定向到标准输出中,也就是显示器。
$ ls -l > test2 $ cat test2 total 20 -rw-rw-r-- 1 rich rich 53 2014-10-16 11:30 test -rw-rw-r-- 1 rich rich 0 2014-10-16 11:32 test2 -rw-rw-r-- 1 rich rich 73 2014-10-16 11:23 testfile $
通过输出重定向符号,通常会显示到显示器的所有输出会被 shell 重定向到指定的重定向文件。
可以将数据追加到某个文件。这可以用>>符号来完成。
$ who >> test2 $ cat test2 total 20 -rw-rw-r-- 1 rich rich 53 2014-10-16 11:30 test -rw-rw-r-- 1 rich rich 0 2014-10-16 11:32 test2 -rw-rw-r-- 1 rich rich 73 2014-10-16 11:23 testfile rich pts/0 2014-10-17 15:34 (192.168.1.2) $
shell 对于错误消息的处理是跟普通输出分开的。
$ ls -al badfile > test3 ls: cannot access badfile: No such file or directory $ cat test3 $
-
STDERR
shell 通过特殊的 STDERR 文件描述符来处理错误消息。STDERR 文件描述符代表 shell 的标准错误输出。shell 或 shell 中运行的程序和脚本出错时生成的错误消息都会发送到这个位置。
默认情况下,STDERR 文件描述符会和 STDOUT 文件描述符指向同样的地方(尽管分配给它们的文件描述符值不同)。也就是说,默认情况下,错误消息也会输出到显示器输出中。
但如上例,STDERR 并不会随着 STDOUT 的重定向而发生改变。
1.2 重定向错误
-
只重定向错误
STDERR 文件描述符被设成 2。可以选择只重定向错误消息,将该文件描述符值放在重定向符号前。该值必须紧紧地放在重定向符号前,否则不会工作。
$ ls -al badfile 2> test4 $ cat test4 ls: cannot access badfile: No such file or directory $
-
重定向错误和数据
如果想重定向错误和正常输出,必须用两个重定向符号。需要在符号前面放上待重定向数据所对应的文件描述符,然后指向用于保存数据的输出文件。
$ ls -al test test2 test3 badtest 2> test6 1> test7 $ cat test6 ls: cannot access test: No such file or directory ls: cannot access badtest: No such file or directory $ cat test7 -rw-rw-r-- 1 rich rich 158 2014-10-16 11:32 test2 -rw-rw-r-- 1 rich rich 0 2014-10-16 11:33 test3 $
shell 利用 1> 符号将 ls 命令的正常输出重定向到了 test7 文件,而这些输出本该是进入 STDOUT 的。所有本该输出到 STDERR 的错误消息通过 2> 符号被重定向到了 test6 文件。
也可以将 STDERR 和 STDOUT 的输出重定向到同一个输出文件。为此 bash shell 提供了特殊的重定向符号 &>。
$ ls -al test test2 test3 badtest &> test7 $ cat test7 ls: cannot access test: No such file or directory ls: cannot access badtest: No such file or directory -rw-rw-r-- 1 rich rich 158 2014-10-16 11:32 test2 -rw-rw-r-- 1 rich rich 0 2014-10-16 11:33 test3 $
当使用 &> 符时,命令生成的所有输出都会发送到同一位置,包括数据和错误。
2. 在脚本中重定向输出
2.1 临时重定向
在重定向到文件描述符时,你必须在文件描述符数字之前加一个 &:
echo "This is an error message" >&2
这行会在脚本的 STDERR 文件描述符所指向的位置显示文本,而不是通常的 STDOUT。
$ cat test8
#!/bin/bash
# testing STDERR messages
echo "This is an error" >&2
echo "This is normal output"
$
像平常一样运行这个脚本,你可能看不出什么区别。
$ ./test8
This is an error
This is normal output
$
默认情况下,Linux 会将 STDERR 导向 STDOUT。但是,如果你在运行脚本时重定向了STDERR,脚本中所有导向 STDERR 的文本都会被重定向。
$ ./test8 2> test9
This is normal output
$ cat test9
This is an error
$
2.2 永久重定向
如果脚本中有大量数据需要重定向,那重定向每个 echo 语句就会很烦琐。取而代之,你可以用exec 命令告诉 shell 在脚本执行期间重定向某个特定文件描述符。
$ cat test10
#!/bin/bash
# redirecting all output to a file
exec 1>testout
echo "This is a test of redirecting all output"
echo "from a script to another file."
echo "without having to redirect every individual line"
$ ./test10
$ cat testout
This is a test of redirecting all output
from a script to another file.
without having to redirect every individual line
$
exec 命令会启动一个新 shell 并将 STDOUT 文件描述符重定向到文件。脚本中发给 STDOUT 的所有输出会被重定向到文件。
$ cat test11
#!/bin/bash
# redirecting output to different locations
exec 2>testerror
echo "This is the start of the script"
echo "now redirecting all output to another location"
exec 1>testout
echo "This output should go to the testout file"
echo "but this should go to the testerror file" >&2
$
$ ./test11
This is the start of the script
now redirecting all output to another location
$ cat testout
This output should go to the testout file
$ cat testerror
but this should go to the testerror file
$
2.3 在脚本中重定向输入
exec 命令允许你将 STDIN 重定向到Linux 系统上的文件中:exec 0< testfile
$ cat test12
#!/bin/bash
# redirecting file input
exec 0< testfile
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
$ ./test12
Line #1: This is the first line.
Line #2: This is the second line.
Line #3: This is the third line.
$
4. 创建自己的重定向
待补充
5. 阻止命令输出
可以将 STDERR 重定向到一个叫作 null 文件的特殊文件。null 文件跟它的名字很像,文件里什么都没有。shell 输出到 null 文件的任何数据都不会保存,全部都被丢掉了。
在 Linux 系统上 null 文件的标准位置是 /dev/null。你重定向到该位置的任何数据都会被丢掉,不会显示。
$ ls -al > /dev/null
$ cat /dev/null
$
也可以在输入重定向中将 /dev/null 作为输入文件。由于 /dev/null 文件不含有任何内容,程序员通常用它来快速清除现有文件中的数据,而不用先删除文件再重新创建。
$ cat testfile
This is the first line.
This is the second line.
This is the third line.
$ cat /dev/null > testfile
$ cat testfile
$