grep -P 不再有效。如何重写我的搜索?

Posted

技术标签:

【中文标题】grep -P 不再有效。如何重写我的搜索?【英文标题】:grep -P no longer works. How can I rewrite my searches? 【发布时间】:2013-05-15 12:45:06 【问题描述】:

看起来新版本的 OSX 不再支持grep -P,因此导致我的一些脚本停止工作。

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

我需要将 grep 捕获到一个变量中,并且我需要使用零宽度断言,以及 \K

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

任何替代品将不胜感激。

【问题讨论】:

安装 gnu grep 怎么样? 你确定是-P吗?我的有。 @Kevin 已在 10.8 中删除。 @AdrianFrühwirth OS X 的 grep 实际上从 10.7 中的 grep (GNU grep) 2.5.1 更改为 10.8 中的 grep (BSD grep) 2.5.1-FreeBSD。我猜是因为 GPL。 FreeBSD grep 也基于 GNU grepgrep 的两个版本都来自 2002。--label-u / --unix-byte-offets 在 10.8 中也被删除。 -z/--decompress-J/--bz2decompress--exclude-dir--include-dir-S-O-p 在 10.8 中添加。 -Z--null 更改为 --decompress OS X 附带的 FreeBSD grep 是从 2002 年开始的,wiki.freebsd.org/BSDgrep 仍然说“唯一的 TODO 项是提高性能”,所以是的。 time grep aa /usr/share/dict/words&gt;/dev/null 在我的 iMac 上重复运行时,使用 OS X 的 grep 大约需要 0.09 秒,使用新的 GNU grep 大约需要 0.01 秒。 【参考方案1】:

我在 docker 重建时突然遇到了与 grep 相同的问题,我在这里找到了解决方案:https://github.com/firehol/firehol/issues/325

只是将 -oP 替换为 -oE

echo $some_var | grep -oE '\b[0-9a-f]5,40\b' | head -1

【讨论】:

【参考方案2】:

如果您的脚本仅供您使用,您可以使用brewhomebrew-core 安装grep

brew install grep 

然后它可以作为 ggrep (GNU grep) 使用。 它不会替换系统grep(您需要将已安装的grep 放在PATH 上的系统一之前)。

brew 安装的版本包含-P 选项,因此您无需更改脚本。

如果您需要使用这些命令的正常名称,您 可以从 bashrc 中将“gnubin”目录添加到 PATH,例如:

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

您可以在 ~/.bashrc 或 ~/.zshrc 上导出此行以保留新会话。

请参阅 here 讨论旧的 --with-default-names 选项的优缺点以及它(最近的)删除。

【讨论】:

