分析shell命令中 >/dev/null 2>&1的语法实现原理
shell中可能经常能看到:>/dev/null 2>&1
命令的结果可以通过%>的形式来定义输出
分解这个组合:“>/dev/null 2>&1” 为五部分。
1:> 代表重定向到哪里,例如:echo "123" > /home/123.txt
2:/dev/null 代表空设备文件
3:2> 表示stderr标准错误
4:& 表示等同于的意思,2>&1,表示2的输出重定向等同于1
5:1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 "1>/dev/null"
因此,>/dev/null 2>&1也可以写成“1> /dev/null 2> &1”
那么本文标题的语句执行过程为:
1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,说白了就是不显示任何信息。
2>&1 :接着,标准错误输出重定向 到 标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。
说清楚了吗,大家理解下吧!
顺便对比述说下这么用的好处!
最常用的方式有:
command > file 2>file 与command > file 2>&1
它们 有什么不同的地方吗?
首先command > file 2>file 的意思是将命令所产生的标准输出信息,和错误的输出信息送到file 中.command > file 2>file 这样的写法,stdout和stderr都直接送到file中, file会被打开两次,这样stdout和stderr会互相覆盖,这样写相当使用了FD1和FD2两个同时去抢占file 的管道。
而command >file 2>&1 这条命令就将stdout直接送向file, stderr 继承了FD1管道后,再被送往file,此时,file 只被打开了一次,也只使用了一个管道FD1,它包括了stdout和stderr的内容。
从IO效率上,前一条命令的效率要比后面一条的命令效率要低,所以在编写shell脚本的时候,较多的时候我们会command > file 2>&1 这样的写法。
命令的结果可以通过%>的形式来定义输出
分解这个组合:“>/dev/null 2>&1” 为五部分。
1:> 代表重定向到哪里,例如:echo "123" > /home/123.txt
2:/dev/null 代表空设备文件
3:2> 表示stderr标准错误
4:& 表示等同于的意思,2>&1,表示2的输出重定向等同于1
5:1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 "1>/dev/null"
因此,>/dev/null 2>&1也可以写成“1> /dev/null 2> &1”
那么本文标题的语句执行过程为:
1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,说白了就是不显示任何信息。
2>&1 :接着,标准错误输出重定向 到 标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。
说清楚了吗,大家理解下吧!
顺便对比述说下这么用的好处!
最常用的方式有:
command > file 2>file 与command > file 2>&1
它们 有什么不同的地方吗?
首先command > file 2>file 的意思是将命令所产生的标准输出信息,和错误的输出信息送到file 中.command > file 2>file 这样的写法,stdout和stderr都直接送到file中, file会被打开两次,这样stdout和stderr会互相覆盖,这样写相当使用了FD1和FD2两个同时去抢占file 的管道。
而command >file 2>&1 这条命令就将stdout直接送向file, stderr 继承了FD1管道后,再被送往file,此时,file 只被打开了一次,也只使用了一个管道FD1,它包括了stdout和stderr的内容。
从IO效率上,前一条命令的效率要比后面一条的命令效率要低,所以在编写shell脚本的时候,较多的时候我们会command > file 2>&1 这样的写法。
举例验证之。。。。
在glibc库的stdio.h头文件中
#define stdin (&__sF[0]) #define stdout (&__sF[1]) #define stderr (&__sF[2]) 比如 fprintf(stderr, "gliethttp\n");那么将把"gliethttp"作为标准错误输出 在shell命令中,0,1和2分别对应glibc中的stdin,stdout和stderr 0 对应stdin 即标准输入 1 对应stdout 即标准输出 2 对应stderr 即标准错误输出 所以>/dev/null表示将程序通过printf或者fprintf打印到handle为1的stdout文件的信息,送到/dev/null空洞文件,/dev/null节点对应的kernel实现就是直接返回写入的字节数,所以程序认为成功存储到/dev/null了[luther.gliethttp]. 但是>/dev/null这个操作不能将fprintf(stderr, "luther.gliethttp\n")打印到stderr上的字符串送到>/dev/null下,所以必须使用 2>&1命令,表示shell将送到2 stderr中的数据转送到1 stdout中,所以这样stderr中会显示到terminal上的信息也将被转送到/dev/null下了. 看个实例: luther@gliethttp:~$ cat a.c #include <stdio.h> int main(int argc, char *argv[]) { fprintf(stdout,"luther stdout\n"); fprintf(stderr,"luther stderr\n"); return 0; } luther@gliethttp:~$ gcc a.c luther@gliethttp:~$ ./a.out luther stdout luther stderr luther@gliethttp:~$ ./a.out >/dev/null luther stderr //可以看到>/dev/null操作并不会将stderr信息送到/dev/null下 写一个test.sh脚本 luther@gliethttp:~$ chmod +x test.sh luther@gliethttp:~$ cat test.sh exec ./a.out >/dev/null luther@gliethttp:~$ ./test.sh luther stderr //可以看到shell也不会将stderr信息送到/dev/null下 luther@gliethttp:~$ cat test.sh exec ./a.out >/dev/null 2>&1 luther@gliethttp:~$ ./test.sh luther@gliethttp:~$ //什么也没有输出,stderr信息被2>&1命令成功变为stdout信息,进而送入了/dev/null淹没 luther@gliethttp:~$ cat test.sh exec ./a.out >/dev/null 1>&2 ./test.sh luther stdout luther stderr luther@gliethttp:~$ 当然对于tee操作也同样存在如上问题,如果打印到stderr的log将不能被tee操作捕获,所以可以将stderr重定向到stdout来解决这个问题, 看看实例: luther@gliethttp:~$ ./a.out luther stdout luther stderr luther@gliethttp:~$ ./a.out|tee luther.txt luther stdout luther stderr luther@gliethttp:~$ cat luther.txt luther stdout luther@gliethttp:~$ ./a.out 2>&1|tee luther.txt luther stderr luther stdout luther@gliethttp:~$ cat luther.txt luther stderr luther stdout luther@gliethttp:~$ ./a.out 1>&2|tee luther.txt luther stderr luther stdout luther@gliethttp:~$ cat luther.txt luther@gliethttp:~$ //啥东西都没有,因为stdout被定向到stderr,所以所有log信息都不能被tee捕获 对于1>&2因为作为一个命令将被shell解析,所以放在哪里都可以,1>&2将影响到该组命令中所有的log输出,比如: luther@gliethttp:~$ 1>&2 ./a.out|tee luther.txt luther stderr luther stdout |