Issue
What is the difference between sh
and source
?
source: source filename [arguments]
Read and execute commands from FILENAME and return. The pathnames
in $PATH are used to find the directory containing FILENAME. If any
ARGUMENTS are supplied, they become the positional parameters when
FILENAME is executed.
And for man sh
:
NAME
bash - GNU Bourne-Again SHell
SYNOPSIS
bash [options] [file]
COPYRIGHT
Bash is Copyright (C) 1989-2004 by the Free Software Foundation, Inc.
DESCRIPTION
Bash is an sh-compatible command language interpreter that executes commands read from the standard input or from a file. Bash also incorporates
useful features from the Korn and C shells (ksh and csh).
Bash is intended to be a conformant implementation of the IEEE POSIX Shell and Tools specification (IEEE Working Group 1003.2).
Solution
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. ;-)
Answered By - F. Hauri Answer Checked By - Terry (WPSolving Volunteer)