零基础通关:Shell 编程核心语法全景详解
在 Linux 的核心世界里,掌握自动化脚本编写是每一个开发者与运维人员的必经之路。要写出高效、稳定的脚本,扎实的语法基本功是重中之重。
本篇博客专门为你梳理 Shell(基于主流的 Bash Shell)编程的完整语法体系 。我们抛开复杂的案例,完全面向零基础,用最通俗的语言、最规范的代码结构,带你逐一击破 Shell 的核心语法。
一、 认知奠基:Shell 脚本的"第一行"与运行结构
一个标准的 Shell 脚本是一个纯文本文件,通常以 .sh 为后缀 。在编写任何 Shell 脚本时,都有一个不可动摇的黄金启始结构。
1. 什么是 Shebang(#!/bin/bash)?
任何 Shell 脚本的第一行,必须是以下这串字符:
bash
#!/bin/bash
- 含义 :
#和!组合在一起被称为 Shebang 。它紧跟的/bin/bash是系统路径,用来告诉操作系统:"当运行这个文本文件时,请立刻调用系统中的 Bash 解释器来翻译并执行后面的代码" 。
2. 编写与运行三步走
-
创建文件 :使用文本编辑器(如
vim)创建一个文件test.sh,第一行写上#!/bin/bash。 -
赋予权限 :Linux 中新创建的文件默认没有执行权限 。必须在终端执行
chmod +x test.sh赋予其可执行权限 。 -
执行脚本 :在当前目录下通过
./test.sh即可一键运行。
二、 核心语法一:变量的定义、引用与作用域
变量是程序中用来存储动态数据的"盒子" 。Shell 中的变量使用非常灵活,但也伴随着极具迷惑性的"空格陷阱"。
1. 变量定义(等号两侧零空格)
bash
# 正确示例:变量名=值
name="Geek"
age=18
# 错误示例!等号两边加了空格,系统会把它误认为是一个叫 my_name 的命令
my_name = "Geek"
⚠️ 变量命名核心规范:
变量名只能由字母、数字、下划线组成,且绝不能以数字开头 (如
1MyVar=123是违法的) 。Bash 的关键字(如
if,for,while)不能用作变量名 。
2. 变量的引用($ 符号)
想使用盒子里存的数据,必须在变量名前面加上 $ 符号 。
bash
echo $name # 输出: Geek
echo ${name} # 推荐写法!用花括号把变量名包裹起来,能精确防止字符拼接时发生歧义
3. 单引号 vs 双引号的区别(经典面试题)
当变量的值包含空格时,必须用引号包裹 。但单双引号的性质完全不同:
-
**
''**单引号()------ 所见即所得:单引号内部的所有字符都会失去特殊含义,变成纯文本 。 -
**
""**双引号()------ 允许解析 :双引号内部允许通过$符号来读取其他变量的值 。
bash
my_var="Linux"
echo '$my_var is powerful' # 输出: $my_var is powerful
echo "${my_var} is powerful" # 输出: Linux is powerful
4. 命令替换(把命令结果存入变量)
如果你想把一个 Linux 命令在终端输出的结果拦截下来,存进变量里,需要使用 $(命令) 语法 :
bash
# 获取当前日期并赋值给 shijian 变量
shijian=$(date "+%Y-%m-%d")
echo "今天的日期是: $shijian"
三、 核心语法二:条件判断与逻辑分支
让脚本能够根据不同的环境做出决策,是实现自动化监控和防御的基础 。
1. 条件判断的基本语法
bash
if [ 条件判断式 ]; then
# 条件为【真】时执行的代码
else
# 条件为【假】时执行的代码
fi # 以 fi (if的反写) 结束整个判断
⚠️ 空间陷阱 :中括号
[的内侧两边、以及]的内侧两边,必须留有空格 !例如if [$a -eq $b]是错的,必须写成if [ $a -eq $b ]。
2. 常用判断条件分类
在 Shell 中,我们不能直接用 >, <, == 来比较数字,而是使用专属的英文字符缩写:
① 整数比较
-
-eq:等于 (Equal) -
-ne:不等于 (Not Equal) -
-gt:大于 (Greater Than) -
-lt:小于 (Less Than) -
-ge:大于等于 (Greater or Equal) -
-le:小于等于 (Less or Equal)
② 字符串比较
-
==:判定两个字符串是否一模一样 -
-z "字符串":判定字符串长度是否为 0(即是否为空)
③ 文件状态判定
-
-e 文件路径:判定文件或目录是否存在 -
-f 文件路径:判定这是否是一个"普通文件" -
-d 文件路径:判定这是否是一个"目录(文件夹)"
3. 多分支语法示例(elif)
bash
score=85
if [ $score -ge 90 ]; then
echo "优秀"
elif [ $score -ge 80 ]; then
echo "良好"
else
echo "及格/不及格"
fi
四、 核心语法三:循环控制结构
循环能够帮助我们批量处理重复性任务,或者让监控程序持续驻留运行 。
1. while循环(条件成立则一直循环)
只要中括号内的条件满足,就会源源不断地执行 do与 done 之间的代码 。
bash
# 经典的 7x24 小时全天候无限循环结构
while true # 条件永远为真
do
echo "每隔5秒轮询一次服务器状态..."
sleep 5 # 核心技巧:必须加睡眠时间,防止死循环空转榨干服务器 CPU!
done # 循环体结束
2. for 循环(遍历固定范围)
当你需要依次处理一组已知的数据、文件或列表时,for 循环是最佳选择。
bash
# 遍历普通列表
for ip in 192.168.1.1 192.168.1.2 192.168.1.3
do
echo "正在检查服务器: ${ip} 的连通性..."
done
五、 核心语法四:输出重定向与用户交互
脚本在执行过程中,必然涉及数据的输入与输出。
1. 输出重定向:> 与 >>
默认情况下,echo 命令会将内容直接打印到屏幕上 。通过重定向符号,我们可以将内容转存到文件中(这正是写日志的核心底层机制) :
-
>****(覆盖写入):会清空目标文件原本的所有内容,然后写入新数据 。 -
>>****(追加写入) :保留原文件内容,在文件的末尾另起一行追加新数据(推荐用于写日志) 。
bash
echo "当前任务开始执行" > /var/log/my.log # 清空旧日志,开始写入
echo "步骤一完成" >> /var/log/my.log # 在末尾追加记录,不会破坏前面的内容
2. 错误输出隔离:2>/dev/null
在执行一些敏感命令(如检测端口、备份数据库)时,如果命令报错,错误信息会弄脏控制台。
-
Linux 中,
1代表标准输出,2代表错误输出 。 -
/dev/null是 Linux 的虚拟"黑洞",丢进去的数据会瞬间消失。
bash
# 如果 rsync 报错了,报错信息会被静默屏蔽,不会打印到屏幕上
rsync -az /data /backup 2>/dev/null
3. 用户输入捕获:read 命令
如果脚本需要与执行它的人类进行交互,可以使用 read 命令实时捕获对方键盘输入的内容,并赋予变量 。
bash
# -p 参数可以在要求输入前,先打印一段中文提示信息
read -p "请输入您想要备份的数据库名称: " db_name
echo "系统收到!即将为您开始备份 [${db_name}] 数据库..."
4. 文本流多行写入:cat << EOF 语法
当你需要通过脚本动态向某个配置文件(如邮件配置、网络配置)中追加写入连续的多行文字时,可以用 << EOF 将文本块包围起来 :
bash
# 将 EOF 之间的三行配置,一次性安全追加到配置文件中
cat >> /etc/test.conf << EOF
server_name=localhost
port=8080
status=active
EOF
💡 初学者稳健通关三大定律
看完上面的语法,请在心里牢记这三条"排错军规",能帮你避开 90% 的低级脚本报错:
1.定义变量不留空格 :key="value",等号两边千万别敲空格 。
-
条件判断必留空格 :
if [ $a -eq $b ],中括号内侧和比较符两边,必须有空格 。 -
安全审计多用追加 :除非特殊清空需求,日常输出日志请认准
>>符号,防止一不小心覆盖掉核心资产数据 。
基础语法已经全部交代完毕了。你现在是否已经准备好,在你的本地 Rocky Linux 或是虚拟机中创建一个 test.sh 来亲手敲一下这些变量和条件判断了?如果在练习基础语法时遇到任何诡异的报错,随时贴出来,我们一起现场 Debug!