PID of the background function, F, in commands invoked in subshells inside F

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
0
down vote

favorite












When foo is run in the background, the BASHPID of foo (bashpid_of_foo) is not available inside the bodies bar_1 to bar_n via $BASHPID, since they get invoked via the Command Substitution feature of bash:



function foo() 
local bashpid_of_foo=$BASHPID
local output

# desired to be shared by all Command Substitutions
# in the body of this function.
local log=/path/to/log.$BASHPID

... >> $log

output=$(bar_1 ...)
...
output=$(bar_n ...)


function bar_1()
# log only specific (and NOT all) messages
# to the shared log file of the invoking thread.
... >> /path/to/log.$BASHPID


foo &
foo &


Question: Is there an elegant way around the above limitation, without having to pass bashpid_of_foo via adhoc environment variables or external disk files?



By elegant, I mean, being able to keep the interfaces and bodies of bar_* functions clean by relying only on bash-provided features. (Eg BASHPID is a bash feature.)



If I try to override the value of BASHPID, like this,



out_1=$(BASHPID=$BASHPID bar_1 ...)


... it (rightly) complains about BASHPID being a readonly variable.



EDIT: (1) Added the definition of bar_1 above. (2) Added the 2nd call to foo in the background. Each foo invocation needs to maintain its own log file, since writing to a common file could result in garbled contents.



NOTE: Whatever logging happens in the runtime context of foo, I want it to go into the foo-specific log file, /path/to/log.$BASHPID WITHOUT passing around the name of this log file or even the PID of foo. foo can have multiple instances running in the background.







share|improve this question

















  • 3




    BASHPID may be special, but bashpid_of_foo is not. You should be able to use that in the command substitutions.
    – Kusalananda
    Jul 27 at 7:28






  • 2




    @Harry If you save $BASHPID in bashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid.
    – Kusalananda
    Jul 27 at 8:02






  • 2




    These are the types of best practices or tricks you have to resort to @Harry as Kusalananda is saying by keeping complex software in Bash.
    – slm♦
    Jul 27 at 8:04










  • @Kusalananda "then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid" Lol that was astute! Ok, bro.
    – Harry
    Jul 27 at 8:34










  • My boss was pressuring me to write my script in Java (yuck!). This is a customer's server - it has Java and bash, but no Perl, Python, Ruby, etc. I fought with him to let me do it in bash since I'm mostly using /bin and /usr/bin commands - coding which in Perl, Python, and Ruby can be relatively more verbose than bash. And now I run into this dead-end - which I can surely workaround (like you suggested) but would've preferred not to (by relying some existing facility. Btw, I feel, this is a feature-flaw in bash: A bash function (and, not an external program) should be allowed +
    – Harry
    Jul 27 at 8:39
















up vote
0
down vote

favorite












When foo is run in the background, the BASHPID of foo (bashpid_of_foo) is not available inside the bodies bar_1 to bar_n via $BASHPID, since they get invoked via the Command Substitution feature of bash:



function foo() 
local bashpid_of_foo=$BASHPID
local output

# desired to be shared by all Command Substitutions
# in the body of this function.
local log=/path/to/log.$BASHPID

... >> $log

output=$(bar_1 ...)
...
output=$(bar_n ...)


function bar_1()
# log only specific (and NOT all) messages
# to the shared log file of the invoking thread.
... >> /path/to/log.$BASHPID


foo &
foo &


Question: Is there an elegant way around the above limitation, without having to pass bashpid_of_foo via adhoc environment variables or external disk files?



By elegant, I mean, being able to keep the interfaces and bodies of bar_* functions clean by relying only on bash-provided features. (Eg BASHPID is a bash feature.)



If I try to override the value of BASHPID, like this,



out_1=$(BASHPID=$BASHPID bar_1 ...)


... it (rightly) complains about BASHPID being a readonly variable.



EDIT: (1) Added the definition of bar_1 above. (2) Added the 2nd call to foo in the background. Each foo invocation needs to maintain its own log file, since writing to a common file could result in garbled contents.



NOTE: Whatever logging happens in the runtime context of foo, I want it to go into the foo-specific log file, /path/to/log.$BASHPID WITHOUT passing around the name of this log file or even the PID of foo. foo can have multiple instances running in the background.







