Shell 哪个grep命令将在其输出中包含当前函数名?

Shell 哪个grep命令将在其输出中包含当前函数名?,shell,grep,Shell,Grep,我使用-p选项运行diff,因此输出将包括发生每个更改的函数的名称。对于grep,是否有类似的选项?如果没有,我可以使用其他什么命令来代替 我不想在匹配之前显示固定数量的上下文行,而是希望在匹配之前只显示一行最新的函数签名,不管文件中有多少行。如果我要查找的选项是-p,则输出可能如下所示,例如: $ cat foo.c int func1(int x, int y) { return x + y; } int func2(int x, int y, int z) { int tmp =

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

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

$ cat foo.c int func1(int x, int y) { return x + y; } int func2(int x, int y, int z) { int tmp = x + y; tmp *= z; return tmp; } $ grep -p -n -e 'return' foo.c 1-int func1(int x, int y) 3: return x + y; -- 5-int func2(int x, int y, int z) 9: return tmp; $cat 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-整数func1(整数x,整数y) 3:返回x+y; -- 5-整数func2(整数x,整数y,整数z) 9:返回tmp;
不幸的是,没有。此功能在
grep
中不存在,在
ack
中也不存在(这是ab改进的
grep
替换)

不过,我真的希望这个存在。它会派上用场的,但看起来他们的补丁从未被接受过(奇怪的是,甚至从未被发布到网上)。你可以试着给他发电子邮件,看看他是否还有代码,是否还想得到一个选项,在
grep
中显示C函数


您可以编写一个正则表达式来匹配一个C函数,但我敢打赌这将是一个巨大的正则表达式。

在GNU grep中没有这样的函数,尽管它已经在过去了


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

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

  • 它需要一个名为
    ctags
  • 因此,它适用于C文件或ctags支持的任何语言,但不能超过这些
  • 它显示所有的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
    

    假设您正在搜索foobar:

    grep -e "^\w.*[(]" -e foobar *.h *.cpp | grep -B 1 foobar
    
    greps表示所有函数和所有foobar,然后greps表示foobar和前面的行,这将只是foobar和包含函数


    在windows版本的cygwin上测试时,我为grep C文件编写了一个脚本,并显示了C函数名和签名以及结果。 基于CTAG

    #!/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 #####
    
    #/bin/bash
    #
    #grep_c_代码
    #
    #Grep C文件并打印结果以及函数名和签名。
    #需要:CTAG、gawk、sed、bash,您可能也需要grep。
    #
    #David Stav撰写,2012年12月19日。
    #
    #发布到公共领域。
    #
    如果[$#-lt 2];然后
    回显“用法:$0”>&2
    回显“”>&2
    echo“示例:”>&2
    echo“$0”grep--color=always-n-e\“PATTERN\”file1 file2 dir1 dir2 | less-R”>&2
    出口1
    fi
    GREP_CMD=“$1”
    转移
    GAWK_脚本=”`
    sed-n-e'/^^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\
    sed-n-e'2,${$D;p}'
    `"
    ctags-f--R--sort=no-n--fields=+afikKmsSzt--extra=+fq“$@”|\
    gawk“$gawk_SCRIPT”“$GREP_CMD”|\
    猛击
    出口0
    #####gawk脚本的开始#####
    函数解析_行(a)
    {
    [“标记名”]=1美元;
    a[“文件名”]=2美元;
    a[“行号”]=gensub(/^([0-9]+).$/,“\\1”,1,$3);
    如果(a[“行号”]==3美元)
    {
    a[“行号”]=“0”;
    }
    a[“种类”]=gensub(/^.*\tkind:([^\t]+).$/,“\\1”,1,$0);
    如果(a[“种类”]==0美元)
    {
    a[“种类”]=“未知种类”;
    }
    a[“签名”]=gensub(/^.*\t签名:(.*)$/,“\\1”,1,$0);
    如果(a[“签名”]==0美元)
    {
    a[“签名”]=“”;
    }
    }
    函数grep_段(a,下一行编号)
    {
    printf(“\n”);
    printf(“\n”);
    printf(“\n”);
    printf(“目录“%s”\\\n”,一个[“文件名]);
    printf(“sed-n-e“%s,%sp'\\\n”,一个[“行号”],下一行号);
    printf(“%s | \\\n”,grep\u cmd);
    printf(“sed-e'1 i\\\n”);
    printf(“\\n\\n\\n--\\n”);
    printf(“[%s:%s]\\\n”、一个[“文件名”]、一个[“行号”]);
    printf(“%s%s\\\n”、一个[“种类”]、一个[“标记名”]、一个[“签名”]);
    printf(“'\n”);
    }
    开始\
    {
    FS=“\t”;
    grep_cmd=ARGV[1];
    ARGV[1]=“”
    }
    !/^!/ \
    {
    解析_行(下一个_行);
    如果(a[“行号”])
    {
    下一行编号=下一行[“行编号”]-1;
    grep_段(a,下一行编号);
    删除一条;
    }
    用于(输入下一行)
    {
    a[键]=下一行[键];
    }
    }
    结束\
    {
    如果(a[“行号”])
    {
    下一行\u编号=“$”;
    grep_段(a,下一行编号);
    }
    }
    #####目瞪口呆脚本结束#####
    

    享受。:)

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

    与大多数文本处理操作一样,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:][]/)开头的任何行。如果您的代码不是这样编写的,只需调整以适应。

    事实上,“grep-p”在过去二十年中一直是AIX中的一个固定选项。它就在那里,只是将行为移植到新代码中的问题

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

    给你:

    git grep --no-index -n -p 'return'
    
    你只需要git。正在搜索的文件不需要是git repo的一部分。 但如果是,则省略
    --无索引
    ,并获得即时速度