背景
在搭建某项目CI环境过程中,在Windows下写了个shell脚本,通过winscp传到了gitlab runner
所在的Linux工作站上,在工作站上执行该shell脚本时报错:1
/bin/bash^M: bad interpreter: No such file or directory
知识
错误信息指出,脚本在试图查找位于/bin/bash^M
处的解释器时出错:文件或目录不存在。事实也确实如此,目标解释器应该是/bin/bash
。^M
表示回车符(Carriage Return,CR)。
回车符\r
本义是光标重新回到本行开头,r的英文return,控制字符可以写成CR
,即Carriage Return,十六进制表示为0x0D
;换行符\n
本义是光标往下一行(不一定到下一行行首),n的英文newline,控制字符可以写成LF
,即Line Feed,十六进制表示为0x0A
。EOL
(End of Line)是CR
和LF
的组合,表示到下一行并把焦点移到第一列。
在不同的操作系统这几个字符表现不同:
- 在Windows系统下,
\r
\n
这两个字符就是表现的本义,即用EOL
作为行结尾符; - 在类Unix系统下,
\n
表现为光标下一行并回到行首,即用LF
作为行结尾符; - 在Mac系统下,
\r
表现为回到本行开头并往下一行,即用CR
作为行结尾符。
至于ENTER键的定义是与操作系统有关的,通常用的Enter是两个加起来。
现实中的具体表现是:
- Unix/Mac系统下的文件在Windows下打开的话,所有文字会变成一行;
- Windows下的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个
^M
符号。
解决
删除Windows环境下编辑的脚本中的多余\r
回车符:1
sed -i -e 's/\r$//' script.sh
关于Linux中sed
命令的使用,可参考此前的一篇文章:《Linux中使用sed命令进行字符串查找和替换》。
参考
- Not able to execute a .sh file: /bin/bash^M: bad interpreter
- The differences between Carriage Return(CR) and Line Feed(LF)
- 关于换行符CR(Carriage return) 和 LF(line feed) 的区别