find+egrep

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Grih65kop
Сообщения: 145

find+egrep

Сообщение Grih65kop »

Задача: найти php файлы, затем пройтись по ним egrep воводя путь, номер строк, и подсвечиваю регулярные выражения.
Я знаю как это сделать по отдельности:

find -maxdepth 3 -type f -name '*.php'
cat 1.php | egrep -R -A 5 -n --color=always 'system\(|eval\(' * | more

Первой строкой нахожу php файлы.
Вторая строка проходит только по 1.php.

Как теперь все это соеденить в одну строчку? Т.е. что бы проходил egrep только в найденых php файлах. Пробывал добавлять параметр -exec для find, не вышло. Может быть есть более логичный, адекватный вариант под мою задачу. Прошу помощи.
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4824
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: find+egrep

Сообщение SLEDopit »

Grih65kop писал(а):
13.04.2010 01:07
Пробывал добавлять параметр -exec для find, не вышло.

Код: Выделить всё

find . -maxdepth 3 -print -name "*php" -exec egrep -A 5 -n --color=always 'php' {} \;
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Grih65kop
Сообщения: 145

Re: find+egrep

Сообщение Grih65kop »

SLEDopit писал(а):
13.04.2010 01:21
Grih65kop писал(а):
13.04.2010 01:07
Пробывал добавлять параметр -exec для find, не вышло.

Код: Выделить всё

find . -maxdepth 3 -print -name "*php" -exec egrep -A 5 -n --color=always 'php' {} \;


К сожалению не подходит, путь показывается у все найденых php файлов, кроме тех где строка присутствует. В моем примере флаг -R выводил путь рядом со строкой если она найдена, сейчас на него нет реакции.
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: find+egrep

Сообщение watashiwa_daredeska »

Код: Выделить всё

find -maxdepth 3 -type f -name '*.php' | xargs egrep -H -A 5 -n --color=always 'system\(|eval\('
Не?
Спасибо сказали:
Grih65kop
Сообщения: 145

Re: find+egrep

Сообщение Grih65kop »

watashiwa_daredeska писал(а):
13.04.2010 01:47

Код: Выделить всё

find -maxdepth 3 -type f -name '*.php' | xargs egrep -H -A 5 -n --color=always 'system\(|eval\('
Не?

В точку. Спасибо всем.
Задумываюсь о том как вывести найденое общее число php файлов и сколько из них подходит под регулярное выражение, 30/5. Это фантастика?
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: find+egrep

Сообщение watashiwa_daredeska »

Grih65kop писал(а):
13.04.2010 09:46
как вывести найденое общее число php файлов

Код: Выделить всё

find -maxdepth 3 -type f -name '*.php' | wc -l


Grih65kop писал(а):
13.04.2010 09:46
сколько из них подходит под регулярное выражение

Код: Выделить всё

find -maxdepth 3 -type f -name '*.php' | xargs egrep -l 'system\(|eval\(' | wc -l

Спасибо сказали:
Аватара пользователя
kirikaza
Сообщения: 6
ОС: Gentoo GNU/Linux

Re: find+egrep

Сообщение kirikaza »

как вывести найденое общее число php файлов и сколько из них подходит под регулярное выражение, 30/5. Это фантастика?
И всё ж таки не фантастика!

Сперва введу сокращения, чтобы запись была покороче:

Код: Выделить всё

alias cmd1="find -maxdepth 3 -type f -name '*.php'"
alias cmd2="xargs egrep -H -A 5 -n --color=always 'system\(|eval\('"

Тогда можно рассматривать

Код: Выделить всё

cmd1 | cmd2

Можно даже заменить команды на более простые для экспериментов. Я сделал так:

Код: Выделить всё

alias cmd1='env'
alias cmd2='grep --colour=always PATH'

Теперь нужно взять подсчитать кол-во строк в выводе cmd1. Для этого можно воспользоваться wc -l. Но при этом вывод cmd1 надо дублировать -- один отправить на wc -l, а другой подать на вход cmd2. К счастью есть команда tee, которая умеет дублировать строки (точнее, умеет выводить их в кучу файлов). А нам-то надо не в файл! Нам надо в программу! Поэтому придётся воспользоваться фичей Bash -- Process Substitution. Подробно она описана в man-странице, суть же в следующем: пишем >(cmd) -- и получаем файл, соответствующий дескриптору для записи, аналогично <(cmd) -- для чтения. Теперь что из этого получается:

Код: Выделить всё

cmd1 | tee >(wc -l >&2) | cmd2

Конструкция >(...) возвращает имя файла вроде /dev/fd/63, запись в который соответствует передаче строк в дескриптор 63, позволяющий писать в пайп, из которого уже читает wc -l; последний уже пишет в stderr (дескриптор 2), чтобы вывод не фильтровался командой cmd2.

Итого имеем на выходе:

Код: Выделить всё

