1

I'm running a script which automates snapraid for my NAS server. It's a script I found online and it was working without issue on Debian 9. I updated to Debian 10 last week and the script now hangs in places it wasn't on Debian 9. I think I've narrowed the issue down to the tee and wait commands.

I've shortened the script to the below snippet for testing and the issue is happening, this is why I think it's tee and wait.

#!/bin/bash

# location of the snapraid binary
SNAPRAID_BIN="/usr/local/bin/snapraid"

# redirect all output to screen and file
> $TMP_OUTPUT
exec 3>&1 4>&2
# NOTE: Not preferred format but valid: exec &> >(tee -ia "${TMP_OUTPUT}" )
exec > >(tee -a "${TMP_OUTPUT}") 2>&1

# run the snapraid DIFF command
echo "###SnapRAID DIFF [`date`]"
$SNAPRAID_BIN diff
# wait for the above cmd to finish
wait
echo
echo "DIFF finished [`date`]"

I ran htop also to see what was happening and the processes created from the snapraid commands just don't end.

wait is doing exactly what it should, wait, but why did this work before and not now?

Full script is here: https://pastebin.com/gJqnz875

sburke
  • 13
  • the difference between debian 9 and 10 is that in debian 9 the wait wasn't actually waiting for the tee to finish piping all the output; ie even then it wasn't working as its author imagined it. In the bash from debian 10 the wait works as "expected" and waits ... forever ;-) –  Jul 16 '19 at 15:12

1 Answers1

4

The tee inside the process substitution will not exit until it gets an eof on its stdin or some error happens.

And, since its stdin is a pipe, it will only get an EOF on its stdin when all the handles to its writing end are closed.

So, you'll have to save the original stdout and stderr, and then, before the wait, redirect them to the originals; dup'ing fds via the new>&old cause the old fd to be closed.

exec {out}>&1 {err}>&2
exec > >(tee -a output) 2>&1
...
exec >&$out 2>&$err
wait $(pgrep -P "$$")

Also, only in newer versions of bash wait also waits for processes running in a > >(...) process substitution; that's why I used wait $(pgrep -P "$$") instead of simply wait (pgrep -P finds processes by their parent). Also see here for this and other pitfalls related to > >(...).

  • Thank you for the explanation. It definitely makes sense now. It was driving me crazy. I should be able to get it running now :) – sburke Jul 17 '19 at 09:43