Capture specific environment variable from Linux sub-shell











up vote
2
down vote

favorite












I am trying to figure out a way to run a shell script B from script A, set or export a variable in script B, and be able to store that value in script A after script B finishes and its sub-shell returns.



I'm not trying to source script B. I only want 1 specific variable. I can add stuff to script A, but I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture.



I'm sure there are some ugly ways, like writing out all the variables I care about in A to a file, source script B, then read everything back in from the file and restore the variables in A, besides the variable set in B that I want. I'm looking for a relatively clean and straightforward way, if one exists.










share|improve this question






















  • "I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture" -- variables set in script B (in a subshell) won't overwrite any variables in A. Child processes cannot write to their parent process's environment variables. You'll need to specifically capture them.
    – Roger Lipscombe
    yesterday










  • Exactly... that's what I want to do. I want to specifically capture them, like in the title of my question. My statement was intended to head off suggestions of sourcing script B.
    – NerdPirate
    yesterday















up vote
2
down vote

favorite












I am trying to figure out a way to run a shell script B from script A, set or export a variable in script B, and be able to store that value in script A after script B finishes and its sub-shell returns.



I'm not trying to source script B. I only want 1 specific variable. I can add stuff to script A, but I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture.



I'm sure there are some ugly ways, like writing out all the variables I care about in A to a file, source script B, then read everything back in from the file and restore the variables in A, besides the variable set in B that I want. I'm looking for a relatively clean and straightforward way, if one exists.










share|improve this question






















  • "I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture" -- variables set in script B (in a subshell) won't overwrite any variables in A. Child processes cannot write to their parent process's environment variables. You'll need to specifically capture them.
    – Roger Lipscombe
    yesterday










  • Exactly... that's what I want to do. I want to specifically capture them, like in the title of my question. My statement was intended to head off suggestions of sourcing script B.
    – NerdPirate
    yesterday













up vote
2
down vote

favorite









up vote
2
down vote

favorite











I am trying to figure out a way to run a shell script B from script A, set or export a variable in script B, and be able to store that value in script A after script B finishes and its sub-shell returns.



I'm not trying to source script B. I only want 1 specific variable. I can add stuff to script A, but I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture.



I'm sure there are some ugly ways, like writing out all the variables I care about in A to a file, source script B, then read everything back in from the file and restore the variables in A, besides the variable set in B that I want. I'm looking for a relatively clean and straightforward way, if one exists.










share|improve this question













I am trying to figure out a way to run a shell script B from script A, set or export a variable in script B, and be able to store that value in script A after script B finishes and its sub-shell returns.



I'm not trying to source script B. I only want 1 specific variable. I can add stuff to script A, but I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture.



I'm sure there are some ugly ways, like writing out all the variables I care about in A to a file, source script B, then read everything back in from the file and restore the variables in A, besides the variable set in B that I want. I'm looking for a relatively clean and straightforward way, if one exists.







linux bash shell environment-variables






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 2 days ago









NerdPirate

716




716












  • "I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture" -- variables set in script B (in a subshell) won't overwrite any variables in A. Child processes cannot write to their parent process's environment variables. You'll need to specifically capture them.
    – Roger Lipscombe
    yesterday










  • Exactly... that's what I want to do. I want to specifically capture them, like in the title of my question. My statement was intended to head off suggestions of sourcing script B.
    – NerdPirate
    yesterday


















  • "I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture" -- variables set in script B (in a subshell) won't overwrite any variables in A. Child processes cannot write to their parent process's environment variables. You'll need to specifically capture them.
    – Roger Lipscombe
    yesterday










  • Exactly... that's what I want to do. I want to specifically capture them, like in the title of my question. My statement was intended to head off suggestions of sourcing script B.
    – NerdPirate
    yesterday
















"I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture" -- variables set in script B (in a subshell) won't overwrite any variables in A. Child processes cannot write to their parent process's environment variables. You'll need to specifically capture them.
– Roger Lipscombe
yesterday




"I don't want any variables possibly set in script B to overwrite anything in script A besides what I am specifically trying to capture" -- variables set in script B (in a subshell) won't overwrite any variables in A. Child processes cannot write to their parent process's environment variables. You'll need to specifically capture them.
– Roger Lipscombe
yesterday












