grep如何处理DOS换行符?CentOS/bash下命令结果疑问解析
咱们先把核心背景说清楚:Windows文本用的是CRLF(也就是\r\n,回车+换行)作为行结束符,而Linux/bash环境默认用LF(\n,仅换行)。这两种换行符的差异,就是导致你这几个grep命令结果不同的根本原因。
你的文件内容字节流是:a l i n e \r \n(也就是"aline"加上Windows换行符),下面逐个拆解每个命令:
1. grep aline file.txt → 输出aline
grep的逻辑是按行扫描,它把\n当作行的分隔符,所以读取到的行内容是aline\r(\n被当作分隔符去掉了,但\r留在了行内容里)。只要行里包含aline这个子串,grep就会匹配成功。
当grep输出匹配的行时,会自动加上Linux的换行符\n,所以最终输出的字节是aline\r\n。终端遇到\r(回车)时,会把光标移到当前行的开头,但因为后面没有其他字符覆盖,所以你看到的就是正常的aline。
2. grep aline$'\r' file.txt → 输出空行
这个命令是要匹配aline紧跟\r的字符串。实际上grep确实匹配到了(行内容就是aline\r),但输出的时候出了问题:grep输出的是aline\r\n(原行的\r加上自动添加的\n)。终端处理时,\r让光标回到行首,紧接着的\n让光标直接换行,导致原来的aline被“覆盖”了——看起来像是没有输出,其实是终端的显示效果欺骗了你。
3. grep aline$'\r'$'\n' file.txt → 输出空行
这个命令试图匹配完整的aline\r\n字节序列,但grep默认是按行处理的,它会把\n当作行的结束标记,不会把\n包含在行内容里进行匹配。也就是说,grep扫描到\n时就会认为这一行结束了,不会把\n和前面的aline\r放在一起作为匹配对象,自然找不到匹配项。
4. grep aline$'\n' file.txt → 输出aline
这里的$'\n'被bash解析为换行符,grep会在文件中查找aline紧跟\n的位置。虽然你的文件里是aline\r\n,但grep的行处理逻辑是:只要aline出现在某一行,而这一行的结束符是\n(不管行内容末尾有没有\r),就会匹配到。简单来说,grep把\n当作行的结束标志,aline在\n之前的行里,所以匹配成功,输出结果和第一个命令一样。
内容的提问来源于stack exchange,提问作者William

