去除 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