«примеры эффективного использования GNU утилит в Linux»

Привет всему сообществу Хабра.
Это мой первый пост и, надеюсь, не последний. Поэтому неизбежны всяческие недочеты, баги и некоторая водянистость текста, так что прошу строго не судить :)
К написанию этого поста меня сподвиг топик «Консоль для новичка.» habrahabr.ru/blog/linux/46610.html, где ISVir поднял острую, на мой взгляд, тему — как доступным языком рассказать новичкам о консоли, не отпугнув их мнимой сверх-сложностью.

Не собираюсь отбирать у ISVir паритет, лишь расскажу о практическом использовании нескольких самых основных утилит «на каждый день», без которых работа в консоли для меня невозможна.

Итак, что мы имеем:

find — поиск файлов. позволяет искать файлы, каталоги, симлинки и другие файловые объекты. find Позволяет задать множество опций поиска таких как:
  • поиск по маске (в имени )
  • контроль глубины вложенности поиска
  • поиск определенных типов файлов(каталог, симлинки, сокеты)
  • поиск по времени создания/модификации файла
  • можно задать размер (от и до в диапазоне) файла
  • выполнение действий с каждым найденным файлом
в мане к find можно прочесть об остальных опциях и параметрах.

итак, с места в карьер — поиск всех файлов в каталоге /etc/, измененных за последние сутки:

$find /etc/ -type f -mtime -1

разберем, что мы написали:

первым параметром всегда указывается начальный каталог для поиска.
опция -type с параметром f говорит find, что нужно искать только обыкновенные файлы.
опция -mtime с параметром -1 указывает find, что нужно найти файлы, изменившиеся за последние сутки.
"-"перед 1 задает верхнюю границу диапазона, т.е. «все, что изменилось за последние 24 часа»

если бы мы указали "+" перед 1, то find нашел бы всех файлы, изменившиеся от 01.01.1970 до вчерашнего дня (более суток назад)
так же можно указать точную дату поставив число без модификатора.

выполнение действий с найденными файлами.
опция -exec принимает строку с командой, которая будет выполнятся для каждого найденного файла
параметр передающийся команде обозначается через {}
строка должна заканчиваться символами " \; "

рассмотрим пример:
* найти в каталоге /tmp все файлы, изменившиеся за последний месяц и скопировать их в каталог
/tmp/backup/
$find /tmp -type f -mtime -30 -exec cp {} /tmp/backup \;

* удалить все каталоги(рекурсивно) с именем logs, изменившиеся за последний день в каталоге
/var/www
$find /var/www -type d -mtime 0 -name logs -exec sudo rm -fr {} \;

параметр d в опции -type указывает на поиск только каталогов
опция -name задает поиск по имени.
здесь стоит добавить, что удалять таким образом файлы не оптимально(медленно).
для удаления у find есть встроенная опция -delete, которая отрабатывает на порядок быстрее.

еще не устали? идем дальше :)

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

во первых, awk может получать данные из STDIN: $echo «test»|awk ...
во вторых, awk эффективен при написании однострочников в консоли, т.к. выполняет код, данные ему как параметр:
$echo «test»|awk " "

awk разделяет входной поток на поля и помещает эти поля в переменные вида $1,$2,..$N
по умолчанию, разделитель полей — пробел, но с помощью опции -F"" это можно переопределить:
$head -4 /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh

$cat /etc/passwd|awk -F":" '{print $1}'
root
daemon
bin

например, у нас в каталоге /var/www есть несколько сайтов. для каждого сайта существует каталог logs, куда пишутся логи апача (для этого сайта).и вот мы хотим узнать суммарный обьем этих логов, а так же найти все логи больше 100Mb.

here we go:

1.поиск больших логов:

$find /var/www -type f -name «access.log*» -size +100M
/var/www/site1/logs/access.log
/var/www/site2/logs/access.log.1.gz

2.подсчитаем суммарный обьем логов:

find /var/www/ -type f -name «access.log*» -exec du -k {} \;|awk '{s+=$1}END{print s}'
5071604

так, не пугаться — щас все обьясню :)

find ищет все файлы по маске (access.log*) и для каждого запускает команду du.
команда du печатает размер файла. опция -k делает вывод в килобайтах.
дальше запускается процессор awk, просто суммирует первое поле строк (числа) в переменную s и выводит значение переменной на экран.

