Iteracja po ciągu wieloliniowym przechowywanym w zmiennej

17

I odczytać , że jest źle pisać takie rzeczy for line in $(command), prawidłowa droga wydaje się być w zamian:

command | while IFS= read -r line; do echo $line; done

To działa świetnie. Ale co, jeśli to, co chcę iterować, to zawartość zmiennej , a nie bezpośredni wynik polecenia?

Na przykład wyobraź sobie, że tworzysz następujący plik quickfox:

The quick brown
foxjumps\ over -
the
lazy ,
dog.

Chciałbym móc zrobić coś takiego:

# This is just for the example,
# I could of course stream the contents to `read`
variable=$(cat quickfox);
while IFS= read -r line < $variable; do echo $line; done; # this is incorrect
Sheljohn
źródło

Odpowiedzi:

19

W nowoczesnych powłokach, takich jak bash i zsh, masz bardzo przydatny readresator `<<< ', który przyjmuje ciąg znaków jako dane wejściowe. Tak byś zrobił

while IFS= read -r line ; do echo $line; done <<< "$variable"

W przeciwnym razie zawsze możesz to zrobić

echo "$variable" | while IFS= read -r line ; do echo $line; done
lgeorget
źródło
Przepraszam, powinienem oczywiście pomyśleć o powtórzeniu treści. Ale i tak dzięki za szybką odpowiedź!
Sheljohn,
1
musisz $variableużyć podwójnego cudzysłowu, gdy go użyjesz, w przeciwnym razie whilepętla uzyska tylko jeden wiersz danych wejściowych. Patrz, na przykład, różnica mocy między echo $variablevs echo "$variable"lub cat <<< $variablevs cat <<< "$variable".
cas
@cas Właściwie to zależy od tego, co jest wewnątrz zmiennej $. W przypadku przedstawionym przez OP („zmienna = $ (cat quickfox)”) działa bez dodatkowych cudzysłowów. Ale w ogólnym przypadku masz rację. Edytuję swoją odpowiedź. Dzięki.
lgeorget 12.04.16
Samo variable=$(cat quickfox)pytanie PO stanowi przykład tego, o czym mówiłem. Używanie tego $variablewewnątrz cudzysłowów obejmuje znaki nowego wiersza, użycie go bez powoduje, że znaki nowego wiersza są tłumaczone na spacje przez powłokę. Jeśli czytasz i przetwarzasz wiersz po wierszu, robi to ogromną różnicę - w tym pierwszym masz wiele linii wejściowych, w drugim masz tylko jedną linię wejściową. Dane wejściowe są powierzchownie podobne, ale w praktyce są całkowicie odmienne w tych dwóch przypadkach.
cas
na przykład: przy tych danych wejściowych cat <<< "$variable" | wc -lzwraca 5. cat <<< $variable | wc -lzwraca 1. Jeśli chcesz / musisz zachować białe znaki (w tym znaki nowej linii, tabulatory, pojedyncze lub wiele spacji) w zmiennej, MUSISZ podwójnie zacytować zmienną, gdy jej używasz, w przeciwnym razie wszystkie zostaną przekształcone w jedną spację między każdym „słowem”.
cas