Jak zapobiec łączeniu ze sobą białych znaków przez „read” z „IFS”? [duplikować]
Weź ten fragment kodu, który wczytuje dane oddzielone |
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"
WYNIK:
IMIĘ: JohnDoe
KRAJ:
WIEK: 30
Powinien działać identycznie jak ten fragment kodu, w którym robimy dokładnie to samo, używając tylko \t
jako separatora zamiast|
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"
Ale tak nie jest.
WYNIK:
IMIĘ: JohnDoe
KRAJ: 30
WIEK:
Bash, lub read
lub IFS
lub jakaś inna część kodu jest globbing razem białe znaki, gdy nie ma. Dlaczego tak się dzieje i jak mogę to naprawić?
Odpowiedzi
bash
zachowuje się dokładnie tak, jak powinien. Z bash
dokumentacji:
Powłoka traktuje każdy znak IFS jako separator i dzieli wyniki innych rozwinięć na słowa dla tych znaków. Jeżeli IFS nie jest ustawione, czy jego wartość jest dokładnie
<space><tab><newline>
, domyślny, a następnie sekwencje<space>
,<tab>
oraz<newline>
na początku i na końcu wyniki poprzednich rozwinięć są ignorowane, a każda sekwencja znaków IFS nie na początku lub na końcu służy do rozgraniczenia słów. Jeśli IFS ma wartość inną niż domyślna, sekwencje białych znaków spacji i tabulacji są ignorowane na początku i na końcu słowa, o ile biały znak znajduje się w wartości IFS (biały znak IFS). Każdy znak w IFS, który nie jest białą spacją IFS, wraz z sąsiednimi białymi znakami IFS, ogranicza pole. Sekwencja białych znaków IFS jest również traktowana jako separator.
Aby obejść tę „funkcję”, możesz zrobić coś takiego:
#!/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