@pepper 什么没用?可能路径设置不正确 - which grep 的输出是什么?应该是/usr/local/bin/grep。在您仔细检查是否有问题之前,投反对票有点意思! 最好将 /usr/local/bin 添加到 PATH 的前面。我相信Brew应该设置它?你用--default-names了吗?无论如何,很高兴它可以工作(:不确定是否可以绕过它,但我认为积分系统是这个网站如此好的资源的原因之一。 是的,我确实使用了 --default-names 和 brew。不确定将 /usr/local/bin 放在路径的前面是否比别名更好,只是一种替代方法 --with-default-names 的替代方法是将alias grep='ggrep' 添加到您的 bash 配置文件中,并让 brew dupes 保留其前缀 --with-default-names 已从 brew 中删除。我必须brew install grep 才能获得ggrep,然后按照@rymo 所说的做alias grep='ggrep'【参考方案3】:

如果你想做最少的工作,改变

grep -P 'PATTERN' file.txt

perl -nle'print if mPATTERN' file.txt

改变

grep -o -P 'PATTERN' file.txt

perl -nle'print $& while mPATTERNg' 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`

【讨论】:

这很好用,但它返回所有匹配项,因为我使用的 grep 只返回第一个匹配项。关于如何只返回第一场比赛的任何想法? @ironintention:将| tail -1 添加到管道的末尾。 grep 总是返回所有匹配的行(除非您使用它根本不打印的选项之一)。无论如何,if (/.../) print $1; last; 将导致它只打印第一个匹配项。 我用它来获取站点地图的网址 - 谢谢伙计,没有你的帖子就不会成功! perl -nle'print $1 if m(.*)' sitemap.xml @Christian,使用适当的 XML 解析器(例如 XML::LibXML)只需 3 行即可。 (关键行:say $_-&gt;textContent for $doc-&gt;findnodes('//loc');【参考方案4】:

使用“-E”选项怎么样?这对我来说可以, 例如,如果我想检查 php -m 中的 php_zipphp_xmlphp_gd2 扩展,我使用:

php -m | grep -E '(zip|xml|gd2)'

【讨论】:

这行得通。 Mac 使用 FreeBSD grep 而 Linux 使用 GNU grep...所以这个修复适用于我的 macOS sierra【参考方案5】:

通过使用管道传递查找输出来使用 perl 单行正则表达式。 我使用 lookbehind(在 html 中获取 src 链接)和 lookahead for " 并传递 curl (html ) 到它。

bash-3.2# curl ***.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"    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"    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"    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"    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"    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"    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"    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"  class="dno
bash-3.2# date
Mon Oct 24 20:57:11 EDT 2016

【讨论】:

【参考方案6】:

这个对我有用:

    awk  -F":" '/PATTERN/' file.txt

【讨论】:

【参考方案7】:

等效于接受的答案,但不需要 -P 开关,这在我可用的两台机器上都不存在。

find . -type f -exec perl -nle 'print $& if m\r\n'  ';' -exec perl -pi -e 's/\r\n/\n/g'  '+'

【讨论】:

【参考方案8】:

OS X 倾向于提供 BSD 而不是 GNU 工具。但是,它确实带有egrep,这可能是您执行正则表达式搜索所需的全部内容。

示例:egrep 'fo+b?r' foobarbaz.txt

OSX grep 手册页中的 sn-p:

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

【讨论】:

不推荐使用 egrep 直接调用。 grep -E 也可以使用相同的功能。这是... Perl 的可悲阴影,缺少环视断言,大多数反斜杠转义,选项,条件等 :( 高级用户会讨厌它,但它至少可以完成这项工作。 谢谢。 grep -E 而不是 grep -P 正是我所需要的。【参考方案9】:

还有另一种选择:pcregrep

Pcregrep 是一个与 Perl 兼容的正则表达式的 grep。它的用法与grep -P 完全相同。因此它将与您的脚本兼容。

可以用自制软件安装:

brew install pcre

【讨论】:

Error: No available formula for pcregrep GaborMarton,我编辑了您的答案以包含 @Martin 的更正评论,并且不得不稍微移动格式以克服最小的更改。【参考方案10】:

安装ack 并使用它。 Ack 是用 Perl 编写的 grep 替代品。它完全支持 Perl 正则表达式。

【讨论】:

我想检查一下,但这是用于工作计算机的,所以我们无法安装任何东西 @ironintention:如果您可以安装 Perl 模块,那就太好了。即使您无法添加到本地 Perl 安装,您也可以始终使用 local::lib。 ack 被设计成独立的;您不需要实际安装它。如果您可以保存文件,将其标记为可执行文件,并在必要时更新您的PATH,您就可以开始了。 能否请教一下替换上面的ack语法 @FullDecent:几乎相同:ack -o '(property:)\K.*\d+(?=end)' file.txt-o 表示相同的意思,但您不需要带有 ack 的 -P【参考方案11】:

-P 的另一种 Perl 解决方案

var1=$( perl -ne 'print $1 if m#<st:italic>([^<]+)</st:italic># ' file.txt)

【讨论】:

【参考方案12】:

use perl;

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

如果您需要更多grep 选项(我知道您至少会喜欢-o),网上有各种各样的pgrep 实现,其中许多在Perl 中。

如果“几乎 Perl”足够好,PCRE 会附带 pcregrep

【讨论】:

以上是关于grep -P 不再有效。如何重写我的搜索?的主要内容,如果未能解决你的问题,请参考以下文章

有效重写的状态404,预期的索引处理程序

如何批量重写 SVN 日志?

修复虚拟机和描述符文件 - 重写 vmx [重复]

仅当目录或文件不存在时才重写规则

重写 bash 命令以符合 ShellCheck

如何将代码从DAO重写为ADO?