I can't seem to figure out, what happens here. I have 4 versions of the same code, the only difference is the order of the code-blocks/lines. My initial expectation was that the redirection order does not make any difference, but it does not seem to be correct. I have also assumed that the >() has some shielding properties from file-descriptor machinations, but no...
Please don't ask what am I using it for, nor do I need alternative solutions, I want to understand THIS piece of code. Or my belief in my understanding of process substitution will be broken forever...
Metacode:
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
Version 1: 1 2 A B 3 C D
Version 2: 1 2 B A 3 D C
Version 3: 1 3 D C 2 B A
Version 4: 1 3 C D 2 A B
NOTE:
I tried 2 A B and 2 B A, as well, they produce consistent outputs, similar to Version 1.
awk: GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.2-p3, GNU MP 6.0.0)
bash: GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Version 1, this produces the output I expect:
( 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 )
)
files contents:
out.out 1.log
out.err 1.ERR
err.out 2.err
err.err 2.ERR
output:
error 4
error 2
error 1
error 3
Version 2:
NOTE: The 1st with the 2nd, the 3rd with the 4th second level indented lines are exchanged, compared to Version 1.
( 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 )
)
file contents:
(!) out.err error 2\n1.ERR
out.out 1.log
(!) err.err 2.ERR\nerror 4
err.out 2.err
output:
error 3
error 1
Version 3:
NOTE: The first level indented code-blocks are exchanged, compared to Version 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 )
)
file contents:
(!) err.err error 2\n2.ERR
(!) err.out 2.err\nerror 3
(!) out.err 1.ERR\nerror 4
out.out 1.log
output:
error 1
(!)
Version 4:
NOTE: The 1st with the 2nd, the 3rd with the 4th second level indented lines are exchanged, compared to Version 3.
( 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 )
)
file contents:
(!) err.out 2.err\nerror 4\nerror 3
err.err 2.ERR
out.out 1.log
out.err 1.ERR
output:
error 2
error 1
(!)
What is happening in Version 2, 3, 4??