web-dev-qa-db-fra.com

Comment rediriger un descripteur de fichier de sortie d'un sous-shell vers un descripteur de fichier d'entrée dans le shell parent?

(En BASH) Je veux qu'un sous-shell utilise un descripteur de fichier non-STDOUT non-STDERR pour transmettre certaines données au shell parent. Comment puis je faire ça? Finalement, j'aimerais enregistrer les données dans une variable du shell parent.

(
  # 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: le sous-shell exécute un programme de boîte noire qui écrit dans STDOUT et & 3.

29
user716468

ATTENTION, BASHISM AHEAD (il existe des shells posix qui sont nettement plus rapides que bash, par exemple ash ou dash, qui n'ont pas de substitution de processus).

Vous pouvez faire une danse de poignée pour déplacer la sortie standard d'origine vers un nouveau descripteur pour rendre la sortie standard disponible pour la tuyauterie (du haut de ma tête):

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

Vous devriez maintenant pouvoir écrire:

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

mais la construction <() est un bashisme. Vous pouvez le remplacer par un pipeline

run_in_subshell | while read line; do
    process $line
done

sauf que la deuxième commande aussi s'exécute dans sous-shell , car toutes les commandes de pipeline faire.

28
Jan Hudec

La façon la plus simple est bien sûr de capturer la sortie directement dans le parent

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

Vous pouvez utiliser un canal nommé comme un autre moyen de lire les données d'un enfant

mkfifo /tmp/fifo

vous pouvez maintenant rediriger l'enfant vers /tmp/fifo

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

et le parent peut lire à partir de là

read data_from_subshell </tmp/fifo

Une autre façon consiste à utiliser coproc pour démarrer un processus enfant. Cela crée un enfant avec un canal bidirectionnel et redirige les stdin et stdout de l'enfant vers les descripteurs de canal. Pour utiliser à la fois le canal et la sortie standard dans l'enfant, vous devez d'abord dupliquer la sortie standard dans le parent

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"

Les coprocessus ont été introduits dans Bash 4.0.

5
Olaf Dietsche