本文最后更新于:2023年12月5日 晚上
基本用法
脚本调试
脚本错误分为三种:
- 语法错误,导致后续命令不继续执行,使用
bash -n
检查错误
- 命令错误,默认后续命令继续执行,使用
bash -x
检查错误
- 逻辑错误,只能使用
bash -x
检查
变量
shell 脚本中的所有变量值都是字符串,其中的数字也是字符串
shell 中变量命名规则
注意: 不支持短横线 “-”,这点和主机名相反
定义变量
引用变量
关于$:
拼接字符串:
删除变量
declare ★★★
declare 是 bash 内置命令,用来声明变量
Shell 内建命令之 trap:https://blog.csdn.net/asty9000/article/details/88393166
i 示例:
n 示例:
eval ★★★
先扫描一遍,进行置换,再执行命令
练习
1、编写脚本 systeminfo.sh,显示当前主机系统信息,包括:主机名,IPv4 地址,操作系统版本,内核版本,CPU 型号,内存大小,硬盘大小
2、编写脚本 backup.sh,可实现每日将 /etc/ 目录备份到 /backup/etcYYYY-mm-dd 中
3、编写脚本 disk.sh,显示当前硬盘分区中空间利用率最大的值
4、编写脚本 links.sh,显示正连接本主机的每个远程主机的 IPv4 地址和连接数,并按连接数从大到小排序
环境变量
对所有用户生效的环境变量:/etc/profile
对特定用户生效的环境变量:~/.bashrc
或者 ~/.bash_profile
临时有效的环境变量:脚本或命令行使用 export 定义
常用环境变量:
显示所有环境变量:
位置变量
位置变量,在 bash shell 中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数
注意:$@
和 $*
只有在被双引号包起来的时候才会有差异,在 for in
循环中,不加引号的时候,$*
和 $@
都可以正常遍历,加双引号的时候,$*
只有一个字符串变量
清空所有位置变量:
范例:利用软链接实现同一个脚本不同功能
退出状态码
用于无条件终止当前脚本的执行 exit n
1-125 这些错误值可以由用户自定义
如果不给定 n 的值,而直接使用 exit,那么返回 exit 之前最后一条语句的状态,等于 exit $?
‘’ “” `` $()
单引号不解析变量,双引号解析变量,反引号中必须是有输出的命令,$() 和 ``是等价的, 但是 $() 可以嵌套
脚本安全和 set
set 命令:可以用来定制 shell 环境,set + 关闭设置,set - 打开设置
set 命令实现脚本安全:
参考:http://www.ruanyifeng.com/blog/2017/11/bash-set.html?utm_source=tool.lu
格式化输出 printf
常用转义字符:
算术运算
bash 只支持整数运算,不支持小数运算。复杂的运算请使用 bc
加减乘除、自加自减,取余,异或取反,三元运算等都和 php 一样。
$RANDOM:内建的随机数生成器变量
示例:生成 0-49 随机数
示例:鸡兔同笼
逻辑运算 &&、||、
短路运算
使用 read 命令来接受输入
read 是 shell 内置命令,从标准输入中读取数据并赋值给变量。如果没有重定向,默认是从键盘读取用户输入的数据,如果进行了重定向,那么可以从文件中都去数据。
如果没有提供变量名,那么读取的数据默认存放到环境变量 REPLY 中。
read 就像表单提交,所有用户提交的信息都是不可信的,一定要做好校验
bash shell 的配置文件
bash shell 配置文件有: /etc/profile
、~/.bash_profile
、~/.bash_login
、~/.profile
、~/.bashrc
、/etc/bashrc
、/etc/profile.d/\*.sh
,不同的启动方式会加载不同的配置文件
生效范围
/etc 目录下的配置文件是全局生效,家目录下的配置文件是对当前用户生效
配置文件太多,为了避免混乱,默认:对所有用户添加配置,添加到 /etc/profile.d/ 目录下,当前用户添加配置,添加到 ~/.bashrc 中
登录方式
shell 登录有两种方式:交互式登录和非交互式登录
交互式
- 帐号密码登录;
su - userName
配置文件生效和执行顺序:
Ubuntu18.4
CentOS7
非交互式
su userName
;
- 图形化界面下打开的终端;
- 执行脚本;
- 任何其他的 bash 实例
非交互式登录,只加载 ~/.bashrc
(centos 的~/.bashrc 中会加载/etc/bashrc 文件)
所以按照功能划分:profile 类只在交互式登录中加载,而 bashrc 类在交互式和非交互式登录中都有加载
bash 退出任务
退出 shell 时自动运行 ~/.bash_logout
文件,可以用来创建自动备份文件、清除临时文件
流程控制 - 条件选择
if
if/then/elif/else/fi
单分支
双分支
多分支
case
类似 php 中的 switch
case/esac
case 支持 glob 风格的通配符:*、?、[]、|
流程控制 - 循环
for in
for in/do/done
递归遍历当前目录下的所有文件
while
while/do/done
无限循环
验证密码,限制尝试输入不超过 5 次
while read
while 循环的特殊用法,遍历文件或文本的每一行
练习,使用 while 实现:
- 编写脚本,求 100 以内所有正奇数之和
- 编写脚本,提示请输入网络地址,如 192.168.0.0,判断输入的网段中主机在线状态,并统计在线和离线主机各多少
- 编写脚本,打印九九乘法表
- 编写脚本,利用变量 RANDOM 生成 10 个随机数字,输出这个 10 数字,并显示其中的最大值和最小值
- 编写脚本,实现打印国际象棋棋盘
- 后续六个字符串: efbaf275cd、4be9c40b8b、44b2395c46、f8c8873ce0、b902c16c8b、ad865d2f63 是通过对随机数变量 RANDOM 随机执行命令:
echo $RANDOM | md5sum | cut -c1-10
后的结果,请破解这些字符串对应的 RANDOM 值
until
while 判断条件为真则循环,until 判断条件为假则循环
无限循环
循环控制 continue 和 break
continue 跳过本次循环,break 跳出所有循环
循环控制 shift
将参数列表最左边的参数删除,while 循环遍历位置参量列表时,常用到 shift
select
select 用于生成菜单,并显示 PS3 提示符,然后等待用户输入,无论输入什么都执行一遍循环,常搭配 case 来处理用户输入,select 通过 break 退出循环
示例:
函数
函数运行在当前 shell 进程
定义函数
调用函数
删除函数
函数返回值
函数返回值:
- 使用 echo 等命令进行输出
- 函数体中调用命令的输出结果
函数的退出状态码:
- 默认取决于函数中执行的最后一条命令的退出状态码
- 自定义退出状态码,其格式为:
return 从函数中返回,用最后状态命令决定返回值
return 0 无错误返回
return 1-255 有错误返回
函数变量
脚本相关工具
trap
信号捕捉,捕捉一个或多个信号,替换为自定义操作
trap 捕捉的信号包括系统信号和 shell 信号,系统信号通过trap -l
或kill -l
查看,shell 信号有四个:EXIT(或信号代码 0)、ERR、DEBUG 和 RETURN。
信号名是 SIG 后面的部分,捕捉的时候可以写信号的编号,也可以写信号名称,不区分大小写
由于不少信号在不同架构的计算机上数值不同,所以在不确定编号是否唯一的时候,最好写信号名称
DEBUG 和 RETURN 这两种信号陷阱无需关注,EXIT 是退出状态码为 0 时发出的信号,退出状态码非 0 时则发出 ERR 信号
系统信号的编号从 1 到 64,EXIT 的编号是 0
mktemp
创建临时文件,可以避免文件名冲突
expect
expect 基于 Tcl( Tool Command Language )语言开发,主要应用于自动化交互式操作的场景,借助 expect 处理交互的命令,可以将交互过程如:ssh 登录,ftp 登录等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率
数组
定义
shell 和 php 一样,支持索引数组和关联数组。
注意:声明索引数组可以省略 declare,声明关联数组不能省略 declare,如果省略不报错,但是数据会乱。
调用
字符串
切片
假设有一个指针 pointer,始终指向字符串的“间隙”,从前往后,“间隙”号依次为 0、1、2、3…,而且显然“间隙”数量比字符数量多 1 个,如果字符串有 2 个字符,那就有 3 个“间隙”。指针默认指向 0,指针的位置就是切片位置。
查找替换
${str#*word}
查找 word 第一次出现的位置,删除其以及之前的部分
${str##*word}
贪婪模式,查找 word 最后一次出现的位置,删除其及其之前的部分
${str%word*}
查找 word 最后出现的位置,删除其及其之后的部分
${str%%word*}
查找 word 第一次出现的位置,删除其及其之后的部分
${str/pattern}
删除第一个匹配
${str//pattern}
删除所有匹配
大小写转换
${str^^}
转大写
${str,,}
转小写
变量测试
变量测试点比较多,而且不怎么用,主要用 if 来判断测试,所以不用深究