2010-07-11 15 views
6

Tengo dos scripts de shell que me gustaría invocar desde un programa C. Me gustaría que las variables de shell establecidas en el primer script sean visibles en el segundo. Esto es lo que se vería así:guardar y restaurar variables de shell

a.sh:

var=blah 
<save vars> 

b.sh:

<restore vars> 
echo $var 

El mejor que he encontrado hasta el momento es una variante de "set>/tmp/vars "para guardar las variables y" eval $ (cat/tmp/vars) "para restaurarlas. El "eval" se ahoga cuando intenta restaurar una variable de solo lectura, así que necesito agotarlos. Una lista de estas variables está disponible a través de "declarar -r". Pero hay algunos vars que no aparecen en esta lista, pero que aún no se pueden configurar en eval, por ej. BASH_ARGC. Así que necesito agriarlos también.

En este punto, mi solución se siente muy frágil y propensa a errores, y no estoy seguro de lo portátil que es. ¿Hay una mejor manera de hacer esto?

Respuesta

0

Si es posible que a.sh llame a b.sh, se transferirá si se exportan. O que un padre establezca todos los valores necesarios y luego llame a ambos. Ese es el método más seguro y seguro que puedo pensar.

No estoy seguro si se acepta el dogma, pero:

bash -c 'export foo=bar; env > xxxx' 
env `cat xxxx` otherscript.sh 

El otherscript tendrá el env impresa a xxxx ...

Actualización:

También tenga en cuenta:

man execle 

Sobre cómo configurar las variables de entorno para otra llamada al sistema desde C, si necesita hacerlo ese. Y:

man getenv 

y http://www.crasseux.com/books/ctutorial/Environment-variables.html

+0

tengo que hacer algún trabajo en C entre la ejecución de a.sh y b.sh, por lo que no es posible para un a llamada B . Tenga en cuenta que estoy interesado en las variables de shell, no en las variables de entorno. – danvk

+0

ah, perdón por eso! – eruciform

2

Si puede utilizar un prefijo común en sus nombres de variables, aquí es una manera de hacerlo:

# save the variables 
yourprefix_width=1200 
yourprefix_height=2150 
yourprefix_length=1975 
yourprefix_material=gravel 
yourprefix_customer_array=("Acme Plumbing" "123 Main" "Anytown") 
declare -p $(echo ${[email protected]}) > varfile 

# load the variables 
while read -r line 
do 
    if [[ $line == declare\ * ]] 
    then 
     eval "$line" 
    fi 
done < varfile 

Por supuesto, el prefijo será más corta . Puede realizar más validaciones al cargar las variables para asegurarse de que los nombres de las variables se ajusten a su esquema de nombres.

La ventaja de utilizar declare es que es más seguro que simplemente usar eval por sí mismo.

Si lo necesita, puede filtrar las variables que están marcadas como de solo lectura o seleccionar las variables que están marcadas para la exportación.

Otros comandos de interés (algunos pueden variar según la versión de Bash):

  • export - sin argumentos, enumera todas las variables exportadas utilizando un formato declare
  • declare -px - igual que el comando anterior
  • declare -pr - enumera las variables de solo lectura
+0

Los dos scripts son provistos por el usuario, por lo que requerir un prefijo común sería un poco incómodo. Por otro lado, podría verificar las variables que han sido modificadas por cada script. Voy a arrojar esta idea en una respuesta para que pueda formatear ... – danvk

4

Una forma de evitar el establecimiento de variables problemáticas es mediante st oring solo aquellos que han cambiado durante la ejecución de cada script. Por ejemplo,

a.sh:

set > /tmp/pre 
foo=bar 
set > /tmp/post 
grep -v -F -f/tmp/pre /tmp/post > /tmp/vars 

b.sh:

eval $(cat /tmp/vars) 
echo $foo 

/tmp/vars contiene esto:

PIPESTATUS=([0]="0") 
_= 
foo=bar 

Evidentemente evaling las dos primeras líneas tiene sin efectos adversos.

+1

'set' incluirá definiciones de funciones,' declare -p' no lo hará ('declare -f'). Tenga en cuenta los [riesgos de seguridad] (http://mywiki.wooledge.org/BashFAQ/048) de 'eval' con datos no validados o desprotegidos (por' declare' por ejemplo). –

0

Una alternativa para guardar y restaurar el estado del shell sería hacer que el programa C y el shell funcionen en paralelo: el programa C inicia el shell program, que ejecuta a.sh, notifica al programa C (tal vez transfiriendo cierta información). aprendido de ejecutar a.sh), y cuando el programa C está listo para más, le dice al programa shell que ejecute b.sh. El programa de shell se vería así:

 
. a.sh 
echo "information gleaned from a" 
arguments_for_b=$(read -r) 
. b.sh 

y la estructura general del programa de C sería:

  • configurar dos pares de tubos, uno para C-> shell y uno para shell- > C
  • tenedor, exec la envoltura del shell
  • leer la información obtenida de una en la shell-> tubo C
  • más procesamiento
  • escritura argumentos a favor de b en el C-> tubo de la cáscara
  • espera para el niño proceso para poner fin a
0

yo fuimos en busca de algo similar y no lo encontraron, ya sea, por lo que hicieron los dos guiones a continuación. Para comenzar, simplemente diga shellstate, entonces probablemente al menos set -i y set -o emacs que este reset_shellstate no hace por usted. No sé cómo preguntarle a bash qué variables cree que son especiales.

~/bin/reset_shellstate:

#!/bin/bash 
__="$PWD/shellstate_${1#_}" 
trap ' 
    declare -p  >"'"$__"'" 
    trap   >>"'"$__"'" 
    echo cd \""$PWD"\"  >>"'"$__"'"  # setting PWD did this already, but... 
    echo set +abefhikmnptuvxBCEHPT >>"'"$__"'" 
    echo set -$- >>"'"$__"'"  # must be last before sed, see $s/s//2 below 
    sed -ri '\'' 
      $s/s//2 
      s,^trap --,trap, 
      /^declare -[^ ]*r/d 
      /^declare -[^ ]* [A-Za-z0-9_]*[^A-Za-z0-9_=]/d 
      /^declare -[^ ]* [^= ]*_SESSION_/d 
      /^declare -[^ ]* BASH[=_]/d 
      /^declare -[^ ]* (DISPLAY|GROUPS|SHLVL|XAUTHORITY)=/d 
      /^declare -[^ ]* WINDOW(ID|PATH)=/d 
      '\'' "'"$__"'" 
    shopt -op  >>"'"$__"'" 
    shopt -p  >>"'"$__"'" 
    declare -f  >>"'"$__"'" 
    echo "Shell state saved in '"$__"'" 
    ' 0 
unset __ 

~/bin/shellstate:

#!/bin/bash 
shellstate=shellstate_${1#_} 
test -s $shellstate || reset_shellstate $1 
shift 
bash --noprofile --init-file shellstate_${1#_} -is "[email protected]" 
exit $? 
Cuestiones relacionadas