share|improve this question

















  • 3




    BASHPID may be special, but bashpid_of_foo is not. You should be able to use that in the command substitutions.
    – Kusalananda
    Jul 27 at 7:28






  • 2




    @Harry If you save $BASHPID in bashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid.
    – Kusalananda
    Jul 27 at 8:02






  • 2




    These are the types of best practices or tricks you have to resort to @Harry as Kusalananda is saying by keeping complex software in Bash.
    – slm♦
    Jul 27 at 8:04










  • @Kusalananda "then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid" Lol that was astute! Ok, bro.
    – Harry
    Jul 27 at 8:34










  • My boss was pressuring me to write my script in Java (yuck!). This is a customer's server - it has Java and bash, but no Perl, Python, Ruby, etc. I fought with him to let me do it in bash since I'm mostly using /bin and /usr/bin commands - coding which in Perl, Python, and Ruby can be relatively more verbose than bash. And now I run into this dead-end - which I can surely workaround (like you suggested) but would've preferred not to (by relying some existing facility. Btw, I feel, this is a feature-flaw in bash: A bash function (and, not an external program) should be allowed +
    – Harry
    Jul 27 at 8:39












up vote
0
down vote

favorite









up vote
0
down vote

favorite











When foo is run in the background, the BASHPID of foo (bashpid_of_foo) is not available inside the bodies bar_1 to bar_n via $BASHPID, since they get invoked via the Command Substitution feature of bash:



function foo() 
local bashpid_of_foo=$BASHPID
local output

# desired to be shared by all Command Substitutions
# in the body of this function.
local log=/path/to/log.$BASHPID

... >> $log

output=$(bar_1 ...)
...
output=$(bar_n ...)


function bar_1()
# log only specific (and NOT all) messages
# to the shared log file of the invoking thread.
... >> /path/to/log.$BASHPID


foo &
foo &


Question: Is there an elegant way around the above limitation, without having to pass bashpid_of_foo via adhoc environment variables or external disk files?



By elegant, I mean, being able to keep the interfaces and bodies of bar_* functions clean by relying only on bash-provided features. (Eg BASHPID is a bash feature.)



If I try to override the value of BASHPID, like this,



out_1=$(BASHPID=$BASHPID bar_1 ...)


... it (rightly) complains about BASHPID being a readonly variable.



EDIT: (1) Added the definition of bar_1 above. (2) Added the 2nd call to foo in the background. Each foo invocation needs to maintain its own log file, since writing to a common file could result in garbled contents.



NOTE: Whatever logging happens in the runtime context of foo, I want it to go into the foo-specific log file, /path/to/log.$BASHPID WITHOUT passing around the name of this log file or even the PID of foo. foo can have multiple instances running in the background.







share|improve this question













When foo is run in the background, the BASHPID of foo (bashpid_of_foo) is not available inside the bodies bar_1 to bar_n via $BASHPID, since they get invoked via the Command Substitution feature of bash:



function foo() 
local bashpid_of_foo=$BASHPID
local output

# desired to be shared by all Command Substitutions
# in the body of this function.
local log=/path/to/log.$BASHPID

... >> $log

output=$(bar_1 ...)
...
output=$(bar_n ...)


function bar_1()
# log only specific (and NOT all) messages
# to the shared log file of the invoking thread.
... >> /path/to/log.$BASHPID


foo &
foo &


Question: Is there an elegant way around the above limitation, without having to pass bashpid_of_foo via adhoc environment variables or external disk files?



By elegant, I mean, being able to keep the interfaces and bodies of bar_* functions clean by relying only on bash-provided features. (Eg BASHPID is a bash feature.)



If I try to override the value of BASHPID, like this,



out_1=$(BASHPID=$BASHPID bar_1 ...)


... it (rightly) complains about BASHPID being a readonly variable.



EDIT: (1) Added the definition of bar_1 above. (2) Added the 2nd call to foo in the background. Each foo invocation needs to maintain its own log file, since writing to a common file could result in garbled contents.



NOTE: Whatever logging happens in the runtime context of foo, I want it to go into the foo-specific log file, /path/to/log.$BASHPID WITHOUT passing around the name of this log file or even the PID of foo. foo can have multiple instances running in the background.









share|improve this question












share|improve this question




share|improve this question








edited Jul 27 at 7:54
























asked Jul 27 at 6:57









Harry

3701313




