Какая команда grep будет включать текущее имя функции в свой вывод?

Я запускаю 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;

Ответы

Ответ 1

В GNU grep нет такой функции, хотя в прошлом она обсуждалась .

Однако, если ваш код находится под управлением git, git grep имеет опцию -p, которая сделает это.

Ответ 2

Ну вот:

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

Тебе просто нужен мерзавец. Разыскиваемые файлы не обязательно должны быть частью git-репо. Но если они есть, то опустите --no-index и получите мгновенный прирост скорости!

Ответ 3

Предполагая, что вы ищете foobar:

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

greps для всех функций и всех foobar, затем greps для просто foobar и предыдущих строк - которые будут только foobars и содержащими их функциями.

протестировано на Cygwin на Windows версии

Ответ 4

К сожалению, нет. Эта функция не существует в grep и не существует в ack (которая улучшена с заменой grep).

Я действительно желаю, чтобы это существовало. Это пригодится. Кто-то сделал попытку реализовать его некоторое время назад, но это не похоже, что их патч когда-либо принимался (или когда-либо даже размещался онлайн, странно). Вы можете попробовать отправить его по электронной почте и посмотреть, есть ли у него код и все еще хочет получить возможность показывать функции C в grep.

Вы можете написать регулярное выражение для соответствия функции C, но я уверен, что это был бы один монстр регулярного выражения.

Ответ 5

Я написал файл script для 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 #####

Enjoy.:)

Ответ 6

Как и в большинстве операций обработки текста, это тривиально с 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:]]/). Если это не так, как ваш код написан, просто подкорректируйте его.

Ответ 7

Вот несовершенное решение. Он имеет следующие недостатки:

  • Для этого требуется инструмент под названием ctags
  • Следовательно, он работает для файлов C или любых языков, поддерживаемых ctags, но не более того
  • Он отображает все заголовки функций C, несмотря ни на что. Это самая большая проблема с моей script, вы можете найти способ ее преодолеть.

Я назвал свой script `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

Ответ 8

На самом деле "grep -p" был инструментом в AIX за последние два десятилетия из того, что я могу вспомнить. Это там, и это просто вопрос переноса поведения в новый код.

Однако это грубо, и может понадобиться помощь, чтобы знать, что пустые строки внутри функции не учитываются.

Ответ 9

Вы можете написать script, который grep -v во временный файл, а затем diff -p, который будет с оригиналом. Таким образом, diff найдет строки, удаленные grep (т.е. Строки, которые вы хотите), и вы получите точно такую ​​же функцию.