我使用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;
答案 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
替换)。
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)
这是一个不完美的解决方案。它有以下缺点:
ctags
我调用了我的脚本`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
删除的行(即你想要的行),你会得到完全相同的函数匹配。