最近开始看UNIX环境高级编程,对于重定向的知识有所学习,在较早学习Linux命令行大全一书时对重定向学习不够深入,在UNIX环境高级编程第三章习题时有种恍然大明白的感觉。

重定向

按照惯例UNIX系统shell把文件描述符0与进程标准输入关联,1与标准输出关联,2与标准错误关联。

标准输入 标准输出 标准错误

默认情况下,标准输出和标准错误都被链接到屏幕上。
标准输入链接到键盘。I/O重定向的功能可以改变输出内容发送的目的地,也可以改变输入内容的来源。通常情况下,输入来自于键盘,输出内容显示在屏幕上,重定向可以改变这一惯例。

标准输出重定向

ls -l /usr/bin > ls-ouput.txt
这里我们将创建/usr/bin目录的一个长列表信息,并把这个显示结果输出到文件ls-output.txt.我们可以使用ls -l ls-output.txt查看文件情况。
接着可以把目录名换成一个不存在的目录名,例如:
ls -l /bin/usr > ls-ouput.txt
我们会收到错误提示:No such file or directory,由于我们没有重定向标准错误,所以错误信息还是直接打印在屏幕上。
这个时候我们通过ls -l命令查看ls-output.txt,吃惊的发现文件被清空了!
原因是我们使用>来重定向标准输出时,目的文件通常会从文件头部重新写。由于ls命令执行后没有任何标准输出,所以重定向操作开始重新改写这个文件,并在出现错误的情况下停止操作,最终导致了该文件内容被删除。
这就为我们提供了一种快速清空文件内容的方法:

> ls-output.txt

如果要在文件后面追加内容,而不是每次都从头开始写入的话可以使用>>来实现,下面的操作执行了两次,文件ls-output的大小翻倍.

标准错误重定向

标准输入 输出 错误对应的文件描述符分别是0 1 2,那么我们重定向标准错误可以采用如下方法:
ls -l /bin/usr 2> ls-error.txt
如果ls信息显示有误,会将相应的错误信息写入文件ls-error.txt,如果ls信息显示无误则列出相应目录的内容。
文件描述符2紧放在重定向符之前,将标准错误重定向到ls-error.txt文件中。

将标准错误和标准输出重定向到同一个文件

第一种传统方法:
ls -l /bin/usr > ls-output.txt 2>&1
使用这个方法将执行两个重定向操作。首先重定向标准输出到ls-output.txt文件中,然后使用标记符2>&1把文件描述符2(标准错误)重定向到文件描述符1(标准输出)中.
第二种方法:
ls -l /bin/usr &> ls-output.txt
在这个例子中只使用了一个标记符“&>”就把标准输出和标准错误都重定向到了ls-output.txt.
操作示例:

上面的例子我们演示了使用第一种方法可以重定向标准错误和标准输出,由于标准输出内容较多,所以我们只显示了10行来验证。
APUE课后习题3.5
The Bourne shell, Bourne-again shell, and Korn shell notation digit1>&digit2
says to redirect descriptor digit1 to the same file as descriptordigit2. What is the difference between the two commands
./a.out > outfile 2>&1
./a.out 2>&1 > outfile
(Hint: the shells process their command lines from left to right.)
大意就是问这两条命令的区别:
./a.out > outfile 2>&1
./a.out 2>&1 > outfile
中文版习题翻译:
在Bourne shell、Bourne-again shell和Korn shell中,digit1>&digit2表示将描述符digit1重定向至描述符digit2的同一文件,请说明下面两条命令的区别。
./a.out >outfile 2>&1
./a.out 2>&1 >outfile
a.out > outfile: 把a.out的标准输出重定向到文件outfile里面, > 为标准输出重定向符,默认重定向标准输出,即文件描述符1。
2>&1:把文件描述符2标准错误重定向到1对应的文件,相当于调用dup2(1, 2)
所以执行第一条命令的结果就是:

第一步:把1重定向到outfile,导致1指向outfile
第二步:把2重定向到1,所以2也指向outfile

第二条命令的执行结果是:

第一步:把2重定向到1对应的文件表,由于1初始状态是指向标准输出的,所以2也指向标准输出
第二步:把1重定向到outfile
验证程序如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

char sstdout[]="stdout";
char sstderr[]="stderr";

int main()
{
    write(1, sstdout, sizeof(sstdout)-1);
    write(2, sstderr, sizeof(sstderr)-1);
    printf("\n");
    return 0;
}

执行情况如下:

标准错误重定向到了标准输出,所以在终端中输出了stderr,标准输出重定向到了文件outfile.