Windows 的又一个坑:R writeLines() 函数的换行符

昨天,又被 Windows 坑到了。

事情的背景是,我的工作环境是 Windows 操作系统。由于一些众所周知的原因,有些事情在 Linux 下做起来比较顺当。于是,我就用 virtualbox 装了个虚拟的 Ubuntu。由于不熟,只用到其中很小一部分功能,所以,凡是能在 Windows 下做的事情,我绝不去 Ubuntu。

昨天,我要写一批 bash 批处理文件,打算在 Ubuntu 里运行。这批 .sh 文件结构格式相同,只是内容略有不同。于是,我就动了点小心思,用 R 语言批量写好了文件内容,最后用 writeLines() 函数生成了这批 .sh 文件。

前面我提到了,这些操作都是在 windows 下完成了。保险起见,我特地指定了 writeLines(useBytes = TRUE),来保证这批 .sh 文件的编码 UTF-8,心想这下应该没问题了吧。

但是,在 Ubuntu 里执行 这批 .sh 文件,居然出错!说什么文件找不到……

为了简化问题,我把从这批运行失败的 .sh 文件里面随便拎出一个,里面删得只剩两条指令:

cd ~
ls

然后另存为 test.sh 文件,用来测试。运行 test.sh,结果:

这么两条命令,居然还有错?

我记得在 Ubuntu 下直接写的 .sh 文件没这个问题啊。

那好,我就在 ubuntu 的文本编辑器里写了一个一模一样的文件,取名 test2.sh,内容也是只有这两条指令。然后运行,居然好了!

肉眼去看,两个文件都完全相同!我对比了一下两个文件的编码,都是 UTF-8。

这是遇见孙悟空和六耳猕猴了?

我祭出两面照妖镜:一个是 Totalcommander 的文本比较工具,一个是 notepad++ 的文本比较插件。比较的结果是,两个文件完全相同!

大惑不解。

使出浑身解数,都没有进展。万般无奈之下,想起这批 .sh 文件是用 R 的 writeLines()函数写的,那就去看看这个函数的帮助文件吧。

这一看,不打紧,竟发现一条惊人的线索。

Linux 的换行分隔符是LF, Windows 是 CRLF?

好像是有这么个印象。于是,我在 notepad++ 里打开了“显示所有符号”。

真相大白!

原来,因为我用 windows 下 R 语言的 writeLines()函数写的 .sh 文件,里面的换行符号是 CRLF,在 Linux 里执行时不认可,所以出现了错误。

F1 才是识别六耳猕猴的如来佛祖!

不仅是 R 函数。Windows 下普通的文本编辑器里,按回车键得到的换行符都是 CRLF

解决办法:同样的 R 代码,在 Linux 运行就可以了,生成的 .sh 文件没有任何问题。

知识点:

  1. R writeLines() 函数得到的文本文件,换行符取决于操作系统。
  2. Windows 下普通的文本文件编辑器,按回车键得到的换行符是 CRLF
  3. bash 批处理文件.sh 的换行符必须是 LF。如果是 CRLF,则无法执行,显示路径错误。

谨以此文,纪念又一次被 windows 坑了一下。

更新:

  • yihui 指出,Linux 下编写的 bat 文件是可以在 Windows 下顺利运行的。
  • rileyge 指出,Notepad++ 可以将换行符互相转换,方法是“编辑”–“档案格式转换”。

谢谢他们的帮助。

comments powered by Disqus