Команда Linux awk: обработка текста

LinuxLinuxBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

Добро пожаловать в мир обработки текста с помощью AWK. В этом лабораторном занятии (LabEx) вы научитесь использовать команду awk для анализа журналов (log files), что является обычной задачей для системных администраторов и аналитиков данных. AWK - это мощный инструмент для обработки структурированных текстовых данных в Linux, который позволяет эффективно извлекать, фильтровать и преобразовывать информацию.

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


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL linux(("Linux")) -.-> linux/BasicFileOperationsGroup(["Basic File Operations"]) linux(("Linux")) -.-> linux/TextProcessingGroup(["Text Processing"]) linux/BasicFileOperationsGroup -.-> linux/touch("File Creating/Updating") linux/BasicFileOperationsGroup -.-> linux/cat("File Concatenating") linux/BasicFileOperationsGroup -.-> linux/head("File Beginning Display") linux/TextProcessingGroup -.-> linux/grep("Pattern Searching") linux/TextProcessingGroup -.-> linux/awk("Text Processing") linux/TextProcessingGroup -.-> linux/sort("Text Sorting") linux/TextProcessingGroup -.-> linux/uniq("Duplicate Filtering") subgraph Lab Skills linux/touch -.-> lab-388493{{"Команда Linux awk: обработка текста"}} linux/cat -.-> lab-388493{{"Команда Linux awk: обработка текста"}} linux/head -.-> lab-388493{{"Команда Linux awk: обработка текста"}} linux/grep -.-> lab-388493{{"Команда Linux awk: обработка текста"}} linux/awk -.-> lab-388493{{"Команда Linux awk: обработка текста"}} linux/sort -.-> lab-388493{{"Команда Linux awk: обработка текста"}} linux/uniq -.-> lab-388493{{"Команда Linux awk: обработка текста"}} end

Просмотр файла журнала

Начнем с того, что рассмотрим содержимое нашего примерного файла журнала (log file). Этот файл содержит имитированные журналы доступа к серверу, которые мы будем анализировать в рамках этого лабораторного занятия (LabEx).

Сначала перейдите в директорию проекта:

cd ~/project

Теперь давайте посмотрим на первые несколько строк файла журнала:

head -n 5 server_logs.txt

Вы должны увидеть вывод, похожий на следующий:

2023-08-01 08:15:23 192.168.1.100 GET /index.html 200
2023-08-01 08:16:45 192.168.1.101 GET /about.html 200
2023-08-01 08:17:30 192.168.1.102 POST /login.php 302
2023-08-01 08:18:12 192.168.1.103 GET /products.html 404
2023-08-01 08:19:05 192.168.1.104 GET /services.html 200

Этот файл журнала содержит информацию о запросах к серверу, включая дату и время, IP - адрес, HTTP - метод, запрашиваемый ресурс и код состояния (status code).

Базовое использование AWK - вывод определенных полей

Теперь, когда мы рассмотрели структуру нашего файла журнала (log file), давайте используем AWK для извлечения определенной информации. По умолчанию AWK разбивает каждую строку на поля на основе пробелов. Мы можем обращаться к этим полям с помощью $1, $2 и т.д., где $1 - это первое поле, $2 - второе и так далее.

Давайте извлечем IP - адреса (третье поле) из нашего файла журнала:

awk '{print $3}' server_logs.txt | head -n 5

Вы должны увидеть вывод, похожий на следующий:

192.168.1.100
192.168.1.101
192.168.1.102
192.168.1.103
192.168.1.104

В этой команде:

  • awk '{print $3}' сообщает AWK вывести третье поле каждой строки.
  • Мы используем конвейер (|) для передачи вывода в head -n 5, чтобы ограничить отображение первыми 5 строками.

Теперь давайте выведем как IP - адрес, так и запрашиваемый ресурс:

awk '{print $3, $5}' server_logs.txt | head -n 5

Вывод:

192.168.1.100 /index.html
192.168.1.101 /about.html
192.168.1.102 /login.php
192.168.1.103 /products.html
192.168.1.104 /services.html

