shell脚本编程(一)
前言
Shell 是 Linux/Unix 系统的命令行解释器,也是运维工程师最核心的自动化工具。Shell 脚本本质是一个按顺序存放 Linux 命令的文本文件,加上变量、条件判断、循环和函数,就成了一门完整的编程语言,特别适合系统管理、软件部署、日志分析和定时任务等场景。相比其他编程语言,Shell 在调用系统命令、管理进程和处理文本方面有天然优势。
一、Shell介绍
1.1 Shell简介
Shell 是 一个用 C 语言编写的程序,是Linux系统中的一个命令行解释器,它是用户与操作系统内核之间的桥梁。简单说,就是你输入命令,Shell 负责理解并告诉内核去执行。
1.2 Shell三大功能
- 命令翻译:把命令翻译成内核能懂的指令
- 输入输出管理 :管理数据从哪来到哪去
- 编程能力:把命令写成脚本自动执行
1.3 常见Shell类型
(1)/bin/bash:默认Shell,CentOS/RHEL都用它
(2)/bin/sh: bash的"祖先",已软链接到bash
(3)/bin/tcsh :C Shell增强版
1.4 Shell解释器
Linux 系统中存在多种 Shell 解释器,用户可通过以下命令查看系统中已安装的 Shell:
cat /etc/shells #查看系统支持的所有Shell
echo $SHELL #查看当前使用的Shell


二、Shell脚本编写与执行
2.1 Shell脚本的基本构成
| 部分 | 说明 | 示例 |
|---|---|---|
| 脚本声明 | 告诉系统用什么解释器 | #!/bin/bash |
| 注释 | 代码说明,不被执行 | # 这是注释 |
| 命令 | 实际执行的语句 | echo “hello” |
2.2 编写 Shell 脚本
使用文本编辑器(如 vi)创建一个新文件,扩展名通常为 .sh
#!/bin/bash
echo "Hello World"
#! 是一个约定标记,指定脚本使用的解释器路径。echo 用于向窗口输出文本。

2.4 创建脚本四步流程
- 创建文件 :vim f01.sh
- 添加权限 :chmod +x f01.sh
- 检查语法 :bash -n f01.sh
- 执行脚本:./f01.sh
2.3 执行 Shell 脚本
- 执行脚本前需赋予执行权限:
chmod +x ./f01.sh

- 执行方式有四种(最常用的是前两种):
sh f01.sh(作为解释器参数执行)./f01.sh(当前目录下执行)source f01.sh(source执行)sh < f01.sh(重定向执行)
- source和bash区别
(1)bash 会创建子进程执行,脚本里的 cd、export、变量赋值等操作,只对子 Shell 生效。脚本执行完毕,子 Shell 销毁,当前终端环境完全不变。
(2)source不会创建子 Shell,直接在当前的 Shell 中逐行执行,不会创建子 Shell,直接在当前的 Shell 中逐行执行。脚本里的 cd、export、变量赋值等操作,会直接影响当前终端。
三、Shell 程序:变量
3.1 语法格式
变量定义格式:变量名=值(等号两侧不能有空格)
- 命名规则:
(1)只能包含字母、数字、下划线
(2)不能以数字开头
(3)区分大小写
3.2 变量使用
利用 $变量名 或 ${变量名} 使用变量。
#!/bin/bash
name="小明"
age=18
echo $name
echo $age
echo "my name is$name ,age is${age}"
#变量后面紧跟着其他字符(比如字母、数字、下划线)时,就必须用花括号{}把变量名括起来,告诉 Shell 哪部分是变量名,哪部分是普通文本。


3.3 echo命令高级用法
- 选项含义:
| 选项 | 作用 | 示例 |
|---|---|---|
| -n | 不换行 | echo -n “请输入” |
| -e | 识别转义符 | echo -e “a\nd” |
- 常用转义字符:最常用是
\n、\t
| 字符 | 含义 |
|---|---|
| \n | 换行 |
| \t | 制表符 |
| \c | 不换行 |
| \b | 退格 |
| \ \ | 输出\本身 |
| \$ | 输出$本身 |

四、特殊变量赋值
4.1 双引号和单引号
- 双引号识别变量,单引号不识别变量

注:需要变量值时用双引号,需要原样输出时用单引号
4.2 反撇号与命令替换
作用:把命令输出存到变量里
4.2.1 反撇号
time=`date +%T`
echo "$time"

4.2.2 $()
$()更容易嵌套
echo "今天日期:$(date +%Y年%m月%d日)"

