Comment appeler un script shell à partir d'un autre script shell?

739

J'ai deux scripts shell, a.shet b.sh.

Comment puis-je appeler à b.shpartir du script shell a.sh?

Praveen
la source
8
Pouvez-vous donner quelques détails: quel système d'exploitation et quel (s) shell (s) ou parlez-vous simplement de ce problème en principe ?? Un exemple de code serait également utile.
jsalonen
14
Il ne s'agit pas vraiment d'une question spécifique ni d'un effort préalable pour résoudre le problème.
Kris
1
Un problème que je rencontrais était qu'il b.shn'avait pas d'autorisations exécutables. Ce pourrait être une bonne chose à vérifier.
seth10
Ajouter ./avant le nom du script, par exemple, à la place b.sh./b.sh
Benny
1
Si quelqu'un continue d'avoir des No such file or directoryerreurs stackoverflow.com/a/2920431/1356559
Amr Lotfy

Réponses:

959

Il existe plusieurs façons de procéder:

  1. Rendez l'autre script exécutable, ajoutez la #!/bin/bashligne en haut et le chemin d'accès du fichier à la variable d'environnement $ PATH. Ensuite, vous pouvez l'appeler comme une commande normale;

  2. Ou appelez-le avec la sourcecommande (alias is .) comme ceci source /path/to/script:;

  3. Ou utilisez la bashcommande pour l' exécuter: /bin/bash /path/to/script;

Les première et troisième méthodes exécutent le script comme un autre processus, les variables et fonctions de l'autre script ne seront donc pas accessibles.
La deuxième méthode exécute le script dans le processus du premier script et extrait les variables et les fonctions de l'autre script afin qu'elles soient utilisables à partir du script appelant.

Dans la deuxième méthode, si vous utilisez exitdans le deuxième script, il quittera également le premier script. Ce qui ne se produira pas dans les première et troisième méthodes.

Certains programmeurs
la source
30
rappelez-vous chmod a+x /path/to/filesinon il ne sera pas exécutable. S'applique uniquement à la méthode ./script.
Nathan Lilienthal
3
N'oubliez pas de changer le format / l'encodage des fichiers exécutables sous Unix s'ils sont créés sous DOS puis téléchargés dans l'environnement Unix -> dos2unix <nom du script>
Abhishek Chatterjee
3
@cecemel La première et la troisième façon pourraient être "async" en utilisant la syntaxe normale en arrière-plan.
Un programmeur
16
Le problème sourceest qu'une exitinstruction dans le script appelé quittera également la vôtre ...
Ohad Schneider
18
@ user528025 .n'est pas un alias pour source, mais plutôt l'inverse. sourceest une extension bash, tout en .fonctionnant dans n'importe quel shell compatible POSIX.
Score_Under
207

Regarde ça.

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."
Budha
la source
4
Cela suppose que script.sh se trouve dans le même répertoire que le script en cours d'exécution. Si vous vouliez appeler un script ailleurs, vous diriezsh <path to script>/script.sh
Morgan Kenyon
32
Cela utilise également deux coquilles bashet sh. Même quand shc'est en fait bashça ne se comporte pas de la même façon. Si vous utilisez, #!/bin/bashvous voulez probablement utiliser bash script.sh(ou simplement ./script.shutiliser le hashbang de ces scripts).
Martin Tournoij
1
Erreur d'obtention de l'autorisation refusée même lorsque j'ai défini le chmod +xfichier .sh. Aucune suggestion?
isaac weathers
@isaacweathers essayez chmod 777
Janac Meena
114

Il existe plusieurs façons de procéder. Terminal pour exécuter le 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")

Tout cela est correct pour le chemin avec des espaces !!!

Andrei Krasutski
la source
41
Quelles sont leurs différences? Pourquoi un, pourquoi un autre?
rocketspacer
. "$ SCRIPT_PATH" est préféré
Harry Mumford-Turner
1
Je peux simplement ajouter que ceux-ci ne sont pas tous équivalents, par exemple sh "$ SCRIPT_PATH" et bash "$ SCRIPT_PATH" ne fonctionneront pas le script #! / Usr / bin / expect, alors que "$ SCRIPT_PATH" le fera.
Tahlor
58