Exactly... that's what I want to do. I want to specifically capture them, like in the title of my question. My statement was intended to head off suggestions of sourcing script B.
– NerdPirate
yesterday




Exactly... that's what I want to do. I want to specifically capture them, like in the title of my question. My statement was intended to head off suggestions of sourcing script B.
– NerdPirate
yesterday










2 Answers
2






active

oldest

votes

















up vote
3
down vote



accepted










This other answer is good, it should be your first choice, especially if your B script does one thing and does it well (see Unix philosophy) and this "one thing" means "computing this particular variable value".



But what if the main purpose of B is to print something else? or even interact with the user? Passing additional data via stdout requires additional parsing of the retrieved result. If so, a totally independent channel of communication between B and A is highly desired. In your case one way communication is sufficient.



A temporary file is in fact quite good for it. But when you say




ugly ways, like writing out all the variables I care about in A to a file, source script B, then read everything back in from the file and restore the variables in A, besides the variable set in B that I want




you're turning the situation upside down and it's indeed ugly. The right way is to use a file to pass this one desired variable only.



In A:



tmpf_foo=$(mktemp)


Then you call B with "$tmpf_foo" as a command line argument and refer to the file by "$1" in B (or by another number, depending on the design). This may not be convenient if B already parses its command line arguments.



An alternative way is to export tmpf_foo in A and refer to the file as "$tmpf_foo" in B.



If B is a general purpose tool that can be used not only from within A, it's good to check (in B) if the file exists, before you write to it (e.g. if [ -f "$tmpf_foo" ]; then …).



Anyway, in B you write your desired value to the file. E.g. the file content will be:



12345


After B successfully finishes, in A you retrieve the value like this:



specificvariable=$(<"$tmpf_foo")


(equivalent to specificvariable=$(cat "$tmpf_foo") but without cat; not portable though).



If you need to pass more than one variable from B to A, you may use multiple lines and read them (in A) with read. But if you don't know in advance which variable(s) should be altered (or if any at all), then make B create lines in the file so it looks like this:



specificvariable=12345
othervariable="xyz 0"
bar=baz
unset var1


After B successfully finishes, in A you source the file:



. "$tmpf_foo"


Note you may pass any command this way (in the above example unset is a command) and it will be executed from within A. For this reason you should be very careful while writing to the file from within B and you should make sure no other (rogue) process can inject strings to the file.



At the end (in A) you remove the temporary file with rm "$tmpf_foo".






share|improve this answer





















  • Oh I like this. Exporting a temp file fits my use case nicely. Thanks!
    – NerdPirate
    yesterday


















up vote
5
down vote













Write that specific variable to stdout, then in A:



specificvariable=$(/path/to/B.sh)





share|improve this answer

















  • 3




    Upvoted, few notes though (mostly with inexperienced users in mind): (1) this runs B.sh, so you run the whole command instead of sole B.sh, not additionally. (2) This will capture the whole output from B.sh, so if the script writes more than the desired variable, the solution cannot be easily applied. // If you wish you can assimilate my remarks into the answer as your own (i.e. without mentioning my input); I think this would make the answer even better.
    – Kamil Maciorowski
    yesterday










  • This is a good option, however not for my use case, since B.sh does potentially emit other output. But this is a good answer for other people who make come across this question. Thanks
    – NerdPirate
    yesterday











Your Answer








StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "3"
};
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',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
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%2fsuperuser.com%2fquestions%2f1376604%2fcapture-specific-environment-variable-from-linux-sub-shell%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
3
down vote



accepted










This other answer is good, it should be your first choice, especially if your B script does one thing and does it well (see Unix philosophy) and this "one thing" means "computing this particular variable value".



But what if the main purpose of B is to print something else? or even interact with the user? Passing additional data via stdout requires additional parsing of the retrieved result. If so, a totally independent channel of communication between B and A is highly desired. In your case one way communication is sufficient.



A temporary file is in fact quite good for it. But when you say




ugly ways, like writing out all the variables I care about in A to a file, source script B, then read everything back in from the file and restore the variables in A, besides the variable set in B that I want




you're turning the situation upside down and it's indeed ugly. The right way is to use a file to pass this one desired variable only.



In A:



tmpf_foo=$(mktemp)


