前言
在做一个代码审查的小工具的时候,需要检测代码中是否有行尾空格,因此就想通过egrep来进行字符串匹配,匹配命令如下:
egrep ' +$' FILE
发现,有些文件明明行尾是有空格的,但是却就是匹配不到,本篇博客就是记录如何排查和解决该问题的。
排除中文影响
最开始的时候,怀疑是由于中文编码格式造成的问题,因此对于能够匹配成功的文件,做了以下测试:
$ file *.txt
ANSI.txt: ISO-8859 text
UCS2BE.txt: Big-endian UTF-16 Unicode text
UCS2LE.txt: Little-endian UTF-16 Unicode text
UTF8.txt: UTF-8 Unicode text
$ egrep ' +$' *.txt -l
ANSI.txt
UCS2BE.txt
UCS2LE.txt
UTF8.txt
即,egrep对于各种编码格式已经做了考虑,问题不在编码格式上。
寻找差异
通过file命令,我们发现了一下差异:
$ file *.txt
ANSI.txt: ISO-8859 text
bad.txt: UTF-8 Unicode text, with CRLF line terminators
注意,对于无法匹配成功的文件结束符是CRLF,而对于可以匹配成功的文件结束符则没有明确说明(通过Notepad++确认是LF)。
我们通过dos2unix命令,将文件转为unix格式后,发现可以使用egrep正确匹配:
$ dos2unix bad.txt
dos2unix: converting file bad.txt to Unix format ...
$ file bad.txt
bad.txt: UTF-8 Unicode text
$ egrep ' +$' bad.txt -l
bad.txt
因此,问题确认就是egrep在处理CRLF结尾的文件时无法正确匹配行尾。
解决方案
网上找到的资料也是先通过dos2unix对文件转换格式后,再进行匹配。但是在进行代码审查的过程是不能修改源文件的。
因此,我按照以下的思路来解决这个问题:
1. 将源文件进行dos2unix转码后,直接输出到标准输出上
2. 通过管道,对上面输出的内容进行egrep匹配
我首先查看dos2unix命令是否有输出到标准输出的参数,发现有-n参数,使用说明如下:
# -n, --newfile write to new file
# infile original file in new file mode
# outfile output file in new file mode
# e.g.: Convert a.txt and write to e.txt.
dos2unix -n a.txt e.txt
这里有一个问题,就是每次转换都需要一个临时文件,那么就存在:临时文件冲突以及需要删除临时文件的问题。而并没有直接输出结果到标准输出上的参数。
迂回一下,我发现dos2unix命令是可以接受管道输入的,即可以有以下的命令:
cat bad.txt | dos2unix
结合上面的egrep,最终的命令如下:
cat bad.txt | dos2unix | egrep ' +$'
而判断是否匹配成功,则可以通过$?来进行判断:
echo $?