Здесь мы выводим третье поле (IP - адрес) и пятое поле (запрашиваемый ресурс) для каждой строки.

Фильтрация записей журнала

Одним из преимуществ AWK является его способность фильтровать данные на основе условий. Давайте воспользуемся этой возможностью, чтобы найти все POST-запросы в нашем журнале, так как они могут быть более чувствительными с точки зрения безопасности, чем GET-запросы.

Запустите следующую команду:

awk '$4 == "POST" {print $0}' server_logs.txt

Разберём синтаксис этой команды, чтобы понять, как работает фильтрация в AWK:

  1. $4 == "POST" - Это шаблон или условие, которое AWK оценивает для каждой строки:

    • $4 ссылается на четвёртое поле текущей строки (в нашем журнале это HTTP-метод)
    • == - это оператор равенства, который проверяет, равны ли два значения
    • "POST" - это строка, с которой мы сравниваем
  2. {print $0} - Это действие, которое AWK выполняет, когда условие истинно:

    • Круглые скобки {} заключают действие
    • print - это команда для вывода текста
    • $0 представляет собой всю текущую строку (все поля)

Структура команды соответствует шаблону AWK: условие {действие}. AWK считывает каждую строку, и если условие оценивается как истинное, он выполняет действие. Если условие не указано (как в наших предыдущих примерах), действие выполняется для каждой строки.

Вы должны увидеть вывод, похожий на следующий:

2023-08-01 08:17:30 192.168.1.102 POST /login.php 302
2023-08-01 09:23:45 192.168.1.110 POST /submit_form.php 200
2023-08-01 10:45:12 192.168.1.115 POST /upload.php 500

Теперь найдём все запросы, которые завершились статусом 404 (Не найдено):

awk '$6 == "404" {print $1, $2, $5}' server_logs.txt

Эта команда следует тому же шаблону, но с другими значениями:

  • Условие $6 == "404" проверяет, равно ли шестое поле (код статуса) 404
  • Действие {print $1, $2, $5} выводит только определенные поля:
    • $1 - Первое поле (дата)
    • $2 - Второе поле (время)
    • $5 - Пятое поле (запрашиваемый ресурс)

Такой выборочный вывод позволяет вам сосредоточиться только на нужной вам информации.

Вывод:

2023-08-01 08:18:12 /products.html
2023-08-01 09:30:18 /nonexistent.html
2023-08-01 11:05:30 /missing_page.html

Вы можете комбинировать несколько условий, используя логические операторы:

  • && для операции И (оба условия должны быть истинными)
  • || для операции ИЛИ (хотя бы одно условие должно быть истинным)
  • ! для операции НЕ (инвертирует условие)

Например, чтобы найти все POST-запросы, которые завершились ошибкой (код статуса >= 400):

awk '$4 == "POST" && $6 >= 400 {print $0}' server_logs.txt

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

Подсчет и суммирование данных

AWK отлично подходит для подсчета количества вхождений и суммирования данных. Давайте используем его для подсчета количества запросов для каждого HTTP-статуса.

Запустите эту команду:

awk '{count[$6]++} END {for (code in count) print code, count[code]}' server_logs.txt | sort -n

Эта команда более сложная, поэтому разберем ее пошагово:

  1. {count[$6]++} - Это основное действие, выполняемое для каждой строки:

    • count - это массив (ассоциативный массив или словарь), который мы создаем
    • [$6] использует значение 6-го поля (статус-код) в качестве индекса/ключа массива
    • ++ - это оператор инкремента, который добавляет 1 к текущему значению
    • Таким образом, для каждой строки мы увеличиваем счетчик для конкретного статуса, найденного в строке
  2. END {for (code in count) print code, count[code]} - Это выполняется после обработки всех строк:

    • END - это специальный шаблон, который соответствует концу входных данных
    • {...} содержит действие, которое нужно выполнить после обработки всех входных данных
    • for (code in count) - это цикл, который проходит по всем ключам в массиве count
    • print code, count[code] выводит каждый статус-код и его количество
  3. | sort -n - Передает вывод в команду сортировки, которая сортирует данные по числовому значению

