Jaki jest zakres IFS

0

Jestem zdezorientowany zakresem IFS, różne osoby wydają się myśleć, że jest on oparty na sesji w porównaniu ze skryptem po jego ustawieniu / zmianie.

Mój problem polega na tym, że przeczytałem chwilę, która ma potencjalnie puste kolumny, co kompensuje zmienne, w których je ustawiam. Jeśli zmienię ogranicznik w danych z karty i zaktualizuję IFS, aby używał tego nowego ogranicznika, obawiam się, że może to wpłynąć na inne polecenia odczytu w moim przepływie pracy.

Jeśli zrobię coś takiego:

while IFS='|' read var1 var2 var3

Czy to zmieni tylko wartość IFS dla tej konkretnej pętli while?

mike ray
źródło

Odpowiedzi:

3

Czy to zmieni tylko wartość IFS dla tej konkretnej pętli while?

Nie, w rzeczywistości zmieni to tylko dla readczęści. W whileciele pętli powróci do wartości domyślnej, ponieważ zostanie ustawiona tylko w kontekście readpolecenia.

Możesz napisać prostą pętlę nad jakimś plikiem, który to potwierdza, np. Z plikiem CSV z dwiema kolumnami:

#!/bin/bash
while IFS="," read a b; do
  echo $a $b
done < "input.csv"
echo $IFS

Ostatni wiersz danych wyjściowych będzie pusty, ponieważ domyślnie IFS jest <space>, <tab>a <newline>zatem $' \t\n'. Szczegółowe informacje można znaleźć w specyfikacji POSIX .

Jeśli (przypadkowo?) Ustawiłeś IFS na jakąś inną wartość dla całego skryptu, unset IFSresetuje go do wartości domyślnej.

Ponadto, jeśli przez „sesję” rozumiesz pojedynczy skrypt (lub powłokę wykonującą skrypt), to gdy skrypt zakończy działanie, wartość nie zostanie zapisana. Oczywiście twój terminal nie zachowuje go również podczas wielu sesji.

slhck
źródło
@DanielListon Istnieje semantyczna różnica między ustawieniem domyślnym, a ustawieniem domyślnym, ale Bash traktuje to tak samo: „Jeśli IFS jest wyłączony, lub jego wartość to dokładnie <space><tab> <newline>, domyślnie, to … ”I„ Jeśli wartość IFS jest równa null, nie występuje dzielenie słów ”. - patrz man bash.
slhck,
Dziękuję za poprawę. Powinienem był ostrzec, gdy strony podręcznika odwołują się do „ja” w IFS jako „wewnętrzny” zamiast właściwego separatora pól „wejściowych”. Opierając się na „domyślnym”, muszę przede wszystkim zakwestionować punkt lub redundancję ustawienia powłoki IFS. :(
Daniel Liston
2
while IFS='|' read var1 var2 var3

Czy to zmieni tylko wartość IFS dla tej konkretnej pętli while?

Nie. Zmieni to tylko wartość IFS dla tego konkretnego read. Ogólnie pętla jest od whiledo done, może zawierać wiele poleceń.

Ani IFSnie readsą tutaj wyjątkowe. Weź ten ogólny kod:

( export a=0
printenv a
while a=1 printenv a && printenv a; printenv a; true; do
   printenv a
   break
done; printenv a )

Wynik to:

0
1
0
0
0
0

Tylko sekunda printenvotrzymuje zmodyfikowaną wartość!

Uwagi:

  • Użyłem podpowłoki z dwóch powodów:
    1. możesz wkleić cały kod, zanim powłoka wykona cokolwiek;
    2. kod nie wpłynie na azmienną w bieżącej powłoce.
  • Użyłem printenv a, nie echo $adlatego , że w tym drugim przypadku powłoka powiększyłaby $asię do wartości widzianej przez samą powłokę jeszcze przed jej echouruchomieniem (niezależnie od tego, czy echojest ona wbudowana w powłokę, czy osobny plik wykonywalny). Składnia variable=foo some_commandrzadko zmienia zmienną dla samej powłoki (wyjątek jest variable=foo export variable). Gdybyś zmienił wszystko printenv ana echo $aw moim kodzie, 0dostałbyś all -s.
Kamil Maciorowski
źródło
-1

Tak, zgodnie z blokiem kodu wartość IFS ustawiana jest tylko dla pętli. Gdy kontrola wyjdzie z pętli, IFS zyskuje na wartości przed wejściem do pętli. Nie wpłynie to na inne operacje odczytu w tym samym skrypcie powłoki. Próbowałem czegoś takiego:

echo "Changing IFS value to ','."
OLD_IFS_VALUE=$IFS
IFS='|'
CURRENT_IFS_VALUE=$IFS
echo "IFS value before entering the loop : $CURRENT_IFS_VALUE"
while IFS=',' read name age city gender
do
    echo $name $age $city $gender
done < "testdata1.csv"
echo "After loop value of IFS : $IFS"

Więc ustawiłem IFS na „|” przed pętlą. Wewnątrz pętli użyłem wartości IFS jako „,”. Gdy kontrola wyszła z pętli, wartość IFS wynosiła „|”.

Saurabh Gupta
źródło
-1, ponieważ ścisła odpowiedź brzmi „nie”. „Gdy kontrola wyszła z pętli” powinna raczej brzmieć „po przejściu kontroli read”. Są miejsca wewnątrz pętli, których IFSnie ma ,. Zobacz moją odpowiedź.
Kamil Maciorowski,