Why is a variable global when set with `read variable` inside a `while` loop, but local when set with `while read variable`?

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











up vote
0
down vote

favorite












unset myVariable i;
while [ -z "$i" ]; do
read myVariable;
echo "myVariable : '$myVariable'";
i=foo;
done;
echo "myVariable : '$myVariable'"


(the unset is there to allow replaying the command)



press any key + ENTER, you'll get :



myVariable : '[what you typed]'
myVariable : '[what you typed]'


The value of myVariable exists outside of the while loop.
Now try :



tmpFile=$(mktemp);
echo -e 'foonbarnbaz' >> "$tmpFile"
while read myVariable; do
otherVariable=whatever;
echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
done < "$tmpFile";
echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
rm "$tmpFile"


you'll get :



myVariable : 'foo', otherVariable : 'whatever'
myVariable : 'bar', otherVariable : 'whatever'
myVariable : 'baz', otherVariable : 'whatever'
myVariable : '', otherVariable : 'whatever'


The value of myVariable is lost when leaving the loop.



Why is there a different behaviour ? Is there a scope trick I'm not aware of ?



NB : running GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)










share|improve this question



























    up vote
    0
    down vote

    favorite












    unset myVariable i;
    while [ -z "$i" ]; do
    read myVariable;
    echo "myVariable : '$myVariable'";
    i=foo;
    done;
    echo "myVariable : '$myVariable'"


    (the unset is there to allow replaying the command)



    press any key + ENTER, you'll get :



    myVariable : '[what you typed]'
    myVariable : '[what you typed]'


    The value of myVariable exists outside of the while loop.
    Now try :



    tmpFile=$(mktemp);
    echo -e 'foonbarnbaz' >> "$tmpFile"
    while read myVariable; do
    otherVariable=whatever;
    echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
    done < "$tmpFile";
    echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
    rm "$tmpFile"


    you'll get :



    myVariable : 'foo', otherVariable : 'whatever'
    myVariable : 'bar', otherVariable : 'whatever'
    myVariable : 'baz', otherVariable : 'whatever'
    myVariable : '', otherVariable : 'whatever'


    The value of myVariable is lost when leaving the loop.



    Why is there a different behaviour ? Is there a scope trick I'm not aware of ?



    NB : running GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)










    share|improve this question

























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      unset myVariable i;
      while [ -z "$i" ]; do
      read myVariable;
      echo "myVariable : '$myVariable'";
      i=foo;
      done;
      echo "myVariable : '$myVariable'"


      (the unset is there to allow replaying the command)



      press any key + ENTER, you'll get :



      myVariable : '[what you typed]'
      myVariable : '[what you typed]'


      The value of myVariable exists outside of the while loop.
      Now try :



      tmpFile=$(mktemp);
      echo -e 'foonbarnbaz' >> "$tmpFile"
      while read myVariable; do
      otherVariable=whatever;
      echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
      done < "$tmpFile";
      echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
      rm "$tmpFile"


      you'll get :



      myVariable : 'foo', otherVariable : 'whatever'
      myVariable : 'bar', otherVariable : 'whatever'
      myVariable : 'baz', otherVariable : 'whatever'
      myVariable : '', otherVariable : 'whatever'


      The value of myVariable is lost when leaving the loop.



      Why is there a different behaviour ? Is there a scope trick I'm not aware of ?



      NB : running GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)










      share|improve this question















      unset myVariable i;
      while [ -z "$i" ]; do
      read myVariable;
      echo "myVariable : '$myVariable'";
      i=foo;
      done;
      echo "myVariable : '$myVariable'"


      (the unset is there to allow replaying the command)



      press any key + ENTER, you'll get :



      myVariable : '[what you typed]'
      myVariable : '[what you typed]'


      The value of myVariable exists outside of the while loop.
      Now try :



      tmpFile=$(mktemp);
      echo -e 'foonbarnbaz' >> "$tmpFile"
      while read myVariable; do
      otherVariable=whatever;
      echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
      done < "$tmpFile";
      echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
      rm "$tmpFile"


      you'll get :



      myVariable : 'foo', otherVariable : 'whatever'
      myVariable : 'bar', otherVariable : 'whatever'
      myVariable : 'baz', otherVariable : 'whatever'
      myVariable : '', otherVariable : 'whatever'


      The value of myVariable is lost when leaving the loop.



      Why is there a different behaviour ? Is there a scope trick I'm not aware of ?



      NB : running GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)







      bash shell-script variable






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Aug 21 at 13:50









      ilkkachu

      51.2k678141




      51.2k678141










      asked Aug 21 at 13:05









      Httqm

      62




      62




















          3 Answers
          3






          active

          oldest

          votes

















          up vote
          5
          down vote



          accepted











          while read myVariable; do


          The value of myVariable is lost when leaving the loop.




          No, myVariable has the value it got from the last read. The script reads from the file, until it gets to the position after the last newline. After that, the final read call gets nothing from the file, sets myVariable to the empty string accordingly, and exits with a false value since it didn't see the delimiter (newline). Then the loop ends.



          You can get a nonempty value from the final read if there's an incomplete line after the last newline:



          $ printf 'abcndefnxxx' | 
          while read a; do echo "got: $a"; done; echo "end: $a";
          got: abc
          got: def
          end: xxx


          Or use while read a || [ "$a" ]; do ... to handle the final line fragment within the loop body.






          share|improve this answer






















          • I've seen while read -r line || [[ -n $line ]]; do process "$line"; done to handle the no-trailing-newline situation
            – glenn jackman
            Aug 21 at 14:45

















          up vote
          -1
          down vote














          Because you're piping into the while loop, a sub shell is created to run the while loop. Now this child process has it's own copy of the environment and can't pass any variables back to its parent (as in any unix process).




          In this case, the done < "$tmpFile" redirection forces bash to generate a sub-shell (as for pipe).



          Quoted from bash variable scope on Stack Overflow.






          share|improve this answer


















          • 1




            there's no pipe
            – glenn jackman
            Aug 21 at 14:42










          • @glennjackman You are right, I added a clarification.
            – andcoz
            Aug 21 at 16:14

















          up vote
          -1
          down vote













          Your second example uses a while loop that has a redirected input.



          It reads using < "$tmpFile" and many shells create a sub-shell for this case. You could try to run this script with ksh93. ksh93 does not create a sub-shell in this case.



          In your specific case, the reason is completely different:



          • in the first example, you read one line from the input


          • in the second example, you read until EOF is reached


          The read command reads the input, then splits the input at IFS characters and then assigns words to the variable arguments of read.



          If there are more words than variables as parameters to the read command, the last variable gets a concatenation of the rest of the words.



          If there are less words than variables, the other variables are assigned an empty value.



          Since you hit EOF, you have no word read but one or more variable as argument to read. This causes all variables to get an empty value assigned.



          So something happened that you did not expect: EOF causes the while loop to be terminated and you see no echo command from within the while loop but only the final echo command after the while loop in this EOF case.



          This final echo now prints the variable content that was cleared from hitting EOF.






          share|improve this answer


















          • 1




            "many shells create a sub-shell for [redirection]" -- really? Do you have a reference for this? Neither bash nor dash create a subshell: echo foo > file; echo $$; while read line; do echo "$$ - $line"; done < file
            – glenn jackman
            Aug 21 at 14:44










          • This case means the while loop.
            – schily
            Aug 21 at 16:10










          • My example is bad: the shell substitutes all the variables including $$ before execution. Nevertheless, redirection does not imply subshell, I believe.
            – glenn jackman
            Aug 21 at 17:14










          • I checked the script again and added a final explanation. I hope this is a better explanation than in the other answer.
            – schily
            Aug 21 at 17:56







          • 1




            I know what you mean by "this case". But there's no subshell for a simple redirection. Using dash, compare (i) using redirection strace -f dash -c 'printf "foonbar" > file; while read line; do echo "1: $line"; done < file; echo "2: $line"' to (ii) using pipe strace -f dash -c 'printf "foonbar" | while read line; do echo "1: $line"; done; echo "2: $line"'
            – glenn jackman
            Aug 21 at 19:45











          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%2f463861%2fwhy-is-a-variable-global-when-set-with-read-variable-inside-a-while-loop-bu%23new-answer', 'question_page');

          );

          Post as a guest






























          3 Answers
          3






          active

          oldest

          votes








          3 Answers
          3






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          5
          down vote



          accepted











          while read myVariable; do


          The value of myVariable is lost when leaving the loop.




          No, myVariable has the value it got from the last read. The script reads from the file, until it gets to the position after the last newline. After that, the final read call gets nothing from the file, sets myVariable to the empty string accordingly, and exits with a false value since it didn't see the delimiter (newline). Then the loop ends.



          You can get a nonempty value from the final read if there's an incomplete line after the last newline:



          $ printf 'abcndefnxxx' | 
          while read a; do echo "got: $a"; done; echo "end: $a";
          got: abc
          got: def
          end: xxx


          Or use while read a || [ "$a" ]; do ... to handle the final line fragment within the loop body.






          share|improve this answer






















          • I've seen while read -r line || [[ -n $line ]]; do process "$line"; done to handle the no-trailing-newline situation
            – glenn jackman
            Aug 21 at 14:45














          up vote
          5
          down vote



          accepted











          while read myVariable; do


          The value of myVariable is lost when leaving the loop.




          No, myVariable has the value it got from the last read. The script reads from the file, until it gets to the position after the last newline. After that, the final read call gets nothing from the file, sets myVariable to the empty string accordingly, and exits with a false value since it didn't see the delimiter (newline). Then the loop ends.



          You can get a nonempty value from the final read if there's an incomplete line after the last newline:



          $ printf 'abcndefnxxx' | 
          while read a; do echo "got: $a"; done; echo "end: $a";
          got: abc
          got: def
          end: xxx


          Or use while read a || [ "$a" ]; do ... to handle the final line fragment within the loop body.






          share|improve this answer






















          • I've seen while read -r line || [[ -n $line ]]; do process "$line"; done to handle the no-trailing-newline situation
            – glenn jackman
            Aug 21 at 14:45












          up vote
          5
          down vote



          accepted







          up vote
          5
          down vote



          accepted







          while read myVariable; do


          The value of myVariable is lost when leaving the loop.




          No, myVariable has the value it got from the last read. The script reads from the file, until it gets to the position after the last newline. After that, the final read call gets nothing from the file, sets myVariable to the empty string accordingly, and exits with a false value since it didn't see the delimiter (newline). Then the loop ends.



          You can get a nonempty value from the final read if there's an incomplete line after the last newline:



          $ printf 'abcndefnxxx' | 
          while read a; do echo "got: $a"; done; echo "end: $a";
          got: abc
          got: def
          end: xxx


          Or use while read a || [ "$a" ]; do ... to handle the final line fragment within the loop body.






          share|improve this answer















          while read myVariable; do


          The value of myVariable is lost when leaving the loop.




          No, myVariable has the value it got from the last read. The script reads from the file, until it gets to the position after the last newline. After that, the final read call gets nothing from the file, sets myVariable to the empty string accordingly, and exits with a false value since it didn't see the delimiter (newline). Then the loop ends.



          You can get a nonempty value from the final read if there's an incomplete line after the last newline:



          $ printf 'abcndefnxxx' | 
          while read a; do echo "got: $a"; done; echo "end: $a";
          got: abc
          got: def
          end: xxx


          Or use while read a || [ "$a" ]; do ... to handle the final line fragment within the loop body.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Aug 21 at 15:05

























          answered Aug 21 at 13:55









          ilkkachu

          51.2k678141




          51.2k678141











          • I've seen while read -r line || [[ -n $line ]]; do process "$line"; done to handle the no-trailing-newline situation
            – glenn jackman
            Aug 21 at 14:45
















          • I've seen while read -r line || [[ -n $line ]]; do process "$line"; done to handle the no-trailing-newline situation
            – glenn jackman
            Aug 21 at 14:45















          I've seen while read -r line || [[ -n $line ]]; do process "$line"; done to handle the no-trailing-newline situation
          – glenn jackman
          Aug 21 at 14:45




          I've seen while read -r line || [[ -n $line ]]; do process "$line"; done to handle the no-trailing-newline situation
          – glenn jackman
          Aug 21 at 14:45












          up vote
          -1
          down vote














          Because you're piping into the while loop, a sub shell is created to run the while loop. Now this child process has it's own copy of the environment and can't pass any variables back to its parent (as in any unix process).




          In this case, the done < "$tmpFile" redirection forces bash to generate a sub-shell (as for pipe).



          Quoted from bash variable scope on Stack Overflow.






          share|improve this answer


















          • 1




            there's no pipe
            – glenn jackman
            Aug 21 at 14:42










          • @glennjackman You are right, I added a clarification.
            – andcoz
            Aug 21 at 16:14














          up vote
          -1
          down vote














          Because you're piping into the while loop, a sub shell is created to run the while loop. Now this child process has it's own copy of the environment and can't pass any variables back to its parent (as in any unix process).




          In this case, the done < "$tmpFile" redirection forces bash to generate a sub-shell (as for pipe).



          Quoted from bash variable scope on Stack Overflow.






          share|improve this answer


















          • 1




            there's no pipe
            – glenn jackman
            Aug 21 at 14:42










          • @glennjackman You are right, I added a clarification.
            – andcoz
            Aug 21 at 16:14












          up vote
          -1
          down vote










          up vote
          -1
          down vote










          Because you're piping into the while loop, a sub shell is created to run the while loop. Now this child process has it's own copy of the environment and can't pass any variables back to its parent (as in any unix process).




          In this case, the done < "$tmpFile" redirection forces bash to generate a sub-shell (as for pipe).



          Quoted from bash variable scope on Stack Overflow.






          share|improve this answer















          Because you're piping into the while loop, a sub shell is created to run the while loop. Now this child process has it's own copy of the environment and can't pass any variables back to its parent (as in any unix process).




          In this case, the done < "$tmpFile" redirection forces bash to generate a sub-shell (as for pipe).



          Quoted from bash variable scope on Stack Overflow.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Aug 21 at 16:13

























          answered Aug 21 at 14:17









          andcoz

          11.9k32938




          11.9k32938







          • 1




            there's no pipe
            – glenn jackman
            Aug 21 at 14:42










          • @glennjackman You are right, I added a clarification.
            – andcoz
            Aug 21 at 16:14












          • 1




            there's no pipe
            – glenn jackman
            Aug 21 at 14:42










          • @glennjackman You are right, I added a clarification.
            – andcoz
            Aug 21 at 16:14







          1




          1




          there's no pipe
          – glenn jackman
          Aug 21 at 14:42




          there's no pipe
          – glenn jackman
          Aug 21 at 14:42












          @glennjackman You are right, I added a clarification.
          – andcoz
          Aug 21 at 16:14




          @glennjackman You are right, I added a clarification.
          – andcoz
          Aug 21 at 16:14










          up vote
          -1
          down vote













          Your second example uses a while loop that has a redirected input.



          It reads using < "$tmpFile" and many shells create a sub-shell for this case. You could try to run this script with ksh93. ksh93 does not create a sub-shell in this case.



          In your specific case, the reason is completely different:



          • in the first example, you read one line from the input


          • in the second example, you read until EOF is reached


          The read command reads the input, then splits the input at IFS characters and then assigns words to the variable arguments of read.



          If there are more words than variables as parameters to the read command, the last variable gets a concatenation of the rest of the words.



          If there are less words than variables, the other variables are assigned an empty value.



          Since you hit EOF, you have no word read but one or more variable as argument to read. This causes all variables to get an empty value assigned.



          So something happened that you did not expect: EOF causes the while loop to be terminated and you see no echo command from within the while loop but only the final echo command after the while loop in this EOF case.



          This final echo now prints the variable content that was cleared from hitting EOF.






          share|improve this answer


















          • 1




            "many shells create a sub-shell for [redirection]" -- really? Do you have a reference for this? Neither bash nor dash create a subshell: echo foo > file; echo $$; while read line; do echo "$$ - $line"; done < file
            – glenn jackman
            Aug 21 at 14:44










          • This case means the while loop.
            – schily
            Aug 21 at 16:10










          • My example is bad: the shell substitutes all the variables including $$ before execution. Nevertheless, redirection does not imply subshell, I believe.
            – glenn jackman
            Aug 21 at 17:14










          • I checked the script again and added a final explanation. I hope this is a better explanation than in the other answer.
            – schily
            Aug 21 at 17:56







          • 1




            I know what you mean by "this case". But there's no subshell for a simple redirection. Using dash, compare (i) using redirection strace -f dash -c 'printf "foonbar" > file; while read line; do echo "1: $line"; done < file; echo "2: $line"' to (ii) using pipe strace -f dash -c 'printf "foonbar" | while read line; do echo "1: $line"; done; echo "2: $line"'
            – glenn jackman
            Aug 21 at 19:45















          up vote
          -1
          down vote













          Your second example uses a while loop that has a redirected input.



          It reads using < "$tmpFile" and many shells create a sub-shell for this case. You could try to run this script with ksh93. ksh93 does not create a sub-shell in this case.



          In your specific case, the reason is completely different:



          • in the first example, you read one line from the input


          • in the second example, you read until EOF is reached


          The read command reads the input, then splits the input at IFS characters and then assigns words to the variable arguments of read.



          If there are more words than variables as parameters to the read command, the last variable gets a concatenation of the rest of the words.



          If there are less words than variables, the other variables are assigned an empty value.



          Since you hit EOF, you have no word read but one or more variable as argument to read. This causes all variables to get an empty value assigned.



          So something happened that you did not expect: EOF causes the while loop to be terminated and you see no echo command from within the while loop but only the final echo command after the while loop in this EOF case.



          This final echo now prints the variable content that was cleared from hitting EOF.






          share|improve this answer


















          • 1




            "many shells create a sub-shell for [redirection]" -- really? Do you have a reference for this? Neither bash nor dash create a subshell: echo foo > file; echo $$; while read line; do echo "$$ - $line"; done < file
            – glenn jackman
            Aug 21 at 14:44










          • This case means the while loop.
            – schily
            Aug 21 at 16:10










          • My example is bad: the shell substitutes all the variables including $$ before execution. Nevertheless, redirection does not imply subshell, I believe.
            – glenn jackman
            Aug 21 at 17:14










          • I checked the script again and added a final explanation. I hope this is a better explanation than in the other answer.
            – schily
            Aug 21 at 17:56







          • 1




            I know what you mean by "this case". But there's no subshell for a simple redirection. Using dash, compare (i) using redirection strace -f dash -c 'printf "foonbar" > file; while read line; do echo "1: $line"; done < file; echo "2: $line"' to (ii) using pipe strace -f dash -c 'printf "foonbar" | while read line; do echo "1: $line"; done; echo "2: $line"'
            – glenn jackman
            Aug 21 at 19:45













          up vote
          -1
          down vote










          up vote
          -1
          down vote









          Your second example uses a while loop that has a redirected input.



          It reads using < "$tmpFile" and many shells create a sub-shell for this case. You could try to run this script with ksh93. ksh93 does not create a sub-shell in this case.



          In your specific case, the reason is completely different:



          • in the first example, you read one line from the input


          • in the second example, you read until EOF is reached


          The read command reads the input, then splits the input at IFS characters and then assigns words to the variable arguments of read.



          If there are more words than variables as parameters to the read command, the last variable gets a concatenation of the rest of the words.



          If there are less words than variables, the other variables are assigned an empty value.



          Since you hit EOF, you have no word read but one or more variable as argument to read. This causes all variables to get an empty value assigned.



          So something happened that you did not expect: EOF causes the while loop to be terminated and you see no echo command from within the while loop but only the final echo command after the while loop in this EOF case.



          This final echo now prints the variable content that was cleared from hitting EOF.






          share|improve this answer














          Your second example uses a while loop that has a redirected input.



          It reads using < "$tmpFile" and many shells create a sub-shell for this case. You could try to run this script with ksh93. ksh93 does not create a sub-shell in this case.



          In your specific case, the reason is completely different:



          • in the first example, you read one line from the input


          • in the second example, you read until EOF is reached


          The read command reads the input, then splits the input at IFS characters and then assigns words to the variable arguments of read.



          If there are more words than variables as parameters to the read command, the last variable gets a concatenation of the rest of the words.



          If there are less words than variables, the other variables are assigned an empty value.



          Since you hit EOF, you have no word read but one or more variable as argument to read. This causes all variables to get an empty value assigned.



          So something happened that you did not expect: EOF causes the while loop to be terminated and you see no echo command from within the while loop but only the final echo command after the while loop in this EOF case.



          This final echo now prints the variable content that was cleared from hitting EOF.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Aug 21 at 17:55

























          answered Aug 21 at 14:36









          schily

          9,63131437




          9,63131437







          • 1




            "many shells create a sub-shell for [redirection]" -- really? Do you have a reference for this? Neither bash nor dash create a subshell: echo foo > file; echo $$; while read line; do echo "$$ - $line"; done < file
            – glenn jackman
            Aug 21 at 14:44










          • This case means the while loop.
            – schily
            Aug 21 at 16:10










          • My example is bad: the shell substitutes all the variables including $$ before execution. Nevertheless, redirection does not imply subshell, I believe.
            – glenn jackman
            Aug 21 at 17:14










          • I checked the script again and added a final explanation. I hope this is a better explanation than in the other answer.
            – schily
            Aug 21 at 17:56







          • 1




            I know what you mean by "this case". But there's no subshell for a simple redirection. Using dash, compare (i) using redirection strace -f dash -c 'printf "foonbar" > file; while read line; do echo "1: $line"; done < file; echo "2: $line"' to (ii) using pipe strace -f dash -c 'printf "foonbar" | while read line; do echo "1: $line"; done; echo "2: $line"'
            – glenn jackman
            Aug 21 at 19:45













          • 1




            "many shells create a sub-shell for [redirection]" -- really? Do you have a reference for this? Neither bash nor dash create a subshell: echo foo > file; echo $$; while read line; do echo "$$ - $line"; done < file
            – glenn jackman
            Aug 21 at 14:44










          • This case means the while loop.
            – schily
            Aug 21 at 16:10










          • My example is bad: the shell substitutes all the variables including $$ before execution. Nevertheless, redirection does not imply subshell, I believe.
            – glenn jackman
            Aug 21 at 17:14










          • I checked the script again and added a final explanation. I hope this is a better explanation than in the other answer.
            – schily
            Aug 21 at 17:56







          • 1




            I know what you mean by "this case". But there's no subshell for a simple redirection. Using dash, compare (i) using redirection strace -f dash -c 'printf "foonbar" > file; while read line; do echo "1: $line"; done < file; echo "2: $line"' to (ii) using pipe strace -f dash -c 'printf "foonbar" | while read line; do echo "1: $line"; done; echo "2: $line"'
            – glenn jackman
            Aug 21 at 19:45








          1




          1




          "many shells create a sub-shell for [redirection]" -- really? Do you have a reference for this? Neither bash nor dash create a subshell: echo foo > file; echo $$; while read line; do echo "$$ - $line"; done < file
          – glenn jackman
          Aug 21 at 14:44




          "many shells create a sub-shell for [redirection]" -- really? Do you have a reference for this? Neither bash nor dash create a subshell: echo foo > file; echo $$; while read line; do echo "$$ - $line"; done < file
          – glenn jackman
          Aug 21 at 14:44












          This case means the while loop.
          – schily
          Aug 21 at 16:10




          This case means the while loop.
          – schily
          Aug 21 at 16:10












          My example is bad: the shell substitutes all the variables including $$ before execution. Nevertheless, redirection does not imply subshell, I believe.
          – glenn jackman
          Aug 21 at 17:14




          My example is bad: the shell substitutes all the variables including $$ before execution. Nevertheless, redirection does not imply subshell, I believe.
          – glenn jackman
          Aug 21 at 17:14












          I checked the script again and added a final explanation. I hope this is a better explanation than in the other answer.
          – schily
          Aug 21 at 17:56





          I checked the script again and added a final explanation. I hope this is a better explanation than in the other answer.
          – schily
          Aug 21 at 17:56





          1




          1




          I know what you mean by "this case". But there's no subshell for a simple redirection. Using dash, compare (i) using redirection strace -f dash -c 'printf "foonbar" > file; while read line; do echo "1: $line"; done < file; echo "2: $line"' to (ii) using pipe strace -f dash -c 'printf "foonbar" | while read line; do echo "1: $line"; done; echo "2: $line"'
          – glenn jackman
          Aug 21 at 19:45





          I know what you mean by "this case". But there's no subshell for a simple redirection. Using dash, compare (i) using redirection strace -f dash -c 'printf "foonbar" > file; while read line; do echo "1: $line"; done < file; echo "2: $line"' to (ii) using pipe strace -f dash -c 'printf "foonbar" | while read line; do echo "1: $line"; done; echo "2: $line"'
          – glenn jackman
          Aug 21 at 19:45


















           

          draft saved


          draft discarded















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f463861%2fwhy-is-a-variable-global-when-set-with-read-variable-inside-a-while-loop-bu%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?

          Bahrain

          Postfix configuration issue with fips on centos 7; mailgun relay