Shell 管道及执行顺序分析

2019-09-23 09:50:52刘景俊


2>&1说明:2>&1 也就是 FD2=FD1 ,这里并不是说FD2 的值 等于FD1的值,因为 > 是改变送出的数据信道,通俗的说是:把stderr并到stdout。
但使用类似 cmd 1>&3 这样的形式时,原理相同,但往往不同于 2>&1 和 1>&2 通常用来合并的作用。

注意:普通cmd命令的cmd n>&n 和exec n>&n 是有区别的。

exec 0 exec 1>outfilename # 打开文件outfilename作为stdout
exec 2>errfilename # 打开文件 errfilename作为 stderr
exec 0<&- # 关闭 FD0
exec 1>&- # 关闭 FD1
exec 5>&- # 关闭 FD5

问:
如果关闭了 FD0、FD1、FD2,其后果是什么?
恢复 FD0、FD1、FD2与 关闭FD0、FD1、FD2 有什么区别?代码分别是什么?
打开了FD3~FD9,我们用完之后,你觉得是将他们关闭还是恢复?

下面是提示(例子来源于CU):
exec 6>&2 2>ver # FD2(本来往monitor送的) 定向到文件ver
command >>dev/null & #丢弃FD1(stdout)
exec 2>&6 # 恢复 FD2

4、简单举例(其中 yes.txt存在,no.txt不存在)
a、stdout 和stderr 都通过管道送给egrep了:
(ls yes.txt 2>&1;ls no.txt 2>&1) 2>&1|egrep * >file
(ls yes.txt;ls no.txt) 2>&1|egrep * >file

###
这个例子就是让大家:理解 命令执行顺序 和 管道“|”
在命令执行前,先要进行重定向的处理,并将把 nested sub-shell 的stdout 接到 egrep 命令的 stdin。
nested sub-shell ,在 ( ) 中的两个命令可以看作一个命令。其 stdout(FD1) 通过 “|” 作为 egrep 的 stdin,再加上 2>&1 时,初始 stdout 和 stderr 都往管道 “|” 送。
###

b、没有任何东西通过管道送给egrep,全部送往monitor。
(ls yes.txt 2>&1;ls no.txt 2>&1) >&2|egrep * >file
虽然在()里面将 FD2转往FD1,但在()外,遇到 >&2 ,结果所有的都送到monitor。

5、中阶例子(其中 you 这个文件是存在的,no 和 wu 这两个文件不存在)
r2007兄的:http://bbs.chinaunix.net/forum/viewtopic.php?t=221848&show_type=new&sid=cf30398c911e0d2b16313c6922123f67

条件:stderr通过管道送给egrep,正确消息仍然送给monitor(不变)

exec 4>&1;(ls you no 2>&1 1>&4 4>&-;ls wu 2>&1 1>&4 4>&-)|egrep * >file;exec 4>&-
或者
exec 4>&1;(ls you no;ls wu) 2>&1 1>&4 4>&-|egrep * >file;exec 4>&-

r2007 兄在其贴已有详细说明,如果加两个条件:
(1)要求cmd1和cmd2并行运行;
(2)将cmd1的返回值赋给变量 ss。

则为:
exec 3>&1;exec 4>&1
ss=$(((ls you no 2>&1 1>&3 3>&-;echo $? >&4)|egrep * >file) 4>&1)
exec 3>&-;exec 4>&-

说明:
exec 3>&1;4>&1
### 建立FD3,是用来将下面ls那条语句(子shell)中的FD1 恢复到正常FD1,即输出到monitor,你可以把FD3看作最初始的FD1的硬盘备份(即输出到monitor);