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.
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"
.
No comments:
Post a Comment