zmiana IFS tymczasowo przed pętlą for [duplikat]

Aug 16 2020

Wiem, że SHELLpozwala przypisać zmienne bezpośrednio przed poleceniem, tak że IFS=":" read a b c d <<< "$here_string"działa ...

Zastanawiałem się, czy takie przypisania nie działają, gdy są wykonywane z instrukcjami złożonymi, takimi jak pętle? Próbowałem czegoś podobnego, IFS=":" for i in $PATH; do echo $i; doneale skutkuje to błędem składni. Zawsze mogłem zrobić coś takiego oldIFS="$IFS"; IFS=":"; for....; IFS="$oldIFS", ale chciałem wiedzieć, czy jest jakiś sposób, w jaki mógłbym sprawić, by takie przypisania w wierszu działały dla instrukcji złożonych, takich jak forpętle?

Odpowiedzi

3 Quasímodo Aug 16 2020 at 21:12

forjest słowem zastrzeżonym i jako taki podlega specjalnym zasadom :

Następujące słowa uznaje się za słowa zastrzeżone:

! {} case do done elif else esac fi for if in then do czasu

Takie uznanie ma miejsce tylko wtedy, gdy żaden ze znaków nie jest cytowany i gdy słowo to jest używane jako:

  • Pierwsze słowo polecenia

  • Pierwsze słowo występujące po jednym z zarezerwowanych słów innych niż case , for lub in

  • Trzecie słowo w poleceniu case (tylko w to ważne w tym przypadku)

  • Trzecie słowo w poleceniu for (tylko in i do są ważne w tym przypadku)

Jeśli spróbujesz

IFS=":" for i in $PATH; do echo $i; done

zgodnie z powyższymi regułami nie jest to forpętla, ponieważ słowo kluczowe nie jest pierwszym słowem polecenia. Ale twój zamiar można osiągnąć dzięki

IFS=: printf '%s\n' $PATH

$PATHpodlega podziałowi na słowa :zgodnie z oczekiwaniami, a każde wynikowe słowo jest wypisywane przez printf, po którym następuje nowa linia.


Być może znasz to prawidłowe podejście:

while IFS= read -r line; do

whilejest pierwszym słowem polecenia, a IFSprzypisanie dotyczy read, więc wszystko jest OK.