How can I detect if I'm in a subshell?Do parentheses really put the command in a subshell?How can I get the pid of a subshell?exit shell script from a subshellcurly braces and subshellExpand subshell before executing it?Assign Subshell background process pid to variableHow to run subshell commands over SSH?set -e in a subshellgrabbing exit code of background process/subshellHow can I get the pid of a subshell?How can I stop a child process of a subshell (as per SIGSTOP) before the subshell exits?How to handle async subshell exit
Why is reverb typically called "wet' or "drippy"?
Why is Macron seemingly opposing an article 50 extension?
The DM is unapologetically providing TPK encounters; what can we do?
Black hole as a storage device?
Ubuntu 19.10: why is the "locate" command missing?
Degraded Array. RAID 6 with three disk failure
Encrypt folder on Linux that can only be decrypted on that specific OS and device
Is it crucial for a UX designer to understand the principles and concepts behind Object Oriented Programming?
Drawing hexagonal lattice in LaTex using Cartesian coordinates
How to print a list of possible matches from C-n?
How do we distinguish old craters from new ones on the Moon?
What is the most life you can have at the end of your first turn with only three cards?
How to make the number 49?
What is the history of the Eldritch Knight as a class/character option?
How to create numeronyms in bash
Extract partitions of images after edge detection
Why there are no major political movements worried about asteroid/comet impact?
How to write strategy and schemes beyond my real-life capabilities?
Why would the command "ls *" generate an error?
What element, if any, would justify mining stars (financially)?
If authors leave out diacritics, should I correct them or leave it as written?
Do you make me up?
How to express "naked" in different situations?
Famous easy to understand examples of a confounding variable invalidating a study
How can I detect if I'm in a subshell?
Do parentheses really put the command in a subshell?How can I get the pid of a subshell?exit shell script from a subshellcurly braces and subshellExpand subshell before executing it?Assign Subshell background process pid to variableHow to run subshell commands over SSH?set -e in a subshellgrabbing exit code of background process/subshellHow can I get the pid of a subshell?How can I stop a child process of a subshell (as per SIGSTOP) before the subshell exits?How to handle async subshell exit
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;
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?
bash shell exit subshell
|
show 4 more comments
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?
bash shell exit subshell
3
stackoverflow.com/questions/4511407/…
– K7AAY
Jun 12 at 18:40
1
That is because of this. $SHLVL is 1 because you are still in shell level 1 even though the echo $SHLVL command is run in a "subshell". According to that post, subshells spawned with parenthesis(...)
inherit all the properties of the parent process. The answers provided are more robust solutions to determining your shell level.
– kemotep
Jun 12 at 18:52
1
Possible duplicate of How can I get the pid of a subshell?
– mosvy
Jun 13 at 5:45
5
@mosvy I feel like that is a different question. e.g. theBASH_SUBSHELL
answer (even if controversial) wouldn't apply to that question.
– Sparhawk
Jun 13 at 9:39
2
Saw the title on HNQ and thought this was a quantum mechanics question...
– Mehrdad
Jun 13 at 22:47
|
show 4 more comments
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?
bash shell exit subshell
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?
bash shell exit subshell
bash shell exit subshell
edited Jun 16 at 10:15
Jeff Schaller♦
50.9k11 gold badges75 silver badges170 bronze badges
50.9k11 gold badges75 silver badges170 bronze badges
asked Jun 12 at 18:35
Jesse_bJesse_b
19.8k3 gold badges47 silver badges90 bronze badges
19.8k3 gold badges47 silver badges90 bronze badges
3
stackoverflow.com/questions/4511407/…
– K7AAY
Jun 12 at 18:40
1
That is because of this. $SHLVL is 1 because you are still in shell level 1 even though the echo $SHLVL command is run in a "subshell". According to that post, subshells spawned with parenthesis(...)
inherit all the properties of the parent process. The answers provided are more robust solutions to determining your shell level.
– kemotep
Jun 12 at 18:52
1
Possible duplicate of How can I get the pid of a subshell?
– mosvy
Jun 13 at 5:45
5
@mosvy I feel like that is a different question. e.g. theBASH_SUBSHELL
answer (even if controversial) wouldn't apply to that question.
– Sparhawk
Jun 13 at 9:39
2
Saw the title on HNQ and thought this was a quantum mechanics question...
– Mehrdad
Jun 13 at 22:47
|
show 4 more comments
3
stackoverflow.com/questions/4511407/…
– K7AAY
Jun 12 at 18:40
1
That is because of this. $SHLVL is 1 because you are still in shell level 1 even though the echo $SHLVL command is run in a "subshell". According to that post, subshells spawned with parenthesis(...)
inherit all the properties of the parent process. The answers provided are more robust solutions to determining your shell level.
– kemotep
Jun 12 at 18:52
1
Possible duplicate of How can I get the pid of a subshell?
– mosvy
Jun 13 at 5:45
5
@mosvy I feel like that is a different question. e.g. theBASH_SUBSHELL
answer (even if controversial) wouldn't apply to that question.
– Sparhawk
Jun 13 at 9:39
2
Saw the title on HNQ and thought this was a quantum mechanics question...
– Mehrdad
Jun 13 at 22:47
3
3
stackoverflow.com/questions/4511407/…
– K7AAY
Jun 12 at 18:40
stackoverflow.com/questions/4511407/…
– K7AAY
Jun 12 at 18:40
1
1
That is because of this. $SHLVL is 1 because you are still in shell level 1 even though the echo $SHLVL command is run in a "subshell". According to that post, subshells spawned with parenthesis
(...)
inherit all the properties of the parent process. The answers provided are more robust solutions to determining your shell level.– kemotep
Jun 12 at 18:52
That is because of this. $SHLVL is 1 because you are still in shell level 1 even though the echo $SHLVL command is run in a "subshell". According to that post, subshells spawned with parenthesis
(...)
inherit all the properties of the parent process. The answers provided are more robust solutions to determining your shell level.– kemotep
Jun 12 at 18:52
1
1
Possible duplicate of How can I get the pid of a subshell?
– mosvy
Jun 13 at 5:45
Possible duplicate of How can I get the pid of a subshell?
– mosvy
Jun 13 at 5:45
5
5
@mosvy I feel like that is a different question. e.g. the
BASH_SUBSHELL
answer (even if controversial) wouldn't apply to that question.– Sparhawk
Jun 13 at 9:39
@mosvy I feel like that is a different question. e.g. the
BASH_SUBSHELL
answer (even if controversial) wouldn't apply to that question.– Sparhawk
Jun 13 at 9:39
2
2
Saw the title on HNQ and thought this was a quantum mechanics question...
– Mehrdad
Jun 13 at 22:47
Saw the title on HNQ and thought this was a quantum mechanics question...
– Mehrdad
Jun 13 at 22:47
|
show 4 more comments
3 Answers
3
active
oldest
votes
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.
You might want to change that to(sh -c 'echo $PPID'; : )
— see my comment on John1024’s answer.
– G-Man
Jun 19 at 21:15
@G-Man Well, that was just to test it (since in actual use it'd be in something way more complicated)... but yeah, would be best if the test worked in all shells. So I've put a no-op both before and after, that will hopefully handle everything.
– derobert
Jun 19 at 21:45
add a comment
|
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
15
It would have been a convenient command in the movie Inception.
– Eric Duminil
Jun 13 at 18:56
In Inception it's probably $SHLVL
– Granny Aching
Jun 14 at 17:14
add a comment
|
[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
11
Nit:BASH_SUBSHELL
is set pretty reliably, but getting its value correctly is iffy. Note what the docs say: "Incremented by one within each subshell or subshell environment when the shell begins executing in that environment." I think that in the pipe example, bash hasn't yet begun executing in that subshell when the variable is expanded. You can compareecho $BASH_VERSION
withdeclare -p BASH_VERSION
- the latter should reliably output 1 with pipes, background jobs, etc.
– muru
Jun 13 at 1:20
6
Even say,eval 'echo $BASH_SUBSHELL $BASHPID' | cat
will output 1 forBASH_SUBSHELL
, because the variable is expanded after execution has started.
– muru
Jun 13 at 6:02
4
all those arguments should also apply to to process & commands substitution, bg processes, yet it's only the pipelines which are different. Looking at the code, incrementingsubshell_level
really is deferred in the case of foreground pipelines, which probably has some reason, but which I'm not able to make out ;-)
– mosvy
Jun 13 at 6:18
2
You're right. Seems Chet explicitly intends it that way. lists.gnu.org/archive/html/bug-bash/2015-06/msg00050.html : "BASH_SUBSHELL measures (...) subshells, not pipeline elements." lists.gnu.org/archive/html/bug-bash/2015-06/msg00054.html: "I'm going to think about whether I should document the status quo or expand the definition of `subshell' that $BASH_SUBSHELL reflects."
– muru
Jun 13 at 7:11
2
@JoL you're wrong, the expansion happens in the separate process too, please read the links and examples from this discussion above; or just try withecho $$ $BASHPID $BASH_SUBSHELL | cat
.
– mosvy
Jun 13 at 19:45
|
show 3 more comments
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f524506%2fhow-can-i-detect-if-im-in-a-subshell%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
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.
You might want to change that to(sh -c 'echo $PPID'; : )
— see my comment on John1024’s answer.
– G-Man
Jun 19 at 21:15
@G-Man Well, that was just to test it (since in actual use it'd be in something way more complicated)... but yeah, would be best if the test worked in all shells. So I've put a no-op both before and after, that will hopefully handle everything.
– derobert
Jun 19 at 21:45
add a comment
|
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.
You might want to change that to(sh -c 'echo $PPID'; : )
— see my comment on John1024’s answer.
– G-Man
Jun 19 at 21:15
@G-Man Well, that was just to test it (since in actual use it'd be in something way more complicated)... but yeah, would be best if the test worked in all shells. So I've put a no-op both before and after, that will hopefully handle everything.
– derobert
Jun 19 at 21:45
add a comment
|
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.
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.
edited Jun 19 at 21:43
answered Jun 12 at 18:46
derobertderobert
81.2k9 gold badges183 silver badges237 bronze badges
81.2k9 gold badges183 silver badges237 bronze badges
You might want to change that to(sh -c 'echo $PPID'; : )
— see my comment on John1024’s answer.
– G-Man
Jun 19 at 21:15
@G-Man Well, that was just to test it (since in actual use it'd be in something way more complicated)... but yeah, would be best if the test worked in all shells. So I've put a no-op both before and after, that will hopefully handle everything.
– derobert
Jun 19 at 21:45
add a comment
|
You might want to change that to(sh -c 'echo $PPID'; : )
— see my comment on John1024’s answer.
– G-Man
Jun 19 at 21:15
@G-Man Well, that was just to test it (since in actual use it'd be in something way more complicated)... but yeah, would be best if the test worked in all shells. So I've put a no-op both before and after, that will hopefully handle everything.
– derobert
Jun 19 at 21:45
You might want to change that to
(sh -c 'echo $PPID'; : )
— see my comment on John1024’s answer.– G-Man
Jun 19 at 21:15
You might want to change that to
(sh -c 'echo $PPID'; : )
— see my comment on John1024’s answer.– G-Man
Jun 19 at 21:15
@G-Man Well, that was just to test it (since in actual use it'd be in something way more complicated)... but yeah, would be best if the test worked in all shells. So I've put a no-op both before and after, that will hopefully handle everything.
– derobert
Jun 19 at 21:45
@G-Man Well, that was just to test it (since in actual use it'd be in something way more complicated)... but yeah, would be best if the test worked in all shells. So I've put a no-op both before and after, that will hopefully handle everything.
– derobert
Jun 19 at 21:45
add a comment
|
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
15
It would have been a convenient command in the movie Inception.
– Eric Duminil
Jun 13 at 18:56
In Inception it's probably $SHLVL
– Granny Aching
Jun 14 at 17:14
add a comment
|
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
15
It would have been a convenient command in the movie Inception.
– Eric Duminil
Jun 13 at 18:56
In Inception it's probably $SHLVL
– Granny Aching
Jun 14 at 17:14
add a comment
|
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
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
answered Jun 12 at 18:45
FreddyFreddy
9,7551 gold badge7 silver badges35 bronze badges
9,7551 gold badge7 silver badges35 bronze badges
15
It would have been a convenient command in the movie Inception.
– Eric Duminil
Jun 13 at 18:56
In Inception it's probably $SHLVL
– Granny Aching
Jun 14 at 17:14
add a comment
|
15
It would have been a convenient command in the movie Inception.
– Eric Duminil
Jun 13 at 18:56
In Inception it's probably $SHLVL
– Granny Aching
Jun 14 at 17:14
15
15
It would have been a convenient command in the movie Inception.
– Eric Duminil
Jun 13 at 18:56
It would have been a convenient command in the movie Inception.
– Eric Duminil
Jun 13 at 18:56
In Inception it's probably $SHLVL
– Granny Aching
Jun 14 at 17:14
In Inception it's probably $SHLVL
– Granny Aching
Jun 14 at 17:14
add a comment
|
[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
11
Nit:BASH_SUBSHELL
is set pretty reliably, but getting its value correctly is iffy. Note what the docs say: "Incremented by one within each subshell or subshell environment when the shell begins executing in that environment." I think that in the pipe example, bash hasn't yet begun executing in that subshell when the variable is expanded. You can compareecho $BASH_VERSION
withdeclare -p BASH_VERSION
- the latter should reliably output 1 with pipes, background jobs, etc.
– muru
Jun 13 at 1:20
6
Even say,eval 'echo $BASH_SUBSHELL $BASHPID' | cat
will output 1 forBASH_SUBSHELL
, because the variable is expanded after execution has started.
– muru
Jun 13 at 6:02
4
all those arguments should also apply to to process & commands substitution, bg processes, yet it's only the pipelines which are different. Looking at the code, incrementingsubshell_level
really is deferred in the case of foreground pipelines, which probably has some reason, but which I'm not able to make out ;-)
– mosvy
Jun 13 at 6:18
2
You're right. Seems Chet explicitly intends it that way. lists.gnu.org/archive/html/bug-bash/2015-06/msg00050.html : "BASH_SUBSHELL measures (...) subshells, not pipeline elements." lists.gnu.org/archive/html/bug-bash/2015-06/msg00054.html: "I'm going to think about whether I should document the status quo or expand the definition of `subshell' that $BASH_SUBSHELL reflects."
– muru
Jun 13 at 7:11
2
@JoL you're wrong, the expansion happens in the separate process too, please read the links and examples from this discussion above; or just try withecho $$ $BASHPID $BASH_SUBSHELL | cat
.
– mosvy
Jun 13 at 19:45
|
show 3 more comments
[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
11
Nit:BASH_SUBSHELL
is set pretty reliably, but getting its value correctly is iffy. Note what the docs say: "Incremented by one within each subshell or subshell environment when the shell begins executing in that environment." I think that in the pipe example, bash hasn't yet begun executing in that subshell when the variable is expanded. You can compareecho $BASH_VERSION
withdeclare -p BASH_VERSION
- the latter should reliably output 1 with pipes, background jobs, etc.
– muru
Jun 13 at 1:20
6
Even say,eval 'echo $BASH_SUBSHELL $BASHPID' | cat
will output 1 forBASH_SUBSHELL
, because the variable is expanded after execution has started.
– muru
Jun 13 at 6:02
4
all those arguments should also apply to to process & commands substitution, bg processes, yet it's only the pipelines which are different. Looking at the code, incrementingsubshell_level
really is deferred in the case of foreground pipelines, which probably has some reason, but which I'm not able to make out ;-)
– mosvy
Jun 13 at 6:18
2
You're right. Seems Chet explicitly intends it that way. lists.gnu.org/archive/html/bug-bash/2015-06/msg00050.html : "BASH_SUBSHELL measures (...) subshells, not pipeline elements." lists.gnu.org/archive/html/bug-bash/2015-06/msg00054.html: "I'm going to think about whether I should document the status quo or expand the definition of `subshell' that $BASH_SUBSHELL reflects."
– muru
Jun 13 at 7:11
2
@JoL you're wrong, the expansion happens in the separate process too, please read the links and examples from this discussion above; or just try withecho $$ $BASHPID $BASH_SUBSHELL | cat
.
– mosvy
Jun 13 at 19:45
|
show 3 more comments
[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
[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
edited Jun 13 at 0:06
answered Jun 13 at 0:01
mosvymosvy
18.1k2 gold badges24 silver badges56 bronze badges
18.1k2 gold badges24 silver badges56 bronze badges
11
Nit:BASH_SUBSHELL
is set pretty reliably, but getting its value correctly is iffy. Note what the docs say: "Incremented by one within each subshell or subshell environment when the shell begins executing in that environment." I think that in the pipe example, bash hasn't yet begun executing in that subshell when the variable is expanded. You can compareecho $BASH_VERSION
withdeclare -p BASH_VERSION
- the latter should reliably output 1 with pipes, background jobs, etc.
– muru
Jun 13 at 1:20
6
Even say,eval 'echo $BASH_SUBSHELL $BASHPID' | cat
will output 1 forBASH_SUBSHELL
, because the variable is expanded after execution has started.
– muru
Jun 13 at 6:02
4
all those arguments should also apply to to process & commands substitution, bg processes, yet it's only the pipelines which are different. Looking at the code, incrementingsubshell_level
really is deferred in the case of foreground pipelines, which probably has some reason, but which I'm not able to make out ;-)
– mosvy
Jun 13 at 6:18
2
You're right. Seems Chet explicitly intends it that way. lists.gnu.org/archive/html/bug-bash/2015-06/msg00050.html : "BASH_SUBSHELL measures (...) subshells, not pipeline elements." lists.gnu.org/archive/html/bug-bash/2015-06/msg00054.html: "I'm going to think about whether I should document the status quo or expand the definition of `subshell' that $BASH_SUBSHELL reflects."
– muru
Jun 13 at 7:11
2
@JoL you're wrong, the expansion happens in the separate process too, please read the links and examples from this discussion above; or just try withecho $$ $BASHPID $BASH_SUBSHELL | cat
.
– mosvy
Jun 13 at 19:45
|
show 3 more comments
11
Nit:BASH_SUBSHELL
is set pretty reliably, but getting its value correctly is iffy. Note what the docs say: "Incremented by one within each subshell or subshell environment when the shell begins executing in that environment." I think that in the pipe example, bash hasn't yet begun executing in that subshell when the variable is expanded. You can compareecho $BASH_VERSION
withdeclare -p BASH_VERSION
- the latter should reliably output 1 with pipes, background jobs, etc.
– muru
Jun 13 at 1:20
6
Even say,eval 'echo $BASH_SUBSHELL $BASHPID' | cat
will output 1 forBASH_SUBSHELL
, because the variable is expanded after execution has started.
– muru
Jun 13 at 6:02
4
all those arguments should also apply to to process & commands substitution, bg processes, yet it's only the pipelines which are different. Looking at the code, incrementingsubshell_level
really is deferred in the case of foreground pipelines, which probably has some reason, but which I'm not able to make out ;-)
– mosvy
Jun 13 at 6:18
2
You're right. Seems Chet explicitly intends it that way. lists.gnu.org/archive/html/bug-bash/2015-06/msg00050.html : "BASH_SUBSHELL measures (...) subshells, not pipeline elements." lists.gnu.org/archive/html/bug-bash/2015-06/msg00054.html: "I'm going to think about whether I should document the status quo or expand the definition of `subshell' that $BASH_SUBSHELL reflects."
– muru
Jun 13 at 7:11
2
@JoL you're wrong, the expansion happens in the separate process too, please read the links and examples from this discussion above; or just try withecho $$ $BASHPID $BASH_SUBSHELL | cat
.
– mosvy
Jun 13 at 19:45
11
11
Nit:
BASH_SUBSHELL
is set pretty reliably, but getting its value correctly is iffy. Note what the docs say: "Incremented by one within each subshell or subshell environment when the shell begins executing in that environment." I think that in the pipe example, bash hasn't yet begun executing in that subshell when the variable is expanded. You can compare echo $BASH_VERSION
with declare -p BASH_VERSION
- the latter should reliably output 1 with pipes, background jobs, etc.– muru
Jun 13 at 1:20
Nit:
BASH_SUBSHELL
is set pretty reliably, but getting its value correctly is iffy. Note what the docs say: "Incremented by one within each subshell or subshell environment when the shell begins executing in that environment." I think that in the pipe example, bash hasn't yet begun executing in that subshell when the variable is expanded. You can compare echo $BASH_VERSION
with declare -p BASH_VERSION
- the latter should reliably output 1 with pipes, background jobs, etc.– muru
Jun 13 at 1:20
6
6
Even say,
eval 'echo $BASH_SUBSHELL $BASHPID' | cat
will output 1 for BASH_SUBSHELL
, because the variable is expanded after execution has started.– muru
Jun 13 at 6:02
Even say,
eval 'echo $BASH_SUBSHELL $BASHPID' | cat
will output 1 for BASH_SUBSHELL
, because the variable is expanded after execution has started.– muru
Jun 13 at 6:02
4
4
all those arguments should also apply to to process & commands substitution, bg processes, yet it's only the pipelines which are different. Looking at the code, incrementing
subshell_level
really is deferred in the case of foreground pipelines, which probably has some reason, but which I'm not able to make out ;-)– mosvy
Jun 13 at 6:18
all those arguments should also apply to to process & commands substitution, bg processes, yet it's only the pipelines which are different. Looking at the code, incrementing
subshell_level
really is deferred in the case of foreground pipelines, which probably has some reason, but which I'm not able to make out ;-)– mosvy
Jun 13 at 6:18
2
2
You're right. Seems Chet explicitly intends it that way. lists.gnu.org/archive/html/bug-bash/2015-06/msg00050.html : "BASH_SUBSHELL measures (...) subshells, not pipeline elements." lists.gnu.org/archive/html/bug-bash/2015-06/msg00054.html: "I'm going to think about whether I should document the status quo or expand the definition of `subshell' that $BASH_SUBSHELL reflects."
– muru
Jun 13 at 7:11
You're right. Seems Chet explicitly intends it that way. lists.gnu.org/archive/html/bug-bash/2015-06/msg00050.html : "BASH_SUBSHELL measures (...) subshells, not pipeline elements." lists.gnu.org/archive/html/bug-bash/2015-06/msg00054.html: "I'm going to think about whether I should document the status quo or expand the definition of `subshell' that $BASH_SUBSHELL reflects."
– muru
Jun 13 at 7:11
2
2
@JoL you're wrong, the expansion happens in the separate process too, please read the links and examples from this discussion above; or just try with
echo $$ $BASHPID $BASH_SUBSHELL | cat
.– mosvy
Jun 13 at 19:45
@JoL you're wrong, the expansion happens in the separate process too, please read the links and examples from this discussion above; or just try with
echo $$ $BASHPID $BASH_SUBSHELL | cat
.– mosvy
Jun 13 at 19:45
|
show 3 more comments
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f524506%2fhow-can-i-detect-if-im-in-a-subshell%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
stackoverflow.com/questions/4511407/…
– K7AAY
Jun 12 at 18:40
1
That is because of this. $SHLVL is 1 because you are still in shell level 1 even though the echo $SHLVL command is run in a "subshell". According to that post, subshells spawned with parenthesis
(...)
inherit all the properties of the parent process. The answers provided are more robust solutions to determining your shell level.– kemotep
Jun 12 at 18:52
1
Possible duplicate of How can I get the pid of a subshell?
– mosvy
Jun 13 at 5:45
5
@mosvy I feel like that is a different question. e.g. the
BASH_SUBSHELL
answer (even if controversial) wouldn't apply to that question.– Sparhawk
Jun 13 at 9:39
2
Saw the title on HNQ and thought this was a quantum mechanics question...
– Mehrdad
Jun 13 at 22:47