Когда AWK обрабатывает массив, как в count[$6]++, он автоматически:

  • Создает массив, если он не существует
  • Создает новый элемент со значением 0, если ключ не существует
  • Затем увеличивает значение на 1

Вы должны увидеть вывод, похожий на этот:

200 3562
301 45
302 78
304 112
400 23
403 8
404 89
500 15

Эта сводка быстро показывает вам распределение статус-кодов в вашем журнале.

Теперь давайте найдем 5 самых часто запрашиваемых ресурсов:

awk '{count[$5]++} END {for (resource in count) print count[resource], resource}' server_logs.txt | sort -rn | head -n 5

Эта команда имеет похожую структуру с некоторыми изменениями:

  1. {count[$5]++} - Подсчитывает количество вхождений 5-го поля (запрашиваемый ресурс)
  2. END {for (resource in count) print count[resource], resource} - После обработки всех строк:
    • Выводит количество сначала, а затем ресурс
    • Это изменение порядка упрощает числовую сортировку по количеству
  3. | sort -rn - Сортирует данные по числовому значению в обратном порядке (сначала самые большие количества)
  4. | head -n 5 - Ограничивает вывод первыми 5 строками (5 лучших результатов)

Вывод:

1823 /index.html
956 /about.html
743 /products.html
512 /services.html
298 /contact.html

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

Например, чтобы подсчитать количество запросов с каждого IP-адреса:

awk '{count[$3]++} END {for (ip in count) print ip, count[ip]}' server_logs.txt

Чтобы подсчитать запросы по методу и статусу:

awk '{key=$4"-"$6; count[key]++} END {for (k in count) print k, count[k]}' server_logs.txt

Эти сводки могут помочь вам понять паттерны трафика и определить популярные (или проблемные) ресурсы на вашем сервере.

Создание простого отчета

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

Сначала создайте файл с именем log_report.awk со следующим содержимым:

Совет: Скопируйте содержимое ниже и вставьте его в терминал, чтобы создать файл.

cat << 'EOF' > log_report.awk
BEGIN {
    print "<html><body>"
    print "<h1>Server Log Summary</h1>"
    total = 0
    errors = 0
}

{
    total++
    if ($6 >= 400) errors++
    ip_count[$3]++
    resource_count[$5]++
}

END {
    print "<p>Total requests: " total "</p>"
    print "<p>Error rate: " (errors/total) * 100 "%</p>"
    
    print "<h2>Top 5 IP Addresses</h2>"
    print "<ul>"
    for (ip in ip_count) {
        top_ips[ip] = ip_count[ip]
    }
    n = asort(top_ips, sorted_ips, "@val_num_desc")
    for (i = 1; i <= 5 && i <= n; i++) {
        for (ip in ip_count) {
            if (ip_count[ip] == sorted_ips[i]) {
                print "<li>" ip ": " ip_count[ip] " requests</li>"
                break
            }
        }
    }
    print "</ul>"
    
    print "<h2>Top 5 Requested Resources</h2>"
    print "<ul>"
    for (resource in resource_count) {
        top_resources[resource] = resource_count[resource]
    }
    n = asort(top_resources, sorted_resources, "@val_num_desc")
    for (i = 1; i <= 5 && i <= n; i++) {
        for (resource in resource_count) {
            if (resource_count[resource] == sorted_resources[i]) {
                print "<li>" resource ": " resource_count[resource] " requests</li>"
                break
            }
        }
    }
    print "</ul>"
    
    print "</body></html>"
}
EOF

