Shell 中 &>/dev/null 和 >/dev/null 2>&1
下面,咱们一起来看看这个命令操作涉及到的知识点,这其实涉及到三部分的内容,如下图:
1. 文件描述符
《linux shell脚本攻略》的描述:
文件描述符是与文件输入、输出关联的整数。它们用来跟踪已打开的文件。最常见的文件描述符是 stidin、stdout、和stderr。我们可以将某个文件描述符的内容重定向到另外一个文件描述符中。
文件描述符我们常见的就是系统预留的0,1和2这三个,他们的意义分别有如下对应关系:
- 0 —— stdin(标准输入)
- 1 —— stdout (标准输出)
- 2 —— stderr (标准错误)
其中,shell 编程里经常用到的就是描述符1和描述符2。这样下面我们来举两个栗子,就知道神马是1和2了:
1 —— stdout
假设:在当前目录下我们有且只有一个文件名为 123.txt 的文本文件。这个时候我们运行下面的命令【ls 123.txt】:
我们就会获得一个标准输出 stdout 的输出结果“123.txt” 。
2 —— stderr
按照上面同样的假设,我们运行另外一跳命令【ls abc.txt】:
我们就会获得一个标准错误 stderr 的输出结果 “ls:无法访问abc.txt:没有那个文件或目录”。
有同学应该会觉得,这两个事例好像跟1和2这两个阿拉伯数字好像没有关系。这个就要结合第二个知识点“重定向操作”来理解了。
2. 重定向操作
重定向操作,其实就是通过在 shell 命令后面追加一个重定向操作符号,将 shell 命令对应的文件描述符输出的文本信息重新输入到另外一个指定文件的操作。
重定向操作符号有两个>和>>。尽管这两个操作符都可以将重定向到文件,但是前者会先清空文件,再写入内容;后者会将内容追加到现有文件的尾部。(对了,重定向的操作制定的文件如果原来不存在的话,重定向的操作会主动创建这个文件名的文件的)
下面我们结合第1个知识点文件描述符来举栗子吧。
A. 重定向标准输出 stdout:
如上图所示,对比没有添加重定向的操作,ls 命令在使用之后并没有将字符 “123.txt” 这个字符串打印到屏幕上。在紧接着的 cat 操作之后,我们可以看到本来应该输出字符串被记录在了 stdout.txt 这个文件里面了。
其实,对于标准输出的重定向操作,>等同于1>。上面栗子执行命令【ls 123.txt > stdout.txt】得到的效果也是一样的。
B. 重定向标准错误 stderr
如上图所示,文件描述符2,标准错误的重定向也是同样的原理被记录在了文件 stderr.txt 这个文件里面了。
描述符的重定向还有下面的几种用法:
你可以将 stderr 单独定向到一个文件,将 stdout 重定向到另一个文件:
cmd 2> stderr.txt 1> stdout.txt
也可以利用下面的方法,将 stderr 转换成 stdout,使得 stderr 和 stdout 都被重新定向到同一个文件中:
cmd > output.txt 2>&1
或者采用这个方法:
cmd &> output.txt
cmd >& output.txt # 两个表达式效果一样哒~
3. linux特殊文件
《linux shell脚本攻略》描述:
/dev/null 是一个特殊的设备文件,这个文件接收到的任何数据都会被丢弃。因此,null 这个设备通常也被成为位桶(bitbucket)或黑洞。
简单地理解就是,重定向操作给这个 /dev/null 文件的所有东西都会被丢弃。
因为这些文件描述符输出的字符串,总是会显示出来的。如果我们在 shell 编程的时候,操作到某一条命令的返回结果,我们不想要,这个时候又不想让这个输出结果打印到屏幕上,我们就可以重定向到 /dev/null 这个文件,由 /dev/null 这个文件负责处理后事。
这个丢弃的结果又不能粗暴的认为是删除错误输出,这个操作是一个丢弃重定向输入输出的操作。
形象地理解就是,ATM机打印的纸质流水账单(stdout和stderr),本来应该你来保存处理的,但是你又没有用,放在手里(打印屏幕)又碍事,所以账单从你的手里重新被丢到了垃圾桶(/dev/null)了。但是,垃圾桶的垃圾是怎么处理的你是不知道的。
实例:
让一个变量获得命令输出的结果,是下面这样的处理:
i=$(ls 123.txt)
这样,i 就能获得命令【ls 123.txt】输出的标准输出。错误提示(标准错误)依然会打印到屏幕上显示。
针对答主的问题,应该是如下操作:
i=$(ls 123.txt 2> /dev/null)
这样的命令,ls 命令如果出现了错误提示,就会被重定向到 /dev/null 垃圾桶去了。所以,屏幕上不会打印任何输出关于错误的提示字符。在这个命令的操作中,i 获得文件 stdout 标准输出,也就是文件述符1的屏幕输出结果 “123.txt”。
如果,这个123.txt 文件不存在,i 就肯定什么都拿不到,因为错误提示被 /dev/null 吃了,被重定向丢弃了屏幕也不显示错误提示。所以,i 就是个什么都没有的空变量。基本就是如下效果一样:
i=''