La réponse que je cherchais:

( exec "path/to/script" )

Comme mentionné, execremplace le shell sans créer de nouveau processus. toutefois , nous pouvons le mettre dans un sous-shell, ce qui se fait en utilisant les parenthèses.

EDIT: En fait, ( "path/to/script" )c'est suffisant.

Maxim Chetrusca
la source
11
Cela semble assez compliqué. Pourquoi ne pas simplement l'appeler avec /path/to/script? Je ne vois pas du tout la nécessité execici?
Martin Tournoij
Le sous-shell n'est pas nécessaire non plus puisque vous ne l'êtes pas exec.
Karel Vlk
6
comment exécuteriez-vous ce script avec des arguments?
Bhargav
Si vous voulez toujours capturer la sortie du sous-script, essayez $ (source "path / to / script")
cmcginty
@Bhargav suivez ce lien stackoverflow.com/questions/14302389/…
tpbafk
16

Dépend de. En bref ... Si vous voulez charger des variables sur la console actuelle et les exécuter, vous pouvez les utiliser source myshellfile.shsur votre code. Exemple:

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

Si vous voulez simplement exécuter un fichier et que la seule chose qui vous intéresse est le résultat, vous pouvez faire:

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

J'espère que cela vous aide. Merci.

Douglas Bonafé
la source
2
Notez qu'il sources'agit d'une fonctionnalité spécifique à bash. Le shell bourne standard a seulement .(par exemple . other_script.sh).
Martin Tournoij
15

Vous pouvez utiliser /bin/shpour appeler ou exécuter un autre script (via votre script réel):

 # 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

La sortie serait:

 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013
Ranjithkumar T
la source
1
Cela fonctionnera sûrement showdate.shsous / bin / sh plutôt que / bin / bash?
Chris Watts
j'ai essayé avec " /bin/sh ./showdate.sh", " /bin/bash ./showdate.sh", " ./showdate.sh" et exécuter le fichier: mainscript.sh et obtenu la même sortie.
Ranjithkumar T
10

Ajoutez simplement dans une ligne ce que vous auriez tapé dans un terminal pour exécuter le script!
par exemple:

#!bin/bash
./myscript.sh &

