2016-03-22 1 views
3

J'essaie de contourner un problème me semble que vous ne pouvez pas passer la connexion db2 ouverte à un sous-shell.Une fonction Shell s'exécute dans un sous-shell

Mon organisation de code est le suivant:

script pilote (en my_driver.sh)

# foo.sh defines baz() bar(), which use a db2 connection 
# Also the "$param_file" is set in foo.sh! 
source foo.sh 

db2 "connect to $dbName USER $dbUser using $dbPass" 

function doit 
{ 
    cat $param_file | while read params 
    do 
     baz $params 
     bar $params 
    done 
} 

doit 

J'ai simplifié mon code, mais assez au-dessus est donner l'idée. Je commence ci-dessus:

my_driver.sh 

Maintenant, mon vrai problème est que la connexion db2 n'est pas disponible en sous-shell:

Je fatigué:

. my_driver.sh 

ne pas aider

Si je le fais manuellement à partir de la ligne de commande:

source foo.sh 

Je tournai $params manuellement:

baz $params 
bar $params 

Ensuite, il fonctionne! Il semble donc que doit ou autre chose agit comme si bar et baz sont exécutés à partir d'un sous-shell.

Je serais ravi si je peux comprendre comment passer db2 connexion ouverte à sous-shell serait le mieux.

Sinon, ces fonctions shell me semblent fonctionner dans un sous-shell. Y a-t-il un moyen de contourner cela?

+0

Je pense que la réponse est évidente pour vous. Oui c'est dans un sous-shell! vous pouvez facilement tester ceci en essayant d'imprimer des variables d'environnement. – raam86

+0

Oui, c'est .. mais ** peut ** Je cours 'bar' ou' baz' * pas * dans un sous-shell? – lzc

+1

Dans votre code, je ne vois aucune possibilité que '' '' baz''' ou '' '' '' '' bar''' s'exécute dans un sous-shell. Probablement ils exécutent eux-mêmes des commandes db2 dans un sous-shell? – dekkard

Répondre

5

Le shell ne crée pas de sous-shell pour exécuter une fonction.

Bien sûr, il crée des sous-couches à bien d'autres fins, qui ne sont pas toutes évidentes. Par exemple, il crée des sous-couches dans l'implémentation de |.

db2 exige que toutes les commandes db2 aient le même parent que la commande db2 qui a établi la connexion. Vous pouvez connecter le PID en utilisant quelque chose comme:

echo "Execute db2 from PID $$" >> /dev/stderr 
db2 ... 

(. Tant que la commande db2 est exécute pas dans une parenthèse de tuyau ou coquille)


Un problème possible dans le code affiché (qui aurait un tout autre symptôme) est l'utilisation de la syntaxe non-standard

function f 

Pour définir une fonction.Un shell standard attend

f() 

Bash comprend à la fois, mais si vous ne disposez pas d'une ligne de tralala ou vous exécutez le fichier de script en utilisant la commande sh, vous finirez par utiliser le shell par défaut du système, ce qui pourrait ne pas être bash .

+0

FYI: J'utilise le bash, et AFAIK en utilisant le mot-clé 'function' est [facultatif] (http://www.gnu.org/software/bash/manual/bashref.html#Shell-Functions) aussi le'> >/dev/stderr' est trompeur ou pour une raison quelconque cela ne fonctionne pas pour moi ... voulez-vous dire: 'echo hello world 2 >> /tmp/my_stderr.log> & 2'? – lzc

0

solution trouvée, mais ne peut pas encore pleinement expliquer le problème ....

si vous changez doit comme suit ça marche!

function doit 
{ 
    while read params 
    do 
     baz $params 
     bar $params 
    done < $param_file 
} 

Seulement, je ne sais pas pourquoi? et comment je peux le prouver ...

Si je colle dans le code de débogage:

echo debug check with PID=$$ PPID=$PPID and SHLVL=$SHLVL 

Je reviens avec le même résultat | ou non. Je comprends que cat $param_file | while read params crée un sous-shell, cependant, mes instructions de débogage montrent toujours les mêmes PID et PPID ...

Donc, mon problème est résolu, mais il me manque quelques explications.

Je me demande aussi si cette question ne conviendrait pas mieux à la communauté unix.stackexchange?

+1

La variable 'BASH_SUBSHELL' dans le code de débogage ** indique ** que le * côté droit * du' | 'est un sous-shell ... donc les appels' db2' suivants ne sont plus dans le shell parent! – lzc