2011-05-26 10 views
15

Ejecuto diff con la opción -p, por lo que la salida incluirá el nombre de la función donde ocurrió cada cambio. ¿Hay una opción análoga para grep? Si no, ¿qué otro comando podría usar en su lugar?¿Qué comando grep incluirá el nombre de la función actual en su salida?

En lugar de -B para mostrar un número fijo de líneas de contexto que preceden inmediatamente a una coincidencia, me gustaría que la coincidencia sea precedida por una sola línea con la firma de función más reciente, sin embargo, muchas líneas atrás estaban en la archivo. Si la opción Busco eran -p, la producción podría tener este aspecto, por ejemplo:

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

Respuesta

2

Por desgracia, no. Esta característica no existe en grep ni existe en ack (que es una sustitución mejorada de grep).

Realmente me gustaría que esto existiera. Sería útil. Someone did take a shot at implementing it a while back, pero no parece que su parche haya sido aceptado (o incluso alguna vez publicado en línea, extrañamente). Puede tratar de enviarle un correo electrónico y ver si todavía tiene el código y aún desea obtener una opción para mostrar las funciones C en grep.

podría escribir una expresión regular para que coincida con una función C, pero apuesto a que sería un monstruo de una expresión regular.

+0

Podría grep para la firma de su función '|'. Habrá un poco de ruido extra pero obtendrás lo que quieres. –

+0

Por lo que estoy buscando, la expresión regular para que coincida con la firma de una función no debería ser mejor que la que utiliza 'diff', incluso'^\ w. * \ ('Parece hacer un buen trabajo. Pero aplicarlo sin limitarlo al contexto del partido "real" produce * mucho * ruido adicional - Tengo más de 1300 coincidencias en un solo subdirectorio de mi proyecto actual. –

+1

Es una característica que estoy pensando para ack 2.x. –

15

No existe tal función en GNU grep, aunque ha sido discussed en el pasado.

Sin embargo, si su código está bajo el control git, git grep tiene una opción -p que hará eso.

+0

Creo que ya leí esa discusión hace mucho tiempo. Probablemente sea en lo que estaba pensando cuando probé 'grep -p' en la actualidad. Ahora estoy usando Mercurial, pero podría probar con Git para la próxima proyecto. Gracias. –

1

Aquí hay una solución imperfecta. Tiene las siguientes defectos:

  1. Se requiere una herramienta llamada ctags
  2. En consecuencia, funciona para archivos de C, o cualquier idioma que CTags soportes, pero no más allá de eso
  3. que muestra todas las cabeceras de función C, no importa qué. Este es el mayor problema con mi script, es posible que puedas encontrar una manera de superarlo.

Me llama mi script `cgrep.sh', que tiene la siguiente sintaxis:

cgrep.sh search-term files... 

Cgrep.sh funciona apoyándose en ctags para producir una lista de patrones de búsqueda para los encabezados de función. A continuación, podemos buscar tanto los encabezados de función como el término de búsqueda. Sin más preámbulos, aquí es 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

Suponiendo que busca: foobar:

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

greps para todas las funciones y todos los foobar, luego imprime filtros por sólo foobar y las líneas anteriores - que serán solo foobars y las funciones contenedoras. (probado en ubuntu bash)

2

Escribí un script para grep C archivos y mostrar los nombres de las funciones C y la firma junto con los resultados. Basado en 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 ##### 

Enjoy. :)

0

Puede escribir un script que grep -v s en un archivo temporal y luego diff -p s con el original. De esta forma, diff eliminaría las líneas que grep (es decir, las líneas que desea), y obtendría exactamente la misma función que coincide.

2

Al igual que con la mayoría de las operaciones de procesamiento de texto, es trivial con 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; 
-- 

Lo anterior presupone una firma de función es cualquier línea que comienza con una letra (/^[[: alpha:]] /). Si esa no es la forma en que se escribe su código, simplemente ajuste para que se ajuste.

1

En realidad "grep -p" ha sido un elemento fijo en AIX durante las últimas dos décadas por lo que puedo recordar. Es es por ahí, y es solo una cuestión de portar el comportamiento en código nuevo.

Sin embargo, es tosco y es posible que necesite ayuda para saber que las líneas en blanco dentro de una función no cuentan.

Cuestiones relacionadas