Давайте разберем этот скрипт AWK по частям:

  1. Блок BEGIN: Выполняется перед обработкой любых входных строк

    BEGIN {
        print "<html><body>"  ## Начало HTML-структуры
        print "<h1>Server Log Summary</h1>"
        total = 0  ## Инициализация счетчика общего количества запросов
        errors = 0  ## Инициализация счетчика ошибочных запросов
    }
  2. Основной блок обработки: Выполняется для каждой строки входного файла

    {
        total++  ## Увеличение счетчика общего количества запросов
        if ($6 >= 400) errors++  ## Подсчет ошибочных ответов (статусные коды >= 400)
        ip_count[$3]++  ## Подсчет запросов по IP-адресу (поле 3)
        resource_count[$5]++  ## Подсчет запросов по ресурсу (поле 5)
    }
  3. Блок END: Выполняется после обработки всех входных строк

    END {
        ## Вывод сводной статистики
        print "<p>Total requests: " total "</p>"
        print "<p>Error rate: " (errors/total) * 100 "%</p>"
    
        ## Обработка и вывод топ-5 IP-адресов
        #...
    
        ## Обработка и вывод топ-5 запрашиваемых ресурсов
        #...
    
        print "</body></html>"  ## Конец HTML-структуры
    }

Давайте рассмотрим логику сортировки для топ-IP (для раздела с ресурсами логика аналогична):

## Копирование счетчиков в новый массив для сортировки
for (ip in ip_count) {
    top_ips[ip] = ip_count[ip]
}

## Сортировка массива по значению в порядке убывания
n = asort(top_ips, sorted_ips, "@val_num_desc")

## Вывод топ-5 записей
for (i = 1; i <= 5 && i <= n; i++) {
    ## Поиск исходного IP, соответствующего этому счетчику
    for (ip in ip_count) {
        if (ip_count[ip] == sorted_ips[i]) {
            print "<li>" ip ": " ip_count[ip] " requests</li>"
            break
        }
    }
}

В этом скрипте:

  • Функция asort() сортирует массив
  • "@val_num_desc" - это специальный аргумент, который сообщает ей сортировать по значению в порядке убывания
  • Вложенные циклы находят и выводят топ-5 записей

Теперь давайте запустим наш скрипт AWK для генерации отчета:

awk -f log_report.awk server_logs.txt > log_report.html

Опция -f сообщает AWK прочитать скрипт из указанного файла:

  • -f log_report.awk - Читает скрипт AWK из файла log_report.awk
  • server_logs.txt - Обрабатывает этот файл с использованием скрипта
  • > log_report.html - Перенаправляет вывод в файл log_report.html

Вы можете просмотреть содержимое отчета с помощью команды cat:

cat log_report.html

Этот отчет предоставляет сводку по общему количеству запросов, проценту ошибок, топ-5 IP-адресов и топ-5 запрашиваемых ресурсов. В реальной ситуации вы можете открыть этот HTML-файл в веб-браузере для просмотра в отформатированном виде.

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

Итоги

Поздравляем! Вы завершили этот практический урок (lab) по использованию команды AWK для анализа журналов (log analysis). Давайте вспомним, что вы узнали:

  1. Базовое использование AWK: вывод определенных полей из структурированного текстового файла.
  2. Фильтрация данных: использование условий в AWK для выбора определенных записей в журнале.
  3. Подсчет и суммирование: использование AWK для генерации статистики из данных журнала.
  4. Создание отчетов: написание более сложных скриптов AWK для генерации отформатированных отчетов.

Эти навыки будут неоценимы для анализа файлов журналов, обработки данных и создания отчетов в вашей будущей работе системным администратором или аналитиком данных.

Вот некоторые дополнительные параметры и функции AWK, которые мы не рассмотрели в этом практическом уроке:

  • -F: задает разделитель полей, отличный от пробела.
  • -v: присваивает значение переменной.
  • NR: встроенная переменная, представляющая номер текущей записи.
  • NF: встроенная переменная, представляющая количество полей в текущей записи.
  • Блоки BEGIN и END: специальные шаблоны для инициализации и завершения.
  • Встроенные функции: математические функции, строковые функции и другие.

Помните, что практика - ключ к овладению AWK. Попробуйте изменить команды и скрипты из этого практического урока, чтобы проанализировать различные аспекты файла журнала или обработать другие типы структурированных текстовых данных.

Ресурсы