Как обработать файл построчно в сценарии Linux Bash

7 февраля 2021 |

Как обработать файл построчно в сценарии Linux Bash

Достаточно легко прочитать содержимое текстового файла Linux построчно в сценарии оболочки — если вы имеете дело с некоторыми тонкими подводными камнями. Вот как это сделать безопасным способом.

Файлы, текст и идиомы

У каждого языка программирования есть набор идиом. Это стандартные простые способы выполнения набора общих задач. Это элементарный способ или способ по умолчанию использовать одну из функций языка, с которым работает программист. Они становятся частью набора интеллектуальных схем программиста.

A terminal window on a Linux computer system. Fatmawati Achmad Zaenuri / Shutterstock

Хорошими примерами являются такие действия, как чтение данных из файлов, работа с циклами и замена значений двух переменных. Программист будет знать по крайней мере один способ достичь своих целей обычным или ванильным способом. Возможно, этого будет достаточно для удовлетворения текущих требований. Или, может быть, они украсят код, чтобы сделать его более эффективным или применимым к конкретному решению, которое они разрабатывают. Но иметь под рукой идиомы из строительных блоков — отличная отправная точка.

Знание и понимание идиом одного языка также упрощает освоение нового языка программирования. Знание того, как вещи устроены на одном языке, и поиск эквивалента — или наиболее близкого — на другом языке — хороший способ оценить сходства и различия между языками программирования, которые вы уже знаете, и тем, который вы изучаете.

Чтение строк из файла: однострочный

В Bash вы можете использовать цикл while в командной строке, чтобы читать каждую строку текста из файла и что-то с ней делать. Наш текстовый файл называется «data.txt». Он содержит список месяцев в году.

январь февраль март. Октябрь Ноябрь Декабрь

Наш простой однострочный текст:

при чтении строки, do echo $ line, done & lt, data.txt

Цикл while считывает строку из файла, а поток выполнения маленькой программы переходит в тело цикла. Команда echo записывает строку текста в окно терминала. Попытка чтения завершается неудачей, когда больше нет строк для чтения, и цикл завершен.

Один из приемов — возможность перенаправить файл в цикл. В других языках программирования вам нужно будет открыть файл, прочитать из него и снова закрыть, когда вы закончите. С Bash вы можете просто использовать перенаправление файлов и позволить оболочке обрабатывать все эти низкоуровневые вещи за вас.

Конечно, этот однострочник не очень полезен. В Linux уже есть команда cat, которая делает это за нас. Мы придумали сложный способ заменить трехбуквенную команду. Но он наглядно демонстрирует принципы чтения из файла.

Это работает достаточно хорошо, до определенного момента. Предположим, у нас есть еще один текстовый файл, содержащий названия месяцев. В этом файле escape-последовательность для символа новой строки добавлена ​​к каждой строке. Назовем его «data2.txt».

Январь Февраль Марчн. Octobern Novembern Decembern

Давайте воспользуемся однострочником в нашем новом файле.

пока читаем строку, делаем echo $ line, done & lt, data2.txt

Экранирующий символ обратной косой черты «» был отброшен. В результате к каждой строке добавляется буква «n». Bash интерпретирует обратную косую черту как начало escape-последовательности. Часто мы не хотим, чтобы Bash интерпретировал то, что он читает. Может быть удобнее прочитать строку целиком — escape-последовательности с обратной косой чертой и все остальное — и выбрать, что нужно разобрать или заменить, в своем собственном коде.

Если мы хотим выполнить какую-либо значимую обработку или анализ на строках текста нам понадобится сценарий.

Чтение строк из файла с помощью сценария

Вот наш сценарий. Он называется «script1.sh».

#!/ bin / bash Counter = 0, а IFS = » read -r LinefromFile || [[-n «$ {LinefromFile}»]], do ((Counter ++)) echo «Доступ к строке $ Counter: $ {LinefromFile}» done & lt, «$ 1»

Мы устанавливаем переменную Counter в ноль, затем мы определяем наш цикл while.

Первый оператор в строке while — IFS = ». IFS означает внутренний разделитель полей. Он содержит значения, которые Bash использует для определения границ слов. По умолчанию команда чтения удаляет начальные и конечные пробелы. Если мы хотим читать строки из файла в точности такими, какие они есть, нам нужно установить IFS как пустую строку.

Мы могли бы установить это один раз вне цикла, точно так же, как мы устанавливаем значение счетчика. Но с более сложными сценариями, особенно со многими определяемыми пользователем функциями в них, возможно, что IFS может быть установлен на другие значения в другом месте сценария. Если каждый раз, когда цикл while повторяется, для IFS устанавливается пустая строка, это гарантирует, что мы знаем, каким будет его поведение.

Мы собираемся прочитать строку текста в переменной с именем LinefromFile. Мы используем параметр -r (считайте обратную косую черту как обычный символ), чтобы игнорировать обратную косую черту. К ним будут относиться так же, как к любому другому персонажу, и не будет особого обращения.