63
MANPATH=
PATH=
...
INFOPATH=

Вот оно число 63! Ура! Теперь делаем такую же магию для cmd2:

Код: Выделить всё

cmd1 | tee >(wc -l >&2) | cmd2 | tee >(wc -l >&2)

Имеем:

Код: Выделить всё

63
MANPATH=
PATH=
...
INFOPATH=
8

Ага, вот и всплыло число 8! Осталось только собрать их вместе. Для этого извлечём весь поток stderr и доработаем напильником (sed-ом):

Код: Выделить всё

{ cmd1 | tee >(wc -l >&2) | cmd2 | tee >(wc -l >&2); } 2> >(sed -n '1h;2{H;g;s|\n|/|;p;q}' >&2)

Имеем:

Код: Выделить всё

MANPATH=
PATH=
...
INFOPATH=
63/8

Та-дам!

Здесь 2> выбирает поток stderr и направляет его опять же на некоторый дескриптор, откуда берёт данные sed, который сохраняет в hold space первую строку (1h), затем принимается за вторую строчку: добавляет к спец. буферу "hold space" (H), вместо текущей строки вставляет содержимое hold space (g), заменяет перенос строки на дробь (s|\n|/|), затем печатает и выходит (p;q). Вывод sed я опять же перенаправил на stderr -- отделил таким образом от полезных данных.

У этого решения есть противопоказания: вывод в stderr каких-то сообщений самими командами будет смешиваться с вычисленными нами значениями, а это может плохо кончиться. Можно, конечно подавить вывод ошибочных сообщений в cmd1 и cmd2, но тогда мы не увидим сообщений об ошибках. Поэтому лучше создать отдельный дескриптор (двунаправленный, вместо stderr). Это можно сделать просто заменив &2 на &3:

Код: Выделить всё

{ cmd1 | tee >(wc -l >&3) | cmd2 | tee >(wc -l >&3); } 3> >(sed -n '1h;2{H;g;s|\n|/|;p;q}' >&2)

С тем же успехом можно воспользоваться значением 4, 5 или 45 -- главное, чтобы были и "входы" (>&3), и "выходы" (3>).

P.S.: занимался сим ради спортивного интереса... но вполне возможно, когда-нибудь и пригодится.
Спасибо сказали:
Аватара пользователя
Luinnar
Сообщения: 246
ОС: Solaris, Debian, Ubuntu

Re: find+egrep

Сообщение Luinnar »

Единственное примечание ко всему, что выше, так это то, как можно склеивать строки.
Вместо

Код: Выделить всё

sed -n '1h;2{H;g;s|\n|/|;p;q}'

можно это сделать несколько проще:

Код: Выделить всё

xargs echo | tr ' ' '/'

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

А вот аналогичный вариант на awk:

Код: Выделить всё

awk '{a[NR]=$0} END{print a[1]"/"a[2]}'

и быстро и выглядит просто.

[+]
Подумал, что изначальную задачу можно решить на awk, пара минут кодинга и готово!

Код: Выделить всё

alias cmd1="find -maxdepth 3 -type f -name '*.php'"
cmd1 | awk '/system\(|eval\(/{print; ++num} END{print num"/"NR}'
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: find+egrep

Сообщение drBatty »

Luinnar писал(а):
14.04.2010 14:54
Однако тут две программы запускаются, а у вас одна, так что sed здесь потенциально быстрее.

медленнее. я проверял.
впрочем и вариант на sed можно улучшить, например так:

Код: Выделить всё

#!/bin/sed -f
N
s/\n/ /
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: find+egrep

Сообщение watashiwa_daredeska »

kirikaza писал(а):
14.04.2010 14:23
cmd1 | tee >(wc -l >&2) | cmd2 | tee >(wc -l >&2)
Э нет, батенька. С egrep -A 5 в cmd2 будет полная фигня.
Спасибо сказали:
Аватара пользователя
kirikaza
Сообщения: 6
ОС: Gentoo GNU/Linux

Re: find+egrep

Сообщение kirikaza »

Luinnar писал(а):
14.04.2010 14:54

Код: Выделить всё

xargs echo | tr ' ' '/'
Да, действительно через tr можно... я и забыл!

Код: Выделить всё

alias cmd1="find -maxdepth 3 -type f -name '*.php'"
cmd1 | awk '/system\(|eval\(/{print; ++num} END{print num"/"NR}'
Великолепно! Всего два колеса -- а ездит! Молодец awk! Надо будет с ним познакомиться поближе.


watashiwa_daredeska писал(а):
14.04.2010 15:51

Код: Выделить всё

cmd1 | tee >(wc -l >&2) | cmd2 | tee >(wc -l >&2)
Э нет, батенька. С egrep -A 5 в cmd2 будет полная фигня.
Э да... тогда разве что egrep -c отдельно использовать... но это лишний раз считать.
Спасибо сказали: