曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 4280|回复: 0
打印 上一主题 下一主题

2>&1 前后位置不同分析

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2012-11-18 16:32:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在许多脚本中会看到 2>&1 的身影,它的意思是将标准错误(stderr)重定向到标准输出(stdin) 中去,其中 2 表示 stderr,&1 表示标准输入。那么为什么不直接写成 2>1 就好了呢?下面做个实验。如果我们将 2>&1 写成 2>1:
$ ls tmp.txt groad.net > file.txt 2>1
$ cat file.txt
tmp.txt
$ ls -l
total 24
-rw-rw-r-- 1 beyes beyes   55 Nov 15 23:15 1
$ cat 1
ls: cannot access groad.net: No such file or directory
在运行 ls 命令的目录下,tmp.txt 文件是存在的,而 groad.net 这个文件是不存在的,因此就会产生一个正确的列出结果和一个提示文件不存在的错误输出。需要注意的是,我们产生了一个名字为 '1' 的文本文件,而它里面正好存放着文件不存在的错误信息。因此,2>1 的意思是要将错误输出重定向到 '1' 这个文件,为了将名为 '1' 这个文件和标准输出区别开来,这里标准输出就写成 &1 这种形式。

了解了 2>&1 后,接着分析 2>&1 书写位置的不同会对命令执行结果有什么影响。

先如下运行:
$ ls tmp.txt groad.net > file.txt 2>&1
$ cat file.txt
ls: cannot access groad.net: No such file or directory
tmp.txt
由上面可见,命令执行成功的信息和文件不存在的错误信息都存储在了 file.txt 这个文件中了。然而,如果将 2>&1 这部分提前:
$ ls tmp.txt groad.net 2>&1 > file.txt
ls: cannot access groad.net: No such file or directory
$ cat tmp.txt
hello
由此可见,file.txt 中只有正确的信息,而错误信息则仍然从终端中输出来。

为什么前后会是这样的差别呢?我们可以用 strace 来观察(使用方法可参考《使用 strace 捕获重定向的执行》)。

对于 ls tmp.txt groad.net > myfile.txt 2>&1 命令,可以观察 strace 的输出,从中可以看到几处关键调用:
open("myfile.txt", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
dup2(3, 1)                        = 1
close(3)                          = 0
dup2(1, 2)                        = 2
第 1 条,打开 myfile.txt 后创建了对应的文件描述符。
第 2 条,dup2(3,1); 的作用就是 > myfile.txt 的实现(重定向符号实质上就是调用 dup2() 函数)。
第 3 条,在完毕了文件描述符的复制后,关闭不需要的文件描述符。
第 4 条,实现了 2>&1 的功能。

同样方法可以得到执行 ls tmp.txt groad.net 2>&1 > myfile.txt 命令时的关键调用语句:
dup2(1, 2)                        = 2
open("myfile.txt", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
dup2(3, 1)                        = 1
close(3)                          = 0
从上面可以看到,调用顺序较之前者有了不同。那么在最后操作:
write(2, "ls: ", 4)               = 4
write(2, "cannot access groad.net", 23) = 23
时,由于 '2' 已经被重定向到了 ‘1’, 所以这个错误信息是从 stdout 输出的。可能会有疑问,那底下 dup2(3,1); 不是又将 '3' 重定向到了 ‘1’ 么?那这样一来,'2' 被重定向到 '1' ,而 '1‘ 又被重定向 '3' ,那 '2' 中输出的信息不是也要写入 '3' 么?其实,说”重定向“ 这一术语,有时会给人以误解,让人印象中是以为这重定向就如同水流的变道一样,从 '2' 流到 '1' ,而 '1' 改道到 '3',而 ’2‘ 中的东西也流向 '3'。实际上,如 dup(1,2); 应该理解为,'2' 复制了 '1' 的属性,这样就不会认为”重定向“是一个流,而是将原本要倒到这个池子里的水,倒到另一个池子里。这样,就不会由于”重定向“这个术语而产生”流动“的疑惑。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-4-29 07:09 , Processed in 0.079509 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表