11

I'm a little confused with my script regarding functions, variable scope, and possibly subshells. I saw in another post that pipes spawn a subshell and the parent shell can't access variables from the subshell. Is this the same case with cmds run in backticks too?

To not bore people, I've shortened my 100+ line script but I tried to remember to leave in the important elements (i.e. backticks, pipes etc). Hopefully I didn't leave anything out.

global1=0
global2=0
start_read=true

function testfunc {
   global1=9999
   global2=1111
   echo "in testfunc"
   echo $global1
   echo $global2
}

file1=whocares
file2=whocares2

for line in `cat $file1`
do
   for i in `grep -P "\w+ stream" $file2 | grep "$line"`   # possible but unlikely problem spot
   do
         end=$(echo $i | cut -d ' ' -f 1-4 | cut -d ',' -f 1)   # possible but unlikely spot
         duration=`testfunc $end`       # more likely problem spot
   done
done

echo "global1 = $global1"
echo "global2 = $global2"

So when I run my script, the last line says global1 = 0. However, in my function testfunc, global1 gets set to 9999 and the debug msgs print out that within the function at least, it is 9999.

Two questions here:

  1. Do the backticks spawn a subshell and thus making my script not work?
  2. How do I work around this issue?
4
  • 1
    1. Yes they do 2. Quick fix: remove the backticks and move the assignment in the function definition. Alternatively write global1= ` testfunc $end ` Commented Jan 8, 2014 at 21:21
  • As an aside, those nested for loops look really twisted and inefficient. I guess you are trying to say grep -P "\w+ stream" "$file2" | grep -f "$file1" | while read i; do... Commented Jan 8, 2014 at 21:38
  • @damienfrancois, thx for your reply. testfunc modifies several global vars. I guess that's one thing I forgot to include. Commented Jan 8, 2014 at 22:11
  • ok, then you can try replacing duration= ` testfunc $end ` with simply testfunc $end and adding duration=... in the body of the function. You can really think of bash functions as macro that are simply expanded inline. Commented Jan 8, 2014 at 22:15

2 Answers 2

3

You can try something like

global1=0
global2=0
start_read=true

function testfunc {
   global1=9999
   global2=1111
   echo "in testfunc"
   echo $global1
   echo $global2
   duration=something
}

file1=whocares
file2=whocares2

for line in `cat $file1`
do
   for i in `grep -P "\w+ stream" $file2 | grep "$line"`   # possible but unlikely problem spot
   do
         end=$(echo $i | cut -d ' ' -f 1-4 | cut -d ',' -f 1)   # possible but unlikely spot
         testfunc $end       # more likely problem spot
   done
done

echo "global1 = $global1"
echo "global2 = $global2"
Sign up to request clarification or add additional context in comments.

1 Comment

Difference to the script of the OP: (1) duration=something has been added to the function body; (2) duration=`testfunc $end` in the loop has been changed to testfunc $end
3

Do the backticks spawn a subshell and thus making my script not work?:

Yes they do and any changes made in variable in a subshell are not visible in parent shell.

How do I work around this issue?

You can probably try this loop that avoid spawning a subshell:

while read line
do
   while read i
   do
      end=$(echo $i | cut -d ' ' -f 1-4 | cut -d ',' -f 1)
      duration=$(testfunc "$end")
   done < <(grep -P "\w+ stream" "$file2" | grep "$line")
done < "$file1"

PS: But testfunc will still be called in sub process.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.