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

后端 未结 2 1520
感情败类
感情败类 2020-12-13 02:27

(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

相关标签:
2条回答
  • 2020-12-13 03:13

    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.

    0 讨论(0)
  • 2020-12-13 03:20

    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 # creates 3 as alias for 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.

    0 讨论(0)
提交回复
热议问题