знаходьте та повторюйте назви файлів лише із знайденим шаблоном


16

Я багато використовував це, поліпшення, якого я намагаюся досягти, - це уникати імен файлів ехо, які не відповідали грепу. Кращий спосіб зробити це?

    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

1

Ви можете спробувати щось на кшталт:

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

Ця команда виконує grep для кожного файлу, виявленого командою 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

1

Є grepальтернативи, які за замовчуванням виводять результати у потрібному форматі. Дві найпопулярніші з них, які я знаю, це 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) {
...

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.