如何匹配CR CR LF换行模式

时间:2019-02-10 08:19:43

标签: regex awk grep newline

在Windows 10环境中,我必须检查目录中有多少个CSV文件(分隔符为“;”)具有这种奇怪的换行模式:CR CR LF(如果愿意,可以使用\ r \ r \ n)。 但是,我无法将\r\r与grep或awk都不匹配。在awk上,我还尝试将RS更改为;,将FS更改为未使用的字符(#),但显然awk匹配单个CR,而不是CR CR 。因此,在Windows中,awk会将CR CR LF视为CR LF和FNR输出的记录数量等于任何其他“正常端线”文件。 奇怪的是,使用Notepad ++,我可以清楚地看到CR CR LF(例如,在Excel中造成额外的换行符),并且使用内置的正则表达式查找器,搜索\r\r\n与所有行匹配。是否可以在不删除某些CR的情况下强制awk对原始文本文件进行操作?
文件是这样的(我已经简化了一点):5行,其中4个字段用;分隔,每行CRCRLF的结尾。用Notepad ++(和Excel)打开,我看到10行。

我希望以下GNU awk脚本返回16 5

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

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

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

我相信这里已经发布了一个非常类似的问题: In Perl, how to match two consecutive Carriage Returns?

2 个答案:

答案 0 :(得分:1)

意识到存在重复(感谢@tripleee):

  

在MS-Windows下,gawk(和许多其他文本程序)在输入时将行\r\n转换为\n,在输出时将行\n转换为\r\n 。特殊的BINMODE变量(例如)可以控制这些翻译,其解释如下:

     
      
  • 如果BINMODE为“ r”或1,则在读取时设置为二进制模式(即读取时不进行翻译)。
  •   
  • 如果BINMODE是“ w”或两个,则在写入时设置二进制模式(即,写入时不转换)。
  •   
  • 如果BINMODE是“ rw”或“ wr”或3,则将二进制模式设置为读写模式。
  •   
  • BINMODE=non-null-stringBINMODE=3相同(即,读或写均不翻译)。但是,如果字符串不是“ rw”或“ wr”之一,gawk会发出警告消息。
  •   
     

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

要使awk保持其原始的POSIX风格,应使用BINMODE=3。使用awk(或任何未修改的版本),通过检查记录是否以\r\r结尾,您应该可以轻松地做到这一点。这是因为awk defaultly0使用RS="\n"在记录中拆分了一个文件。当GOW使用GNU awk时,您有以下选择:

计数文件:

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

计数文件并打印文件名:

awk '/\r\r$/{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}
     /\r\r$/{c++}
     END { print f,"files match" }' BINMODE=3 *.csv

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

答案 1 :(得分:0)

您可以尝试使用GNU grep的-z-P开关,请尝试以下操作:

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

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

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

我可以像这样在csv文件中搜索\r\r\n

> grep -zcP "\r\r\n" *.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 "\r\r\n" *.csv | awk -F: "$2{c++}END{print c}"
1

OR ,只需单独使用awk

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

因此,在以上grepawk示例中,都应读取整个文件,而不是每回合都处理每一行。