находить и отображать имена файлов только с найденным шаблоном

16

Я много использовал это, улучшение, которого я пытаюсь достичь, - это избегать имен эхо-файлов, которые не совпадают в grep. Лучший способ сделать это?

    for file in `find . -name "*.py"`; do echo $file; grep something $file; done
шайка
источник

Ответы:

24
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 и его производных).

Стефан Шазелас
источник
6

Если вы используете 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если вам нужны более продвинутые предикаты.

Тоби Спейт
источник
1
В зависимости от версии GNU grep, grepможет или не может заглянуть внутрь символических ссылок или пройти символические ссылки на каталоги. Вы также можете найти некоторые вариации в обработке других типов нестандартных файлов.
Стефан
5

Вы можете указать 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
rollstuhlfahrer
источник
1

Вы можете попробовать что-то вроде:

find . -name "*.py:" -exec grep -l {} \;

Эта команда exec grep для каждого файла, обнаруженного командой find и ее стандартной функцией find

Ромео Нинов
источник
1

Используйте -lаргумент.

for file in `find . -name "*.py"`; do grep -l something $file && grep something $file; done

Более находчивое использование будет:

for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done
kmkaplan
источник
1

Существуют 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) {
...

Я не могу показать вам здесь, но результат аккуратно раскрашен. Я получаю имена файлов оливково-зеленого цвета, номера строк - золотисто-желтого цвета, а соответствующие фрагменты в каждой строке - кроваво-красного цвета. Цвета настраиваются, хотя.

Йол
источник