I’ve written a quick-and-dirty script to time some reports from a web service:
BASE_URL='http://example.com/json/webservice/'
FIRST=1
FINAL=10000
for report_code in $(seq 1 $FINAL); do
(time -p response=$(curl --write-out %{http_code} --silent -O ${BASE_URL}/${report_code}) ) 2> ${report_code}.time
echo $response # <------- this is out of scope! How do I fix that?
if [[ $response = '404' ]]; then
echo "Deleting report # ${report_code}!"
rm ${report_code}
else
echo "${report_code} seems to be good!"
fi
done
I need to wrap the time command in a subshell so I can redirect its output, but that makes the value of $response unavailable to the parent shell. How do I get around this problem?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You can’t bring a variable’s value from a subshell to its parent, not without doing some error-prone marshalling and cumbersome communication.
Fortunately, you don’t need a subshell here. Redirection only requires command grouping with { … }, not a subshell.
{ time -p response=$(curl --write-out '%{http_code}' --silent -O "${BASE_URL}/${report_code}"); } 2> "${report_code}.time"
(Don’t forget double quotes around variable substitutions.)
Method 2
Fellow U&L users: Before downvoting my answer for using C-style with main() function, please visit this link: https://unix.stackexchange.com/a/313561/85039 Using main functions in scripts is a common practice, used by many professionals in the field.
As Gilles pointed out, subshells cannot make variables available outside of their environment. But let’s approach this problem from another angle – if you write your script in functions, it’s possible to declare variable as local and that can be edited.
From bash 4.3’s manual, local description:
…When local is used within a function, it causes the variable name to have a visible scope restricted to that function and its children…
Example:
#!/bin/bash
outter()
{
for i in $(seq 1 3)
do
var=$i
done
}
main()
{
local var=0
outter
echo $var
}
main "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b296f2">[email protected]</a>"
$ ./testscript.sh
3
As you can see after 3 iterations of the looping function, the variable is modified.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0