What is the difference between using `sh` and `source`?
When you call source
or .
(the one is an alias to the other. source
cmd not POSIX - kind of bashism), you load and execute a shell script into the current shell process. So you can
- read variables set in the sourced script,
- use functions defined within it.
- and even execute forks and/or subprocess if script do this.
When you call sh
, you initiate a fork (sub-process or child) that runs a new session of /bin/sh
(which is often a symbolic link to bash
). In this case, environment variables set by the sub-script would be dropped when the sub-script terminate.
Caution: sh
could be a symlink to another shell.
Practical sample
For example, if you want to change current working directory by a specific manner, you could not do
$ cat <<eof >myCd2Doc.sh
#!/bin/sh
cd /usr/share/doc
eof
$ chmod +x myCd2Doc.sh
This won't do what you expect:
$ cd /tmp
$ pwd
/tmp
$ ~/myCd2Doc.sh
$ pwd
/tmp
because current working dir is part of environment and myCd2Doc.sh
would run in a subshell.
But:
$ cat >myCd2Doc.source <<eof
# Shell source file
myCd2Doc() {
cd /usr/share/doc
}
eof
$ . myCd2Doc.source
$ cd /tmp
$ pwd
/tmp
$ myCd2Doc
$ pwd
/usr/share/doc
Have a look at mycd
function!! (With bash completion based on Associative Array).
Execution level $SHLVL
$ cd /tmp
printf %b '\43\41/bin/bash\necho This is level \44SHLVL.\n' >qlvl.sh
$ bash qlvl.sh
This is level 2.
$ source qlvl.sh
This is level 1.
Recursion (when a script run from itself)
$ cat <<eoqlvl2 >qlvl2.sh
#!/bin/bash
export startLevel recursionLimit=5
echo This is level $SHLVL started:${startLevel:=$SHLVL}.
(( SHLVL < recursionLimit )) && ./qlvl2.sh
eoqlvl2
$ chmod +x qlvl2.sh
$ ./qlvl2.sh
This is level 2 started:2.
This is level 3 started:2.
This is level 4 started:2.
This is level 5 started:2.
$ source qlv2.sh
This is level 1 started:1.
This is level 2 started:1.
This is level 3 started:1.
This is level 4 started:1.
This is level 5 started:1.
A little futher
$ sed '$a ps --sid $SID fw' qlvl.sh >qlvl3.sh
$ chmod +x qlvl3.sh
$ export SID
$ read SID < <(ps ho sid $$)
$ echo $SID $$
8983 8983
( Current PID ($$
== process Id) are same identifier than SID (session ID). It's not alway true.)
$ ./qlvl3.sh
This is level 2.
PID TTY STAT TIME COMMAND
8983 pts/10 Ss 0:00 /bin/bash
10266 pts/10 S+ 0:00 \_ /bin/bash ./qlvl3.sh
10267 pts/10 R+ 0:00 \_ ps --sid 8983 fw
$ . qlvl3.sh
This is level 1.
PID TTY STAT TIME COMMAND
8983 pts/10 Ss 0:00 /bin/bash
10428 pts/10 R+ 0:00 \_ ps --sid 8983 fw
Dot .
is an alias of source
. So the only difference between two command are slash
replaced by space
.
And a final test:
$ printf %b '\43\41/bin/bash\necho Ending this.\nsleep 1;exit 0\n' >finalTest.sh
$ bash finalTest.sh
Ending this.
$ source finalTest.sh
Ending this.
... You may notice a different behaviour between the two syntaxes. ;-)
What is the difference between source script.sh and ./script.sh?
source script.sh
runs the script within the current process, thus all variable assignments are preserved as variables even after the script finishes (and don't have to be explicitly export
'd).
./script.sh
just runs the script in a subprocess, and any variables which are assigned disappear after the script is done.
Using dot or source while calling another script - what is the difference?
There is no difference.
From the manual:
source
source filename
A synonym for . (see Bourne Shell Builtins).
Difference between ./ and sh in UNIX
sh file
executes a shell-script file in a new shell process.
. file
executes a shell-script file in the current shell process.
./file
will execute the file in the current directory. The file can be a binary executable, or it can start with a hashbang line (the first line of the file in form of #!....
, for example #!/usr/bin/ruby
in a file would signify the script needs to be executed as a Ruby file). The file needs to have the executable flag set.
For example, if you have the script test.sh
:
#!/bin/sh
TEST=present
and you execute it with sh test.sh
, you'd launch a new sh
(or rather bash
, most likely, as one is softlinked to the other in modern systems), then define a new variable inside it, then exit. A subsequent echo $TEST
prints an empty line - the variable is not set in the outer shell.
If you launch it using . test.sh
, you'd execute the script using the current shell. The result of echo $TEST
would print present
.
If you launch it using ./test.sh
, the first line #!/bin/sh
would be detected, then it would be exactly as if you wrote /bin/sh ./test.sh
, which in this case boils down to the first scenario. But if the hashbang line was, for example, #!/usr/bin/perl -w
, the file would have been executed with /usr/bin/perl -w ./test.sh
.
What is the difference between ./a.sh and . ./a.sh?
. path/to/script
sources the file (executes it in the same shell). The other call forks a new shell process which executes the script.
Invoking a script in a child process will make its variables not available to the parent process. Sourcing a script will introduce and change variables in the same parent process.
What's the difference between: . [script] or source [script], bash [script] or $SHELL [script], and ./ [script] or [script]?
. script
and source script
execute the contents of script
in the current environment, i.e. without creating a subshell. On the upside this allows script
to affect the current environment, for example changing environment variables or changing the current work directory. On the downside this allows script
to affect the current environment, which is a potential security hazard.
bash script
passes script
to the bash
interpreter to execute. Whatever shebang is given by script
itself is ignored. ("Shebang" referring to the first line of script
, which could e.g. read #!/bin/bash
, or #!/usr/bin/perl
, or #!/usr/bin/awk
, to specify the interpreter to be used.)
$SHELL script
passes script
to whatever is your current shell interpreter to execute. That may, or may not, be bash
. (The environment variable SHELL
holds the name of your current shell interpreter. $SHELL
, if running bash, is evaluated to /bin/bash
, with the effect detailed in the previous paragraph.)
./script
executes the contents of a file script
in the current work directory. If there is no such file, an error is generated. The contents of $PATH
have no effect on what happens.
script
looks for a file script
in the directories listed in $PATH
, which may or may not include the current work directory. The first script
found in this list of directories is executed, which may or may not be the one in your current work directory.
Difference between source, zsh, . and directly shell script calling
Your first line is wrong:
# !/bin/zsh
It should be:
#!/bin/zsh
Related Topics
Automatically Capture Output of Last Command into a Variable Using Bash
How to Set Environment Variable For Everyone Under My Linux System
Split One File into Multiple Files Based on Delimiter
How to Escape Single Quotes in Bash/Grep
Quickly Create a Large File on a Linux System
Command Not Found When Using Sudo
How to Copy Commits from One Git Repo to Another
How to Change 'Rpath' in an Already Compiled Binary
Difference Between Using 'Sh' and 'Source'
Find Multiple Files and Rename Them in Linux
Maximum Number of Processes in Linux
How to Configure Apache 2 to Run Perl Cgi Scripts
Setting Up Ftp on Amazon Cloud Server
How to Find the Last Field Using 'Cut'
Error When Using Git Credential Helper With Gnome-Keyring as Sudo