什么grep命令将在其输出中包含当前函数名称?

时间:2011-05-26 05:15:38

标签: shell grep

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

而不是-B显示紧跟在匹配之前的固定数量的上下文行,我希望匹配前面只有一行具有最新的函数签名,但是很多行都支持它在文件中。如果我正在寻找的选项是-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;

9 个答案:

答案 0 :(得分:18)

GNU grep中没有这样的功能,尽管过去已经discussed

但是,如果您的代码位于git的控制之下,git grep会有一个选项-p来执行此操作。

答案 1 :(得分:6)

您在这里:

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

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

答案 2 :(得分:4)

假设您正在寻找foobar:

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

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

在Windows版本的cygwin上测试

答案 3 :(得分:2)

不幸的是,没有。 grep中不存在此功能,ack中也不存在此功能(更改为grep替换)。

但是,我确实希望这存在。它会派上用场。 Someone did take a shot at implementing it a while back,但看起来他们的补丁看起来没有被接受(或者甚至曾经在线发布过,奇怪的是)。您可以尝试通过电子邮件发送给他,看看他是否仍然拥有代码,并且仍然想要选择将C函数显示为grep

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

答案 4 :(得分:2)

我编写了一个脚本来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 #####

享受。 :)

答案 5 :(得分:2)

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

答案 6 :(得分:1)

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

  1. 它需要一个名为ctags
  2. 的工具
  3. 因此,它适用于C文件或ctags支持的任何语言,但不能超越
  4. 无论如何,它都会显示所有C函数标题。这是我的脚本最大的问题,你或许可以找到克服它的方法。
  5. 我调用了我的脚本`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
    

答案 7 :(得分:1)

实际上,从我记忆中来看,过去二十年来,“grep -p”一直是AIX的固定装置。 就在那里,而这只是在新代码中移植行为的问题。

虽然这很粗糙,但可能需要帮助才能知道函数中的空行不计算在内。

答案 8 :(得分:0)

您可以将grep -v的脚本写入临时文件,然后将diff -p写入原始文件。那样diff会找到grep删除的行(即你想要的行),你会得到完全相同的函数匹配。