еще примерчик: найдем в системе все файлы и каталоги принадлежищие юзеру test1 и подсчитаем суммарный обьем.
#find / -user test1 -exec du -sm {} \;|awk '{s+=$1}END{print s}'

т.е. здесь с помощью опции -user find ищет файлы, принадлежашие юзеру test1 и для каждого файла/каталога подсчитываем его размер (команда du)
дальше через конвеер эти данные принимает awk и, как мы делали выше, считает их сумму в Kb.

ок. думаю, на сегодня хватит.
пост вышел довольно большим, видимо с непривычки :)

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

спасибо, что уделили время.
+1
16 июля 2008, 09:07
86
walker –9,6

комментарии (55)

0
HerMajor #
Cтатья понравилась, в манах такого не встретишь.
мне как новичку в линуксе полезно было прочесть - в закладки !
поставил бы плюсег, если бы мог
+1
catsmile #
СОХРОНИЛ.
жду продолжения по sed и т.д.
+1
walker #
да, про sed обязательно будет, в связке с awk, find и т.д.
0
foff4ik #
Оч. понравилось, жду продолжения.
+2
Flickr #
Довольно популярный способ распространения троянов это вставки на сайты iframe блока указывающего на “вражеский сервер” с самим трояном. Перелопатить несколько тысяч страниц вручную, задача из разряда фантастических.

Еще полезная команда (чистка кода сайта от iframe вставок):
find ./ -type f -name \*.php -exec sed -i ’s/^.*iframe bla bla bla.*$//g’ {} \;
+1
walker #
да, в следующий раз об этом как раз собираюсь рассказать
ваш пример очень показателен.
–4
Flickr #
Написал бы тоже статейку, но где бы взять карму
+3
akral #
Я не уверен, что после «Вы забыли: rm -rf /» и «Привык работать с root» имеет смысл писать статьи для новичков в Линуксе...
–5
Flickr #
иди дрочи на свою карму
0
aaaDron #
тоже часто приходится чистить сайты от троянских iframе-ов
типа ( <script...>..ndfc() {.... ),
мой вариант делает почти тоже самое, находит и удаляет строчку ndfc() плюс еще 6 строк ниже:
find ./ -type f -print0 | xargs -0 -I'{}' sed -i '/ndfc()/,+6 d' '{}'
+1
Pokoinik #
Часто пользуюсь следующей связкой
find -type d -exec chmod 755 {} \;
find -type f -exec chmod 644 {} \;
0
mprokopov #
chmod -R 755 dirname
0
iTube #
и ты сделаешь все внутри 755.

Показаный выше пример, папкам ставит 755, а файлам 644
+1
walker #
делать chmod -R в данном случае неверно, т.к. права изменяться и на файлы и на каталоги, а если нужно, как писал посмотреть профиль Pokoinik изменить права только на файлы, тогда
find ./ -type f -exec chmod 644 {} \;
НЛО прилетело и опубликовало эту надпись здесь
+2
Lunatik #
find — далеко не самый лучший "поисковик", если использовать его именно как поисковик. locate с этим делом справляется быстрее, индекс, все-таки.

А find удобен именно для того, чтобы перебирать файлы из конкретного участка дерева и с ними что-нибудь делать.
0
iTube #
Если файлы часто обновляются, делать updatedb постоянно не лучший вариант. А так конечно намного быстрее.
0
walker #
верно, locate/slocate на несколько порядков быстрее (т.к.поиск по созданной базе)
но на боевых серверах файлы обновляются часто и запускать индексирование чаще, чем раз в сутки, имхо накладно
к тому же, я делаю упор не на сам поиск, а на выполнение действий с найденным.
как пример : -exec в find + поиск по заданным критериям.
конечно, с locate такое тоже частично можно делать:

locate some_dir|xargs rm -fr
locate named.conf|xargs grep some_zone -A 20

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

вобщем, тема для еще одной статьи ))
–1
kilg #
всегда думал, что locate для блондинок, не знающих, что у них на компе находится.
никогда не использовал, и не вижу надобности.
0
walker #
а вот смотрите:
есть у вас два десятка серверов (или даже просто неизвестный сервер)
и вам нужно поправить httpd.conf например - и совсем не факт, что он будет лежать в /etc/httpd/conf/httpd.conf
где вы будете его искать ? делать find / ?

