Pull to refresh

Comments 144

Еще можно добавить про расширения grep —

grep is used for simple patterns and basic regular expressions (BREs); egrep can handle extended regular expres-
sions (EREs). See re_format(7) for more information on regular expressions. fgrep is quicker than both grep
and egrep, but can only handle fixed patterns (i.e. it does not interpret regular expressions). Patterns may
consist of one or more lines, allowing any of the pattern lines to match a portion of the input.

zgrep, zegrep, and zfgrep act like grep, egrep, and fgrep, respectively, but accept input files compressed with
the compress(1) or gzip(1) compression utilities.
Спасибо за пост! Действительно, отчего-то многие по каким-то непонятным причинам боятся осваивать grep. Поэтому простые вводные мануалы очень кстати. Вот ещё несколько кратких статеек о самых основах:
Команда grep — человеческий man
О grep для начинающих
A Beginner’s Guide to Grep: Basics and Regular Expressions
Beginner’s Guide to Grep
UFO just landed and posted this here
Да, тяжело читать. Лучше совсем без подсветки, чем с такой
Просто не надо такие примеры из под рута запускать :-)
grep это ещё цветочки перед awk.
UFO just landed and posted this here
UFO just landed and posted this here
Что тут знать-то? Вы же понимаете, что тут значит точка? Это не нужно запоминать, надо просто понимать как это работает.
Отсутствие пробела в примере между grep и точкой сбивает с толку.
Отсутствие пробела — это просто опечатка. Он таки нужен, иначе ничего не работает.
Ваш вариант хорош в комбинации с исключением комментариев. Например, демонстрировать конфиги удобно с помощью

grep -Ev '^$|^\s*#' /etc/nginx/nginx.conf
grep ^[^#] /etc/nginx/nginx.conf (если перед # ничего нет)
Не убирает пустые строки, и вот лично у меня /etc/nginx/nginx.conf (как и в официальном примере) имеет пробельные символы перед комментариями.
А ноль часов это четный час?

Ну если делится без остатка на 2 то чётный )
Один из полезнейших и регуляршнейших инструментов. Не rocket science, но очень многим полезно было бы знать — не только системным администраторам.
Забыли упомянуть важную особенность грепа да и любой команды:
man grep | grep -A1 -- -P
       -P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This is  highly
              experimental and grep -P may warn of unimplemented features.


Любимый вопрос для собеседования: удалить файл с именем "-". Хотя как можно не знать grep… Хотя на фрилансе искали, это многое объясняет.

Насчёт cat не всегда справедливо. Я часто делаю сначала cat… а потом просто добавляю в конец grep, если надо.
Любимый вопрос для собеседования: удалить файл с именем «-».
Вот так: unlink -
На самом деле конкретно с файлами проще всего использовать "./filename". Работает в любых командах, какой бы кривой парсер командной строки там не использовался. А вот -- — это для примера выше, то есть когда нужен аргумент, начинающийся с минуса и не являющийся именем файла.
Я знаю для чего он. unlink позволяет ни с чем не заморачиваться — она просто удаляет, что дадут.
Даже он не сможет так просто удалить файлы "--help" и "--version"
Видимо от ОС зависит:
bolk@bolknote ~$ touch — --help
bolk@bolknote ~$ ls — --help
--help
bolk@bolknote ~$ unlink --help
bolk@bolknote ~$ ls — --help
ls: --help: No such file or directory
Скорее от версии unlink. У меня GNU coreutils 8.21
На FreeBSD, о которой идет речь в статье, конечно всё может быть по-другому.
Любимый вопрос для собеседования: удалить файл с именем "-".

Я что-то упускаю?

