J'ai la fonction récursive suivante pour définir les variables d'environnement:
function par_set {
PAR=$1
VAL=$2
if [ "" != "$1" ]
then
export ${PAR}=${VAL}
echo ${PAR}=${VAL}
shift
shift
par_set $*
fi
}
Si je l'appelle par lui-même, il définit à la fois la variable et fait écho à stdout:
$ par_set FN WORKS
FN=WORKS
$ echo "FN = "$FN
FN = WORKS
La redirection de stdout vers un fichier fonctionne également:
$ par_set REDIR WORKS > out
cat out
REDIR=WORKS
$ echo "REDIR = "$REDIR
REDIR = WORKS
Mais, si je redirige stdout vers une autre commande, la variable n'est pas définie:
$ par_set PIPE FAILS |sed -e's/FAILS/BARFS/'
PIPE=BARFS
$ echo "PIPE = "$PIPE
PIPE =
Pourquoi le canal empêche-t-il la fonction d'exporter la variable? Existe-t-il un moyen de résoudre ce problème sans recourir à des fichiers temporaires ou à des canaux nommés?
Résolu:
Code de travail grâce à Gilles:
par_set $(echo $*|tr '=' ' ') > >(sed -e's/^/ /' >> ${LOG})
Cela permet au script d'être appelé ainsi:
$ . ./script.sh PROCESS_SUB ROCKS PIPELINES=NOGOOD
$ echo $PROCESS_SUB
ROCKS
$ echo $PIPELINES
NOGOOD
$ cat log
7:20140606155622162731431:script.sh:29581:Parse Command Line parameters. Params must be in matched pairs separated by one or more '=' or ' '.
PROCESS_SUB=ROCKS
PIPELINES=NOGOOD
Projet hébergé sur bitbucket https://bitbucket.org/adalby/monitor-bash si intéressé par le code complet.
Cela ne fonctionne pas car chaque côté du tuyau s'exécute dans un sous-shell
bash
et les variables définies dans un sous-shell sont locales à ce sous-shell.Mettre à jour:
Il semble qu'il soit facile de passer des variables du parent au shell enfant, mais vraiment difficile de le faire dans l'autre sens. Certaines solutions de contournement sont nommées tubes, fichiers temporaires, écriture dans stdout et lecture dans le parent, etc.
Quelques références:
http://mywiki.wooledge.org/BashFAQ/024
/programming//q/15541321/3565972
/programming//a/15383353/3565972
http://forums.opensuse.org/showthread .php / 458979-How-export-variable-in-subshell-back-out-to-parent
la source
$$
c'est la même chose pour les coquilles des parents et des enfants. Vous pouvez utiliser$BASHPID
pour obtenir le pid du sous-shell. Quand je suis à l'echo $$ $BASHPID
intérieur,par_set
je reçois différents pids.Vous signalez les sous-coquilles - qui peuvent être contournées avec quelques agissements dans le shell à l'extérieur d'un pipeline - mais la partie la plus difficile du problème a à voir avec la concurrence du pipeline .
Tous les membres du processus du pipeline démarrent en même temps , et donc le problème pourrait être plus facile à comprendre si vous le regardez comme ceci:
Les processus de pipeline ne peuvent pas hériter des valeurs de variable car ils sont déjà désactivés et en cours d'exécution avant que la variable soit définie.
Je ne peux pas vraiment comprendre à quoi sert votre fonction - à quoi sert-elle qui
export
ne l'est pas déjà? Ou même justevar=val
? Par exemple, voici à nouveau presque le même pipeline:Et avec
export
:Donc, votre truc pourrait fonctionner comme:
Qui se connecterait à
sed
la sortie d'un fichier et le livrerait à votre fonction en tant que shell-split"$@"
.Ou bien:
Si je devais écrire votre fonction, cela ressemblerait probablement à ceci:
la source
|pipeline | sh
sh
. Il utilise déjàexport
.