Come chiamare uno script di shell da un altro script di shell?


739

Ho due script di shell a.she b.sh.

Come posso chiamare b.shdall'interno dello script della shell a.sh?


8
Puoi dare alcuni dettagli: quale sistema operativo e quale shell (s) o stai solo parlando di quel problema in linea di principio ?? Anche il codice di esempio sarebbe utile.
jsalonen,

14
Questa non è davvero una domanda specifica né dimostra uno sforzo precedente per risolvere il problema.
Kris,

1
Un problema che stavo avendo era che b.shnon aveva permessi eseguibili. Potrebbe essere una buona cosa da controllare.
seth10

Aggiungi ./prima del nome dello script, ad esempio, invece b.sh./b.sh
Benny

1
Se qualcuno continua a No such file or directoryerrore stackoverflow.com/a/2920431/1356559
Amr Lotfy

Risposte:


959

Ci sono un paio di modi diversi per farlo:

  1. Rendi eseguibile l'altro script, aggiungi la #!/bin/bashriga in alto e il percorso in cui il file si trova nella variabile di ambiente $ PATH. Quindi puoi chiamarlo come un normale comando;

  2. Oppure chiamalo con il sourcecomando (alias is .) in questo modo source /path/to/script:;

  3. Oppure utilizzare il bashcomando per eseguirlo: /bin/bash /path/to/script;

Il primo e il terzo metodo eseguono lo script come un altro processo, quindi le variabili e le funzioni nell'altro script non saranno accessibili.
Il secondo metodo esegue lo script nel processo del primo script e inserisce variabili e funzioni dall'altro script in modo che siano utilizzabili dallo script chiamante.

Nel secondo metodo, se si utilizza exitnel secondo script, uscirà anche il primo script. Che non accadrà con il primo e il terzo metodo.


30
ricordati di chmod a+x /path/to/filealtrimenti non sarà eseguibile. Si applica solo al metodo ./script.
Nathan Lilienthal,

3
Ricorda di cambiare formato / codifica dei file eseguibili in unix se vengono creati in DOS e quindi caricati in ambiente unix -> dos2unix <nome script>
Abhishek Chatterjee

3
@cecemel Il primo e il terzo modo potrebbero essere "asincroni" usando la normale sintassi run-in-background.
Qualche programmatore, amico,

16
Il problema sourceè che exitun'istruzione nello script chiamato uscirà anche dalla tua ...
Ohad Schneider,

18
@ user528025 .non è un alias per source, ma piuttosto il contrario. sourceè un'estensione bash, mentre .funziona in qualsiasi shell POSIX compatibile.
Score_Under

207

Controllalo.

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."

4
Ciò presuppone che script.sh sia nella stessa directory di qualunque script sia in esecuzione. Se volessi chiamare una sceneggiatura da qualche altra parte, direstish <path to script>/script.sh
Morgan Kenyon il

32
Questo utilizza anche due shell bashe sh. Anche quando shin realtà bashnon si comporta allo stesso modo. Se stai usando #!/bin/bash, probabilmente vorrai usare bash script.sh(o semplicemente ./script.shusare l'hashbang di quegli script).
Martin Tournoij,

1
Continuo a ottenere l'autorizzazione negata errore anche quando ho impostato il chmod +xfile .sh. Eventuali suggerimenti?
Isaac cala il

@isaacweathers provare chmod 777
Janac Meena il

114

Ci sono un paio di modi per farlo. Terminale per eseguire lo script:

#!/bin/bash
SCRIPT_PATH="/path/to/script.sh"

# Here you execute your script
"$SCRIPT_PATH"

# or
. "$SCRIPT_PATH"

# or
source "$SCRIPT_PATH"

# or
bash "$SCRIPT_PATH"

# or
eval '"$SCRIPT_PATH"'

# or
OUTPUT=$("$SCRIPT_PATH")
echo $OUTPUT

# or
OUTPUT=`"$SCRIPT_PATH"`
echo $OUTPUT

# or
("$SCRIPT_PATH")

# or
(exec "$SCRIPT_PATH")

Tutto questo è corretto per il percorso con spazi !!!


41
Quali sono le loro differenze? Perché uno, perché un altro?
rocketspacer

. È preferito "$ SCRIPT_PATH"
Harry Mumford-Turner,

