Wydaje się, że normalna praktyka wystawiałaby ustawienie IFS poza pętlę while, aby nie powtarzać ustawiania go dla każdej iteracji ... Czy jest to zwykły styl „małpa patrz, małpa robi”, jak to miało miejsce w przypadku tej małpy do Czytam mężczyznę czytającego , czy brakuje mi tutaj jakiejś subtelnej (lub rażąco oczywistej) pułapki?
81
while IFS=X read
nie dzieli się naX
, alewhile IFS=X; read
...while
nie ma sensu - stan nawhile
końcach w tym średnikiem, więc nie ma rzeczywistego pętla ...read
staje się właśnie pierwsze polecenie wewnątrz pętli jednego elementu ... Albo nie ? Codo
wtedy ...?while
stanie (wcześniejdo
).IFS=
działa, aleIFS=X
nie ... (a może ja przedawkowała na to za jakiś czas .. przerwa kawowa potrzebne :)Spójrzmy na przykład z starannie przygotowanym tekstem wejściowym:
To dwie linie, pierwsza zaczynająca się spacją i kończąca się odwrotnym ukośnikiem. Po pierwsze, spójrzmy na to, co się dzieje bez żadnych środków ostrożności
read
(ale używającprintf '%s\n' "$text"
do ostrożnego drukowania$text
bez ryzyka ekspansji). (Poniżej$
znajduje się monit powłoki).read
zjadł ukośniki odwrotne: ukośnik-nowa linia powoduje zignorowanie nowej linii, a ukośnik-cokolwiek ignoruje ten pierwszy ukośnik. Aby uniknąć specjalnego traktowania ukośników odwrotnych, używamyread -r
.Tak lepiej, mamy dwie linie zgodnie z oczekiwaniami. Dwie linie prawie zawierają pożądaną treść: podwójna spacja między
hello
iworld
została zachowana, ponieważ znajduje się wline
zmiennej. Z drugiej strony początkowa przestrzeń została zjedzona. Dzieje się tak, ponieważread
odczytuje tyle słów, ile przekazujesz, zmienne, z tą różnicą, że ostatnia zmienna zawiera resztę wiersza - ale wciąż zaczyna się od pierwszego słowa, tzn. Początkowe spacje są odrzucane.Tak więc, aby odczytać każdą linię dosłownie, musimy upewnić się, że nie dochodzi do podziału słów . Robimy to, ustawiając
IFS
zmienną na pustą wartość.Zwróć uwagę, jak ustawiliśmy
IFS
specjalnie na czas trwaniaread
wbudowanego . WIFS= read -r line
ustawia zmienne środowiskaIFS
(na pusty wartość) specjalnie dla realizacjiread
. Jest to przykład ogólnej składni komend prostych : (być może pusta) sekwencja przypisań zmiennych, po której następuje nazwa komendy i jej argumenty (można także przekierowywać w dowolnym momencie). Ponieważread
jest to funkcja wbudowana, zmienna nigdy nie kończy się w środowisku zewnętrznego procesu; niemniej jednak wartość$IFS
jest przypisywana tak długo, jak długoread
jest wykonywana¹. Pamiętaj, żeread
nie jest to specjalne wbudowane , więc zadanie trwa tylko przez czas jego trwania.Dlatego staramy się nie zmieniać wartości
IFS
innych instrukcji, które mogą na nim polegać. Ten kod będzie działał bez względu na to, coIFS
początkowo ustawił otaczający kod i nie spowoduje żadnych problemów, jeśli kod w pętli będzie polegałIFS
.Porównaj z tym fragmentem kodu, który wyszukuje pliki w ścieżce oddzielonej dwukropkami. Lista nazw plików jest odczytywana z pliku, jedna nazwa pliku w wierszu.
Jeśli pętla była
while IFS=; read -r name; do …
, tofor dir in $PATH
nie podzieliłaby się$PATH
na składniki oddzielone dwukropkami. Gdyby kod byłIFS=; while read …
, byłoby jeszcze bardziej oczywiste, żeIFS
nie jest ustawione:
w treści pętli.Oczywiście możliwe byłoby przywrócenie wartości
IFS
po wykonaniuread
. Wymagałoby to jednak znajomości poprzedniej wartości, która stanowi dodatkowy wysiłek.IFS= read
to prosty sposób (i dogodnie także najkrótszy sposób).¹ A jeśli
read
zostanie przerwany przez sygnał pułapki, być może podczas działania pułapki - nie jest to określone przez POSIX i zależy od powłoki w praktyce.źródło
while IFS= read
(bez średnika po=
) nie jest specjalną postaciąwhile
ani zIFS
lub zread
.. Konstrukt jest ogólny: tj.anyvar=anyvalue anycommand
. Brak;
ustawienia poanyvar
powoduje, że zakres pętlianyvar
lokalnej doanycommand
... Pętla while - do / done jest w 100% niezwiązana z zakresem lokalnymany_var
.Oprócz (już wyjaśnionego)
IFS
różnic zakresu między iwhile IFS='' read
,IFS=''; while read
awhile IFS=''; read
idiomami ( zakres na polecenie vsIFS
zakres / zmienna obejmująca całą powłokę ), lekcją wstępną jest to, że tracisz początkowe i końcowe spacje linii wejściowej, jeśli zmienna IFS jest ustawiony na (zawiera a) spację.Może to mieć dość poważne konsekwencje, jeśli przetwarzane są ścieżki plików.
Dlatego ustawienie zmiennej IFS na pusty ciąg nie jest złym pomysłem, ponieważ zapewnia, że początkowe i końcowe białe znaki linii nie zostaną usunięte.
Zobacz także: Bash, czytać linia po linii z pliku, za pomocą IFS
źródło
Zainspirowany odpowiedzią Yuzema
Jeśli chcesz ustawić
IFS
prawdziwą postać, działało to dla mnieźródło