3701313







  • 3




    BASHPID may be special, but bashpid_of_foo is not. You should be able to use that in the command substitutions.
    – Kusalananda
    Jul 27 at 7:28






  • 2




    @Harry If you save $BASHPID in bashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid.
    – Kusalananda
    Jul 27 at 8:02






  • 2




    These are the types of best practices or tricks you have to resort to @Harry as Kusalananda is saying by keeping complex software in Bash.
    – slm♦
    Jul 27 at 8:04










  • @Kusalananda "then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid" Lol that was astute! Ok, bro.
    – Harry
    Jul 27 at 8:34










  • My boss was pressuring me to write my script in Java (yuck!). This is a customer's server - it has Java and bash, but no Perl, Python, Ruby, etc. I fought with him to let me do it in bash since I'm mostly using /bin and /usr/bin commands - coding which in Perl, Python, and Ruby can be relatively more verbose than bash. And now I run into this dead-end - which I can surely workaround (like you suggested) but would've preferred not to (by relying some existing facility. Btw, I feel, this is a feature-flaw in bash: A bash function (and, not an external program) should be allowed +
    – Harry
    Jul 27 at 8:39












  • 3




    BASHPID may be special, but bashpid_of_foo is not. You should be able to use that in the command substitutions.
    – Kusalananda
    Jul 27 at 7:28






  • 2




    @Harry If you save $BASHPID in bashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid.
    – Kusalananda
    Jul 27 at 8:02






  • 2




    These are the types of best practices or tricks you have to resort to @Harry as Kusalananda is saying by keeping complex software in Bash.
    – slm♦
    Jul 27 at 8:04










  • @Kusalananda "then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid" Lol that was astute! Ok, bro.
    – Harry
    Jul 27 at 8:34










  • My boss was pressuring me to write my script in Java (yuck!). This is a customer's server - it has Java and bash, but no Perl, Python, Ruby, etc. I fought with him to let me do it in bash since I'm mostly using /bin and /usr/bin commands - coding which in Perl, Python, and Ruby can be relatively more verbose than bash. And now I run into this dead-end - which I can surely workaround (like you suggested) but would've preferred not to (by relying some existing facility. Btw, I feel, this is a feature-flaw in bash: A bash function (and, not an external program) should be allowed +
    – Harry
    Jul 27 at 8:39







3




3




BASHPID may be special, but bashpid_of_foo is not. You should be able to use that in the command substitutions.
– Kusalananda
Jul 27 at 7:28




BASHPID may be special, but bashpid_of_foo is not. You should be able to use that in the command substitutions.
– Kusalananda
Jul 27 at 7:28




2




2




@Harry If you save $BASHPID in bashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid.
– Kusalananda
Jul 27 at 8:02




@Harry If you save $BASHPID in bashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid.
– Kusalananda
Jul 27 at 8:02




2




2




These are the types of best practices or tricks you have to resort to @Harry as Kusalananda is saying by keeping complex software in Bash.
– slm♦
Jul 27 at 8:04




These are the types of best practices or tricks you have to resort to @Harry as Kusalananda is saying by keeping complex software in Bash.
– slm♦
Jul 27 at 8:04












@Kusalananda "then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid" Lol that was astute! Ok, bro.
– Harry
Jul 27 at 8:34




@Kusalananda "then the only thing you have to do differently in your command substitutions is to not press shift when typing bashpid" Lol that was astute! Ok, bro.
– Harry
Jul 27 at 8:34












My boss was pressuring me to write my script in Java (yuck!). This is a customer's server - it has Java and bash, but no Perl, Python, Ruby, etc. I fought with him to let me do it in bash since I'm mostly using /bin and /usr/bin commands - coding which in Perl, Python, and Ruby can be relatively more verbose than bash. And now I run into this dead-end - which I can surely workaround (like you suggested) but would've preferred not to (by relying some existing facility. Btw, I feel, this is a feature-flaw in bash: A bash function (and, not an external program) should be allowed +
– Harry
Jul 27 at 8:39




My boss was pressuring me to write my script in Java (yuck!). This is a customer's server - it has Java and bash, but no Perl, Python, Ruby, etc. I fought with him to let me do it in bash since I'm mostly using /bin and /usr/bin commands - coding which in Perl, Python, and Ruby can be relatively more verbose than bash. And now I run into this dead-end - which I can surely workaround (like you suggested) but would've preferred not to (by relying some existing facility. Btw, I feel, this is a feature-flaw in bash: A bash function (and, not an external program) should be allowed +
– Harry
Jul 27 at 8:39










2 Answers
2






active

oldest

votes

















up vote
1
down vote



accepted










#!/bin/bash

bar ()
# bashpid is set in our environment from the calling function
printf 'bar BASHPID = %d, bar bashpid = %dn' "$BASHPID" "$bashpid"

# in your case, you would have...

local logfile="/some/path/to/log.$bashpid"

# etc.


foo ()
local bashpid="$BASHPID"
local message

local logfile="/some/path/to/log.$BASHPID"

message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"


foo &
foo &
foo &

wait


Example run:



$ bash script.sh
Message from bar: bar BASHPID = 71979, bar bashpid = 18461
Message from bar: bar BASHPID = 7420, bar bashpid = 71036
Message from bar: bar BASHPID = 6109, bar bashpid = 18461
Message from bar: bar BASHPID = 27868, bar bashpid = 71036
Message from bar: bar BASHPID = 44547, bar bashpid = 60086
Message from bar: bar BASHPID = 69310, bar bashpid = 71036
Message from bar: bar BASHPID = 37649, bar bashpid = 60086
Message from bar: bar BASHPID = 15999, bar bashpid = 71036
Message from bar: bar BASHPID = 81520, bar bashpid = 18461
Message from bar: bar BASHPID = 92568, bar bashpid = 60086
Message from bar: bar BASHPID = 72438, bar bashpid = 18461
Message from bar: bar BASHPID = 15094, bar bashpid = 60086


