使用正则表达式提取两个块之间的文本。

4
我正在尝试使用以下正则表达式提取两个字符串之间的文本。
(?s)Non-terminated Pods:.*?in total.\R(.*)(?=Allocated resources)

这个正则表达式在 regex101 上看起来没问题,但是在使用 perl 或者 grep -P 时无法打印 pod 细节信息。以下命令的输出为空。

kubectl describe  node |perl -le '/(?s)Non-terminated Pods:.*?in total.\R(.*)(?=Allocated resources)/m; printf "$1"'

以下是示例输入:

PodCIDRs:                     10.233.65.0/24
Non-terminated Pods:          (7 in total)
  Namespace                   Name                                        CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                        ------------  ----------  ---------------  -------------  ---
  default                     foo                                         0 (0%)        0 (0%)      0 (0%)           0 (0%)         105s
  kube-system                 nginx-proxy-kube-worker-1                   25m (1%)      0 (0%)      32M (1%)         0 (0%)         9m8s
  kube-system                 nodelocaldns-xbjp8                          100m (5%)     0 (0%)      70Mi (4%)        170Mi (10%)    7m4s
Allocated resources:

问题:

  1. 如何从上述输出中提取信息,使其看起来像下面的样子?正则表达式或使用的命令有什么问题吗?
Namespace                   Name                                        CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                        ------------  ----------  ---------------  -------------  ---
  default                     foo                                         0 (0%)        0 (0%)      0 (0%)           0 (0%)         105s
  kube-system                 nginx-proxy-kube-worker-1                   25m (1%)      0 (0%)      32M (1%)         0 (0%)         9m8s
  kube-system                 nodelocaldns-xbjp8                          100m (5%)     0 (0%)      70Mi (4%)  

问题-2: 如果我有两个类似的输入块,如何提取pod详细信息? 例如:

如果输入是:

PodCIDRs:                     10.233.65.0/24
Non-terminated Pods:          (7 in total)
  Namespace                   Name                                        CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                        ------------  ----------  ---------------  -------------  ---
  default                     foo                                         0 (0%)        0 (0%)      0 (0%)           0 (0%)         105s
  kube-system                 nginx-proxy-kube-worker-1                   25m (1%)      0 (0%)      32M (1%)         0 (0%)         9m8s
  kube-system                 nodelocaldns-xbjp8                          100m (5%)     0 (0%)      70Mi (4%)        170Mi (10%)    7m4s
Allocated resources:
....some
.......random data...
PodCIDRs:                     10.233.65.0/24
Non-terminated Pods:          (7 in total)
  Namespace                   Name                                        CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                        ------------  ----------  ---------------  -------------  ---
  default                     foo-1                                         0 (0%)        0 (0%)      0 (0%)           0 (0%)         105s
  kube-system                 nginx-proxy-kube-worker-2                   25m (1%)      0 (0%)      32M (1%)         0 (0%)         9m8s
  kube-system                 nodelocaldns-xbjp3-2                          100m (5%)     0 (0%)      70Mi (4%)        170Mi (10%)    7m4s
Allocated resources:

2
请只提出一个问题。 - Cyrus
4个回答

5

在某些明显的假设下,同时保持与问题中的模式接近:

perl -0777 -wnE'
    @pods = /Non-terminated\s+Pods:\s+\([0-9]+\s+in\s+total\)\n(.*?)\nAllocated resources:/gs;
    say for @pods
' input-file

(请注意这行正则表达式中的修改器,它太长以至于不能全部显示在屏幕上:/gs)


与本答案中的那个正则表达式相比,问题中的正则表达式可以用于单个文本块(并且不需要 /s 修改器)。为了能够处理多个文本块,需要将其中的 (.*) 改为 (.*?),这样它就不会一直匹配到最后一个 Allocated...

问题没有清楚地说明正则表达式 "如何使用 perl";我无法说出具体哪里出了问题。