valdikss@valaptop ~/test % l
total 8.0K
-rw-r--r--  1 valdikss users    0 Jul 12 02:02 -
drwxr-xr-x  2 valdikss users 4.0K Jul 12 02:02 .
drwx------ 92 valdikss users 4.0K Jul 12 02:02 ..
valdikss@valaptop ~/test % rm -
valdikss@valaptop ~/test % l
total 8.0K
drwxr-xr-x  2 valdikss users 4.0K Jul 12 02:02 .
drwx------ 92 valdikss users 4.0K Jul 12 02:02 ..
valdikss@valaptop ~/test %
Имелось ввиду, видимо:

# touch -- "-1.txt"
# rm -1.txt
rm: illegal option -- 1
usage: rm [-f | -i] [-dIPRrvW] file ...
       unlink file
# rm -- "-1.txt"
#

Свежие версии rm стали умнее в таких случаях.
$ rm --version
rm (GNU coreutils) 8.21
# more lines
$ rm -l.txt
rm: invalid option — 'l'
Try 'rm ./-l.txt' to remove the file ‘-l.txt’.
А ведь и правда :-)
Две любимые команды:

поиск процессов
ps aux | grep mysql

поиск текста в файлах директории
grep -rl 'some text' ./
Можно и без грепа:
ps -C mysql
Использование POSIX-классов не спасает:

А использование \t?
Так просто \t вы туда не засунете, но можно использовать $'\t' — но это уже не grep, а bash.
А чего там сувать-то? Жмём Ctrl+V в консоли, потом Tab.
Да. Почитайте мои коментарии к ней.
Тогда я не понял ваше сообщение совершенно…
Зачем сувать \t или использовать башизмы, если можно просто сам «tab», как символ вставить? Вот о чём мой комментарий.
Читабельность. И копипастить удобнее.
Ээээ… читабельность?
А как правильно выбрать строки между двумя шаблонами? Я намучился с выкусыванием Java-ошибок из лога. Надо показать все, начиная со строки с шаблоном ERROR и заканчивая строкой, начинающейся с шаблона временной метки, типа 2014-07-11 14:45:48,073
Здесь лучше подойдёт awk.
ant0.ru/sed1line.html
Печатать часть файла между двумя регулярными выражениями (включительно):
  • sed -n '/Iowa/,/Montana/p' (регистро зависимый)

В вашем случае как-то так: sed -n '/ERROR/,/^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}/p'
Если хочется ненормального программирования, то можно grep -A 9999 ERROR | grep -B 9999 2014-07-11
Это только если ошибка была одна.
olorin@stitch:~$ echo "sdlfkj ololosdkfjl   sdkjfzhigurda sd;flk;lk" | grep -oE 'ololo(.)*zhigurda'
ololosdkfjl   sdkjfzhigurda
olorin@stitch:~$
Это работает только в одной строке.
Почему это? Сам так логи разбирал.

