Как мне написать псевдоним / функцию bash для grep всех файлов во всех подкаталогах для строки? - PullRequest
3 голосов
/ 29 мая 2009

Я использовал следующую команду для поиска строки во всех исходных файлах python в моем текущем каталоге и под ним:

find . -name '*.py' -exec grep -nHr <string> {} \;

Я хотел бы упростить вещи, чтобы я мог просто напечатать что-то вроде

findpy <string>

И получите точно такой же результат. Псевдонимы не кажутся достаточными, так как они только раскрывают строку, и аргумент, который мне нужно указать, не последний аргумент. Похоже, функции подходят для этой задачи, поэтому у меня есть несколько вопросов:

  • Как мне написать это?
  • Куда мне его положить?

Ответы [ 9 ]

10 голосов
/ 29 мая 2009

Если вы не хотите создавать целый сценарий для этого, вы можете сделать это только с помощью функции оболочки:

findpy() { find . -name '*.py' -exec grep -nHr "$1" {} \; ; }

... но тогда вам, возможно, придется определить его как в ~ / .bashrc, так и в ~ / .bash_profile, поэтому он будет определен как для входа в систему, так и для интерактивных оболочек (см. Раздел «ПРИЗНАНИЕ» на справочной странице bash).

6 голосов
/ 29 мая 2009

На заметку, вы должны взглянуть на Ack за то, что вы делаете. Он предназначен для замены Grep, написанного на Perl. Фильтрация файлов на основе целевого языка или игнорирование каталогов .svn и т.п.

Пример (фрагмент из источника Trac):

$ ack --python foo ./mysource
ticket/tests/wikisyntax.py
139:milestone:foo
144:<a class="missing milestone" href="/milestone/foo" rel="nofollow">milestone:foo</a>

ticket/tests/conversion.py
34:        ticket['foo'] = 'This is a custom field'

ticket/query.py
239:        count_sql = 'SELECT COUNT(*) FROM (' + sql + ') AS foo'
6 голосов
/ 29 мая 2009

Все вышеприведенные решения "find ... -exec" в порядке в том смысле, что они работают, но они ужасно неэффективны и будут чрезвычайно медленными для больших деревьев. Причина в том, что они запускают новый процесс для каждого одного * .py файла. Вместо этого используйте xargs (1) и запускайте grep только для файлов (не каталогов):

#! /bin/sh
find . -name \*.py -type f | xargs grep -nHr "$1"

Например:

$ time sh -c 'find . -name \*.cpp -type f -exec grep foo {} \; >/dev/null'
real    0m3.747s
$ time sh -c 'find . -name \*.cpp -type f | xargs grep foo >/dev/null'
real    0m0.278s
2 голосов
/ 13 июня 2013

Я хотел что-то подобное, и ответ от Idelic напомнил одну из приятных особенностей xargs: она ставит команду в конце. Видите ли, моя проблема заключалась в том, что я хотел написать псевдоним оболочки, который будет "принимать параметры" (на самом деле, он будет расширяться таким образом, чтобы позволить мне передавать параметр так grep).

Вот что я добавил к своему bash_aliases:

alias findpy = "find. -Type f -name '* .py' | xargs grep"

Таким образом, я мог бы написать findpy WORD или findpy -e REGEX или findpy -il WORD - точка, которая может использовать любой параметр командной строки grep.

1 голос
/ 25 сентября 2013

Добавьте следующую строку в ~ / .bashrc или ~ / .bash_profile или ~ / .profile

alias findpy='find . -type f -name "*.py" -print0 | xargs -0 grep'

тогда вы можете использовать это так

findpy def

или с опциями grep

findpy -i class

следующий псевдоним будет игнорировать мета-каталог управления версиями git и svn

alias findpy='find . -type f -not -path "*/.git/*" -a -not -path "*/.svn/*" -name "*.py" -print0 | xargs -0 grep'
1 голос
/ 30 мая 2009

Многие версии grep имеют опции для рекурсии, указания шаблона имени файла и т. Д.

grep --perl-regexp --recursive --include='*.py' --regexp="$1" .

Это повторяется, начиная с текущего каталога (.), Просматривает только файлы, заканчивающиеся на 'py', использует регулярные выражения в стиле Perl.

Если ваша версия grep не поддерживает --recursive и --include, то вы все равно можете использовать find и xargs, но не забудьте разрешить имена путей со встроенными пробелами, используя аргумент -print0 для поиска и -null опция для xargs, чтобы справиться с этим.

find . -type f -name '*.py' -print0 | xargs --null grep "$1"

должно работать.

1 голос
/ 29 мая 2009

Сценарий:

#!/bin/bash
find . -name '*.py' -exec grep -nHr "$1" {} ';'

это то, как я бы это сделал.

Вы пишете это с помощью редактора, подобного vim, и помещаете его куда-нибудь на свой путь. Мой обычный подход - иметь каталог ~/bin и убедиться, что мой файл .profile (или его эквивалент) содержит:

PATH=$PATH:~/bin
1 голос
/ 29 мая 2009

Поместите следующие три строки в файл с именем findpy

#!/bin/bash

find . -name '*.py' -exec grep -nHr $1 {} \;

Тогда скажи

chmod u+x findpy

У меня обычно есть каталог с именем bin в моей домашней директории, куда я помещаю маленькие скрипты оболочки, подобные этой. Обязательно добавьте каталог в ваш PATH.

0 голосов
/ 22 июля 2013
#######################################################################################
#
# Function to search all files (including sub-directories) that match a given file
# extension ($2) looking for an indicated string ($1) - in a case insensitive manner.
#
# For Example:
#
# -> findfile AllowNegativePayments cpp
#
#
#######################################################################################
findfile ()
{
    find . -iname "*.$2*" -type f -print0 | xargs -0 grep -i "$1" {} \; 2> /dev/nul
}

alias _ff='findfile'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...