Grep персонажей до и после матча?

144

Используя это:

grep -A1 -B1 "test_pattern" file

выдаст одну строку до и после сопоставленного шаблона в файле. Есть ли способ отображать не строки, а указанное количество символов?

Строки в моем файле довольно большие, поэтому я не заинтересован в печати всей строки, а просто наблюдаю за совпадением в контексте. Любые предложения о том, как это сделать?

легенда
источник
1
Дубликат unix.stackexchange.com/q/163726 Почти копия дубликата stackoverflow.com/q/2034799
sondra.kinsey

Ответы:

184

3 символа до и 4 символа после

$> echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}'
23_string_and
ДМИТРИЙ МАЛИКОВ
источник
5
Хороший ответ для небольших объемов данных, но он начинает замедляться, когда вы сопоставляете> 100 символов - например, в моем гигантском XML-файле я хочу {1200} до и после, и он слишком медленный для использования.
Benubird
3
Версия awk от @amit_g намного быстрее.
ssobczak
6
Недоступно в Mac OSX, поэтому на самом деле это не широко доступное решение. Версия -E (указанная ниже) является лучшим решением. Что такое -P? Читайте дальше ... -P, --perl-regexp Интерпретировать PATTERN как регулярное выражение Perl (PCRE, см. Ниже). Это очень экспериментально, и grep -P может предупредить о невыполненных функциях.
Xofo
2
На OSX установите через: brew install homebrew/dupes/grepи запустите его как ggrep.
Кенорб
1
Как подразумевает @Benubird, это будет невозможно с точки зрения производительности для огромных файлов с умеренно широким окружением, требуемым для цели совпадения.
matanster
113
grep -E -o ".{0,5}test_pattern.{0,5}" test.txt 

Это будет соответствовать до 5 символов до и после вашего шаблона. Ключ -o указывает grep показывать только совпадение, а -E использовать расширенное регулярное выражение. Обязательно поместите кавычки вокруг вашего выражения, иначе оно может быть интерпретировано оболочкой.

ekse
источник
1
Хороший ответ, интересно , что он ограничен в 2 ^ 8-1 длиной в {} так {0,255}работах {0,256}даетgrep: invalid repetition count(s)
CodeMonkey
Это, кажется, становится значительно менее производительным, когда я увеличиваю количество совпадающих символов (5 -> 25 -> 50), есть идеи, почему?
Адам Хьюз
37

Вы могли бы использовать

awk '/test_pattern/ {
    match($0, /test_pattern/); print substr($0, RSTART - 10, RLENGTH + 20);
}' file
amit_g
источник
2
Хорошо работает даже с немного большими файлами
Touko
4
как вы можете использовать это, чтобы найти несколько совпадений в строке?
koox00
1
Каково значение первого числа в парах в фигурных скобках? Как 0 в "grep -E -o". {0,5} test_pattern. {0,5} "test.txt"?
Лью
Это действительно быстрее, но не так точно, как ответ @ ekse.
Абдолла
24

Вы имеете в виду, как это:

grep -o '.\{0,20\}test_pattern.\{0,20\}' file

?

Это напечатает до двадцати символов по обе стороны от test_pattern. \{0,20\}Обозначения как *, но указывает , от нуля до двадцати повторений вместо нуля или more.The -oговорит , чтобы показать только сам матч, а не всей линии.

ruakh
источник
Эта команда не работает для меня:grep: Invalid content of \{\}
Александр Правдин
0

С помощью gawkвы можете использовать функцию соответствия:

    x="hey there how are you"
    echo "$x" |awk --re-interval '{match($0,/(.{4})how(.{4})/,a);print a[1],a[2]}'
    ere   are

Если с вами все в порядке perl, более гибкое решение: «Далее» напечатает три символа перед шаблоном, затем реальный шаблон и затем 5 символов после шаблона.

echo hey there how are you |perl -lne 'print "$1$2$3" if /(.{3})(there)(.{5})/'
ey there how

Это также может быть применено к словам, а не только к символам. Следующие будут печатать одно слово перед фактической соответствующей строкой.

echo hey there how are you |perl -lne 'print $1 if /(\w+) there/'
hey

Далее будет напечатано одно слово после шаблона:

echo hey there how are you |perl -lne 'print $2 if /(\w+) there (\w+)/'
how

Далее будет напечатано одно слово перед шаблоном, затем фактическое слово, а затем одно слово после шаблона:

echo hey there how are you |perl -lne 'print "$1$2$3" if /(\w+)( there )(\w+)/'
hey there how
П....
источник
0

Вы можете использовать регулярное выражение grep для поиска + второй grep для выделения

echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}' | grep string

23_string_and

введите описание изображения здесь

Андрей Жилин
источник
0

Я никогда не запомню эти загадочные модификаторы команд, поэтому я взял главный ответ и превратил его в функцию в моем ~/.bashrcфайле:


cgrep() {
    # For files that are arrays 10's of thousands of characters print.
    # Use cpgrep to print 30 characters before and after search patttern.
    if [ $# -eq 2 ] ; then
        # Format was 'cgrep "search string" /path/to/filename'
        grep -o -P ".{0,30}$1.{0,30}" "$2"
    else
        # Format was 'cat /path/to/filename | cgrep "search string"
        grep -o -P ".{0,30}$1.{0,30}"
    fi
} # cgrep()

Вот как это выглядит в действии:

$ ll /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

-rw-r--r-- 1 rick rick 25780 Jul  3 19:05 /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

$ cat /tmp/rick/scp.Mf7UdS/Mf7UdS.Source | cgrep "Link to iconic"

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

$ cgrep "Link to iconic" /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

Файл, о котором идет речь, представляет собой одну непрерывную строку 25 КБ, и безнадежно найти то, что вы ищете, используя обычные grep.

Обратите внимание на два разных способа вызова cgrepэтого grepметода параллелей .

Существует «более изящный» способ создания функции, где «2» передается только при установке, что позволяет сохранить 4 строки кода. У меня это не удобно, хотя. Нечто подобное ${parm2} $parm2. Если я найду его, я пересмотрю функцию и этот ответ.

WinEunuuchs2Unix
источник