Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect an output file descriptor of a subshell to an input file descriptor in the parent shell?

(In BASH) I want a subshell to use a non-STDOUT non-STDERR file descriptor to pass some data back to the parent shell. How can I do that? Eventually I would love to save the data into some variable of the parent shell.

(   # The following two lines show the behavior of the subshell.   # We cannot change them.   echo "This should go to STDOUT"   echo "This is the data I want to pass to the parent shell" >&3 ) #... data_from_subshell=... # Somehow assign the value of &3 of the                        # subshell to this variable 

EDIT: The subshell runs a black-box program that writes to STDOUT and &3.

like image 808
user716468 Avatar asked Mar 01 '13 08:03

user716468


People also ask

How do I redirect standard output to a file?

Redirecting stdout and stderr to a file: The I/O streams can be redirected by putting the n> operator in use, where n is the file descriptor number. For redirecting stdout, we use “1>” and for stderr, “2>” is added as an operator.

How do you redirect both the output and error of a command to a file?

Any file descriptor can be redirected to other file descriptor or file by using operator > or >> (append).

Which symbol should I use to redirect the standard output to a file appending to the file?

Redirecting output to append to a file When the notation > > filename is added to the end of a command, the output of the command is appended to the specified file name, rather than writing over any existing data. The >> symbol is known as the append redirection operator.

How do I redirect stdout and stderr to the same location?

Solution. Use the shell syntax to redirect standard error messages to the same place as standard output. where both is just our (imaginary) program that is going to generate output to both STDERR and STDOUT.


2 Answers

BEWARE, BASHISM AHEAD (there are posix shells that are significantly faster than bash, e.g. ash or dash, that don't have process substitution).

You can do a handle dance to move original standard output to a new descriptor to make standard output available for piping (from the top of my head):

exec 3>&1 # open 3 to the same output as 1 run_in_subshell() { # just shortcut for the two cases below     echo "This goes to STDOUT" >&3     echo "And this goes to THE OTHER FUNCTION" } 

Now you should be able to write:

while read line; do     process $line done < <(run_in_subshell) 

but the <() construct is a bashism. You can replace it with pipeline

run_in_subshell | while read line; do     process $line done 

except than the second command also runs in subshell, because all commands in pipeline do.

like image 110
Jan Hudec Avatar answered Oct 03 '22 11:10

Jan Hudec


The easiest way of course, is to capture the output directly in the parent

data_from_subshell=$(echo "This is the data I want to pass to the parent shell") 

You can use a named pipe as an alternative way to read data from a child

mkfifo /tmp/fifo 

now you can redirect the child to /tmp/fifo

(     echo "This should go to STDOUT"     echo "This is the data I want to pass to the parent shell" >/tmp/fifo ) & 

and the parent can read from there

read data_from_subshell </tmp/fifo 

Another way is to use coproc to start a child process. This creates a child with a bidirectional pipe and redirects the child's stdin and stdout to the pipe descriptors. To use both the pipe and stdout in the child, you must duplicate stdout in the parent first

exec 4>&1 # duplicate stdout for usage in client  coproc SUBSHELL (     exec 3>&1 1>&4- # redirect fd 3 to pipe, redirect fd 1 to stdout     (     echo "This should go to STDOUT"     echo "This is the data I want to pass to the parent shell" >&3     ) )  exec 4>&- # close fd 4 in parent read data <&${SUBSHELL[0]} echo "Parent: $data" 

Coprocesses were introduced in Bash 4.0.

like image 40
Olaf Dietsche Avatar answered Oct 03 '22 09:10

Olaf Dietsche