【问题标题】:How do I write a bash alias/function to grep all files in all subdirectories for a string?如何编写 bash 别名/函数来 grep 字符串的所有子目录中的所有文件?
【发布时间】:2009-05-29 04:05:43
【问题描述】:

我一直在使用以下命令在我当前目录及其下方的所有 python 源文件中查找字符串:

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

我想简化一些事情,以便我可以输入类似的内容

findpy <string>

并得到完全相同的结果。别名似乎不够用,因为它们只进行字符串扩展,而且我需要指定的参数不是最后一个参数。听起来功能适合这项任务,所以我有几个问题:

  • 我该怎么写?
  • 我应该把它放在哪里?

【问题讨论】:

    标签: bash shell grep


    【解决方案1】:

    如果你不想为此创建一个完整的脚本,你可以只用一个 shell 函数来完成:

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

    ...但是您可能必须在 ~/.bashrc 和 ~/.bash_profile 中定义它,因此它被定义为登录和交互式 shell(请参阅 bash 手册页的 INVOCATION 部分)。

    【讨论】:

    • 我的发行版设置了 .bash_profile 采取的唯一操作是获取 .bashrc,所以这不是问题。谢谢!
    • 函数和别名应该放在 ~/.bashrc 和 ~/.bash_profile 或 ~/.profile 应该源 ~/.bashrc
    • 是的,从另一个采购一个让生活更轻松。为了安全起见,我首先检查 .bash_profile,如下所示: if [ -f ~/.bashrc ];然后 。 ~/.bashrc;菲
    【解决方案2】:

    上面所有的“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

    【讨论】:

    • time sh -c 'find . -name *.cpp -type f -exec grep foo {} + >/dev/null' 比较?对我来说,它比 xargs 快一点,但是 xargs 在一些名称中有空格的 Python 文件上给了我一些“没有这样的文件或目录错误”(感谢 cmu)。 -exec 版本没有抱怨。
    • 使用“-exec ... +”在性能上应该等同于xargs,但它的便携性和灵活性不如xargs。通过将 -print0 传递给 find 并将 -0 传递给 args 可以轻松处理文件名中的空格,因此文件名由 NUL 字符而不是空格分隔,即“find -name *.cpp -print0 | xargs -0 grep foo”。
    • 实际上,我刚刚检查了“-exec ... +”在 POSIX 中,因此它可以被认为是可移植的。剩下的只是灵活性作为 xargs 的论据 :-)
    • 我发现了一些外来文件名(包含“:”字符)的问题。将其更改为以下内容:查找 . -type f -name *.py -print0|xargs --null grep -nHr "$1"
    【解决方案3】:

    顺便说一句,您应该查看Ack 以了解您在做什么。它旨在替代用 Perl 编写的 Grep。根据目标语言过滤文件或忽略 .svn 目录等。

    示例(来自 Trac 源的 sn-p):

    $ 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'
    

    【讨论】:

      【解决方案4】:

      我想要类似的东西,answer by Idelic 提醒了xargs 的一个不错的功能:它将命令放在最后。你看,我的问题是我想写一个“接受参数”的 shell 别名(真的,它会扩展为允许我传递参数grep)。

      这是我在bash_aliases 中添加的内容:

      别名 findpy="find . -type f -name '*.py' | xargs grep"

      这样,我可以编写 findpy WORDfindpy -e REGEXfindpy -il WORD - 关键是可以使用任何 grep 命令行选项。

      【讨论】:

        【解决方案5】:

        将以下三行放入名为findpy的文件中

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

        然后说

        chmod u+x findpy
        

        我通常在我的主目录中有一个名为 bin 的目录,我在其中放置了这样的小 shell 脚本。确保将目录添加到您的PATH

        【讨论】:

          【解决方案6】:

          脚本:

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

          我会怎么做。

          您使用像vim 这样的编辑器编写它,然后将它放在您的路径上的某个位置。我通常的做法是拥有一个~/bin 目录并确保我的.profile 文件(或同等文件)包含:

          PATH=$PATH:~/bin
          

          【讨论】:

          • 我认为你的 grep 上不需要 -r ;-)
          【解决方案7】:

          许多版本的 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"
          

          应该可以。

          【讨论】:

          • 在我的系统上,find 比 grep --recursive 快。此外, grep --recursive 在某些情况下 find 不返回“递归目录循环”错误。
          • 有趣!我从来没有遇到过“递归目录循环”,因为我通常在没有真正符号链接的 Windows 机器上运行。我想这就是你得到那个错误的原因?
          【解决方案8】:

          将以下行添加到您的 ~/.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'
          

          【讨论】:

            【解决方案9】:
            #######################################################################################
            #
            # 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'
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-03-15
              • 2023-04-06
              • 1970-01-01
              • 2016-07-06
              • 2012-11-05
              • 2018-01-29
              • 2021-06-23
              • 1970-01-01
              相关资源
              最近更新 更多