上图是 test3.sh 的内容
但是 ./test3.sh 却报错
# ./test3.sh
zsh: ./test3.sh: bad interpreter: /bin/bash^M: no such file or directory
你这个错误
主要是因为脚本文件里有 Windows 风格的换行符 (CRLF, ^M
)。
在 macOS / Linux 上脚本需要使用 Unix 风格换行符 (LF)。
解决方法有几种:
方法 1:用 dos2unix
转换
方法 2:用 sed
删除 ^M # OK 有大用
完全OK 的写法是 sed -i '' $'s/\r$//' test3.sh
方法 3:在 vim
里转换 # OK 有大用
进入 vim test3.sh
后输入: ff 是文件格式的意思
方法 4:用 tr
转换
另外一个细节:'\r'
在 shell 中的含义
在 zsh
/bash
里,单引号 ' \r '
不会把 \r
展开成回车字符;它通常会被当作两个字符(反斜杠和字母 r)传给 tr
—— 这是不想要的。
正确并可靠的写法是用 ANSI-C 引号:$'\r'
,它会展开成真实的 CR(回车)字节。
也可以用八进制表示:$'\015'
。
所以完全OK 的写法是
tr -d $'\r' < test3.sh > test3_fixed.sh && mv test3_fixed.sh test3.sh
之后再执行:
就不会再报 bad interpreter
了。
要不要我帮你写一个一行命令,直接把当前目录下所有脚本里的 ^M
都去掉?
为什么在 linux 的 vim 能看到 ^M ,,在macos 下在却看不到 ^M
这个问题本质上是 终端和 Vim 的显示方式 + 文件的换行符 不同导致的。
1. 文件里真实存在的内容
2. 为什么 Linux 的 Vim 看到 ^M
Linux 上 vim
默认不会自动“猜测”并隐藏 \r
,所以当文件带有 Windows 风格的 \r\n
时,它会把 \r
显示为 ^M
,方便你知道文件格式有问题。
3. 为什么 macOS 的 Vim 看不到 ^M
macOS 自带的 vim
在打开文件时,会尝试根据内容自动识别 fileformat
(ff
),可能识别为 dos
或 unix
,并在显示上自动隐藏了 ^M
。
实际上,^M
还在,只是被 Vim 解释掉了。
你可以在 macOS 的 Vim 里输入:
如果返回的是 dos
,说明文件还是 CRLF 格式,只是没显示 ^M
。
4. 如何强制在 macOS Vim 里显示 ^M
在 vim
里输入:
这样 \r
和 \n
等隐藏字符都会显示出来(^M
就能看到了)。
✅ 总结:
Linux Vim 显示 ^M
,因为它直接把 \r
展现出来。
macOS Vim 默认识别 dos
换行并隐藏了 ^M
,所以你肉眼看不到。
但文件内容没变,解释器还是会把 #!/bin/bash^M
当成错误的路径。
要不要我给你一个方法,让你在 macOS 下也能用 vim
一眼就看出文件是 CRLF 还是 LF?
unix 是什么意思 ,,set ff=unix是什么意思
好问题 👍 我来拆开解释一下:
1. 什么是 Unix 换行 (LF)
在文件里,“换行”其实是某个特殊的控制符。
不同操作系统用的符号不一样:
Unix / Linux / macOS (现代的) → 用 \n
(Line Feed,简称 LF)
Windows → 用 \r\n
(Carriage Return + Line Feed,CRLF)(Carriage Return是回车) ( Line Feed是换行)
老旧的 MacOS (OS9 以前) → 用 \r
(Carriage Return, CR)
所以:
unix
= 每行只用 \n
结尾
dos
= 每行用 \r\n
结尾
mac
= 每行只用 \r
结尾(几乎不用了)
2. set ff=unix
是什么意思
在 Vim 里 ff
是 fileformat
的缩写,表示文件的换行格式。
你可以随时查看:
结果可能是:
unix
→ 文件用 \n
换行
dos
→ 文件用 \r\n
换行
mac
→ 文件用 \r
换行
当你输入:
相当于告诉 Vim:
👉 把这个文件 保存 成 “Unix 换行符”(即只用 \n
)。
然后再 :wq
保存时,Vim 会自动把行尾的 \r\n
全部转换成 \n
。
3. 为什么要用 ff=unix
因为在 Linux / macOS 运行脚本时,如果 shebang (#!/bin/bash
) 结尾有 \r
,解释器会当成路径的一部分(变成 /bin/bash^M
),就会报错:
所以必须改成 unix
格式才能运行。
✅ 总结:
unix = LF (\n
) → Linux/macOS 正常
dos = CRLF (\r\n
) → Windows 格式,Linux/macOS 会出错
set ff=unix
就是强制把文件保存成 Unix 风格的换行符
要不要我帮你写一个 命令行小脚本,一次性把当前目录下所有脚本从 dos
换行批量转换成 unix
?
tr -d '\r' < test3.sh > test3_fixed.sh
mv test3_fixed.sh test3.sh 详解
macos tr -d < '\r' test3.sh > test3.sh 会有问题
正确的方法是
tr -d '\r' < test3.sh > test3_fixed.sh
mv test3_fixed.sh test3.sh
在 macOS 中,tr -d '\r' < test3.sh > test3.sh
这条命令的目的是删除文件 test3.sh
中的回车符(\r
,即 CR 字符)。然而,直接在同一个文件上进行操作可能会导致文件内容丢失。以下是详细解释和注意事项:
命令拆解
tr -d '\r' test3.sh
tr
:字符转换/删除工具。
-d '\r'
:删除输入中的所有回车符(\r
)。
test3.sh
:输入文件。
> test3.sh
潜在问题
正确做法
方法 1:使用临时文件(推荐)
tr -d '\r' < test3.sh > temp.sh && mv temp.sh test3.sh
方法 2:使用 sponge
(需安装 moreutils
)
brew install moreutils # 如果未安装
tr -d '\r' < test3.sh | sponge test3.sh
方法 3:原地编辑(如 sed -i
)
sed -i '' 's/\r//g' test3.sh
适用场景
总结
原命令存在风险,建议使用临时文件或工具(如 sponge
/sed
)安全操作。理解重定向和文件的处理顺序是关键!
set list 是什么意思
好问题 👍
在 Vim 里:
:set list
的作用
list
选项控制 是否显示不可见字符(比如换行、制表符、空格等)。
:set list
→ 开启显示模式
:set nolist
→ 关闭显示模式(默认)
开启后,Vim 会用特殊的符号把“隐藏字符”显示出来:
配合 listchars
使用
你还可以用 listchars
自定义显示符号:
可能输出:
例如:
这样:
行尾换行符显示 $
Tab 显示 >---
行尾多余空格显示 .
典型用途
发现 Windows 的 ^M
(多余的 \r
)
发现行尾空格(可能导致脚本出错)
对齐检查(Tab 和空格混用时特别有用)
✅ 总结:
:set list
→ 让不可见字符显示出来
结合 listchars
→ 可以自定义显示符号
对排查 ^M
这类隐藏问题非常实用
要不要我给你一个 Vim 配置示例,让你以后打开任何文件时自动显示 ^M
、Tab 和行尾空格?
set ff? 是什么意思
这个问题问得好! 👍
在 Vim 里,ff
是 fileformat
的缩写,表示 当前缓冲区(文件)的换行符格式。
:set ff?
的意思
:set ff?
用来查询当前文件的换行符类型。
结果会返回三种之一:
unix
→ 每行结尾只有 \n
dos
→ 每行结尾是 \r\n
mac
→ 每行结尾是 \r
例子
可能显示:
说明这个文件用的是 Windows 的 CRLF 换行。
改变文件格式
如果你想把它转成 Unix 格式(解决 ^M
问题),在 Vim 里可以执行:
保存后,所有换行会被转换为 Unix 风格(\n
),文件就不会再有 ^M
了。
✅ 总结:
要不要我帮你写一段 Vim 命令(或者放到 .vimrc
里),让 Vim 打开文件时 自动把 dos → unix,免得以后手动 :set ff=unix
?
sed -i '' 's/\r//' test3.sh 详解
好——把这条命令拆得很细,逐项解释它在 macOS(BSD sed
)上的语义、坑、以及更安全/更精确的替代做法。
原命令
逐项详解
关于 \r
的兼容性说明(关键)
常见变体及其含义
为什么可能产生问题(风险)
-i ''
会原地替换,实现通常是写入临时文件然后重命名回原名 —— 这会改变文件的 inode,可能影响权限/时间戳/所有者(极少数情况下会丢失可执行位),所以修改后最好确认并恢复 chmod +x
(如果原来是可执行的话)。
如果 sed
没有正确识别 \r
(兼容性问题),可能根本没有删掉 CR;或者在磁盘空间不足、写入失败时会留下半成品(因此用备份或先写到临时文件更安全)。
推荐的更稳妥做法
验证是否成功(检查方法)
file test3.sh
→ 会告诉你是否有 CRLF / CR 终止符。
cat -v test3.sh | sed -n '1,20p'
→ 会把 \r
显示为 ^M
,方便肉眼检查。
hexdump -C test3.sh | head
或 xxd test3.sh | head
→ 直接看字节(查 0d 0a
/ 0d
)。
小结(要点)
需要的话我可以直接把你当前目录下的 test3.sh
通过一个安全命令批量修正为 Unix 行尾(并保留可执行位);或者给你一条一次性可复制粘贴的“最保险的一行命令” —— 你想要哪种?
cat -v test3.sh 详解
好,我们把 cat -v test3.sh
逐项解释清楚。
1. 基本命令
2. cat -v
的作用
正常情况下,cat
会原样输出文件的内容,控制字符(比如回车 \r
、BEL、ESC)不会显示出来。
加上 -v
后,cat
会把那些非打印字符用特殊符号表示出来:
字符 | ASCII | 显示结果(cat -v) | 说明 |
---|
回车 \r | 0x0D | ^M | 经典的 Windows/DOS 行尾 CR 符号 |
换行 \n | 0x0A | 正常换行 | 不额外显示 |
制表符 \t | 0x09 | 正常显示为 Tab | 不变 |
BEL(响铃) | 0x07 | ^G |
|
ESC | 0x1B | ^[ |
|
其他 0x00–0x1F | 对应 ^@ 到 ^_ | 控制字符显示为 ^X 形式 |
|
这样,你就能直观地看到文件里是否真的存在 ^M
(回车符)。
3. 常见情况对比
Unix/Linux 格式(LF,\n
)
👉 行尾什么都不显示,正常换行。
Windows 格式(CRLF,\r\n
)
👉 在每行结尾会多一个 ^M
。
经典 Mac 格式(CR,\r
)
👉 每行结尾也显示 ^M
,但是不会换行。
4. 用法扩展
只想显示不可见字符,不影响正常内容:
想看控制字符 + 制表符(tab 也可见):
想看控制字符 + 换行符(把换行符显示成 $
):
5. 小技巧
✅ 总结:
cat -v test3.sh
的意义是 把隐藏的控制字符显示出来,尤其是 Windows 下的 ^M
(\r
),让你肉眼确认文件到底是 LF、CRLF 还是 CR 行尾。
要不要我帮你整理一套「检测文件行尾格式」的三连检查命令(用 cat -v
、file
、hexdump
各自确认),这样你以后只要敲一组命令就能立刻判断文件是哪种换行符?