去除 vi/vim 和 git diff 中的 ^M 问题解决办法
- 问题现象
- 初步分析
- 进一步查看
- 问题解决
- Source Insight
- dos2unix
- Nodpad++
- Vim
- sed 命令
- 综上
- Reference
问题现象
git diff 时发现下面的情况,新修改的代码之处都是携带 ^M 字符,

初步分析
肯定是因为 Windows 和 Linux 系统之间换行符标准不同导致的。
- CR(Carriage Return):ASCII 码中的控制符,代表回车。意思是将光标移到当前行的首位。用转义序列
"\r"表示; - LF(Line Feed):ASCII 码中的控制符,代表换行。意思是代表一行文本的结束,将光标移到下一行,用转义序列
"\n"表示。
- Windows 系统采用 CRLF(回车+换行)表示下一行,即
"\r\n"; - Linux/UNIX 系统采用 LF 表示下一行,即
"\n"; - MAC 系统采用 CR 表示下一行,即
"\r";

进一步查看
通过 vim 打开查看文件,设置 :set list 进一步查看,没看出差异。

再查看文件类型,显示如下:
file fileName.c
fileName.c: C source, Unicode text, UTF-8 text, with CRLF line terminators
上面可以明显看出提示有 CRLF 结束UTF-8 格式文本。
再次通过 cat -A fileName 命令查看文件内容如下,原来,整个文件全都是携带 ^M 字符。

若使用 od 命令(输出指定二进制、八进制、十六进制或其它格式编码的字符)查看文件内容截图如下:
od -tc fileName

通过 od 命令查看,可以很清晰的看到 CRLF(回车+换行)符号。
问题解决
既然已经定位出问题,那么接下来就是看怎么修改文本行结尾 ^M 控制字符。
本篇针对不同场景,有不同解决办法。
Source Insight
依次选择【Options】->【Preferences】->【Files】->【Other】->【Default line ending:】选择 Unix(LF) 即可。

dos2unix
直接使用 linux 工具 dos2unix
dos2unix fileName
Nodpad++
依次选择 【编辑(E)】->【文档格式转换(E)】->【转为 Unix(LF) 】

Vim
前面提到直接使用 vi/vim fileName 是没看到 ^M ,但是通过 cat -A fileName 命令是可以看到 ^M 。 因此这里需要使用 vim -b fileName 命令来查看。
vim -b fileName
:% s/^M$//g #vim 底线命令模式(Last line mode)
:% s/^M//g #vim 底线命令模式(Last line mode)
:% s/\r//g #vim 底线命令模式(Last line mode)
注意:上面的 ^M 需要通过 CTRL+V 和 CTRL+ M ,即按住CTRL键,然后依次按下 V 和 M 键。
sed 命令
sed 命令同上面的 vim 方式基本一样,只是命令行的差异。
sed -i s/^M$//g fileName
sed -i s/^M//g fileName
sed -i s/\r//g fileName
综上
综上是几种解决 ^M 问题的办法。
想必仔细阅读的读者心里会有一个小的疑问,为何最后的两种方式中, ^M 可以用 \r 替换呢?
这是因为,前面描述 ASCII 和 回车、换行符之间关系的时候提到:
- CR,用转义序列
"\r"表示; - LF,用转义序列
"\n"表示; - CRLF,用转义序列
"\r\n"表示;
我们在 Linux 环境中使用 bash 查看文本,在文本行结尾通常会看到(显示)$、 ^M$,其中 ^M 就表示回车(CR,用转义序列 "\r" 表示),$ 表示换行(用转义序列 "\n" 表示)。即:
"\r"在类Unix系统下会被显示为^M;"\n"在类Unix系统下会被显示为$
So,读者认为命令行中的 "\r" 和 ^M 是否可以相互替换呢?
Reference
ASCII 表
Ascii码表
How to remove CTRL-M (^M) characters from a file in Linux
What is the ^M character called?
https://www.jianshu.com/p/cff726d86978



















