I’m trying to write a function to replace the functionality of the exit builtin to prevent myself from exiting the terminal.
I have attempted to use the SHLVL environment variable but it doesn’t seem to change within subshells:
$ echo $SHLVL 1 $ ( echo $SHLVL ) 1 $ bash -c 'echo $SHLVL' 2
My function is as follows:
exit () {
if [[ $SHLVL -eq 1 ]]; then
printf '%sn' "Nice try!" >&2
else
command exit
fi
}
This won’t allow me to use exit within subshells though:
$ exit Nice try! $ (exit) Nice try!
What is a good method to detect whether or not I am in a subshell?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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.
Method 2
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
Method 3
[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
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0