2>&1 的用法说明
command>/dev/null 2>&1,command>/dev/null等命令,/dev/null表示一个空设备,就是说吧command的执行结果重定向到空设备中,说白了就是不显示任何信息。那么2>&1又是什么含义?
几个基本符号及其含义
- /dev/null 表示空设备文件
- 0 表示stdin标准输入
- 1 表示stdout标准输出
- 2 表示stderr标准错误
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>&1与command 1>a 2>a还是有区别的,区别就在于前者只打开一次文件a,后者会打开文件两次,并导致stdout被stderr覆盖。&1的含义就可以理解为用标准输出的引用,引用的就是重定向标准输出产生打开的a。从IO效率上来讲,command 1>a 2>&1比command 1>a 2>a的效率更高。
体验一下
-
这里会将stdout与stderr分别存放至find.out和find.err中
find /etc -name passwd #查找/etc目录下所有名字是passwd的文件【表示按名称查找】 find /etc -name passwd >find.out 2>find.err find /etc -name passwd 1>find.out 2>find.err 其实就是find /etc -name passwd的命令的执行结果输出正确的输出(stdout)被1接收,错误的信息(stderr)被2接收。 -
若要将所有的输出及错误信息都显示出来,可以用&表示全部1和2的信息,例如:
find /etc -name passwd &>find.all -
有时候希望将错误的信息重新定向到输出,就是将2的结果重定向至1中就有了”2>1”这样的思路,如果按照上面的写法,系统会默认将错误的信息(stderr)2重定向到一个名字为1的文件中,而非所想的(stdout)中。因此需要加&进行区分。就有了 2>&1 这样的用法,举例:
find /etc -name passwd 2>&1 |less -
有时候还能看到这样的用法
find /etc -name passwd &2>&1 |less 这里可以分解成 find /etc -name passwd & #表示前面的命令放到后台执行。 2>&1 |less #表示将错误信息重定向至标准输出,并用less进行分页显示。
思考一下
为何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文件
注意:
- 1、shell遇到”>”操作符,会判断右边文件是否存在,如果存在就先删除,并且创建新文件。不存在直接创建。 无论左边命令执行是否成功。右边文件都会变为空。
- 2、“»”操作符,判断右边文件,如果不存在,先创建。以添加方式打开文件,会分配一个文件描述符[不特别指定,默认为1,2]然后,与左边的标准输出(1)或错误输出(2) 绑定。
- 3、当命令:执行完,绑定文件的描述符也自动失效。0,1,2又会空闲。
- 4、一条命令启动,命令的输入,正确输出,错误输出,默认分别绑定0,1,2文件描述符。
- 5、一条命令在执行前,先会检查输出是否正确,如果输出设备错误,将不会进行命令执行
输入重定向
格式:
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、扩展自己新的描述符,对文件进行读写操作