八、shell脚本
2026/6/8 21:26:01 网站建设 项目流程

Linux入门到大神笔记https://blog.csdn.net/qq_58308926/category_13058048.html?fromshare=blogcolumn&sharetype=blogcolumn&sharerId=13058048&sharerefer=PC&sharesource=qq_58308926&sharefrom=from_link

Linux企业实战练习https://blog.csdn.net/qq_58308926/category_13049591.html?fromshare=blogcolumn&sharetype=blogcolumn&sharerId=13049591&sharerefer=PC&sharesource=qq_58308926&sharefrom=from_link

一、Shell脚本概述

1.1 什么是Shell脚本

  • Shell脚本本质上是一个文件,里面定义了多个Linux命令、变量以及逻辑控制(判断、循环等)
  • 实现自动化运维,批量重复操作,减少管理员工作量
  • 基于Linux命令,解释性语言,上手简单

1.2 学习Shell脚本的前提

  1. 熟悉Linux常用命令
  2. 熟悉常用服务的部署与配置(如Apache、Nginx、DNS等)
  3. 熟练文本处理工具:grepawksed
  4. 熟悉Vim编辑器

二、Shell脚本编写规范

2.1 基本规范

  • 文件后缀:以.sh结尾
  • 第一行声明解释器#!/bin/bash#!/bin/sh
  • 注释:使用#表示注释行,不参与执行
  • 脚本开头建议包含信息
#!/bin/bash # Author: 作者名 # Mail: 联系方式 # Date: 日期 # Describe: 脚本描述 # Warning: 警告信息 # Version: 版本号 # Modify: 修改记录
  • 代码缩进:提高可读性
  • 尽量不使用中文注释(避免编码问题)

2.2 快速生成注释模板(.vimrc配置)

~/.vimrc中添加以下内容,新建.sh文件时自动生成头部注释:

autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()" func SetTitle() if expand("%:e") == 'sh' call setline(1,"#!/bin/bash") call setline(2,"##############################################################") call setline(3, "# File Name: ".expand("%")) call setline(4, "# Version: V1.0") call setline(5, "# Author: yourname") call setline(6, "# Email: your@email.com") call setline(7, "# Created Time : ".strftime("%F %T")) call setline(8, "# Description:") call setline(9,"##############################################################") call setline(10, "") endif endfunc

2.3 注释方式

  • 单行注释:以#开头
  • 多行注释:使用<<EOF ... EOF(EOF可替换为其他标识)
<<EOF 这是多行注释 不会被执行 EOF

三、Shell脚本的执行方式

3.1 四种执行方式

方式

语法

是否需要x权限

执行环境

相对路径

./script.sh

需要

子Shell

绝对路径

/root/script.sh

需要

子Shell

source或点

source script.sh. script.sh

不需要(需要r权限)

当前Shell

bash/sh

bash script.shsh script.sh

不需要(需要r权限)

子Shell

3.2 注意事项

  • 子Shell vs 当前Shell:在子Shell中定义的变量、环境更改不会影响父Shell;使用source.执行时,变量会在当前Shell中生效
  • 相对/绝对路径执行需要给脚本添加执行权限:chmod a+x script.sh

四、变量与参数

4.1 位置化变量(位置参数)

用于在执行脚本时传入参数:

变量

含义

$0

脚本文件本身的名字

$1

第一个参数

$2

第二个参数

...

...

${10}

第十个及以上参数需用花括号

示例:创建用户并设置密码的脚本

#!/bin/bash # useradd.sh useradd $1 echo $2 | passwd --stdin $1

执行:./useradd.sh zhangsan redhat

4.2 预定义变量

变量

含义

$?

上一条命令的退出状态码(0成功,非0失败)

$#

传递给脚本的参数个数

$*

所有参数(作为一个字符串)

$@

所有参数(每个作为独立字符串)

$$

当前Shell进程的PID

4.3 read命令 – 从键盘读取输入

语法read [选项] [变量名]

选项

说明

-p "提示信息"

输出提示信息

-s

隐藏输入(常用于密码)

-t 秒数

超时自动跳过

不指定变量名

数据存入环境变量REPLY

示例

#!/bin/bash read -p "请输入用户名: " username read -s -p "请输入密码: " password useradd $username echo $password | passwd --stdin $username echo "$username 创建成功,密码已设置"

4.4 exit命令

  • 直接执行exit会退出当前终端或脚本
  • 在脚本中遇到exit立即终止脚本
  • exit n:指定退出码(n为数字,0表示成功,1-255表示失败)
  • 退出码可通过echo $?查看

示例:检查密码中是否包含连续数字12345,若包含则退出

#!/bin/bash read -p "请输入密码: " pass echo $pass | grep 12345 -q if [ $? -eq 0 ]; then echo "密码不能包含12345" exit 1 fi echo "密码合法"

五、逻辑运算符与复合指令

5.1 逻辑运算符

运算符

含义

规则

&&

逻辑与

前一条命令成功(返回0)才执行后一条

