使用 Bash、Perl 和 Regex 将文本文件中的变量提取到数组中

使用 Bash、Perl 和 Regex 将文本文件中的变量提取到数组中

我想使用 Bash、Perl 和 Regex 从文本文件中提取变量。

该文件如下所示(并且已读入变量 $str):

Filename: XXXXX
Type: XXX
Size: XXXX
Unimportant thing: XXXX

Filename: YYYYY
Type: YYY
Size: YYYY
Unimportant thing: YYYY

我需要每个块的文件名、类型和大小。数组是最好的,但包含由给定字符分隔的这些变量的字符串也是可以接受的。

然而,有时某些字段(例如大小或类型)会丢失。我想省略这些记录,所以我想我需要一个可以通过多行匹配的正则表达式。

我尝试了以下方法:

perl -pe 's/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n/\1\t\2\t\3\n/' <<< $str

但这没有修改就打印出了原始文本。

然后我在没有 p 命令行参数的情况下尝试了它(我希望通过这种方式处理整个文件而不是迭代行):

perl -e 's/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n/\1\t\2\t\3\n/' <<< $str

这个没有打印任何东西(空结果)。

然后我尝试在正则表达式前面添加 print ,因为我认为删除 -p 可能会导致 Perl 不知道我想要打印结果:

perl -e 'print s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n/\1\t\2\t\3\n/' <<< $str

仍然没有成功(空结果)。

我缺少什么?

更新:

我希望将其作为一行 perl 命令。

答案1

我的 Perl 知识很薄弱,但由于没有其他人提供 Perl 答案,所以我会尝试一下。

将数据作为文件传递,它将打印制表符分隔的行,每行三个值:

perl -e 'while (<>) { $s .= $_; } chomp $s; @arr = split(/\n{2,}/, $s); foreach my $a(@arr) { $a =~ s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n.*/$1\t$2\t$3\n/ || next; print "$a"; } ' infile

结果:

XXXXX   XXX     XXXX
YYYYY   YYY     YYYY

这有点暴力,但可以通过将输入分成段落/块,然后将多行正则表达式应用于每个段落/块来工作。

细节...

  • while (<>) { $s .= $_; }- 将输入变成单个字符串。
  • chomp $s- 从字符串中删除尾随换行符。
  • @arr = split(/\n{2,}/, $s)- 在连续的换行符上分割字符串。这将其分成段落/块。将块存储在数组中。
  • foreach my $a(@arr)- 循环每个数组元素(块)。接下来的两行代码将应用于每个块。
  • $a =~ s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n.*/$1\t$2\t$3\n/ || next- 从三个感兴趣的字段中提取值。如果没有发生替换(意味着正则表达式不匹配,因为例如缺少值),则跳过此块并移至下一个。
  • print "$a"- 打印替换结果:用制表符分隔的三个值。

再说一次,我不太使用 Perl,所以可能有比这更优雅的解决方案。

答案2

不是 perl 方面的大专家,但使用sed它会看起来像这样:

sed  -n '/^$/d;/^Filename/,/^Unimportant/{:a;/Unimportant/!{N;ba};s/Filename: \([^\n]*\)\nType: \([^\n]*\)\nSize: \([^\n]*\)\n.*/\1\t\2\t\3/p};'

在哪里:

  • /^$/d-- 将删除所有空行
  • /^Filename/,/^Unimportant/将分别匹配从 Filename 到 Unimportant 的每个块。我假设您在每个块中都有不重要的记录。
  • :a;/Unimportant/!{N;ba};将把整个块连接到一个缓冲区中。需要,因为sed无法使用多行正则表达式或以其他方式一次处理多行
  • s/Filename: \([^\n]*\)\nType: \([^\n]*\)\nSize: \([^\n]*\)\n.*/\1\t\2\t\3/p};将替换为您需要的格式(基于您的 perl 正则表达式)

相关内容