linux shell重定向

来源:互联网 发布:python tf idf 编辑:程序博客网 时间:2024/06/10 17:39
脚本是:
      nohup /mnt/Nand3/H2000G  >/dev/null  2>&1  &
      对于& 1 更准确的说应该是文件描述符 1,而1 一般代表的就是STDOUT_FILENO,实际上这个操作就是一个dup2(2)调用.他标准输出到all_result ,然后复制标准输出到文件描述符2(STDERR_FILENO),其后果就是文件描述符1和2指向同一个文件表项,也可以说错误的输出被合并了.其中0表示键盘输入 1表示屏幕输出 2表示错误输出.把标准出错重定向到标准输出,然后扔到/DEV/NULL下面去。通俗的说,就是把所有标准输出和标准出错都扔到垃圾桶里面。
      command >out.file  2>&1 &
      command >out.file是将command的输出重定向到out.file文件,即输出内容不打印到屏幕上,而是输出到out.file文件中。2>&1 是将标准出错重定向到标准输出,这里的标准输出已经重定向到了out.file文件,即将标准出错也输出到out.file文件中。最后一个& , 是让该命令在后台执行。
       
      试想2>1代表什么,2与>结合代表错误重定向,而1则代表错误重定向到一个文件1,而不代表标准输出;
换成2>&1,&与1结合就代表标准输出了,就变成错误重定向到标准输出.

      你可以用
            ls 2>1测试一下,不会报没有2文件的错误,但会输出一个空的文件1;
            ls xxx 2>1测试,没有xxx这个文件的错误输出到了1中;
            ls xxx 2>&1测试,不会生成1这个文件了,不过错误跑到标准输出了;
            ls xxx >out.txt 2>&1, 实际上可换成 ls xxx 1>out.txt 2>&1;重定向符号>默认是1,错误和输出都传到out.txt了。
      为何2>&1要写在后面?
      command > file 2>&1 
       首先是command > file将标准输出重定向到file中, 2>&1 是标准错误拷贝了标准输出的行为,也就是同样被重定向到file中,最终结果就是标准输出和错误都被重定向到file中。 
      command 2>&1 >file 
      2>&1 标准错误拷贝了标准输出的行为,但此时标准输出还是在终端。>file 后输出才被重定向到file,但标准错误仍然保持在终端。

用strace可以看到: 
1. command > file 2>&1 
这个命令中实现重定向的关键系统调用序列是: 
open(file) == 3 
dup2(3,1) 
dup2(1,2) 

2. command 2>&1 >file 
这个命令中实现重定向的关键系统调用序列是: 
dup2(1,2) 
open(file) == 3 
dup2(3,1) 

      可以考虑一下不同的dup2()调用序列会产生怎样的文件共享结构。请参考APUE 3.10, 3.12 


在 shell 程式中,最常使用的 FD (file descriptor) 大概有三个, 分别是: 

0: Standard Input (STDIN) 

1: Standard Output (STDOUT) 

2: Standard Error Output (STDERR) 

在标准情况下, 这些FD分别跟如下设备关联: 

stdin(0): keyboard  键盘输入,并返回在前端 

stdout(1): monitor  正确返回值 输出到前端 

stderr(2): monitor 错误返回值 输出到前端 

举例说明吧:

当前目录只有一个文件 a.txt. 

[root@redhat box]# ls 

a.txt 

[root@redhat box]# ls a.txt b.txt          

ls: b.txt: No such file or directory     由于没有b.txt这个文件, 于是返回错误值, 这就是所谓的2输出 

a.txt     而这个就是所谓的1输出 

再接着看:

[root@redhat box]# ls a.txt b.txt  1>file.out 2>file.err 

执行后,没有任何返回值. 原因是, 返回值都重定向到相应的文件中了,而不再前端显示 

[root@redhat box]# cat file.out 

a.txt 

[root@redhat box]# cat file.err 

ls: b.txt: No such file or directory 

一般来说, "1>" 通常可以省略成 ">". 

即可以把如上命令写成: ls a.txt b.txt  >file.out 2>file.err 

有了这些认识才能理解 "1>&2" 和 "2>&1".

