How can I detect if I'm in a subshell?
In bash, you can compare $BASHPID
to $$
$ ( if [ "$$" -eq "$BASHPID" ]; then echo not subshell; else echo subshell; fi )
subshell
$ if [ "$$" -eq "$BASHPID" ]; then echo not subshell; else echo subshell; fi
not subshell
If you're not in bash, $$
should remain the same in a subshell, so you'd need some other way of getting your actual process ID.
One way to get your actual pid is sh -c 'echo $PPID'
. If you just put that in a plain ( … )
it may appear not to work, as your shell has optimized away the fork. Try extra no-op commands ( : ; sh -c 'echo $PPID'; : )
to make it think the subshell is too complicated to optimize away. Credit goes to John1024 on Stack Overflow for that approach.
How about BASH_SUBSHELL
?
BASH_SUBSHELL
Incremented by one within each subshell or subshell environment when the shell
begins executing in that environment. The initial value is 0.
$ echo $BASH_SUBSHELL
0
$ (echo $BASH_SUBSHELL)
1
[this should've been a comment, but my comments tend to be deleted by moderators, so this will stay as an answer that I could use it as a reference even if deleted]
Using BASH_SUBSHELL
is completely unreliable as it be only set to 1 in some subshells, not in all subshells.
$ (echo $BASH_SUBSHELL)
1
$ echo $BASH_SUBSHELL | cat
0
Before claiming that the subprocess a pipeline command is run in is not a really real subshell, consider this man bash
snippet:
Each command in a pipeline is executed as a separate process (i.e., in a subshell).
and the practical implications -- it's whether a script fragment is run a subprocess or not which is essential, not some terminology quibble.
The only solution, as already explained in the answers to this question is to check whether $BASHPID
equals $$
or, portably but much less efficient:
if [ "$(exec sh -c 'echo "$PPID"')" != "$$" ]; then
echo you\'re in a subshell
fi