`

`

!

逻辑非

对返回状态取反

示例

# 创建用户并设置密码 useradd luojiyu && echo 1 | passwd --stdin luojiyu # 如果用户存在则修改密码,否则创建 useradd devops || echo 1 | passwd --stdin devops # 判断IP是否通,根据结果写入不同文件 ping -c4 10.10.10.1 &>/dev/null && echo 10.10.10.1 > /opt/ip-ok.txt || echo 10.10.10.1 > /opt/ip-error.txt

5.2 复合指令

  • ;:顺序执行多条命令,无条件执行所有命令
command1; command2; command3
  • (命令;命令):在子Shell中执行,括号开头不需要空格,最后命令不用分号
(cd /tmp; pwd)
  • { 命令;命令; }:在当前Shell中执行,花括号开头必须有空格,每条命令以分号结尾
{ cd /tmp; pwd; }

六、条件测试语句

条件测试用于判断表达式的真假,返回值为0表示真,非0表示假。

6.1 三种测试语法

语法

说明

test 条件表达式

常用在终端临时测试

[ 条件表达式 ]

脚本中常用,注意空格

[[ 条件表达式 ]]

支持正则和通配符,更强大

示例

test root = 123 ; echo $? # 返回1 [ 1 -eq 1 ]; echo $? # 返回0 [[ "abc" == a* ]]; echo $? # 支持通配符,返回0

6.2 文件属性运算符

运算符

含义

-e 文件

文件存在

-f 文件

是普通文件

-d 文件

是目录

-s 文件

文件非空

-r 文件

可读

-w 文件

可写

-x 文件

可执行

-L 文件

是链接文件

示例

# 如果/tmp/passwd不存在则拷贝 [ -e /tmp/passwd ] || cp /etc/passwd /tmp/passwd # 如果useradd有执行权限则拷贝并修改所有者 [ -x /usr/sbin/useradd ] && cp /usr/sbin/useradd /tmp && chown devops /tmp/useradd # 如果文件没有读权限则添加 [ -r /tmp/passwd ] || chmod a+r /tmp/passwd

6.3 数字比较运算符

运算符

含义

-eq

等于

-ne

不等于

-gt

大于

-ge

大于等于

-lt

小于

-le

小于等于

注意:不要使用数学符号><等在条件测试中,它们会被解释为重定向

示例:判断根分区使用率是否超过10%

