Capture specific environment variable from Linux sub-shell











up vote
2
down vote

favorite
1












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
    2 hours ago















up vote
2
down vote

favorite
1












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
    2 hours ago













up vote
2
down vote

favorite
1









up vote
2
down vote

favorite
1






1





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 11 hours ago









NerdPirate

694




694












  • "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
    2 hours ago


















  • "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
    2 hours ago
















"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
2 hours ago




"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
2 hours ago










2 Answers
2






active

oldest

votes

















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
    9 hours ago


















up vote
2
down vote













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





















    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
    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
      9 hours ago















    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
      9 hours ago













    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 10 hours 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
      9 hours ago














    • 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
      9 hours ago








    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
    9 hours ago




    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
    9 hours ago












    up vote
    2
    down vote













    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

























      up vote
      2
      down vote













      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























        up vote
        2
        down vote










        up vote
        2
        down vote









        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 8 hours ago









        Kamil Maciorowski

        22.5k155072




        22.5k155072






























             

            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

            Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

            Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

            A Topological Invariant for $pi_3(U(n))$