It's because the first version doesn't set IFS
to "/" until after the first line has been read and split. When and where you set a variable determines what it affects, and it's important to understand the differences.
Walking through what gets executed might help. When the script reaches the while
loop, it first executes the while
clause:
while read -r owner provider version
...which reads the first line from the file. Since IFS
still has its default value (space + tab + newline) at this point, the line is split based on that (i.e. not split at all), so the entire line goes in the owner
variable.
Next, since the while
clause succeeded, the body of the while
loop executes:
IFS=/
echo $owner
...this sets IFS
and then echo
es $owner
. Since $owner
is not double-quoted, and by the time that runs IFS
has been set to "/", the value gets word-split based on "/", so what's effectively executed is echo "hashicorp" "aws" "4.27.0"
, which sort-of has the effect of turning the "/" characters in the variable into spaces. This sort of weird parsing effect is why you should almost always double-quote variable references.
Next, the loop runs again. This time IFS
has been set to "/", so the read
command will split the line based on that, and from this point on it'll behave as you expect.
Now, compare that to the second version:
while IFS=/ read -r owner provider version; do
Here, the assignment to IFS
isn't a separate command, it's a prefix to the read
command. This means it always applies to the read
command, and also makes it apply only to the read
command. So it applies every time read
runs, and also it doesn't affect other things later, like any unquoted variable references. Setting IFS
to a nonstandard value can cause trouble, and restricting it to a single command like this is a good way to keep it from causing trouble later.
Lessons: 1) Double-quote your variables, and 2) set IFS
as a prefix to specific commands when possible (when that's not possible, set it before the command it needs to affect, and then set it back to normal as soon as possible afterward).