Я много использовал это, улучшение, которого я пытаюсь достичь, - это избегать имен эхо-файлов, которые не совпадают в 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) {
...
Я не могу показать вам здесь, но результат аккуратно раскрашен. Я получаю имена файлов оливково-зеленого цвета, номера строк - золотисто-желтого цвета, а соответствующие фрагменты в каждой строке - кроваво-красного цвета. Цвета настраиваются, хотя.