Why doesn't while ''IFS=, read -r part'' split a comma-separated string into two parts?
Asked Answered
E

1

6

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?

Eberle answered 1/5, 2022 at 21:14 Comment(4)
help read : "Read a line from the standard input [...] The line is split into fields [...] with any leftover words assigned to the last NAME"Keslie
read is only populating one variable, so no splitting occurs. That said, your first loop should only output hello\nworld. Your input string is one line containing the two characters \ and n, not two lines.Feininger
@chepner, smells like the OP is running somewhere echo has XPG-like behavior and is replacing the \n with a newline itself (which is odd, because that's very much not default on bash).Blackmarketeer
@yoyobara, ...are you starting your script with #!/bin/bash or running it with bash yourscript? If your interpreter were something other than bash (for example, if it were sh), that would clear up the mystery about echo behavior.Blackmarketeer
B
6

Answering The "Why" Question

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: it's thus normal and expected that $part contains the entire record, commas included.


Alternatives Where IFS Is Honored

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 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> 
Blackmarketeer answered 1/5, 2022 at 21:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.