2010-07-11 16 views
6

Ho due script di shell che vorrei richiamare da un programma C. Vorrei che le variabili di shell impostate nel primo script fossero visibili nel secondo. Ecco cosa sarebbe simile:salva e ripristina le variabili shell

a.sh:

var=blah 
<save vars> 

b.sh:

<restore vars> 
echo $var 

Il migliore che è venuta in mente finora è una variante sul tema "SET>/tmp/vars "per salvare le variabili e" eval $ (cat/tmp/vars) "per ripristinarle. "Eval" soffoca quando tenta di ripristinare una variabile di sola lettura, quindi ho bisogno di annullarli. Un elenco di queste variabili è disponibile tramite "declare -r". Ma ci sono alcune vars che non appaiono in questo elenco, ma non possono ancora essere impostate in eval, ad es. BASH_ARGC. Quindi ho bisogno di far fuori anche quelli.

A questo punto, la mia soluzione sembra molto fragile e soggetta a errori, e non sono sicuro di quanto sia portatile. C'è un modo migliore per farlo?

risposta

0

Se a.sh è possibile chiamare b.sh, verrà trasferito se vengono esportati. Oppure avere un genitore imposta tutti i valori necessari e poi chiama entrambi. Questo è il metodo più sicuro e sicuro che riesca a pensare.

Non sono sicuro se è accettato il dogma, ma:

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

Il otherscript avrà l'ENV stampata a xxxx ...

Aggiornamento:

anche notare:

man execle 

Su come impostare le variabili di ambiente per un'altra chiamata di sistema da C, se è necessario quella. E:

man getenv 

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

+0

ho bisogno di fare un certo lavoro in C tra l'esecuzione di a.sh e b.sh, quindi non è possibile per una chiamata a b . Nota che sono interessato alle variabili di shell, non alle variabili di ambiente. – danvk

+0

ah, mi dispiace per quello! – eruciform

2

Se è possibile utilizzare un prefisso comune sui vostri nomi delle variabili, qui è un modo per farlo:

# 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 

Naturalmente, il prefisso sarà più breve . È possibile eseguire ulteriori convalide dopo aver caricato le variabili per assicurarsi che i nomi delle variabili siano conformi allo schema di denominazione.

Il vantaggio dell'utilizzo di declare è che è più sicuro dell'uso di eval.

Se necessario, è possibile filtrare le variabili contrassegnate come readonly o selezionare le variabili contrassegnate per l'esportazione.

Altri comandi di interesse (alcuni possono variare in base alla versione di Bash):

  • export - senza argomenti, elenca tutte le variabili esportati utilizzando un formato declare
  • declare -px - uguale al comando precedente
  • declare -pr - elenca le variabili di sola lettura
+0

I due script sono forniti dall'utente, quindi richiedere un prefisso comune sarebbe un po 'imbarazzante. D'altra parte, ho potuto controllare le variabili che sono state modificate da ogni script. Andando a lanciare questa idea in una risposta in modo da ottenere la formattazione ... – danvk

4

Un modo per evitare di impostare le variabili problematiche è oring solo quelli che sono cambiati durante l'esecuzione di ogni script. Ad esempio,

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 questo:

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

Evidentemente evaling le prime due righe ha nessun effetto negativo

+1

'set' includerà le definizioni di funzione,' declare -p' no ('declare -f' will). Sii consapevole dei [rischi per la sicurezza] (http://mywiki.wooledge.org/BashFAQ/048) di 'eval' con input non validato o non protetto (per' declare' per esempio). –

0

Un'alternativa al salvataggio e al ripristino dello stato della shell sarebbe quella di far funzionare il programma C e il programma shell in parallelo: il programma C avvia il programma shell, che esegue a.sh, quindi notifica il programma C (forse passando alcune informazioni è imparato dall'esecuzione di a.sh) e quando il programma C è pronto per ulteriori informazioni, dice al programma shell di eseguire b.sh. Il programma shell sarebbe così:

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

e la struttura generale del programma C sarebbe:

  • istituito due coppie di tubi, uno per C-> guscio e una per shell- > C
  • forcella, exec l'involucro shell
  • leggi le informazioni raccolte da un sulla shell-> C tubo
  • maggiore elaborazione
  • write argomenti per b sul C-> tubo di guscio
  • attesa per il bambino processo di porre fine
0

sono andato alla ricerca di qualcosa di simile e non riusciva a trovare neanche, così ho fatto i due script di seguito. Per iniziare, basta dire shellstate, quindi probabilmente almeno set -i e set -o emacs che questo reset_shellstate non fa per te. Non conosco un modo per chiedere a bash quali variabili pensi siano speciali.

~/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 $? 
Problemi correlati