Passa tutte le variabili da una shell all’altra?

Quindi diciamo che ho uno script shellscript / bash chiamato test.sh

con:

#!/bin/bash # TESTVARIABLE=hellohelloheloo ./test2.sh 

il mio test2.sh ha questo aspetto

 #!/bin/bash # echo ${TESTVARIABLE} 

questo non funziona. Non voglio passare tutte le variabili come parametri da quando questo è eccessivo. C’è un modo diverso?

Hai fondamentalmente due opzioni:

  1. Rendi la variabile una variabile d’ambiente ( export TESTVARIABLE ) prima di eseguire il secondo script.
  2. Dai il secondo script, es . test2.sh . test2.sh e verrà eseguito nella stessa shell. Questo ti permetterebbe di condividere facilmente variabili più complesse come gli array, ma significa anche che l’altro script potrebbe modificare le variabili nella shell sorgente.

AGGIORNARE:

Per utilizzare l’ export per impostare una variabile d’ambiente, puoi utilizzare una variabile esistente:

 A=10 # ... export A 

Questo dovrebbe funzionare sia in bash che in sh . bash permette anche di essere combinato in questo modo:

 export A=10 

Questo funziona anche nel mio sh (che capita di essere bash , puoi usare echo $SHELL per controllare). Ma non credo che sia garantito che funzioni in tutto, quindi è meglio giocare in sicurezza e separarli.

Qualsiasi variabile esportata in questo modo sarà visibile negli script che esegui, ad esempio:

cenere:

 #!/bin/sh MESSAGE="hello" export MESSAGE ./b.sh 

b.sh:

 #!/bin/sh echo "The message is: $MESSAGE" 

Poi:

 $ ./a.sh The message is: hello 

Il fatto che questi siano entrambi script di shell è anche solo secondario. Le variabili di ambiente possono essere passate a qualsiasi processo che si esegue, ad esempio se abbiamo usato python invece potrebbe apparire come:

cenere:

 #!/bin/sh MESSAGE="hello" export MESSAGE ./b.py 

b.py:

 #!/usr/bin/python import os print 'The message is:', os.environ['MESSAGE'] 

Reperimento:

Invece potremmo ottenere come questo:

cenere:

 #!/bin/sh MESSAGE="hello" . ./b.sh 

b.sh:

 #!/bin/sh echo "The message is: $MESSAGE" 

Poi:

 $ ./a.sh The message is: hello 

Questo “importa” più o meno il contenuto di b.sh direttamente e lo esegue nella stessa shell . Si noti che non è stato necessario esportare la variabile per accedervi. Questo condivide implicitamente tutte le variabili che hai, così come l’altro script per aggiungere / eliminare / modificare le variabili nella shell. Naturalmente, in questo modello entrambi gli script dovrebbero essere la stessa lingua ( sh o bash ). Per dare un esempio di come possiamo passare i messaggi avanti e indietro:

cenere:

 #!/bin/sh MESSAGE="hello" . ./b.sh echo "[A] The message is: $MESSAGE" 

b.sh:

 #!/bin/sh echo "[B] The message is: $MESSAGE" MESSAGE="goodbye" 

Poi:

 $ ./a.sh [B] The message is: hello [A] The message is: goodbye 

Funziona altrettanto bene in bash . Rende anche più semplice la condivisione di dati più complessi che non è ansible esprimere come variabile di ambiente (almeno senza un notevole sollevamento da parte dell’utente), come array o array associativi.

Errore fatale ha dato una possibilità semplice: fonte il tuo secondo script! se sei preoccupato che questo secondo script possa alterare alcune delle tue preziose variabili, puoi sempre trovarlo in una subshell:

 ( . ./test2.sh ) 

Le parentesi faranno accadere la sorgente in una subshell, in modo che la shell madre non veda le modifiche che test2.sh potrebbe eseguire.


C’è un’altra possibilità che dovrebbe essere sicuramente referenziata qui: usa set -a .

Dal riferimento set POSIX :

-a : quando questa opzione è triggers, l’attributo export deve essere impostato per ciascuna variabile a cui viene eseguita un’assegnazione; vedere il volume delle definizioni di base di IEEE Std 1003.1-2001, Sezione 4.21, Assegnazione variabile . Se l’assegnazione precede un nome di utilità in un comando, l’attributo export non deve persistere nell’ambiente di esecuzione corrente dopo il completamento dell’utilità, con l’eccezione che prima di uno dei programmi di utilità incorporati speciali persiste l’attributo di esportazione dopo la creazione in ha completato. Se il compito non precede un nome di utilità nel comando, o se l’assegnazione è il risultato dell’operazione dei getopts o delle utilità di lettura , l’attributo export deve persistere fino a quando la variabile non viene disinserita.

Dal manuale di Bash :

-a : Contrassegna le variabili e le funzioni che vengono modificate o create per l’esportazione nell’ambiente dei comandi successivi.

Quindi nel tuo caso:

 set -a TESTVARIABLE=hellohelloheloo # ... # Here put all the variables that will be marked for export # and that will be available from within test2 (and all other commands). # If test2 modifies the variables, the modifications will never be # seen in the present script! set +a ./test2.sh # Here, even if test2 modifies TESTVARIABLE, you'll still have # TESTVARIABLE=hellohelloheloo 

