我一直在使用以下命令在当前目录及其下方的所有 python 源文件中对字符串进行 grep:
find . -name '*.py' -exec grep -nHr <string> {} \;
我想简化一些事情,这样我就可以输入类似的东西
findpy <string>
并得到完全相同的结果。别名似乎不够用,因为它们只进行字符串扩展,而且我需要指定的参数不是最后一个参数。听起来功能适合这项任务,所以我有几个问题:
- 我该怎么写?
- 我把它放在哪里?
如果您不想为此创建整个脚本,则可以仅使用 shell 函数来完成:
findpy() { find . -name '*.py' -exec grep -nHr "$1" {} \; ; }
...但是您可能必须在 ~/.bashrc 和 ~/.bash_profile 中定义它,因此它会为登录和交互式 shell 定义(参见 bash 手册页的 INVOCATION 部分)。
上面所有的“find ... -exec”解决方案在它们工作的意义上都是可以的,但是它们的效率非常低,并且对于大树来说非常慢。原因是他们为每个*.py 文件启动了一个新进程。相反,使用 xargs(1),并仅对文件(而不是目录)运行 grep:
#!/bin/sh 寻找 。-name \*.py -type f | xargs grep -nHr "$1"
例如:
$ 时间 sh -c '查找 . -name \*.cpp -type f -exec grep foo {} \; >/开发/空' 实际0m3.747s $ 时间 sh -c '查找 . -name \*.cpp -type f | xargs grep foo >/dev/null' 实际0m0.278s
附带说明一下,您应该查看Ack以了解您在做什么。它旨在替代用 Perl 编写的 Grep。根据目标语言过滤文件或忽略 .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'
我想要类似的东西,Idelic 的回答让我想起了 : 的一个很好的特性xargs
:它将命令放在最后。你看,我的问题是我想编写一个“接受参数”的 shell 别名(实际上,它会以这样的方式扩展以允许我传递参数 so grep
)。
这是我添加到我的bash_aliases
:
别名 findpy="find . -type f -name '*.py' | xargs grep"
这样,我可以写findpy WORD
or findpy -e REGEX
or findpy -il WORD
- 关键是可以使用任何grep
命令行选项。
将以下三行放在一个名为findpy
#!/bin/bash
find . -name '*.py' -exec grep -nHr $1 {} \;
然后说
chmod u+x findpy
我通常bin
在我的主目录中有一个名为的目录,我在其中放置了这样的小 shell 脚本。确保将目录添加到您的PATH
.
剧本:
#!/bin/bash
find . -name '*.py' -exec grep -nHr "$1" {} ';'
我会怎么做。
你用一个编辑器写它,vim
然后把它放在你的路径上。我通常的方法是有一个~/bin
目录并确保我的.profile
文件(或等效文件)包含:
PATH=$PATH:~/bin
许多版本的 grep 都有执行递归、指定文件名模式等的选项。
grep --perl-regexp --recursive --include='*.py' --regexp="$1" .
这从当前目录 (.) 开始递归,只查看以 'py' 结尾的文件,使用 Perl 样式的正则表达式。
如果您的 grep 版本不支持 --recursive 和 --include,那么您仍然可以使用 find 和 xargs,但请确保通过使用 find 的 -print0 参数和 --null 选项来允许包含嵌入空格的路径名到 xargs 来处理。
find . -type f -name '*.py' -print0 | xargs --null grep "$1"
应该管用。
将以下行添加到您的 ~/.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'
#######################################################################################
#
# 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'