si le script à exécuter ne se trouve pas dans le même répertoire, utilisez simplement le chemin complet du script.
par exemple: `/ home / user / script-directory /./ myscript.sh &

Anon
la source
@Carpetsmoker &pour tâche de fond
Andrei Krasutski
9

Vous devez d'abord inclure le fichier que vous appelez:

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

alors vous appelez votre fonction comme ceci:

#!/bin/bash
my_called_function
Ghazi Triki
la source
9

Une source simple vous aidera. Pour Ex.

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"
Nitin Jawarkar
la source
9

Si vous avez un autre fichier dans le même répertoire, vous pouvez soit:

bash another_script.sh

ou

source another_script.sh

ou

. another_script.sh

Lorsque vous utilisez bashau lieu de source, le script ne peut pas modifier l'environnement du script parent. La .commande est la norme POSIX tandis que la sourcecommande est un synonyme bash plus lisible pour .(je préfère sourceplus .). Si votre script réside ailleurs, indiquez simplement le chemin d'accès à ce script. Le chemin relatif et le chemin complet devraient fonctionner.

Shital Shah
la source
5

La première réponse suggère d'ajouter une #!/bin/bashligne à la première ligne du sous-script appelé. Mais même si vous ajoutez le shebang, il est beaucoup plus rapide * d'exécuter un script dans un sous-shell et de capturer la sortie:

$(source SCRIPT_NAME)

Cela fonctionne lorsque vous souhaitez continuer à exécuter le même interpréteur (par exemple de bash vers un autre script bash) et garantit que la ligne shebang du sous-script n'est pas exécutée.

Par exemple:

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

Production:

~ ❯❯❯ 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

* Par exemple, lorsque des virus ou des outils de sécurité s'exécutent sur un appareil, cela peut prendre 100 ms supplémentaires pour exécuter un nouveau processus.

cmcginty
la source
4
pathToShell="/home/praveen/"   
chmod a+x $pathToShell"myShell.sh"
sh $pathToShell"myShell.sh"
Abdennour TOUMI
la source
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=$?
Valero
la source
1
incorrect pour le scriptPathnom du dossier ou du fichier scriptNameavec des espaces
Andrei Krasutski
3

Supposons que le nouveau fichier est "/ home / satya / app / app_specific_env" et que le contenu du fichier est le suivant

#!bin/bash

export FAV_NUMBER="2211"

Ajoutez cette référence de fichier au fichier ~ / .bashrc

source /home/satya/app/app_specific_env

Chaque fois que vous redémarrez la machine ou vous reconnectez, essayez echo $FAV_NUMBERdans le terminal. Il affichera la valeur.

Au cas où vous voudriez voir l'effet immédiatement, source ~/.bashrcdans la ligne de commande.

Satya Kalluri
la source
3
chmod a+x /path/to/file-to-be-executed

C'était la seule chose dont j'avais besoin. Une fois que le script à exécuter est rendu exécutable comme ceci, vous (du moins dans mon cas) n'avez besoin d'aucune autre opération supplémentaire comme shou ./pendant que vous appelez le script.

Merci au commentaire de @Nathan Lilienthal

Asqan
la source
1

Il y a quelques problèmes pour importer des fonctions à partir d'un autre fichier.
Premièrement : vous n'avez pas besoin de faire ce fichier exécutable. Mieux vaut ne pas le faire! Ajoutez simplement

. file

pour importer toutes les fonctions. Et tous seront comme s'ils étaient définis dans votre fichier.
Deuxièmement : vous pouvez définir la fonction avec le même nom. Il sera écrasé. C'est mauvais. Vous pouvez déclarer comme ça

declare -f new_function_name=old_function_name 

et seulement après cela, importez. Vous pouvez donc appeler l'ancienne fonction par un nouveau nom.
Troisièmement : vous ne pouvez importer que la liste complète des fonctions définies dans le fichier. Si certains ne sont pas nécessaires, vous pouvez les désactiver. Mais si vous réécrivez vos fonctions après leur désactivation, elles seront perdues. Mais si vous lui définissez une référence comme décrit ci-dessus, vous pouvez restaurer après unset avec le même nom.
finalementDans la procédure courante d'importation, il est dangereux et pas si simple. Faites attention! Vous pouvez écrire un script pour le faire plus facilement et en toute sécurité. Si vous n'utilisez qu'une partie des fonctions (pas toutes), mieux vaut les diviser en différents fichiers. Malheureusement cette technique n'a pas bien fonctionné en bash. En python par exemple et dans d'autres langages de script, c'est simple et sûr. Possibilité de faire de l'importation partielle uniquement les fonctions nécessaires avec ses propres noms. Nous voulons tous que dans les prochaines versions de bush, la même fonctionnalité soit exécutée. Mais maintenant, nous devons écrire beaucoup de morue supplémentaire pour faire ce que vous voulez.

Anatoly
la source
(Bienvenue à SO!) En tant qu'utilisateur Praveen a été vu pour la dernière fois en 2011, il est difficile de déterminer si la question était de savoir comment faire en sorte que le shell exécutant a.sh exécute b.sh (et continue à exécuter a.sh sinon commandé autrement ), ou littéralement b.sh appel . (Mon vérificateur d'orthographe n'attrape pas bush versions.) (Avez-vous quelqu'un vers qui vous tourner pour vous aider avec la grammaire anglaise? (J'aimerais parfois l'avoir.))
greybeard
0

Utilisez des backticks.

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

Récupérez ensuite la sortie du script producteur comme argument sur le script consommateur.

dacabdi
la source