对上面的命令行程序的注释:

  • 选项 -0777 让程序读入整个文件为一个字符串,可以在程序中通过变量 $_ 访问,并且默认绑定到正则表达式(binding)

    还有一个别名选项 -g 也等价于 -0777,自 5.36.0 版本开始支持。

  • 仍然需要选项 -n,以便程序迭代处理输入(来自 STDIN 或文件)的“行”。在这种情况下,输入记录分隔符 是未定义的,因此整个输入都被视为一行。

  • 正则表达式进行匹配捕获并返回结果,因为匹配运算符用于列表上下文中,并赋值给数组 @pods


4

使用gnu-grep,您可以对正则表达式进行一些调整:

kubectl describe  node |
grep -zoP '(?s)Non-terminated Pods:.*?in total.\R\K(.*?)(?=Allocated resources)'

  Namespace                   Name                                        CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                        ------------  ----------  ---------------  -------------  ---
  default                     foo                                         0 (0%)        0 (0%)      0 (0%)           0 (0%)         105s
  kube-system                 nginx-proxy-kube-worker-1                   25m (1%)      0 (0%)      32M (1%)         0 (0%)         9m8s
  kube-system                 nodelocaldns-xbjp8                          100m (5%)     0 (0%)      70Mi (4%)        170Mi (10%)    7m4s
  • \R后使用\K(匹配重置)以从输出中删除该行
  • 使用-z选项将输入和输出数据视为由零字节(ASCII NUL字符)而不是换行符终止的行序列。

提示:同样的正则表达式也适用于第二个输入块,在每个块之前都有显示的标题行。


或者您也可以使用任何版本的sed来完成此任务:

kubectl describe  node |
sed -n '/Non-terminated Pods:.*in total.*/,/Allocated resources:/ {//!p;}'

  Namespace                   Name                                        CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                        ------------  ----------  ---------------  -------------  ---
  default                     foo                                         0 (0%)        0 (0%)      0 (0%)           0 (0%)         105s
  kube-system                 nginx-proxy-kube-worker-1                   25m (1%)      0 (0%)      32M (1%)         0 (0%)         9m8s
  kube-system                 nodelocaldns-xbjp8                          100m (5%)     0 (0%)      70Mi (4%)        170Mi (10%)    7m4s

3
请使用您展示的样例,尝试以下GNU awk代码。 代码已在GNU awk中编写和测试。简单解释如下:将Input_file的RS设置为Non-terminated Pods:.*Allocated resources:。 然后在主程序中,检查RT是否不为空,然后使用awkgsub函数将(^|\n)Non-terminated Pods:[^\n]*\n\nAllocated resources:\n*替换为空值,并打印其值,这将提供与所示样本相同的输出结果。
awk -v RS='Non-terminated Pods:.*Allocated resources:' '
RT{
  gsub(/(^|\n)Non-terminated Pods:[^\n]*\n|\nAllocated resources:\n*/,"",RT)
  print RT
}
'  Input_file

1

对于需要逐行读取的大文件,可能的解决方案如下:

选择感兴趣的行范围,并删除最后一行,因为它不包含在所需的输出中。

use strict;
use warnings;

while(<>) {
    if( /^  Namespace/ .. /^Allocated resources:/ ) {
        print unless /^Allocated resources:/;
    }
}

exit 0;

输出

  Namespace                   Name                                        CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                        ------------  ----------  ---------------  -------------  ---
  default                     foo                                         0 (0%)        0 (0%)      0 (0%)           0 (0%)         105s
  kube-system                 nginx-proxy-kube-worker-1                   25m (1%)      0 (0%)      32M (1%)         0 (0%)         9m8s
  kube-system                 nodelocaldns-xbjp8                          100m (5%)     0 (0%)      70Mi (4%)        170Mi (10%)    7m4s
  Namespace                   Name                                        CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                        ------------  ----------  ---------------  -------------  ---
  default                     foo-1                                       0 (0%)        0 (0%)      0 (0%)           0 (0%)         105s
  kube-system                 nginx-proxy-kube-worker-2                   25m (1%)      0 (0%)      32M (1%)         0 (0%)         9m8s
  kube-system                 nodelocaldns-xbjp3-2                        100m (5%)     0 (0%)      70Mi (4%)        170Mi (10%)    7m4s

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接