1115

I have two shell scripts, a.sh and b.sh.

How can I call b.sh from within the shell script a.sh?

Promise Preston
  • 24,334
  • 12
  • 145
  • 143
Praveen
  • 11,459
  • 4
  • 16
  • 7
  • 9
    Can you give some specifics: which OS and which shell(s) or are you just talking about that problem in principle?? Example code would be helpful as well. – jsalonen Dec 02 '11 at 07:07
  • 19
    This is not really a specific question nor does it demonstrate prior effort to solve the issue. – Kris Jul 29 '14 at 07:37
  • 2
    One issue I was having was that `b.sh` did not have executable permissions. It might be a good thing to check. – seth10 Mar 28 '17 at 12:57
  • 2
    Append `./` before the script name, example, instead: `b.sh`, use: `./b.sh` – Benny Jul 02 '18 at 14:02
  • 2
    If anyone keeps getting `No such file or directory` error https://stackoverflow.com/a/2920431/1356559 – Amr Lotfy Aug 15 '18 at 01:10
  • 1
    What your be wrong with this solution?: Start the second script just the same way you started the first script. I'm very much surprised that this question receives such a high rating when not even the most trivial code or error message was presented in the question. – U. Windl Mar 16 '22 at 13:03

18 Answers18

1340

There are a couple of different ways you can do this:

  1. Make the other script executable with chmod a+x /path/to/file(Nathan Lilienthal's comment), add the #!/bin/bash line (called shebang) at the top, and the path where the file is to the $PATH environment variable. Then you can call it as a normal command;

  2. Or call it with the source command (which is an alias for .), like this:

    source /path/to/script
    
  3. Or use the bash command to execute it, like:

    /bin/bash /path/to/script
    

The first and third approaches execute the script as another process, so variables and functions in the other script will not be accessible.
The second approach executes the script in the first script's process, and pulls in variables and functions from the other script (so they are usable from the calling script). It will of course run all the commands in the other script, not only set variables.

In the second method, if you are using exit in second script, it will exit the first script as well. Which will not happen in first and third methods.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 6
    Remember to change format/encoding of executable files in unix if they are created in DOS and then uploaded to unix environment -> dos2unix – Abhishek Chatterjee Feb 05 '14 at 06:19
  • 4
    Also, note that the scope of each script is the top level of your project's directory - if `./.git/hooks/pre-commit` has `source foo`, you had better have `./foo`! – Athan Clark Jun 06 '15 at 02:11
  • 31
    @user528025 `.` is not an alias for `source`, but rather the other way around. `source` is a bash extension, while `.` works in any POSIX compatible shell. – Score_Under Jan 16 '16 at 21:51
  • 2
    @OhadSchneider In my case it was desirable to exit the script if the called script exited. – Danijel Dec 01 '20 at 08:36
  • `source` and the alias `.` don't pass along arguments either unless I'm missing something. I had to use `./`, `/bin/bash`, or the shorter `bash` for my use case which is passing along a dryrun flag to all subsequent scripts. – postal Apr 28 '21 at 17:39
  • Relevant: https://www.gnu.org/software/bash/manual/bash.html#Command-Execution-Environment – Roland Oct 05 '21 at 10:48
  • 1
    If both of your scripts are in the same directory, but still you are not sure [where you're calling from](https://en.wikipedia.org/wiki/Where_I%27m_Calling_From), than you will have to construct the path to your script by first finding the script dir `SCRIPT_DIRECTORY="$(dirname $(realpath "$0"))"`, and then calling it: `source $SCRIPT_DIRECTORY/script.sh`. – Danijel Apr 26 '22 at 09:45
  • I have added `~/bin` to `$PATH`. Scripts inside `~/bin` can be called as normal commands in the console. But `command not found` error if those scripts are called inside a script file. I have to use `~/bin/my_script` to call it inside a script file. – midnite Feb 10 '23 at 14:34
  • @midnite Have you tried printing `$PATH` from one of the scripts where you have this problem? And did you remember to `export PATH` after adding `~/bin`? – Some programmer dude Feb 10 '23 at 15:01
  • @Someprogrammerdude - Thank you. Two files `my_script` and `test_run` are inside `~/bin`. In console, `my_script` simply echoes some text. In `test_run`, if only one line `my_script` in the file, then call `test_run` in the console, it echoes the same text. In `test_run`, if there are two lines : `#!/bin/sh` (new line) `test_run` in the file, calling `test_run` in the console, it gives `/root/bin/test_run: line 2: my_script: command not found` error. – midnite Feb 10 '23 at 15:25
303

Check this out.

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."
maksimov
  • 5,792
  • 1
  • 30
  • 38
Budha
  • 3,055
  • 1
  • 12
  • 2
  • 6
    This assumes that script.sh is in the same directory as the whatever script is running. If you wanted to call a script somewhere else, you would say `sh /script.sh` – Morgan Kenyon Aug 21 '15 at 20:32
  • 74
    This also uses *two* shells, `bash` and `sh`. Even when `sh` is in fact `bash` it doesn't behave the same. If you're using `#!/bin/bash` then you probably want to use `bash script.sh` (or just `./script.sh` to use that scripts's hashbang). – Martin Tournoij Nov 14 '16 at 07:47
  • 1
    Kept getting permission denied error even when I set the `chmod +x` to the .sh file. Any suggestions? – isaac weathers Nov 15 '16 at 07:09
  • 1
    @isaacweathers try chmod 777 – Janac Meena Apr 22 '20 at 15:45
  • 1
    @isaacweathers This indicates your user is not authorized, so you need to use sudo as in `sudo chmod +x` – not2savvy Jul 16 '21 at 08:50
  • For the difference between `sh` and `bash`, you can consider some answers of [this U&L question](https://unix.stackexchange.com/a/630792/318461). For example with the read command, there is a big difference between the two. – Cadoiz Sep 26 '22 at 11:28
  • Specifyieng path is required to run *command* not in `$PATH`, but if *command* if `sh`. argument is script. There are no need to specify path (`./`): running `sh script.sh` will work – F. Hauri - Give Up GitHub Sep 26 '22 at 11:42
204

There are a couple of ways you can do this. Terminal to execute the 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")

All this is correct for the path with spaces!!!

Andrei Krasutski
  • 4,913
  • 1
  • 29
  • 35
  • 75
    What are their differences? Why one, why another? – tu4n Mar 14 '17 at 21:39
  • . "$SCRIPT_PATH" is preferred – Harry Mumford-Turner Oct 06 '17 at 11:08
  • 1
    I can just add that these are not all equivalent, e.g. sh "$SCRIPT_PATH" and bash "$SCRIPT_PATH" will not run #!/usr/bin/expect script, whereas just "$SCRIPT_PATH" will. – Tahlor Jan 23 '19 at 19:10
  • If you need to pass arguments into the second script, `"$SCRIPT_PATH"`, `source`, and `.` don't work that I can see. `./`, `/bin/bash`, or the shorter `bash` all work though. – postal Apr 28 '21 at 17:41
  • Note that 1-3 need the script to be executable while 4 for example does not. I think, this should be included/edited in the answer, right? – sb813322 Sep 26 '22 at 11:20
  • `source` is a synonym of `.`, https://unix.stackexchange.com/a/459089/21027 – maksimov Jan 13 '23 at 16:16
69

The answer which I was looking for:

( exec "path/to/script" )

As mentioned, exec replaces the shell without creating a new process. However, we can put it in a subshell, which is done using the parantheses.

EDIT: Actually ( "path/to/script" ) is enough.

Maxim Chetrusca
  • 3,262
  • 1
  • 32
  • 28
39

If you have another file in same directory, you can either do:

bash another_script.sh

or

source another_script.sh

or

. another_script.sh

When you use bash instead of source, the script cannot alter environment of the parent script. The . command is POSIX standard while source command is a more readable bash synonym for . (I prefer source over .). If your script resides elsewhere just provide path to that script. Both relative as well as full path should work.

Flinsch
  • 4,296
  • 1
  • 20
  • 29
Shital Shah
  • 63,284
  • 17
  • 238
  • 185
21

Depends on. Briefly... If you want load variables on current console and execute you may use source myshellfile.sh on your code. Example:

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

If you just want to execute a file and the only thing intersting for you is the result, you can do:

#!/bin/bash
set -x
./executing_only.sh
bash i_can_execute_this_way_too.sh
bash or_this_way.sh
set +x
Cadoiz
  • 1,446
  • 21
  • 31
Douglas Bonafé
  • 311
  • 2
  • 2
  • 3
    Note that `source` is a bash-specific feature. The standard bourne shell only has `.` (e.g. `. other_script.sh`). – Martin Tournoij Nov 14 '16 at 07:49
  • For the difference between `sh` and `bash`, you can consider some answers of [this U&L question](https://unix.stackexchange.com/a/630792/318461). For example with the read command, there is a big difference between the two. – Cadoiz Sep 26 '22 at 11:33
16

You can use /bin/sh to call or execute another script (via your actual script):

 # 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

The output would be:

 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013
nbro
  • 15,395
  • 32
  • 113
  • 196
Ranjithkumar T
  • 1,886
  • 16
  • 21
  • 2
    Surely this will run `showdate.sh` under /bin/sh rather than /bin/bash? – Chris Watts Jan 06 '17 at 10:44
  • i have tried with "`/bin/sh ./showdate.sh`", "`/bin/bash ./showdate.sh`", "`./showdate.sh`" and run the file: mainscript.sh and got same output. – Ranjithkumar T May 02 '17 at 06:14
  • For the difference between `sh` and `bash`, you can consider some answers of [this U&L question](https://unix.stackexchange.com/a/630792/318461). For example with the read command, there is a big difference between the two. – sb813322 Sep 26 '22 at 11:36
13

First you have to include the file you call:

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

then you call your function like this:

#!/bin/bash
my_called_function
Torsten
  • 1,696
  • 2
  • 21
  • 42
Ghazi Triki
  • 146
  • 2
  • 4
12

Simple source will help you. For Ex.

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"
Nitin Jawarkar
  • 129
  • 1
  • 2
11

Just add in a line whatever you would have typed in a terminal to execute the script!
e.g.:

#!bin/bash
./myscript.sh &

if the script to be executed is not in same directory, just use the complete path of the script.
e.g.:`/home/user/script-directory/./myscript.sh &

ChrisF
  • 134,786
  • 31
  • 255
  • 325
Anon
  • 111
  • 1
  • 2
11

This was what worked for me, this is the content of the main sh script that executes the other one.

#!/bin/bash 
source /path/to/other.sh
subharb
  • 3,374
  • 8
  • 41
  • 72
10

The top answer suggests adding #!/bin/bash line to the first line of the sub-script being called. But even if you add the shebang, it is much faster* to run a script in a sub-shell and capture the output:

$(source SCRIPT_NAME)

This works when you want to keep running the same interpreter (e.g. from bash to another bash script) and ensures that the shebang line of the sub-script is not executed.

For example:

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

Output:

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

* For example when virus or security tools are running on a device it might take an extra 100ms to exec a new process.

cmcginty
  • 113,384
  • 42
  • 163
  • 163
5
pathToShell="/home/praveen/"   
chmod a+x $pathToShell"myShell.sh"
sh $pathToShell"myShell.sh"
Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254
5
 #!/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
  • 51
  • 1
  • 2
5
chmod a+x /path/to/file-to-be-executed

That was the only thing I needed. Once the script to be executed is made executable like this, you (at least in my case) don't need any other extra operation like sh or ./ while you are calling the script.

Thanks to the comment of @Nathan Lilienthal

Asqan
  • 4,319
  • 11
  • 61
  • 100
4

Assume the new file is "/home/satya/app/app_specific_env" and the file contents are as follows

#!bin/bash

export FAV_NUMBER="2211"

Append this file reference to ~/.bashrc file

source /home/satya/app/app_specific_env

When ever you restart the machine or relogin, try echo $FAV_NUMBER in the terminal. It will output the value.

Just in case if you want to see the effect right away, source ~/.bashrc in the command line.

Satya Kalluri
  • 5,148
  • 4
  • 28
  • 37
3

There are some problems to import functions from other file.
First: You needn't to do this file executable. Better not to do so! just add

. file

to import all functions. And all of them will be as if they are defined in your file.
Second: You may be define the function with the same name. It will be overwritten. It's bad. You may declare like that

declare -f new_function_name=old_function_name 

and only after that do import. So you may call old function by new name.
Third: You may import only full list of functions defined in file. If some not needed you may unset them. But if you rewrite your functions after unset they will be lost. But if you set reference to it as described above you may restore after unset with the same name.
Finally In common procedure of import is dangerous and not so simple. Be careful! You may write script to do this more easier and safe. If you use only part of functions(not all) better split them in different files. Unfortunately this technique not made well in bash. In python for example and some other script languages it's easy and safe. Possible to make partial import only needed functions with its own names. We all want that in next bush versions will be done the same functionality. But now We must write many additional cod so as to do what you want.

Anatoly
  • 31
  • 1
  • (Welcome to SO!) As user [Praveen](https://stackoverflow.com/users/1049028/praveen) was last seen in 2011, it is bound to be difficult to sort out whether the question was *how to make the shell executing* a.sh *execute* b.sh *(and continue executing* a.sh *if not commanded otherwise*), or to literally *call b.sh*. (My spelling checker doesn't catch `bush versions`.) (Do you have someone to turn to to help you with English grammar? (Sometimes wish I had.)) – greybeard Aug 19 '17 at 18:38
3

Use backticks.

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

Then fetch the output of the producer script as an argument on the consumer script.

dacabdi
  • 344
  • 4
  • 14