【问题标题】:What grep command will include the current function name in its output?什么 grep 命令将在其输出中包含当前函数名称?
【发布时间】:2011-09-02 07:15:52
【问题描述】:

我使用-p 选项运行diff,因此输出将包括发生每次更改的函数的名称。 grep 有类似的选项吗?如果没有,我还可以使用什么其他命令?

而不是 -B 来显示紧接在匹配之前的固定数量的上下文行,我希望匹配之前只有一行具有最新的函数签名,不管它后面有多行文件。如果我要查找的选项是 -p,则输出可能如下所示,例如:

$猫foo.c int func1(int x, int y) { 返回 x + y; } int func2(int x, int y, int z) { int tmp = x + y; tmp *= z; 返回 tmp; } $ grep -p -n -e 'return' foo.c 1-int func1(int x, int y) 3:返回 x + y; -- 5-int func2(int x, int y, int z) 9:返回tmp;

【问题讨论】:

    标签: shell grep


    【解决方案1】:

    假设您正在搜索 foobar:

    grep -e "^\w.*[(]" -e foobar *.h *.cpp | grep -B 1 foobar
    

    greps 用于所有函数和所有 foobar,然后 greps 仅用于 foobar 和前面的行 - 这将只是 foobars 和包含的函数。

    在 Windows 版本的 cygwin 上测试

    【讨论】:

    • 这真的很方便。
    • 略通俗易懂:grep -e ^\\w.*\( -e 'return' foo.c | grep -B 1 'return'
    • 8年后回头看,我不知道为什么我没有使用两个-e而不是'or' |。感谢改进的表达方式:)
    【解决方案2】:

    给你:

    git grep --no-index -n -p 'return'
    

    你只需要 git。被搜索的文件不需要是 git repo 的一部分。 但如果是,请忽略 --no-index 并立即获得速度提升!

    【讨论】:

    • 这是一个很好的答案。鉴于我们中的许多人将在我们的机器上使用git,因此该解决方案适用于大多数人。
    【解决方案3】:

    据我回忆,实际上“grep -p”在过去的二十年里一直是 AIX 中的固定装置。它就在那里,只是将行为移植到新代码中的问题。

    不过,这很粗略,可能需要帮助才能知道函数中的空白行不算数。

    【讨论】:

      【解决方案4】:

      与大多数文本处理操作一样,使用 awk 很简单:

      $ awk -v re='return' '/^[[:alpha:]]/{f=FNR"-"$0} $0~re{printf "%s\n%d:%s\n--\n",f,FNR,$0; f="" }' file
      1-int func1(int x, int y)
      3:  return x + y;
      --
      5-int func2(int x, int y, int z)
      9:  return tmp;
      --
      

      以上假设函数签名是任何以字母 (/^[[:alpha:]]/) 开头的行。如果这不是您编写代码的方式,只需调整以适应。

      【讨论】:

      • 确实微不足道!顺便说一句,我如何在// 中排除re
      • 我的意思是忽略注释行中的搜索模式实例。例如//return bla bla bla
      • 没关系。我已经想通了(不值得一个新问题)
      【解决方案5】:

      您可以编写一个脚本,将grep -vs 写入一个临时文件,然后将diff -ps 与原始文件一起写入。这样diff 将找到grep 删除的行(即您想要的行),并且您将获得完全相同的函数匹配。

      【讨论】:

        【解决方案6】:

        我编写了一个脚本来 grep C 文件并显示 C 函数名称和签名以及结果。 基于 ctags。

        #!/bin/bash
        
        #
        # grep_c_code
        #
        # Grep C files and print the results along with the function name and signature.
        # Requires: ctags, gawk, sed, bash, and you probably want grep too.
        #
        # Written by David Stav, December 19 2012.
        #
        # Released to the public domain.
        #
        
        if [ $# -lt 2 ]; then
            echo "Usage: $0 <grep_cmd> <files/dirs...>" >&2
            echo "" >&2
            echo "Example:" >&2
            echo "  $0 'grep --color=always -n -e \"PATTERN\"' file1 file2 dir1 dir2 | less -R" >&2
            exit 1
        fi
        
        GREP_CMD="$1"
        shift
        
        GAWK_SCRIPT="`
        sed -n -e '/^##### START of gawk script #####$/,/^##### END of gawk script #####$/p' \"$0\" | \
        sed -n -e '2,$ { $ D; p}'
        `"
        
        ctags -f - -R --sort=no -n --fields=+afikKmsSzt --extra=+fq "$@" | \
        gawk "$GAWK_SCRIPT" "$GREP_CMD" | \
        bash
        
        exit 0
        
        ##### START of gawk script #####
        function parse_line(a)
        {
            a["tagname"] = $1;
            a["filename"] = $2;
            a["line_number"] = gensub(/^([0-9]+).*$/, "\\1", 1, $3);
            if (a["line_number"] == $3)
            {
                a["line_number"] = "0";
            }
            a["kind"] = gensub(/^.*\tkind:([^\t]+).*$/, "\\1", 1, $0);
            if (a["kind"] == $0)
            {
                a["kind"] = "unknown kind";
            }
            a["signature"] = gensub(/^.*\tsignature:(.*)$/, "\\1", 1, $0);
            if (a["signature"] == $0)
            {
                a["signature"] = "";
            }
        }
        
        function grep_section(a, next_line_number)
        {
            printf("\n");
            printf("\n");
            printf("\n");
            printf("cat '%s' | \\\n", a["filename"]);
            printf("sed -n -e '%s,%sp' | \\\n", a["line_number"], next_line_number);
            printf("%s | \\\n", grep_cmd);
            printf("sed -e '1 i \\\n");
            printf("\\n\\n\\n--\\\n");
            printf("[%s:%s]\\\n", a["filename"], a["line_number"]);
            printf("<%s> %s%s\\\n", a["kind"], a["tagname"], a["signature"]);
            printf("'\n");
        }
        
        BEGIN \
        {
            FS = "\t";
            grep_cmd = ARGV[1];
            ARGV[1] = ""
        }
        
        !/^!/ \
        {
            parse_line(next_line);
            if (a["line_number"])
            {
                next_line_number = next_line["line_number"] - 1;
                grep_section(a, next_line_number);
                delete a;
            }
            for (key in next_line)
            {
                a[key] = next_line[key];
            }
        }
        
        END \
        {
            if (a["line_number"])
            {
                next_line_number = "$";
                grep_section(a, next_line_number);
            }
        }
        ##### END of gawk script #####
        

        享受。 :)

        【讨论】:

          【解决方案7】:

          这是一个不完美的解决方案。它有以下缺陷:

          1. 它需要一个名为ctags 的工具
          2. 因此,它适用于 C 文件或 ctags 支持的任何语言,但不能超出此范围
          3. 无论如何,它都会显示所有 C 函数头。这是我的脚本最大的问题,您也许可以找到解决方法。

          我将我的脚本命名为“cgrep.sh”,其语法如下:

          cgrep.sh search-term files...
          

          Cgrep.sh 依靠ctags 来生成函数头的搜索模式列表。然后我们可以搜索函数头和搜索词。 废话不多说,这里是cgrep.sh:

          #!/bin/sh
          
          # Grep, which includes C function headers
          # cgrep term files*
          
          TERM=$1                             # Save the search term
          shift
          
          ctags "$@"                          # produces the tags file
          sed -i.bak 's:^.*/^:^:;s:/$::' tags # Prepare the tags file for grep
                                              # Original contents is backed up to tags.bak
          grep -f tags -e $TERM "$@"          # Grep both headers and search term
          rm tags tags.bak                    # Clean up
          

          【讨论】:

            【解决方案8】:

            很遗憾,没有。此功能在grep 中不存在,ack 中也不存在(这是对grep 的替换改进)。

            不过,我真的希望这存在。它会派上用场的。 Someone did take a shot at implementing it a while back,但看起来他们的补丁从未被接受(或者甚至从未在网上发布过,奇怪的是)。您可以尝试给他发电子邮件,看看他是否还有代码,并且仍然希望获得将 C 函数显示到 grep 的选项。

            可以编写一个正则表达式来匹配一个 C 函数,但我敢打赌那将是一个正则表达式的怪物。

            【讨论】:

            • 您可以使用 grep 获取您的模式 | 函数签名。会有一些额外的噪音,但你会得到你想要的。
            • 对于我正在寻找的东西,匹配函数签名的正则表达式不必比 diff 使用的那个更好——甚至 ^\w.*\( 似乎做得很好.但是在不将其限制在“真实”匹配的上下文的情况下应用它会产生很多的额外噪音——我当前项目的一个子目录中只有 1300 多个匹配。
            • 这是我正在为 ack 2.x 考虑的一个功能。
            【解决方案9】:

            GNU grep 中没有这样的功能,虽然过去一直是discussed

            但是,如果您的代码在 git 的控制之下,git grep 有一个选项 -p 可以做到这一点。

            【讨论】:

            • 我想我很久以前就读过那个讨论了。这可能是我今天尝试grep -p 时所想的。我现在正在使用 Mercurial,但我可能会在下一个项目中尝试 Git。谢谢。
            猜你喜欢
            • 1970-01-01
            • 2019-07-28
            • 2015-05-01
            • 2013-04-14
            • 1970-01-01
            • 1970-01-01
            • 2019-05-20
            • 1970-01-01
            • 2020-04-04
            相关资源
            最近更新 更多