2. Shell脚本基础:变量、条件判断、循环、函数、常用命令组合
Shell脚本这东西,说白了就是你把一堆Linux命令写进一个文件里,让机器自动去执行。我刚开始做运维那会儿,每天手动敲命令敲到手抽筋,后来学会了写脚本,才真正体会到什么叫「事半功倍」。这一章咱们就把Shell脚本的核心知识点过一遍,都是我在项目中反复用到的东西。
2.1 变量:脚本里的「小盒子」
变量就像一个个小盒子,用来存数据。Shell里的变量用起来很随意,不需要提前声明类型。
#!/bin/bash
# 定义一个变量,等号两边不能有空格
name="张三"
age=28
echo "我的名字是 $name,今年 $age 岁"
嗯,这里要注意:变量名和等号之间不能有空格。我第一次写的时候习惯性加了空格,结果脚本直接报错,找了半天才发现问题。
变量使用规则:
- 引用变量用
$变量名或${变量名} - 双引号里可以解析变量,单引号不行
- 变量名区分大小写,
$Name和$name是两个东西
我在项目中遇到过一个问题:有个同事用单引号包住了变量,结果打印出来全是 $name 这种字符串,而不是实际的值。记住,单引号是纯文本,双引号才会解析变量。
2.2 条件判断:让脚本学会「思考」
条件判断就是让脚本根据不同情况执行不同操作。Shell里用 if、elif、else 这套组合拳。
#!/bin/bash
score=85
if [ $score -ge 90 ]; then
echo "优秀"
elif [ $score -ge 80 ]; then
echo "良好"
else
echo "继续努力"
fi
你想想看,为什么这里用 -ge 而不是 >=?因为Shell里的比较运算符有自己的写法:
| 运算符 | 含义 | 示例 |
|---|---|---|
-eq |
等于 | [ $a -eq $b ] |
-ne |
不等于 | [ $a -ne $b ] |
-gt |
大于 | [ $a -gt $b ] |
-lt |
小于 | [ $a -lt $b ] |
-ge |
大于等于 | [ $a -ge $b ] |
-le |
小于等于 | [ $a -le $b ] |
我曾经踩过的坑:判断文件是否存在时,[ -f "$file" ] 这个写法里,变量最好用双引号包起来。否则如果文件名为空,脚本会直接报语法错误。别问我怎么知道的……
2.3 循环:重复的事情交给机器
循环就是让脚本反复执行某段代码。Shell里最常用的是 for 循环和 while 循环。
for 循环:遍历列表
#!/bin/bash
# 遍历一组IP地址
for ip in 192.168.1.1 192.168.1.2 192.168.1.3; do
echo "正在ping $ip ..."
ping -c 1 $ip &>/dev/null && echo "$ip 通" || echo "$ip 不通"
done
我个人习惯用 for 循环来处理批量任务,比如批量检查服务器状态、批量修改配置。你想想看,如果100台服务器要挨个检查,手动操作得累死,但脚本几秒钟就跑完了。
while 循环:条件控制
#!/bin/bash
count=1
while [ $count -le 5 ]; do
echo "第 $count 次执行"
count=$((count + 1))
done
为什么有时候用 while 而不是 for?说白了,for 适合已知范围的遍历,while 适合不知道什么时候结束的场景,比如等待某个进程启动完成。
2.4 函数:把重复代码「打包」
函数就是把一段代码封装起来,起个名字,想用的时候直接调用。我建议你把经常用的功能写成函数,这样脚本会清爽很多。
#!/bin/bash
# 定义一个函数
check_port() {
local host=$1
local port=$2
nc -zv $host $port &>/dev/null
if [ $? -eq 0 ]; then
echo "$host:$port 端口开放"
else
echo "$host:$port 端口未开放"
fi
}
# 调用函数
check_port "192.168.1.1" 80
check_port "192.168.1.1" 443
小技巧:函数里的 local 关键字用来声明局部变量,避免变量污染。我在写复杂脚本时,每个函数都会用 local 声明变量,这样不同函数之间不会互相干扰。
我记得有一次写监控脚本,没注意变量作用域,结果一个函数里改了全局变量,导致另一个函数的行为完全乱套了。从那以后,我养成了在函数里用 local 的习惯。
2.5 常用命令组合:实战中的「组合拳」
单个命令功能有限,但组合起来威力巨大。我整理了几个我在项目中经常用的组合:
管道与重定向
# 查找日志中错误信息,统计出现次数
grep "ERROR" /var/log/app.log | sort | uniq -c | sort -rn
# 把进程信息保存到文件
ps aux | grep java > java_process.txt
命令替换
#!/bin/bash
# 获取当前日期,用于日志文件名
today=$(date +%Y%m%d)
echo "今天的日志文件:app_${today}.log"
# 获取服务器负载
load=$(uptime | awk '{print $NF}')
echo "当前系统负载:$load"
实战案例:批量备份配置文件
#!/bin/bash
# 批量备份 /etc 下的 .conf 文件
backup_dir="/backup/conf_$(date +%Y%m%d)"
mkdir -p $backup_dir
for conf_file in /etc/*.conf; do
if [ -f "$conf_file" ]; then
cp $conf_file $backup_dir/
echo "已备份:$conf_file"
fi
done
echo "备份完成,共备份 $(ls $backup_dir | wc -l) 个文件"
核心要点总结:
- 变量用
$引用,双引号里能解析 - 条件判断用
[],注意空格和运算符 - 循环用
for或while,根据场景选择 - 函数用
function_name() {}定义,局部变量用local - 管道
|和重定向>是组合命令的核心
说实话,Shell脚本这东西,光看是学不会的。我建议你打开终端,把上面的例子挨个敲一遍。遇到报错别慌,仔细看错误信息,大部分问题都是空格、引号、权限这些小细节。等你写了几十个脚本之后,这些东西就变成肌肉记忆了。