web-dev-qa-db-ja.com

サブシェルの出力ファイル記述子を親シェルの入力ファイル記述子にリダイレクトする方法は?

(BASHの場合)サブシェルが非STDOUT非STDERRファイル記述子を使用して、データを親シェルに返すようにします。どうやってやるの?最終的には、親シェルの変数にデータを保存したいと思います。

(
  # 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

編集:サブシェルは、STDOUTおよび&3に書き込むブラックボックスプログラムを実行します。

29
user716468

BEWARE、BASHISM AHEAD(プロセス置換のないashやdashなど、bashよりも大幅に高速なposixシェルがあります)。

ハンドルダンスを実行して、元の標準出力を新しい記述子に移動し、標準出力をパイピングに使用できるようにします(頭の上から)。

_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"
}
_

今、あなたは書くことができるはずです:

_while read line; do
    process $line
done < <(run_in_subshell)
_

しかし、<()コンストラクトはバシズムです。パイプラインに置き換えることができます

_run_in_subshell | while read line; do
    process $line
done
_

2番目のコマンドalso以外はsubshel​​lで実行されます。パイプラインを行います。

28
Jan Hudec

もちろん、最も簡単な方法は、出力を親で直接キャプチャすることです

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

子からデータを読み取る代替方法として名前付きパイプを使用できます

mkfifo /tmp/fifo

これで、子を/tmp/fifoにリダイレクトできます

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

親はそこから読むことができます

read data_from_subshell </tmp/fifo

別の方法は、 coproc を使用して子プロセスを開始することです。これにより、双方向パイプを持つ子が作成され、子のstdinとstdoutがパイプ記述子にリダイレクトされます。子でパイプと標準出力の両方を使用するには、最初に親で標準出力を複製する必要があります

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"

コプロセスはBash 4.0で導入されました。

5
Olaf Dietsche