将windows文本文件转换为linux格式

Wednesday, May 6, 2020

中文环境下,在Windows和Linux下创建的文本文件主要区别有两个

  • Windows行尾为 \r\n ,Linux行尾为 \n

  • Windows下中文使用GBK编码,Linux下一般是UTF-8

第一点可能导致不能识别换行,所有文本挤在一行, 但大部分文本编辑器都能够自动判断和处理(偏偏Windows自带的记事本不行)

第二点会导致中文乱码,虽然GBK正逐渐成为历史,但就我自己的体验来看,中文互联网上依旧存在大量GBK编码的文本文件

CR和LF

即“回车”(carriage return)和“换行”(line feed)

在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在 这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。 于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。 这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。

后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。 Unix/Linux 系统里,每行结尾只有“<换行>”,即“\n”;Windows系统里面,每行结尾是“ <回车><换行>”,即“\r\n”;Mac系统里,每行结尾是“<回车>”,即“\r”(现在已改成跟Unix/Linux一样的"\n")。

一个直接后果是,Unix/Linux/Mac系统下的文件在Windows里打开的话,会出现换行丢失,整个文本会乱成一团。(类似UltraEdit 这种编辑器可以正确识别); 而反过来就会出现^M的符号(这是Unix/Linux 等系统下规定的特殊标记,占一个字符大小,不是^和M的组合,打印不出来的,可以通过ctrl+V, ctrl+M 输入)。Unix/Linux 下很多文本编辑器(命令行)会在显示这个标记之后,补上一个自己的换行符,以避免内容混乱(只是用于显示,补充的换行符不会写入文件,有专门的命令将Windows换行符替换为Unix/Linux 换行符)。 Unix/Linux 系统下的换行符在Windows系统的文本编辑器中会被忽略,整个文本会乱成一团。 Windows 的换行是\r\n,十六进制数值是:0D0A。 Unix/Linux/OS X 的换行是\n,十六进制数值是:0A。

更多相关讨论参考这里

文件名

一些文件可能文件名也会乱码,使用convmv转换文件名编码

$ convmv -f GBK -t UTF-8 --notest file

如果不指定 --notest 则只会显示转换后的文件名但不会产生实际的修改

查看编码

file

file可以查看文件类型、编码和换行符,但对于GBK编码中英文混合的情况的识别似乎不太准确

$ file *.php
post.php:  HTML document, UTF-8 Unicode text
sort.php:  PHP script, ISO-8859 text, with CRLF line terminators

enca

相比之下,enca可以指定语言,识别效果比较好

$ enca -L zh *.php
post.php: Universal transformation format 8 bits; UTF-8
sort.php: Simplified Chinese National Standard; GB2312
  CRLF line terminators

显示enca支持的语言

$ enca --list languages
belarusian: CP1251 IBM866 ISO-8859-5 KOI8-UNI maccyr IBM855 KOI8-U
 bulgarian: CP1251 ISO-8859-5 IBM855 maccyr ECMA-113
     czech: ISO-8859-2 CP1250 IBM852 KEYBCS2 macce KOI-8_CS_2 CORK
  estonian: ISO-8859-4 CP1257 IBM775 ISO-8859-13 macce baltic
  croatian: CP1250 ISO-8859-2 IBM852 macce CORK
 hungarian: ISO-8859-2 CP1250 IBM852 macce CORK
lithuanian: CP1257 ISO-8859-4 IBM775 ISO-8859-13 macce baltic
   latvian: CP1257 ISO-8859-4 IBM775 ISO-8859-13 macce baltic
    polish: ISO-8859-2 CP1250 IBM852 macce ISO-8859-13 ISO-8859-16 baltic CORK
   russian: KOI8-R CP1251 ISO-8859-5 IBM866 maccyr
    slovak: CP1250 ISO-8859-2 IBM852 KEYBCS2 macce KOI-8_CS_2 CORK
   slovene: ISO-8859-2 CP1250 IBM852 macce CORK
 ukrainian: CP1251 IBM855 ISO-8859-5 CP1125 KOI8-U maccyr
   chinese: GBK BIG5 HZ
      none:

enca也能转换文件编码并且修改换行符

$ enca -L zh -x UTF-8 < origin_file > new_file

iconv和awk

如果你不想安装额外软件,也可以使用大多数发行版都会默认安装的GNU工具

用iconv转换文件编码

$ iconv -f GBK -t UTF-8 -o new_file origin_file

用awk修改换行符

$ awk 'sub("\r$", "")' origin_file > new_file

也可以反过来将Unix格式转换为Wiondos格式

$ awk 'sub("$", "\r")' origin_file > new_file

vim

vim也支持文件编码和换行符的修改

先用vim打开要修改的文件

$ vim file

如果你的vim没有配置好 fileencodings 可能会看到中文乱码,此时你可以

:e ++enc=gbk

现在你应该可以看到正常显示的文本

然后修改文件编码和换行符

set fileencoding=utf8 fileformat=unix

保存文件

w

更多细节可以参考vim的用户手册

:h usr_23.txt

参考:

linux

SUID、SGID 和 SBIT

C 和 Lua 取模运算的异同