Coding 极简派

CRLF vs LF

Windows/Unix line ending

最近在帮金融系的教授做研究助理,帮教授写程序.有编程基础的教授化身产品经理的模样,不断地抛出需求.我要做的就是为教授的金融模型或者理论做大量的数据处理,于是写了不少python和shell scprits. 有时教授会形成习惯了甚至把我当IT使用,死机窗口卡顿的时候呼唤我…..不过被信任还是很荣幸的.

然而出现了这样一个问题.

我在 Mac上写好的shell script并且写过小测试试了下发给教授,教授run的时候却出现syntax error,could not find expecting…bla bla…

第一个反应当然是自我怀疑地重新run了我本地的script.Bam! Nothing is wrong!然后怀疑教授,让教授重新下载脚本重run. The same problem…..然后我就和见鬼了一样看着两台机子上的script大致比对…”shell不可能有indentation的问题啊…then what’s wrong? “,然后我想到那些诡异的隐藏符,比如换行之类的,然后快速在教授机子上重写了一遍script,save it and run. Went smoothly as expected.

一个肉眼不可见的问题,我想起了那些诡异的隐藏符.那么可能就是操作系统带来的差别,我查了mac本地的文件类型是unix.

Cited from stackoverflow

1
2
3
4
5
6
7
From samjudson:
>This is only a difference in text files, where UNIX uses a single Line Feed (LF) to signify a new line, Windows uses a Carriage Return/Line Feed (CRLF) and Mac uses just a CR.
Cebjyre elaborates:
> OS X uses LF, the same as UNIX - MacOS 9 and below did use CR though.

Found our Murderer

在不同的机器上写出的text file的line ending是不同的,windos/dos 机上为”\r\n”,而Unix/Linux 只有”\n”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
unix
LF only (each line ends with an LF character).
Unix based systems and Mac OS X and later.
---
dos
CRLF (each line ends with CR then LF).
DOS and Windows.
---
mac
CR only (each line ends with a CR character).
Mac OS version 9 and earlier
later becomes LF
CR is carriage return (return cursor to left margin), which is Ctrl-M or ^M or hex 0D.
LF is linefeed (move cursor down), which is Ctrl-J or ^J or hex 0A. Sometimes, LF is written as NL (newline).

Conversion between CRLF and Just line feed

  1. 查找替换.
    这是最直觉的方法.可以利用自己偏好的Editor查找替换,或者用一些智能的功能.
    比如在Vim里可以用:set ff?来查看fileformat. 这里的ff(fileformat 的缩写)是局限于当前buffer的,当文件被读入的时候被Vim赋值,或者可以在command line中指定,fileformat决定了buffer怎样读入一个文件(包括对line ending进行相应的修改),以及可以通过改变fileformat的值对buffer写文件的格式进行修改 :set fileformat=dos/unix/mac

    同时还有一个fifleformats的全局选项,是在没有特殊指定的时候vim将按照这些顺序去read这个文件,在mac上会显示fileformats=unix,dos
    文件格式的问题会出现^M的乱码,用:e ++ff=dos 去掉.
    手动的话可以:%s/^V^M//g

    还有一种看到的办法是(未亲测)Notepad++ Edit -> EOL Conversion 里面有已经准备好的选项可以用

    然而简单的查找替换的速度有限,在文件不大的时候可以考虑

  1. 现有工具

    • 可以用FTP, 在传输之前先敲ascii,会被转换成ascii文件格式,当传到另一个host上时会用合适于它的的格式打开
    • dos2unix 和 unix2dos, 在unix平台上装上可以使用

      dos2unix winfile.txt unixfile.txt
      
      unix2dos unixfile.txt winfile.txt
      
    • 还有一些脚本方法,没有试过,暂时写在这里

      # 只可以转unix
        tr -d '\15\32' < winfile.txt > unixfile.txt
      
# awk
  awk '{ sub("\r$", ""); print }' winfile.txt > unixfile.txt
  awk 'sub("$", "\r")' unixfile.txt > winfile.txt

# perl
  perl -p -e 's/\r$//' < winfile.txt > unixfile.txt 
  perl -p -e 's/\n/\r\n/' < unixfile.txt > winfile.txt
  1. A simple trick
    直接拖进chrome/firefox 然后剪切粘贴即可以解决这个问题……仿佛看到了一位生活小能手的同学
xubing wechat
奇闻共欣赏,疑义相与析.欢迎来我的微信公众号