Then you call B with "$tmpf_foo" as a command line argument and refer to the file by "$1" in B (or by another number, depending on the design). This may not be convenient if B already parses its command line arguments.



An alternative way is to export tmpf_foo in A and refer to the file as "$tmpf_foo" in B.



If B is a general purpose tool that can be used not only from within A, it's good to check (in B) if the file exists, before you write to it (e.g. if [ -f "$tmpf_foo" ]; then …).



Anyway, in B you write your desired value to the file. E.g. the file content will be:



12345


After B successfully finishes, in A you retrieve the value like this:



specificvariable=$(<"$tmpf_foo")


(equivalent to specificvariable=$(cat "$tmpf_foo") but without cat; not portable though).



If you need to pass more than one variable from B to A, you may use multiple lines and read them (in A) with read. But if you don't know in advance which variable(s) should be altered (or if any at all), then make B create lines in the file so it looks like this:



specificvariable=12345
othervariable="xyz 0"
bar=baz
unset var1


After B successfully finishes, in A you source the file:



. "$tmpf_foo"


Note you may pass any command this way (in the above example unset is a command) and it will be executed from within A. For this reason you should be very careful while writing to the file from within B and you should make sure no other (rogue) process can inject strings to the file.



At the end (in A) you remove the temporary file with rm "$tmpf_foo".






share|improve this answer





















  • Oh I like this. Exporting a temp file fits my use case nicely. Thanks!
    – NerdPirate
    yesterday















up vote
3
down vote



accepted










This other answer is good, it should be your first choice, especially if your B script does one thing and does it well (see Unix philosophy) and this "one thing" means "computing this particular variable value".



But what if the main purpose of B is to print something else? or even interact with the user? Passing additional data via stdout requires additional parsing of the retrieved result. If so, a totally independent channel of communication between B and A is highly desired. In your case one way communication is sufficient.



A temporary file is in fact quite good for it. But when you say




ugly ways, like writing out all the variables I care about in A to a file, source script B, then read everything back in from the file and restore the variables in A, besides the variable set in B that I want




you're turning the situation upside down and it's indeed ugly. The right way is to use a file to pass this one desired variable only.



In A:



tmpf_foo=$(mktemp)


Then you call B with "$tmpf_foo" as a command line argument and refer to the file by "$1" in B (or by another number, depending on the design). This may not be convenient if B already parses its command line arguments.



An alternative way is to export tmpf_foo in A and refer to the file as "$tmpf_foo" in B.



If B is a general purpose tool that can be used not only from within A, it's good to check (in B) if the file exists, before you write to it (e.g. if [ -f "$tmpf_foo" ]; then …).



Anyway, in B you write your desired value to the file. E.g. the file content will be:



12345


After B successfully finishes, in A you retrieve the value like this:



specificvariable=$(<"$tmpf_foo")


(equivalent to specificvariable=$(cat "$tmpf_foo") but without cat; not portable though).



If you need to pass more than one variable from B to A, you may use multiple lines and read them (in A) with read. But if you don't know in advance which variable(s) should be altered (or if any at all), then make B create lines in the file so it looks like this:



specificvariable=12345
othervariable="xyz 0"
bar=baz
unset var1


After B successfully finishes, in A you source the file:



. "$tmpf_foo"


Note you may pass any command this way (in the above example unset is a command) and it will be executed from within A. For this reason you should be very careful while writing to the file from within B and you should make sure no other (rogue) process can inject strings to the file.



At the end (in A) you remove the temporary file with rm "$tmpf_foo".






share|improve this answer





















  • Oh I like this. Exporting a temp file fits my use case nicely. Thanks!
    – NerdPirate
    yesterday













up vote
3
down vote



accepted







up vote
3
down vote



accepted






This other answer is good, it should be your first choice, especially if your B script does one thing and does it well (see Unix philosophy) and this "one thing" means "computing this particular variable value".



But what if the main purpose of B is to print something else? or even interact with the user? Passing additional data via stdout requires additional parsing of the retrieved result. If so, a totally independent channel of communication between B and A is highly desired. In your case one way communication is sufficient.



A temporary file is in fact quite good for it. But when you say




ugly ways, like writing out all the variables I care about in A to a file, source script B, then read everything back in from the file and restore the variables in A, besides the variable set in B that I want




