Are processes run from Bash run in a “sub shell”?












1














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?










share|improve this question
























  • 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
















1














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?










share|improve this question
























  • 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














1












1








1







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?










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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


















  • 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










1 Answer
1






active

oldest

votes


















3














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.]






share|improve this answer























  • 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











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
});


}
});














draft saved

draft discarded


















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









3














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.]






share|improve this answer























  • 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
















3














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.]






share|improve this answer























  • 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














3












3








3






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.]






share|improve this answer














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.]







share|improve this answer














share|improve this answer



share|improve this answer








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 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
















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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Morgemoulin

Scott Moir

Souastre