У меня есть следующий файл .txt:
Marco
Paolo
Antonio
Я хочу читать это построчно, и для каждой строки я хочу присвоить строковое значение .txt переменной. Предположим, моя переменная $name
, поток:
- Читать первую строку из файла
- Назначить
$name
= "Марко" - Выполните несколько задач с
$name
- Читать вторую строку из файла
- Назначить
$name
= "Паоло"
Ответы:
Следующее читает файл, передаваемый в качестве аргумента построчно:
Это стандартная форма для чтения строк из файла в цикле. Объяснение:
IFS=
(илиIFS=''
) предотвращает обрезку начальных / конечных пробелов.-r
предотвращает интерпретацию обратной косой черты.Или вы можете поместить его в вспомогательный скрипт bash, пример содержимого:
Если вышеперечисленное сохраняется в сценарии с именем файла
readfile
, его можно запустить следующим образом:Если файл не является стандартным текстовым файлом POSIX (= не завершается символом новой строки), цикл может быть изменен для обработки завершающих частичных строк:
Здесь,
|| [[ -n $line ]]
предотвращает игнорирование последней строки, если она не заканчивается на\n
(посколькуread
возвращает ненулевой код завершения, когда она встречает EOF).Если команды внутри цикла также считываются из стандартного ввода, используемый дескриптор файла
read
может быть заменен чем-то другим (избегайте стандартных дескрипторов файлов ), например:(Оболочки не Bash могут не знать
read -u3
; используйтеread <&3
вместо этого.)источник
ssh
без-n
флага будет эффективно заставить вас выйти из цикла. Вероятно, для этого есть веская причина, но мне потребовалось некоторое время, чтобы понять, что приводило к сбою моего кода, прежде чем я это обнаружил.ffmpeg
потреблением stdin. Добавьте</dev/null
к своейffmpeg
строке, и он не сможет, или использовать альтернативный FD для цикла. Этот подход «альтернативного FD» выглядит следующим образомwhile IFS='' read -r line <&3 || [[ -n "$line" ]]; do ...; done 3<"$1"
..sh
продление. Исполняемые файлы в UNIX обычно вообще не имеют расширений (вы не запускаетеls.elf
), и наличие bash-shebang (и инструментов только для bash, таких как[[ ]]
) и расширение, подразумевающее совместимость с POSIX sh, внутренне противоречиво.Я призываю вас использовать
-r
флаг,read
который обозначает:Я цитирую
man 1 read
.Другое дело - взять имя файла в качестве аргумента.
Вот обновленный код:
источник
sh
, нетbash
; расширенная тестовая команда, используемая в|| [[ -n "$line" ]]
синтаксисе в принятом ответе, является башизмом. Тем не менее, этот синтаксис на самом деле имеет соответствующее значение: он заставляет цикл продолжаться до последней строки во входном файле, даже если он не имеет новой строки. Если вы хотите сделать это в POSIX-совместимом виде, вам нужно|| [ -n "$line" ]
использовать[
вместо[[
.IFS=
дляread
предотвращения обрезки пробелов.Использование следующего шаблона Bash позволит вам читать по одному значению за раз из файла и обрабатывать его.
источник
*
.источник
Enter
после последней строки), в противном случае последняя строка будет игнорироваться. По крайней мере, так случилось со мной.Многие люди опубликовали решение, которое слишком оптимизировано. Я не думаю, что это неправильно, но я скромно думаю, что было бы желательно менее оптимизированное решение, чтобы позволить всем легко понять, как это работает. Вот мое предложение:
источник
Использование:
Если вы установили
IFS
иначе, вы получите странные результаты.источник
*
в строке? Во всяком случае, это антипаттерн . Не читайте строки с for .read
подход является подходом наилучшей практики на основе консенсуса сообщества . Предупреждение, которое вы упоминаете в своем комментарии, применяется, когда ваш цикл запускает команды (такие какffmpeg
), которые читают из stdin, тривиально решается с использованием не-stdin FD для цикла или перенаправляет ввод таких команд. Напротив, работа с ошибкойfor
глобализации в вашем подходе -loop означает внесение (а затем и необходимость обратного изменения) глобальных настроек оболочки.for
подход петли используется здесь , означает , что все содержание должно быть прочитано до того , как цикл может начать выполнение на все, что делает его совершенно непригодным для использования , если вы цикл над гигабайтами данных , даже если у вас есть инвалиды подстановка;while read
циклу не нужно не больше , чем данные в одной строке в магазин за один раз, то есть он может начать выполнение в то время как содержание генерации подпроцесса все еще работает (таким образом , быть пригодным для целей потоковой передачи), а также имеет ограниченный объем памяти.while
основанных на подходах проблем, похоже, есть * характерные. Смотрите комментарии принятого ответа выше. Не спорю с тем, что for-iteration над файлами является антипаттерном.Если вам нужно обработать как входной файл, так и пользовательский ввод (или что-либо еще из stdin), используйте следующее решение:
На основании принятого ответа и учебника перенаправления bash-хакеров .
Здесь мы открываем файловый дескриптор 3 для файла, переданного в качестве аргумента сценария, и говорим
read
использовать этот дескриптор в качестве input (-u 3
). Таким образом, мы оставляем дескриптор ввода по умолчанию (0), прикрепленный к терминалу или другому источнику ввода, способный считывать ввод данных пользователем.источник
Для правильной обработки ошибок:
источник
Следующее просто распечатает содержимое файла:
источник
Использовать инструмент IFS (внутренний разделитель полей) в bash, определяет символ, используемый для разделения строк на токены, по умолчанию включает в себя < tab > / < space > / < newLine >
Шаг 1 : Загрузите данные файла и вставьте в список:
шаг 2 : теперь повторяем и выводим вывод:
echo конкретный индекс в массиве : доступ к переменной в массиве:
источник