Qual è la differenza tra “source x”, “. x "e" ./x "in Bash?


11

Ho una fonte bash run.shcome segue,

#!/bin/bash
if [ $# -ne 1 ]; then
    exit
fi
...

quando lo eseguo in due modi, ci sono comportamenti diversi. Il primo modo è,

source run.sh

Chiuderà il terminale dopo l'esecuzione. Il secondo modo è

./run.sh

questo finirà semplicemente di eseguire lo script e rimarrà sul terminale. Sto chiedendo se esiste un comando per uscire da uno script bash sia per l' esecuzione source run.shche per l' ./run.shesecuzione. Ho provato returnanche io , che non funziona bene in fase di ./run.shesecuzione.

Più in generale, sono interessato al motivo per cui ciò sta accadendo e alla differenza tra l'utilizzo di "source" e "." per l'esecuzione dello script?

Risposte:


16

Prima di rispondere, penso che siano necessari alcuni chiarimenti. Analizziamo le tre righe seguenti:

source run.sh
. run.sh
./run.sh

Le prime due righe sono esattamente identiche: .in realtà è un alias per source. Quello che sourcefa è eseguire lo script della shell nel contesto corrente, quindi una chiamata a exituscirà dalla shell.

La terza linea (che è quella che ti confonde) non ha comunque nulla a che fare con le altre linee. ./run.shè solo un percorso ed è uguale a (ad esempio) /home/user/run.sho /usr/bin/something. Ricorda sempre che i comandi nella shell sono separati da uno spazio. Quindi, in questo caso, il comando non lo è ., ma lo è ./run.sh: ciò significa che verrà eseguita una sotto-shell e che exitavrà effetto solo sulla sotto-shell.


5

Tre modi:

È possibile racchiudere lo script in una funzione e utilizzare solo return.

#!/usr/bin/env bash
main() {
    ...
    return 1
    ...
}
main "$@"

È possibile verificare se lo script proviene da una shell interattiva.

if [[ $- = *i* ]]; then
    return 1
else
    exit 1
fi

Puoi provare a tornare e, se fallisce, esci.

return 1 2>/dev/null || exit 1

Qualche suggerimento su come funziona l'incantesimo magico $- = *i* ?
deadbeef404,

@ deadbeef404 Il parametro speciale -contiene i flag di opzione attualmente attivi. Il test verifica se il -iflag è attivo. Vedi gnu.org/software/bash/manual/html_node/Special-Parameters.html
geirha

1

Pensa al comando 'source' come nell'istruzione 'include'. Prende il contenuto dell'argomento e lo esegue come se fosse eseguito direttamente. In questo caso il tuo comando è 'source' con un argomento di 'run.sh' e run.sh viene eseguito esattamente come se avessi digitato il contenuto di run.sh nella tua riga di comando.

Quando esegui './run.sh', './run.sh' è il tuo comando e non ha argomenti. Dato che questo file è in chiaro e non binario, la tua shell cerca un interprete in shebang ('#!' Nella prima riga) e trova '/ bin / bash'. Quindi la shell avvia quindi una nuova istanza di bash e il contenuto di run.sh viene eseguito all'interno di questa nuova istanza.

Nel primo caso, quando bash raggiunge il comando 'exit' viene eseguito esattamente come se fosse stato digitato nella riga di comando. Nel secondo caso viene eseguito nel processo bash avviato dalla shell, quindi solo questa istanza di bash riceve un comando 'exit'.

Quando si digita una riga in bash, tutto ciò che precede il primo spazio viene trattato come un comando e tutto ciò che segue viene trattato come argomento. Il comando '.' è un alias di "fonte". Quando corri ". run.sh 'the'. ' è un comando da solo in quanto è separato dai suoi argomenti da uno spazio. Quando esegui './run.sh' il tuo comando è './run.sh' e '.' fa parte del percorso relativo di run.sh con '.' che rappresenta la cartella corrente.


Se sei un programmatore C / C ++ che cerca di migliorare con gli script shell / bash questa è la risposta perfetta.
Justin il
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.