111

What's the difference between executing a script like this:

./test.sh

and executing a script like this:

. test.sh?

I tried a simple, two-line script to see if I could find if there was a difference:

#!/bin/bash
ls

But both . test.sh and ./test.sh returned the same information.

2
  • Apologies if this is a duplicate - upon further investigation, I found some pages with relevant information by searching for 'bash dot' instead of 'bash .'.
    – Nathan
    Jul 25, 2012 at 6:32
  • 6
    Just as test.sh is not the same as ./test.sh (the first invokes a PATH search), so are . test.sh and . ./test.sh different in the same way (the former invokes a PATH search). Many shells seem to implicitly include . at the end of PATH when doing a . path search, but this behavior is not standard. Thus, it is more accurate to compare test.sh vs . test.sh and ./test.sh vs . ./test.sh.
    – jw013
    Jul 30, 2012 at 21:13

4 Answers 4

123

./test.sh runs test.sh as a separate program. It may happen to be a bash script, if the file test.sh starts with #!/bin/bash. But it could be something else altogether.

. ./test.sh executes the code of the file test.sh inside the running instance of bash. It works as if the content file test.sh had been included textually instead of the . ./test.sh line. (Almost: there are a few details that differ, such as the value of $BASH_LINENO, and the behavior of the return builtin.)

source ./test.sh is identical to . ./test.sh in bash (in other shells, source may be slightly different or not exist altogether; . for inclusion is in the POSIX standard).

The most commonly visible difference between running a separate script with ./test.sh and including a script with the . builtin is that if the test.sh script sets some environment variables, with a separate process, only the environment of the child process is set, whereas with script inclusion, the environment of the sole shell process is set. If you add a line foo=bar in test.sh and echo $foo at the end of the calling script, you'll see the difference:

$ cat test.sh
#!/bin/sh
foo=bar
$ ./test.sh
$ echo $foo

$ . ./test.sh
$ echo $foo
bar
2
  • 24
    Also adding echo $$ to the script will show the difference quite clear. The $$ variable holds the PID of the current shell.
    – user13742
    Jul 25, 2012 at 10:15
  • 1
    Another usage scenario is using the . ./test.sh call from within another shell script to use functions that are described within test.sh. I mean, it is not just variables that you can set, you can also create new functions in this way which are then callable from bash, or some other script. . /usr/libexec/company/tools; custom_command "variable"
    – Rqomey
    Jul 31, 2012 at 8:33
12

Running a script the first way runs it as a child process. Sourcing (the second way), on the other hand, runs the script as if you entered all its commands into the current shell - if the script sets a variable, it will remain set, if the script exits, your session will exit. See help . for documentation.

4

Another thing that I note is that if you have an alias like this:

# add into .bashrc_aliases
alias ls='ls -lht'

With ./test.sh you'll get a normal ls output (and a different PID than current shell):

auraham@pandora:~/iso$ ./test.sh 
dsl-4.4.10.iso  test.sh
3136 # PID

With . test.sh or . ./test.sh you'll get a more detailed output (and the same PID than current shell):

auraham@pandora:~/iso$ echo $$
2767 # shell PID

auraham@pandora:~/iso$ . test.sh 
total 50M
drwxrwxr-x  2 auraham auraham 4.0K Jul 30 15:41 .
-rwxrwxr-x  1 auraham auraham   32 Jul 30 15:41 test.sh
drwxr-xr-x 50 auraham auraham 4.0K Jul 30 15:30 ..
-rw-rw-r--  1 auraham auraham  50M Jul 28 17:24 dsl-4.4.10.iso
2767 # PID
3
  • You can include this in .bashrc if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi Then, put your aliases in .bash_aliases.
    – auraham
    Aug 1, 2012 at 1:17
  • Of course, but don't you still have to use the alias keyword? (Maybe that's just a mistake in you post -- on line 3?) Aug 1, 2012 at 10:26
  • totally correct, my mistake. Thanks @EmanuelBerg
    – auraham
    Aug 1, 2012 at 18:40
0

Usually, a ./file is just a way to point to a file, which in this case, is equivalent to the PWD (present working directory) path followed by the file name used.

$ pwd
/home/isaac/me/bin/

$ realpath ./file
/home/isaac/me/bin/file

It also happens that a path at the start of a line (first argument or argument 0) signals the shell to try to execute that file. If it is a shell script, most probably, the shell will load it to execute it in a new execution environment. If it is some other form of valid executable, the shell will try to execute it via the kernel exec command.

Adding an initial dot to a command line (only works if it is the whole argument zero) will allow a shell script (not an external executable) to be loaded with the same execution environment already present.

$ . ./file        # that exact same file as above, now it is sourced
$ source ./file   # an equivalent (but longer) command.

Of course, if the directory is not set in the path (not starting dot), some searching will be involved to find the specific file to be sourced.

In bash:

If filename does not contain a slash, filenames in PATH are used to find the directory containing filename.

And, if in POSIX mode, the PWD is also used to search for the filename given.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .