find+egrep
Модераторы: /dev/random, Модераторы разделов
-
Grih65kop
- Сообщения: 145
find+egrep
Задача: найти 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, не вышло. Может быть есть более логичный, адекватный вариант под мою задачу. Прошу помощи.
Я знаю как это сделать по отдельности:
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
Код: Выделить всё
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.
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
-
Grih65kop
- Сообщения: 145
Re: find+egrep
SLEDopit писал(а): ↑13.04.2010 01:21Код: Выделить всё
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
Код: Выделить всё
find -maxdepth 3 -type f -name '*.php' | xargs egrep -H -A 5 -n --color=always 'system\(|eval\('Мои розовые очки
Спасибо сказали:
-
Grih65kop
- Сообщения: 145
Re: find+egrep
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
Код: Выделить всё
find -maxdepth 3 -type f -name '*.php' | wc -lКод: Выделить всё
find -maxdepth 3 -type f -name '*.php' | xargs egrep -l 'system\(|eval\(' | wc -lМои розовые очки
-
kirikaza
- Сообщения: 6
- ОС: Gentoo GNU/Linux
Re: find+egrep
И всё ж таки не фантастика!как вывести найденое общее число 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
Единственное примечание ко всему, что выше, так это то, как можно склеивать строки.
Вместо
можно это сделать несколько проще:
Однако тут две программы запускаются, а у вас одна, так что sed здесь потенциально быстрее.
А вот аналогичный вариант на awk:
и быстро и выглядит просто.
[+]
Подумал, что изначальную задачу можно решить на awk, пара минут кодинга и готово!
Вместо
Код: Выделить всё
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
медленнее. я проверял.
впрочем и вариант на sed можно улучшить, например так:
Код: Выделить всё
#!/bin/sed -f
N
s/\n/ /-
watashiwa_daredeska
- Бывший модератор
- Сообщения: 4038
- Статус: Искусственный интеллект (pre-alpha)
- ОС: Debian GNU/Linux
-
kirikaza
- Сообщения: 6
- ОС: Gentoo GNU/Linux
Re: find+egrep
Да, действительно через tr можно... я и забыл!
Великолепно! Всего два колеса -- а ездит! Молодец awk! Надо будет с ним познакомиться поближе.Код: Выделить всё
alias cmd1="find -maxdepth 3 -type f -name '*.php'" cmd1 | awk '/system\(|eval\(/{print; ++num} END{print num"/"NR}'
Э да... тогда разве что egrep -c отдельно использовать... но это лишний раз считать.watashiwa_daredeska писал(а): ↑14.04.2010 15:51Э нет, батенька. С egrep -A 5 в cmd2 будет полная фигня.Код: Выделить всё
cmd1 | tee >(wc -l >&2) | cmd2 | tee >(wc -l >&2)