4.3 read交互式输入命令
常用选项
-p:显示提示-n:限制字符数-s:静默输入(输入密码)-t:超时秒数
#!/bin/bash
read -p "请输入名字:" name
echo "你好,$name"
read -n 11 -p "请输入手机号:" phone
echo ""
echo "$phone"
read -s -p "请输入密码:" pwd
echo "$pwd"


五、变量运算
5.1 expr
expr 是一款表达式计算工具,它能完成表达式的求值操作。
expr 1 + 1 #运算符两边必须有空格
expr 2 \* 3 #乘法需要转义
expr 10 % 3 #取余
a=5
b=3
expr $a + $b #expr也支持变量运算
sum=`expr $a + $b` #用反撇号把结果存为变量
echo $sum
sum=$(expr $a + $b) #用$()把结果存为变量
echo $sum



5.2 $[ ] 和 $(())
echo $[2 * 3] #用$[]不需要把乘法转义
echo $((2 * 3)) #用$(())不需要把乘法转义
a=9
b=6
echo $[a + b]
echo $((a - b))
echo $[a * b]
echo $[a / b]

- 三种方式对比:
| 方式 | 乘法转义 | 变量$ |
|---|---|---|
| expr | 需要 | 需要 |
| $[] | 不需要 | 可省略 |
| $(()) | 不需要 | 可省略 |
5.3 let命令——直接修改变量
let会修改变量本身
num=5
let num=num+4 #此时num变为9
echo $num #输出num为9
num=5
let num+=5 #此时num变为10
echo $num #输出num为10
let num-=4 #此时num为10-4=6
echo $num #输出num为6
let num*=2 #此时num为6*2=12
echo $num #此时num为12

let自增自减
num=15
let num++ #此时num为16
echo $num #输出为16
let num-- #此时num为16-1=15
echo $num #输出为15

let幂运算(特有)
num=2
let num=num**10 #2的10次方,num变为1024
echo $num #输出为1024

5.4 bc计算器——浮点运算
5.4.1 expr只能计算整数,而bc可以计算小数(基本用法)
echo "scale=2; 10/3" | bc #scale=2 表示保留2位小数,输出为3.33
echo "4^2" | bc #表示4的2次方,输出为16
echo "sqrt(16)" | bc #表示为16开根号,输出为4
r=5
echo "3.14159 * $r * $r" | bc #表示为3.14159*5*5,输出为78.53975
scale只对除法有效
5.4.2 bc逻辑运算(返回0或1)
echo "3>5"|bc #输出为0(假)
echo "3<5"|bc #输出为1(真)
echo "10 == 10"|bc #输出为1(真)

六、变量类型与作用范围
6.1 自定义变量与环境变量
- 自定义变量:用户自己定义的变量
- 环境变量:系统预定义的
- 常见环境变量:
| 变量 | 含义 |
|---|---|
| echo $USER | 当前用户名 |
| echo $HOME | 用户主目录 |
| echo $PWD | 当前工作目录 |
| echo $SHELL | 默认Shell |
| echo $LANG | 系统语言 |
| echo $RANDOM | 随机数(0-32767) |
| echo $UID | 用户ID |
echo $PATH #命令搜索路径,查看PATH

注:PATH=“” 会让所有命令失效!
6.2 只读变量
readonly PI=3.1415926 #设置只读变量
PI=3.14 #结果报错,只读变量不能改变
unset PI #只读变量无法删除

6.3 位置变量
#!/bin/bash
echo "脚本名称:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "第三个参数:$3"
echo "参数总数:$#"
echo "所有参数(\$*):$*"
echo "所有参数(\$@):$@"
ls /etc > /dev/null
echo "ls /etc 的返回值:$?" # 返回值为0则上一条命令正确,返回值大于0则上一条命令错误
ls /abc > /dev/null 2>&1
echo "ls /abc 的返回值:$?"
echo "当前Shell进程PID:$$"
sleep 100 &
echo "后台进程PID:$!"

6.4 预定义变量
常用预定义变量
$?:上一条命令的返回状态(0=成功,非0=失败)$$:当前进程的进程号$!:最后一个后台进程的进程号
ls /etc > /dev/null
echo "ls /etc 的返回值:$?" # 返回值为0则上一条命令正确,返回值大于0则上一条命令错误
ls /abc > /dev/null 2>&1
echo "ls /abc 的返回值:$?"
echo "当前Shell进程PID:$$"
sleep 100 &
echo "后台进程PID:$!"

