2011-05-26 19 views
15

我使用-p選項運行diff,因此輸出將包含發生每次更改的函數的名稱。 grep有沒有類似的選項?如果不是,我可以使用其他命令嗎?什麼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; 

回答

2

不幸的是,沒有。此功能在grep中不存在,也不存在於ack(這是改進grep替代)。

雖然我確實希望這個存在。它會派上用場。 Someone did take a shot at implementing it a while back,但它看起來並不像他們的補丁被接受(或奇怪的是甚至在網上發佈)。您可以嘗試給他發送電子郵件,看看他是否仍然有該代碼,並且仍然希望獲得將C函數顯示爲grep的選項。

可能寫一個正則表達式來匹配C函數,但我敢打賭,這將是一個正則表達式的怪物。

+0

你可以grep你的模式'''函數簽名。會有一些額外的噪音,但你會得到你想要的。 – 2011-05-26 05:49:27

+0

對於我所尋找的,匹配函數簽名的正則表達式不一定要比差異使用的更好 - 即使是'^ \ w。* \('似乎做得很好。但是,將它應用到「真實」匹配的上下文中會產生很多額外的噪音 - 我在當前項目的一個子目錄中有超過1300個匹配項。 – 2011-05-26 06:20:50

+1

這是我正在考慮的一個特性2.x. – 2011-06-07 14:07:18

15

在GNU grep中沒有這樣的功能,雖然它在過去一直是discussed

但是,如果您的代碼是在git的控制下,git grep有一個選項-p將這樣做。

+0

我想我很久以前就已經閱讀過這個討論了,這可能是我今天嘗試'grep -p'時想到的,我現在使用的是Mercurial,但我可能會嘗試使用Git項目,謝謝。 – 2011-05-26 06:08:23

1

這是一個不完美的解決方案。它具有以下缺陷:

  1. 它需要一個叫做ctags
  2. 因此工具,它適用於C文件,或C標籤支持的任何語言,但不能超出該
  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 "[email protected]"       # 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 "[email protected]"   # Grep both headers and search term 
rm tags tags.bak     # Clean up 
2

假設你正在尋找foobar的:

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

裏grep的所有功能和所有foobar的,接着就把剛剛取得foobar過濾器和前行 - 這將只是foobars和包含功能。 (在Ubuntu bash上測試)

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 "[email protected]" | \ 
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 ##### 

享受。 :)

0

你可以寫一個腳本,grep -v s到一個臨時文件,然後diff -p s與原件。這樣diff就會找到grep刪除的行(即你想要的行),你會得到完全相同的函數匹配。

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

上面假定的函數簽名是以字母開頭的任何線(/^[[:阿爾法:]] /)。如果這不是您的代碼編寫方式,只需調整即可。

1

實際上,從我記得的情況來看,「grep -p」在過去的二十年中一直是AIX中的一個工具。它那裏,它只是一個移植在新鮮的代碼中的行爲的問題。

雖然這很粗糙,但可能需要幫助才能知道函數中的空行不計數。

相關問題