10

The accepted answer for a similar question for bash does not seem to work for zsh. In fact, if I copy basically the same code given in that answer, to produce the script

#!/usr/bin/zsh -
# test.sh

[[ $_ != $0 ]] && echo "sourced\n" || echo "subshell\n"

the output hardly ever corresponds to the actual situation:

zsh% chmod +x ./test.sh
zsh% env -i /usr/bin/zsh -f
zsh% ./test.sh
sourced

zsh% /usr/bin/zsh ./test.sh
sourced

zsh% /bin/bash ./test.sh
sourced

zsh% source ./test.sh
subshell

zsh% . ./test.sh
subshell

zsh% env -i /bin/bash --norc --noprofile
bash-3.2$ ./test.sh
sourced

bash-3.2$ /usr/bin/zsh ./test.sh
sourced

bash-3.2$ /bin/bash ./test.sh
sourced

bash-3.2$ source ./test.sh
sourced

bash-3.2$ . ./test.sh
sourced

When the current interactive shell is zsh, the script gets it exactly wrong every time. It fares a bit better under bash (though in a way reminiscent of the stopped watch that gets the time exactly right twice a day).

These truly abysmal results give me little confidence in this approach.

Is there something better?

1
  • 3
    If I were desperate I'd use $SECONDS - if it's zero, then it's a subshell; >0 and the file's been sourced. That idea is so stinky, I'm only posting it as a novelty item. Commented Apr 19, 2013 at 14:56

4 Answers 4

9
if [[ $ZSH_EVAL_CONTEXT == 'toplevel' ]]; then
    # We're not being sourced so run the colors command which in turn sources
    # this script and uses its content to produce representative output.
    colors
fi

Via Kurtis Rader on the zsh-users mailing list.

4
  • The variable is empty in both cases in my zsh 5.4.2. Commented Jan 1, 2018 at 23:48
  • Works in zsh 5.7.1, I use it to verify that the script is being sourced. Commented Jan 7, 2020 at 12:31
  • This does not work in Zsh 5.8. Commented Jun 24, 2020 at 11:58
  • Better to check whether 'file' is in zsh_eval_context. See man zshparam in zsh_eval_context where a dozen zsh_eval_contexts are described, all but one of which could be present in a non-sourced script, maybe nested with others. See answer by Marlon Richert above. Commented Jun 23, 2022 at 17:25
3

To see if the code is running in a subshell, check the value of $ZSH_SUBSHELL:

if (( ZSH_SUBSHELL )); then
  echo "subshell, $ZSH_SUBSHELL fork(s) deep"
else
  echo "not a subshell"
fi

To see if the code is sourced, check if zsh_eval_context contains the word file:

if (( zsh_eval_context[(I)file] )); then
  echo "sourced"
else
  echo "not sourced"
fi
0

You could get the Shell Level:

[ $SHLVL -gt 1 ] && echo "subshell"

There's also (ZSH-only) $ZSH_SUBSHELL.

Obviously these break if you're nesting.

1
  • 1
    This does not help when you want to check if you're being sourced. Commented Jun 24, 2020 at 12:10
-1

Isn't the answer you are looking for the difference between login and interactive shell?

localhost% cat foo
#!/usr/bin/env zsh

[[ $- == *i* ]] && print ' interactive=sourced' || print ' login=called'

localhost% source foo
 interactive=sourced
localhost% zsh foo   
 login=called

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.