1
Posso solo aggiungere che questi non sono tutti equivalenti, ad esempio sh "$ SCRIPT_PATH" e bash "$ SCRIPT_PATH" non eseguirà lo script #! / Usr / bin / prevedono, mentre lo farà solo "$ SCRIPT_PATH".
Tahlor,

58

La risposta che stavo cercando:

( exec "path/to/script" )

Come accennato, execsostituisce la shell senza creare un nuovo processo. Tuttavia , possiamo metterlo in una subshell, che viene eseguita usando le parentesi.

EDIT: in realtà ( "path/to/script" )è abbastanza.


11
Questo sembra piuttosto contorto. Perché non chiamarlo con /path/to/script? Non vedo la necessità di execqui?
Martin Tournoij,

La subshell non è necessaria neanche perché non lo stai utilizzando exec.
Karel Vlk,

6
come eseguiresti questo script con argomenti?
Bhargav,

Se vuoi ancora catturare l'output del sub-script prova $ (sorgente "percorso / to / script")
cmcginty

@Bhargav segui questo link stackoverflow.com/questions/14302389/...
tpbafk

16

Dipende da. Brevemente ... Se vuoi caricare variabili sulla console corrente ed eseguire puoi usare source myshellfile.shil tuo codice. Esempio:

!#/bin/bash
set -x
echo "This is an example of run another INTO this session."
source my_lib_of_variables_and_functions.sh
echo "The function internal_function() is defined into my lib."
returned_value=internal_function()
echo $this_is_an_internal_variable

set +x

Se vuoi solo eseguire un file e l'unica cosa interessante per te è il risultato, puoi fare:

!#/bin/bash
set -x
./executing_only.sh
sh i_can_execute_this_way_too.sh
bash or_this_way.sh
set +x

Spero ti aiuti. Grazie.


2
Si noti che sourceè una funzione specifica per bash. La shell bourne standard ha solo .(ad esempio . other_script.sh).
Martin Tournoij,

15

Puoi usare /bin/shper chiamare o eseguire un altro script (tramite il tuo script reale):

 # cat showdate.sh
 #!/bin/bash
 echo "Date is: `date`"

 # cat mainscript.sh
 #!/bin/bash
 echo "You are login as: `whoami`"
 echo "`/bin/sh ./showdate.sh`" # exact path for the script file

L'output sarebbe:

 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013

1
Sicuramente questo funzionerà showdate.shsotto / bin / sh piuttosto che / bin / bash?
Chris Watts,

ho provato con " /bin/sh ./showdate.sh", " /bin/bash ./showdate.sh", " ./showdate.sh" ed ho eseguito il file: mainscript.sh e ho ottenuto lo stesso output.
Ranjithkumar T,

10

Basta aggiungere in una riga qualunque cosa tu abbia digitato in un terminale per eseguire lo script!
per esempio:

#!bin/bash
./myscript.sh &

