Source Vs Run
TLDR
# Runs the hi.sh script within the parent process.
# - parent process env variables are affected.
source /tmp/hi.sh
# Creates child process to run hi.sh script in.
# - parent process env variables are not affected
/tmp/hi.sh
PID: Process ID
PID
Details
Lets say you have a script /tmp/hi.sh
Which has the following ($$ prints PID (Process ID))
echo "My PID: $$"
If you run it as
/tmp/hi.sh
You will get PID that is different from parent process.
But if you run it as
source /tmp/hi.sh
You will get the same PID as your parent process.
Example code:
echo 'echo pid in /tmp/hi.sh: $$' > /tmp/hi.sh
chmod +x /tmp/hi.sh
echo "PID of parent process is: $$"
echo "Running /tmp/hi.sh"
/tmp/hi.sh
echo "Source /tmp/hi.sh"
source /tmp/hi.sh
Env Variables example
Env Variables. Example: source ./scratch2.sh (does change ENV variables)
Lets say you have two files scratch.sh and scratch2.shScratch Shell:
main() {
SOME_ENV="Scratch1 value"
echo "Running Scratch1, PID: $$"
echo.green "SOME_ENV: ${SOME_ENV:?}"
echo "Starting source:"
echo "--------------------------------------------------------------------------------"
source "${SCRATCH_SHELL2:?}"
echo "--------------------------------------------------------------------------------"
echo "Finished source."
echo.green "SOME_ENV: ${SOME_ENV:?}"
}
main "${@}" || exit 1
Scratch 2 Shell:
main() {
echo "Running Scratch2, PID: $$"
SOME_ENV="some Scratch2 value"
}
main "${@}" || exit 1
When you run scratch 1 shell since you are using source env variables are affected leading to output:
Running Scratch1, PID: 27508
SOME_ENV: Scratch1 value
Starting source:
--------------------------------------------------------------------------------
Running Scratch2, PID: 27508
--------------------------------------------------------------------------------
Finished source.
SOME_ENV: some Scratch2 value
Env Variables, Example: ./scratch2.sh (does not change parent ENV variables)
# scratch.sh:
main() {
SOME_ENV="Scratch1 value"
echo "Running Scratch1, PID: $$"
echo.green "SOME_ENV: ${SOME_ENV:?}"
echo "Starting source:"
echo "--------------------------------------------------------------------------------"
"${SCRATCH_SHELL2:?}"
echo "--------------------------------------------------------------------------------"
echo "Finished source."
echo.green "SOME_ENV: ${SOME_ENV:?}"
}
main "${@}" || exit 1
# scratch2.sh:
main() {
echo "Running Scratch2, PID: $$"
SOME_ENV="some Scratch2 value"
echo.green "SOME_ENV: ${SOME_ENV:?}"
}
main "${@}" || exit 1
Output:
Running Scratch1, PID: 27577
SOME_ENV: Scratch1 value
Starting source:
--------------------------------------------------------------------------------
Running Scratch2, PID: 27578
SOME_ENV: some Scratch2 value
--------------------------------------------------------------------------------
Finished source.
SOME_ENV: Scratch1 value
Notice even though we set env variable in scratch2, the change was not reflected from perspective of scratch1 since it was a separate process.
Source Further Dive
Source to pipe
Piping output of source makes it so ENV variable changes are not reflected in parent process.
When you pipe you create a sub-process. Hence, you env variable changes would not propagate up to parent, since they were only changed in the child process.
Example Code
# scratch1.sh
main() {
SOME_ENV="Scratch1 value"
echo "SOME_ENV: ${SOME_ENV:?} (in Scratch1) (PID: $$, BASHPID: $BASHPID)"
echo "--------------------------------------------------------------------------------Starting source"
source "${SCRATCH_SHELL2:?}" | tee /tmp/out
echo "--------------------------------------------------------------------------------Finished source"
echo "SOME_ENV: ${SOME_ENV:?} (in Scratch1) (PID: $$, BASHPID: $BASHPID)"
}
main "${@}" || exit 1
# scratch2.sh
main() {
SOME_ENV="Scratch2-value"
echo "SOME_ENV: ${SOME_ENV:?} (in Scratch2) (PID: $$, BASHPID: $BASHPID)"
}
main "${@}" || exit 1
Children