如何匹配CR CR LF换行模式



在Windows 10环境中,我必须检查目录中有多少CSV文件(分隔符为";")具有这种奇怪的换行模式:CR CR LF(或者\r\n如果您愿意)。然而,我既不能用grep也不能用awk匹配rr。在awk上,我还尝试将RS更改为;,将FS更改为未使用的字符(#),但显然awk匹配单个CR,而不是CR CR。因此,在Windows中,awk将CR CR LF视为CR LF,FNR输出的记录数等于任何其他"正常结束行"文件的记录数。奇怪的是,使用Notepad++,我可以清楚地看到CR CR LF(导致额外的换行,例如在Excel中),并且使用内置的正则表达式查找器,搜索与所有行匹配的rrn。如果不删除一些CR,就不可能强制awk对原始文本文件执行操作吗
文件如下(我稍微简化了一下):5行,4 x字段,由;分隔,每行末尾为CRCRLF。用记事本++(和Excel)打开,我看到了10行。

我希望下面的GNU awk脚本能返回16 5

BEGIN {RS = ";";FS = "#"; linecount = 0}
/rr/ {linecount = linecount + 1}
END {print FNR, linecount}

但是,它返回16 0。如果我搜索以匹配/r/,则获得16 5

所以基本上,我担心Windows CMD shell在将流传递给gawk之前会剥离两个连续CR中的一个(或者更好地说,是用LF替换CR-LF对),我想知道是否可以避免这种情况,因为我想用gawk来检测有多少文件有这个奇怪的CR-CR-LF换行符。

我相信这里已经发布了一个非常相似的问题:在Perl中,如何匹配两个连续的回车?

在意识到有重复后(感谢@triplee):

在MS Windows下,gawk(和许多其他文本程序)在输入时无声地将行尾rn转换为n,在输出时将n翻译为rn。一个特殊的BINMODE变量(c.e.)允许控制这些翻译,并解释如下:

  • 如果CCD_;r〃;或者一个,则在读取时设置二进制模式(即,在读取时不进行翻译)
  • 如果CCD_ 18是"0";w";或者两个,则在写入时设置二进制模式(即,在写入时不进行翻译)
  • 如果CCD_ 19是"0";rw";或";wr";或者三个二进制模式被设置用于读取和写入
  • BINMODE=non-null-stringBINMODE=3相同(即读取或写入时没有翻译)。然而,如果字符串不是";rw";或";wr">

来源:https://www.gnu.org/software/gawk/manual/gawk.html#PC-使用

要使awk保持其原始POSIX样式,您应该使用BINMODE=3。使用awk(或任何未修改的版本),您应该可以通过检查记录是否以rr结尾来轻松完成此操作。这是因为awk defaultly0使用RS="n"在记录中拆分文件。由于GOW使用GNU awk,您有以下选项:

计数文件:

awk '/rr$/{f++; nextfile} END {print f,"files match"}' BINMODE=3 *.csv

计数文件并打印文件名:

awk '/rr$/{f++; print FILENAME; nextfile} END {print f,"files match"}' BINMODE=3 *.csv

计数文件,打印文件名和行数:

awk '(FNR==1){if (c) {print fname, c; f++}; c=0; fname=FILENAME}
/rr$/{c++}
END { print f,"files match" }' BINMODE=3 *.csv

注意:在任何POSIX系统上删除BINMODE=3

你可以试试GNU grep的-z-P开关,试试这个:

grep -zcP "rrn" *.csv | awk -F: "$2{c++}END{print c}"

所以我创建了一个文件,就像你说的那样:

awk 'BEGIN{ORS="rrn"; OFS=";"; for(i=1;i<11;i++)print "aa","bb","cc",i>"strange.csv"}'

我可以在csv文件中搜索rrn,如下所示:

> grep -zcP "rrn" *.csv
file1.csv:0
file2.csv:0
file3.csv:0
file_a.csv:0
file_b.csv:0
results.csv:0
strange.csv:1

并与awk:结合

awk -F: "$2{c++}END{print c}"

获取计数:

> grep -zcP "rrn" *.csv | awk -F: "$2{c++}END{print c}"
1

,只需单独使用awk即可:

> awk 'BEGIN{RS="";}/rrn/{c++;nexfile}END{print c}' *.csv
1                                                    

因此,以上grepawk的例子,都是读取整个文件,而不是每转处理一行。

最新更新