那天项目部署的时候,遇到一个很诡异的现象,一度怀疑本身职业生涯到此结束了,后面经排除发现,原来是
Linux
和Windows
下shell
脚本换行符的格式问题,致使脚本一直执行不了...(到此,标题所说的事故讲完了...:)html
看起来很蠢的问题,溜了 :) ...但莎士比亚说过,解决一个问题最好的方式,就是下次不要再犯了。因此咱们刨根问底儿,完全搞清楚换行符在计算机系统中究竟是个啥玩意儿。linux
在计算机出现以前,有一种通讯设备叫电传打字机(Teletype Mode),每秒输出10个字符,平均每一个字符0.1秒,但有个问题,就是打完一行换行的时候,要消耗0.2秒,在这个时间段内,若是有新字符传来,就将丢失,因此有人为了解决这个问题,在每一行后面加两个字符表示该行结束。shell
那这里就涉及到两个动做:vim
后面这个概念就被搬到了计算机系统上,But,有人的地方就有分歧,各大系统开始秀了。bash
Windows
系统里,每行结尾是回车+换行(和上述提到的两个动做一致),\r\n
;Unix
系统,每行结尾只有换行\n
;Mac
系统,每行结尾只有换行\n
;PS:老
MAC
系统用的\r
,如今的MAC
都是用的\n
,和Unix
一致了。运维
不一样系统之间的换行规则的不一样,致使不一样系统下的文件交叉使用的时候,存在不一致,好比最多见的,Unix/Mac
系统下的文件在Windows
里打开,全部文字会变成一行,缘由显而易见。编辑器
二进制 | 十进制 | 十六进制 | 字符/缩写 | 解释 |
---|---|---|---|---|
00001001 | 9 | 09 | HT (Horizontal Tab) | 水平制表符 |
00001010 | 10 | 0A | LF/NL(Line Feed/New Line) | 换行键 |
00001011 | 11 | 0B | VT (Vertical Tab) | 垂直制表符 |
00001100 | 12 | 0C | FF/NP (Form Feed/New Page) | 换页键 |
00001101 | 13 | 0D | CR (Carriage Return) | 回车键 |
00001110 | 14 | 0E | SO (Shift Out) | 不用切换 |
咱们一步步来实践下上述说的,测试环境是
Windows
和Linux
。post
Windows
下新建个win.txt
文件,写一句大白话。上面有听讲的同窗应该知道,这里的换行符为CRLF
。talk is cheap,
show me your code.
复制代码
Linux
系统用vim
打开刚新建的文件这看起来不是挺正常的么?和Windows
上显示的同样啊。注意这里vim
查看文件的时候,会检测换行符,若是全部的换行符都是CRLF
,那么它会自动以dos
格式来显示文本内容,最下面[dos]
里也体现了这一点。测试
dos
(Disk Operating System 磁盘操做系统)和Windows
同样采用的是CRLF
spa
cat -A
选项查看文本全部的字符能够看到多了^M$
,^M
这是Linux
等系统下规定的特殊标记,占一个字符大小,不是^
和M
的组合,只能用Ctrl+v,Ctrl+m
按出来;而$
不是换行符,能够理解为Linux
下用来表示文本结束EOF的符号。
cat -v
选项显示出非打印字符sed -i '1s/^M//' win.txt
复制代码
看到第一行的^M
不见了,第二行仍是保留。
结果展现vim
中多了^M
这个符号,左下角也没了[dos]
的标识,这里回应了第二点提到的现象,表示vim
用Linux
来显示文本内容。
到这一步为止,咱们证明了Windows
和Linux
环境下不一样换行规则带来的差别。
看到社区里的小伙伴作了这个尝试,便参考着作了下,能够直观体现什么是“回车”。
cat -A
查看全部字符sed -i '1s/.*/& ypm/g' win.txt
在第一行末尾加上ypm
.*
匹配整行的时候,不包括换行符^M
,因此ypm
加在了第一行的末尾cat
正常查看文本的时候,发现一件奇怪的事情,ypm
覆盖了talk
,怎么解释?咱们要知道
cat
普通模式下输出文本内容,会将^M
理解为回车。
这就能够解释了,遇到回车符,就像打印探头从右回到了左,ypm
这里的四个字符,恰好覆盖了talk
四个字符。这就直观解释了什么是回车。
谈到如何规避这个差别,其实不一样方向上有不一样方法,好比针对^M
、强制转换文本格式,但我的以为,能解决其根本问题的,仍是在不一样系统间,代码编辑的时候,注意到这个格式问题,各大IDE都有本身的解决方案。
cat -v win.txt | tr -d '^M' > linux.txt
或者
cat win.txt |tr -d '\015' > linux.txt
或者
cat win.txt |tr -d '\r' > linux.txt
复制代码
vim 编辑器中输入
:%s/^M//g
或者
:set fileformat=unix
复制代码
dos2unix win.txt
复制代码
\r
:CR(carriage return)\n
:LF(line feed)Windows
系统遵循最原始的规则,即必须知足回车符+换行符,缺乏或者顺序调换都不可,即\r\n
Unix
系统中遇到换行符\n
就会进行回车+换行的操做,而回车符\r
会做为特殊字符^M
显示没想到这么简单的问题,扯了这么多,其实不少小伙伴也都遇到过这个问题,社区里也常常有由于换行符致使的“血案”,但愿没有所以酿成以前那个程序猿小哥手误致使的几千万的损失。在运维、DB等领域,这些“小问题”可能会被放大,所以仍是须要引发重视,虽然有不少规避手段,但在代码编写的初期,就应该养成习惯关注到这一点,排查问题的时候这一样是一个方向。
PS: 可能会有不严谨的地方,也欢迎你们讨论,轻喷...