¿Cómo evito que `read` con` IFS` combine caracteres de espacio en blanco? [duplicar]

Nov 26 2020

Tome este fragmento de código que lee datos separados por |

DATA1="Andreas|Sweden|27"
DATA2="JohnDoe||30"   # <---- UNKNOWN COUNTRY
while IFS="|" read -r NAME COUNTRY AGE; do 
    echo "NAME:    $NAME"; echo "COUNTRY: $COUNTRY";
    echo "AGE:     $AGE"; done<<<"$DATA2"

SALIDA:

NOMBRE: JohnDoe
PAÍS:
EDAD: 30

Debería funcionar de manera idéntica a este fragmento de código, donde estamos haciendo exactamente lo mismo, solo usándolo \tcomo separador en lugar de|

DATA1="Andreas  Sweden  27"
DATA2="JohnDoe      30"  # <---- THERE ARE TWO TABS HERE
while IFS=$'\t' read -r NAME COUNTRY AGE; do echo "NAME: $NAME";
    echo "COUNTRY: $COUNTRY"; echo "AGE: $AGE";
done<<<"$DATA2"

Pero no es así.

OUTPUT:

NAME: JohnDoe
COUNTRY: 30
AGE:

Bash, or read or IFS or some other part of the code is globbing together the whitespace when it isn't supposed to. Why is this happening, and how can I fix it?

Respuestas

3 fpmurphy Nov 26 2020 at 11:00

bash is behaving exactly as it should. From the bash documentation:

The shell treats each character of IFS as a delimiter, and splits the results of the other expansions into words on these characters. If IFS is unset, or its value is exactly <space><tab><newline>, the default, then sequences of <space>, <tab>, and <newline> at the beginning and end of the results of the previous expansions are ignored, and any sequence of IFS characters not at the beginning or end serves to delimit words. If IFS has a value other than the default, then sequences of the whitespace characters space and tab are ignored at the beginning and end of the word, as long as the whitespace character is in the value of IFS (an IFS whitespace character). Any character in IFS that is not IFS whitespace, along with any adjacent IFS whitespace characters, delimits a field. A sequence of IFS whitespace characters is also treated as a delimiter.

To overcome this "feature", you could do something like the following:

#!/bin/bash

DATA1="Andreas  Sweden  27"
DATA2="JohnDoe          30"  # <---- THERE ARE TWO TABS HERE

echo "$DATA2" | sed 's/\t/;/g' | while IFS=';' read -r NAME COUNTRY AGE; do echo "NAME: $NAME"
    echo "COUNTRY: $COUNTRY" echo "AGE: $AGE"
done