Osserva che le specifiche specificano solo che con set -a la variabile è contrassegnata per l’esportazione. Questo è:

 set -a a=b set +a a=c bash -c 'echo "$a"' 

echo c e non una riga vuota né b (vale a dire, set +a non deseleziona per l’esportazione, né “salva” il valore dell’assegnazione solo per l’ambiente esportato). Questo è, naturalmente, il comportamento più naturale.

Conclusione: usare set -a / set +a può essere meno noioso dell’esportazione manuale di tutte le variabili. È superiore all’approvvigionamento del secondo script, poiché funzionerà per qualsiasi comando, non solo quelli scritti nello stesso linguaggio shell.

In realtà c’è un modo più semplice di esportare, disinserire o eseguire di nuovo il sourcing (almeno in bash, a patto che tu stia bene con il passaggio manuale delle variabili d’ambiente):

sia a.sh essere

 #!/bin/bash secret="winkle my tinkle" echo Yo, lemme tell you \"$secret\", b.sh! Message=$secret ./b.sh 

e b.sh essere

 #!/bin/bash echo I heard \"$Message\", yo 

L’output osservato è

[rob @ Archie test] $ ./a.sh
Yo, ti dico “ammicca il mio tintinnio”, b.sh!
Ho sentito “ammiccare il mio tintinnio”, yo

La magia si trova nell’ultima riga di a.sh , dove Message , solo per la durata dell’invocazione di ./b.sh , è impostato sul valore di secret da a.sh Fondamentalmente, è un po ‘come parametri / argomenti chiamati. Inoltre, funziona anche per variabili come $DISPLAY , che controlla in quale X Server viene avviata un’applicazione.

Ricorda, la lunghezza dell’elenco delle variabili di ambiente non è infinita. Sul mio sistema con un kernel relativamente vanilla, xargs --show-limits mi dice che la dimensione massima del buffer degli argomenti è 2094486 byte. Teoricamente, stai usando gli script di shell errati se i tuoi dati sono più grandi di così (pipe, chiunque?)

In Bash se esporti la variabile in una subshell, usando le parentesi come mostrato, eviti di perdere le variabili esportate:

 #!/bin/bash TESTVARIABLE=hellohelloheloo ( export TESTVARIABLE source ./test2.sh ) 

Il vantaggio è che dopo aver eseguito lo script dalla riga di comando, non vedrai una TESTVARIABLE $ trapelata nel tuo ambiente:

 $ ./test.sh hellohelloheloo $ echo $TESTVARIABLE #empty! no leak $ 

Aggiungendo alla risposta di Errore fatale, c’è un altro modo per passare le variabili ad un altro script di shell.

La soluzione suggerita sopra ha alcuni inconvenienti:

  1. using Export : farà sì che la variabile sia presente al di fuori del loro ambito che non è una buona pratica di progettazione.
  2. using Source : può causare collisioni di nomi o sovrascrittura accidentale di una variabile predefinita in qualche altro file di script di shell che ha originariamente fornito un altro file.

C’è un’altra semplice soluzione disponibile per noi da usare. Considerando l’esempio pubblicato da te,

test.sh

 #!/bin/bash TESTVARIABLE=hellohelloheloo ./test2.sh "$TESTVARIABLE" 

test2.sh

 #!/bin/bash echo $1 

produzione

 hellohelloheloo 

Inoltre è importante notare che "" sono necessari se passiamo stringhe multiword. Prendendo un altro esempio

master.sh

 #!/bin/bash echo in master.sh var1="hello world" sh slave1.sh $var1 sh slave2.sh "$var1" echo back to master 

slave1.sh

 #!/bin/bash echo in slave1.sh echo value :$1 

slave2.sh

 #!/bin/bash echo in slave2.sh echo value : $1 

produzione

 in master.sh in slave1.sh value :"hello in slave2.sh value :"hello world" 

Succede per le ragioni appropriatamente descritte in questo link

Un altro modo, che per me è un po ‘più semplice, è usare pipe con nome. Le named pipe hanno fornito un modo per sincronizzare e inviare messaggi tra diversi processi.

A.bash:

 #!/bin/bash msg="The Message" echo $msg > A.pipe 

B.bash:

 #!/bin/bash msg=`cat ./A.pipe` echo "message from A : $msg" 

Uso:

 $ mkfifo A.pipe #You have to create it once $ ./A.bash & ./B.bash # you have to run your scripts at the same time 

B.bash attenderà il messaggio e non appena A.bash invia il messaggio, B.bash continuerà a funzionare.

Un’altra opzione sta usando eval . Questo è adatto solo se le stringhe sono attendibili. Il primo script può echeggiare i compiti delle variabili:

echo "VAR=myvalue"

Poi:

eval $(./first.sh) ./second.sh

Questo approccio è di particolare interesse quando il secondo script che si desidera impostare per le variabili di ambiente non è in bash e non si desidera export le variabili, forse perché sono sensibili e non si desidera che persistano.