а locate httpd.conf вам в этом случае сразу все покажет.
*httpd.conf редко перемещают с места на места, так что инфа будет актуальной.
0
kilg #
у меня есть "неизвестный" сервер? Откуда? Что мне делать на неизвестном мне сервере?
а на известных мне серверах, я знаю, где какие конфиги лежат
0
Lunatik #
Если вы не видите надобности, это еще не значит, что ее нет. Если бы locate был совсем не нужен, его бы не написали в далеком 83 году.

Я, вроде бы, не блондинка, но таки не знаю что где именно находится из 678000 файлов на моем домашнем компьютере.
+1
dovg #
ИМХО: образцовая статья про использование консоли.
Спасибо!
0
walker #
аригато, гозаимаста ))
0
preprocessor #
наконец то кто-то понял что нужно писать в статьях для новичков линукса. спасибо.
0
walker #
спасибо за отзыв, значит дальше буду двигаться в данном стиле.
+1
chegivara #
я бы не советовал начинать работать в консоли с этой статьи.
Может для начало надо было обьяснить новечку что вообще такое консоль?
Что такое STDIN, STDOUT, STDERR. Философию Unix в отношении консоли. Рассказать подробнее про pipe, про bg, fg. Также использование подстановочных символов, шаблонов. О том, что консоль рассматривается как файл.
+2
walker #
ну я тоже не советую эту статью, как первую или вторую
здесь наверно будет уместным еще раз сослаться на статью "Консоль для новичка.", написанную посмотреть профиль ISVir.
я же предполагаю, что человек уже изучил подобные вещи, но не совсем понимает что с ними делать ...как-то так.
0
chegivara #
Вот прекрасная , на мой взгляд лучше не написать
0
leave #
несколько комментариев.
1. -exec есть зло, ибо выполняет действие отдельно над каждой строкой. xargs работает процентов на 30 быстрее.
2. >> find /var/www/ -type f -name "access.log*" -exec du -k {} \;|awk '{s+=$1}END{print s}'
с точки зрения производительности и читабельности ИМХО не самое лучшее решение. Предлагаю свой вариант:
find /usr/local/apache/logs/ -type f -name "*_log"|xargs du -csh
0 /usr/local/apache/logs/modsec_debug_log
2.2M /usr/local/apache/logs/access_log
1.0K /usr/local/apache/logs/audit_log
875K /usr/local/apache/logs/error_log
96K /usr/local/apache/logs/ssl_engine_log
3.1M total

где:
-c - "Итого"
-s - "display only a total for each argument"
-h - human-readable. Кому как, но лично мне не очень удобно переводить в уме кило в мега.

3. awk
>>по умолчанию, разделитель полей - пробел, но с помощью опции -F" " это можно переопределить
кавычки для агрумента -F не нужны - они слишком "въедаются" в мозг, и это приводит к некоторым неудобствам: тот же -F ":" не на всех системах корректно отрабатывает.
но это так, мелкая придирка :)
вообще, всю конструкцию
>>cat /etc/passwd|awk -F":" '{print $1}'

я бы заменил более короткой
cat /etc/passwd|cut -d : -f 1


В любом случае, успехов вам. Ждем продолжения про sed :)
0
walker #
1. верно, но не вспоминать про жту опцию тоже было бы плохо, не так ли?
2.дело в том, что мой вариант более гибкий и я бы хотел, чтобы человек научился прежду всего именно ему.
3.опять вы правы, но как-то я побоялся втискивать в рамки статьи еще и cut, а про awk сказать хотелось.

вобщем, все это будет во второй части
0
leave #
2. Согласен, но -h можно было и упомянуть :)

