Кажется, что в обычной практике установка IFS выходит за пределы цикла while, чтобы не повторять установку его для каждой итерации ... Является ли это просто привычным стилем "monkey see, monkey do", как это было для этой обезьяны до Я читаю человека, читаю , или мне не хватает какой-то тонкой (или явно очевидной) ловушки?
81
while IFS=X read
не разделяетсяX
, ноwhile IFS=X; read
...while
не имеет особого смысла - условие дляwhile
концов на этой точкой с запятой, так что нет никакого фактического цикла ...read
становится только первая команда в цикле один-элемент ... Или нет ? А как жеdo
тогда ..?while
условии (доdo
).IFS=
работает, ноIFS=X
не работает ... (или, может быть, я какое-то время занимался этим вопросом ... кофе-брейк нужен :)Давайте посмотрим на пример с тщательно продуманным вводным текстом:
Это две строки, первая из которых начинается с пробела и заканчивается обратной косой чертой. Во-первых, давайте посмотрим на то, что происходит без каких-либо мер предосторожности
read
(но с помощьюprintf '%s\n' "$text"
осторожной печати$text
без риска расширения). (Ниже приведена$
подсказка оболочки.)read
уничтожение обратной косой черты: обратная косая черта-новая строка приводит к игнорированию новой строки, а обратная косая черта - все игнорирует эту первую обратную косую черту. Чтобы избежать обратного слеша, мы используем специальноread -r
.Это лучше, у нас есть две линии, как и ожидалось. Две строки почти содержат желаемое содержимое: двойной пробел между
hello
иworld
был сохранен, потому что он находится внутриline
переменной. С другой стороны, начальное пространство было съедено. Это потому, чтоread
читает столько слов, сколько вы передаете переменным, за исключением того, что последняя переменная содержит остаток строки - но она все равно начинается с первого слова, то есть начальные пробелы отбрасываются.Итак, чтобы буквально прочитать каждую строку, нам нужно убедиться, что разделение слов не происходит. Мы делаем это, устанавливая
IFS
переменную в пустое значение.Обратите внимание, как мы установили
IFS
специально для продолжительностиread
встроенного . ВIFS= read -r line
устанавливает переменную окруженияIFS
(пустое значение) , специально для исполненияread
. Это пример общего простого синтаксиса команды : (возможно, пустая) последовательность назначений переменных, за которой следует имя команды и ее аргументы (также вы можете добавлять перенаправления в любой точке). Посколькуread
эта переменная является встроенной, она фактически никогда не попадает в среду внешнего процесса; тем не менее, ценность$IFS
- это то, что мы назначаем там, покаread
выполняется ». Обратите внимание, чтоread
это не специальная встроенная функция , поэтому назначение выполняется только в течение его продолжительности.Поэтому мы стараемся не менять значение
IFS
других инструкций, которые могут на него полагаться. Этот код будет работать независимо от того, чтоIFS
изначально было установлено для окружающего кода , и не вызовет никаких проблем, если код внутри цикла полагаетсяIFS
.Сравните это с фрагментом кода, который просматривает файлы в двоеточии. Список имен файлов читается из файла, по одному имени файла в строке.
Если бы цикл был
while IFS=; read -r name; do …
, тоfor dir in $PATH
не разбился бы на разделенные$PATH
двоеточием компоненты. Если бы код былIFS=; while read …
, было бы еще более очевидно, чтоIFS
он не установлен:
в теле цикла.Конечно, было бы возможно восстановить значение
IFS
после выполненияread
. Но это потребовало бы знания предыдущего значения, что является дополнительным усилием.IFS= read
это простой способ (и, удобно, также самый короткий путь).¹ И, если
read
он прерывается перехваченным сигналом, возможно, во время выполнения перехвата - это не указано в POSIX и зависит от оболочки на практике.источник
while IFS= read
(без точки с запятой=
) не является специальной формой,while
или,IFS
или изread
.. Конструкция является общей: то есть.anyvar=anyvalue anycommand
, Отсутствие;
после установкиanyvar
делает объемanyvar
локального доanycommand
.. пока - делать / сделать цикл 100% связан с местной сферойany_var
.Помимо (уже выяснены)
IFS
обзорных различия междуwhile IFS='' read
,IFS=''; while read
иwhile IFS=''; read
идиомы (за команду против сценария / оболочки по всейIFS
видимости переменной), то забирать домой урок заключается в том, что вы теряете ведущие и завершающие пробелы из строки ввода , если переменная IFS устанавливается на (содержит) пробел.Это может иметь довольно серьезные последствия, если пути к файлам обрабатываются.
Поэтому установка переменной IFS для пустой строки - это не плохая идея, поскольку она гарантирует, что начальный и конечный пробелы в строке не будут удалены.
Читайте также: Bash, чтение построчно из файла, с IFS
источник
Вдохновленный ответом Юзема
Если вы хотите установить
IFS
реальный характер, это сработало для меняисточник