![Awk 可以读取转义的换行符吗?即读取过去的换行符](https://linux22.com/image/7561/Awk%20%E5%8F%AF%E4%BB%A5%E8%AF%BB%E5%8F%96%E8%BD%AC%E4%B9%89%E7%9A%84%E6%8D%A2%E8%A1%8C%E7%AC%A6%E5%90%97%EF%BC%9F%E5%8D%B3%E8%AF%BB%E5%8F%96%E8%BF%87%E5%8E%BB%E7%9A%84%E6%8D%A2%E8%A1%8C%E7%AC%A6.png)
我的输入看起来像这样:
entry1line1
entry2line1\
entry2line2\
entry2line3
entry3line1
我想将此类输入读入 AWK 中的数组,然后将其与嵌入的换行符一起处理。那可能吗?最好不要使用 GNU 功能。
答案1
通过 posix awk,您可以使用 getline
awk '{while(/\\$/){getline tmp;$0=$0"\n"tmp}print "<LINE>"$0"<LINE>"}' file
只要最后一行以 结尾,就继续添加下一行\
。
<LINE>entry1line1<LINE>
<LINE>entry2line1\
entry2line2\
entry2line3<LINE>
<LINE>entry3line1<LINE>
Perl 中也一样
perl -ne '$_.=<> while /\\$/;chomp;print "<LINE>$_<LINE>\n"' file
答案2
使用 GNU awk:
$ awk '{printf "%s%s%s","line=",$0,RT}' RS='[^\\\\]\n' text
line=entry1line1
line=entry2line1\
entry2line2\
entry2line3
line=entry3line1
正如您所看到的,以 结尾的行\
连接到下一行。这是因为记录分隔符 RS
被重新定义为任何非反斜杠后跟换行符。换句话说,反斜杠-换行符不是记录分隔符。
这里的一个小技巧是记录分隔符吞掉了记录的最后一个字符。不过,该字符已为我们保存在内置变量中RT
。对程序进行轻微更改即可更正$0
代码开头的 值,从而使该问题消失:
$ awk '{$0=$0 substr(RT,1,1)} {print "line=",$0}' RS='[^\\\\]\n' text
line= entry1line1
line= entry2line1\
entry2line2\
entry2line3
line= entry3line1
RT
包含整个实际观察到的记录分隔符。在我们的例子中,这意味着它具有记录的最后一个字符和后面的换行符。因此,在上面的代码中,substr
用于将 的第一个字符添加RT
到 的末尾$0
。
答案3
您可以更改记录分隔符POSIXawk
通过改变RS
. POSIX 没有指定是否可以是正则表达式,只说
使用多字符 RS 值的未指定行为是允许将来可能基于用于记录分隔符的扩展正则表达式进行扩展。历史实现采用字符串的第一个字符并忽略其他字符。
但是,您可以将整个文件作为字符串读取(通过选择不太可能的RS
),或者使用getline
,查看行尾并根据需要将结果拼接在一起。
答案4
这Perl 食谱有一个如何使用 perl 执行此操作的示例。
我已经调整了该示例以使用<>
(stdin 和/或在命令行上作为参数给出的任何文件名)而不是命名文件句柄,并且还保留了延续后的换行符\
(这有点不寻常) - 更常见的情况是希望将连续行视为长行,连续行要么不连接,要么不连接空格字符)。
perl -e '
$count=1;
while (defined($line = <>) ) {
chomp($line);
if ($line =~ s/\\$//) {
$line .= "\n" . <>;
redo unless eof();
}
# process full record in $line here
printf "%04i:\"%s\"\n\n", $count++,$line;
}' willdavies.txt
$line
您可以在评论后做任何您想做的事情# process full record...
。我选择将每一行打印为带有零填充行计数器的单独段落。我还添加了引号,$line
以便您可以准确地看到其中的内容$line
(以及不包含的内容)。
输出:
0001:"entry1line1"
0002:"entry2line1
entry2line2
entry2line3"
0003:"entry3line1"