新建的test.sh文件,vim进去,每行开头都默认有一个~符号,是什么意思,而且在里面鼠标也失效了?
你问的这两个问题,恰好是初学者刚接触 vim 编辑器时最常遇到的两个困惑。它们完全正常,不是系统出错了。
一、每行开头的 ~ 波浪号是什么意思?
结论 :~ 表示这一行是空白行(没有任何字符,连空格都没有)。
详细解释
| 符号 | 含义 |
|---|---|
~(波浪号) |
缓冲区(buffer)里没有内容的行 |
| 普通字母/符号 | 文件实际存在的内容 |
你的情况:
-
你用
vim test.sh创建了一个新文件 -
新文件是空的,所以整个屏幕都是空白区
-
vim用~来标记这些空白行,告诉你"这里没有内容"
当你开始输入内容时:
#!/bin/bash
echo "hello"
~
~
~
-
第1、2行变成了实际内容(没有
~) -
第3行及以后仍然是空白行(还有
~)
类比:就像一本笔记本,有字的页没有标记,空白页印了一个淡淡的"此页空白"水印。
二、为什么鼠标失效了?
结论 :vim 默认运行在"纯键盘模式"下,根本不支持鼠标操作。
| 编辑器 | 鼠标支持 |
|---|---|
| Vim | 默认不支持(纯键盘操作) |
| VS Code | 完全支持 |
| Notepad | 完全支持 |
| Nano(另一个命令行编辑器) | 支持鼠标(如果开启) |
为什么 Vim 要这样设计?
-
历史原因:Vim 诞生于 1991 年,当时鼠标不是标配
-
设计哲学:手不离键盘,提高编辑效率(高手用键盘比鼠标快得多)
-
远程操作:服务器上根本没有图形界面,鼠标不存在
在 Vim 里怎么操作?
| 你想要 | 键盘操作(代替鼠标) |
|---|---|
| 移动光标 | h(左)、j(下)、k(上)、l(右) |
| 跳到行首 | 0 |
| 跳到行尾 | $ |
| 删除一个字符 | x |
| 删除一行 | dd |
| 复制一行 | yy |
| 粘贴 | p |
| 保存并退出 | ESC → :wq → Enter |
如果你实在想用鼠标(不推荐初学者)
在 ~/.vimrc 中添加:
vim
set mouse=a
但这会改变 Vim 的正常行为(选中文本会变成 Visual 模式),反而更容易让初学者困惑。
三、正确的 Vim 学习路径
| 步骤 | 操作 |
|---|---|
| 1 | 用 vim test.sh 打开文件 |
| 2 | 按 i 键进入 插入模式 (屏幕底部会显示 -- INSERT --) |
| 3 | 用键盘输入内容 |
| 4 | 按 ESC 键退出插入模式 |
| 5 | 输入 :wq 然后按 Enter 保存并退出 |
记住 Vim 的两种核心模式:
-
命令模式(默认):按键盘是各种命令,不能输入文字
-
插入模式 (按
i进入):按键盘就是输入文字
四、如果你只是想快速编辑文件(不是学 Vim)
| 编辑器 | 优点 | 缺点 |
|---|---|---|
nano |
简单直观,底部有快捷键提示 | 功能弱 |
cat |
查看文件内容 | 不能编辑 |
echo > |
快速写入简单内容 | 只能写,不能改 |
bash
bash
# 用 nano 编辑(更友好)
nano test.sh
# 屏幕底部有 ^X Exit 等提示,^ 表示 Ctrl 键
# 用 cat 快速创建
cat > test.sh << 'EOF'
#!/bin/bash
echo "hello"
EOF
总结
| 你的问题 | 答案 |
|---|---|
每行开头的 ~ |
空白行的标记,不是错误 |
| 鼠标失效 | Vim 默认纯键盘,这就是它的设计 |
| 怎么输入文字 | 按 i 进入插入模式 |
| 怎么保存退出 | ESC → :wq → Enter |
| 不想学 Vim 怎么办 | 用 nano 代替 |
建议 :如果你未来想走大数据开发,Vim 是服务器上必用的工具(因为服务器没有图形界面),值得花一天时间入门。但如果只是偶尔编辑小文件,用 nano 完全够用。
老师说shell脚本语言的很多语法或设计反人类,尤其我之前作为web前端开发写JavaScript灵活多了,开始学Oracle的时候就觉得这语言太传统了,现在学Shell感觉语法更古老。
vim 中退出时提示没有文件名 怎么解决
为什么会出现这种情况,编辑时 vim 后面忘记跟文件名!!!
以为自己写了,实际没有,所以才会报错没有文件名。
在 Vim 中看到「没有文件名」的提示,通常是因为你正在编辑一个还没有保存过的新缓冲区 (没有关联到任何文件)。当你直接输入 :q 想退出时,Vim 会拒绝退出以防止内容丢失。
解决方法
1. 保存后再退出
vim
:w filename.txt " 先保存为 filename.txt
:q " 再退出
或直接:
vim
:wq filename.txt " 保存为 filename.txt 后退出
2. 强制退出(不保存)
vim
:q!
这会放弃所有修改,直接退出。
3. 保存并退出的快捷命令
vim
:x
或
vim
ZZ " 注意:是大写 Z,不是小写
这两个命令会:
-
如果缓冲区有关联的文件名,直接保存并退出
-
如果没有文件名,
ZZ会提示你保存(相当于:wq),:x行为类似
为什么会这样?
-
正常退出
:q:要求缓冲区必须已经写入磁盘(有关联文件且未修改) -
强制退出
:q!:忽略所有警告(包括无文件名、有未保存修改)
实用建议
如果你经常忘记保存,可以设置 Vim 提醒:
vim
set confirm " 退出时如果没有保存,会询问而不是直接报错
这样当你输入 :q 时,Vim 会提示:
text
No write since last change (add ! to override)
而不是直接拒绝退出。
请罗列shell语法需要注意的点,或容易错误的点,让我可以平稳过渡。比如空格 双圆括号 中括号 等
你这个感受完全正确 。作为前端开发者,你已经被 JavaScript 的灵活性"惯坏了"。Shell 的设计年代(1970年代)决定了它的语法像一台老式手动挡汽车:到处都是坑,而且每个坑都摔过无数人。
下面这张**"Shell 语法避坑地图"** ,专为你这种 JavaScript 背景量身定制。记住,不要试图理解它"为什么反人类",只需要记住规则并绕过陷阱。
一、最危险的陷阱:空格敏感(JavaScript 最自由,Shell 最严格)
在 JavaScript 中,空格基本无害。在 Shell 中,空格是语法分隔符,多一个少一个都会炸。
| 场景 | ✅ 正确写法(没空格) | 解释 |
|---|---|---|
| 变量赋值 | name="Tom" |
等号两边绝对不能有空格 |
| 条件判断 | if [ "$a" == "$b" ] |
括号内部必须有空格,变量最好加引号 |
| 函数定义 | foo() 或 function foo() |
括号前后不要乱加空格 |
bash
bash
# 典型案例(一定会出错)
name="Tom" # ✅ 正确
name = "Tom" # ❌ 报错:name: command not found
记忆口诀 :赋值等号紧贴变量,比较方括号留空隙。
二、变量的引号地狱(JS 模板字符串真香)
Shell 中双引号、单引号、反引号行为完全不同,而且没有 JS 的模板字符串好使。
| 引用方式 | 行为 |
|---|---|
"$VAR" (双引号) |
变量会展开 |
'$VAR' (单引号) |
变量不会展开,纯字面量 |
cmd (反引号) |
执行命令,获取输出 |
bash
bash
name="world"
echo "hello $name" # hello world(双引号展开)
echo 'hello $name' # hello $name(单引号不展开)
# 建议:除非你明确需要防止变量展开,否则一律用双引号包裹变量
echo "$name" # ✅ 安全
echo $name # ⚠️ 如果变量有空格会被拆分,容易炸
黄金法则 :所有变量都用 "$VAR" 括起来。
三、条件判断的括号迷阵(JS 一个 if 走天下)
Shell 有 3 种括号,功能完全不同,是新手最容易晕的地方。
| 语法 | 名称 | 用途 |
|---|---|---|
[ ] |
test 命令 | 字符串/文件判断 |
[[ ]] |
扩展 test | 支持正则、&&、` |
(( )) |
算术运算 | 数学计算、数值比较 |
bash
a=5
b=10
# ✅ 数值比较:用 (( ))
if (( a < b )); then
echo "$a 小于 $b"
fi
# ✅ 字符串比较:用 [[ ]]
name="Alice"
if [[ "$name" == "Alice" ]]; then
echo "hello Alice"
fi
# ❌ 错误:用 [ ] 做数值比较会炸(它比较的是字符串)
if [ $a < $b ]; then # 错误!
推荐写法 :字符串/文件用 [[ ]],数字用 (( )) ,忘记古老的 [ ]。
四、命令执行与管道(JS 的 Promise 是天堂)
Shell 中命令执行、管道、错误处理非常原始。
| 需求 | Shell 写法 | JS 类比 |
|---|---|---|
| 执行命令并获取输出 | output=$(ls -l) |
const output = execSync('ls -l') |
| 上一条命令是否成功 | $? (0=成功,非0=失败) |
没有直接类比 |
| 逻辑与 (AND) | cmd1 && cmd2 |
cmd1 && cmd2 |
| 逻辑或 (OR) | `cmd1 | |
| 管道(前输出当后输入) | `cmd1 | cmd2` |
bash
# 典型的脚本模式
if [ -f "config.txt" ]; then
echo "文件存在"
else
echo "文件不存在,创建中..."
touch config.txt
fi
# 检查命令是否执行成功
grep "error" app.log
if [[ $? -eq 0 ]]; then
echo "发现错误"
fi
五、函数定义与返回值(JS 的函数是瑞士军刀)
Shell 函数非常原始,没有 return 值(只能用 echo 输出)。
| 概念 | Shell |
|---|---|
| 定义 | myfunc() { ... } |
| 调用 | myfunc |
| 参数 | $1, $2, $@ |
| 返回值 | 只能用 echo 输出 |
bash
# ✅ 正确:函数返回字符串用 echo
get_name() {
echo "Alice"
}
name=$(get_name) # name="Alice"
# ❌ 错误:return 只能返回 0-255 的状态码(成功/失败)
get_name() {
return "Alice" # 错误!return 不是返回值,是退出码
}
记忆 :Shell 函数就是一段命令集合,不是 JS 的函数。
六、常见错误速查表(打印出来贴显示器旁)
| 错误代码 | 原因 | 正确写法 |
|---|---|---|
command not found |
变量赋值有空格 | name="Tom" |
[: too many arguments |
变量未加引号,有空格 | if [[ "$var" == "abc" ]] |
unexpected operator |
[ ] 里用了 == |
改用 [[ "$var" == "abc" ]] |
syntax error near unexpected token |
if 后少了 then 或 ; |
if [[ ... ]]; then |
bad substitution |
错误的变量语法 | "${var}" 或 $(cmd) |
七、一份"反人类但必须记住"的模板
bash
#!/bin/bash
# 模板:安全、健壮、可读
# 1. 变量:等号无空格,一律加双引号
name="world"
greeting="Hello, $name"
# 2. 条件:用 [[ ]] 和 (( ))
if [[ -f "config.txt" ]]; then
echo "config exists"
fi
if (( 5 > 3 )); then
echo "math works"
fi
# 3. 命令替换:用 $(...),不是反引号
current_date=$(date +%Y-%m-%d)
echo "Today is $current_date"
# 4. 函数:输出用 echo
get_full_name() {
echo "Alice Johnson"
}
full_name=$(get_full_name)
# 5. 错误处理
if ! mkdir -p "/tmp/mydir"; then
echo "Failed to create directory"
exit 1
fi
八、最后:给你的心态建议
| 感觉 | 现实 |
|---|---|
| "这太原始了" | 它就是 1970 年代的设计,目的不是优雅,是在资源极度匮乏的环境下稳定运行 |
| "为什么不能像 JS 那样" | 因为 Shell 是胶水语言,用来粘合各种小命令,不是用来写复杂逻辑的 |
| "我该学到什么程度" | 能写 50 行以内的脚本、能看懂别人写的脚本、能改 bug,就完全够用 |
一句话总结 :不要和 Shell 讲道理,记住它的"奇葩规则",把它当工具用,写完就跑。你的主业是大数据,不是 Shell 专家。
等你写几天 Shell,再回去写 JS,你会感动得流泪。
Shell在不同Linux版本中语法好像有细微差异,比如 ((A+$B))有些版本正确,有些版本错误,请使用表格总结常见差异
你的观察非常敏锐!$(( $A + $B )) 在某些系统上报错,而在另一些系统上正常,这确实是 Shell 脚本跨平台兼容性的经典问题。核心原因在于:不同 Linux 发行版默认的 /bin/sh 指向不同的 Shell 实现。
一、问题根源:/bin/sh 指向谁?
| 发行版 | /bin/sh 实际指向 |
特点 |
|---|---|---|
| Ubuntu / Debian | dash |
轻量、POSIX 严格、启动快、功能少 |
| CentOS / RHEL | bash |
功能丰富、支持扩展语法 |
| Alpine Linux | busybox ash |
极简、POSIX 子集 |
| macOS | bash(旧版)或 zsh |
取决于版本 |
关键结论 :如果你用 #!/bin/sh 声明脚本,Ubuntu 会用 dash 执行,而 CentOS 会用 bash 执行。dash 对语法要求更严格,很多 bash 的"舒服写法"在 dash 下直接报错。
你遇到的 $(( $A + $B )) 问题,正是因为 dash 对算术运算的语法要求更严格。
二、Shell 语法差异速查表
1. 算术运算
| 语法 | Bash | Dash/Zsh | 说明 |
|---|---|---|---|
$(( a + b )) |
✅ | ✅ | 标准写法,通用 |
$(( $a + $b )) |
✅ | ⚠️ 部分版本报错 | dash 对 $ 嵌套敏感 |
$[ a + b ] |
✅ | ❌ 报错 | 旧语法,已废弃 |
let a++ |
✅ | ❌ let: not found |
let 是 bash 内建命令-2-7 |
(( a++ )) |
✅ | ❌ 语法错误 | C 风格循环同理 |
✅ 通用写法 :result=$((a + b))(内部变量不加 $)
bash
# ❌ 在 dash 中可能报错
result=$(( $a + $b ))
# ✅ 通用写法
result=$((a + b))
2. 条件判断
| 语法 | Bash | Dash/Zsh | 说明 |
|---|---|---|---|
[ "$a" = "$b" ] |
✅ | ✅ | POSIX 标准 |
[ "$a" == "$b" ] |
✅ | ❌ 部分报错 | == 是 bash 扩展-7 |
[[ "$a" == "$b" ]] |
✅ | ❌ 语法错误 | [[ ]] 是 bash 扩展 |
[[ $a =~ regex ]] |
✅ | ❌ 不支持 | 正则匹配是 bash 扩展 |
✅ 通用写法 :[ "$a" = "$b" ](单等号,双括号)
3. 字符串与数组
| 语法 | Bash | Dash/Zsh | 说明 |
|---|---|---|---|
array=(a b c) |
✅ | ❌ 不支持 | 数组是 bash 扩展-7 |
${array[1]} |
✅ | ❌ 不支持 | 同上 |
${#var} |
✅ | ✅ | 字符串长度 |
${var:1:2} |
✅ | ❌ 不支持 | 子串截取是 bash 扩展-7 |
${var^^} |
✅ | ❌ 不支持 | 大小写转换是 bash 扩展-7 |
✅ 通用替代 :用 cut、sed、awk 或 tr 处理字符串
bash
# ❌ 子串截取
echo ${str:1:2}
# ✅ 通用写法
echo "$str" | cut -c2-3
4. 函数
| 语法 | Bash | Dash/Zsh | 说明 |
|---|---|---|---|
func() { ... } |
✅ | ✅ | POSIX 标准 |
function func() { ... } |
✅ | ❌ 语法错误 | function 关键字是 bash 扩展-7 |
✅ 通用写法 :func() { ... }(不要写 function)
5. 循环
| 语法 | Bash | Dash/Zsh | 说明 |
|---|---|---|---|
for i in {1..10}; do ... |
✅ | ❌ 不展开 | {m..n} 是 bash 扩展-7 |
for ((i=0;i<10;i++)); do ... |
✅ | ❌ 语法错误 | C 风格循环是 bash 扩展-4-7 |
select var in list; do ... |
✅ | ❌ 不支持 | select 是 bash 扩展-7 |
✅ 通用写法 :for i in $(seq 1 10); do ... 或 while 循环
bash
# ❌ dash 不支持
for ((i=0;i<10;i++)); do echo $i; done
# ✅ 通用写法
i=0
while [ $i -lt 10 ]; do
echo $i
i=$((i + 1))
done
6. 重定向与 Here Document
| 语法 | Bash | Dash/Zsh | 说明 |
|---|---|---|---|
<<< "string" |
✅ | ❌ 不支持 | Here String 是 bash 扩展-7 |
>&word(非数字) |
✅ | ❌ 报错 | >&err.log 写法有问题-7 |
✅ 通用写法 :用 Here Document 或 >file 2>&1
bash
# ❌ Here String
cat <<< "hello"
# ✅ Here Document
cat << EOF
hello
EOF
7. Shebang 与执行方式
| 场景 | Bash | Dash/Zsh | 说明 |
|---|---|---|---|
#!/bin/sh |
用 /bin/sh 执行 |
用 /bin/sh 执行 |
执行器取决于系统-1-5 |
#!/bin/bash |
用 bash 执行 | 用 bash 执行 | 前提是系统安装了 bash |
sh script.sh |
忽略 shebang | 忽略 shebang | 强制用 sh 执行 |
./script.sh |
按 shebang 执行 | 按 shebang 执行 | 尊重脚本第一行 |
关键警告 :即使用了 #!/bin/bash,如果你用 sh script.sh 执行,会强制使用 sh ,忽略 shebang-7!
三、算术运算问题详解
针对你提到的 $(( $A + $B )):
bash
a=5
b=3
# ❌ 在 dash 中可能报错
result=$(( $a + $b )) # dash 报错:bad substitution
# ✅ 通用写法(内部不加 $)
result=$((a + b)) # bash 和 dash 都支持
# ✅ 另一种通用写法
result=$(expr $a + $b) # 注意空格,但性能较差[citation:6]
为什么 $(( $a + $b )) 在 dash 中会报错?
dash 的解析器要求 $(( )) 内部不要使用 $ 引用变量 ,直接写变量名即可。虽然某些版本的 dash 可能宽容处理,但为了跨平台兼容,永远不要在内层加 $。
四、如何编写跨平台脚本?
方案一:坚持 POSIX 标准(推荐生产环境)
使用 #!/bin/sh + 仅 POSIX 语法,功能受限但到处能跑。
bash
#!/bin/sh
# POSIX 兼容写法
a=5
b=3
result=$((a + b)) # 算术
[ "$a" -eq "$b" ] && echo eq # 比较
for i in $(seq 1 10); do # 循环
echo $i
done
方案二:明确使用 bash
用 #!/bin/bash 声明,并确保脚本以 ./script.sh 或 bash script.sh 方式执行 -1-7。
bash
#!/bin/bash
# 大胆使用 bash 扩展
array=(a b c)
for ((i=0;i<10;i++)); do
echo $i
done
方案三:测试你的脚本
bash
# 用 dash 测试(Ubuntu)
dash script.sh
# 用 bash 测试
bash script.sh
# 检查语法
sh -n script.sh
五、一句话总结
| 你的问题 | 答案 |
|---|---|
为什么 $(( $a + $b )) 在某些系统报错? |
Ubuntu 的 /bin/sh 是 dash,要求算术运算内变量不加 $ |
| 通用写法是什么? | result=$((a + b)) |
| 最安全的策略 | 生产环境用 #!/bin/sh + POSIX 语法;复杂功能用 #!/bin/bash |
我用的Ubuntu,老师用的CentOS,test.sh开头的确老师推荐写的是#!/bin/sh,执行的时候老师用的是 sh test.sh。
我应该是用 bash test.sh执行吗
你的判断完全正确 ,而且你问到了一个非常关键、生产环境必踩的坑。
结论先行:在你的 Ubuntu 上,应该用 bash test.sh 执行,或者把脚本第一行改成 #!/bin/bash 然后用 ./test.sh 执行。
一、为什么老师用 sh test.sh 没事,你用就会出问题?
| 环境 | /bin/sh 实际指向 |
sh test.sh 的效果 |
|---|---|---|
| 老师的 CentOS | bash |
等于在用 bash 执行,语法宽松 |
| 你的 Ubuntu | dash |
在用 dash 执行,语法严格,很多写法报错 |
结论 :同样写 #!/bin/sh + sh test.sh,在你俩机器上实际用的解释器不一样。
这就是为什么:
-
老师写的脚本在你机器上可能报错
-
你按老师的习惯写脚本,可能被
dash卡住
二、你应该怎么做?(三个方案)
| 方案 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 方案一(推荐学) | 脚本第一行写 #!/bin/bash,执行用 ./test.sh(需 chmod +x)或 bash test.sh |
语法丰富,和老师教的兼容 | |
| 方案二(最稳妥) | 脚本第一行写 #!/bin/sh,但执行时用 bash test.sh |
不依赖 shebang,强制用 bash | 每次执行要多敲 bash |
| 方案三(不推荐) | 强行适配 dash,只写 POSIX 语法 |
脚本到处能跑 | 语法限制多,很痛苦,不适合学习 |
三、具体操作示例
#!/bin/bash + ./test.sh
bash
#!/bin/bash
# 第一行写 bash,而不是 sh
a=5
b=3
echo $((a + b)) # 算术
array=(1 2 3) # 数组也可以用
echo ${array[0]}
执行方式:
bash
chmod +x test.sh
./test.sh
# 或
bash test.sh
四、验证你的环境(强烈建议亲手跑一下)
bash
# 1. 查看 /bin/sh 指向谁
ls -l /bin/sh
# Ubuntu 输出:/bin/sh -> dash
# CentOS 输出:/bin/sh -> bash
# 2. 测试脚本
cat > test.sh << 'EOF'
#!/bin/sh
if [[ "a" == "a" ]]; then
echo "双等号测试"
fi
EOF
# 3. 用 sh 执行(Ubuntu 会报错)
sh test.sh
# 报错:test.sh: 2: [[: not found
# 4. 用 bash 执行(成功)
bash test.sh
# 输出:双等号测试
五、学习阶段的建议
| 阶段 | 建议写法 | 执行方式 |
|---|---|---|
| 跟着老师抄作业 | 脚本里写 #!/bin/bash |
用 bash test.sh 执行 |
| 自己写练习脚本 | 用 #!/bin/bash |
养成好习惯 |
| 考试 / 作业提交 | 按老师要求来 | 如果老师用 CentOS,他的 sh = bash,你写 #!/bin/sh 在他那边也能跑 |
一个现实建议 :你可以继续用 #!/bin/sh 写脚本,但执行时一律用 bash test.sh。这样:
-
语法上你和老师保持一致(他读你脚本不别扭)
-
执行上你在 Ubuntu 不会踩
dash的坑
总结一句话
在 Ubuntu 上,用
#!/bin/bash或bash test.sh执行,才能和 CentOS 的行为对齐。
不是说 bash test.sh和sh test.sh一样吗
不一样! 这是 Shell 学习中最常见的误解之一,你问到了关键点。
核心结论
| 执行方式 | Ubuntu 上实际用的是 | CentOS 上实际用的是 |
|---|---|---|
bash test.sh |
bash | bash |
sh test.sh |
dash(不是 bash!) | bash(sh 指向 bash) |
结论 :bash test.sh 和 sh test.sh 在 Ubuntu 上不一样,在 CentOS 上才一样。
为什么会有这个误解?
因为很多人(包括老师)在 CentOS 上学习,CentOS 的 /bin/sh 是软链接指向 /bin/bash,所以执行 sh test.sh 就等于执行 bash test.sh。
bash
# CentOS 上
ls -l /bin/sh
# 输出:/bin/sh -> bash ← sh 就是 bash
# 所以这两个命令完全等价
sh test.sh # 实际执行的是 bash
bash test.sh # 也是 bash
但在 Ubuntu 上不一样:
bash
# Ubuntu 上
ls -l /bin/sh
# 输出:/bin/sh -> dash ← sh 是 dash,不是 bash!
# 这两个命令不等价
sh test.sh # 实际执行的是 dash(语法严格、功能少)
bash test.sh # 执行的是 bash(功能丰富)
验证实验(强烈建议你自己跑一遍)
bash
# 1. 创建一个测试脚本
cat > test.sh << 'EOF'
#!/bin/sh
echo "当前使用的 Shell: $0"
if [[ "a" == "a" ]]; then
echo "双等号测试通过"
else
echo "双等号测试失败"
fi
EOF
# 2. 用 sh 执行(Ubuntu 上会报错)
sh test.sh
# 输出:
# 当前使用的 Shell: sh
# test.sh: 4: [[: not found ← dash 不认识 [[
# 双等号测试失败
# 3. 用 bash 执行(成功)
bash test.sh
# 输出:
# 当前使用的 Shell: bash
# 双等号测试通过 ← bash 认识 [[
为什么 Ubuntu 要把 /bin/sh 设为 dash?
| 原因 | 说明 |
|---|---|
| 性能 | dash 比 bash 轻量得多,启动快 2-3 倍 |
| 标准化 | dash 严格遵循 POSIX 标准,不添加扩展语法 |
| 系统脚本 | Ubuntu 系统自己的启动脚本都用 dash 执行,加速开机 |
代价 :很多在 bash 里写得很舒服的语法([[ ]]、数组、==、source 等),在 dash 里直接报错。
你在 Ubuntu 上应该怎么做?
| 你的需求 | 推荐做法 | 说明 |
|---|---|---|
| 跟着老师学(CentOS 风格) | 用 bash test.sh 执行 |
绕开 dash,行为与 CentOS 一致 |
| 自己写脚本练习 | 脚本第一行写 #!/bin/bash,然后 chmod +x + ./test.sh |
养成好习惯 |
| 考试/作业提交 | 用 bash test.sh 测试通过后再提交 |
确保语法正确 |
| 写跨平台脚本 | 只写 POSIX 语法,用 sh test.sh 测试 |
到处能跑(不推荐初学者) |
一句话记忆
Ubuntu 上
sh不是bash,是dash。想用 bash 就写bash或#!/bin/bash。