Есть два условия, которые удовлетворяют циклу while и позволяют обрабатывать текст телом цикла:

  • read -r LinefromFile: когда строка текста При успешном чтении из файла команда чтения отправляет сигнал успеха в while, а цикл while передает поток выполнения в тело цикла. Обратите внимание, что команда чтения должна видеть символ новой строки в конце строки текста, чтобы считать ее успешным считыванием. Если файл не является текстовым файлом, совместимым с POSIX, последняя строка может не включать символ новой строки. Если команда чтения видит маркер конца файла (EOF) до того, как строка заканчивается символом новой строки, она не будет рассматривать это как успешное чтение. Если это произойдет, последняя строка текста не будет передана в тело цикла и не будет обработана.
  • [-n «$ {LinefromFile}»]: нам нужно проделать дополнительную работу для обработки файлов, несовместимых с POSIX. Это сравнение проверяет текст, читаемый из файла. Если оно не завершено символом новой строки, это сравнение все равно вернет успех циклу while. Это гарантирует, что любые фрагменты завершающей строки обрабатываются телом цикла.

Эти два предложения разделяются логическим оператором OR »|| ”Так что, если любое из предложений возвращает успех, полученный текст обрабатывается телом цикла, независимо от того, есть ли символ новой строки или нет.

В теле цикла мы увеличиваем значение переменной Counter на единицу и используем echo для отправки некоторого вывода в окно терминала. Отображаются номер строки и текст каждой строки.

Мы все еще можем использовать наш трюк с перенаправлением, чтобы перенаправить файл в цикл. В этом случае мы перенаправляем $ 1, переменную, которая содержит имя первого параметра командной строки, переданного в сценарий. Используя этот трюк, мы можем легко передать имя файла данных, над которым мы хотим, чтобы сценарий работал.

Скопируйте и вставьте сценарий в редактор и сохраните его с именем файла «script1.sh». Используйте команду chmod, чтобы сделать его исполняемым.

chmod + x script1.sh

Давайте посмотрим, что наш скрипт делает с текстовым файлом data2.txt и содержащимися в нем обратными косыми чертами внутри него.

./script1.sh data2.txt

Каждый символ в строке отображается дословно. Обратные косые черты не интерпретируются как escape-символы. Они печатаются как обычные символы.

Передача строки в функцию

Мы все еще просто выводим текст на экран. В реальном сценарии программирования мы, вероятно, собираемся сделать что-нибудь более интересное со строкой текста. В большинстве случаев хорошей практикой программирования является обработка дальнейшей обработки строки в другой функции.

Вот как мы могли бы это сделать. Это «script2.sh».

#!/ bin / bash Counter = 0 function process_line () {echo «Строка обработки $ Counter: $ 1″} при IFS = » read -r LinefromFile || [[-n «$ {LinefromFile}»]], do ((Counter ++)) process_line «$ LinefromFile» done & lt, «$ 1»

Мы определяем нашу переменную Counter, как и раньше, а затем определяем функцию с именем process_line ( ). Определение функции должно появиться до первого вызова функции в сценарии.

Наша функция будет передавать недавно прочитанную строку текста на каждой итерации цикла while. Мы можем получить доступ к этому значению в функции, используя переменную $ 1. Если бы функции были переданы две переменные, мы могли бы получить доступ к этим значениям, используя $ 1 и $ 2, и так далее для большего количества переменных.

Цикл while в основном такой же. В теле цикла есть только одно изменение. Эхо-строка заменена вызовом функции process_line (). Обратите внимание, что вам не нужно использовать скобки «()» в имени функции, когда вы ее вызываете.

Имя переменной LinefromFile, содержащей строку текста, заключено в кавычки. отмечает, когда он передается в функцию. Это касается строк, в которых есть пробелы. Без кавычек первое слово рассматривается функцией как $ 1, второе слово — как $ 2 и так далее. Использование кавычек гарантирует, что вся строка текста будет обработана как $ 1. Обратите внимание, что это не тот же $ 1, который содержит тот же файл данных, переданный в скрипт.

Поскольку Counter был объявлен в основном теле скрипта, а не внутри функции, на него можно ссылаться внутри process_line ().

Скопируйте или введите указанный выше сценарий в редактор и сохраните его с именем файла «script2.sh». Сделайте его исполняемым с помощью chmod:

chmod + x script2.sh

Теперь мы можем запустить его и передать новый файл данных «data3.txt». Здесь есть список месяцев и одна строка с множеством слов.

Январь Февраль Март. Октябрь Ноябрь nБольше текста «в конце строки» Декабрь

Наша команда:

./script2.sh data3.txt

Строки читаются из файла и по очереди передаются в функцию process_line (). Все строки отображаются правильно, в том числе нечетная с обратным пробелом, кавычками и несколькими словами в ней.

Строительные блоки полезны

Ходят мысли, что идиома должна содержать что-то уникальное для этой язык. Я не разделяю этого убеждения. Важно то, что он хорошо использует язык, легко запоминается и обеспечивает надежный и надежный способ реализации некоторых функций в вашем коде.

Как обработать файл построчно в сценарии Linux Bash

Tags:

Напишите пару строк: