Featured post
Bash process substitution and syncing -
(possibly related do programs not accept process substitution input files?)
in bash unit test scripts i'm using following trick log and display stdout , stderr of command:
command > >(tee "${stdoutf}") 2> >(tee "${stderrf}" >&2)
this process produces output stdout, $stdoutf
file gets data. run command not output data:
diff -r "$source" "$target" > >(tee "${stdoutf}") 2> >(tee "${stderrf}" >&2)
however, doesn't process finishes before test emptiness run (using shunit-ng):
assertnull 'unexpected output stdout' "$(<"$stdoutf")"
in 100 run test failed 25 times.
should sufficient call sync
before testing file emptiness:
sync assertnull 'unexpected output stdout' "$(<"$stdoutf")"
... and/or should work forcing sequence of commands:
diff -r "$source" "$target" \ > >(tee "${stdoutf}"; assertnull 'unexpected output stdout' "$(<"$stdoutf")") 2> >(tee "${stderrf}" >&2)
... and/or possible tee
somehow assertnull
directly instead of file?
update: sync
not answer - see gilles' response below.
update 2: discussion taken further save stdout, stderr , stdout+stderr synchronously. answers!
in bash, process substitution substitution command foo > >(bar)
finishes foo
finishes. (this not discussed in documentation.) can check with
: > >(sleep 1; echo a)
this command returns immediately, prints a
asynchronously 1 second later.
in case, tee
command takes 1 little bit of time finish after command
completes. adding sync
gave tee
enough time complete, doesn't remove race condition, more adding sleep
would, makes race more unlikely manifest.
more generally, sync
not have internally observable effect: makes difference if want access device filesystems stored under different operating system instance. in clearer terms, if system loses power, data written before last sync
guaranteed available after reboot.
as removing race condition, here few of possible approaches:
explicitly synchronize substituted processes.
mkfifo sync.pipe command > >(tee -- "$stdoutf"; echo >sync.pipe) 2> >(tee -- "$stderrf"; echo >sync.pipe) read line < sync.pipe; read line < sync.pipe
use different temporary file name each command instead of reusing
$stdoutf
,$stderrf
, , enforce temporary file newly created.give on process substitution , use pipes instead.
{ { command | tee -- "$stdoutf" 1>&3; } 2>&1 \ | tee -- "$stderrf" 1>&2; } 3>&1
if need command's return status, bash puts in
${pipestatus[0]}
.{ { command | tee -- "$stdoutf" 1>&3; exit ${pipestatus[0]}; } 2>&1 \ | tee -- "$stderrf" 1>&2; } 3>&1 if [ ${pipestatus[0]} -ne 0 ]; echo command failed; fi
- Get link
- X
- Other Apps
Comments
Post a Comment