
Я хочу рекурсивно найти файлы в моем исходном дереве по содержимому. Я попробовал следующее с помощью grep:
$ grep -rn printf | grep %s | grep bcm_errmsg\(rv\)
Это возвращает мне каждую строку, как я и хотел, но теперь я хотел бы получить имя файла для каждого совпадающего файла, поэтому я изменил это на:
$ grep -rn printf | grep %s | grep -l bcm_errmsg\(rv\)
но вместо того, чтобы печатать имена файлов, я получаю только
(standard input)
выводится на stdout. Как мне это исправить, чтобы получить каждое имя файла и путь (для использования sed
в нем)?
Что я хочу сделать: найти все файлы со printf
строками, которые также содержат %s
и , bcm_errmsg(rv)
а затем применить следующую команду sed к найденным файлам:
sed -i 's/%s/%d/g; s/bcm_errmsg(rv)/rv/g;'
решение1
Я думаю, вы слишком усложняете. Чтобы найти строку foo
во всех файлах, расположенных в текущем каталоге и подкаталогах, просто запустите
grep -r "foo" *
По умолчанию grep выводит совпадающую строку, к которой добавляется имя файла, в котором она была найдена.
Следующий код вместо этого выведет только имя файла без соответствующей строки:
grep -rl "foo" *
решение2
Следуя первоначальной идее @steeldriver, вы можете сделать:
egrep -rl '.*printf.*%s.*bcm_errmsg\(rv\).*' . | xargs -d '\n' sed -i '/printf/ s/%s/%d/; /printf/ s/bcm_errmsg(rv)/rv/'
решение3
grep -rlZP '(?=.*printf)(?=.*%s)(?=.*bcm_errstr\(rv\))' . |
xargs -r0 sed -i -e '
/%s/!b
/printf/!b
/bcm_errstr(rv)/!b
s/%s/%d/g;s/bcm_errstr(rv)/rv/g
'
Сначала мы запускаем рекурсивный dir. из текущего dir, который сканирует файлы, которые содержат строки: printf, %s и bcm_errstr(rv) на одной строке, но, возможно, в любом порядке. Параметры, grep
которые помогают нам это сделать, следующие:
-r
=> рекурсивно запустит все файлы в текущем каталоге и ниже.-l
=> выведет список имен файлов, соответствующих критериям, а именно, все 3 строки на одной строке.-Z
=> выбранные имена файлов разделены нулем (\0) вместо обычного символа новой строки (\n), поэтому мы можем работать с любыми именами файлов.-P
=> включить механизм регулярных выражений Perl, с помощью которого мы можем использовать опережающий просмотр для определения того, находятся ли три строки в одной строке.
На другой стороне канала, xargs
ожидает получения имен файлов, разделенных \0. Затем он передает все эти имена файлов, насколько это возможно, в командную строку sed. Команда sed, которую вы уже знаете из вашего предыдущего вопроса, где она выполняет подпрограммы. только на тех строках, которые содержат 3 строки в одной строке.