Qual è la differenza tra l'esecuzione di uno script Bash e il suo sourcing?
Qual è la differenza tra l'esecuzione di uno script Bash come A e il sourcing di uno script Bash come B?
A
> ./myscript
B
> source myscript
Sourcing uno script eseguirà i comandi nel processo corrente della shell.
Eseguire uno script eseguirà i comandi in un nuovo processo di shell.
Usa source se vuoi che lo script cambi l'ambiente nella tua shell correntemente in esecuzione, altrimenti usa execute.
Se siete ancora confusi, continuate a leggere.
Per chiarire una certa confusione comune sulla sintassi di execute e la sintassi di source:
./myscript
Questo eseguirà myscript
purché il file sia eseguibile e si trovi nella directory corrente. Il punto e la barra iniziale (./
) indicano la directory corrente. Questo è necessario perché la directory corrente di solito non è (e di solito non dovrebbe essere) in $PATH
.
myscript
Questo eseguirà myscript
se il file è eseguibile e si trova in qualche directory in $PATH
.
source myscript
Questo sorgerà myscript
. Non è necessario che il file sia eseguibile, ma deve essere uno script di shell valido. Il file può essere nella directory corrente o in una directory in $PATH
.
. myscript
Anche questo sorgerà myscript
. Questo “spelling” è quello ufficiale definito da POSIX . Bash ha definito source
come alias del punto.
Consideriamo myscript.sh
con il seguente contenuto:
#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD
Prima di eseguire lo script controlliamo l'ambiente corrente:
$ env | grep FOO
$ echo $PWD
/home/lesmana
La variabile FOO
non è definita e siamo nella home directory.
Ora eseguiamo il file:
$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir
Controlla di nuovo l'ambiente:
$ env | grep FOO
$ echo $PWD
/home/lesmana
La variabile FOO
non è impostata e la directory di lavoro non è cambiata.
L'output dello script mostra chiaramente che la variabile è stata impostata e la directory è stata cambiata. Il controllo successivo mostra che la variabile non è impostata e la directory non è cambiata. Cosa è successo? Le modifiche sono state fatte in una nuova shell. La shell corrente ha generato una nuova shell per eseguire lo script. Lo script è in esecuzione nella nuova shell e tutti i cambiamenti all'ambiente hanno effetto nella nuova shell. Dopo che lo script è finito, la nuova shell viene distrutta. Tutte le modifiche all'ambiente nella nuova shell vengono distrutte con la nuova shell. Solo il testo in uscita viene stampato nella shell corrente.
Ora noi sorgiamo il file:
$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir
Controlla di nuovo l'ambiente:
$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir
La variabile FOO è impostata e la directory di lavoro è cambiata.
La creazione dello script non crea una nuova shell. Tutti i comandi vengono eseguiti nella shell corrente e i cambiamenti all'ambiente hanno effetto nella shell corrente.
Notate che in questo semplice esempio l'output dell'esecuzione è lo stesso del sourcing dello script. Questo non è necessariamente sempre il caso.
Considerate il seguente script pid.sh
:
#!/bin/sh
echo $$
(la variabile speciale $$
si espande al PID del processo corrente della shell in esecuzione)
Prima stampa il PID della shell corrente:
$ echo $$
25009
Source lo script:
$ source pid.sh
25009
Esegui lo script, nota il PID:
$ ./pid.sh
25011
Fonte di nuovo:
$ source pid.sh
25009
Esegui di nuovo:
$ ./pid.sh
25013
Puoi vedere che il sourcing dello script gira nello stesso processo mentre l'esecuzione dello script crea un nuovo processo ogni volta. Questo nuovo processo è la nuova shell che è stata creata per l'esecuzione dello script. Il sourcing dello script non crea una nuova shell e quindi il PID rimane lo stesso.
Sia il sourcing che l'esecuzione dello script eseguiranno i comandi nello script linea per linea, come se li aveste digitati a mano linea per linea.
Le differenze sono:
Usa source se vuoi che lo script cambi l'ambiente nella tua shell corrente, altrimenti usa execute.
Vedi anche:
L'esecuzione di uno script lo esegue in un processo figlio separato, cioè viene invocata un'istanza separata di shell per elaborare lo script. Questo significa che qualsiasi variabile d'ambiente ecc. definita nello script non può essere aggiornata nella shell madre (corrente).
Sourcing di uno script significa che viene analizzato ed eseguito dalla shell corrente stessa. È come se si digitasse il contenuto dello script. Per questo motivo, non è necessario che lo script che viene estratto sia eseguibile. Ma deve essere eseguibile se lo state eseguendo, naturalmente.
Se avete argomenti posizionali nella shell corrente, sono invariati.
Quindi se ho un file a.sh
contenente:
echo a $*
e faccio:
$ set `date`
$ source ./a.sh
ottengo qualcosa come:
a Fri Dec 11 07:34:17 PST 2009
considerando che:
$ set `date`
$ ./a.sh
mi dà:
a
Spero che questo aiuti.
sourcing è essenzialmente lo stesso che digitare ogni linea dello script al prompt dei comandi una alla volta…
L'esecuzione avvia un nuovo processo e poi esegue ogni linea dello script, modificando l'ambiente corrente solo per ciò che restituisce.
Sourcing si ottengono tutte le variabili extra definite nello script.
Quindi se avete configurazioni o definizioni di funzioni dovreste fare il source e non l'esecuzione. Le esecuzioni sono indipendenti dall'ambiente dei genitori.
Il comando source
esegue lo script fornito (il permesso eseguibile è non obbligatorio ) nell'ambiente corrente della shell, mentre ./
esegue lo script eseguibile fornito in una nuova shell.
Inoltre, controllate questa risposta per esempio: https://superuser.com/a/894748/432100