简述:
shell脚本中经常会出现在一个命令cmd后面跟着 >/dev/null 2>&1,本文详细理清一下shell重定向。
为什么需要重定向?
shell脚本在执行的过程中,会有一些系统打印,有的是标准输出,有的是错误输出,这里的错误输出不一定是指shell脚本有问题,而是系统打印的一些异常或者错误输出,不影响系统运行的。一般shell脚本都是相较复杂多指令的。这里有个问题,C语言程序中调用shell脚本,一般是用 system 来调用,这里就有一个问题,system执行过程中,shell脚本是否顺利执行完毕,要看执行期间有没有被异常信号中断,如果出现异常信号,system调用的shell则会终止。
这里我们需要做的就是去掉system调用的shell脚本中的异常输出,这里就需要shell重定向输出了。
shell重定向
当执行shell命令时,会默认打开3个文件,每个文件有对应的文件描述符来方便我们使用:
类型 | 文件描述符 | 默认情况 | 对应文件句柄位置 |
---|---|---|---|
标准输入(standard input) | 0 | 从键盘获得输入 | /proc/self/fd/0 |
标准输出(standard output) | 1 | 输出到屏幕(即控制台) | /proc/self/fd/1 |
错误输出(error output) | 2 | 输出到屏幕(即控制台) | /proc/self/fd/2 |
我们可以看下具体信息
root@LEDE:/proc/392/fd# ls -all dr-x------ 2 root root 0 Jul 23 10:36 . dr-xr-xr-x 8 root root 0 Jul 23 09:48 .. lr-x------ 1 root root 64 Jul 23 10:36 0 -> /dev/ttyS0 l-wx------ 1 root root 64 Jul 23 10:36 1 -> /dev/ttyS0 lrwx------ 1 root root 64 Jul 23 10:36 10 -> /dev/tty l-wx------ 1 root root 64 Jul 23 10:36 2 -> /dev/ttyS0
/dev/ttyS0对应的就是串行端口终端。
输出重定向
输出重定向的使用方式很简单,基本的一些命令如下:
命令 | 介绍 |
---|---|
command >filename | 把标准输出重定向到新文件中 |
command 1>filename | 同上 |
command >>filename | 把标准输出追加到文件中 |
command 1>>filename | 同上 |
command 2>filename | 把标准错误重定向到新文件中 |
command 2>>filename | 把标准错误追加到新文件中 |
我们使用>或者>>对输出进行重定向。符号的左边表示文件描述符, 如果没有的话表示1,也就是标准输出 ,符号的右边可以是一个文件,也可以是一个输出设备。当使用>时,会判断右边的文件存不存在,如果存在的话就先删除,然后创建一个新的文件,不存在的话则直接创建。但是当使用>>进行追加时,则不会删除原来已经存在的文件。
举例:
root@LEDE:/tmp# touch exist.txt root@LEDE:/tmp# ls exist.txt notexist.txt 1>out ls: notexist.txt: No such file or directory root@LEDE:/tmp# cat out exist.txt root@LEDE:/tmp# ls exist.txt notexist.txt 1>>out ls: notexist.txt: No such file or directory root@LEDE:/tmp# cat out exist.txt exist.txt root@LEDE:/tmp# ls exist.txt notexist.txt 2>err exist.txt root@LEDE:/tmp# cat err ls: notexist.txt: No such file or directory root@LEDE:/tmp# ls exist.txt notexist.txt >out 2>err root@LEDE:/tmp# cat out exist.txt root@LEDE:/tmp# cat err ls: notexist.txt: No such file or directory
输入重定向
对输入进行重定向的基本命令:
命令 | 介绍 |
---|---|
command <filename | 以filename文件作为标准输入 |
command 0<filename | 同上 |
command <<delimiter | 从标准输入中读入,直到遇到delimiter分隔符 |
我们使用<对输入做重定向时, 如果符号左边没有写值,那么默认就是0。
请用cat进行试验。
/dev/null
手抄一段《linux shell脚本攻略》描述:
/dev/null是一个特殊的设备文件,这个文件接收到的任何数据都会被丢弃。因此,null这个设备通常也被称为位桶(bit bucket)或黑洞。
简单地理解就是,重定向操作给这个/dev/null文件的所有东西都会被丢弃。
因为这些文件描述符输出的字符串,总是会显示出来的。如果我们在shell编程的时候,操作到某一条命令的返回结果,我们不想要这个时候又不想让这个输出结果打印到屏幕上,我们就可以重定向到/dev/null这个文件来,由/dev/null这个文件负责处理后事。
这个丢弃的结果又不能粗暴的认为是删除错误输出,这个操作是一个丢弃重定向输入输出的操作。
>filename 2>&1
1.2>&1,将错误输出绑定到标准输出上。由于此时的标准输出是默认值,也就是输出到屏幕,所以错误输出会输出到屏幕。
2.>filename, 将标准输出1重定向到filename中。
>/dev/null 2>&1 VS >/dev/null 2>/dev/null
首先command > file 2>file 的意思是将命令所产生的stdout标准输出信息和stderr错误的输出信息送到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效率上,command >file 2>&1命令的效率要比command > file 2>file的命令效率高,所以在编写shell脚本时,我们较多时间使用command > file 2>&1的写法。