2>&1 的用法说明

command>/dev/null 2>&1command>/dev/null等命令,/dev/null表示一个空设备,就是说吧command的执行结果重定向到空设备中,说白了就是不显示任何信息。那么2>&1又是什么含义?

几个基本符号及其含义

1 . command>/dev/null

其实这条命令是一个缩写版,对于一个重定向命令,肯定是a > b这种形式,那么command > /dev/null难道是command充当a的角色,/dev/null充当b的角色。这样看起来比较合理,其实一条命令肯定是充当不了a,肯定是command执行产生的输出来充当a,其实就是标准输出stdout。所以command > /dev/null相当于执行了command 1 > /dev/null。执行command产生了标准输出stdout(用1表示),重定向到/dev/null的设备文件中。

2 . 2>&1

通过上面command > /dev/null等价于command 1 > /dev/null,那么对于2>&1也就好理解了,2就是标准错误,1是标准输出,那么这条命令不就是相当于把标准错误重定向到标准输出么。等等是&1而不是1,这里&是什么?这里&相当于等效于标准输出。这里有点不好理解,先看下面。

3 . command>a 2>a 与 command>a 2>&1的区别

通过上面的分析,对于command>a 2>&1这条命令,等价于command 1>a 2>&1可以理解为执行command产生的标准输入重定向到文件a中,标准错误也重定向到文件a中。那么是否就说command 1>a 2>&1等价于command 1>a 2>a呢。其实不是,command 1>a 2>&1command 1>a 2>a还是有区别的,区别就在于前者只打开一次文件a,后者会打开文件两次,并导致stdout被stderr覆盖。&1的含义就可以理解为用标准输出的引用,引用的就是重定向标准输出产生打开的a。从IO效率上来讲,command 1>a 2>&1command 1>a 2>a的效率更高。

体验一下

思考一下

为何2>&1要写在command>1的后面,直接用2可以么。比如ls 2>a。其实这种用法也是可以的,ls命令列出当前的目录,用stdout(1)表示,由于这个时候没有stderr(2),这个时候执行ls 2>a也会正常产生一个a的文件,但是a的文件中是空的,因为这时候执行ls并没有产生stderr(2)。

输出重定向:

格式:

command-line1 [1-n] > file或文件操作符或设备

意思是:将一条命令执行结果(标准输出,或者错误输出,本来都要打印到屏幕上面的) 重定向其它输出设备(文件,打开文件操作符,或打印机等等)1,2分别是标准输出,错误输出。

实例:

显示当前目录文件 test.sh test1.sh test1.sh实际不存在

[root@cicada-nightly-bochs ~]#ls test.sh test1.sh
    ls: test1.sh: 没有这个文件和目录
    test.sh

正确输出与错误输出都显示在屏幕了,现在需要把正确输出写入suc.txt

1>可以省略,不写,默认所至标准输出

[root@cicada-nightly-bochs ~]# ls test.sh test1.sh 1>suc.txt
    ls: test1.sh: 没有这个文件和目录
[root@cicada-nightly-bochs ~]# cat suc.txt 
    test.sh

把错误输出,不输出到屏幕,输出到err.txt

[root@cicada-nightly-bochs ~]# ls test.sh test1.sh 1>suc.txt 2>err.txt
[root@cicada-nightly-bochs ~]# cat suc.txt err.txt 
    test.sh
    ls: test1.sh: 没有这个文件和目录

继续追加把输出写入suc.txt err.txt “»”追加操作符

[root@cicada-nightly-bochs ~]# ls test.sh test1.sh 1>>suc.txt 2>>err.txt 

将错误输出信息关闭掉

[root@cicada-nightly-bochs ~]# ls test.sh test1.sh 2>&-
    test.sh
[root@cicada-nightly-bochs ~]# ls test.sh test1.sh 2>/dev/null
    test.sh

&[n] 代表是已经存在的文件描述符,&1 代表输出 &2代表错误输出 &-代表关闭与它绑定的描述符 /dev/null 这个设备,是linux 中黑洞设备,什么信息只要输出给这个设备,都会给吃掉