Вы молодец, завидую по-доброму: я вот не умею писать статьи такого уровня, чтобы доходчиво о простых вещах; как-то "серьезные" мануалы лучше получаются :)
+1
walker #
2. ну для моего контекста она скорее мешала, поэтому и не описал.
почему мешала?
просто вывод du обрабатывается потом awk и мне там совсем ни к чему символы K,M,G и запятые ..
подумайте сами, как бы вы распарсили (с уклоном для новичка) вывод
du -sh|awk "??"
а du -k дает нам однозначные цифры, без "грязи"
0
leave #
Логично :) Не подумал как-то про этот момент. Мои извинения.
0
walker #
ничего, все ок ))
почему бы вам тоже не написать что-то более веское ? - знания, вижу у вас есть...
0
leave #
Я молчать не умею, карма страдает хроническим минусом :)
И придумать тему не получается такую, чтобы и полезно, и многим :)
0
walker #
ну карму мы вам поправим :), надеюсь, не только я...
а тем очень много - надо просто взглянуть на свою работу со стороны - попробуйте.
0
leave #
Спасибо, но... Работа администратора j2ee серверов приложений вряд ли интересна хабраюзерам. Попробую прикинуть, что из моего фрилансерского опыта может быть полезным широким массам. Спасибо за доверие.
0
walker #
а я бы с удовольствием прочел про администрирование J2ee серверов и приложений. серьезно.
ну и по фрилансу, думаю, всем интересно будт почитать
0
leave #
вы меня почти уговорили :)
попробую написать что-нибудь, если самому понравится - стукнусь вам за кармой :) не против?
0
walker #
и спасибо за поддержку - этого в таких вещах всегда не хватает...
более серьезные вещи тоже обязательно будут, не все сразу :)
0
walker #
>кавычки для агрумента -F не нужны

для новичка - это более наглядно, вы согласны?
НЛО прилетело и опубликовало эту надпись здесь
0
sin_avatar #

Еще очень рекомендую xargs. Возможно вам стоит упомянуть про perl (подавляющее число однострочников я пишу на нем).

0
Wasiliy #
Доступно и с примерами.
Спасибо за статью, в деле пригодится!
0
segun #
Есть хорошая, на мой взгляд, книга - Unix Power Tools - Shelley Powers, Jerry Peek, Tim O'Reilly, Mike Loukides. Будет полезна новичкам и не только.
0
nikitad #
Где-то слышал фразу: если бы люди умели пользоваться find, sed, awk и grep, то миллионы программ никогда не были бы написаны.
0
walker #
отлично сказано!
помню, в начале освоения линукса, уже администрируя несколько веб серверов, писал простыни на перле, хотя с помощью sed+find задача решалась в одну строку.
с другой стороны, это дало мне опыт программинга на перле :)
0
3a2pu34uk #
Спасибо за развитие темы.
Есть один общий вопрос касательно поиска ответов для начинающих пользователей, или КАК КУДА и Почему обращаться "по уму"
Суть вопроса в описании web-ресурсов и некоторых правил общения, гарантирующих адекватную реакцию на обращение за помощью.
В идеале хотелось бы иметь свои "желтые страницы" рунета по opensource.
Просто зачастую пара нерешенных вопросов заставляет многих возвращаться к окнам. У меня, к примеру, так и не работает сканер Canon Lide 90 и дровишек к нему пока не предвидется :(
и извиняйте за невольный офтоп
0
retif #
а как такое сделать %)
каждый из 10 файлов в папке переместить в 10 создаваемых папкок названных как эти 10 файлов причем из названия файлов и папок убирать некую последовательность символов :)

получится такое 1 командой?
+1
walker #
$ls
. .. 10.log 1.log 2.log 3.log 4.log 5.log 6.log 7.log 8.log 9.log

$for i in *;do m=`echo $i|sed "s/\.log//"`;mkdir $m ;mv $i $m/$m;done

$ls -l
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 1
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 10
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 2
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 3
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 4
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 5
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 6
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 7
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 8
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 9
drwxr-xr-x 12 test1 test1 4096 Июл 18 03:17 .
drwxrwxrwx 11 root root 20480 Июл 18 03:13 ..

$ls -l 1

-rw-r--r-- 1 test1 test1 0 Июл 18 03:14 1
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 .
drwxr-xr-x 12 test1 test1 4096 Июл 18 03:17 ..
$ls -l 6

-rw-r--r-- 1 test1 test1 0 Июл 18 03:14 6
drwxr-xr-x 2 test1 test1 4096 Июл 18 03:17 .
drwxr-xr-x 12 test1 test1 4096 Июл 18 03:17 ..
0
retif #
спасибо, консоль рулит!
0
Scala #
history|awk ‘{a[$2]++} END{for(i in a){printf “%5d\t%s\n”,a[i],i}}’|sort -rn|head
0
ezodoc #
Как мне сделать поиск тех файлов в которых есть троян, с параметром в котором задан пример «вредного» текста, но без замены (удаления) такового?
0
walker #
просто grep:

$cd www_site_path
$grep -ri «some malware code» ./

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.