grep -P больше не работает. Как я могу переписать свои поиски?

99

Похоже, новая версия OSX больше не поддерживает, grep -Pи поэтому некоторые из моих скриптов перестали работать.

var1=`grep -o -P '(?<=<st:italic>).*(?=</italic>)' file.txt`

Мне нужно записать grep в переменную, и мне нужно использовать утверждения нулевой ширины, а также \K

var2=`grep -P -o '(property:)\K.*\d+(?=end)' file.txt`

Приветствуются любые альтернативы.

Кугёша
источник
8
как насчет установки gnu grep?
Кент
Вы уверены, что это -P? У меня это есть.
Кевин
4
@Kevin Он был удален в 10.8.
Пт
8
@ AdrianFrühwirth OS X grepфактически изменилась с grep (GNU grep) 2.5.1версии 10.7 на версию grep (BSD grep) 2.5.1-FreeBSD10.8. Я думаю, это было из-за GPL. FreeBSD grepтакже основана на GNU, grepи обе версии grepотносятся к 2002 г. --labelи -u/ --unix-byte-offetsтакже были удалены в 10.8. -z/ --decompress, -J/ --bz2decompress, --exclude-dir, --include-dir, -S, -O, И -pбыли добавлены в 10,8. -Zизменено с --nullна --decompress.
Вт, 03
3
FreeBSD grep, поставляемая с OS X, выпущена в 2002 году, и wiki.freebsd.org/BSDgrep по- прежнему говорит, что «единственный элемент TODO - повышение производительности», так что да. time grep aa /usr/share/dict/words>/dev/nullзанимает около 0,09 секунды с grep в OS X и около 0,01 секунды с новым GNU grep при повторных запусках на моем iMac.
Вт, 03

Ответы:

68

Если вы хотите выполнить минимальный объем работы, измените

grep -P 'PATTERN' file.txt

к

perl -nle'print if m{PATTERN}' file.txt

и изменить

grep -o -P 'PATTERN' file.txt

к

perl -nle'print $& while m{PATTERN}g' file.txt

Итак, вы получаете:

var1=`perl -nle'print $& while m{(?<=<st:italic>).*(?=</italic>)}g' file.txt`
var2=`perl -nle'print $& while m{(property:)\K.*\d+(?=end)}g' file.txt`

В вашем конкретном случае вы можете добиться более простого кода с дополнительной работой.

var1=`perl -nle'print for m{<st:italic>(.*)</italic>}g' file.txt`
var2=`perl -nle'print for /property:(.*\d+)end/g' file.txt`
икегами
источник
1
Это отлично работает, но возвращает все совпадения, поскольку использованный grep вернул только первое совпадение. есть идеи, как вернуть только первый матч?
kugyousha
1
@ironintention: добавить | tail -1в конец конвейера.
Питер
grepвсегда возвращает все совпадающие строки (если вы не используете один из вариантов, при котором он вообще не печатает). В любом случае, if (/.../) { print $1; last; }он будет печатать только первое совпадение.
ikegami
Я использовал это, чтобы получить URL-адреса карты сайта - спасибо, дружище, не сделал бы этого без вашего сообщения! perl -nle'print $ 1 if m {<loc> (. *) </loc>} 'sitemap.xml
Кристиан
2
@Christian, потребуется всего 3 строки, чтобы сделать это с помощью правильного анализатора XML, такого как XML :: LibXML. (Key линия: say $_->textContent for $doc->findnodes('//loc');)
Ikegami
93

Если ваши скрипты только для личного использования, вы можете установить grepс homebrew-coreпомощью brew:

brew install grep 

Тогда он доступен как ggrep(GNU grep). он не заменяет систему grep(вам нужно поставить установленный grep перед системным PATH).

Версия, установленная с помощью, brewвключает эту -Pопцию, поэтому вам не нужно изменять скрипты.

Если вам нужно использовать эти команды с их обычными именами, вы можете добавить каталог «gnubin» в свой PATH из вашего bashrc, например:

PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"

Вы можете экспортировать эту строку в свой ~ / .bashrc или ~ / .zshrc, чтобы сохранить ее для новых сеансов.

Пожалуйста, смотрите здесь обсуждение плюсов и минусов старого --with-default-namesварианта и его (недавнего) удаления.