关闭所有输出

[root@cicada-nightly-bochs ~]# ls test.sh test1.sh  1>&- 2>&- 

关闭 1,2 文件描述符

[root@cicada-nightly-bochs ~]# ls test.sh test1.sh  2>/dev/null 1>/dev/null

将1,2 输出转发给/dev/null设备

[root@cicada-nightly-bochs ~]# ls test.sh test1.sh >/dev/null 2>&1

将错误输出2 绑定给 正确输出 1,然后将 正确输出 发送给 /dev/null设备 这种常用

[root@cicada-nightly-bochs ~]# ls test.sh test1.sh &>/dev/null

& 代表标准输出 ,错误输出 将所有标准输出与错误输出 输入到/dev/null文件

注意:

输入重定向

格式:

command-line [n] <file或文件描述符&设备

命令默认从键盘获得的输入,改成从文件,或者其它打开文件以及设备输入。执行这个命令,将标准输入0,与文件或设备绑定。将由它进行输入。

实例:

[root@cicada-nightly-bochs ~]# cat > catfile 
    testing 
    cat file test

这里按下 [ctrl]+d 离开 从标准输入【键盘】获得数据,然后输出给catfile文件

cat 从test.sh 获得输入数据,然后输出给文件catfile

[root@cicada-nightly-bochs ~]# cat>catfile <test.sh

« 这个连续两个小符号, 他代表的是『结束的输入字符』的意思。这样当空行输入eof字符,输入自动结束,不用ctrl+D

[root@cicada-nightly-bochs ~]# cat>catfile <<eof
test a file
test!
eof

Linux Bash中三个小于号 < < < 是什么意思

 < < < 就是将后面的内容作为前面命令的标准输入
while read line;do
    grep "Holder" <<< $line
    [[ $? -eq 0 ]] && rm $line  #如果grep成功则删除文件
done <<EOF
`ls`
EOF

exec绑定重定向

格式:

exec 文件描述符[n] <或> file或文件描述符或设备

在上面讲的输入,输出重定向 将输入,输出绑定文件或设备后。只对当前那条指令是有效的。如果需要在绑定之后,接下来的所有命令都支持的话。就需要用exec命令

实例:

将标准输出与fd 6绑定

[root@cicada-nightly-bochs ~]# exec 6>&1

出现文件描述符6

[root@cicada-nightly-bochs ~]# ls  /proc/self/fd/ 
    0  1  2  3  6

将接下来所有命令标准输出,绑定到suc.txt文件(输出到该文件)

[root@cicada-nightly-bochs ~]# exec 1>suc.txt

执行命令,发现什么都不返回了,因为标准输出已经输出到suc.txt文件了

[root@cicada-nightly-bochs ~]# ls -al

恢复标准输出

[root@cicada-nightly-bochs ~]# exec 1>&6

关闭fd 6描述符

[root@cicada-nightly-bochs ~]# exec 6>&-

[root@cicada-nightly-bochs ~]# ls /proc/self/fd/
    0  1  2  3

说明:使用前先将标准输入保存到文件描述符6,这里说明下,文件描述符默认会打开0,1,2 还可以使用自定义描述符 。然后对标准输出绑定到文件,接下来所有输出都会发生到文件。 使用完后,恢复标准的输出,关闭打开文件描述符6。

有趣事情:

可能有朋友会这样用:exec 1>suc.txt ,接下来所有输出都绑定到suc.txt 文件,那么怎么样恢复原来的呢? 试试你就会发现问题所在……

复杂一点实例

打开test.sh可读写操作,与文件描述符3绑定

exec 3<>test.sh;

循环读取文件描述符3(读取的是test.sh内容)

while read line<&3
 do
    echo $line;
done

关闭文件的,输入,输出绑定

exec 3>&-
exec 3<&-

其实,总结一下,重定向应用通常就以下两点:

1、重新设置命令的默认输入,输出,指向到自己文件(文件,文件描述符,设备其实都是文件,因为linux就是基于设备也是文件,描述符也指向是文件,哈哈)

2、扩展自己新的描述符,对文件进行读写操作