【发布时间】:2017-12-13 11:18:54
【问题描述】:
假设您有一个文件,其中包含由两个或多个\n 分隔的五个数据块来分隔记录(一种常见的文本格式)。
如果您使用RS="" 运行awk,则设置awk 以将块分隔为记录。然后您可以设置FS=\n 将块的行分隔为字段。
例子:
$ cat lines
f1, r1
f2, r1 then 2 \n:
f1, r2 then 3 \n:
f1,r3
f2,r3 then 4 \n:
f1, r4
f2,r4 then 6 \n:
f1,r5
idiomatic 用 awk 将块分成记录和将行分成字段的方法是:
$ awk 'BEGIN{RS=""; FS="\n"; OFS="|"}
{$1=$1; printf "NR: %d, NF: %d, record: \"%s\"\n", NR, NF, $0 }' lines
NR: 1, NF: 2, record: "f1, r1|f2, r1 then 2 \n:"
NR: 2, NF: 1, record: "f1, r2 then 3 \n:"
NR: 3, NF: 2, record: "f1,r3|f2,r3 then 4 \n:"
NR: 4, NF: 2, record: "f1, r4|f2,r4 then 6 \n: "
NR: 5, NF: 1, record: "f1,r5"
不管有多少个\n分隔块,只要2个或更多,就是一个记录。
(使用gawk 可以通过设置RS="\n\n+" 而不是RS="" 获得完全相同的结果,因为gawk 支持正则表达式来分隔记录。感谢Ed Morton 指出POSIX awk 和gawk 之间的区别)
虽然perl 不支持使用正则表达式作为输入记录分隔符,但有两种方法可以设置等效段落模式。您可以使用-00 命令行开关或将输入记录分隔符$/ 设置为空字符串:
$ perl -00 -F"\n" -lane 'BEGIN{ $\=""; $,="|"}
printf "NR: %d, NF: %d, record: \"%s\"\n", $., scalar(@F), join($,,@F)' lines
NR: 1, NF: 2, record: "f1, r1|f2, r1 then 2 \n:"
NR: 2, NF: 1, record: "f1, r2 then 3 \n:"
NR: 3, NF: 2, record: "f1,r3|f2,r3 then 4 \n:"
NR: 4, NF: 2, record: "f1, r4|f2,r4 then 6 \n: "
NR: 5, NF: 1, record: "f1,r5"
或者,
$ perl -F"\n" -lane 'BEGIN{ $\=""; $,="|"; $/=""}
printf "NR: %d, NF: %d, record: \"%s\"\n", $., scalar(@F), join($,,@F)' lines
也可以——同样的输出。
Ruby 确实 具有段落模式,但与 Perl 和 awk 不同的是,它具有重要的行为差异。如果有超过 2 个 \n,则不会忽略 \n 的运行。它相当于 Ruby 中的正则表达式 /\n\n/ 与 awk 和 Perl 中的 /\n\n+/。它搞砸了同一输入上的字段计数和记录计数。
演示:
$ ruby -00 -F"\n" -lane 'BEGIN{$\=""; $,="|"};
printf "NR: %d, NF: %d, record: \"%s\"\n", $.,$F.length,$F.join' lines
NR: 1, NF: 2, record: "f1, r1|f2, r1 then 2 \n:"
NR: 2, NF: 1, record: "f1, r2 then 3 \n:"
NR: 3, NF: 3, record: "|f1,r3|f2,r3 then 4 \n:"
NR: 4, NF: 0, record: ""
NR: 5, NF: 2, record: "f1, r4|f2,r4 then 6 \n: "
NR: 6, NF: 0, record: ""
NR: 7, NF: 0, record: ""
NR: 8, NF: 1, record: "f1,r5"
所以当 Perl 和 Awk 认为它有 5 条记录和 8 个字段时,Ruby 的-00 段落模式认为相同的内容有 8 条记录和 9 个字段。
有没有办法让 Ruby 获得与 Perl 和 Awk 相同的结果?
【问题讨论】:
-
ruby -F"\n" -lane 'BEGIN{$/=""; $\=""; $,="|"; $i=1}; print "#{$F.join($,)}\t\t#{$i}\n"; $i+=1;' lines为我工作。使用相同的开关和输入/输出分隔符,Ruby 的行为很像 Perl。 -
@Stefan:Doh!请张贴。但是 - 请注意
-00的行为与使用 ruby 的$\=""不同,其中 perl 对每个都是相同的。
标签: awk gawk perl ruby bash perl awk record