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

发布于 2024-11-09 15:35:17 字数 511 浏览 2 评论 0原文

我使用 -p 选项运行 diff,因此输出将包含每次更改发生的函数的名称。 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;

I run diff with the -p option so the output will include the name of the function where each change occurred. Is there an analogous option for grep? If not, what other command could I use instead?

Instead of -B to show a fixed number of context lines that immediately precede a match, I'd like for the match to be preceded by just one line with the most recent function signature, however many lines back it was in the file. If the option I'm looking for were -p, output might look like this, for example:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

拍不死你 2024-11-16 15:35:18

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

但是,如果您的代码在 git 的控制之下,则 git grep 有一个选项 -p 可以执行此操作。

There is no such function in GNU grep, although it has been discussed in the past.

However if your code is under git's control, git grep has an option -p that will do that.

一个人的夜不怕黑 2024-11-16 15:35:18

给你:

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

你只需要 git。正在搜索的文件不需要是 git 存储库的一部分。
但如果是的话,请省略 --no-index 并立即获得速度提升!

Here you go:

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

You just need git. The files being searched do not need to be part of a git repo.
But if they are, then omit --no-index and get an instant speed boost!

情泪▽动烟 2024-11-16 15:35:18

假设您正在搜索 foobar:

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

grep 查找所有函数和所有 foobar,然后 grep 查找 foobar 和前面的行 - 这将只是 foobar 和包含的函数。

在 windows 版本的 cygwin 上测试

Assuming you are searching for foobar:

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

greps for all functions and all foobar, then greps for just foobar and the preceding lines - which will be only foobars and the containing functions.

tested on cygwin on windows version

可遇━不可求 2024-11-16 15:35:18

不幸的是,没有。此功能在 grep 中不存在,在 ack 中也不存在(这是改进的 grep 替代品)。

不过,我真的希望这个存在。它会派上用场的。 不久前确实有人尝试过实现它,但看起来他们的补丁并没有被接受(或者甚至没有发布到网上,奇怪的是)。您可以尝试给他发电子邮件,看看他是否仍然有代码,并且仍然希望获得在 grep 中显示 C 函数的选项。

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

Unfortunately, no. This feature does not exist in grep nor does it exist in ack (which is ab improved grep replacement).

I really do wish this existed, though. It would come in handy. Someone did take a shot at implementing it a while back, but it doesn't look like their patch ever got accepted (or was ever even posted online, strangely). You can try emailing him and see if he still has the code and still wants to get an option to show C functions into grep.

You could write a regular expression to match a C function, but I bet that'd be one monster of a regexp.

只等公子 2024-11-16 15:35:18

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

享受。 :)

I wrote a script to grep C files and show the C function names and signature along with the results.
Based on 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 #####

Enjoy. :)

心头的小情儿 2024-11-16 15:35:18

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

As with most text processing operations, it's trivial with 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;
--

The above assumes a function signature is any line that starts with a letter (/^[[:alpha:]]/). If that's not the way your code is written, just tweak to suit.

や三分注定 2024-11-16 15:35:18

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

  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

Here is an imperfect solution. It has the following flaws:

  1. It requires a tool called ctags
  2. Consequently, it works for C files, or any languages that ctags supports, but not beyond that
  3. It displays all C function headers, no matter what. This is the biggest problem with my script, you might be able to find a way to overcome it.

I called my script `cgrep.sh', which has the following syntax:

cgrep.sh search-term files...

Cgrep.sh works by relying on ctags to produce a list of search patterns for function headers. We can then search for both the function headers and the search term.
Without further ado, here is 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
演出会有结束 2024-11-16 15:35:18

事实上,据我所知,“grep -p”在过去二十年里一直是 AIX 中的固定装置。它就在那里,只需将行为移植到新代码中即可。

不过,这很粗糙,并且可能需要帮助才能知道函数中的空行不算在内。

Actually "grep -p" has been a fixture in AIX for the last two decades from what I can recall. It is out there, and it's just a matter of porting the behaviour over in fresh code.

It's crude, though, and may need help to know that blank lines within a function don't count.

甜尕妞 2024-11-16 15:35:18

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

You could write a script that grep -vs into a temporary file and then diff -ps that with the original. That way diff would find the lines that grep removed (i.e. the lines that you want), and you would get the exact same function matching.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文