Цикл while по строкам из переменной в bash

Предположим, файл file состоит из нескольких строк.

$ cat file
foo
bar
baz

Предположим далее, что я хочу перебирать каждую строку с помощью цикла while.

$ while IFS= read -r line; do
$   echo $line
$   # do stuff
$ done < file
foo
bar
baz

Наконец, предположим, что я хочу передать строки, хранящиеся в переменной, а не строки, хранящиеся в файле. Как я могу прокручивать строки, которые сохраняются как переменная, не получая приведенную ниже ошибку?

$ MY_VAR=$(cat file)
$ while IFS= read -r line; do
$   echo $line
$   # do stuff
$ done < $(echo "$MY_VAR")
bash: $(echo "$MY_VAR"): ambiguous redirect

person Michael G    schedule 26.06.2017    source источник
comment
echo $line не то же самое, что echo "$line". См. BashPitfalls #14.   -  person Charles Duffy    schedule 26.06.2017
comment
Кроме того, имена переменных, написанные заглавными буквами, используются для переменных, имеющих значение для оболочки или ОС, тогда как имена с символами нижнего регистра гарантированно не конфликтуют с работой системы. См. pubs.opengroup.org/onlinepubs/9699919799/basedefs/, четвертый абзац.   -  person Charles Duffy    schedule 26.06.2017


Ответы (2)


У вас есть несколько вариантов:

  • Строка (обратите внимание, что это не POSIX-расширение): done <<<"$MY_VAR"
  • Heredoc (совместимый с POSIX, будет работать с /bin/sh):

    done <<EOF
    $MY_VAR
    EOF
    
  • Подстановка процесса (тоже расширение, отличное от POSIX, но использование printf вместо echo делает его более предсказуемым для поддерживаемых оболочек; см. примечание об ИСПОЛЬЗОВАНИИ ПРИЛОЖЕНИЯ в Спецификация POSIX для echo): done < <(printf '%s\n' "$MY_VAR")


Обратите внимание, что первые два параметра (в bash) создают временный файл на диске с содержимым переменной, тогда как последний использует FIFO.

person Charles Duffy    schedule 26.06.2017
comment
Спасибо за подробные объяснения, а также полезные комментарии выше. Очень признателен. - person Michael G; 26.06.2017

За < должно следовать имя файла. Вы можете использовать здесь строку:

done <<< "$MY_VAR"

или замена процесса:

done < <(echo "$MY_VAR")
person Barmar    schedule 26.06.2017