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 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
。
OS X 附带的 FreeBSD grep
是从 2002 年开始的,wiki.freebsd.org/BSDgrep 仍然说“唯一的 TODO 项是提高性能”,所以是的。 time grep aa /usr/share/dict/words>/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】:如果您的脚本仅供您使用,您可以使用brew
从homebrew-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 msay $_->textContent for $doc->findnodes('//loc');
)【参考方案4】:
使用“-E”选项怎么样?这对我来说可以,
例如,如果我想检查 php -m 中的 php_zip
、php_xml
、php_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&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 'elasticsearch-2.0'" rel="tag">elasticsearch-2.0</a> <a href="/questions/tagged/elasticsearch-dsl" class="post-tag" title="show questions tagged 'elasticsearch-dsl'" 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 'sharding'" rel="tag">sharding</a> <a href="/questions/tagged/master" class="post-tag" title="show questions tagged 'master'" 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 'linux'" rel="tag">linux</a> <a href="/questions/tagged/camera" class="post-tag" title="show questions tagged 'camera'" 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 'firebase'" 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 'firebase-authentication'" 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 'ios'" rel="tag">ios</a> <a href="/questions/tagged/in-app-purchase" class="post-tag" title="show questions tagged 'in-app-purchase'" rel="tag">in-app-purchase</a> <a href="/questions/tagged/piracy-protection" class="post-tag" title="show questions tagged 'piracy-protection'" 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 'unity3d'" rel="tag">unity3d</a> <a href="/questions/tagged/vr" class="post-tag" title="show questions tagged 'vr'" 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 不再有效。如何重写我的搜索?的主要内容,如果未能解决你的问题,请参考以下文章