6.5 export命令
name="李四"
bash # 进入子Shell
echo $name # 无输出(子Shell看不到)
exit # 退出子Shell
export name # 导出变量
bash # 进入子Shell
echo $name # 输出:李四(子Shell能看到)
#export的三种用法
#方式1:先定义再导出
name="李四"
export name
#方式2:定义时直接导出
export city=beijing
# 方式3:export -n 取消导出
export -n name # 取消后,子Shell又看不到了

七、重定向与管道
7.1 标准输入输出与错误输出
Linux的三条“流水线”
| 文件描述符 | 名称 | 默认设备 | 说明 |
|---|---|---|---|
| 0 | STDIN | 键盘 | 程序从这里读数据 |
| 1 | STDOUT | 显示器 | 正常输出到这里 |
| 2 | STDERR | 显示器 | 错误信息到这里 |
7.2 输出重定向
uname -p > kernel.txt # > 覆盖:把输出保存到文件(覆盖原有内容)
uname -r >> kernel.txt # >> 追加:把输出追加到文件末尾
ls /etc/passwd xxx > ok.txt 2> err.txt # 正确的保存到ok.txt,错误的保存到err.txt
command > /dev/null 2>&1 # 忽略所有输出(正确+错误都丢弃)
echo $? #输出值为0,则上一条命令正确



7.3 输入重定向
#输出到文件
cat > config.txt << EOF
app_name=MyApp
version=1.0
EOF
cat config.txt #查看文件

7.4 管道操作
- 常用管道命令
| 命令 | 功能 |
|---|---|
| grep | 过滤 |
| sort | 排序 |
| uniq | 去重/统计 |
| wc | 统计行/字/字符 |
| cut | 提取列 |
rpm -qa | grep httpd # 查找httpd包
who | wc -l # 统计当前登录用户数
cat test.txt | awk '{print $1}' | sort | uniq -c | sort -rn | head -3 # 统计文件中出现次数最高的3个水果
# awk '{print $1}':取每行第一个字段(通常是 IP)
# sort :排序,方便 uniq 统计
# uniq -c :统计每个 IP 出现次数
# sort -rn :按次数倒序排序
# head -10 :取前 10 条
cat /etc/passwd | grep "/bin/bash$" | cut -d: -f1 # 提取bash用户
# grep "/bin/bash$" 选择以/bin/bash结尾的行
# -d:指定以冒号为分割符
# -f1 取第一列



- 常用管道组合
| 组合 | 含义 |
|---|---|
| sort filename | 按字母排序 |
| sort -n filename | 按数字排序 |
| sort -r filename | 倒序 |
| sort file | uniq | 去重 |
| sort file |uniq -c | 统计出现次数 |
| sort file | uniq -d | 只显示重复行 |
7.5 案例
7.5.1 案例一:自动化备份
#!/bin/bash
echo "CPU负载:$(uptime | awk '{print $10}')" #打印第10列
echo "内存:$(free -h | awk 'NR==2{print $3"/"$2}')"
echo "磁盘:$(df -h | awk 'NR>1 && $5+0>80 {print "⚠ 磁盘"$1"使用率:"$5}')" #行号>1(跳过标题行)且 第5字段数值>80,打印警告信息、第1字段(分区名)、第5字段(使用率%)


7.5.2 案例二:服务器健康检查
#!/bin/bash
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d)
tar -czf ${BACKUP_DIR}/backup_${DATE}.tar.gz /home 2>${BACKUP_DIR}/error.log
#将 /home 目录打包压缩成带日期的 .tar.gz 文件,并把所有错误信息单独保存到日志文件中。
if [ $? -eq 0 ]; then
echo "✓ 备份成功!"
else
echo "✗ 备份失败,请查看错误日志"
fi


总结
本文系统介绍了Shell编程的核心基础知识。Shell既是命令解释器,也是脚本编程语言,在系统管理和自动化运维中应用广泛。
- 脚本编写与执行:创建脚本文件后需赋予执行权限
(chmod +x),可通过路径执行、bash调用或source方式运行,三种方式在子进程环境上有所区别。 - 变量与字符串:变量定义无需声明类型,局部变量与环境变量作用域不同;单引号保留字面值,双引号支持变量解析。
- 参数传递与运算符:
$#统计参数个数,$*将所有参数合并为单字符串,$@保持参数独立。同时掌握了算术运算、关系比较、逻辑操作及文件测试等各类运算符的使用方法。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)