For each invocation of foo in the main part of the script, four calls to bar will be made and four lines of output will be produced. As you see, there is only three unique bashpid numbers, each from one of the foo invocations.



Another way of passing $bashpid from foo to bar is obviously to pass it as a command line argument and to receive it with local bashpid="$1" in bar or something similar, but you say you don't want to do this.






share|improve this answer























  • The bashpid approach should work for me. But if bashpid is the local/dynamic scope of foo, why are you passing it as an env var when calling bar?
    – Harry
    Jul 29 at 4:46







  • 1




    @Harry It allows for the case where bar is a script or other application (not a function).
    – Kusalananda
    Jul 29 at 9:13










  • Then, can't we just export it from within foo so that ALL calls to functions or programs/scripts from within foo automatically get it, instead of I passing it explicitly every time?
    – Harry
    Jul 29 at 9:26






  • 1




    @Harry Yes, of course, if you wish to do it that way. However, that would also set it in foo and in whatever environment foo is executing in. In this case, you are running foo as a background job, so it doesn't affect the other foos or the main script.
    – Kusalananda
    Jul 29 at 9:42

















up vote
1
down vote













NOTE: In regards to your general questions around $BASHPID, this is readonly and you cannot manipulate it. This is by design.



It's typically my general advice that when you get to the level of sophistication with Bash scripts like this, it's time to move it to Python, Ruby, whatever.




Your example



I guess I don't see what your issue is, this works for me:



$ cat subby.bash
#!/bin/bash

function foo()
local bashpid_of_foo=$BASHPID
local output=blipblop

echo "foo: $bashpid_of_foo"
echo "foo: $output"
out_1=$(echo $bashpid_of_foo)
out_n=$(echo $output)
echo "out_1: $out_1"
echo "out_n: $out_n"


foo &


$ ./subby.bash
foo: 4900
foo: blipblop
out_1: 4900
out_n: blipblop


Addition of export



If we change this around by making bar_1 into a shell script:



$ cat bar_1
#!/bin/bash

echo "from bar_1: $bashpid_of_foo"


And change your original script like this:



#!/bin/bash

function foo()
export bashpid_of_foo=$BASHPID
local output=blipblop

echo "foo: $bashpid_of_foo"
echo "foo: $output"
out_1=$(echo $bashpid_of_foo)
out_2=$(./bar_1)
out_n=$(echo $output)
echo "out_1: $out_1"
echo "out_2: $out_2"
echo "out_n: $out_n"


foo &


We can see that the $bashpid_of_foo is getting exported properly to subshells:



$ ./subby.bash
foo: 5014
foo: blipblop
out_1: 5014
out_2: from bar_1: 5014
out_n: blipblop


We need to use an export here and not just a local because otherwise the environment variables will not get exported to any children. The subshells are child shells here.



$ help export
...
Marks each NAME for automatic export to the environment of subsequently
executed commands. If VALUE is supplied, assign VALUE before exporting.





