Qual è la differenza tra l'esecuzione di uno script Bash e l'approvvigionamento?


Risposte:


346

Risposta breve

Il sourcing di uno script eseguirà i comandi nel processo di shell corrente .

L'esecuzione di uno script eseguirà i comandi in un nuovo processo di shell.

Utilizzare source se si desidera che lo script cambi l'ambiente nella shell attualmente in esecuzione. usa esegui altrimenti.

Se sei ancora confuso, continua a leggere.

Terminologia

Per chiarire un po 'di confusione comune sulla sintassi da eseguire e la sintassi sull'origine:

./myscript

Ciò verrà eseguito a myscript condizione che il file sia eseguibile e si trovi nella directory corrente. Il punto iniziale e la barra ( ./) indica la directory corrente. Questo è necessario perché la directory corrente di solito non è (e di solito non dovrebbe esserlo) in $PATH.

myscript

Questo verrà eseguito myscript se il file è eseguibile e si trova in una directory in $PATH.

source myscript

Questo fonte myscript . Il file non deve essere eseguibile ma deve essere uno script shell valido. Il file può trovarsi nella directory corrente o in una directory in $PATH.

. myscript

Anche questo fonte myscript . Questa "ortografia" è quella ufficiale come definita da POSIX . Bash definito sourcecome alias al punto.

Dimostrazione

Considerare myscript.shcon 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 FOOnon è definita e ci troviamo nella home directory.

Ora noi 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 FOOnon è impostata e la directory di lavoro non è cambiata.

L'output dello script mostra chiaramente che la variabile è stata impostata e la directory è stata modificata. Il controllo in seguito mostra che la variabile non è impostata e la directory non è stata modificata. Quello che è successo? Le modifiche sono state apportate in una nuova shell. La shell corrente ha generato una nuova shell per eseguire lo script. Lo script è in esecuzione nella nuova shell e tutte le modifiche all'ambiente hanno effetto nella nuova shell. Al termine dello script, la nuova shell viene distrutta. Tutte le modifiche all'ambiente nella nuova shell vengono eliminate con la nuova shell. Nella shell corrente viene stampato solo il testo di output.

Ora fonte 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 è stata modificata.

Il sourcing dello script non crea una nuova shell. Tutti i comandi vengono eseguiti nella shell corrente e le modifiche all'ambiente diventano effettive nella shell corrente.

Si noti che in questo semplice esempio l'output dell'esecuzione è uguale all'approvvigionamento dello script. Questo non è sempre necessariamente il caso.

Un'altra dimostrazione

Prendi in considerazione il seguente script pid.sh:

#!/bin/sh
echo $$

