L'unica grande differenza è tra l'approvvigionamento e l'esecuzione di uno script. source foo.shlo procurerà e tutti gli altri esempi che mostri sono in esecuzione. Più in dettaglio:
./file.sh
Questo eseguirà uno script chiamato file.shche si trova nella directory corrente ( ./). Normalmente, quando si esegue command, la shell cercherà tra le directory in $PATHun file eseguibile chiamato command. Se si fornisce un percorso completo, come /usr/bin/commando ./command, quindi $PATHviene ignorato e viene eseguito quel file specifico.
../file.sh
Questo è fondamentalmente lo stesso di ./file.shtranne che invece di cercare nella directory corrente file.sh, cerca nella directory parent ( ../).
sh file.sh
Questo equivalente a sh ./file.sh, come sopra, eseguirà lo script chiamato file.shnella directory corrente. La differenza è che lo stai eseguendo esplicitamente con la shshell. Sui sistemi Ubuntu, questo è dashe non bash. Di solito, gli script hanno una riga shebang che fornisce al programma in cui devono essere eseguiti. Chiamandoli con uno diverso si annulla quello. Per esempio:
$ cat foo.sh
#!/bin/bash
## The above is the shebang line, it points to bash
ps h -p $$ -o args='' | cut -f1 -d' ' ## This will print the name of the shell
Lo script stamperà semplicemente il nome della shell utilizzata per eseguirlo. Vediamo cosa restituisce quando viene chiamato in diversi modi:
$ bash foo.sh
bash
$ sh foo.sh
sh
$ zsh foo.sh
zsh
Quindi, chiamare chiamando uno script con shell scriptsovrascriverà la linea shebang (se presente) ed eseguirà lo script con qualunque shell tu gli dica.
source file.sh o . file.sh
Questo si chiama, abbastanza sorprendentemente, approvvigionamento della sceneggiatura. La parola chiave sourceè un alias del .comando incorporato shell . Questo è un modo per eseguire lo script all'interno della shell corrente. Normalmente, quando uno script viene eseguito, viene eseguito nella sua shell che è diversa da quella corrente. Illustrare:
$ cat foo.sh
#!/bin/bash
foo="Script"
echo "Foo (script) is $foo"
Ora, se imposto la variabile foosu qualcos'altro nella shell genitore e quindi eseguo lo script, lo script stamperà un valore diverso di foo(perché è anche impostato all'interno dello script) ma il valore di foonella shell genitore rimarrà invariato:
$ foo="Parent"
$ bash foo.sh
Foo (script) is Script ## This is the value from the script's shell
$ echo "$foo"
Parent ## The value in the parent shell is unchanged
Tuttavia, se provo lo script invece di eseguirlo, verrà eseguito nella stessa shell, quindi il valore di foonel genitore verrà modificato:
$ source ./foo.sh
Foo (script) is Script ## The script's foo
$ echo "$foo"
Script ## Because the script was sourced,
## the value in the parent shell has changed
Pertanto, il sourcing viene utilizzato nei pochi casi in cui si desidera che uno script influisca sulla shell da cui lo si esegue. In genere viene utilizzato per definire le variabili della shell e renderle disponibili al termine dello script.
Tenendo presente tutto ciò, il motivo per cui ottieni risposte diverse è, innanzitutto, che la tua sceneggiatura non fa ciò che pensi che faccia. Conta il numero di volte che bashappare nell'output di ps. Questo non è il numero di terminali aperti , è il numero di shell in esecuzione (in realtà, non è nemmeno quello, ma questa è un'altra discussione). Per chiarire, ho semplificato un po 'la tua sceneggiatura a questo:
#!/bin/bash
logname=terdon
not=`ps -au$logname | grep -c bash`
echo "The number of shells opened by $logname is $not"
Ed eseguilo in vari modi con un solo terminale aperto:
Lancio diretto, ./foo.sh.
$ ./foo.sh
The number of shells opened by terdon is 1
Qui, stai usando la linea shebang. Ciò significa che lo script viene eseguito direttamente da qualsiasi cosa sia impostata lì. Ciò influisce sul modo in cui lo script viene mostrato nell'output di ps. Invece di essere elencato come bash foo.sh, verrà mostrato solo come foo.shciò significa che grepti mancherà. In realtà ci sono 3 istanze di bash in esecuzione: il processo parent, il bash che esegue lo script e un altro che esegue il pscomando . Quest'ultimo è importante, l'avvio di un comando con sostituzione del comando ( `command`o $(command)) comporta l'avvio di una copia della shell padre e l'esecuzione del comando. Qui, tuttavia, nessuno di questi è mostrato a causa del modo in cui psmostra il suo output.
Avvio diretto con shell esplicita (bash)
$ bash foo.sh
The number of shells opened by terdon is 3
Qui, poiché stai funzionando con bash foo.sh, l'output di psverrà mostrato bash foo.she conteggiato. Quindi, qui abbiamo il processo genitore, l' bashesecuzione dello script e la shell clonata (in esecuzione ps) tutti mostrati perché ora psli mostrerà ciascuno perché il tuo comando includerà la parola bash.
Avvio diretto con una shell diversa ( sh)
$ sh foo.sh
The number of shells opened by terdon is 1
Questo è diverso perché stai eseguendo lo script con she non bash. Pertanto, l'unica bashistanza è la shell padre in cui è stato avviato lo script. shInvece, vengono eseguite tutte le altre shell menzionate sopra .
Sourcing (sia .o source, stessa cosa)
$ . ./foo.sh
The number of shells opened by terdon is 2
Come ho spiegato sopra, l'approvvigionamento di uno script provoca l'esecuzione nella stessa shell del processo padre. Tuttavia, viene avviata una subshell separata per avviare il pscomando e questo porta il totale a due.
Come nota finale, il modo corretto di contare i processi in esecuzione non è analizzare psma utilizzare pgrep. Tutti questi problemi sarebbero stati evitati se avessi appena corso
pgrep -cu terdon bash
Quindi, una versione funzionante del tuo script che stampa sempre il numero giusto è (nota l'assenza di sostituzione del comando):
#!/usr/bin/env bash
user="terdon"
printf "Open shells:"
pgrep -cu "$user" bash
Ciò restituirà 1 quando viene fornito e 2 (perché verrà lanciato un nuovo bash per eseguire lo script) per tutti gli altri modi di avvio. Restituirà comunque 1 all'avvio shpoiché il processo figlio non lo è bash.