3

I have a while loop that allows setting variables when written one way but does not allow it when written another way. Why is that? This prints var as 1234 and does not print var2

#!/bin/bash

var=1234

while var=9876 var2=765 read line
do

    echo $var $var2
    echo $line

done <datafile

echo out of loop $var

This prints var as 9876 and also prints var2

#!/bin/bash

var=1234

while 
var=9876 
var2=765 
read line
do

    echo $var $var2
    echo $line

done <datafile

echo out of loop $var
Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233

2 Answers2

5

In your second example, by placing var and var2 on separate lines, this makes the command the same as

while var=9876; var2=765; read line

The while command allows for a list of commands before executing the commands in the do--while loop.   help while shows this:

while: while COMMANDS; do COMMANDS; done
  Execute commands as long as a test succeeds.
  Expand and execute COMMANDS as long as the final command in the
  `while' COMMANDS has an exit status of zero.
  Exit Status: Returns the status of the last command executed.

On the other hand, when a variable assignment precedes a command (in this case read), and that assignment is only followed by whitespace, the scope of that variable is local to the command ONLY! (internally)...

See:  In 'while IFS= read..', why does IFS have no effect?

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Peter.O
  • 32,916
  • You could probably get the multiline style you want using a subshell - start with an opening paren on the first line and end it before the do. You should also be able to use a bash function here too. – Danny Staple Nov 06 '11 at 23:09
  • @Danny: It really depends on what you are trying to do. eg. For read to have a local IFS value, then IFS='?' read is the only way. Note that all of the commands between while and do are called consecutively each time it loops. The while only exits when the last command exits with non-zero. Construct-wise read is independant of the 'do--doneblock. You could have your do-stuff in a command placed betweenreadanddoand have nothing indo-while`. However, to leave the while loop, the onus is on your last command to exit with a non-zero value at the appropriate time. – Peter.O Nov 07 '11 at 12:47
1

I did not know that bash could do those things, so thanks for posting them.

Here's my explanation.

This line in your first script:

while var=9876 var2=765 read line 

actually sets an environment variable named "var" to value "9876", and sets another environment variable named "var2" to value "765" but only for the command read line. It's a weird old school shell "feature". That's why the line echo $var $var2 only prints out "1234" - the environment variable named "var" only applies to read line.

The second script, where the variable assignments and the read line appear on different lines, I think that assigns shell variables named "var" and "var2" every time through the loop.