Домашняя страница 5 инструментов работы с текстом которые вы обязаны знать
Публикация
Отменить

5 инструментов работы с текстом которые вы обязаны знать

Текст имеет большое значение в мире UNIX. Почти все, что может потребоваться узнать о системе, может быть получено путем чтения текстовых файлов. Часто такие файлы могут иметь несколько тысяч строк. Иногда - двенадцать миллионов.

В таких случаях сложно обойтись без обработки текста. Обработка текста позволяет получить ответ быстрее и проще. Стоит отметить, что у всех есть вопросы к их системе. Например, “Сколько ошибок 404 случилось на моем сайте?”, “Пытался ли кто-то получить доступ к моему серверу, а я об этом не знал?”, “Какая из программ так сильно загружает CPU?”

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

grep

Команду grep можно найти в строках запроса по всему миру. И это не случайно. Данная команда, в процессе обработки файла, выводит только те строки, которые удовлетворяют введенному правилу.

Например, я хочу увидеть список ip адресов тех, кто авторизовался используя мой ник.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
symkat@symkat:~$ wc -l /var/log/auth.log
1819 /var/log/auth.log
symkat@symkat:~$ grep symkat /var/log/auth.log
symkat.com sshd[18021]: Accepted publickey for symkat from 10.0.0.234 port 4233 ssh2
symkat.com sshd[30845]: Accepted publickey for symkat from 172.16.32.56 port 56964 ssh2
symkat.com sshd[6065]: Accepted publickey for symkat from 192.168.1.100 port 56374 ssh2
symkat.com sshd[8457]: Accepted publickey for symkat from 10.0.0.234 port 4162 ssh2
symkat.com sshd[8498]: Accepted publickey for symkat from 10.0.0.234 port 5353 ssh2
symkat.com sshd[9474]: Accepted publickey for symkat from 172.16.32.56 port 62164 ssh2
symkat.com sshd[9889]: Accepted publickey for symkat from 10.0.0.234 port 5059 ssh2
symkat.com sshd[23298]: Accepted publickey for symkat from 172.16.32.56 port 51604 ssh2
symkat.com sshd[23607]: Accepted publickey for symkat from 172.16.32.56 port 51611 ssh2
symkat.com sshd[15610]: Accepted publickey for symkat from 10.0.0.234 port 4146 ssh2
symkat.com sshd[17435]: Accepted publickey for symkat from 10.0.0.234 port 4320 ssh2
symkat.com sshd[22907]: Accepted publickey for symkat from 10.0.0.234 port 4254 ssh2
symkat.com sshd[8303]: Accepted publickey for symkat from 192.168.1.100 port 65065 ssh2
symkat.com sshd[26505]: Accepted publickey for symkat from 10.0.0.234 port 4282 ssh2
symkat@symkat:~$

Давайте сохраним этот вывод в файл, чтобы в дальнейшем экспериментировать на нем.

1
symkat@symkat:~$ grep symkat /var/log/auth.log > auth.log

Файл auth.log содержит большое количество информации, которая для ответа на вопрос нам не нужна. Выше мы выполнили команду “wc -l /var/log/auth.log” и обнаружили, что файл содержит 1819 строк текста. Команда grep показала нам только то, что мы хотели узнать, т.е. только 14 строк.

awk

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

Мы можем сделать одну хитрость с помощью команды awk - показать только нужные нам столбцы информации. В нашем случае нам нужен 8-й столбец.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
symkat@symkat:~$ awk '{print $8}' auth.log
10.0.0.234
172.16.32.56
192.168.1.100
10.0.0.234
10.0.0.234
172.16.32.56
10.0.0.234
172.16.32.56
172.16.32.56
10.0.0.234
10.0.0.234
10.0.0.234
192.168.1.100
10.0.0.234
symkat@symkat:~$

