Я много использовал это, улучшение, которого я пытаюсь достичь, - это избегать имен эхо-файлов, которые не совпадают в grep. Лучший способ сделать это?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
Я много использовал это, улучшение, которого я пытаюсь достичь, - это избегать имен эхо-файлов, которые не совпадают в grep. Лучший способ сделать это?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
Ответы:
find . -name '*.py' -exec grep something {} \; -print
напечатает имя файла после соответствующих строк.
find . -name '*.py' -exec grep something /dev/null {} +
будет печатать имя файла перед каждой соответствующей строкой (мы добавляем /dev/null
для случая, когда есть только один соответствующий файл, поскольку grep
он не печатает имя файла, если передается только один файл для просмотра. В реализации GNU grep
есть -H
опция для этого как альтернатива).
find . -name '*.py' -exec grep -l something {} +
будет печатать только имена файлов, которые имеют хотя бы одну совпадающую строку.
Чтобы напечатать имя файла перед соответствующими строками, вы можете использовать вместо этого awk:
find . -name '*.py' -exec awk '
FNR == 1 {filename_printed = 0}
/something/ {
if (!filename_printed) {
print FILENAME
filename_printed = 1
}
print
}' {} +
Или вызовите grep
дважды для каждого файла - хотя это было бы менее эффективно, так как при этом выполнялась бы как минимум одна grep
команда и до двух для каждого файла (и дважды читалось содержимое файла):
find . -name '*.py' -exec grep -l something {} \; \
-exec grep something {} \;
В любом случае, вы не хотите зацикливаться на выводе find
подобного, и не забывайте заключать в кавычки ваши переменные .
Если вы хотите использовать цикл оболочки с инструментами GNU:
find . -name '*.py' -exec grep -l --null something {} + |
xargs -r0 sh -c '
for file do
printf "%s\n" "$file"
grep something < "$file"
done' sh
(также работает на FreeBSD и его производных).
Если вы используете GNU grep, вы можете использовать его -r
или --recursive
опцию, чтобы сделать этот простой поиск для вас:
grep -r --include '*.py' -le "$regexp" ./ # for filenames only
grep -r --include '*.py' -He "$regexp" ./ # for filenames on each match
Вам нужно только find
если вам нужны более продвинутые предикаты.
grep
, grep
может или не может заглянуть внутрь символических ссылок или пройти символические ссылки на каталоги. Вы также можете найти некоторые вариации в обработке других типов нестандартных файлов.
Вы можете указать grep включить имя файла в вывод. Так что, если есть совпадение, оно будет показано на консоли; если в файле нет совпадений, для этого файла не будет напечатано ни одной строки.
find . -name "*.py" | xargs grep -n -H something
Из man grep
:
-H Always print filename headers with output lines
-n, --line-number
Each output line is preceded by its relative line number in the file, starting at line 1. The line number counter is reset for each file processed.
This option is ignored if -c, -L, -l, or -q is specified.
Если в ваших файлах могут быть имена с пробелами, вам нужно переключить канал, чтобы использовать символы NUL в качестве разделителя. Полная команда теперь будет выглядеть так:
find . -name "*.py" -print0 | xargs -0 grep -n -H something
Вы можете попробовать что-то вроде:
find . -name "*.py:" -exec grep -l {} \;
Эта команда exec grep для каждого файла, обнаруженного командой find и ее стандартной функцией find
Существуют grep
альтернативы, которые по умолчанию выводят свои результаты в нужном формате. 2 самых популярных из них, которые я знаю ag
(ака "серебряный искатель") и ack
. ag
рекламируется как более быстрая альтернатива ack
.
$ ag '^\w+\s*\w+\(' ~/build/i3/src
build/i3/src/display_version.c
58:void display_running_version(void) {
build/i3/src/load_layout.c
42:static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings =
518:json_content_t json_determine_content(const char *filename) {
575:void tree_append_json(Con *con, const char *filename, char **errormsg) {
build/i3/src/x.c
64:CIRCLEQ_HEAD(state_head, con_state) state_head =
67:CIRCLEQ_HEAD(old_state_head, con_state) old_state_head =
70:TAILQ_HEAD(initial_mapping_head, con_state) initial_mapping_head =
97:void x_con_init(Con *con, uint16_t depth) {
...
Я не могу показать вам здесь, но результат аккуратно раскрашен. Я получаю имена файлов оливково-зеленого цвета, номера строк - золотисто-желтого цвета, а соответствующие фрагменты в каждой строке - кроваво-красного цвета. Цвета настраиваются, хотя.