(la variabile speciale si $$espande al PID dell'attuale processo di shell in esecuzione)

Prima stampa il PID della shell corrente:

$ echo $$
25009

Fonte lo script:

$ source pid.sh
25009

Eseguire lo script, notare il PID:

$ ./pid.sh
25011

Fonte di nuovo:

$ source pid.sh
25009

Eseguire di nuovo:

$ ./pid.sh
25013

Si può vedere che l'approvvigionamento dello script viene eseguito nello stesso processo mentre l'esecuzione dello script crea un nuovo processo ogni volta. Quel nuovo processo è la nuova shell creata per l'esecuzione dello script. Il sourcing dello script non crea una nuova shell e quindi il PID rimane lo stesso.

Sommario

Sia l'approvvigionamento che l'esecuzione dello script eseguiranno i comandi nello script riga per riga, come se si digitassero tali comandi manualmente riga per riga.

Le differenze sono:

  • Quando si esegue lo script che si sta aprendo una nuova shell, digitare i comandi nella nuova shell, copiare l'output nella shell corrente, quindi chiudere la nuova shell. Qualsiasi modifica all'ambiente avrà effetto solo nella nuova shell e andrà persa una volta chiusa la nuova shell.
  • Quando si procede allo script, si digitano i comandi nella shell corrente . Qualsiasi modifica all'ambiente avrà effetto e rimarrà nella shell corrente.

Utilizzare source se si desidera che lo script cambi l'ambiente nella shell attualmente in esecuzione. usa esegui altrimenti.


Guarda anche:


2
Un uso del sourcing è la creazione di una forma rudimentale di file di configurazione per i tuoi script. Si inizia impostando varie variabili sui valori predefiniti, quindi si procede a qualcosa di simile a myscript.conf e lo script di origine può avere istruzioni di assegnazione che sovrascrivono qualsiasi valore desiderato. Poiché lo script di origine non inizia con # / bin / bash, non è consigliabile eseguirlo direttamente.
LawrenceC,

Quindi l'origine è un po 'come eseguirla in un ambito globale e l'esecuzione crea un nuovo ambito locale. Questo può essere esteso a una funzione in uno script? eseguire una funzione (normalmente) o "sorgente"?
aliteralmind

2
C'è una differenza tra usare source myscript.she . myscript.sh?
Holloway,

2
praticamente nessuna differenza se si utilizza bash. source è un alias da punteggiare in bash.
lesmana,

1
Mi piace quando le persone forniscono esempi così elaborati in modo che anche i neofiti di Linux come me possano capire. Grazie!
Giulio,

21

L'esecuzione di uno script lo esegue in un processo figlio separato, ovvero viene invocata un'istanza separata della shell per elaborare lo script. Ciò significa che eventuali variabili di ambiente ecc., Definite nello script, non possono essere aggiornate nella shell genitore (corrente).

Il sourcing di uno script significa che viene analizzato ed eseguito dalla shell corrente stessa. È come se tu scrivessi il contenuto dello script. Per questo motivo, lo script di provenienza non deve essere eseguibile. Ma deve essere eseguibile se lo stai eseguendo, ovviamente.

Se hai argomenti posizionali nella shell corrente, sono invariati.

Quindi se ho un file a.shcontenente:

echo a $*

e io faccio:

$ set `date`
$ source ./a.sh

Ottengo qualcosa del tipo:

a Fri Dec 11 07:34:17 PST 2009

Mentre:

$ set `date`
$ ./a.sh

mi da:

a

Spero che aiuti.


5
sebbene questa risposta sia corretta in tutti i modi, trovo molto difficile da capire perché è dimostrata usando un altro concetto (impostazione dei parametri posizionali), che, a mio avviso, è ancora più confuso della differenza di approvvigionamento ed esecuzione stessa.
lesmana,

9

sourcing è essenzialmente lo stesso che digitare ogni riga dello script al prompt dei comandi uno alla volta ...

L'esecuzione avvia un nuovo processo e quindi esegue ogni riga dello script, modificando solo l'ambiente corrente in base a ciò che restituisce.


6

Oltre a quanto sopra, l'esecuzione dello script ./myscriptrichiede l'autorizzazione di esecuzione per myscript dei file mentre l'approvvigionamento non richiede alcuna autorizzazione di esecuzione. Ecco perché chmod +x myscriptnon è richiesto primasource myscript


2
Vero, ma se questo è un problema, puoi sempre correre bash myscript.
Daniel Beck

5

Sourcing ottieni tutte le variabili extra definite nello script.
Pertanto, se si dispone di configurazioni di configurazione o di funzioni, è necessario eseguire il sorgente e non eseguire. Le esecuzioni sono indipendenti dall'ambiente dei genitori.


3

Se ricordo bene, l'esecuzione dello script esegue l'eseguibile in #!linea con il file di script come argomento (in genere avvia una nuova shell e procede efficacemente allo script nella nuova shell, come con #!/bin/sh);
mentre, l'approvvigionamento dello script esegue ogni riga nell'ambiente di shell corrente, il che è utile per mutare la shell corrente (ad esempio, fornendo un modo per definire le funzioni di shell ed esportare le variabili di ambiente).


2

sourceIl comando esegue lo script fornito (l'autorizzazione eseguibile non è obbligatoria ) nell'ambiente shell corrente , mentre ./esegue lo script eseguibile fornito in una nuova shell.

Inoltre, controlla questa risposta per esempio: https://superuser.com/a/894748/432100

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.