我正在尝试编写一个脚本,它只会计算文件中\ r \ n \ r \ n的出现次数。 (以vim二进制模式打开示例文件会在适当的位置显示^ M字符,并且新行仍然作为换行符读取。)
无论如何,我知道有很多解决方案,但它们似乎没有让我得到我想要的东西。
e.g。 awk -e '/\r/,/\r/!d'
或使用$'\n'
作为grep语句的一部分。
然而,这些似乎都没有产生我需要的东西。我用grep的“技巧”找不到\r\n\r\n
模式,因为它只扩展了一个变量。 awk解决方案是贪婪的,因此让我获得比我想要/需要更多的行。
将grep切换为二进制/ Perl / no-newline模式似乎更接近我想要的,
例如grep -UPzo '\x0D'
,但我真正想要的是grep -UPzo '\x0D\x00\x0D\x00'
,它不会产生我想要的输出。
这似乎是一项如此简单的任务。
答案 0 :(得分:3)
默认情况下,awk将\n
视为记录分隔符。这使得计算\r\n\r\n
非常困难。如果我们选择其他记录分隔符,比如说一个字母,那么我们可以很容易地计算出这种组合的外观。因此:
awk '{n+=gsub("\r\n\r\n", "")} END{print n}' RS='a' file
此处,gsub
返回所做的替换次数。这些是相加的,在达到file
结束后,我们打印总数。
在这里,我们使用bash的$'...'
构造来显式添加换行符和换行符:
$ echo -n $'\r\n\r\n\r\n\r\na' | awk '{n+=gsub("\r\n\r\n", "")} END{print n}' RS='a'
2
我们可以告诉它将\r\n\r\n
视为记录分隔符,然后返回记录数的计数(减1):
cat file <(echo 1) | awk 'END{print NR-1;}' RS='\r\n\r\n'
在awk中,RS
是记录分隔符,NR
是记录数的计数。由于我们使用的是多字符记录分隔符,因此需要使用GNU awk。
如果文件以\r\n\r\n
结尾,则上述内容将被关闭。为避免这种情况,echo -n 1
语句用于确保文件中最后\r\n\r\n
后始终至少有一个字符。
在这里,我们使用bash的$'...'
构造来显式添加换行符和换行符:
$ echo -n $'abc\r\n\r\n' | cat - <(echo 1) | awk 'END{print NR-1;}' RS='\r\n\r\n'
1
$ echo -n $'abc\r\n\r\ndef' | cat - <(echo 1) | awk 'END{print NR-1;}' RS='\r\n\r\n'
1
$ echo -n $'\r\n\r\n\r\n\r\n' | cat - <(echo 1) | awk 'END{print NR-1;}' RS='\r\n\r\n'
2
$ echo -n $'1\r\n\r\n2\r\n\r\n3' | cat - <(echo 1) | awk 'END{print NR-1;}' RS='\r\n\r\n'
2