马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
一、报错长什么样
在 Linux 里跑 Shell 脚本,有一种非常常见的错误提示:
-bash: ./xxx.sh: /bin/bash^M: bad interpreter: No such file or directory
注意报错里的那个 ^M——它不是打错的字,而是回车符(CR)在终端里的显示形式。看到这个符号,基本就能断定是换行符问题,不用再往库、权限、解释器路径上去猜。
二、为什么会这样:CRLF 和 LF 的差别
根源是两套系统对「一行结束」的写法不同:
- Windows:文本文件的行尾是回车符(CR)+ 换行符(LF)的组合,合称 CRLF;
- Linux / Unix:行尾只有换行符(LF)。
在 Windows 环境下写(或编辑)Shell 脚本,文件存下来是 CRLF 行尾;把它搬到 Linux 上执行时,Linux 把行尾那个多余的 CR 当成了命令的一部分,于是 #!/bin/bash 这行的解释器路径变成了 /bin/bash^M——路径不存在,自然报 bad interpreter。 这就是这个错误最典型的触发场景:脚本在本地 Windows 写好,rsync / scp / git 同步到服务器,一键就炸。
三、一行命令解决:用 sed 删掉回车符
最简单的办法是用 sed 把脚本里的回车符去掉:
sed -i 's/\r$//' xxx.sh
这条命令在做什么,拆开看:
-i:in-place,原地修改文件,不另存新文件;
s/\r$//:替换——查找每一行末尾的回车符 \r$,替换成空(也就是删掉);
xxx.sh:目标文件。
执行完,文件就从 CRLF 转成纯 LF 的 Unix 风格行尾,那个 ^M 消失,再跑一次 ./xxx.sh 就正常了。这一步能解决九成以上的 bad interpreter。
四、验证到底改干净没有:file 和 cat -A
改完别急着跑,先看一眼文件现在的行尾属性:
file xxx.sh
cat -A xxx.sh | head
file 输出里带 CRLF line terminators 说明还没改干净;显示 LF line terminators 才是 LF。用 cat -A 看,行尾应该只剩 $,还带 ^M$ 的就是还有残留。
五、批量处理:一整目录脚本一起修
如果同步过来一整个项目的脚本,一个一个敲太慢,用 find 批量:
grep -rlI $'\r' ./scripts/ | xargs sed -i 's/\r$//'
grep -rlI 先挑出含回车符的纯文本文件(-I 会自动跳过二进制),再交给 sed 逐个处理。先 grep 过滤这一步别省,否则误伤二进制文件(图片、jar)会更麻烦。
六、注意两件事
- 动手前先备份。 运行
sed 之前最好留一份原文(cp xxx.sh xxx.sh.bak 或进版本库),万一改错了还回得去。
- 从源头解决更高效。 如果经常要在 Windows 和 Linux 之间编辑运行 Shell 脚本,用支持「Unix/LF 行尾格式」选项的编辑器(Visual Studio Code、Notepad++ 等),保存时就指定 LF,比事后批量 sed 省事得多。 顺带一提,
git config core.autocrlf input 也能在提交环节避免把 CRLF 带进仓库,团队里推荐统一配一下。
七、顺带认识另外两个「换行符坑」
同一个根因还会衍生出两个相似但不同的症状,别混淆:
^M: command not found:CR 被当成了命令名的一部分,说明还有行尾残留没清干净;
- 脚本能跑但输出多了空行:一般不是 CR 问题,是 heredoc 或 echo 写法带多了换行,跟本条无关。
八、一句话结论
看到 /bin/bash^M: bad interpreter,就是行尾带了 Windows 的回车符。用 sed -i 's/\r$//' 脚本名 清一遍,或者以后保存时直接选 LF,問題就断根了。
(本文由 qidao123.com企服评测-应用市场 编辑提示整理:示例基于 GNU sed / coreutils 环境,适用于 CentOS / Ubuntu / openEuler 等 Linux 发行版的 Shell 脚本排障。批量处理前请先备份。) |