share|improve this answer























    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',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    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%2f458760%2fpid-of-the-background-function-f-in-commands-invoked-in-subshells-inside-f%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote



    accepted










    #!/bin/bash

    bar ()
    # bashpid is set in our environment from the calling function
    printf 'bar BASHPID = %d, bar bashpid = %dn' "$BASHPID" "$bashpid"

    # in your case, you would have...

    local logfile="/some/path/to/log.$bashpid"

    # etc.


    foo ()
    local bashpid="$BASHPID"
    local message

    local logfile="/some/path/to/log.$BASHPID"

    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"


    foo &
    foo &
    foo &

    wait


    Example run:



    $ bash script.sh
    Message from bar: bar BASHPID = 71979, bar bashpid = 18461
    Message from bar: bar BASHPID = 7420, bar bashpid = 71036
    Message from bar: bar BASHPID = 6109, bar bashpid = 18461
    Message from bar: bar BASHPID = 27868, bar bashpid = 71036
    Message from bar: bar BASHPID = 44547, bar bashpid = 60086
    Message from bar: bar BASHPID = 69310, bar bashpid = 71036
    Message from bar: bar BASHPID = 37649, bar bashpid = 60086
    Message from bar: bar BASHPID = 15999, bar bashpid = 71036
    Message from bar: bar BASHPID = 81520, bar bashpid = 18461
    Message from bar: bar BASHPID = 92568, bar bashpid = 60086
    Message from bar: bar BASHPID = 72438, bar bashpid = 18461
    Message from bar: bar BASHPID = 15094, bar bashpid = 60086


    For each invocation of foo in the main part of the script, four calls to bar will be made and four lines of output will be produced. As you see, there is only three unique bashpid numbers, each from one of the foo invocations.



    Another way of passing $bashpid from foo to bar is obviously to pass it as a command line argument and to receive it with local bashpid="$1" in bar or something similar, but you say you don't want to do this.






    share|improve this answer























    • The bashpid approach should work for me. But if bashpid is the local/dynamic scope of foo, why are you passing it as an env var when calling bar?
      – Harry
      Jul 29 at 4:46







    • 1




      @Harry It allows for the case where bar is a script or other application (not a function).
      – Kusalananda
      Jul 29 at 9:13










    • Then, can't we just export it from within foo so that ALL calls to functions or programs/scripts from within foo automatically get it, instead of I passing it explicitly every time?
      – Harry
      Jul 29 at 9:26






    • 1




      @Harry Yes, of course, if you wish to do it that way. However, that would also set it in foo and in whatever environment foo is executing in. In this case, you are running foo as a background job, so it doesn't affect the other foos or the main script.
      – Kusalananda
      Jul 29 at 9:42














    up vote
    1
    down vote



    accepted










    #!/bin/bash

    bar ()
    # bashpid is set in our environment from the calling function
    printf 'bar BASHPID = %d, bar bashpid = %dn' "$BASHPID" "$bashpid"

    # in your case, you would have...

    local logfile="/some/path/to/log.$bashpid"

    # etc.


    foo ()
    local bashpid="$BASHPID"
    local message

    local logfile="/some/path/to/log.$BASHPID"

    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"


    foo &
    foo &
    foo &

    wait


    Example run:



    $ bash script.sh
    Message from bar: bar BASHPID = 71979, bar bashpid = 18461
    Message from bar: bar BASHPID = 7420, bar bashpid = 71036
    Message from bar: bar BASHPID = 6109, bar bashpid = 18461
    Message from bar: bar BASHPID = 27868, bar bashpid = 71036
    Message from bar: bar BASHPID = 44547, bar bashpid = 60086
    Message from bar: bar BASHPID = 69310, bar bashpid = 71036
    Message from bar: bar BASHPID = 37649, bar bashpid = 60086
    Message from bar: bar BASHPID = 15999, bar bashpid = 71036
    Message from bar: bar BASHPID = 81520, bar bashpid = 18461
    Message from bar: bar BASHPID = 92568, bar bashpid = 60086
    Message from bar: bar BASHPID = 72438, bar bashpid = 18461
    Message from bar: bar BASHPID = 15094, bar bashpid = 60086


    For each invocation of foo in the main part of the script, four calls to bar will be made and four lines of output will be produced. As you see, there is only three unique bashpid numbers, each from one of the foo invocations.



    Another way of passing $bashpid from foo to bar is obviously to pass it as a command line argument and to receive it with local bashpid="$1" in bar or something similar, but you say you don't want to do this.






    share|improve this answer























    • The bashpid approach should work for me. But if bashpid is the local/dynamic scope of foo, why are you passing it as an env var when calling bar?
      – Harry
      Jul 29 at 4:46







    • 1




      @Harry It allows for the case where bar is a script or other application (not a function).
      – Kusalananda
      Jul 29 at 9:13










    • Then, can't we just export it from within foo so that ALL calls to functions or programs/scripts from within foo automatically get it, instead of I passing it explicitly every time?
      – Harry
      Jul 29 at 9:26






    • 1




      @Harry Yes, of course, if you wish to do it that way. However, that would also set it in foo and in whatever environment foo is executing in. In this case, you are running foo as a background job, so it doesn't affect the other foos or the main script.
      – Kusalananda
      Jul 29 at 9:42












    up vote
    1
    down vote



    accepted







    up vote
    1
    down vote



    accepted






    #!/bin/bash

    bar ()
    # bashpid is set in our environment from the calling function
    printf 'bar BASHPID = %d, bar bashpid = %dn' "$BASHPID" "$bashpid"

    # in your case, you would have...

    local logfile="/some/path/to/log.$bashpid"

    # etc.


    foo ()
    local bashpid="$BASHPID"
    local message

    local logfile="/some/path/to/log.$BASHPID"

    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"


    foo &
    foo &
    foo &

    wait


    Example run:



    $ bash script.sh
    Message from bar: bar BASHPID = 71979, bar bashpid = 18461
    Message from bar: bar BASHPID = 7420, bar bashpid = 71036
    Message from bar: bar BASHPID = 6109, bar bashpid = 18461
    Message from bar: bar BASHPID = 27868, bar bashpid = 71036
    Message from bar: bar BASHPID = 44547, bar bashpid = 60086
    Message from bar: bar BASHPID = 69310, bar bashpid = 71036
    Message from bar: bar BASHPID = 37649, bar bashpid = 60086
    Message from bar: bar BASHPID = 15999, bar bashpid = 71036
    Message from bar: bar BASHPID = 81520, bar bashpid = 18461
    Message from bar: bar BASHPID = 92568, bar bashpid = 60086
    Message from bar: bar BASHPID = 72438, bar bashpid = 18461
    Message from bar: bar BASHPID = 15094, bar bashpid = 60086


    For each invocation of foo in the main part of the script, four calls to bar will be made and four lines of output will be produced. As you see, there is only three unique bashpid numbers, each from one of the foo invocations.



    Another way of passing $bashpid from foo to bar is obviously to pass it as a command line argument and to receive it with local bashpid="$1" in bar or something similar, but you say you don't want to do this.






    share|improve this answer















    #!/bin/bash

    bar ()
    # bashpid is set in our environment from the calling function
    printf 'bar BASHPID = %d, bar bashpid = %dn' "$BASHPID" "$bashpid"

    # in your case, you would have...

    local logfile="/some/path/to/log.$bashpid"

    # etc.


    foo ()
    local bashpid="$BASHPID"
    local message

    local logfile="/some/path/to/log.$BASHPID"

    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %sn' "$message"


    foo &
    foo &
    foo &

    wait


    Example run:



    $ bash script.sh
    Message from bar: bar BASHPID = 71979, bar bashpid = 18461
    Message from bar: bar BASHPID = 7420, bar bashpid = 71036
    Message from bar: bar BASHPID = 6109, bar bashpid = 18461
    Message from bar: bar BASHPID = 27868, bar bashpid = 71036
    Message from bar: bar BASHPID = 44547, bar bashpid = 60086
    Message from bar: bar BASHPID = 69310, bar bashpid = 71036
    Message from bar: bar BASHPID = 37649, bar bashpid = 60086
    Message from bar: bar BASHPID = 15999, bar bashpid = 71036
    Message from bar: bar BASHPID = 81520, bar bashpid = 18461
    Message from bar: bar BASHPID = 92568, bar bashpid = 60086
    Message from bar: bar BASHPID = 72438, bar bashpid = 18461
    Message from bar: bar BASHPID = 15094, bar bashpid = 60086


    For each invocation of foo in the main part of the script, four calls to bar will be made and four lines of output will be produced. As you see, there is only three unique bashpid numbers, each from one of the foo invocations.



    Another way of passing $bashpid from foo to bar is obviously to pass it as a command line argument and to receive it with local bashpid="$1" in bar or something similar, but you say you don't want to do this.







    share|improve this answer















    share|improve this answer



    share|improve this answer








    edited Jul 27 at 9:55


























    answered Jul 27 at 9:28









    Kusalananda

    101k13199311




    101k13199311











    • The bashpid approach should work for me. But if bashpid is the local/dynamic scope of foo, why are you passing it as an env var when calling bar?
      – Harry
      Jul 29 at 4:46







    • 1




      @Harry It allows for the case where bar is a script or other application (not a function).
      – Kusalananda
      Jul 29 at 9:13










    • Then, can't we just export it from within foo so that ALL calls to functions or programs/scripts from within foo automatically get it, instead of I passing it explicitly every time?
      – Harry
      Jul 29 at 9:26






    • 1




      @Harry Yes, of course, if you wish to do it that way. However, that would also set it in foo and in whatever environment foo is executing in. In this case, you are running foo as a background job, so it doesn't affect the other foos or the main script.
      – Kusalananda
      Jul 29 at 9:42
















    • The bashpid approach should work for me. But if bashpid is the local/dynamic scope of foo, why are you passing it as an env var when calling bar?
      – Harry
      Jul 29 at 4:46







    • 1




      @Harry It allows for the case where bar is a script or other application (not a function).
      – Kusalananda
      Jul 29 at 9:13










    • Then, can't we just export it from within foo so that ALL calls to functions or programs/scripts from within foo automatically get it, instead of I passing it explicitly every time?
      – Harry
      Jul 29 at 9:26






    • 1




      @Harry Yes, of course, if you wish to do it that way. However, that would also set it in foo and in whatever environment foo is executing in. In this case, you are running foo as a background job, so it doesn't affect the other foos or the main script.
      – Kusalananda
      Jul 29 at 9:42















    The bashpid approach should work for me. But if bashpid is the local/dynamic scope of foo, why are you passing it as an env var when calling bar?
    – Harry
    Jul 29 at 4:46





    The bashpid approach should work for me. But if bashpid is the local/dynamic scope of foo, why are you passing it as an env var when calling bar?
    – Harry
    Jul 29 at 4:46





    1




    1




    @Harry It allows for the case where bar is a script or other application (not a function).
    – Kusalananda
    Jul 29 at 9:13




    @Harry It allows for the case where bar is a script or other application (not a function).
    – Kusalananda
    Jul 29 at 9:13












    Then, can't we just export it from within foo so that ALL calls to functions or programs/scripts from within foo automatically get it, instead of I passing it explicitly every time?
    – Harry
    Jul 29 at 9:26




    Then, can't we just export it from within foo so that ALL calls to functions or programs/scripts from within foo automatically get it, instead of I passing it explicitly every time?
    – Harry
    Jul 29 at 9:26




    1




    1




    @Harry Yes, of course, if you wish to do it that way. However, that would also set it in foo and in whatever environment foo is executing in. In this case, you are running foo as a background job, so it doesn't affect the other foos or the main script.
    – Kusalananda
    Jul 29 at 9:42




    @Harry Yes, of course, if you wish to do it that way. However, that would also set it in foo and in whatever environment foo is executing in. In this case, you are running foo as a background job, so it doesn't affect the other foos or the main script.
    – Kusalananda
    Jul 29 at 9:42












    up vote
    1
    down vote













    NOTE: In regards to your general questions around $BASHPID, this is readonly and you cannot manipulate it. This is by design.



    It's typically my general advice that when you get to the level of sophistication with Bash scripts like this, it's time to move it to Python, Ruby, whatever.




    Your example



    I guess I don't see what your issue is, this works for me:



    $ cat subby.bash
    #!/bin/bash

    function foo()
    local bashpid_of_foo=$BASHPID
    local output=blipblop

    echo "foo: $bashpid_of_foo"
    echo "foo: $output"
    out_1=$(echo $bashpid_of_foo)
    out_n=$(echo $output)
    echo "out_1: $out_1"
    echo "out_n: $out_n"


    foo &


    $ ./subby.bash
    foo: 4900
    foo: blipblop
    out_1: 4900
    out_n: blipblop


    Addition of export



    If we change this around by making bar_1 into a shell script:



    $ cat bar_1
    #!/bin/bash

    echo "from bar_1: $bashpid_of_foo"


    And change your original script like this:



    #!/bin/bash

    function foo()
    export bashpid_of_foo=$BASHPID
    local output=blipblop

    echo "foo: $bashpid_of_foo"
    echo "foo: $output"
    out_1=$(echo $bashpid_of_foo)
    out_2=$(./bar_1)
    out_n=$(echo $output)
    echo "out_1: $out_1"
    echo "out_2: $out_2"
    echo "out_n: $out_n"


    foo &


    We can see that the $bashpid_of_foo is getting exported properly to subshells:



    $ ./subby.bash
    foo: 5014
    foo: blipblop
    out_1: 5014
    out_2: from bar_1: 5014
    out_n: blipblop


    We need to use an export here and not just a local because otherwise the environment variables will not get exported to any children. The subshells are child shells here.



    $ help export
    ...
    Marks each NAME for automatic export to the environment of subsequently
    executed commands. If VALUE is supplied, assign VALUE before exporting.





    share|improve this answer



























      up vote
      1
      down vote













      NOTE: In regards to your general questions around $BASHPID, this is readonly and you cannot manipulate it. This is by design.



      It's typically my general advice that when you get to the level of sophistication with Bash scripts like this, it's time to move it to Python, Ruby, whatever.




      Your example



      I guess I don't see what your issue is, this works for me:



      $ cat subby.bash
      #!/bin/bash

      function foo()
      local bashpid_of_foo=$BASHPID
      local output=blipblop

      echo "foo: $bashpid_of_foo"
      echo "foo: $output"
      out_1=$(echo $bashpid_of_foo)
      out_n=$(echo $output)
      echo "out_1: $out_1"
      echo "out_n: $out_n"


      foo &


      $ ./subby.bash
      foo: 4900
      foo: blipblop
      out_1: 4900
      out_n: blipblop


      Addition of export



      If we change this around by making bar_1 into a shell script:



      $ cat bar_1
      #!/bin/bash

      echo "from bar_1: $bashpid_of_foo"


      And change your original script like this:



      #!/bin/bash

      function foo()
      export bashpid_of_foo=$BASHPID
      local output=blipblop

      echo "foo: $bashpid_of_foo"
      echo "foo: $output"
      out_1=$(echo $bashpid_of_foo)
      out_2=$(./bar_1)
      out_n=$(echo $output)
      echo "out_1: $out_1"
      echo "out_2: $out_2"
      echo "out_n: $out_n"


      foo &


      We can see that the $bashpid_of_foo is getting exported properly to subshells:



      $ ./subby.bash
      foo: 5014
      foo: blipblop
      out_1: 5014
      out_2: from bar_1: 5014
      out_n: blipblop


      We need to use an export here and not just a local because otherwise the environment variables will not get exported to any children. The subshells are child shells here.



      $ help export
      ...
      Marks each NAME for automatic export to the environment of subsequently
      executed commands. If VALUE is supplied, assign VALUE before exporting.





      share|improve this answer

























        up vote
        1
        down vote










        up vote
        1
        down vote









        NOTE: In regards to your general questions around $BASHPID, this is readonly and you cannot manipulate it. This is by design.



        It's typically my general advice that when you get to the level of sophistication with Bash scripts like this, it's time to move it to Python, Ruby, whatever.




        Your example



        I guess I don't see what your issue is, this works for me:



        $ cat subby.bash
        #!/bin/bash

        function foo()
        local bashpid_of_foo=$BASHPID
        local output=blipblop

        echo "foo: $bashpid_of_foo"
        echo "foo: $output"
        out_1=$(echo $bashpid_of_foo)
        out_n=$(echo $output)
        echo "out_1: $out_1"
        echo "out_n: $out_n"


        foo &


        $ ./subby.bash
        foo: 4900
        foo: blipblop
        out_1: 4900
        out_n: blipblop


        Addition of export



        If we change this around by making bar_1 into a shell script:



        $ cat bar_1
        #!/bin/bash

        echo "from bar_1: $bashpid_of_foo"


        And change your original script like this:



        #!/bin/bash

        function foo()
        export bashpid_of_foo=$BASHPID
        local output=blipblop

        echo "foo: $bashpid_of_foo"
        echo "foo: $output"
        out_1=$(echo $bashpid_of_foo)
        out_2=$(./bar_1)
        out_n=$(echo $output)
        echo "out_1: $out_1"
        echo "out_2: $out_2"
        echo "out_n: $out_n"


        foo &


        We can see that the $bashpid_of_foo is getting exported properly to subshells:



        $ ./subby.bash
        foo: 5014
        foo: blipblop
        out_1: 5014
        out_2: from bar_1: 5014
        out_n: blipblop


        We need to use an export here and not just a local because otherwise the environment variables will not get exported to any children. The subshells are child shells here.



        $ help export
        ...
        Marks each NAME for automatic export to the environment of subsequently
        executed commands. If VALUE is supplied, assign VALUE before exporting.





        share|improve this answer















        NOTE: In regards to your general questions around $BASHPID, this is readonly and you cannot manipulate it. This is by design.



        It's typically my general advice that when you get to the level of sophistication with Bash scripts like this, it's time to move it to Python, Ruby, whatever.




        Your example



        I guess I don't see what your issue is, this works for me:



        $ cat subby.bash
        #!/bin/bash

        function foo()
        local bashpid_of_foo=$BASHPID
        local output=blipblop

        echo "foo: $bashpid_of_foo"
        echo "foo: $output"
        out_1=$(echo $bashpid_of_foo)
        out_n=$(echo $output)
        echo "out_1: $out_1"
        echo "out_n: $out_n"


        foo &


        $ ./subby.bash
        foo: 4900
        foo: blipblop
        out_1: 4900
        out_n: blipblop


        Addition of export



        If we change this around by making bar_1 into a shell script:



        $ cat bar_1
        #!/bin/bash

        echo "from bar_1: $bashpid_of_foo"


        And change your original script like this:



        #!/bin/bash

        function foo()
        export bashpid_of_foo=$BASHPID
        local output=blipblop

        echo "foo: $bashpid_of_foo"
        echo "foo: $output"
        out_1=$(echo $bashpid_of_foo)
        out_2=$(./bar_1)
        out_n=$(echo $output)
        echo "out_1: $out_1"
        echo "out_2: $out_2"
        echo "out_n: $out_n"


        foo &


        We can see that the $bashpid_of_foo is getting exported properly to subshells:



        $ ./subby.bash
        foo: 5014
        foo: blipblop
        out_1: 5014
        out_2: from bar_1: 5014
        out_n: blipblop


        We need to use an export here and not just a local because otherwise the environment variables will not get exported to any children. The subshells are child shells here.



        $ help export
        ...
        Marks each NAME for automatic export to the environment of subsequently
        executed commands. If VALUE is supplied, assign VALUE before exporting.






        share|improve this answer















        share|improve this answer



        share|improve this answer








        edited Jul 27 at 8:00


























        answered Jul 27 at 7:31









        slm♦

        232k65479649




        232k65479649






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f458760%2fpid-of-the-background-function-f-in-commands-invoked-in-subshells-inside-f%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            Displaying single band from multi-band raster using QGIS

            How many registers does an x86_64 CPU actually have?