you're turning the situation upside down and it's indeed ugly. The right way is to use a file to pass this one desired variable only.



In A:



tmpf_foo=$(mktemp)


Then you call B with "$tmpf_foo" as a command line argument and refer to the file by "$1" in B (or by another number, depending on the design). This may not be convenient if B already parses its command line arguments.



An alternative way is to export tmpf_foo in A and refer to the file as "$tmpf_foo" in B.



If B is a general purpose tool that can be used not only from within A, it's good to check (in B) if the file exists, before you write to it (e.g. if [ -f "$tmpf_foo" ]; then …).



Anyway, in B you write your desired value to the file. E.g. the file content will be:



12345


After B successfully finishes, in A you retrieve the value like this:



specificvariable=$(<"$tmpf_foo")


(equivalent to specificvariable=$(cat "$tmpf_foo") but without cat; not portable though).



If you need to pass more than one variable from B to A, you may use multiple lines and read them (in A) with read. But if you don't know in advance which variable(s) should be altered (or if any at all), then make B create lines in the file so it looks like this:



specificvariable=12345
othervariable="xyz 0"
bar=baz
unset var1


After B successfully finishes, in A you source the file:



. "$tmpf_foo"


Note you may pass any command this way (in the above example unset is a command) and it will be executed from within A. For this reason you should be very careful while writing to the file from within B and you should make sure no other (rogue) process can inject strings to the file.



At the end (in A) you remove the temporary file with rm "$tmpf_foo".






share|improve this answer












This other answer is good, it should be your first choice, especially if your B script does one thing and does it well (see Unix philosophy) and this "one thing" means "computing this particular variable value".



But what if the main purpose of B is to print something else? or even interact with the user? Passing additional data via stdout requires additional parsing of the retrieved result. If so, a totally independent channel of communication between B and A is highly desired. In your case one way communication is sufficient.



A temporary file is in fact quite good for it. But when you say




ugly ways, like writing out all the variables I care about in A to a file, source script B, then read everything back in from the file and restore the variables in A, besides the variable set in B that I want




you're turning the situation upside down and it's indeed ugly. The right way is to use a file to pass this one desired variable only.



In A:



tmpf_foo=$(mktemp)


Then you call B with "$tmpf_foo" as a command line argument and refer to the file by "$1" in B (or by another number, depending on the design). This may not be convenient if B already parses its command line arguments.



An alternative way is to export tmpf_foo in A and refer to the file as "$tmpf_foo" in B.



If B is a general purpose tool that can be used not only from within A, it's good to check (in B) if the file exists, before you write to it (e.g. if [ -f "$tmpf_foo" ]; then …).



Anyway, in B you write your desired value to the file. E.g. the file content will be:



12345


After B successfully finishes, in A you retrieve the value like this:



specificvariable=$(<"$tmpf_foo")


(equivalent to specificvariable=$(cat "$tmpf_foo") but without cat; not portable though).



If you need to pass more than one variable from B to A, you may use multiple lines and read them (in A) with read. But if you don't know in advance which variable(s) should be altered (or if any at all), then make B create lines in the file so it looks like this:



specificvariable=12345
othervariable="xyz 0"
bar=baz
unset var1


After B successfully finishes, in A you source the file:



. "$tmpf_foo"


Note you may pass any command this way (in the above example unset is a command) and it will be executed from within A. For this reason you should be very careful while writing to the file from within B and you should make sure no other (rogue) process can inject strings to the file.



At the end (in A) you remove the temporary file with rm "$tmpf_foo".







share|improve this answer












share|improve this answer



share|improve this answer










answered yesterday









Kamil Maciorowski

22.6k155072




22.6k155072












  • Oh I like this. Exporting a temp file fits my use case nicely. Thanks!
    – NerdPirate
    yesterday


















  • Oh I like this. Exporting a temp file fits my use case nicely. Thanks!
    – NerdPirate
    yesterday
















Oh I like this. Exporting a temp file fits my use case nicely. Thanks!
– NerdPirate
yesterday




Oh I like this. Exporting a temp file fits my use case nicely. Thanks!
– NerdPirate
yesterday












up vote
5
down vote













Write that specific variable to stdout, then in A:



specificvariable=$(/path/to/B.sh)