Команда awk требует задания шаблона и действия, которое следует выполнить если шаблон будет найден. Для того, чтобы понять как это работает, давайте рассмотрим несколько тезисов об awk:

  • awk требует шаблона и действия, которое следует на нем выполнять
  • awk присваивает переменным $1, $2, $3 и так далее прочитанные значения из входной строки, разделенных пробелами. В нашем случае $1 = symkat.com, $2 = sshd[]:, …
  • В нашем примере мы не использовали шаблон. Следовательно awk принял все строки. Действие, которое мы выбрали, состояло в выводе 8 столбца.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
symkat@symkat:~$ awk '{print $6 " " $8 }' auth.log
symkat 10.0.0.234
symkat 172.16.32.56
symkat 192.168.1.100
symkat 10.0.0.234
symkat 10.0.0.234
symkat 172.16.32.56
symkat 10.0.0.234
symkat 172.16.32.56
symkat 172.16.32.56
symkat 10.0.0.234
symkat 10.0.0.234
symkat 10.0.0.234
symkat 192.168.1.100
symkat 10.0.0.234
symkat@symkat:~$

sort

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
symkat@symkat:~$ awk '{print $8 }' auth.log | sort
10.0.0.234
10.0.0.234
10.0.0.234
10.0.0.234
10.0.0.234
10.0.0.234
10.0.0.234
10.0.0.234
172.16.32.56
172.16.32.56
172.16.32.56
172.16.32.56
192.168.1.100
192.168.1.100
symkat@symkat:~$
В данном примере “” - потоковый оператор. Он использует STDOUT команды слева от него, и направляет его на STDIN команды справа от него. В данном примере мы берем ip адреса (8й столбец из файла auth.log) и отправляем их в качестве входных значений команде sort, которая в свою очередь выводит их нам в отсортированном виде.

uniq

Здесь нет ошибки - это правописание UNIX! Эта команда удаляет дублирующиеся записи, однако требует отсортированных данных. Эта команда смотрит на строку текста, и если следующая строка такая же, не выводит ее, если другая - то выводит. Поэтому мы не можем обрабатывать несортированные данные этой командой.

1
2
3
4
5
symkat@symkat:~$ awk '{print $8 }' auth.log | sort | uniq
10.0.0.234
172.16.32.56
192.168.1.100
symkat@symkat:~$

Теперь мы знаем три ip адреса с которых производилась авторизация с логином symkat на symkat.com. Дальше мы можем захотеть узнать, как часто была авторизация с каждого из них. В таком случае, мы можем использовать ключ -c команды uniq, чтобы посчитать количество строк.

1
2
3
4
5
symkat@symkat:~$ awk '{print $8 }' auth.log | sort | uniq -c
      8 10.0.0.234
      4 172.16.32.56
      2 192.168.1.100
symkat@symkat:~$

Также ничего не стоит отсортировать вывод по количество попыток:

1
2
3
4
5
symkat@symkat:~$ awk '{print $8 }' auth.log | sort | uniq -c | sort
      2 192.168.1.100
      4 172.16.32.56
      8 10.0.0.234
symkat@symkat:~$

Вы можете заметить, что порядок сортировки возрастающий, так принято по умолчанию. Чтобы сменить его - мы должны использовать ключ -r. Также ввиду того, что мы используем числовые данные, воспользуемся ключом -n.

1
2
3
4
5
symkat@symkat:~$ awk '{print $8 }' auth.log | sort | uniq -c | sort -rn
      8 10.0.0.234
      4 172.16.32.56
      2 192.168.1.100
symkat@symkat:~$

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

1
2
3
4
5
6
7
8
9
10
11
12
13
symkat@symkat:~$ cat > data_source.txt
101
12
133
symkat@symkat:~$ sort data_source.txt
101
12
133
symkat@symkat:~$ sort -n data_source.txt
12
101
133
symkat@symkat:~$

Как Вы можете заметить результаты получаются разными. Сложности алгоритмов сортировки оставим за пределами этой статьи. Правило одно - если вы сортируете числа - используйте числовую сортировку.

