Какая команда grep будет включать текущее имя функции в свой вывод? - PullRequest
20 голосов
/ 26 мая 2011

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

Ответы [ 9 ]

18 голосов
/ 26 мая 2011

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

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

6 голосов
/ 13 сентября 2018

Вот, пожалуйста:

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

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

4 голосов
/ 22 июля 2011

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

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

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

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

2 голосов
/ 12 января 2013

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

2 голосов
/ 19 декабря 2012

Я написал скрипт для 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 #####

Наслаждайтесь. :)

2 голосов
/ 26 мая 2011

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

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

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

1 голос
/ 05 сентября 2013

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

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

1 голос
/ 26 мая 2011

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

  1. Требуется инструмент под названием ctags
  2. Следовательно, он работает для файлов C или любых языков, которые поддерживает ctags, но не более того
  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 "$@"                          # 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
0 голосов
/ 11 января 2013

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...