Я багато використовував це, поліпшення, якого я намагаюся досягти, - це уникати імен файлів ехо, які не відповідали грепу. Кращий спосіб зробити це?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
Я багато використовував це, поліпшення, якого я намагаюся досягти, - це уникати імен файлів ехо, які не відповідали грепу. Кращий спосіб зробити це?
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 {} \;
Ця команда виконує grep для кожного файлу, виявленого командою find та стандартною функцією пошуку команди
Є 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) {
...
Я не можу вам тут показати, але вихід акуратно кольоровий. Я отримую найменування оливково-зеленого кольору, рядки - золотисто-жовтого кольору, а зібраний фрагмент у кожному рядку - червоно-червоним. Кольори можна налаштувати, хоча.