Unix: Differencebetween Source and Export

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.\nsle' \
'ep 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. ;-)

Defining a variable with or without export

export makes the variable available to sub-processes.

That is,

export name=value

means that the variable name is available to any process you run from that shell process. If you want a process to make use of this variable, use export, and run the process from that shell.

name=value

means the variable scope is restricted to the shell, and is not available to any other process. You would use this for (say) loop variables, temporary variables etc.

It's important to note that exporting a variable doesn't make it available to parent processes. That is, specifying and exporting a variable in a spawned process doesn't make it available in the process that launched it.

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).

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.

What does the 'export' command do?

export in sh and related shells (such as Bash), marks an environment variable to be exported to child-processes, so that the child inherits them.

export is defined in POSIX:

The shell shall give the export attribute to the variables corresponding to the specified names, which shall cause them to be in the environment of subsequently executed commands. If the name of a variable is followed by = word, then the value of that variable shall be set to word.

What is the difference between $(()) and expr?

$(()) will almost certainly be within the shell that you are using.
expr may be an external call

Export command in Unix

The shell expanded the non-existent variable $TEST into an empty string, and then ran the command export with no arguments. When you do that, the shell lists the exported environment variables.

If you want to export an empty variable TEST, you should have written any of these:

export TEST
export TEST=
export TEST=''
export TEST=""

(and in this case, there are other ways to achieve the same effect, such as export TEST=$TEST or, more or less sanely, export TEST="$TEST", but that is normally abbreviated to export TEST.)

The detailed declare -x notation in the output is designed to allow you to take write the output to a file, and then reload the environment with the . (dot) or source commands. Different shells present the output differently, and not necessarily reusably.

The set command is similar (but more complex). It can be used to set shell options, to set the positional arguments ($1, $2, etc), but when run with no arguments it lists the set variables. Note that not every variable that is created is an exported environment variable.



Related Topics



Leave a reply



Submit