我在读本文档其中给出了以下有关重定向和文件描述符的示例。
ls > dirlist 2>&1
将把标准输出和标准错误定向到文件目录列表,而命令
ls 2>&1 > dirlist
只会将标准输出定向到 dirlist。这对于程序员来说是一个有用的选项。
这些例子是不是都是错误的?在我看来第二例如“将标准输出和标准错误定向到文件目录列表”,而第一的例如“仅将标准输出定向到目录列表”。
如果我错了(......可能......)有人可以清楚地解释这两个例子的逻辑吗?
答案1
首先,您需要了解n>&m
语法。这是一个复制操作,意味着将 m 复制到 n。查看部分“3.6.8 复制文件描述符”。
我在看这篇文章的时候也有和你一样的疑问。所以我可以尝试向你解释一下:
ls > dirlist 2>&1
使用上面的命令,首先将输出重定向到 dirlist by > dirlist
。 2>&1
表示将文件描述符1复制到2,换句话说,使fd2成为fd1的副本。现在fd1已经指向dirlist,使fd2成为fd1的副本意味着fd2也指向dirlist。结果是fd1->dirlist,fd2->dirlist。
ls 2>&1 > dirlist
这样,您首先将 fd2 制作为 fd1 的副本,而 fd1 仍然是终端,因此 fd2->terminal。然后将 fd1 重定向到 dirlist。结果是,fd2 -> 终端,fd1->dirlist。
答案2
方向是从左到右处理的。
ls > dirlist 2>&1
使 shell 最终将自身变成 ls,执行以下系统调用(为简洁起见,省略错误检查)。
/* Handle > dirlist */
int temp_fd = open("dirlist",O_WR); /* Open dirlist for output */
dup2(temp_fd, 1); /* Make file descriptor 1 (stdout) point to dirlist */
close(temp_fd); /* Don't need this other file descriptor for dirlist */
/* Handle 2>&1 */
dup2(1,2); /* Make fd 2 be a copy of fd 1, which points to dirlist */
所以首先改变fd 1,然后改变fd 2。
相反 ls 2>&1 > dirlist 会
/* Handle 2>&1 */
dup2(1,2); /* Make fd 2 be a copy of fd 1, the original stdout */
/* Handle > dirlist */
int temp_fd = open("dirlist",O_WR); /* Open dirlist for output */
dup2(temp_fd, 1); /* Make file descriptor 1 (stdout) point to dirlist */
close(temp_fd); /* Don't need this other file descriptor for dirlist */
另一种看待它的方式就是将其视为作业。本来fd1=initial_stdout,那么
/* ls > dirlist 2>&1 */
fd1=to_dirlist
fd2=fd1 (i.e. to_dirlist)
/* ls 2>&1 > dirlist */
fd2=fd1 (i.e. initial_stdout)
fd1=to_dirlist.
或者你可以说copy by value
而不是copy by reference
。