it-swarm.it

Diversi modi per eseguire uno script Shell

Esistono diversi modi per eseguire uno script, quelli che conosco sono:

/path/to/script # using the path (absolute or relative)
. script        # using the . (dot)
source script   # using the `source` command

Sono più di questo? Quali sono le differenze tra loro? Ci sono situazioni che devo usare una e non un'altra?

44
phunehehe

Un altro modo è quello di chiamare l'interprete e passandogli il percorso dello script:

/bin/sh /path/to/script

Il punto e la sorgente sono equivalenti. (EDIT: no, non lo sono: come sottolinea KeithB in un commento su un'altra risposta, "." Funziona solo con shell correlate a bash, dove "source" funziona con shell sia bash che csh.) Esegue lo script in -place (come se avessi copiato e incollato lo script proprio lì). Ciò significa che restano tutte le funzioni e le variabili non locali nello script. Significa anche se lo script fa un cd in una directory, sarai ancora lì quando avrà finito.

Gli altri modi di eseguire uno script lo eseguiranno nella sua stessa shell secondaria. Le variabili nello script non sono ancora vive al termine. Se lo script ha cambiato directory, non influisce sull'ambiente chiamante.

/ path/to/script e/bin/sh script sono leggermente diversi. In genere, una sceneggiatura all'inizio ha uno "Shebang" che assomiglia a questo:

#! /bin/bash

Questo è il percorso dell'interprete di script. Se specifica un interprete diverso da quello che fai quando lo esegui, allora potrebbe comportarsi diversamente (o potrebbe non funzionare affatto).

Ad esempio, gli script Perl e Ruby iniziano con (rispettivamente):

#! /bin/Perl

e

#! /bin/Ruby

Se esegui uno di questi script eseguendo /bin/sh script, quindi non funzioneranno affatto.

Ubuntu in realtà non usa la shell bash, ma molto simile chiamata dash. Gli script che richiedono bash potrebbero funzionare in modo leggermente errato quando vengono chiamati facendo /bin/sh script perché hai appena chiamato uno script bash usando l'interprete trattino.

Un'altra piccola differenza tra la chiamata diretta dello script e il passaggio del percorso dello script all'interprete è che lo script deve essere contrassegnato come eseguibile per eseguirlo direttamente, ma non per eseguirlo passando il percorso all'interprete.

Un'altra variante minore: puoi aggiungere un prefisso a uno di questi modi per eseguire uno script con eval, quindi puoi avere

eval sh script
eval script
eval . script

e così via. In realtà non cambia nulla, ma ho pensato di includerlo per completezza.

32
Shawn J. Goff

La maggior parte delle persone esegue il debug degli script Shell aggiungendo i seguenti flag di debug allo script:

set -x     # Print command traces before executing command.
set -v     # Prints Shell input lines as they are read.
set -xv    # Or do both

Ma questo significa che devi aprire il file con un editor (supponendo che tu abbia i permessi per modificare il file), aggiungendo una riga come set -x, salva il file, quindi esegui il file. Quindi, quando hai finito, devi seguire gli stessi passaggi e rimuovere set -x, ecc. ecc. Questo può essere noioso.

Invece di fare tutto ciò, è possibile impostare i flag di debug sulla riga di comando:

$ bash -x ~/bin/ducks
+ du -cks -x dir1 dir2 dir3 file1 file2 file3
+ sort -n
+ tail .ducks
123 etc
424 bin
796 total



$ sh -xv ~/bin/ducks  
#!/usr/bin/env bash

# Find the disk hog
# Borrowed from http://oreilly.com/pub/h/15
...
...
9
Stefan Lasiewski

Shawn J. Goff ha fatto molti buoni punti, ma non ha incluso l'intera storia:

Ubuntu in realtà non usa la shell bash, ma molto simile chiamata dash. Gli script che richiedono bash potrebbero funzionare in modo leggermente errato quando vengono chiamati facendo /bin/sh script perché hai appena chiamato uno script bash utilizzando l'interprete trattino.

Molti script di sistema (come in init.d, in/etc e così via) hanno uno Shebang #!/bin/sh, ma /bin/sh è in effetti un collegamento simbolico con un'altra shell - in passato /bin/bash, al giorno d'oggi /bin/dash. Ma quando uno di essi viene invocato come /bin/sh, si comportano in modo diverso, ovvero si attaccano alla modalità di compatibilità POSIX.

Come lo fanno? Bene, controllano come sono stati invocati.

Uno stesso shellscript può testare come è stato invocato e fare cose diverse, a seconda di ciò? Sì, può. Quindi il modo in cui lo invochi può sempre portare a risultati diversi, ma ovviamente è raro che ti infastidisca. :)

Come regola generale: se stai imparando una shell specifica come bash e scrivi comandi da un tutorial bash, inserisci #!/bin/bash nel titolo, non #!/bin/sh, salvo dove diversamente indicato. Altrimenti i tuoi comandi potrebbero fallire. E se non hai scritto tu stesso uno script, invocalo direttamente (./foo.sh, bar/foo.sh) invece di indovinare una shell (sh foo.sh, sh bar/foo.sh). Lo Shebang dovrebbe invocare la Shell giusta.

E qui ci sono altri due tipi di invocazione:

cat foo.sh | dash
dash < foo.sh
7
user unknown

. e source sono equivalenti in quanto non generano un sottoprocesso ma eseguono comandi nella Shell corrente. Questo è importante quando lo script imposta le variabili di ambiente o cambia la directory di lavoro corrente.

Utilizzando il percorso o assegnandolo a /bin/sh crea un nuovo processo in cui vengono eseguiti i comandi.

5
mouviciel
sh script
bash script

Sto riflettendo se ci sono più ...

. e source sono uguali. Dopo l'esecuzione, qualsiasi modifica dell'ambiente in script verrà mantenuta. Di solito, sarebbe usato per creare una libreria Bash, quindi la libreria può essere riutilizzata in molti script diversi.

Inoltre è un buon modo per mantenere la directory corrente. Se si cambia directory nello script, non verrà applicato nella Shell su cui si esegue quello script. Ma se lo si esegue per eseguirlo, dopo la chiusura dello script, la directory corrente verrà mantenuta.

2
livibetter

. e source sono almeno un po 'diversi in zsh (è quello che uso) perché

source file

Works, mentre

. file

non ha bisogno

. ./file
1
bollovan
. ./filename
# ( dot space dot slash filename )

Esegue lo script nella Shell corrente quando la directory non si trova nel percorso.

1
jrh_enginnering

" serland exec " conta come un modo diverso? Userland exec carica il codice e lo fa eseguire senza l'uso di una chiamata di sistema execve ().

1
Bruce Ediger