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)

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

Scratch 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

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
Link to original