share|improve this answer

















  • 3




    Upvoted, few notes though (mostly with inexperienced users in mind): (1) this runs B.sh, so you run the whole command instead of sole B.sh, not additionally. (2) This will capture the whole output from B.sh, so if the script writes more than the desired variable, the solution cannot be easily applied. // If you wish you can assimilate my remarks into the answer as your own (i.e. without mentioning my input); I think this would make the answer even better.
    – Kamil Maciorowski
    yesterday










  • This is a good option, however not for my use case, since B.sh does potentially emit other output. But this is a good answer for other people who make come across this question. Thanks
    – NerdPirate
    yesterday















up vote
5
down vote













Write that specific variable to stdout, then in A:



specificvariable=$(/path/to/B.sh)





share|improve this answer

















  • 3




    Upvoted, few notes though (mostly with inexperienced users in mind): (1) this runs B.sh, so you run the whole command instead of sole B.sh, not additionally. (2) This will capture the whole output from B.sh, so if the script writes more than the desired variable, the solution cannot be easily applied. // If you wish you can assimilate my remarks into the answer as your own (i.e. without mentioning my input); I think this would make the answer even better.
    – Kamil Maciorowski
    yesterday










  • This is a good option, however not for my use case, since B.sh does potentially emit other output. But this is a good answer for other people who make come across this question. Thanks
    – NerdPirate
    yesterday













up vote
5
down vote










up vote
5
down vote









Write that specific variable to stdout, then in A:



specificvariable=$(/path/to/B.sh)





share|improve this answer












Write that specific variable to stdout, then in A:



specificvariable=$(/path/to/B.sh)






share|improve this answer












share|improve this answer



share|improve this answer










answered 2 days ago









Ipor Sircer

3,41711014




3,41711014








  • 3




    Upvoted, few notes though (mostly with inexperienced users in mind): (1) this runs B.sh, so you run the whole command instead of sole B.sh, not additionally. (2) This will capture the whole output from B.sh, so if the script writes more than the desired variable, the solution cannot be easily applied. // If you wish you can assimilate my remarks into the answer as your own (i.e. without mentioning my input); I think this would make the answer even better.
    – Kamil Maciorowski
    yesterday










  • This is a good option, however not for my use case, since B.sh does potentially emit other output. But this is a good answer for other people who make come across this question. Thanks
    – NerdPirate
    yesterday














  • 3




    Upvoted, few notes though (mostly with inexperienced users in mind): (1) this runs B.sh, so you run the whole command instead of sole B.sh, not additionally. (2) This will capture the whole output from B.sh, so if the script writes more than the desired variable, the solution cannot be easily applied. // If you wish you can assimilate my remarks into the answer as your own (i.e. without mentioning my input); I think this would make the answer even better.
    – Kamil Maciorowski
    yesterday










  • This is a good option, however not for my use case, since B.sh does potentially emit other output. But this is a good answer for other people who make come across this question. Thanks
    – NerdPirate
    yesterday








3




3




Upvoted, few notes though (mostly with inexperienced users in mind): (1) this runs B.sh, so you run the whole command instead of sole B.sh, not additionally. (2) This will capture the whole output from B.sh, so if the script writes more than the desired variable, the solution cannot be easily applied. // If you wish you can assimilate my remarks into the answer as your own (i.e. without mentioning my input); I think this would make the answer even better.
– Kamil Maciorowski
yesterday




Upvoted, few notes though (mostly with inexperienced users in mind): (1) this runs B.sh, so you run the whole command instead of sole B.sh, not additionally. (2) This will capture the whole output from B.sh, so if the script writes more than the desired variable, the solution cannot be easily applied. // If you wish you can assimilate my remarks into the answer as your own (i.e. without mentioning my input); I think this would make the answer even better.
– Kamil Maciorowski
yesterday












This is a good option, however not for my use case, since B.sh does potentially emit other output. But this is a good answer for other people who make come across this question. Thanks
– NerdPirate
yesterday




This is a good option, however not for my use case, since B.sh does potentially emit other output. But this is a good answer for other people who make come across this question. Thanks
– NerdPirate
yesterday


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f1376604%2fcapture-specific-environment-variable-from-linux-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

サソリ

広島県道265号伴広島線

Accessing regular linux commands in Huawei's Dopra Linux