Linux实战入门:从零编写第一个Bash Shell脚本(附避坑指南)
作为 Linux 系统管理员或开发人员,掌握 Shell 脚本编写是一项必备技能。今天通过一个初学者的视角,一步步带你写出属于自己的第一个 Bash 脚本,并总结出新手最容易踩到的坑。本文基于《创建第一个Shell脚本》的学习笔记整理而成。
📚 一、 准备工作与开发规范
1. 编辑器选择
在 Linux 中,推荐使用 vim 编辑器编写脚本,它支持语法高亮和补全功能。
如果你习惯输入 vi,可以设置一个别名映射到 vim,并使其永久生效:
bash
bash
echo "alias vi=vim" >> /etc/bashrc
source /etc/bashrc
2. 脚本头部声明(Shebang)
Shell 脚本的第一行必须是脚本解释器声明 ,即 #!/bin/bash。
- 由
#!开头,内核会根据它指定用哪个程序来解释脚本。 - 这行必须位于脚本的第一行,否则会被当成普通注释忽略。
3. 良好的代码习惯(规范)
养成好习惯能避免后期大量维护成本:
- 添加注释 :使用
#号。尽量不要使用中文(防止系统换环境后出现乱码),建议使用英文注释。 - 脚本命名 :以
.sh为后缀,如firstscript.sh。 - 排版规范 :成对符号(
{}[])一次性写完再补充内容;中括号[]两端必须至少保留一个空格 ;流程控制语句(if...then...fi等)格式要完整;建议通过缩进提高代码可读性。 - 变量引号 :字符串变量定义建议加双引号
"";强引用(所见即所得)用单引号'';命令引用不建议用反引号,推荐用$()(后面会详细说明)。
🚀 二、 Shell 脚本的四种执行方式
新手经常会发现自己的脚本写好了却跑不起来,这通常是因为执行方式不对。主要有以下 4 种:
| 执行方式 | 命令示例 | 是否需要 x 权限 |
核心区别 |
|---|---|---|---|
| 1. 解释器执行 | bash first.sh 或 sh first.sh |
❌ 不需要 | 方便,适合快速测试。 |
| 2. 相对/绝对路径 | ./first.sh 或 /root/first.sh |
✅ 必须 chmod +x |
最标准的方式,生产环境常用。 |
| 3. 当前 Shell 执行 | source first.sh 或 . first.sh |
❌ 不需要 | 重点 :在当前父 Shell 进程中直接执行,脚本中的变量值运行后依然保留。 |
| 4. 管道/重定向 | bash < first.sh 或 `cat first.sh |
bash` | ❌ 不需要 |
💡 为什么特别强调 source 执行方式?
常规执行(bash 或 ./)会启动一个新的子 Shell 进程 去运行脚本,脚本结束回到父 Shell 时,子进程销毁,里面的变量也就消失了 。
而 source 或 . 是在当前 Shell 进程中执行,所以执行完毕后,脚本里定义的变量在当前命令行中依然有效。
bash
bash
# 测试例子
echo 'user=$(whoami)' > test2.sh
bash test2.sh
echo $user # 输出为空(因为子Shell的变量被销毁了)
source test2.sh
echo $user # 输出 root(因为变量留在了当前父Shell中)
💻 三、 实战案例分析
案例1:Hello World
这是最简单的入门脚本:
bash
bash
#!/bin/bash
echo "Hello, world"
bash
bash
chmod +x hello.sh
./hello.sh
案例2:标准输出与错误输出(优雅的报错处理)
在日常脚本中,我们会用 echo 打印正常日志,用 >&2 将错误信息输出到标准错误(STDERR),这样在执行时可以将错误和正常信息分离。
bash
bash
#!/bin/bash
echo "Hello, world"
echo "ERROR: Laogao, we have a problem." >&2
执行测试:
bash
bash
./hello.sh 2>hello.log # 把错误信息单独存入文件
cat hello.log # 输出:ERROR: Laogao, we have a problem.
案例3:获取系统磁盘状态(firstscript.sh)
结合我们之前的实战,编写一个自动收集系统信息的脚本,输出到 output.txt 中。
bash
bash
#!/bin/bash
# 第一次写入使用 ">" 覆盖原文件
echo "This is my first bash script" > ~/output.txt
echo "" >> ~/output.txt
echo "############################################" >> ~/output.txt
echo "LIST BLOCK DEVICES" >> ~/output.txt
echo "" >> ~/output.txt
# 注意:使用 &>> 能同时将报错信息也写入文件,避免命令找不到时文件为空
lsblk &>> ~/output.txt
echo "" >> ~/output.txt
echo "############################################" >> ~/output.txt
echo "FILESYSTEM FREE SPACE STATUS" >> ~/output.txt
echo "" >> ~/output.txt
df -h >> ~/output.txt
echo "############################################" >> ~/output.txt
案例4:打印系统信息(info.sh)
使用 $() 执行系统命令并打印基础信息:
bash
bash
#!/bin/bash
echo "====系统信息===="
echo "主机名:$(hostname)"
echo "当前时间:$(date)"
echo "当前内核版本:$(uname -r)"
echo "当前登录用户:$(whoami)"
bash
bash
source info.sh
案例6:清理 /tmp 目录下的旧文件(clean_tmp.sh)
常用于清理临时缓存,注意 ls 报错信息要丢弃:
bash
bash
#!/bin/bash
cd /tmp
rm -f *.txt
echo "已清理 /tmp 下 txt 文件"
ls -l *.txt 2>/dev/null # 2>/dev/null 表示屏蔽"文件未找到"的错误提示
⚠️ 四、 避坑指南与进阶技巧(博客防坑必读)
我们在实践中经常会遇到一些想不通的问题,这里我把 PDF 笔记中没有细讲但实际最常踩的坑整理出来:
🔴 坑1:命令输出丢失(lsblk 没写进文件)
如果你用 lsblk >> ~/output.txt,在某些系统(如 CentOS 7 最小化安装)中,如果没装 lsblk 命令,它会提示 command not found。但 >> 只会记录正确信息,不会记录错误信息 ,导致你打开文件看到标题下方是一片空白!
✅ 解决办法 :使用 lsblk &>> ~/output.txt。&>> 会同时捕获标准输出 和标准错误,不管命令运行正常还是报错,都能原样写进文件。
🔴 坑2:反引号 vs. 单引号 vs. $()
很多老教材告诉你用反引号 date 来执行命令。但反引号长得和单引号 ' 太像了,极易打错。
- 单引号
':纯文本,什么都不会执行。d='date',输出就是date。 - 反引号 ``` :旧式命令替换,确实会执行,但在键盘左上角,常被误打成顿号/间隔号。
✅ 最佳实践 :请使用现代 Shell 推荐的$()进行命令替换 。d=$(date),既清晰明了,又支持嵌套,还不容易和单引号混淆。
🎯 总结
今天主要介绍了:
- 写脚本前必须加
#!/bin/bash并注意排版规范。 - 学习 4 种执行方式的区别,特别是
source和./的变量作用域差异。 - 通过 4 个实战案例掌握了输入输出重定向、环境信息抓取和日志清理。
- 避开了重定向和引号两个新手常见大坑。
✨ 作业挑战: 尝试把你的 firstscript.sh 脚本中收集的时间加上时间戳,并在执行时把结果通过 source 方式加载,看看系统变量是否会在你的终端保留!