disk_num=$(df | grep -w / | awk '{print $5}' | tr -d %) if [ $disk_num -ge 10 ]; then rm -rf /tmp/* echo "tmp目录已清空" else echo "disk free,使用率: ${disk_num}%" fi

6.4 字符串比较运算符

运算符

含义

===

相等

!=

不等

-z 字符串

字符串为空(长度0)

-n 字符串

字符串非空

示例

# 判断输入是否为root read -p "输入用户名: " name [ "$name" = "root" ] && echo "UID: $(id -u root)" || exit # 检查参数是否为空 [ -z $1 ] && echo "请传入参数" || echo "参数是: $1"

6.5 布尔运算符(用于[ ]中)

运算符

含义

-a

逻辑与(AND)

-o

逻辑或(OR)

!

逻辑非

[[ ]]中可使用&&||!更直观。

示例

# 用户名是zhangsan 且 UID>=1000 [ "$username" = "zhangsan" -a $useruid -ge 1000 ] && echo ok || echo error # 使用[[ ]] [[ "$username" = "zhangsan" && $useruid -ge 1000 ]] && echo ok

七、判断语句

7.1 if单分支

语法

if 条件表达式; then 执行语句 fi # 第二种写法 if 条件表达式 then 执行语句 fi

示例:用户已存在则退出

#!/bin/bash read -p "输入用户名: " name if id $name &>/dev/null; then echo "$name 已存在,不能创建" exit fi useradd $name

7.2 if双分支

语法

if 条件表达式; then 语句1 else 语句2 fi

示例:用户存在则重置密码,否则创建

#!/bin/bash read -p "输入用户名: " name if id $name &>/dev/null; then read -p "重置密码: " pass echo $pass | passwd --stdin $name else useradd $name echo 1 | passwd --stdin $name fi

示例:备份脚本(判断目录是否存在)

#!/bin/bash read -p "要备份的文件路径: " src read -p "备份目录路径: " dst if [ -d "$dst" ]; then chmod 777 $dst else mkdir $dst fi cp -a $src $dst/$(basename $src)-$(date +%F).bak

7.3 if多分支

语法

if 条件1; then 语句1 elif 条件2; then 语句2 else 语句3 fi

示例:成绩等级判断

read -p "请输入成绩(0-100): " score if [ $score -ge 85 ]; then echo "优秀 - A" elif [ $score -ge 70 ]; then echo "良好 - B" elif [ $score -ge 60 ]; then echo "合格 - C" else echo "不合格 - D" fi

7.4 case多分支

用于多值匹配,比多个elif更清晰。

语法

case 变量 in 模式1) 命令 ;; 模式2) 命令 ;; *) 默认命令 ;; esac

示例:成绩等级(case版本)

read -p "请输入成绩(0-100): " score case $score in 8[5-9]|9[0-9]|100) echo "优秀 - A" ;; 7[0-9]|8[0-4]) echo "良好 - B" ;; 6[0-9]) echo "合格 - C" ;; *) echo "不合格 - D" ;; esac

模式支持

  • |表示或
  • [0-9]表示范围
  • *表示任意

八、循环语句

8.1 for循环

语法

for 变量名 in 列表; do 命令 done

四种列表生成方式

# 1. 直接列出 for i in 1 2 3 4 5; do echo $i; done # 2. 大括号(支持数字和字母) for i in {1..5}; do echo $i; done for c in {a..z}; do echo $c; done # 3. seq命令 for i in $(seq 1 5); do echo $i; done # 4. 命令执行结果 for file in $(ls *.sh); do echo $file; done

C语言风格for循环

for ((i=1; i<=10; i++)); do echo $i done

示例1:批量创建用户(从文件读取)

for user in $(cat userlist.txt); do useradd $user echo 123456 | passwd --stdin $user done

示例2:扫描局域网在线主机

for i in {1..254}; do ip="192.168.1.$i" ping -c2 -W1 $ip &>/dev/null if [ $? -eq 0 ]; then echo "$ip is up" else echo "$ip is down" fi done

8.2 while循环

当条件为真时循环,条件为假时退出。

语法

while 条件表达式; do 命令 done

示例:读取文件每一行(三种方式)

# 方式1:exec重定向 exec < file.txt while read line; do echo $line done # 方式2:管道 cat file.txt | while read line; do echo $line done # 方式3:重定向结尾(推荐) while read line; do echo $line done < file.txt

示例:从iplist文件读取IP和端口

# iplist内容: # 192.168.1.101 22 # 192.168.1.102 80 while read line; do IP=$(echo $line | awk '{print $1}') PORT=$(echo $line | awk '{print $2}') echo "IP: $IP, PORT: $PORT" done < iplist

8.3 until循环

与while相反:条件为时进入循环,为时退出。

语法

until 条件表达式; do 命令 done

示例:等待某个文件出现

until [ -f /tmp/ready ]; do echo "等待文件..." sleep 2 done echo "文件已出现"

8.4 break和continue

  • break:立即跳出当前循环
  • continue:跳过本次循环剩余语句,进入下一次迭代

示例

# break: 当i=4时跳出 for i in {1..10}; do if [ $i -eq 4 ]; then break fi echo $i done # 输出: 1 2 3 # continue: 当i=4时跳过 for i in {1..10}; do if [ $i -eq 4 ]; then continue fi echo $i done # 输出: 1 2 3 5 6 7 8 9 10

九、综合实践案例

9.1 一键部署Nginx脚本框架

#!/bin/bash # 检查是否root用户 if [ $EUID -ne 0 ]; then echo "请使用root用户执行" exit 1 fi # 安装依赖 yum install -y gcc make pcre-devel zlib-devel # 下载并编译安装Nginx cd /usr/local/src wget http://nginx.org/download/nginx-1.24.0.tar.gz tar xf nginx-1.24.0.tar.gz cd nginx-1.24.0 ./configure --prefix=/usr/local/nginx make && make install # 启动 /usr/local/nginx/sbin/nginx echo "Nginx部署完成"

9.2 安全创建用户脚本

#!/bin/bash read -p "请输入用户名: " username if id $username &>/dev/null; then echo "用户已存在" exit 1 fi read -s -p "请输入密码: " password read -s -p "确认密码: " password2 echo if [ "$password" != "$password2" ]; then echo "两次密码不一致" exit 1 fi useradd $username echo $password | passwd --stdin $username &>/dev/null echo "用户 $username 创建成功"

9.3 系统监控脚本

#!/bin/bash # 监控CPU、内存、磁盘使用率 cpu=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1) mem=$(free | grep Mem | awk '{printf "%.2f", $3/$2 * 100}') disk=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%') echo "CPU使用率: $cpu%" echo "内存使用率: $mem%" echo "根分区使用率: $disk%" if [ $disk -gt 80 ]; then echo "警告:磁盘空间不足" fi

十、总结

知识点

核心要点

编写规范

#!/bin/bash, 注释, .sh后缀

执行方式

路径需x权限;source在当前shell;其他在子shell

位置变量

1...

{10}

特殊变量

#参数个数

read

-p提示,-s隐藏,-t超时

条件测试

[ ],文件 -f/-d,数字 -eq/-gt,字符串 =/-z

逻辑符

&&(成功则执行),||(失败则执行)

判断

if单/双/多分支,case多值匹配

循环

for(列表/C风格),while(条件真循环),until(条件假循环)

控制

break跳出,continue跳过本次

掌握以上内容,即可编写大部分日常运维所需的Shell脚本。实践中多动手、多调试,利用set -x调试模式查看执行过程。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询