Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In bash, how to capture some output in variable, letting rest got to standard output

I'm aware of the bash "capture output" capability, along the lines of (two separate files):

sub.sh:     echo hello
main.sh:    greeting="$(./sub.sh)"

This will set the greeting variable to be hello.

However, I need to write a script where I want to just capture some information, allowing the rest to got to "normal" standard output:

sub.sh:     xyzzy hello ; plugh goodbye
main.sh:    greeting="$(./sub.sh)"

What I would like is for hello to be placed in the greeting variable but goodbye to be sent to the standard output of main.sh.

What do the magic commands xyzzy and plugh need to be replaced with above (or what can I do in main.sh), in order to achieve this behaviour? I suspect it could be done with some sneaky fiddling around of handle-based redirections but I'm not sure. If not possible, I'll have to revert to writing one of the items to a temporary file to be picked up later, but I'd prefer not to do that.


To make things clearer, here's the test case I'm using (currently using the non-working file handle 3 method). First sub.sh:

echo xx_greeting >&3 # This should be captured to variable.
echo xx_stdout       # This should show up on stdout.
echo xx_stderr >&2   # This should show up on stderr.

Then main.sh:

greeting="$(./sub.sh)" 3>&1
echo "Greeting was ${greeting}"

And I run it thus:

./main.sh >/tmp/out 2>/tmp.err

expecting to see the following files:

/tmp/out:
    xx_stdout
    Greeting was xx_greeting 
/tmp/err:
    xx_stderr
like image 866
paxdiablo Avatar asked Nov 06 '22 04:11

paxdiablo


1 Answers

This can be done by introducing an extra file descriptor as follows. First the sub.sh script for testing, which simply writes a different thing to three different descriptors (implicit >&1 for the first):

echo for-var
echo for-out >&3
echo for-err >&2

Second, the main.sh which calls it:

exec 3>&1
greeting="$(./sub.sh)"
echo "Variable is ${greeting}"

Then you simply run it ensuring you know what output is going to the different locations:

pax> ./main.sh > xxout 2> xxerr

pax> cat xxout
for-out
Variable is for-var

pax> cat xxerr
for-err

Hence you can see that, when calling sub.sh from main.sh, stuff written to file handle 1 goes to the capture variable, stuff written to file handle 2 goes to standard error, and stuff written to file handle 3 goes to standard output.

like image 199
paxdiablo Avatar answered Nov 11 '22 04:11

paxdiablo