What grep command will include the current functio

2019-02-21 07:41发布

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;

标签: shell grep
9条回答
虎瘦雄心在
2楼-- · 2019-02-21 08:16

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.

查看更多
Anthone
3楼-- · 2019-02-21 08:17

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.

查看更多
乱世女痞
4楼-- · 2019-02-21 08:17

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.

查看更多
迷人小祖宗
5楼-- · 2019-02-21 08:18

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.

查看更多
Evening l夕情丶
6楼-- · 2019-02-21 08:20

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. :)

查看更多
时光不老,我们不散
7楼-- · 2019-02-21 08:23

Assuming you are searching for foobar:

grep foobar\\\|^\\w.*\(  *.h *.cpp  | grep -B 1 foobar

greps for all functions and all foobar, then prints filters for just foobar and the preceding lines - which will be only foobars and the containing functions. (tested on ubuntu bash)

查看更多
登录 后发表回答