2009-12-11 15:24:17 +0000 2009-12-11 15:24:17 +0000
302
302

Wat is het verschil tussen het uitvoeren van een Bash script en het sourcen ervan?

Wat is het verschil tussen het uitvoeren van een Bash-script als A en het sourcen van een Bash-script als B?

A
> ./myscript

B
> source myscript

Antwoorden (6)

369
369
369
2010-08-16 21:58:48 +0000

Sourcing een script voert de commando’s uit in het huidige commandoregelproces.

Uitvoeren een script zal de commando’s in een nieuw shell proces uitvoeren.

Gebruik source als je wilt dat het script de omgeving in je huidige shell verandert. Gebruik anders execute.

Als je nog steeds in de war bent, lees dan verder.

Terminologie

Om wat verwarring op te helderen over de syntaxis voor execute en source:

./myscript

Dit zal Uitvoeren myscript mits het bestand uitvoerbaar is en zich in de huidige directory bevindt. De voorlopende punt en schuine streep (./) geven de huidige directory aan. Dit is nodig omdat de huidige directory meestal niet in $PATH staat (en meestal ook niet zou moeten staan).

myscript

Dit Uitvoeren myscript als het bestand uitvoerbaar is en zich in een directory in $PATH bevindt.

source myscript

Dit bron myscript. Het bestand hoeft niet uitvoerbaar te zijn, maar het moet wel een geldig shell script zijn. Het bestand kan in de huidige directory staan of in een directory in $PATH.

. myscript

Dit zal ook source myscript. Deze “spelling” is de officiële zoals gedefinieerd door POSIX . Bash heeft source gedefinieerd als een alias voor de punt.

Demonstratie

Beschouw myscript.sh met de volgende inhoud:

#!/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

Voordat we het script uitvoeren, controleren we eerst de huidige omgeving:

$ env | grep FOO
$ echo $PWD
/home/lesmana

De variabele FOO is niet gedefinieerd en we zijn in de homedirectory.

Nu Uitvoeren we het bestand:

$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Controleer de omgeving opnieuw:

$ env | grep FOO
$ echo $PWD
/home/lesmana

De variabele FOO is niet gedefinieerd en de werkdirectory is niet gewijzigd.

De uitvoer van het script laat duidelijk zien dat de variabele is ingesteld en dat de directory is gewijzigd. De controle achteraf laat zien dat de variabele niet is ingesteld en de map niet is gewijzigd. Wat is er gebeurd? De wijzigingen werden aangebracht in een nieuwe commandoregel. De huidige shell spawnde een nieuwe shell om het script uit te voeren. Het script wordt uitgevoerd in de nieuwe shell en alle wijzigingen in de omgeving worden van kracht in de nieuwe shell. Nadat het script klaar is, wordt de nieuwe shell vernietigd. Alle veranderingen aan de omgeving in de nieuwe shell worden vernietigd met de nieuwe shell. Alleen de uitvoertekst wordt in de huidige shell afgedrukt.

Nu sourcen we het bestand:

$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Controleer de omgeving opnieuw:

$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir

De variabele FOO is ingesteld en de werkdirectory is gewijzigd.

Het sourcen van het script maakt geen nieuwe commandoregel aan. Alle commando’s worden uitgevoerd in de huidige shell en wijzigingen in de omgeving worden van kracht in de huidige shell.

Merk op dat in dit eenvoudige voorbeeld de uitvoer van het uitvoeren hetzelfde is als het sourcen van het script. Dit is niet noodzakelijkerwijs altijd het geval.

Een andere demonstratie

Beschouw het volgende script pid.sh:

#!/bin/sh
echo $$

(de speciale variabele $$ expandeert tot de PID van het huidige draaiende shellproces)

Druk eerst de PID van de huidige shell af:

$ echo $$
25009

Bron het script:

$ source pid.sh
25009

Voer het script uit, noteer de PID:

$ ./pid.sh
25011

Bron opnieuw:

$ source pid.sh
25009

Voer opnieuw uit:

$ ./pid.sh
25013

Je kunt zien dat het sourcen van het script in hetzelfde proces draait, terwijl het uitvoeren van het script iedere keer een nieuw proces creëert. Dat nieuwe proces is de nieuwe commandoregel die is aangemaakt voor de uitvoering van het script. Sourcing van het script maakt geen nieuwe commandoregel aan en dus blijft de PID hetzelfde.

Samenvatting

Zowel het sourcen als het uitvoeren van het script voert de commando’s in het script regel voor regel uit, alsof je die commando’s regel voor regel met de hand hebt ingetypt.

De verschillen zijn:

  • Wanneer je het script uitvoert, open je een nieuwe commandoregel, typ je de commando’s in de nieuwe commandoregel, kopieer je de uitvoer terug naar je huidige commandoregel, en sluit je de nieuwe commandoregel. Alle veranderingen aan de omgeving worden alleen in de nieuwe shell doorgevoerd en gaan verloren zodra de nieuwe shell wordt gesloten.
  • Wanneer je het script sourcet typ je de commando’s in je huidige shell. Alle veranderingen aan de omgeving worden van kracht en blijven in je huidige shell.

Gebruik source als je wilt dat het script de omgeving in je huidige shell verandert. Gebruik anders execute.


Zie ook:

23
23
23
2009-12-11 15:35:56 +0000

Het uitvoeren van een script voert het uit in een apart child proces, dat wil zeggen dat een aparte instantie van shell wordt aangeroepen om het script te verwerken. Dit betekent dat omgevingsvariabelen etc., gedefinieerd in het script, niet kunnen worden bijgewerkt in de bovenliggende (huidige) shell.

Een script sourcen betekent dat het wordt geparsed en uitgevoerd door de huidige shell zelf. Het is alsof je de inhoud van het script intypt. Om deze reden hoeft het script dat gesourced wordt niet uitvoerbaar te zijn. Maar het moet natuurlijk wel uitvoerbaar zijn als je het uitvoert.

Als je positionele argumenten hebt in de huidige shell, blijven ze ongewijzigd.

Dus als ik een bestand a.sh heb met daarin:

echo a $*

en ik doe:

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

dan krijg ik zoiets als:

a Fri Dec 11 07:34:17 PST 2009

Overwegende dat:

$ set `date`
$ ./a.sh

geeft me:

a

Hoop dat dat helpt.

9
9
9
2009-12-11 15:27:08 +0000

sourcen is in wezen hetzelfde als elke regel van het script één voor één intypen op de opdrachtprompt…

Execution start een nieuw proces en voert dan elke regel van het script uit, waarbij alleen de huidige omgeving wordt gewijzigd door wat het teruggeeft.

6
6
6
2012-02-23 07:27:43 +0000

Naast het bovenstaande vereist het uitvoeren van het script als ./myscript execute permissie voor het bestand myscript terwijl sourcen geen execute permissie vereist. Daarom is chmod +x myscript niet nodig voor source myscript

5
5
5
2009-12-11 15:25:38 +0000

Met broncode krijg je alle extra variabelen die in het script gedefinieerd zijn.
Dus als je configs of functie definities hebt moet je sourcen en niet uitvoeren. Uitvoeringen zijn onafhankelijk van de omgeving van de ouders.

2
2
2
2015-03-27 14:04:20 +0000

source commando voert het geleverde script uit (uitvoerbare toestemming is niet verplicht ) in de huidige shell-omgeving, terwijl ./ het geleverde uitvoerbare script in een nieuwe shell uitvoert.

Bekijk ook dit antwoord als voorbeeld: https://superuser.com/a/894748/432100