root@server:/# tail ./test 
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "Backtrace:"
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "[1] : The\Core\Application::onShutdown()"
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "[2] /home//core/rev20140516113043/Core/Application.php:960 The\Core\TemplateEngine\Template::__toString()"
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "[3] /home//core/rev20140516113043/Core/TemplateEngine/Template.php:23 The\Core\TemplateEngine\TemplateAdapter::run([Long string(10622)] '<!DOCTYPE html>"
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "<html lang="ru-RU">"
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "<head>"
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "    <meta charset="utf-8">"
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "    <title><?=$this->makeEcho...,array([Long string(214)] array(),object The\Core\TemplateEngine\TemplateRawInput,array([Long string(129)] array([Long string(...))"
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "[4] /home//core/rev20140516113043/Core/TemplateEngine/TemplateAdapter.php:30 eval()"
[12-Jul-2014 10:43:38] WARNING: [pool admin] child 20811 said into stderr: "----------------------------------------------------------..."
root@server:/# tail ./test | grep -oE "\"(.*)\""
"Backtrace:"
"[1] : The\Core\Application::onShutdown()"
"[2] /home//core/rev20140516113043/Core/Application.php:960 The\Core\TemplateEngine\Template::__toString()"
"[3] /home//core/rev20140516113043/Core/TemplateEngine/Template.php:23 The\Core\TemplateEngine\TemplateAdapter::run([Long string(10622)] '<!DOCTYPE html>"
"<html lang="ru-RU">"
"<head>"
"    <meta charset="utf-8">"
"    <title><?=$this->makeEcho...,array([Long string(214)] array(),object The\Core\TemplateEngine\TemplateRawInput,array([Long string(129)] array([Long string(...))"
"[4] /home//core/rev20140516113043/Core/TemplateEngine/TemplateAdapter.php:30 eval()"
"----------------------------------------------------------..."
root@server:/#
Ну вы опять же в одной строке нашли открывающую и закрывающую скобку. Попробуйте например найти от 'Backtrace:' до '<title>'.
Ааа, при таком раскладе. Ну тогда да, мой вариант не катит:)
есть утилитка pcregrep с ключем -oNUMBER, которая позволяет возвращать только нужную группу
Некрасивая конструкция? Потрюкачим немного:
root@nm3:/ # ps -afx | grep "[t]tyv" 1269 v1 Is+ 0:00.00 /usr/libexec/getty Pc ttyv1 1270 v2 Is+ 0:00.00 /usr/libexec/getty Pc ttyv2 1271 v3 Is+ 0:00.00 /usr/libexec/getty Pc ttyv3 1272 v4 Is+ 0:00.00 /usr/libexec/getty Pc ttyv4 1273 v5 Is+ 0:00.00 /usr/libexec/getty Pc ttyv5 1274 v6 Is+ 0:00.00 /usr/libexec/getty Pc ttyv6 1275 v7 Is+ 0:00.00 /usr/libexec/getty Pc ttyv7

А как это работает этот пример? Я что-то не понял.

P.S.: Спасибо за статью. Реквестирую такую же по sed!
Да, пример изначально алогичный. И само использование символьного класса для одного символа кажется бессмысленным.
По шагам как происходит обработка этого момента:
grep "[t]tyv" помещается в список процессов;
— происходит преобразование символьного класса [t] в t;
— grep начинает работу;
Т.е. grep ищет ttyv, в то время как в список процессов попало [t]tyv.
Надеюсь смог объяснить.
Всё было так просто :-) Спасибо за разъяснение.
Часто пользуюсь -l когда надо что бы grep показал в каком файле нашёл ответ:
> grep -l "www.google.com" *.conf
httpd-test.conf


Или в совокупности с find:
> find . -name "*.conf" -exec grep -l "ServerName" {} \;
./httpd-test.conf
./conf/httpd.conf


Можно без find'a:
grep -Rl "ServerName" --include="*.conf" .

find ваш тоже можно существенно ускорить:
find . -name "*.conf" -exec grep -l "ServerName" {} \+
То было просто как упрощённый пример. find может много ещё сверху фильтров сделать типа времени и прочего.

А по поводу "\+" не знал, спасибо. Почти как xargs получается.
а еще удобна -L, когда нужно найти файлы, в которых не встречается искомая конструкция
Хотелось бы добавить, что в windows есть не менее полезная команда findstr
Например,
netstat -anb | findstr 554
И как все виндовые утилиты командной строки, она ошеломляет возможностями и удобством.
Но все же, поиск по файлу/рекурсивный по директории может, нумеровать строки может, строки до и после паттерна так же отображает. Таким образом, на мой взгляд, все наиболее распространенные варианты использования линукс-аналога предоставляет.
Если есть возможность — лучше все-таки залить портированный grep.
На своих машинах у меня всегда стоят юниксовые тулзы. Но бывает, надо что-то быстро сделать на чужой машине, тогда подобное знание очень пригождается.
Хотелось бы добавить что пора прекратить насиловать труп BAT-файлов в Windows есть powershell, а в нём команда «Select-String» и прочие.
Не всегда нужна(удобна) пушка, для некоторых воробьев и рогатки хватает. Findstr удобен для 'быстрых' задач/действий. Согласен что скрипты удобнее на powershell писать.
Какая пушка? Это отличный инструмент на каждый день. BAT/CMD надо забыть, как страшный сон.
powershell не годится в качестве замены шелла, потому что он enveloping. В том смысле, что нормально в нём работать можно только с софтом, который готов к powershell'у, и отдаёт структурированные объекты. В условиях неструктурированного stdin powershell, мягко говоря, не очень удобен.
Вот уж не знаю чем он вам не угодил в таких случаях. Я на нём много программировал, когда у меня Винда была, никаких трудностей не испытывал. С утилитами, которые гонят «объекты» по пайпу просто удобнее, с остальными — примерно так же, как на «баше».
Про опцию -o ни слова, хотя она очень и очень полезна, особенно вместе с регэкспами.

