CR 与 LF 换行符

前言

你是否知道不同操作系统,诸如:windows系列、unix系列的换行符(回车)的差异?

你是否在使用git时,配置过core.autocrlf参数?

换行符的差异对你项目开发的有什么影响?

接下来,以工作中采坑的一个列子,来回答上述三个问题。

 

背景

开发环境说明:windows+virtualbox虚拟机+虚拟机里面运行的ubuntu+ubuntu里面装的docker,编辑代码是直接在windows上使用phpstorm编辑,代码目录被挂载到了虚拟机的共享目录上,从而实现了类似文件自动同步映射,达到了在windows上编程,在linux下运行的目的!

今天拿到武汉同事提供的一个php后端项目的镜像,里面包含了openresty+php-fpm,我针对-v挂载目录参数做了自定义调整了后(因为别人的-v对应宿主机的源目录、容器内映射目录是别人的命名风格),始终docker run运行不起,准确来说应该是运行完毕,容器马上退出。

容器启动命令如下:

docker run -p 8622:8080 -e RELEASE=test --env-file /home/insight/env/pre.env -v /c/users/docker-files/insight-v2/v2-killbox:/home/work/app --name=insight-tracking -d harbor.inf.avlyun.org/inf/v2-killbox:rb-1.0.2

查看容器报错如下:

root@ubt-docker:/home/insight/env# docker logs c06bd7ff978b

: invalid optionntrypoint.sh: line 2: set: -

set: usage: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]

emmm,乍一看,真的看不出所以然,字面意思“脚本非法”,但是对应的脚本貌似名字不对,实际上容器启动后,会执行entrypoint.sh的脚本,用于针对laravel项目基于容器挂载的env环境变量配置,把这些配置替换到laravel的.env文件中!

尝试解决:

其实之前在构建自定义的nginx 支持https协议的镜像时(nginx默认配置没有https,以及没有开启openssl的支持),也遇到过同样的问题,最终解决是在Dockerfile中ENTRYPOINT以 /bin/bash结尾。但是该镜像在武汉同事的开发机上能正常运行,说明镜像本身是没有任何问题的!

请教了公司大佬,表明是容器启动时,会执行entrypoint.sh脚本,这个脚本也是放在git代码仓库里面的,报错的字面意思大概是shell脚本的文本解析有误!导致脚本运行失败,容器退出!大佬初步猜测是git关于换行的设置有误,导致虚拟机的脚本的换行符不是LF。(不愧是大佬,定位问题真的是稳准狠)

然后我本地git bash关于换行符设置是:

$ git config --global -l

user.name=wangzhiping

user.email=wangzhiping@antiy.cn

core.autocrlf=true

http.lowspeedlimit=0

http.lowspeedtime=999999

 

关于core.autocrlf参数额外涉及的知识点:

1.什么是CRLF和LF

CRLF 是 carriage return line feed 的缩写;中文意思是 回车换行。是windows下的换行符,对应文本符号是^M$

LF 是 line feed 的缩写,中文意思是换行。是linux下的换行符,对应的文本符号是$

2.autocrlf参数的含义

autocrlf = true 表示要求git在提交时将crlf转换为lf,而在检出时将lf转换为crlf。

autocrlf = false 表示提交和检出代码时均不进行转换

autocrlf = input 表示在提交时将crlf转换为lf,而检出时不转换

前情提要:我本地是win10,上面安装了virtualbox,开发环境是docker,docker是跑在虚拟机里面的。通过virtualbox的共享文件夹功能,做了windows下的特定目录与虚拟机的目录映射;映射后文件会双向自动同步,从而达到我在phpstorm编辑代码,变动会同步到虚拟机的代码目录!之前的s9的php脚本也是CRLF,但是却能正常执行,为啥shell脚本就不行呢?

那么,如何证明我虚拟机里面的entrypoint.sh的换行符是CRLF呢?

进入虚拟机,vi entrypoint.sh,得到:(这个脚本实际位置是windows的项目目录,通过vi打开的是映射到虚拟机下的共享目录文件,实际上是同一份文件)

如果我们想看一下每一行的结尾的换行符到底是什么符号呢,如何在vi里面显示换行符?

执行:set list

 

结果是"$",看到这里会不会有点蒙蔽,$就代表换行符是对的,那为啥entrypoint.sh没有被正常解析,这就矛盾了!

稍安勿躁,问题在于我们第一次打开entrypoint.sh的时候,左下角的[dos]符号,就已经告诉我们这个脚本是CRLF的换行模式了。

如何证明[dos]只会在打开CRLF换行模式的文件时,显示!

那我们直接在虚拟机里面,vi test.sh 新建一个shell脚本,随便输入一些信息,退出保存,再次打开得到的效果如下:

 

既然我们当前的entrypoint.sh是CRLF,那么只要我们改成LF,保障entrypoint.sh能被正常执行,是不是就能运行容器了?

那么如何修改文本的换行模式?在phpstorm里面直接点击编辑器右下角,就可更改!但是这种方式只能改一个文件,不能全局批量更改,改了之后,git会把你的改动视为一次变更,git status会发现该文件被改了(因为换行符被修改,换行符也算是代码的一部分)

 

进入虚拟机,再次执行:vi entrypoint.sh得到:

 

最后执行:

docker run -p 8622:8080 -e RELEASE=test --env-file /home/insight/env/pre.env -v /c/users/docker-files/insight-v2/v2-killbox:/home/work/app --name=insight-tracking -d harbor.inf.avlyun.org/inf/v2-killbox:rb-1.0.2

容器启动成功:

 

反思:

1.phpstorm打开文件,在右下角切换换行方式,这种设置方式,重启编辑器后,换行模式不会重置,相当于已经把文本的行末的换行符替换了一次,但是这种方式只能改当前文件!

如何改变整个项目的所有文本文件的换行模式呢?有没有简单的方式,难不成一个文件一个人间的去转换换行格式?

这种全局的设置方式,只能保证在编辑器内新建文本时,换行模式与设置选项保持一致!

问题是,现在本地仓库已经存在了,代码文件很多,想要变更的最简单的方式,如何批量变更换行符?

我选择的做法是,删除本地仓库,修改git的全局配置,重新拉取代码,让拉下来的代码统一为LF

变更换行模式:git config --global core.autocrlf false

2.为啥用以前用php,使用的CRLF,php脚本依旧能在虚拟机正常解析呢?不存在shell脚本的换行符错误导致解析失败的问题?!

难道是因为php脚本虽然是脚本语言,是解释执行,但实际上在执行前,源码有一个编译过程,zend引擎会把php编译成opcode?再交给zend虚拟机解释执行!

猜测是不是在编译成opcode的环节,对换行符做了适配,忽略了LF和CRLF的差异?

3.不借助编辑器,如何在linux下直接更改换行模式?

结语

希望大家看了这篇文章后,能让你对CR 与 LF 换行符有更深刻的认识。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值