Como faço para impedir que `read` com` IFS` junte caracteres de espaço em branco? [duplicado]

Nov 26 2020

Pegue este pedaço de código que lê dados 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"

RESULTADO:

NOME: JohnDoe
PAÍS:
IDADE: 30

Deve funcionar de forma idêntica a este pedaço de código, onde estamos fazendo exatamente a mesma coisa, apenas usando \tcomo separador em vez 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"

Mas isso não acontece.

RESULTADO:

NOME: JohnDoe
PAÍS: 30
IDADE:

Bash, ou readou IFSou alguma outra parte do código está aglutinando os espaços em branco quando não deveria. Por que isso está acontecendo e como posso corrigir isso?

Respostas

3 fpmurphy Nov 26 2020 at 11:00

bashestá se comportando exatamente como deveria. Da bashdocumentação:

O shell trata cada caractere do IFS como um delimitador e divide os resultados das outras expansões em palavras nesses caracteres. Se IFS é definida, ou o seu valor é exatamente <space><tab><newline>, o padrão, então seqüências de <space>, <tab>e<newline>no início e no final dos resultados das expansões anteriores são ignorados, e qualquer sequência de caracteres IFS que não esteja no início ou no final serve para delimitar palavras. Se IFS tiver um valor diferente do padrão, as sequências de espaço de caracteres de espaço em branco e tabulação serão ignoradas no início e no final da palavra, desde que o caractere de espaço em branco esteja no valor de IFS (um caractere de espaço em branco IFS). Qualquer caractere em IFS que não seja um espaço em branco IFS, junto com quaisquer caracteres de espaço em branco IFS adjacentes, delimita um campo. Uma sequência de caracteres de espaço em branco do IFS também é tratada como um delimitador.

Para superar esse "recurso", você poderia fazer algo como o seguinte:

#!/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