В предыдущих примерах с файлом auth.log мы использовали относительно небольшой набор данных. Давайте представим, что итоговый результат содержит несколько тысяч ip адресов, и мы хотим знать какие из них встречаются наиболее часто. В таком случае мы будем спрашивать только два адреса, которые встречаются наиболее часто. Есть также команда tail, которая в отличии от head оперирует с концом файла.

В нашем примере мы будем использовать команду head, которая просто выводит требуемое количество строк:

1
2
3
4
symkat@symkat:~$ awk '{print $8 }' auth.log | sort | uniq -c | sort -rn | head -n 2
      8 10.0.0.234
      4 172.16.32.56
symkat@symkat:~$

Выше были упомянуты три вопроса. Команды представлены ниже - попробуйте понять, как они работают:

1
2
3
4
5
6
7
8
symkat@symkat:~$ awk '{print $7 " " $9}' /var/log/lighttpd/access.log | grep " 404" \
> | awk '{print $1}' | sort | uniq -c | sort -rn | head -n 5
      7 /robots.txt
      5 /favicon.ico
      2 /sitemap.xml.gz
      1 http://www.wantsfly.com/prx2.php
      1 http://216.245.205.74/judge.php
symkat@symkat:~$

В данном примере мы определяем основные места возникновения ошибок 404. Три из них я должен исправить или уже исправил, две остальных заключаются в том, что кто-то решил использовать сервер как прокси (чего ему делать незя).

1
2
3
4
symkat@symkat:~$ grep AllowUsers /var/log/auth.log | awk '{print $7 " " $9}' | sort | uniq -c
    221 root 81.30.185.201.dynamic.ufanet.ru
      8 root vayu1.nci.org.au
symkat@symkat:~$

Было совершено 221 попытка авторизации с адреса 81.30.185.201 с логином root. Поэтому следует использовать исключающее правило AllowUsers в настройках sshd_config. Если Вы этого не сделаете, то будете получать такие сообщения.

1
2
3
4
5
6
7
symkat@symkat:~$ ps aux | sort -rnk 3 | head -n 5
httpd 30317  0.0  6.2  46644 31776 ?        S    Aug01   0:01 /usr/bin/php5-cgi
httpd 30316  0.0  1.0  33016  5176 ?        Ss   Aug01   0:00 /usr/bin/php5-cgi
httpd 30315  0.0  0.3  33016  1948 ?        S    Aug01   0:00 /usr/bin/php5-cgi
httpd 30314  0.0  1.0  33016  5180 ?        Ss   Aug01   0:00 /usr/bin/php5-cgi
httpd 30313  0.0  0.3  33016  1944 ?        S    Aug01   0:00 /usr/bin/php5-cgi
symkat@symkat:~$

Использование CPU - третий столбец. В данный момент, нет ничего что сильно использовало бы процессор. Однако если посмотреть на память (4й столбец):

1
2
3
4
5
6
7
symkat@symkat:~$ ps aux | sort -rnk 4 | head -n 5
httpd 30317  0.0  6.2  46644 31776 ?        S    Aug01   0:01 /usr/bin/php5-cgi
mysql     3650  0.0  3.8 123016 19724 ?        Sl   Jul23   3:33 /usr/sbin/mysqld
httpd 30316  0.0  1.0  33016  5176 ?        Ss   Aug01   0:00 /usr/bin/php5-cgi
httpd 30314  0.0  1.0  33016  5180 ?        Ss   Aug01   0:00 /usr/bin/php5-cgi
httpd 30312  0.0  1.0  33016  5176 ?        Ss   Aug01   0:00 /usr/bin/php5-cgi
symkat@symkat:~$

Мы увидим, что php и mysql занимают больше всего памяти.

Статья переводная, оригинал тут.

Публикация защищена лицензией CC BY 4.0 .