se lo script da eseguire non si trova nella stessa directory, basta usare il percorso completo dello script.
ad esempio: `/ home / user / directory-script /./ myscript.sh &


@Carpetsmoker &per attività in background
Andrei Krasutski,

9

Per prima cosa devi includere il file che chiami:

#!/bin/bash
. includes/included_file.sh

quindi chiamate la vostra funzione in questo modo:

#!/bin/bash
my_called_function

9

La fonte semplice ti aiuterà. Per es.

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"

9

Se hai un altro file nella stessa directory, puoi fare:

bash another_script.sh

o

source another_script.sh

o

. another_script.sh

Quando si utilizza bashinvece di source, lo script non può modificare l'ambiente dello script principale. Il .comando è POSIX standard mentre sourcecommand è un sinonimo bash più leggibile per .(preferisco sourceover .). Se il tuo script risiede altrove, basta fornire il percorso a quello script. Sia il percorso relativo che quello completo dovrebbero funzionare.


5

La risposta in alto suggerisce di aggiungere una #!/bin/bashriga alla prima riga del sotto-script chiamato. Ma anche se aggiungi lo shebang, è molto più veloce * eseguire uno script in una sotto-shell e catturare l'output:

$(source SCRIPT_NAME)

Funziona quando si desidera continuare a eseguire lo stesso interprete (ad es. Da bash a un altro script bash) e garantisce che la riga shebang dello script secondario non venga eseguita.

Per esempio:

#!/bin/bash
SUB_SCRIPT=$(mktemp)
echo "#!/bin/bash" > $SUB_SCRIPT
echo 'echo $1' >> $SUB_SCRIPT
chmod +x $SUB_SCRIPT
if [[ $1 == "--source" ]]; then
  for X in $(seq 100); do
    MODE=$(source $SUB_SCRIPT "source on")
  done
else
  for X in $(seq 100); do
    MODE=$($SUB_SCRIPT "source off")
  done
fi
echo $MODE
rm $SUB_SCRIPT

Produzione:

~ ❯❯❯ time ./test.sh
source off
./test.sh  0.15s user 0.16s system 87% cpu 0.360 total

~ ❯❯❯ time ./test.sh --source
source on
./test.sh --source  0.05s user 0.06s system 95% cpu 0.114 total

* Ad esempio, quando un dispositivo antivirus o di sicurezza è in esecuzione su un dispositivo, potrebbero essere necessari altri 100 ms per eseguire un nuovo processo.


4
pathToShell="/home/praveen/"   
chmod a+x $pathToShell"myShell.sh"
sh $pathToShell"myShell.sh"

4
 #!/bin/bash

 # Here you define the absolute path of your script

 scriptPath="/home/user/pathScript/"

 # Name of your script

 scriptName="myscript.sh"

 # Here you execute your script

 $scriptPath/$scriptName

 # Result of script execution

 result=$?

1
errato per scriptPathil nome della cartella o del file scriptNamecon spazi
Andrei Krasutski

3

Supponiamo che il nuovo file sia "/ home / satya / app / app_specific_env" e che il contenuto del file sia il seguente

#!bin/bash

export FAV_NUMBER="2211"

Aggiungi questo riferimento al file ~ / .bashrc

source /home/satya/app/app_specific_env

Ogni volta che riavvii la macchina o accedi nuovamente, prova echo $FAV_NUMBER nel terminale. Produrrà il valore.

Nel caso in cui si desideri vedere subito l'effetto, source ~/.bashrcnella riga di comando.


3
chmod a+x /path/to/file-to-be-executed

Questa era l'unica cosa di cui avevo bisogno. Una volta che lo script da eseguire è reso eseguibile in questo modo, tu (almeno nel mio caso) non hai bisogno di altre operazioni extra come sho ./mentre stai chiamando lo script.

Grazie al commento di @Nathan Lilienthal


1

Ci sono alcuni problemi per importare funzioni da altri file.
Primo : non è necessario eseguire questo file eseguibile. Meglio non farlo! basta aggiungere

. file

per importare tutte le funzioni. E tutti saranno come se fossero definiti nel tuo file.
Secondo : è possibile definire la funzione con lo stesso nome. Sarà sovrascritto. È cattivo. Puoi dichiarare così

declare -f new_function_name=old_function_name 

e solo dopo ciò importa. Quindi puoi chiamare la vecchia funzione con un nuovo nome.
Terzo : è possibile importare solo l'elenco completo delle funzioni definite nel file. Se alcuni non sono necessari, è possibile annullarli. Ma se riscrivi le tue funzioni dopo averle disattivate, andranno perse. Ma se si imposta il riferimento come descritto sopra, è possibile ripristinare dopo non impostato con lo stesso nome.
FinalmenteNella procedura comune di importazione è pericoloso e non così semplice. Stai attento! Puoi scrivere uno script per farlo in modo più semplice e sicuro. Se usi solo una parte delle funzioni (non tutte) meglio dividerle in file diversi. Purtroppo questa tecnica non ha funzionato bene in bash. In python per esempio e in alcuni altri linguaggi di script è facile e sicuro. È possibile effettuare l'importazione parziale solo delle funzioni necessarie con i propri nomi. Vogliamo tutti che nelle prossime versioni di Bush si ottenga la stessa funzionalità. Ma ora dobbiamo scrivere molti altri codici in modo da fare quello che vuoi.


(Benvenuti in SO!) Come visto per la prima volta l' utente Praveen nel 2011, è difficile stabilire se la domanda era come far eseguire la shell a.sh a eseguire b.sh (e continuare a eseguire a.sh in caso contrario) comandato altrimenti ), o letteralmente b.sh chiamata . (Il mio correttore ortografico non funziona bush versions.) (Hai qualcuno a cui rivolgersi per aiutarti con la grammatica inglese? (A volte vorrei averlo fatto.))
Barbabianca

0

Usa i backtick.

$ ./script-that-consumes-argument.sh `sh script-that-produces-argument.sh`

Quindi recupera l'output dello script del produttore come argomento sullo script del consumatore.

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.