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

Clash 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.
bash process background-process
 |Â
show 1 more comment
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.
bash process background-process
3
BASHPIDmay be special, butbashpid_of_foois not. You should be able to use that in the command substitutions.
â Kusalananda
Jul 27 at 7:28
2
@Harry If you save$BASHPIDinbashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typingbashpid.
â 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 andbash, but no Perl, Python, Ruby, etc. I fought with him to let me do it inbashsince I'm mostly using/binand/usr/bincommands - coding which in Perl, Python, and Ruby can be relatively more verbose thanbash. 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 inbash: Abashfunction (and, not an external program) should be allowed +
â Harry
Jul 27 at 8:39
 |Â
show 1 more comment
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.
bash process background-process
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.
bash process background-process
edited Jul 27 at 7:54
asked Jul 27 at 6:57
Harry
3701313
3701313
3
BASHPIDmay be special, butbashpid_of_foois not. You should be able to use that in the command substitutions.
â Kusalananda
Jul 27 at 7:28
2
@Harry If you save$BASHPIDinbashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typingbashpid.
â 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 andbash, but no Perl, Python, Ruby, etc. I fought with him to let me do it inbashsince I'm mostly using/binand/usr/bincommands - coding which in Perl, Python, and Ruby can be relatively more verbose thanbash. 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 inbash: Abashfunction (and, not an external program) should be allowed +
â Harry
Jul 27 at 8:39
 |Â
show 1 more comment
3
BASHPIDmay be special, butbashpid_of_foois not. You should be able to use that in the command substitutions.
â Kusalananda
Jul 27 at 7:28
2
@Harry If you save$BASHPIDinbashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typingbashpid.
â 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 andbash, but no Perl, Python, Ruby, etc. I fought with him to let me do it inbashsince I'm mostly using/binand/usr/bincommands - coding which in Perl, Python, and Ruby can be relatively more verbose thanbash. 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 inbash: Abashfunction (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
 |Â
show 1 more comment
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.
Thebashpidapproach should work for me. But ifbashpidis the local/dynamic scope offoo, why are you passing it as an env var when callingbar?
â Harry
Jul 29 at 4:46
1
@Harry It allows for the case wherebaris a script or other application (not a function).
â Kusalananda
Jul 29 at 9:13
Then, can't we justexportit from withinfooso that ALL calls to functions or programs/scripts from withinfooautomatically 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 infooand in whatever environmentfoois executing in. In this case, you are runningfooas a background job, so it doesn't affect the otherfoos or the main script.
â Kusalananda
Jul 29 at 9:42
add a comment |Â
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.
add a comment |Â
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.
Thebashpidapproach should work for me. But ifbashpidis the local/dynamic scope offoo, why are you passing it as an env var when callingbar?
â Harry
Jul 29 at 4:46
1
@Harry It allows for the case wherebaris a script or other application (not a function).
â Kusalananda
Jul 29 at 9:13
Then, can't we justexportit from withinfooso that ALL calls to functions or programs/scripts from withinfooautomatically 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 infooand in whatever environmentfoois executing in. In this case, you are runningfooas a background job, so it doesn't affect the otherfoos or the main script.
â Kusalananda
Jul 29 at 9:42
add a comment |Â
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.
Thebashpidapproach should work for me. But ifbashpidis the local/dynamic scope offoo, why are you passing it as an env var when callingbar?
â Harry
Jul 29 at 4:46
1
@Harry It allows for the case wherebaris a script or other application (not a function).
â Kusalananda
Jul 29 at 9:13
Then, can't we justexportit from withinfooso that ALL calls to functions or programs/scripts from withinfooautomatically 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 infooand in whatever environmentfoois executing in. In this case, you are runningfooas a background job, so it doesn't affect the otherfoos or the main script.
â Kusalananda
Jul 29 at 9:42
add a comment |Â
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.
#!/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.
edited Jul 27 at 9:55
answered Jul 27 at 9:28
Kusalananda
101k13199311
101k13199311
Thebashpidapproach should work for me. But ifbashpidis the local/dynamic scope offoo, why are you passing it as an env var when callingbar?
â Harry
Jul 29 at 4:46
1
@Harry It allows for the case wherebaris a script or other application (not a function).
â Kusalananda
Jul 29 at 9:13
Then, can't we justexportit from withinfooso that ALL calls to functions or programs/scripts from withinfooautomatically 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 infooand in whatever environmentfoois executing in. In this case, you are runningfooas a background job, so it doesn't affect the otherfoos or the main script.
â Kusalananda
Jul 29 at 9:42
add a comment |Â
Thebashpidapproach should work for me. But ifbashpidis the local/dynamic scope offoo, why are you passing it as an env var when callingbar?
â Harry
Jul 29 at 4:46
1
@Harry It allows for the case wherebaris a script or other application (not a function).
â Kusalananda
Jul 29 at 9:13
Then, can't we justexportit from withinfooso that ALL calls to functions or programs/scripts from withinfooautomatically 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 infooand in whatever environmentfoois executing in. In this case, you are runningfooas a background job, so it doesn't affect the otherfoos 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
add a comment |Â
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.
add a comment |Â
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.
add a comment |Â
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.
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.
edited Jul 27 at 8:00
answered Jul 27 at 7:31
slmâ¦
232k65479649
232k65479649
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
3
BASHPIDmay be special, butbashpid_of_foois not. You should be able to use that in the command substitutions.â Kusalananda
Jul 27 at 7:28
2
@Harry If you save
$BASHPIDinbashpid, then the only thing you have to do differently in your command substitutions is to not press shift when typingbashpid.â 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 inbashsince I'm mostly using/binand/usr/bincommands - coding which in Perl, Python, and Ruby can be relatively more verbose thanbash. 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 inbash: Abashfunction (and, not an external program) should be allowed +â Harry
Jul 27 at 8:39