【问题标题】:Processing curl output in perl在 perl 中处理 curl 输出
【发布时间】:2018-02-01 09:40:13
【问题描述】:

我正在处理来自curl -s 的输出。 具体来自这个页面:https://support.microsoft.com/en-us/help/971058/how-do-i-reset-windows-update-components

在我陈述我的目标之前,我会提到我只对从该页面的 curl 输出中提取所需数据的答案感兴趣。 (我知道此页面上建议的操作已经以文本、powershell 脚本等形式提供。)

最终目标是获取 dll 列表。 应该快速完成而不大惊小怪(所以单行),但现在它已成为我的学习经历。基本的正则表达式是/regsvr32.exe (.*?\.dll)/

我感兴趣的 curl 输出看起来像这样(注意缺少换行符):

<li>regsvr32.exe a.dll</li><li>regsvr32.exe b.dll</li>etc

所以我尝试了 perl,如下所示: perl -F"li" -lane 'print $1 if /regsvr32.exe (.*?\.dll)/g'

(逻辑是我可以在任何“li”出现时草率地拆分,并且仍然应该得到合理的结果,我可以稍后进行微调)

我根本无法让-F 工作。我尝试了单个字符,我尝试了像 /PATTERN/ 这样的正则表达式,我尝试省略各种其他标志(特别是 -l),我写了一个单行来显示拆分。我无法进行分裂。

然后我检查了 curl 手册页,看看它是否有任何可能有帮助的输出消毒剂。这是一个很长的手册页,但我什么也没看到。

然后我突然想到,如果我编写的 perl 能够正常工作,无论同一个正则表达式是否在同一行上多次匹配,那将是一件好事。但是我找不到任何适合单线的东西。

我能找到的最明智的方法是生成所需的单行输出:

curl -vs \
https://support.microsoft.com/en-us/help/971058/how-do-i-reset-windows-update-components 2>&1 | \
perl -pe 's|</li>|\n|g' | \
perl -lne 'print $1 if /regsvr32.exe (.*?\.dll)/'

谁能提出一些不那么荒谬的建议?

另外,我喜欢任何对 Perl 的 -F 参数的解释,它比 perldoc perlrun 更有启发性。

【问题讨论】:

  • 不确定它是否更荒谬,但这里有一个替代方案(这可能远非最佳)。 curl -vs https://support.microsoft.com/en-us/help/971058/how-do-i-reset-windows-update-components 2&gt;&amp;1 | grep -Po 'regsvr32.exe (.*?\.dll)' | cut -d ' ' -f 2
  • 您正在尝试使用单行中的简单正则表达式解析凌乱的 HTML。为什么不写一个漂亮的小脚本,比如HTML::TreeBuilder?这将是一件轻而易举的事。顺便说一句,您并没有真正说明您对“感兴趣”的具体内容——“看起来像这样”并没有让我明白。
  • @zdim 基本上是一个简单易用的解决方案。我试图澄清一下我的问题。一旦问题进入脚本领域,我倾向于切换到 C# 或 C++,只是因为我对这些语言更加熟悉。
  • 当然,考虑到目标是什么(很好的编辑,谢谢),确实可行,就像答案一样。但是请记住,由于所有这些出色的模块,某些类型的工作,例如解析 (X)HTML,使用脚本比使用 C++(我喜欢并使用 C++——不是抱怨这种语言)要简单得多。
  • @zdim - C# 对这些内置的东西有相当广泛的支持,但我怀疑 perl 或 python 让它更容易。 (当然不需要明确的编译步骤)。 Python 已经在我工作的地方使用了一点(并且往往出现在 Windows 机器上),但是 perl 解决了我的很多小问题,我很纠结该学哪一个。所以我在这两个方面都很糟糕:)

标签: regex perl curl


【解决方案1】:

无需拆分&lt;li&gt; 元素或使用解析器(您不关心文档的结构),因此您只需搜索regsvr32.exe 字符串直到下一个&lt;字符。

curl $msft_url | perl -lane 'print for ( m|regsvr32.exe (.+?.dll)<|g );'

要处理多个捕获,您将需要一个额外的while 循环来迭代匹配对。 shift 命令从数组中提取第一个元素,reverse 命令反转数组。这会捕获 2 个字符串并以相反的顺序打印它们:

curl $msft_url | perl -lane '@m = m|(regsvr32).exe (.+?.dll)<|g; while (@m) { print join " ", reverse(shift @m, shift @m) };'

【讨论】:

  • 绝对完美。不真正使用 perl 编写脚本的缺点是很难学习像这样的有效技巧……因为当然,我并不真正了解 perl。所以这个答案是一座金矿。我注意到如果我添加了额外的捕获组,所有内容都会被打印出来。极好的。我不认为有一种简单的方法可以从这样的循环中构造输出?例如,可以使用 single 两个捕获组匹配的输出来执行 print "$2 $1"
【解决方案2】:

我发现了如何执行我正在尝试的另一种方法(有点),即让 perl 进行拆分。关键是-a-F 不决定记录拆分行为。只有-0 可以。

-a每个 记录(在内部)拆分为 @F 数组,文档现在似乎完全清楚地说明了这一点。 @F 数组主要用于awk 样式,因此可以很容易地说“打印第二列”($F[1])。所以我可以改写为“-0 通常是获取行的方式,-a 通常是获取列的方式,粗略地说。”

但是,它可以服务于目的:

curl -vs \
https://support.microsoft.com/en-us/help/971058/how-do-i-reset-windows-update-components 2>&1 \
| perl -F'<\/li>' -lane 'foreach my $match (map { /regsvr32.exe (.+?.dll)/ } @F) {print"$match"}

出于显而易见的原因,我更喜欢这个问题的公认解决方案,但我可以看到这种方法在其他地方很方便。 PS---0 的解决方案(使用&gt; 上的记录拆分)是:

| perl -0x3c -ne 'print "$1\n" if /regsvr32.exe (.+?\.dll)/'

【讨论】:

  • @zdim - 我错误地认为-F 是做同样事情的更强大的方式。虽然| perl -0x3c -ne 'print "$1\n" if /regsvr32.exe (.+?\.dll)/' 成功了...... ugggh,即使对我来说,这也有点太不尊重html了。在&lt;/li&gt; 上以某种方式分裂似乎......有点合理。
  • 好的,现在清除 :) 我清理了编辑后不合适的 cmets。
  • @zdim 行/列的事情也有意义吗?如果这对您没有意义,我不确定它是否会帮助那些不了解 -F-0 行为方式的人(就像我没有那样)。我想知道我的意思的一个小而简单的例子是否会有所帮助......或者不合适?
  • 当你说“列”时,我想把每行数据分成块,这样这些行就变成了“列”。这就是-F 所做的,所以对我来说似乎没问题。但是对我来说,“行”意味着一行数据……所以我看不出这与返回整个文件的-0 有什么关系。即使您认为该文件被&lt; 分解,我仍然看不到“行”。我的想法。我认为,一个例子总是好的。 (如果您想了解如何从行和列的角度来查看它——这里没有必要。您已经展示了如何使用 -F 来做这件事很好。)
  • 好的,我明白你的意思了——但它仍然不能让我对“行”感到满意 :) (但我在这里分叉了 :)
猜你喜欢
  • 2011-06-26
  • 2010-11-17
  • 2013-02-17
  • 2023-03-09
  • 2022-01-21
  • 2011-03-16
  • 1970-01-01
  • 2020-07-13
  • 2017-10-13
相关资源
最近更新 更多