since the default value of the IFS variable is a newline/tab/space, the following code:
while read -r line
do
echo $line
done <<< "hello\nworld"
outputs:
hello
world
but, if I understand it correctly, I can change it so it will separate it by, comma for example.
so this code:
while IFS=',' read -r part
do
echo $part
done <<< "hello,world"
but this one just outputs:
hello,world
and I expected it to print the same as the script from before.
what am I missing here?
CodePudding user response:
IFS is a field separator, not a record separator. (The default record separator is the newline; it can be changed with the -d
argument to read
). Each call to read
reads a single record, and optionally splits it into multiple variables at field boundaries.
When you run read -r part
, you're reading only one record (the one that goes into part
), so there's no separating to be done. By contrast, if you used -a
to specify your destination as an array (read -r -a parts
) or passed more than one destination variable (read -r part1 part2 part3
), splitting into fields would take place.
Compare to:
while IFS=, read -r part; do
echo "part=$part"
done <<<"hello,world"
...or...
while IFS=, read -r key value; do
echo "key=$key, value=$value"
done <<EOF
hello,world
hi,neighbor
EOF
Similarly, one can read a line into an array:
while IFS=, read -r -a parts; do # split on comma into array
printf 'Read %d parts: ' "${#parts[@]}" # count items in array
printf '<%s> ' "${parts[@]}" # print those items in arrow brackets
printf '\n'
done <<EOF
three,word,array
this,is,four,words
EOF
...which, as expected, emits:
Read 3 parts: <three> <word> <array>
Read 4 parts: <this> <is> <four> <words>
CodePudding user response:
These are working identically. In the example, read
is executing exactly once. There's no splitting going on. Try adding an extra step and you'll see this:
while read -r line
do
echo $line; echo ---
done <<< "hello\nworld"
Outputs:
hello
world
---
read
always reads a full line into the variables given (with all left overs added to the last one). If you want it be split up into an array rather than a list of variables, you can use -A
:
while IFS=',' read -rA line
do
for part in $line; do echo "$part"; done
done <<< "hello,world"
This will do what you're expecting, I believe.