1>&2  正确返回值传递给2输出通道 &2表示2输出通道 

如果此处错写成 1>2, 就表示把1输出重定向到文件2中. 

2>&1 错误返回值传递给1输出通道, 同样&1表示1输出通道. 

举个例子. 

[root@redhat box]# ls a.txt b.txt 1>file.out 2>&1 

[root@redhat box]# cat file.out 

ls: b.txt: No such file or directory 

a.txt 

现在, 正确的输出和错误的输出都定向到了file.out这个文件中, 而不显示在前端. 

补充下, 输出不只1和2, 还有其他的类型, 这两种只是最常用和最基本的.

 

先看例子:

r2007@www r2007 $ (echo -n 123456;sleep 1;echo -n abc >&2;sleep 1;echo -n 789)>puzzle 2>puzzle  r2007@www r2007 $ cat puzzle  abc456789  r2007@www r2007 $ (echo -n 123456;sleep 1;echo -n abc >&2;sleep 1;echo -n 789)>puzzle 2>&1  r2007@www r2007 $ cat puzzle  123456abc789  


为了强调每个输出都是step by step,所以加了sleep命令,其实可以省略。(echo ....)等同于一个cmd命令,在这里用一组echo命令是为了能清晰的看到整个操作过程。 
第一种用法实际上同时打开2次puzzle文件。过程如下: 
>puzzle ---- 打开puzzle文件(打开文件的操作会在核心中产生一个数据结构-假设叫做foo结构,其中有很多参数,比如file position-以下简称fp,就是其中之一),然后fd1(标准输出)保存着这个指针(具体结构没做深入分析,姑且简化为保存了一个指针),总而言之,通过fd1可以引用到这个核心中的数据结构。 
2>puzzle --- 基本同上,再次打开这个文件,核心中会产生一个新的数据结构,同时fd2(标准错误输出)保存了这个结构的指针。 
一开始,这两个foo结构中的fp都是0,第一个echo在puzzle文件写入了123456,同时fd1所指向的foo结构中的fp变为6,然后第二个echo要在puzzle文件写入abc,但是它得到的fp是fd2所指向的foo结构中的fp,所以仍然从文件头开始写,所以puzzle中的内容变为abc456,第三个echo就不再罗嗦一遍了,它是从6这个位置开始写操作的。

为什么cmd >file 2>&1这种模式就不会发生混乱呢? 
就是因为2>&1,不是再打开一次文件,而是fd2照抄fd1,这两个fd共用一个foo结构,所以它们使用的fp也是同一个。 

以下例子可以加深理解这个道理: 
(echo -n 123;sleep 1;echo -n abcde >&2;sleep 1;echo -n 789) >puzzle 2>puzzle  结果:abc789



 

 (echo -n 123;sleep 1;echo -n abcdeghij >&2;sleep 1;echo -n 789) >puzzle 2>puzzle  结果:abc789hij



对于编程我是个外行,其中如有错误的概念,欢迎指正。

cat x y 1> hold 2>&1

结果就是将标准+错误输出到hold;

cat x y 2>&1 1> hold
则是将错误输出重定向到标准输出,而将标准定向到hold。
所以错误输出不会进入hold,因为被定向到标准输出。

赋值关系 (1) 1 = hold , 2 = 1;
         (2) 2 = 1 , 1 = hold。
明白了?呵呵

为何2>&1要写在后面? 
      command > file 2>&1 
       首先是command > file将标准输出重定向到file中, 2>&1 是标准错误拷贝了标准输出的行为,也就是同样被重定向到file中,最终结果就是标准输出和错误都被重定向到file中。 
      command 2>&1 >file 
      2>&1 标准错误拷贝了标准输出的行为,但此时标准输出还是在终端。>file 后输出才被重定向到file,但标准错误仍然保持在终端。

用strace可以看到: 
1. command > file 2>&1 
这个命令中实现重定向的关键系统调用序列是: 
open(file) == 3 
dup2(3,1) 
dup2(1,2)

2. command 2>&1 >file 
这个命令中实现重定向的关键系统调用序列是: 
dup2(1,2) 

open(file) == 3 
dup2(3,1)