我好像搞不懂这里发生了什么。我有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/

10-13 09:20