我好像搞不懂这里发生了什么。我有4个版本的相同代码,唯一的区别是代码块/代码行的顺序。我最初的期望是重定向顺序不会产生任何影响,但它似乎不正确。我还假设>()具有一些屏蔽文件描述符的属性,但是没有。。。
请不要问我用它做什么,我也不需要其他的解决方案,我想了解这段代码。或者我对过程替代的理解将永远被打破。。。
元代码:
1_cmd_producing_both_stdout_and_stderr
|
+-stdout-> 2_cmd_producing_both_stdout_and_stderr
| |
| +-stdout-> A_awk_writing_stdout_to_file_producing_stderr
| |
| +-stderr-> B_awk_writing_stdout_to_file_producing_stderr
|
+-stdout-> 3_cmd_producing_both_stdout_and_stderr
|
+-stdout-> C_awk_writing_stdout_to_file_producing_stderr
|
+-stderr-> D_awk_writing_stdout_to_file_producing_stderr
版本1:
1 2 A B 3 C D
版本2:
1 2 B A 3 D C
版本3:
13天C 2 B A
版本4:
1 3 C D 2 A B
注:
我试过了
2甲B
和
2b A,同样,它们产生一致的输出,类似于版本1。
锥度:
GNU Awk 4.1.1,API:1.1(GNU MPFR 3.1.2-p3,GNU MP 6.0.0)
猛击:
GNU bash,版本4.3.30(1)-发行版(x86_64-pc-linux-GNU)
版本1,这将产生我期望的输出:
( echo log; echo err 1>&2; ) \
1> >( ( echo -n '1.'; cat; echo '1.ERR' 1>&2 ; ) \
1> >( awk 'BEGIN { print "error 1" >"/dev/stderr" } { print $0 }' >out.out ) \
2> >( awk 'BEGIN { print "error 2" >"/dev/stderr" } { print $0 }' >out.err )
) \
2> >( ( echo -n '2.'; cat; echo '2.ERR' 1>&2 ; ) \
1> >( awk 'BEGIN { print "error 3" >"/dev/stderr" } { print $0 }' >err.out ) \
2> >( awk 'BEGIN { print "error 4" >"/dev/stderr" } { print $0 }' >err.err )
)
文件内容:
out.out 1.log
out.err 1.ERR
err.out 2.err
err.err 2.ERR
输出:
error 4
error 2
error 1
error 3
版本2:
注:与第1版相比,第1版与第2版、第3版与第4版之间的第2级缩进线是交换的。
( echo log; echo err 1>&2; ) \
1> >( ( echo -n '1.'; cat; echo '1.ERR' 1>&2 ; ) \
2> >( awk 'BEGIN { print "error 1" >"/dev/stderr" } { print $0 }' >out.err ) \
1> >( awk 'BEGIN { print "error 2" >"/dev/stderr" } { print $0 }' >out.out )
) \
2> >( ( echo -n '2.'; cat; echo '2.ERR' 1>&2 ; ) \
2> >( awk 'BEGIN { print "error 3" >"/dev/stderr" } { print $0 }' >err.err ) \
1> >( awk 'BEGIN { print "error 4" >"/dev/stderr" } { print $0 }' >err.out )
)
文件内容:
(!) out.err error 2\n1.ERR
out.out 1.log
(!) err.err 2.ERR\nerror 4
err.out 2.err
输出:
error 3
error 1
版本3:
注意:与版本2相比,第一级缩进的代码块是交换的。
( echo log; echo err 1>&2; ) \
2> >( ( echo -n '2.'; cat; echo '2.ERR' 1>&2 ; ) \
2> >( awk 'BEGIN { print "error 1" >"/dev/stderr" } { print $0 }' >err.err ) \
1> >( awk 'BEGIN { print "error 2" >"/dev/stderr" } { print $0 }' >err.out )
) \
1> >( ( echo -n '1.'; cat; echo '1.ERR' 1>&2 ; ) \
2> >( awk 'BEGIN { print "error 3" >"/dev/stderr" } { print $0 }' >out.err ) \
1> >( awk 'BEGIN { print "error 4" >"/dev/stderr" } { print $0 }' >out.out )
)
文件内容:
(!) err.err error 2\n2.ERR
(!) err.out 2.err\nerror 3
(!) out.err 1.ERR\nerror 4
out.out 1.log
输出:
error 1
(!)
版本4:
注:与第3版相比,第1版与第2版、第3版与第4版之间的第2级缩进线是交换的。
( echo log; echo err 1>&2; ) \
2> >( ( echo -n '2.'; cat; echo '2.ERR' 1>&2 ; ) \
1> >( awk 'BEGIN { print "error 1" >"/dev/stderr" } { print $0 }' >err.out ) \
2> >( awk 'BEGIN { print "error 2" >"/dev/stderr" } { print $0 }' >err.err )
) \
1> >( ( echo -n '1.'; cat; echo '1.ERR' 1>&2 ; ) \
1> >( awk 'BEGIN { print "error 3" >"/dev/stderr" } { print $0 }' >out.out ) \
2> >( awk 'BEGIN { print "error 4" >"/dev/stderr" } { print $0 }' >out.err )
)
文件内容:
(!) err.out 2.err\nerror 4\nerror 3
err.err 2.ERR
out.out 1.log
out.err 1.ERR
输出:
error 2
error 1
(!)
版本2,3,4发生了什么??
最佳答案
您认为输出重定向的顺序无关紧要的假设是不正确的。秩序很重要。让我们考虑一下代码示例2中的字符串“error 2”,看看为什么它会被写入文件out.err
。代码是:
( echo log; echo err 1>&2; ) \
1> >( ( echo -n '1.'; cat; echo '1.ERR' 1>&2 ; ) \
2> >( awk 'BEGIN { print "error 1" >"/dev/stderr" } { print $0 }' >out.err ) \
1> >( awk 'BEGIN { print "error 2" >"/dev/stderr" } { print $0 }' >out.out )
) \
2> >( ( echo -n '2.'; cat; echo '2.ERR' 1>&2 ; ) \
2> >( awk 'BEGIN { print "error 3" >"/dev/stderr" } { print $0 }' >err.err ) \
1> >( awk 'BEGIN { print "error 4" >"/dev/stderr" } { print $0 }' >err.out )
)
字符串“error 2”由进程B写入其stderr。由于shell解析以启动进程B的字符串不包含对stderr的重定向,因此进程B从其父进程继承其stderr。它的父级是您标记为
2
的子shell。该流程有两个重定向,每个重定向到子流程。在进程B启动时,进程2的stderr被定向到进程A,因此这是进程B将写入字符串的位置。进程A读取字符串并将其写入stdout,即文件out.err
。如果与重定向的顺序相反,那么process2
的stderr尚未被重定向,因此processB
的stderr将与发起进程的stderr相同(例如,您的tty)关于bash - 用一点awk了解bash中的嵌套过程替换,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45002425/