2009-05-29 2 views
3

Я использую следующую команду, чтобы вычленить информацию строки во всех исходных файлах питона в и ниже моем текущем каталоге:Как написать псевдоним/функцию bash для grep всех файлов во всех подкаталогах для строки?

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

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

findpy <string> 

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

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

ответ

10

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

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

... но тогда вы, возможно, придется определить его как в ~/.bashrc и ~/.bash_profile, поэтому он получает определенный для обоих логин и интерактивных оболочек (см раздел призывание человека в Bash страница).

+0

Моя Дистрибутив это настроило, что единственное действие, которое .bash_profile занимает источник .bashrc, поэтому он не является проблемой. Благодаря! – saffsd

+1

функции и aliasses должны идти в ~/.bashrc и ~/.bash_profile или ~/.profile should source ~/.bashrc – lhunath

+0

Yah, поиск одного из другого делает жизнь намного проще. Для безопасности я сначала проверяю свой .bash_profile, например: if [-f ~/.bashrc]; тогда . ~/.bashrc; fi –

1

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

#!/bin/bash 

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

Тогда говорят

chmod u+x findpy 

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

1

Сценарий:

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

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

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

PATH=$PATH:~/bin 
+0

Я не думаю, что вам нужно -r на вашем Grep там ;-) – lhunath

6

Все решения «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 
+0

Как наступает время sh -c 'find. -name \ *. cpp -type f -exec grep foo {} +>/dev/null 'сравнить? Для меня это было немного быстрее, чем xargs, но xargs дал мне некоторые «такие ошибки файла или каталога» на нескольких файлах Python с пробелами в их именах (спасибо cmu). В версиях -exec не жаловались. –

+0

Использование «-exec ... +» должно быть эквивалентно xargs с точки зрения производительности, но оно не переносимо и не так гибко, как xargs.Пробелы в именах файлов могут быть легко обработаны путем передачи -print0 для поиска и -0 в args, поэтому имена файлов ограничены символами NUL вместо пробелов, то есть «find -name \ *. Cpp -print0 | xargs -0 grep foo», – Idelic

+0

На самом деле, я только что проверил, что «-exec ... +» находится в POSIX, поэтому его можно считать переносимым. Это оставляет гибкость в качестве аргумента для xargs :-) – Idelic

6

На стороне записки, вы должны взглянуть на 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' 
1

Многие версии Grep есть варианты, чтобы сделать рекурсию, задающие имя файла шаблона и т.д.

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

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

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

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

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

+0

В моей системе поиск быстрее, чем grep - -recursive. Кроме того, grep -recursive возвращает ошибки «рекурсивного каталога» при некоторых обстоятельствах, когда find не делает. –

+0

Интересно! Я никогда не получал «рекурсивный цикл каталогов», как я обычно запускаю в окне Windows, имеют реальную символическую ссылки. Я предполагаю, что именно так вы получили эту ошибку? –

2

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

Вот что я добавил к моему bash_aliases: "найти -типа е -name '* .py' | xargs Grep"

псевдоним findpy =

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

0
####################################################################################### 
# 
# 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' 
1

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

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

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

findpy def 

или с grep

findpy -i class 

следующее: псевдоним будет игнорировать контроль версий мета-каталог мерзавца и СВН

alias findpy='find . -type f -not -path "*/.git/*" -a -not -path "*/.svn/*" -name "*.py" -print0 | xargs -0 grep'