Шайтанство с --line-buffered тоже не раскрыто. А ведь новичков ждёт большой сюрприз с такой строчкой:

tail -f /var/log/apache/access.log|grep myfile|grep 200

С большой вероятностью вывода не будет довольно долго. Правильно:

tail -f /var/log/apache/access.log|grep --line-buffered myfile|grep 200

Комбинация grep foo|awk '{print $2}' заменима на awk '/foo/{print $2}'
Ах, спасибо за замену grep foo|awk '{print $2}' на awk '/foo/{print $2}'! Взял на вооружение.
grep -v # /etc/resolv.conf

Не сработает как вы описали — с «#» тут начнётся комментарий. Существует так же fgrep (или grep -F), который ищет подстроку, а не регулярку, он быстрее и позволяет не экранировать спецсимволы регулярных выражений.
Что это за неуч минуснул?
# /bin/csh
root@nm3:/ # grep -v # /etc/resolv.conf
nameserver 8.8.8.8

root@nm3:/ # /bin/tcsh
root@nm3:/ # grep -v # /etc/resolv.conf
nameserver 8.8.8.8

root@nm3:/ # /bin/sh
# grep -v # /etc/resolv.conf
Usage: grep [OPTION]… PATTERN [FILE]…
Try `grep --help' for more information.
# grep -v "#" /etc/resolv.conf
nameserver 8.8.8.8

пояснения нужны?
Нужны. В каком Линуксе по-умолчанию стоит csh и с каких пор, для примеров на другом шелле, специально не указывается, что шелл другой?
Да я почти с этого статью начал.
Распишем детальнее:
root@nm3:/ # grep --version | grep grep
grep (GNU grep) 2.5.1-FreeBSD
root@nm3:/ # uname -o
FreeBSD
root@nm3:/ # id
uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
root@nm3:/ # echo $SHELL
/bin/csh
У вас в тегах «Линукс».
Я думаю, что большинство примеров будут работать и в Линуксе, ну а уж выяснять в каком шелле требуется закавычивание, а в каком нет, уж извините, не буду )
И не нужно. Обычная вещь — при использовании шелла отличного от sh, указывается какой шелл вы имеете ввиду.
А что же по вашему делает Борновский шелл таким привилегированным? :)
пройдёмся по дефолт-шеллам:
BusyBox ash
GoboLinux zsh
OpenBSD ksh
FreeBSD tcsh
Mac OS X tcsh / bash
Minix ash
AIX вроде ksh
Согласен, что может стоит указывать shell в котором делаются тесты, но уж никак не по причине того что это не sh
Ничего. Потому что я говорю не про bsh, не про bash, а про sh (именно этот шелл указан в большинстве шелл-скриптов, которые мне попадаются в самых разных ОС). Кроме того, в тегах «Линукс», а не все эти операционные системы, которые вы указали.
В тегах ещё и *nix, и все вышеперечисленные Unix-подобные, не говоря уж о FreeBSD, которая самый что ни на есть прямой потомок ATT UNIX
А что касается именования sh, то посмотрите куда он линкуется, под ним может скрываться несколько совершенно разных shell'ов.
Как пример:
root@DD-WRT:~# echo $SHELL
/bin/sh
root@DD-WRT:~# $SHELL --version
BusyBox v1.22.1 (2014-06-23 09:50:00 CEST) built-in shell (ash)

Знаю я куда он линкуется, ну и что? Когда в файле пишут !#/bin/sh, то пишут именно на sh, а не на том, куда он там линкуется.
Совсем не понимаете?
Это значит что по пути /bin/sh может быть хардлинк или симлинк на какой угодно шелл.
Как вы и просили выше пример линукса с дефолтным ash
Нет, это вы не понимаете.

sh — это вполне определённый язык. Например, «#» там комментарий. Неважно на какой шелл у вас там линк, «#» должна работать единообразно — быть комментарием.

Если вы используете другой шелл, то укажите какой, только и всего, не заставляйте всех гадать.
Ладно попробуем по шагам:
— sh — это командный интерпретатор. Ему можно передавать команды на исполнение.
— Они могут передаваться как из интерфейса командной строки так и из скриптов.
— Сейчас говорим только об интерфейсе командной строки (попутно вопрос — Откуда там могут взяться комментарии?)
— По пути /bin/sh может оказаться совсем не тот интерпретатор, который Вы ожидаете увидеть, то что он зовётся sh, совсем не значит, что там живёт sh

бузибокс:
/bin/sh --version
BusyBox v1.22.1 (2014-06-23 09:50:00 CEST) built-in shell (ash)

дебиан
ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar 1 2012 /bin/sh -> dash

центос
# /bin/sh --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

Надеюсь вы понимаете что между ash, dash и bash таки есть хоть какая-то разница.
Я понятнее не смогу объяснить.
Зачем вы это всё рассказываете?

sh — это интерпретатор и вполне конкретный язык. Да, многие шеллы с ним совместимы. Когда вы используете другой язык (не sh), надо это указать. Вот и всё. Не нужно уже несколько комментариев играть в Капитана Очевидность.
— По пути /bin/sh может оказаться совсем не тот интерпретатор, который Вы ожидаете увидеть, то что он зовётся sh, совсем не значит, что там живёт sh
Давайте не будем рассказывать сказки. По адресу /bin/sh живёт именно sh. Это может быть bash, dash, ksh или FigZnaetChroSh, но это точно не csh и у него есть вполне определённые правила. И, в частности, в главе Token Recognition чётко и недвусмысленно написано, что всё, что следует за символом # считается комментарием.
Сказок никаких нет. Яж и не спорю, что /bin/sh — все Борн-шелл совместимые (даже в той же FreeBSD). И при исполнении сценариев в основном они стараются поддерживать Борн-шелл совместимость, хотя давно уже не удаётся, иначе не писалось бы кучу книг о переносимом Борн-шелл программировании. Вот только Вы опять упустили суть с чего начался вопрос. Мы говорим не о сценариях. В сценариях и С-шеллы интерпретируют # однозначно как комментарий и никак иначе. И если поместить строку с которой начался вопрос в скрипт и выполнить её /bin/csh'ем, то она гарантированно не отработает.

Но, объясните откуда взялись комментарии в интерфейсе командной строки. Или в борн-совместимых шеллах можно в командной строке писать команды с комментариями?
иначе не писалось бы кучу книг о переносимом Борн-шелл программировании
Непортабельно можно писать на любом языке, будь то C или Java.

Но, объясните откуда взялись комментарии в интерфейсе командной строки. Или в борн-совместимых шеллах можно в командной строке писать команды с комментариями?
Разумеется. Вот этого бреда:
В сценариях и С-шеллы интерпретируют # однозначно как комментарий и никак иначе. И если поместить строку с которой начался вопрос в скрипт и выполнить её /bin/csh'ем, то она гарантированно не отработает.
в них нету.

Вернее это не совсем так: в bash'е подобное поведение можно включить (100500 опций — это «наше всё», да, разработчики GNU'сных утилит это любят), но понятно, что по умолчанию оно выключено.

Зачем вообще может быть нужен, с позволения сказать, shell, который ведёт себя по разному в интерфейсе командной строки и при интерпретации скрипта? Я всегда думал, что только Microsoft мог создать подобный ужас. Сами себе вы можете создавать какие угодно проблемы, но по умолчанию интерактивный shell и неинтерактивный ведут себя одинаково. И, в частности, одинаково реагируют на #
Это стандартное поведение для С-шеллов.
Более того зачастую в системе используются по умолчанию разные login- и script- шеллы.
Ну в той же FreeBSD дефолтным логин-шеллом является tcsh, а скриптовым ash (т.е. они даже не одного пошиба, первый С-шный, второй Борновский)
Если не ошибаюсь, то и в Mac OS X старых версий были tcsh и bash
Ну в той же FreeBSD дефолтным логин-шеллом является tcsh, а скриптовым ash
Такого понятия, как «дефолтный скриптовый шелл», не существует. Какой шелл запрошен в первой строчке — такой и будет этот скрипт обрабатывать.
А если ни какой не запрошен, то скрипт или будет работать — или нет, в зависимости от того, из какого шелла его запустили. А из других программ так вообще его не запустить. Так что нельзя #! пропускать никогда.
Запустил. Вот результат: execl failed, return code = -1
Аналогичная вариативность поведения наблюдается и у ksh с zsh (которые являются bourne-совместимыми с элементами C-шеллов). Например, zsh использует : для комментариев (и в командной строке, и в скриптах), но ещё и адекватно воспринимает # в скриптах (для shebang, как минимум).

Возможно, что поведение csh/tcsh аналогично, я не тестировал.
Да я вот и не пойму на кой чёрт мне комменты в консоли? На утро пересматривать history с комментариями, чтобы понимать что спьяну вечером наворотил?

Ну кто мешал при разборе optarg закавычить #
Хотя, возможно, всё дело привычки. Это фряшники привыкли к разным скрипт/логин шеллам. Для линуксоидов это, действительно, кажется необычным.

Но таки всем участникам обсуждения спасибо!
В статье закавычил все #.
Да я вот и не пойму на кой чёрт мне комменты в консоли? На утро пересматривать history с комментариями, чтобы понимать что спьяну вечером наворотил?
Например, чтобы не потерять набранную команду, когда нужно проверить какие-то предусловия. А следом взять её из history, поправить, если нужно, и выполнить. У меня это основной кейс.

А набрать "<C-a>: <Ret>" мне подчас удобнее, чем, например, открыть второй терминал и привести его к тому же стейту.

Хотя, возможно, всё дело привычки. Это фряшники привыкли к разным скрипт/логин шеллам. Для линуксоидов это, действительно, кажется необычным.
Для тех, кто пользуется, например, zsh — ничего необычного (у меня скрипты — sh/bash, а интерактивная консоль — zsh). Неудобств не испытываю.
/bin/sh это в 99.99999% случаев совместимый с ним шелл. Однако Большая часть скриптов коорые указывают sh в shebang используют bash и ожидают по /bin/sh обнаружить именно его. И ни о какой совместимости с sh там не думают. Ссылаться на /bin/sh удобно потому, что он там всегда есть, а bash может и не быть.

Вернемся к началу: то, что вы не знаете о том, что есть "#" в sh-совместимых шелах это исключительно ваша проблема. Ко мне не раз такие вот как вы обращались с криками, что мои zsh скрипты не работают в их баше, хотя у них даже раширение стояло zsh.
Авторы нормальных скриптов знают, что /bin/sh должен быть совместим с оригинальным sh, а не bash или zsh. В Debian/Ubuntu это dash, и башизмов в системных скриптах с /bin/sh нет.
Зачем вы мне это рассказываете?
К моему удивлению никто из претендентов с обоими вопросами не справился. Двое, в принципе, не знали о существовании grep.


(Дергая веком) К-к-к-ак?! Вы точно указали, что вакансия unix-админа?

Большое спасибо за статью. Было интересно и познавательно.
К сожалению, эта история имела продолжение. Поиски проводились ещё дважды. Суммарно ещё человек 10. Одному пришлось отказать, т.к. вряд-ли работодатель смог бы его мотивировать через полгода-год. Из остальных был выбран самый молодой в надежде, что удастся его научить… Но, видимо, учитель я плохой…
Не понимаю. Вы искали на удалёнку или в каком-то конкретном городе? Может денег давали мало? Смотрю на примере своем и своих знакомых. Знаю как минимум пять людей (не считая меня), которые подобные задачки решат сходу спросонья.

Одному пришлось отказать, т.к. вряд-ли работодатель смог бы его мотивировать через полгода-год.


Тут имеется ввиду, что человек через полгода-год захотел бы больше денег или повышение в должности?
Удалёнку, со сменным идиотским графиком и монотонной и скучной работой без фантазии, хоть и с приличной оплатой (для удалёнки).
Задача которая меня всегда интересовала — как сделать рекурсивный поиск по директориям включая архивы? После винды, где тотал ищет очень быстро, этого порой очень нехватает.
ack, ag (the silver searcher). Удивлён, что о них ещё не написали. Ищут очень быстро, особенно ag. По бинарным файлам (архивам) grep ищет по умолчанию, ack и ag нужно специально это указывать, поскольку они создавались для поиска по исходному коду.
Искать рекурсивно и в архивах можно примерно так:
Скрытый текст
Структура директории и содержание файлов:
$ tree
.
├── test.txt
├── test.zip
└── ttt
    └── test.zip

1 directory, 3 files
$ cat test.txt 
one two three four
five

six


seven

grep (пример из документации ack):
$ grep seven $(find . -type f | grep -v '\.svn')
./test.txt:seven
Binary file ./ttt/test.zip matches
Binary file ./test.zip matches

ack (простого решения не нашёл, его сейчас сложно заставить искать по бинарным файлам):
$ ack --type-set archive:ext:zip --archive seven
ttt/test.zip
8:seven

test.zip
8:seven

$ ack seven                                     
test.txt
7:seven

$ # or like in grep:
ack seven $(find . -type f | grep -v '\.svn')
./test.txt
7:seven

ttt/test.zip
8:seven

./test.zip
8:seven


ag:
$  ag --search-binary seven
Binary file ttt/test.zip matches.

test.txt
7:seven

Binary file test.zip matches.


Да, есть ещё git grep, который очень быстро ищет по репозиторию git.
Имелся в виду не поиск по бинарным файлам архивов, а распаковка на лету. Если в незапакованном файле строка была, в запакованном её может не быть и наоборот.
Большое спасибо за ack, ag. До этого пользовался самописным скриптом для этой задачи на основе grep.
Сейчас потестил, скорость поиска заметна даже на небольших проектах.
Вывод также стал более читаем.
Не по архивам, но никто не написал: grep -R (постоянно использую для поиска в исходниках).
Выше несколько раз написали про -r (это синоним -R).
cat любите, а перенаправление вывода ненавидите? Почему?
wc -l? А опция -c в grep почему не?
wc -l? А опция -c в grep почему не?
В статье то же самое написано.
> Отбираем только строки с ip:
> root@nm3:/ # grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" /etc/resolv.conf

А строки с 999.999.999.999 тоже отберет?
Да, конечно, я сознательно не усложнял эту регулярку.
grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b' /etc/resolv.conf
была бы совсем нечитабельна.
Для анализа логов в большинстве случаев хватает и [0-9\.]{7,15}
Как открыть результат в nano? По типу grep foo /bar | cat
поставить nano2.2 и выше, где была добавлена эта фича.
У меня стоит 2.2.6, и когда я пробовал сделать grep foo /bar | nano, он создает отдельный файл вместо того, чтобы просто показать output в нано
Странно, что grep кому-то приходится объяснять, без него в командной строке очень сложно и бессмысленно. Это одна из первых команд, которую вообще должен выучить линуксоид (ну, после head/tail).

Вкупе с sed становится бронебойным инструментом обработки файлов (удаления кусков, форматирования и т.п.). Под виндой, увы, приходится писать мелкие скрипты на перле.
Под Виндой PowerShell есть.
Ох как тут не хватает поддержки PCRE…


Попробуйте pcregrep. Не тратится время на придумывание BREs.
Автору спасибо за статью — весьма интересно. Особенно про «топ»-админов.

По поводу ключей. М.б. лучше показывать их полные наименования? Не -А, а --after-context и т.д. Думается, что основная причина неиспользования «миллиардов» ключей в утилитах — лень их запоминать. Я вот их все не помню, но примерно знаю, что какая-то утилита что-то умеет и могу найти это. Полные ключики могут оставить в памяти человечей больший семантический отпечаток, нежели короткие.

Оптимизация — корень всех зол. Конечно, когда у нас гига-бега-мега файл, есть смысл использовать ключики одной команды. Но вся суть *nix*'а в том, что это — набор утилит, каждая из которых делает только одну функцию.

Прочитать? cat. Посчитать слова/строки? wc. И т.д.

Я считаю, что будущим *nix*'ов должна стать большая пользователе-ориентированность:
* Унификация интерфейсов/ключей/названий утилит
* Способность оболочки оптимизировать, а не перекладывать это на пользователя. Т.е. если будущий дружественный humansh видит что-то типа cat bla | another --blabla, то пусть он сам переделывает это в более оптимальный вариант, убирая cat. Как это будет сделано — нам фиолетово.

ps: Отсутствия комаров и мошек на шашлыках :)
Да, и я в большинстве случаев за разделение. Но иногда мы этим разделением доходим до абсурда и в ущерб производительности и удобству. К слову я как-то тестировал grep content -c file и grep content file | wc -l и grep выиграл почти на порядок. И на тот момент для меня это было принципиально.

Ну а вообще принцип KISS — это тема для отдельной статьи :)
Не повезло вам с претендентами, возможно не там искали, я еще до того как устроился на первую работу помощником программиста уже научился пользоваться половиной команд grep из статьи, и догадывался о всех остальных возможностях, но тогда и с линуксом был знаком около года. Хотя наверное отдельная благодарность пользователю korjik, это он рассказал о чудо grep'е и приучил к редактору vim.
Интересно что там за админы такие в топе крупнейших фрилансерских сайтов, но даже веб-разработчику grep бывает довольно часто полезен. Сам не представляю как бы без него искал те или иные участки кода в запутанных системах имея под рукой только доступ к консоли. В этом плане grep экономит многие часы ручного перелопачивания кода.
Вы знаете… После этой статьи я смотрю на них снисходительнее. Выяснилось, что хабровчане с достаточно высоким рейтингом не знают элементарных основ (U|L)*n+x
Если вы считаете себя знаком Юникса, шелла или командной строки, то почитайте книгу «UNIX. Инструментальные средства» 1999 года.



И поймете, как мало вы знаете :)
Если вы считаете себя знаком Юникса

Я не считаю себя знаком и даже знатоком Юникса. А эту книгу я когда-то купил студентом за свои деньги. Я и сейчас не стесняюсь учиться, иначе будет скучно жить.
Книга у Вас осталась? Содержимое диска куда-нибудь выложить можете? А то я в продаже найти не могу.
Нет, книга была подарена лет 10 назад, а судьбы диска не помню.
В некоторых украинских интернет магазинов еще есть.
Спасибо. Просто купил оригинал у О'Рейлли. Причем третье издание.
А можно ссылочку?
Sign up to leave a comment.

Articles