Как обрезать длинные совпадающие строки, возвращаемые grep или ack

Я хочу запустить ack или grep для файлов HTML, которые часто имеют очень длинные строки. Я не хочу видеть очень длинные строки, которые многократно переносятся. Но я хочу видеть только ту часть длинной строки, которая окружает строку, соответствующую регулярному выражению. Как я могу получить это, используя любую комбинацию инструментов Unix?


person dan    schedule 09.01.2010    source источник
comment
Что такое ack? Это команда, которую вы используете, когда вам что-то не нравится? Что-то вроде ack file_with_long_lines | grep pattern? :-)   -  person Alok Singhal    schedule 09.01.2010
comment
@Alok ack (известный как ack-grep в Debian) grep на стероидах. У него также есть опция --thpppt (не шучу). betterthangrep.com   -  person ZoogieZork    schedule 09.01.2010
comment
Спасибо. Я сегодня кое-что узнал.   -  person Alok Singhal    schedule 09.01.2010
comment
Хотя функция --thpppt несколько спорна, ключевым преимуществом является то, что вы можете использовать регулярные выражения Perl напрямую, а не какие-то сумасшедшие [[:space:]] и символы, такие как {, [ и т. д., меняющие значение с помощью переключателей -e и -E таким образом, что это невозможно запомнить. .   -  person Evgeni Sergeev    schedule 03.01.2014
comment
Аналогично: unix.stackexchange.com/q/163726 и stackoverflow.com/q/8101701   -  person sondra.kinsey    schedule 15.09.2019
comment
Я использую grep --color=always | less -S -R. Затем введите -R, чтобы развернуть/сложить линии.   -  person Jérôme Pouiller    schedule 11.08.2020


Ответы (10)


Вы можете использовать параметр grep -o, возможно, в сочетании с изменением вашего шаблона на ".{0,10}<original pattern>.{0,10}", чтобы увидеть некоторый контекст вокруг него:

       -o, --only-matching
              Show only the part of a matching line that matches PATTERN.

..or -c:

       -c, --count
              Suppress normal output; instead print a count of matching  lines
              for  each  input  file.  With the -v, --invert-match option (see
              below), count non-matching lines.
person Ether    schedule 09.01.2010
comment
пример: grep -oE .{0,20}mysearchstring.{0,20} myfile - person Renaud; 09.11.2012
comment
вы должны изменить ответ, чтобы добавить параметр -E, как показано @Renaud (расширенный вариант шаблона), или предложенный шаблон для расширения контекста не будет работать. - person kriss; 28.10.2013
comment
Возможно, это не обязательно, но вот пример: $ echo "eeeeeeeeeeeeeeeeeeeeqqqqqqqqqqqqqqqqqqqqMYSTRINGwwwwwwwwwwwwwwwwwwwwrrrrrrrrrrrrrrrrrrrrr" > fileonelongline.txt && grep -oE ".{0,20}MYSTRING.{0,20}" ./fileonelongline.txt печатает qqqqqqqqqqqqqqqqqqqqMYSTRINGwwwwwwwwwwwwwwwwwwww - person Ulises Layera; 21.11.2018
comment
Это хорошо работает; но заметным недостатком является то, что при использовании, например, oE ".{0,20}mysearchstring.{0,20}" вы теряете выделение внутренней исходной строки по сравнению с контекстом, потому что все это становится шаблоном поиска. Хотелось бы найти способ сохранить невыделенный контекст вокруг результатов поиска, чтобы упростить визуальное сканирование и интерпретацию результатов. - person Aaron Wallentine; 18.09.2020
comment
О, вот решение проблемы с подсветкой, вызванной использованием подхода -oE ".{0,x}foo.{0,x}" (где x — количество символов контекста) — добавить ` | grep foo` до конца. Работает для решений ack или grep. Другие решения также здесь: unix.stackexchange.com/questions/163726/ - person Aaron Wallentine; 18.09.2020

Передайте результаты через cut. Я также рассматриваю возможность добавления переключателя --cut, чтобы вы могли сказать --cut=80 и получить только 80 столбцов.

person Andy Lester    schedule 09.01.2010
comment
Что делать, если совпадающая часть не находится в первых 80 символах? - person Ether; 10.01.2010
comment
FWIW я добавил | cut=c1-120 к grep, у меня сработало (хотя не знаю, как обрезать совпадающий текст) - person Jake Rayson; 08.12.2011
comment
| cut=c1-120 у меня не получилось, мне нужно было сделать | cut -c1-120 - person Ken Cochrane; 09.03.2012
comment
Я думаю, что @edib точен в синтаксисе | cut -c 1-100 stackoverflow.com/a/48954102/1815624 - person CrandellWS; 23.10.2018
comment
@AndyLester: А как насчет опции --no-wrap, в которой используется $COLUMNS? - person naught101; 08.03.2019
comment
@naught101 Вы можете отправить это как задачу github.com/beyondgrep/ack3/issues Помните, что ack также работает в Windows, и я не знаю, есть ли у них $COLUMNS - person Andy Lester; 08.03.2019

Вы можете использовать less в качестве пейджера для подтверждения и обрезки длинных строк: ack --pager="less -S" Это сохраняет длинную строку, но оставляет ее на одной строке вместо переноса. Чтобы увидеть больше строки, прокручивайте влево/вправо меньше с помощью клавиш со стрелками.

У меня есть следующая настройка псевдонима для ack, чтобы сделать это:

alias ick='ack -i --pager="less -R -S"' 
person Jonah Braun    schedule 14.06.2012
comment
Обратите внимание, что вы можете поместить эту команду --pager в свой файл ~/.ackrc, если вы всегда хотите ее использовать. - person Andy Lester; 05.02.2014
comment
Это звучит как лучшее решение этой проблемы, которая меня сильно беспокоит. Хотел бы я знать, как использовать ack. - person Brian Peterson; 17.03.2015
comment
@BrianPeterson ack очень похож на grep, только проще в наиболее распространенных случаях - person Aaron Wallentine; 18.09.2020

cut -c 1-100

получает символы от 1 до 100.

person edib    schedule 23.02.2018

grep -oE ".\{0,10\}error.\{0,10\}" mylogfile.txt

В нестандартной ситуации, когда вы не можете использовать -E, используйте вместо этого -e в нижнем регистре.

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

person Josh Withee    schedule 30.07.2020
comment
Не используйте обратную косую черту - grep -oE ".{0,10}error.{0,10}" mylogfile.txt - по крайней мере, в Z-желле - person Aurelijus Rozenas; 26.04.2021

Взято из: http://www.topbug.net/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/

Предложенный подход ".{0,10}<original pattern>.{0,10}" вполне хорош, за исключением того, что цвет выделения часто путают. Я создал скрипт с аналогичным выводом, но цвет также сохранен:

#!/bin/bash

# Usage:
#   grepl PATTERN [FILE]

# how many characters around the searching keyword should be shown?
context_length=10

# What is the length of the control character for the color before and after the
# matching string?
# This is mostly determined by the environmental variable GREP_COLORS.
control_length_before=$(($(echo a | grep --color=always a | cut -d a -f '1' | wc -c)-1))
control_length_after=$(($(echo a | grep --color=always a | cut -d a -f '2' | wc -c)-1))

grep -E --color=always "$1" $2 |
grep --color=none -oE \
    ".{0,$(($control_length_before + $context_length))}$1.{0,$(($control_length_after + $context_length))}"

Предполагая, что сценарий сохранен как grepl, тогда grepl pattern file_with_long_lines должен отображать совпадающие строки, но только с 10 символами вокруг совпадающей строки.

person xuhdev    schedule 19.08.2016
comment
Работает, но у меня выводит конечный мусор, например: ^[[?62;9;c. Я не пробовал отлаживать, потому что @Jonah Braun answer меня удовлетворил. - person sondra.kinsey; 16.09.2018

Я вставил следующее в свой .bashrc:

grepl() {
    $(which grep) --color=always $@ | less -RS
}

Затем вы можете использовать grepl в командной строке с любыми аргументами, доступными для grep. Используйте клавиши со стрелками, чтобы увидеть хвост более длинных линий. Используйте q для выхода.

Объяснение:

  • grepl() {: Определите новую функцию, которая будет доступна в каждой (новой) консоли bash.
  • $(which grep): Получить полный путь к grep. (Ubuntu определяет псевдоним для grep, который эквивалентен grep --color=auto. Нам нужен не этот псевдоним, а исходный grep.)
  • --color=always: Раскрасить вывод. (--color=auto из псевдонима не будет работать, так как grep определяет, что вывод помещается в канал, и тогда не окрашивает его.)
  • $@: поместите сюда все аргументы, переданные функции grepl.
  • less: Отображение строк с помощью less
  • -R: Показать цвета
  • S: Не разбивайте длинные строки
person pt1    schedule 06.11.2019

Вот что я делаю:

function grep () {
  tput rmam;
  command grep "$@";
  tput smam;
}

В моем .bash_profile я переопределяю grep, чтобы он автоматически запускал tput rmam до и tput smam после, что отключало перенос, а затем повторно позволяет это.

person ognockocaten    schedule 21.11.2019
comment
Это хорошая альтернатива - за исключением того, что фактическое совпадение затем выходит за пределы экрана... - person Xerus; 14.05.2020

ag также может использовать трюк с регулярным выражением, если вы предпочитаете его:

ag --column -o ".{0,20}error.{0,20}"
person Luke Miles    schedule 12.05.2021

Silver Searcher (ag) изначально поддерживает его с помощью параметра --width NUM. Он заменит остальные более длинные строки на [...].

Пример (обрезать после 120 символов):

 $ ag --width 120 '@patternfly'
 ...
 1:{"version":3,"file":"react-icons.js","sources":["../../node_modules/@patternfly/ [...]

В ack3 запланирована подобная функция, но в настоящее время она не реализована.

person Philipp Claßen    schedule 24.06.2021