Чтение данных столбцов из текстового файла в Bash

Одной из задач в повседневной работе является построчное чтение данных из файла, разбор данных и их обработка. Входной файл может быть либо обычным текстовым файлом, где каждая строка содержит несколько полей, разделенных пробелами, либо CSV-файлом, отформатированным с разделенными разделителями значениями в каждой строке. Bash позволяет считывать столбцы из файла и сохранять их в отдельные переменные для дальнейшей обработки.

Чтение данных столбцов из текстового файла в Bash

Чтение столбцов, разделенных пробелами, в Bash

Пример текстового файла (os.txt)

1 linux 5 'A Linux-based system is a modular Unix-like operating system'
2 windows 10 'Microsoft Windows'
3 macos 21 'macOS is a proprietary graphical operating system'

Для чтения данных столбцов из файла в bash можно использовать встроенную команду read, которая читает одну строку из стандартного ввода или дескриптора файла. В сочетании с циклом for/while команда read может читать содержимое файла построчно, пока не будет достигнут конец файла. Если каждая строка содержит несколько полей, read может считывать отдельные поля и сохранять их в заданных переменных. По умолчанию read распознает пробелы как разделитель для разных полей.

while read index name version description; do
    echo "$index : $name, $version , $description"
done < "os.txt"
cat os.txt | while read index name version description; do
    echo "$index : $name, $version , $description"
done

Чтение столбцов из файла CSV в Bash

При работе с CSV-файлом, в котором в качестве разделителя столбцов используется символ, не являющийся пробелом (например, "," или ";" или "|"), необходимо указать  разделитель в переменной IFS. Переменная IFS (сокращение от "Input Field Separator") - это специальная переменная bash, которая указывает символ или символы, разделяющие поля.

Пример файла (os.csv)

linux,5,"A Linux-based system is a modular Unix-like operating system"
windows,10,"Microsoft Windows"
macos,,"macOS is a proprietary graphical operating system"

Цикл while может прочитать CSV-файл и сохранить столбцы в указанные переменные.  IFs= перед командой read указывает read использовать "," в качестве разделителя слов. Для проверки, пуст ли конкретный столбец или нет, используется оператор -z.

while IFS=, read name version description; do
if [ -z "$version" ]; then
    echo "$name no version"
else
    echo "$name $version"
fi
done < "os.csv"

Чтение данных столбцов с помощью регулярного выражения

Более общий и сложный сценарий - это чтение данные столбцов из менее структурированных файлов, таких как журналы. Типичный файл журнала не так структурирован, как CSV-файлы, и может не использовать фиксированный символ-разделитель, а также фиксированное количество столбцов. В качестве примера рассмотрим следующий фрагмент файла auth.log.

Feb 21 08:42:51 debian sudo: dan : TTY=pts/1 ; PWD=/home/dan/download/shc ; USER=root ; COMMAND=/usr/bin/apt-get install nload
Feb 21 08:42:51 debian sudo: pam_unix(sudo:session): session opened for user root by (uid=0)
Feb 21 08:42:52 debian sudo: pam_unix(sudo:session): session closed for user root
Feb 21 09:40:20 debian sudo: alice : TTY=pts/1 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/apt remove apache2
Feb 21 09:40:20 debian sudo: pam_unix(sudo:session): session opened for user root by (uid=0)
Feb 21 09:40:25 debian sudo: pam_unix(sudo:session): session closed for user root
Feb 22 10:50:43 debian sudo: dan : TTY=pts/0 ; PWD=/home/dan/abc ; USER=root ; COMMAND=/usr/bin/nano /etc/hosts
Feb 22 10:50:43 debian sudo: pam_unix(sudo:session): session opened for user root by (uid=0)
Feb 22 10:50:49 debian sudo: pam_unix(sudo:session): session closed for user root
Feb 22 10:51:56 debian sudo: dan : TTY=pts/0 ; PWD=/home/dan/abc ; USER=root ; COMMAND=/usr/bin/nano /etc/resolv.conf

Для примера можно извлечь логин пользователя и команду sudo, запущенную пользователем.

while read -r line; do
    pattern='debian sudo:\s+([^[:space:]]+).*COMMAND=(.*)'
    if [[ $line =~ $pattern ]]; then
        echo "${BASH_REMATCH[1]} : ${BASH_REMATCH[2]}"
    fi
done < "auth.log"

При разборе, мы проверяем соответствует ли строка регулярному выражению и извлекаем значения конкретных столбцов.

Добавить комментарий