4

I am trying to find a method to save the output of a command to variable but also print it in real time. I initially found an example with tee that seemed to work;

VARIABLE=$(./build.sh | tee /dev/tty)

However the problem with this is that if I run it on a system with virtual console (i.e. git hub actions) I get an error tee: /dev/tty: No such device or address. I just want to find a way to save output to a variable and do a normal print in real time (i.e. just like echo, printf, etc.)

2
  • 2
    What is wrong with printf '%s\n' "$VARIABLE" just after? Nov 7, 2022 at 22:44
  • I rather see it live, and I also have set set -e -o pipefail so if the build fails I will not get any outputs Nov 8, 2022 at 14:02

2 Answers 2

4

The problem with using /dev/tty is it assumes that stdout was originally attached to a tty - this is not necessarily so as demonstrated by GitHub Actions. It would also be a problem if you were redirecting stdout of the script elsewhere (a log file for instance).

What you want to pass to tee is what was stdout before the process substitution (the $(...) bit) - process substitution takes stdout in order to capture the output. Bash and other shells have the ability to manipulate file descriptors for your use case:

exec 3>&1  # Open FD 3 as a duplicate of stdout (fd 1)
# Run ./build.sh but make sure it does not have FD 3 open and tee to FD 3
VARIABLE=$(./build.sh 3>&- | tee /dev/fd/3)
exec 3>&-  # Close FD 3

Doing it this way allows the stdout of the script to be manipulated outside the script (redirecting to a logger, or /dev/null, etc), preserving the correct behaviour WRT stdout.

3
  • Would I be able to simply tee to stdout or stderror as recommended below ? Or I would need to take this path ? Also I have set -e -o pipefail set, if the command fails and exits will exec will be closed properly ? Nov 8, 2022 at 14:01
  • @TorqueNoFriction You can tee to stderr if that's what you want. My answer is how you tee to stdout, since the command substitution alters stdout so it can capture the output. Exiting early will not be a problem. When a process exits, all its files are closed.
    – camh
    Nov 8, 2022 at 20:06
  • @camh BEST ANSWER EVER
    – CoderBrien
    Feb 8 at 16:01
2

You could tee to stderr:

VARIABLE=$(./build.sh | tee /dev/stderr)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .