Fork me on GitHub

Unix和Windows中文本行末结束符

目录

  • 背景
  • 第一部分 回车和换行
  • 第二部分 兼容性问题解决
  • 参考文献及资料

背景

或许你遇到过这样的坑。当你信心满满将自己编写的程序文件或配置文件上传到生产环境(linux),却发现无法运行或者生效。但是明明在本地(Windows)测试运行没有问题。那么很大几率遇到文本行末结束符的坑。

Unix和Windows中文本行末结束符是不同的。本文将详细讲解这个坑的背景、产生原因和解决办法。

第一部分 回车和换行

1.1 历史背景

关于回车(Carriage Return)和换行(Line Feed)的来历,需要从英文打字机讲起。在机械英文打字机中有个叫“字车”的部件,每打印一个英文字符,“字车”前进一位。但是纸张每行是有限制的,打满一行后,“字车”需要重置回到起始位置。从机械角度看,打印机有两个响应动作:(1)“字车”归位;(2)纸张的滚筒上卷一行,开始新的一行。这里“字车”归位就是“回车”,而滚筒上卷一行就是“换行”。

到了电传打印机时候,需要使用控制字符来通知打印机执行非打印操作的指令(回车(CR)和换行(NL))。而在ASCII码中分别使用\r(值13)和\n(值10)表示。

再后来计算机发明后,两个概念也就被搬到计算机中(计算机通常需要和打印机交互,保持兼容性)。考虑到当时存储资源的昂贵,就有人提出来文本中使用两个操作符表示行末结束较为浪费,于是分歧就产生了。

1.2 分歧

目前主流操作系统(Unix、Windows、Mac)中分歧如下:

操作系统 系统行末结束符 备注
UNIX \n
window \n\r
MAC OS \n v9 之前 Mac OS 用 ‘\r’

注:从2001年3月发布的Mac OS 10.0开始,系统行末结束符采用”\n”。

这种分歧就导致不同操作系统之间兼容问题。

第二部分 兼容性问题解决

这种兼容问题通常发生在:不同操作系统之间传输纯文本文件。

  • Unix/Mac系统创建的文件在Windows里打开,文字会变成一行。因为没有\r
  • Windows里的文件在Unix/Mac下打开的话,在每行会多出一个^M符号。多了\r

2.1 Windows文件上传Linux问题

我们经常遇到的问题是:Windows下编写的Shell脚本或者Python脚本,放到Linux下执行会出错。通常上传文件前,使用UEUltraedit)或者Nodepad++来转换。

  • UE中,执行“File->conversions->Dos to Unix”,将文件中\n\r转换成\n

  • Nodepad++中,执行“编辑->档案格式转换->转换为UNIX格式”。

上传到Linux后还可以使用下面的命令查看是否准确:

1
cat -v test.txt

如果每行换行处都有^M,这说明仍然是Windows下的文本文件。

注:cat -A命令:显示不可见字符。如换行符显示为“$”,TAB 显示为^I等。在这种模式下,回车(\r)字符将显示为^M

可以使用下面的命令进行统一替换:

1
sed -i 's/^M$//g' test.txt

另外还有专用命令dos2unix(如果操作系统没有改命令需要安装一下)。

1
dos2unix test.txt

最后还可以使用vi打开文件,输入:set fileformat=unix,回车。最后保存退出即可。

2.2 Linux文件上传Windows问题

在Windows中使用Ultraedit或者Nodepad++文本编辑器查看Linux文件,而不是系统自带的记事本。

2.3 FTP中传输问题

FTP软件在传输文件的时候,通常有两种模式:文本模式(ASCII模式)和二进制模式(BINARY模式)。两种模式的区别就是行末结束符的处理,BINARY模式不会对数据进行任何处理。而ASCII模式将行末结束符转换为本机操作系统的行末结束符。例如Windows系统将文本文件上传至Linux,就会将\r\n替换成\n

在使用过程中需要注意两种模式的差别。特别的上实际生产环境上线投产过程中建议统一使用二进制模式,避免FTP对文件进行转换。

2.4 编程语言中

  • Python 使用 “Universal Newline“ 处理这个问题。文本使用 open() 方法打开时,会对行末结束符进行识别并一致处理成 ‘\n’,在文件写入的时候,使用 write(‘\n’) 即可,Python 会根据当前程序执行的操作系统自动处理。
  • Java中行末结束符使用下面的函数方法统一处理:
1
System.getProperty("line.separator")

参考文献及资料

1、Line_feed,链接:https://nl.wikipedia.org/wiki/Line_feed

0%