Древицко
источник
3
@pepper что не сработало? Скорее всего, путь установлен неправильно - каков результат which grep? Должно быть /usr/local/bin/grep. Это немного означало бы проголосовать против, прежде чем вы внимательно проверите, есть ли проблема!
drevicko
2
вероятно, лучше добавить /usr/local/binв начало вашего PATH. Я полагаю, пив должен установить это? Вы использовали --default-names? Во всяком случае, рад, что он работает (: Не уверен, что насчет этого, но я думаю, что балльная система - одна из причин, по которой этот сайт является таким хорошим ресурсом.
drevicko
1
да, я использовал --default-names и варево. Не уверен, что размещение / usr / local / bin перед вашим путем лучше, чем псевдоним, просто альтернатива
перец
10
альтернатива --with-default-names- добавить alias grep='ggrep'в свой профиль на bash и позволить brew dupes сохранять свой префикс
rymo 01
4
--with-default-namesудаляется из заварки. Мне пришлось brew install grepполучить ggrep, а затем сделать, как говорит и делать @rymo alias grep='ggrep'.
Henge
12

Установите ack и используйте его. Ack - это замена grep, написанная на Perl. Он полностью поддерживает регулярные выражения Perl.

Майкл Карман
источник
Я бы хотел это проверить, но это для рабочих компьютеров, поэтому мы не можем ничего установить
Кугёша
@ironintention: Если вы можете установить модули Perl, все в порядке. Даже если вы не можете добавить в локальную установку Perl, вы всегда можете использовать local :: lib.
Майкл Карман
ackразработан, чтобы быть автономным; вам не нужно его устанавливать. Если вы можете сохранить файл, пометить его как исполняемый и PATHпри необходимости обновить его, все готово .
tripleee 02
Не могли бы вы воспользоваться синтаксисом ack, который заменяет вышеприведенное?
Уильям Энтрикен
@FullDecent: Это почти идентично: ack -o '(property:)\K.*\d+(?=end)' file.txt( -oозначает то же самое, но вам не нужен -Pс ack)
Майкл Карман
11

OS X имеет тенденцию предоставлять инструменты BSD, а не GNU. Однако он есть egrep, и это, вероятно, все, что вам нужно для выполнения поиска по регулярным выражениям.

пример: egrep 'fo+b?r' foobarbaz.txt

Фрагмент справочной страницы OSX grep:

grep is used for simple patterns and basic regular expressions (BREs); egrep can handle extended regular expressions (EREs).

туманный
источник
5
Прямой вызов как egrep устарел. Такая же возможность доступна как grep -E. Это ... грустная тень Perl, в которой отсутствуют проверочные утверждения, большинство экранированных символов обратной косой черты, параметры, условные выражения и т. Д. (Опытные пользователи будут ненавидеть ее, но она, по крайней мере, выполняет свою работу.
Деви Морган,
1
Спасибо. grep -Eвместо grep -Pбыло именно то, что мне было нужно.
asmaier
6

use perl;

perl -ne 'print if /regex/' files ...

Если вам нужно больше grepопций (я вижу, вы, -oпо крайней мере, хотели бы), в сети ходят различные pgrepреализации, многие из которых на Perl.

Если "почти Perl" достаточно хорош, PCRE поставляется с pcregrep.

тройной
источник
5

Существует еще одна альтернатива: pcregrep.

Pcregrep - это grep с регулярными выражениями, совместимыми с Perl. Он используется точно так же, как grep -P. Так что он будет совместим с вашими скриптами.

Его можно установить с помощью homebrew:

brew install pcre

Габор Мартон
источник
Error: No available formula for pcregrep
Аарон Брагер,
ГаборМартон, я отредактировал ваш ответ, включив в него исправляющий комментарий @Martin, и мне пришлось немного переместить форматирование, чтобы преодолеть минимальные изменения.
Дэниел Бэрд,
3

Как насчет использования опции '-E'? Он отлично работает для меня, например, если я хочу проверить для php_zip, php_xml, php_gd2расширение из PHP -m я использую:

php -m | grep -E '(zip|xml|gd2)'
ZenC
источник
1
это работает. Mac использует FreeBSD grep, а Linux использует GNU grep ... так что это исправление сработало на моей macOS sierra
jimh
2

Эквивалент принятого ответа, но без использования переключателя -P, которого не было на обеих машинах, которые у меня были.

find . -type f -exec perl -nle 'print $& if m{\r\n}' {} ';' -exec perl -pi -e 's/\r\n/\n/g' {} '+'
нуццолило
источник
2

Это сработало для меня:

    awk  -F":" '/PATTERN/' file.txt
Petegam
источник
0

Еще одно решение Perl для -P

var1=$( perl -ne 'print $1 if m#<st:italic>([^<]+)</st:italic># ' file.txt)
Рори Хантер
источник
0

используйте однострочное регулярное выражение perl, передав вывод find через канал. Я использовал lookbehind (получить ссылки src в html) и lookahead для " и передал ему вывод curl (html).

bash-3.2# curl stackoverflow.com | perl -0777 -ne '$a=1;while(m/(?<=src\=\")(.*)(?=\")/g){print "Match #".$a." "."$&\n";$a+=1;}'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  239k  100  239k    0     0  1911k      0 --:--:-- --:--:-- --:--:-- 1919k
Match #1 //ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
Match #2 //cdn.sstatic.net/Js/stub.en.js?v=fb6157e02696
Match #3 https://ssum-sec.casalemedia.com/usermatch?s=183712&amp;cb=https%3A%2F%2Fengine.adzerk.net%2Fudb%2F22%2Fsync%2Fi.gif%3FpartnerId%3D1%26userId%3D
Match #4 //i.stack.imgur.com/817gJ.png" height="16" width="18" alt="" class="sponsor-tag-img">elasticsearch</a> <a href="/questions/tagged/elasticsearch-2.0" class="post-tag" title="show questions tagged &#39;elasticsearch-2.0&#39;" rel="tag">elasticsearch-2.0</a> <a href="/questions/tagged/elasticsearch-dsl" class="post-tag" title="show questions tagged &#39;elasticsearch-dsl&#39;" rel="tag
Match #5 //i.stack.imgur.com/817gJ.png" height="16" width="18" alt="" class="sponsor-tag-img">elasticsearch</a> <a href="/questions/tagged/sharding" class="post-tag" title="show questions tagged &#39;sharding&#39;" rel="tag">sharding</a> <a href="/questions/tagged/master" class="post-tag" title="show questions tagged &#39;master&#39;" rel="tag
Match #6 //i.stack.imgur.com/tKsDb.png" height="16" width="18" alt="" class="sponsor-tag-img">android</a> <a href="/questions/tagged/linux" class="post-tag" title="show questions tagged &#39;linux&#39;" rel="tag">linux</a> <a href="/questions/tagged/camera" class="post-tag" title="show questions tagged &#39;camera&#39;" rel="tag
Match #7 //i.stack.imgur.com/tKsDb.png" height="16" width="18" alt="" class="sponsor-tag-img">android</a> <a href="/questions/tagged/firebase" class="post-tag" title="show questions tagged &#39;firebase&#39;" rel="tag"><img src="//i.stack.imgur.com/5d55j.png" height="16" width="18" alt="" class="sponsor-tag-img">firebase</a> <a href="/questions/tagged/firebase-authentication" class="post-tag" title="show questions tagged &#39;firebase-authentication&#39;" rel="tag
Match #8 //i.stack.imgur.com/tKsDb.png" height="16" width="18" alt="" class="sponsor-tag-img">android</a> <a href="/questions/tagged/ios" class="post-tag" title="show questions tagged &#39;ios&#39;" rel="tag">ios</a> <a href="/questions/tagged/in-app-purchase" class="post-tag" title="show questions tagged &#39;in-app-purchase&#39;" rel="tag">in-app-purchase</a> <a href="/questions/tagged/piracy-protection" class="post-tag" title="show questions tagged &#39;piracy-protection&#39;" rel="tag
Match #9 //i.stack.imgur.com/tKsDb.png" height="16" width="18" alt="" class="sponsor-tag-img">android</a> <a href="/questions/tagged/unity3d" class="post-tag" title="show questions tagged &#39;unity3d&#39;" rel="tag">unity3d</a> <a href="/questions/tagged/vr" class="post-tag" title="show questions tagged &#39;vr&#39;" rel="tag
Match #10 http://pixel.quantserve.com/pixel/p-c1rF4kxgLUzNc.gif" alt="" class="dno
bash-3.2# date
Mon Oct 24 20:57:11 EDT 2016
Рохит Малгаонкар
источник