Подтвердить что ты не робот

Как перенаправить дескриптор выходного файла подоболочки на дескриптор входного файла в родительскую оболочку?

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

EDIT: Подселочка запускает программу черного ящика, которая записывает в STDOUT и & 3.

4b9b3361

Ответ 1

BEWARE, BASHISM AHEAD (есть ракеты posix, которые значительно быстрее, чем bash, например, ash или тире, которые не имеют подстановки процесса).

Вы можете сделать ручку танца, чтобы перенести исходный стандартный вывод на новый дескриптор, чтобы сделать стандартный вывод доступным для трубопровода (с верхней части головы):

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

Простейшим способом, конечно, является захват вывода непосредственно в родительском

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 на дескрипторы каналов. Чтобы использовать как канал, так и stdout в дочернем, вы должны дублировать 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.