Я изучаю bash, и я увидел эту конструкцию:
cat file | while IFS= read -r line;
do
...
done
Может ли кто-нибудь объяснить, что делать IFS=
? Я знаю это поле ввода sepereter, но оно ничего не задано?
Я изучаю bash, и я увидел эту конструкцию:
cat file | while IFS= read -r line;
do
...
done
Может ли кто-нибудь объяснить, что делать IFS=
? Я знаю это поле ввода sepereter, но оно ничего не задано?
IFS
делает много вещей, но вы спрашиваете об этом конкретном цикле.
Эффект в этом цикле заключается в сохранении верхнего и конечного пробелов в line
. Чтобы проиллюстрировать это, сначала наблюдайте, что IFS ничего не задано:
$ echo " this is a test " | while IFS= read -r line; do echo "=$line=" ; done
= this is a test =
Переменная line
содержит все пустое пространство, полученное на его stdin. Теперь рассмотрим тот же оператор с IFS по умолчанию:
$ echo " this is a test " | while read -r line; do echo "=$line=" ; done
=this is a test=
В этой версии белое пространство, внутреннее для линии, сохраняется. Но начальное и конечное пробелы были удалены.
-r
в read -r
?Параметр -r
не позволяет read
рассматривать обратную косую черту как специальный символ.
Чтобы проиллюстрировать, мы используем две команды эха, которые снабжают две строки в цикле while
. Обратите внимание, что происходит с -r
:
$ { echo 'this \\ line is \' ; echo 'continued'; } | while IFS= read -r line; do echo "=$line=" ; done
=this \\ line is \=
=continued=
Теперь наблюдайте, что происходит без -r
:
$ { echo 'this \\ line is \' ; echo 'continued'; } | while IFS= read line; do echo "=$line=" ; done
=this \ line is continued=
Без -r
произошли два изменения. Во-первых, двойная обратная косая черта была преобразована в единую обратную косую черту. Во-вторых, обратная косая черта в конце первой строки интерпретировалась как символ продолжения линии, и две линии были объединены в один.
В целом, если вы хотите, чтобы обратные косые черты во входном значении имели особое значение, не используйте -r
. Если вы хотите, чтобы обратные косые черты во входном файле принимались как простые символы, используйте -r
.
Так как read
принимает ввод по одной строке за раз, IFS ведет себя, влияет на каждую строку с несколькими линейными входами так же, как на однострочный вход. -r
ведет себя аналогично исключению, что без -r
несколько строк могут быть объединены в одну строку с использованием обратной обратной косой черты, как показано выше.
Поведение с несколькими линейными вводами можно, однако, резко изменить, используя флаг -d
. -d
изменяет символ разделителя, который read
использует для обозначения конца строки ввода. Например, мы можем завершить строки с символом табуляции:
$ echo $'line one \n line\t two \n line three\t ends here'
line one
line two
line three ends here
$ echo $'line one \n line\t two \n line three\t ends here' | while IFS= read -r -d$'\t' line; do echo "=$line=" ; done
=line one
line=
= two
line three=
Здесь конструкция $'...'
использовалась для ввода специальных символов, таких как newline, \n
и tab, \t
. Обратите внимание, что -d$'\t'
, read
делит свой вход на "строки" на основе символов табуляции. Все, что после последней вкладки игнорируется.
Самое важное использование описанных выше функций - обработка сложных имен файлов. Поскольку один символ, который не может отображаться в path/filenames, является нулевым символом, нулевой символ может использоваться для разделения списка имен файлов. В качестве примера:
while IFS= read -r -d $'\0' file
do
# do something to each file
done < <(find ~/music -type f -print0)