Are processes run from Bash run in a “sub shell”?
When I run an executable (like a.out) from a Bash shell, is that executable run in some kind of "sub" shell, i.e. different from the shell at which I'm typing?
I'll try illustrate my question with an example. The following program gets and prints the value of an environment variable, changes it, then re-gets and prints it again:
#include <iostream>
#include <string>
#include <cstdlib>
int main( int argc, char* argv )
{
std::string str( getenv( "FOO" ) );
std::cout << str << std::endl;
setenv( "FOO", "bar", 1 );
str = getenv( "FOO" );
std::cout << str << std::endl;
return 0;
}
Now, notice the output when I run the following at my Bash prompt:
>unset FOO && export FOO=foo && printf "$FOOn" && ./a.out && printf "$FOOn"
foo
foo
bar
foo
>
>unset FOO && export FOO=baz && printf "$FOOn" && ./a.out && printf "$FOOn"
baz
baz
bar
baz
So I'm exporting FOO
so it's gettable from the executable - I understand that. And the executable's output shows the envvar being changed.
But the final printf "$FOOn"
prints the pre-executable value. Is this because the executable is run in a "different environment" than where I type commands?
bash process subshell
add a comment |
When I run an executable (like a.out) from a Bash shell, is that executable run in some kind of "sub" shell, i.e. different from the shell at which I'm typing?
I'll try illustrate my question with an example. The following program gets and prints the value of an environment variable, changes it, then re-gets and prints it again:
#include <iostream>
#include <string>
#include <cstdlib>
int main( int argc, char* argv )
{
std::string str( getenv( "FOO" ) );
std::cout << str << std::endl;
setenv( "FOO", "bar", 1 );
str = getenv( "FOO" );
std::cout << str << std::endl;
return 0;
}
Now, notice the output when I run the following at my Bash prompt:
>unset FOO && export FOO=foo && printf "$FOOn" && ./a.out && printf "$FOOn"
foo
foo
bar
foo
>
>unset FOO && export FOO=baz && printf "$FOOn" && ./a.out && printf "$FOOn"
baz
baz
bar
baz
So I'm exporting FOO
so it's gettable from the executable - I understand that. And the executable's output shows the envvar being changed.
But the final printf "$FOOn"
prints the pre-executable value. Is this because the executable is run in a "different environment" than where I type commands?
bash process subshell
Beware that "subshell" has a specific meaning. A subshell is created by a shell with a fork not followed by an exec. So it is still the shell binary running, not another program like your C++ example.
– jlliagre
Feb 24 at 15:28
add a comment |
When I run an executable (like a.out) from a Bash shell, is that executable run in some kind of "sub" shell, i.e. different from the shell at which I'm typing?
I'll try illustrate my question with an example. The following program gets and prints the value of an environment variable, changes it, then re-gets and prints it again:
#include <iostream>
#include <string>
#include <cstdlib>
int main( int argc, char* argv )
{
std::string str( getenv( "FOO" ) );
std::cout << str << std::endl;
setenv( "FOO", "bar", 1 );
str = getenv( "FOO" );
std::cout << str << std::endl;
return 0;
}
Now, notice the output when I run the following at my Bash prompt:
>unset FOO && export FOO=foo && printf "$FOOn" && ./a.out && printf "$FOOn"
foo
foo
bar
foo
>
>unset FOO && export FOO=baz && printf "$FOOn" && ./a.out && printf "$FOOn"
baz
baz
bar
baz
So I'm exporting FOO
so it's gettable from the executable - I understand that. And the executable's output shows the envvar being changed.
But the final printf "$FOOn"
prints the pre-executable value. Is this because the executable is run in a "different environment" than where I type commands?
bash process subshell
When I run an executable (like a.out) from a Bash shell, is that executable run in some kind of "sub" shell, i.e. different from the shell at which I'm typing?
I'll try illustrate my question with an example. The following program gets and prints the value of an environment variable, changes it, then re-gets and prints it again:
#include <iostream>
#include <string>
#include <cstdlib>
int main( int argc, char* argv )
{
std::string str( getenv( "FOO" ) );
std::cout << str << std::endl;
setenv( "FOO", "bar", 1 );
str = getenv( "FOO" );
std::cout << str << std::endl;
return 0;
}
Now, notice the output when I run the following at my Bash prompt:
>unset FOO && export FOO=foo && printf "$FOOn" && ./a.out && printf "$FOOn"
foo
foo
bar
foo
>
>unset FOO && export FOO=baz && printf "$FOOn" && ./a.out && printf "$FOOn"
baz
baz
bar
baz
So I'm exporting FOO
so it's gettable from the executable - I understand that. And the executable's output shows the envvar being changed.
But the final printf "$FOOn"
prints the pre-executable value. Is this because the executable is run in a "different environment" than where I type commands?
bash process subshell
bash process subshell
edited Dec 16 at 4:25
Rui F Ribeiro
38.9k1479129
38.9k1479129
asked Feb 24 at 0:08
StoneThrow
417413
417413
Beware that "subshell" has a specific meaning. A subshell is created by a shell with a fork not followed by an exec. So it is still the shell binary running, not another program like your C++ example.
– jlliagre
Feb 24 at 15:28
add a comment |
Beware that "subshell" has a specific meaning. A subshell is created by a shell with a fork not followed by an exec. So it is still the shell binary running, not another program like your C++ example.
– jlliagre
Feb 24 at 15:28
Beware that "subshell" has a specific meaning. A subshell is created by a shell with a fork not followed by an exec. So it is still the shell binary running, not another program like your C++ example.
– jlliagre
Feb 24 at 15:28
Beware that "subshell" has a specific meaning. A subshell is created by a shell with a fork not followed by an exec. So it is still the shell binary running, not another program like your C++ example.
– jlliagre
Feb 24 at 15:28
add a comment |
1 Answer
1
active
oldest
votes
On Unix, each process has its own independent copy of the environment. A process gets its initial environment when its created (via fork()
) by copying the parent process's environment.
So if you add a variable to the the shell's environment before calling a.out, a.out will see it (because a.out received a copy of the shell's environment, which contained that variable).
If a.out changes the environment, that changes a.out's environment — not the shell's. If a.out were to call another program (e.g., using system()
), then that program would see the changed environment, because it'd get a copy of a.out's environment.
When a.out exits, its environment variables are destroyed; of course, if a child process were running, it'd still retain its copy (until it exits).
If you modify the environment in the shell, while a.out is still running (e.g., in the background: a.out &
), then a.out will not see the changes: the environment is only copied at process creation.
[Note this is the typical way; the execve
syscall allows you to execute a program with an environment you specify, instead of the one copied from the parent process.]
I guess in retrospect, I ought to have been able to surmise what you described: I'm familiar-ish withfork()
andexec*()
, and Bash is ultimately just another executable: so the way it "runs" processes when you type an executable name at the prompt must be some form offork()
andexec*()
, and hence subject to the rules you described. Thanks again.
– StoneThrow
Feb 24 at 1:33
add a comment |
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/3.0/"u003ecc by-sa 3.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%2f426203%2fare-processes-run-from-bash-run-in-a-sub-shell%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
On Unix, each process has its own independent copy of the environment. A process gets its initial environment when its created (via fork()
) by copying the parent process's environment.
So if you add a variable to the the shell's environment before calling a.out, a.out will see it (because a.out received a copy of the shell's environment, which contained that variable).
If a.out changes the environment, that changes a.out's environment — not the shell's. If a.out were to call another program (e.g., using system()
), then that program would see the changed environment, because it'd get a copy of a.out's environment.
When a.out exits, its environment variables are destroyed; of course, if a child process were running, it'd still retain its copy (until it exits).
If you modify the environment in the shell, while a.out is still running (e.g., in the background: a.out &
), then a.out will not see the changes: the environment is only copied at process creation.
[Note this is the typical way; the execve
syscall allows you to execute a program with an environment you specify, instead of the one copied from the parent process.]
I guess in retrospect, I ought to have been able to surmise what you described: I'm familiar-ish withfork()
andexec*()
, and Bash is ultimately just another executable: so the way it "runs" processes when you type an executable name at the prompt must be some form offork()
andexec*()
, and hence subject to the rules you described. Thanks again.
– StoneThrow
Feb 24 at 1:33
add a comment |
On Unix, each process has its own independent copy of the environment. A process gets its initial environment when its created (via fork()
) by copying the parent process's environment.
So if you add a variable to the the shell's environment before calling a.out, a.out will see it (because a.out received a copy of the shell's environment, which contained that variable).
If a.out changes the environment, that changes a.out's environment — not the shell's. If a.out were to call another program (e.g., using system()
), then that program would see the changed environment, because it'd get a copy of a.out's environment.
When a.out exits, its environment variables are destroyed; of course, if a child process were running, it'd still retain its copy (until it exits).
If you modify the environment in the shell, while a.out is still running (e.g., in the background: a.out &
), then a.out will not see the changes: the environment is only copied at process creation.
[Note this is the typical way; the execve
syscall allows you to execute a program with an environment you specify, instead of the one copied from the parent process.]
I guess in retrospect, I ought to have been able to surmise what you described: I'm familiar-ish withfork()
andexec*()
, and Bash is ultimately just another executable: so the way it "runs" processes when you type an executable name at the prompt must be some form offork()
andexec*()
, and hence subject to the rules you described. Thanks again.
– StoneThrow
Feb 24 at 1:33
add a comment |
On Unix, each process has its own independent copy of the environment. A process gets its initial environment when its created (via fork()
) by copying the parent process's environment.
So if you add a variable to the the shell's environment before calling a.out, a.out will see it (because a.out received a copy of the shell's environment, which contained that variable).
If a.out changes the environment, that changes a.out's environment — not the shell's. If a.out were to call another program (e.g., using system()
), then that program would see the changed environment, because it'd get a copy of a.out's environment.
When a.out exits, its environment variables are destroyed; of course, if a child process were running, it'd still retain its copy (until it exits).
If you modify the environment in the shell, while a.out is still running (e.g., in the background: a.out &
), then a.out will not see the changes: the environment is only copied at process creation.
[Note this is the typical way; the execve
syscall allows you to execute a program with an environment you specify, instead of the one copied from the parent process.]
On Unix, each process has its own independent copy of the environment. A process gets its initial environment when its created (via fork()
) by copying the parent process's environment.
So if you add a variable to the the shell's environment before calling a.out, a.out will see it (because a.out received a copy of the shell's environment, which contained that variable).
If a.out changes the environment, that changes a.out's environment — not the shell's. If a.out were to call another program (e.g., using system()
), then that program would see the changed environment, because it'd get a copy of a.out's environment.
When a.out exits, its environment variables are destroyed; of course, if a child process were running, it'd still retain its copy (until it exits).
If you modify the environment in the shell, while a.out is still running (e.g., in the background: a.out &
), then a.out will not see the changes: the environment is only copied at process creation.
[Note this is the typical way; the execve
syscall allows you to execute a program with an environment you specify, instead of the one copied from the parent process.]
edited Feb 24 at 13:34
Jeff Schaller
38.6k1053125
38.6k1053125
answered Feb 24 at 1:20
derobert
71.8k8152210
71.8k8152210
I guess in retrospect, I ought to have been able to surmise what you described: I'm familiar-ish withfork()
andexec*()
, and Bash is ultimately just another executable: so the way it "runs" processes when you type an executable name at the prompt must be some form offork()
andexec*()
, and hence subject to the rules you described. Thanks again.
– StoneThrow
Feb 24 at 1:33
add a comment |
I guess in retrospect, I ought to have been able to surmise what you described: I'm familiar-ish withfork()
andexec*()
, and Bash is ultimately just another executable: so the way it "runs" processes when you type an executable name at the prompt must be some form offork()
andexec*()
, and hence subject to the rules you described. Thanks again.
– StoneThrow
Feb 24 at 1:33
I guess in retrospect, I ought to have been able to surmise what you described: I'm familiar-ish with
fork()
and exec*()
, and Bash is ultimately just another executable: so the way it "runs" processes when you type an executable name at the prompt must be some form of fork()
and exec*()
, and hence subject to the rules you described. Thanks again.– StoneThrow
Feb 24 at 1:33
I guess in retrospect, I ought to have been able to surmise what you described: I'm familiar-ish with
fork()
and exec*()
, and Bash is ultimately just another executable: so the way it "runs" processes when you type an executable name at the prompt must be some form of fork()
and exec*()
, and hence subject to the rules you described. Thanks again.– StoneThrow
Feb 24 at 1:33
add a comment |
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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%2f426203%2fare-processes-run-from-bash-run-in-a-sub-shell%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
Beware that "subshell" has a specific meaning. A subshell is created by a shell with a fork not followed by an exec. So it is still the shell binary running, not another program like your C++ example.
– jlliagre
Feb 24 at 15:28