设计网站公司力荐亿企邦,阿里云wordpress 讲解,关于网站开发的自我评价,gae+wordpress目录 1 基础1.1 程序组成1.2 程序编程风格1.3 编程语言1.4 编程逻辑处理方式 2 shell 脚本语言的基本结构2.1 shell脚本的用途2.2 shell脚本基本结构2.3 创建shell脚本过程2.4 脚本注释规范2.5 第一个脚本2.6 脚本调试2.7 变量2.7.1 变量2.7.2 变量类型2.7.3 编程语言分类2.7.4… 目录 1 基础1.1 程序组成1.2 程序编程风格1.3 编程语言1.4 编程逻辑处理方式 2 shell 脚本语言的基本结构2.1 shell脚本的用途2.2 shell脚本基本结构2.3 创建shell脚本过程2.4 脚本注释规范2.5 第一个脚本2.6 脚本调试2.7 变量2.7.1 变量2.7.2 变量类型2.7.3 编程语言分类2.7.4 shell中变量命名法则2.7.5 变量定义和引用2.7.6 环境变量2.7.7 只读变量2.7.8 位置变量2.7.9 退出状态码变量2.7.10 展开命令行2.7.11 脚本安全和 set 命令 2.8 格式化输出 printf2.9 算术运算2.10 逻辑运算2.11 条件测试命令2.11.1 变量测试2.11.2 数值测试2.11.3 字符串测试2.11.4 文件测试 2.12 关于()和{}2.13 组合测试条件2.13.1 方法 1 []2.13.2 方法 2 [[]] 2.13 使用read命今来接受输入 3 bash的配置文件3.1 按生效范围划分两类3.2 shell登录两种方式分类3.2.1 交互式登录3.2.2 非交互式登录 3.3 按功能划分分类3.3.1 profile类3.3.2 Bashrc类 3.4 编辑配置文件生效3.5 Bash 退出任务 4 流程控制4.1 条件选择4.1.1 选择执行 if 语句4.1.2 条件判断 case 语句 4.2 循环4.2.1 循环执行介绍4.2.2 for循环**格式1:****格式2** 例加入参数实现三角形4.2.3 while循环4.2.4 until循环4.2.4 循环控制语句 continue4.2.5 循环控制语句 break4.2.6 循环控制 shift 命令4.2.7 while read 特殊用法4.2.8 select 循环与菜单 5 函数介绍5.1 管理函数5.1.1 定义函数5.1.2 查看函数5.1.3 删除函数 5.2 函数调用**5.2.1 交互式环境调用函数**5.2.2 在脚本中定义及使用函数5.2.3 使用函数文件 5.3 函数返回值5.4 环境函数5.5 函数参数5.6 函数变量5.7 函数递归 6 其它脚本相关工具6.1 信号捕捉 trap6.2 创建临时文件 mktemp6.3 安装复制文件 install6.4 交互式转化批处理工具 expect 7数组7.1 数组介绍7.2 声明数组7.3 数组赋值7.4 显示所有数组7.5 引用数组7.6 删除数组7.7 数组数据处理7.8 关联数组7.9 范例 8 字符串处理8.1 字符串切片8.2 查找替换、8.3 查找并删除8.4 字符大小写转换 9 高级变量9.1 高级变量赋值9.2 高级变量用法-有类型变量9.3 变量间接引用9.3.1 eval命令9.3.2 间接变量引用9.3.3变量引用reference 1 基础
1.1 程序组成
程序:算法数据结构数据:是程序的核心算法:处理数据的方式数据结构: 数据在计算机中的类型和组织方式
1.2 程序编程风格
面向过程语言
做一件事情排出个步骤第一步干什么第二步干什么如果出现情况A做什么处理如果出现了情况B做什么处理问题规模小可以步骤化按部就班处理以指令为中心数据服务于指令Cshell
面向对象语言
一种认识世界、分析世界的方法论。将万事万物抽象为各种对象类是抽象的概念是万事万物的抽象是一类事物的共同特征的集合对象是类的具象是一个实体问题规模大复杂系统以数据为中心指令服务于数据javaC#pythongolang等
1.3 编程语言
计算机运行二进制指令
编程语言人与计算机之间交互的语言。分为两种:低级语言和高级语言 低级编程语言: 机器二进制的0和1的序列称为机器指令。与自然语言差异太大难懂、难写 汇编用一些助记符号替代机器指令称为汇编语言 如:ADDAB 将寄存器A的数与寄存器B的数相加得到的数放到寄存器A中 汇编语言写好的程序需要汇编程序转换成机器指令 汇编语言稍微好理解即机器指令对应的助记符助记符更接近自然语言 高级编程语言: 编译高级语言–编译器–机器代码文件-执行如: CC解释高级语言–执行–解释器–机器代码如: shellpythonphpJavaScriptperl
编译和解释型语言
1.4 编程逻辑处理方式 三种处理逻辑
顺序执行选择执行循环执行
2 shell 脚本语言的基本结构
2.1 shell脚本的用途
自动化常用命令执行系统管理和故障排排除创建简单的应用程序处理文本或文件
2.2 shell脚本基本结构
shell脚本编程:是基于过程式、解释执行的语言
编程语言的基本结构
各种系统命令的组合 数据存储:变量、数组 表达式:ab 控制语句: if
shell脚本:包含一些命令或声明并符合一定格式的文本文件
格式要求:首行shebang机制
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl2.3 创建shell脚本过程
第一步使用文本编辑器来创建文本文件
第一行必须包括shell声明序列: #!示例:#!/bin/bash添加注释,注释以#开头
第二步加执行权限
给予执行权限在命令行上指定脚本的绝对或相对路径
第三步运行脚本
直接运行解释器将脚本作为解释器程序的参数运行
autocmd BufNewFile *.sh exec :cal SetTitle()
func SetTitle()if expand(%:e) shcall setline(1,#!/bin/bash)call setline(2,#)call setline(3,#*****************************************************)call setline(4,#Author: minNexus)call setline(5,#QQ: 1299575088)call setline(6,#Date: .strftime(%Y-%m-%d))call setline(7,#FileName: .expand(%))call setline(8,#URL: https://blog.csdn.net/qq_24472227?typeblog) call setline(9,#Description: The test script)call setline(10,#Copyright (C): .strftime(%Y), All rights reserved)call Setline(11,#****************************************************)call setline(12,)endif
endfunc
autocmd BufNewFile * normal G2.4 脚本注释规范 第一行一般为调用使用的语言 程序名避免更改文件名为无法找到正确的文件 版本号 更改后的时间 作者相关信息 该程序的作用及注意事项 最后是各版本的更新简要说明
2.5 第一个脚本
[rootCentOS8 ~]#vim hello.sh
输入echo hello world
[rootCentOS8 ~]#./hello.sh 执行hello.sh
hello world2.6 脚本调试 语法错误导致后续命令不再执行 命令错误后续命令仍然执行 逻辑错误
检测脚本中的语法错误bash后加-n提示出错行不一定准确不执行
bash -n /path/to/some_script一定程度上检查逻辑出错 与 命令出错调试并执行加-x逐行执行并显示
bash -x /path/to/some_script注意
bash ScriptName 开启一个子进程在里面执行脚本source ScriptName 在当前进程执行脚本不开启子进程如果在其中修改了变量则修改了当前shell的变量不推荐使用除非配置文件
2.7 变量
2.7.1 变量
变量表示命名的内存空间将数据放在内存空间中通过变量名引用获取数据
2.7.2 变量类型
类型
内置变量如: PS1PATHUIDHOSTNAMEPPID$ ?BASHPIDHISTSIZE使用$查看用户自定义变量
不同的变量存放的数据不同决定了以下
数据存储方式参与的运算表示的数据范围
变量数据类型:
字符数值整型、浮点型 bash不支持浮点型
2.7.3 编程语言分类
静态和动态语言
静态编译语言:使用变量前先声明变量类型之后类型不能改变在编译时检查如:javac动态编译语言:不用事先声明可随时改变类型如: bashPython
强类型和弱类型语言
强类型语言: 不同类型数据操作必须经过强制转换才同一类型才能运算如java c#python
如:以下python代码
print(magedu 10) 提示出错不会自动转换类型
print(magedustr(10)) 结果为magedu10需要显示转换类型弱类型语言:语言的运行时会隐式类型转换。无须指定类型默认均为字符型参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用 如: bash phpjavascript
2.7.4 shell中变量命名法则
不能使程序中的保留字:如: if,for
只能使用数字、字母及下划线且不能以数字开头注意:不支持短横线“.和主机名相反
见名知义用英文单词命名并体现出实际作用不要用简写如: ATM
统一命名规则驼峰命名法studentname大驼峰StudentName 小驼峰studentName
变量名大写STUDENTNAME局部变量小写函数名小写
2.7.5 变量定义和引用
变量的生效范围等标准划分变量类型
普通变量生效范围为当前shel进程对当前shell之外的其它shell进程包括当前shell的子shell进程均无效环境变量生效范围为当前shell进程及其子进程本地变量生效范围为当前shell进程中某代码片断通常指函数
变量赋值:
namevaluevalue可以是以下多种形式
直接字串: name‘root’变量引用: name“$USER”命令引用: nameCOMMAND 或者 name$(COMMAND)
注意变量赋值临时生效终端退出将自动删除不过为了安全起见最好使用完手动删除。脚本中的变量也随脚本结束自动删除 变量引用:
$name
${name}弱引用和强引用
$name 双引号弱引用其中的变量引用会被替换为变量值
$name 单引号强引用其中的变量引用不会被替换为变量值而保持原字符串显示已定义的所有变量
set删除变量
unset name例
1
[rootCentOS8 ~]#ls
f1.txt f2.txt f3.txt issue.bak passwd scripts test.img
[rootCentOS8 ~]#FILE* 将当前文件夹所有文件名保存至变量FILE中
[rootCentOS8 ~]#echo $FILE
f1.txt f2.txt f3.txt issue.bak passwd scripts test.img2
[rootCentOS8 ~]#FILEi am $HOSTNAME 将hostname的变量名存入变量FILE中
[rootCentOS8 ~]#echo $FILE
i am CentOS8.Joyce.person13
[rootCentOS8 ~]#seq 10
1
2
3
4
5
6
7
8
9
10
[rootCentOS8 ~]#NUMseq 10
[rootCentOS8 ~]#echo $NUM
1 2 3 4 5 6 7 8 9 10
[rootCentOS8 ~]#echo $NUM 加双引号保留多行格式
1
2
3
4
5
6
7
8
9
102.7.6 环境变量
环境变量可以使子进程(包括子子进程)继承父进程的变量但是无法让父进程使用子进程的变量 一旦子进程修改从父进程继承的变量新的值将传递给子子进程 一般只在系统配置文件中使用在脚本中较少使用
声明环境变量 并赋值
export nameVALUE
declare -x nameVALUE或分2步
nameVALUE
export name变量引用
$name
${name}例
[rootCentOS8 ~]#NAMEjoyce
[rootCentOS8 ~]#AGE21
[rootCentOS8 ~]#echo $NAME$AGE
joyce21
[rootCentOS8 ~]#echo $NAME_$AGE
21
[rootCentOS8 ~]#echo ${NAME}_$AGE
joyce_21显示所有环境变量
env
printenv
export
declare -x删除变量:
unset namebash内建的环境变量
PATH
SHELL
USER
UID
HOME
PWD
SHLVL 当前所在shell的深度使用bash进入下一shell开子进程后深度1最低是1
LANG 当前设置语言与编码格式
MAIL 邮箱位置
HOSTNAME
HISTSIZE
_ 下划线表示前一命令的最后一个参数前面记得加$脚本显示系统信息
RED\E[1;31m
GREEN\E[1;32m
END\E[0m
echo -e \E[1;32m--------------------------------Host systeminfo------------------------------------$END
echo -e HOSTNAME: $REDhostname$END
echo -e IPADDR: $RED ifconfig ens160|grep -Eo ([0-9]{1,3}\.){3}[0-9][1,3] |head -n1$END
echo -e OSVERSION: $REDcat /etc/redhat-release$END
echo -e KERNEL: $REDuname -r$END
echo -e CPU: $REDlscpu|grep Model name|tr -s |cut -d : -f2$END
echo -e MEMORY: $REDfree -h|grep Mem|tr -s : |cut -d : -f2$END
echo -e DISK: $REDlsblk |grep ^sd |tr -s |cut -d -f4$END
echo -e \E[1;32m-----------------------------------------------------------------------------------$END2.7.7 只读变量
只读变量只能声明定义但后续不能修改和删除即常量退出终端自动删除
声明只读变量: 加-r
readonly name
declare -r name查看只读变量:
readonly [-p]
declare -r2.7.8 位置变量
位置变量在bash shell中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数
$1$2... 对应第1个、第2个等参数shift [n]换位置
$0 命令本身包括路径想只显示名字可以写basename $0
$* 传递给脚本的所有参数全部参数合为一个字符串
$ 传递给脚本的所有参数每个参数为独立字符串
$# 传递给脚本的参数的个数注意: $ $ 只在被双引号包起来的时候才会有差异*
清空所有位置变量
set --例
[rootCentOS8 ~]#cat arg.sh 查看arg.sh文件
#!/bin/bash
#
#*****************************************************************************
#Author: minNexus
#QQ: 1299575088
#Date: 2023-07-25
#FileName: arg.sh
#URL: https://blog.csdn.net/qq_24472227?typeblog
#Description: The test script
#Copyright (C): 2023 All rights reserved
#****************************************************************************echo lst arg is $l
echo 2st arg is $2
echo 3st arg is $3
echo 10st arg is ${l0}
echo 1lst arg is ${11}echo The number of arg is $#
echo All args are $*
echo All args are $
echo The scriptname is basename $0[rootCentOS8 ~]#bash arg.sh {a..z} 运行脚本加上a..z参数
lst arg is
2st arg is b
3st arg is c
10st arg is
1lst arg is k
The number of arg is 26
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
The scriptname is arg.sh2.7.9 退出状态码变量
进程执行后将使用变量 ? 保存状态码的相关数字不同的值反应成功或失败$?取值范例 0-255
$?的值为0 代表成功$?的值是1到255 代表失败
例
[rootCentOS8 ~]#curl www.google.com /dev/null
[rootCentOS8 ~]#echo $?
7用户可以在脚本中使用以下命令自定义退出状态码
exit [n]注意:
脚本中一旦遇到exit命令脚本会立即终止终止退出状态取决于exit命令后面的数字如果未给脚本指定退出状态码整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
2.7.10 展开命令行
展开命令执行顺序:
把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
命令替换$()和
再次把命令行分成命令词
展开文件通配* ? [abc]等等
准备I/0重导向 、
运行命令防止扩展
反斜线(\)会使随后的字符按原意解释加引号来防止扩展
单引号()-防止所有扩展
双引号 ()也可防止扩展但是以下情况例外: $(美元符号)变量扩展反引号命令替换
\ 反斜线禁止单个字符扩展
! 叹号历史命令替换2.7.11 脚本安全和 set 命令
**set命令**可以用来定制shell环境
$- 变量
h hashal打开洗项后Shell会将命令所在的路径hash下来避免每次都要查询。通过set h将h洗项关闭
i interactive-comments包含这个选项说明当前的 shel 是一个交式的 shel。所谓的交式shell在脚本中i选项是关闭的
m monitor打开监控模式就可以通过Job control来控制进程的停止、继续后台或者前台执行等
B braceexpand大括号{}扩展set B关闭{}的功能
H historyH选项打开可以展开历史列表中的命令可以通过!感叹号来完成例如“!返回上最近的一个历史命令“!n”返回第 n个历史命令set 命今实现脚本安全 推荐打开-eu
-u 在扩展一个没有设置的变量时显示错误信息等同set -o nounset避免出现删除整个目录
-e 如果一个命令返回一个非0退出状态值(失败)就退出等同set -o errexit
-o option 显示打开或者关闭选项显示选项 set-o打开选项 set -o选项关闭选项 set o选项
-x 当执行命令时打印命令及其参数类似bash -x2.8 格式化输出 printf
格式
printf 指定的格式 文本1 文本2...常用格式替换符
%s 字符串
%f 浮点格式
%b 相对应的参数中包含转义字符时可以使用此替换符进行替换对应的转义字符会被转义
%c ASCII字符即显示对应参数的第一个字符
%d,%i 十进制整数
%o 八进制值
%u 不带正负号的十进制值
%x 十六进制值 (a-f)
%X 十六进制值 (A-F)
%% 说明:%s中的数字代表此替换符中的输出字符宽度不足补空格默认是右对齐%-10s表示10个字符宽- 表示左对齐
常用转义字符
\a 警告字符通常为ASCII的BEL字符
\b 后退
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ 表示\本身例
[rootCentOS8 ~]#printf (%.3f)\n 1 2 3
(1.000)
(2.000)
(3.000)[rootCentOS8 ~]#printf %s\n%s 1 2 3 4;echo
1
23
42.9 算术运算
shell 支持算术运算但只支持整数不支持小数 bash中的算术运算 -
*
/
% 取模即取余数%5的结果在0-4
** 乘方乘法符号有些场景中需要转义 实现算术运算:
let var算术表达式
var$[算术表达式]
var$((算术表达式))
var$(expr argl arg2 arg3 ...) 注意expr里*可能被当作通配符乘法要用\*
declare -i var 数值
echo算术表达式|bc例
[rootCentOS8 ~]#echo -e \E[1;$[RANDOM%731]mhello\e[0m 打印随机颜色的hello颜色编号31-37
hello[rootCentOS8 ~]#expr 99 \* 3
297[rootCentOS8 ~]#echo scale3;3/7|bc
.428内建的随机数生成器变量 $RANDOM 取值范围 0-32767
增强型赋值 i10 相当于 ii10
- i-j 相当于 ii-j
*
/
%i,i 相当于 ii1
-- i--,--i 相当于 ii-12.10 逻辑运算
true false1 0与: 与0为0与1保留1与111与000与100与00
或:| 同0为01或111或010或110或00
非:!!1 0 ! true!0 1 ! false
异或:^ 异或的两个值相同为假0不同为真非0。1^101^010^110^00两个数字异或将结果与任意一个数字异或结果是另一数字12^848^41212^48例
[rootCentOS8 ~]#ii10;j20;echo i$[i^(i^j)] j$[j^(i^j)] 使用异或交换i和j的值
i20 j10
[rootCentOS8 ~]#i10;j20;i$[i^j];j$[i^j];i$[i^j];echo i$i,j$j
i20,j10短路运算
短路与 CMD1 短路与 CMD2
第一个CMD1结果为0(假)总的结果必定为0因此不需要执行CMD2第一个CMD1结果为1(真)第二个CMD2必须要参与运算才能得到最终的结果
短路或 CMD1 短路或CMD2
第一个CMD1结果为1(真)总的结果必定为1因此不需要执行CMD2第一个CMD1结果为0(假)第二个CMD2必须要参与运算才能得到最终的结果
2.11 条件测试命令
条件测试判断某需求是否满足需要由测试机制来实现专用的测试表达式需要由测试命令辅助完成测试过程实现评估布尔声明以便用在条件性环境下进行执行
若真则状态码变量 $? 返回0若假则状态码变量 $? 返回1
条件测试命令
test EXPRESSION 等价于 [ EXPRESSION ] 推荐使用[ ]
[[ EXPRESSION ]]注意EXPRESSION前后必须有空白字符
2.11.1 变量测试
-v VAR 变量VAR是否设置即是否存在
-R VAR 变量VAR是否设置并引用示例判断NAME变量是否定义
[rootCentOS8 ~]#[ -v name ] 或 test -v NAME
[rootCentOS8 ~]#echo $?
12.11.2 数值测试
-eq 是否等于
-ne 是否不等于
-gt 是否大于
-ge 是否大于等于
-lt 是否小于
-le 是否小于等于例
[rootCentOS8 ~]#x33
[rootCentOS8 ~]#y44
[rootCentOS8 ~]#[ $x -gt $y ] 必须假$
[rootCentOS8 ~]#echo $?
1
[rootCentOS8 ~]#[ $x -lt $y ]
[rootCentOS8 ~]#echo $?
02.11.3 字符串测试
-z STRING 字符串是否为空未定义或空为真不空为假
-n STRING 字符串是否不空不空为真空为假 是否等于
! 是否不等于 ascii码是否大于ascii码 是否小于左侧字符串是否和右侧的PATTERN相同
注意:此表达式用于[[ ]]中PATTERN为通配符
~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配注意: 此表达式用于[[ ]]中;扩展的正则表达式
即只在正则表达式才用双中括号[[]]其他都用[]且在[[ ]] 右侧的*单列则表示通配符只作为字符需要加或\转义字符串最好两边加否则可能出现问题
[rootCentOS8 ~]#namehello babe
[rootCentOS8 ~]#[ $name ]
-bash: [: hello: unary operator expected
[rootCentOS8 ~]#[ $name ]
[rootCentOS8 ~]#echo $?
0例
[rootCentOS8 ~]#title1ceo
[rootCentOS8 ~]#title1cto
[rootCentOS8 ~]#[ $title1 $title2 ] 字符串之间必须加空格 不加空格则成赋值
[rootCentOS8 ~]#echo $?
12通配符
[rootCentOS8 ~]#FILEtest.log
[rootCentOS8 ~]#[[ $FILE *.log ]]
[rootCentOS8 ~]#echo $?
03正则表达式
[rootCentOS8 ~]#FILEtest.log
[rootCentOS8 ~]#[[ $FILE ~ \.log$ ]]
[rootCentOS8 ~]#echo $?
0[rootCentOS8 ~]#IP1.2.3.444 判断ip地址是否合法在255.255.255.255之间
[rootCentOS8 ~]#[[ $IP ~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
[rootCentOS8 ~]#echo $?
1
[rootCentOS8 ~]#IP1.2.3.4
[rootCentOS8 ~]#echo $?
02.11.4 文件测试
存在性测试
-a FILE 同 -e
-e FILE 文件存在性测试存在为真否则为假
-b FILE 是否存在且为块设备文件
-C FILE 是否存在且为字符设备文件
-d FILE 是否存在且为目录文件
-f FILE 是否存在且为普通文件判断软链接则判断软链接指定的文件
-h FILE 或 -L FILE: 存在且为符号链接文件
-p FILE 是否存在且为命名管道文件
-S FILE 是否存在且为套接字文件例
[rootCentOS8 ~]#[[ -c /dev/zero ]] 判断是否为字符文件
[rootCentOS8 ~]#echo $?
0文件权限测试.
-r FILE 是否存在且可读
-W FILE 是否存在且可写
-X FILE 是否存在且可执行
-u FILE 是否存在且拥有suid权限
-g FILE 是否存在且拥有sgid权限
-k FILE 是否存在且拥有sticky权限例
[rootCentOS8 ~]# [[ -x CHOOK_RABBIT.sh ]] 判断是否有执行权限
[rootCentOS8 ~]#echo $?
0
[rootCentOS8 ~]#chmod 0 CHOOK_RABBIT.sh 去除所有权限
[rootCentOS8 ~]# [[ -x CHOOK_RABBIT.sh ]] 判断是否有执行权限
[rootCentOS8 ~]#echo $?
1[rootCentOS8 ~]# [[ -r CHOOK_RABBIT.sh ]] 判断是否有可读权限因为我们是root所有仍然可以读
[rootCentOS8 ~]#echo $?
0
[rootCentOS8 ~]# [[ -w CHOOK_RABBIT.sh ]] 判断是否有写入权限因为我们是root所有仍然可以写
[rootCentOS8 ~]#echo $?
0文件属性测试
-S FILE 是否存在且非空
-t fd fd 文件描述符是否在某终端已经打开
-N FILE 文件自从上一次被读取之后是否被修改过
-O FILE 当前有效用户是否为文件属主
-G FILE 当前有效用户是否为文件属组
FILE1 -ef FILE2 FILE1是否是FILE2的硬链接
FILE1 -nt FILE2 FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2 FILE1是否旧于FILE22.12 关于()和{}
(CMD1;CMD2;...) 都可以批量执行多个命令
{ CMD1;CMD2;...; }最后加;{ }内前后加空格()会开启子shell继承父进程的变量。list中变量赋值及内部命令执行后不影响后续的环境。帮助参看:man bash 搜索(list) {;}不会启子shell在当前shell中运行会影响当前shell环境帮助参看:man bash 搜索{list;}
例
[rootCentOS8 ~]#namebabe;(echo $name;namehello;echo $name);echo $name 使用()
babe
hello
babe
[rootCentOS8 ~]#namebabe;{ echo $name;namehello;echo $name; };echo $name 使用{}
babe
hello
hello2.13 组合测试条件
2.13.1 方法 1 []
EXPRESSION1 -a EXPRESSION2 并且EXPRESSION1和EXPRESSION2都是真结果才为真
EXPRESSION1 -o EXPRESSION2 或者EXPRESSION1和EXPRESSION2只要有一个真结果就为真
[ ! EXPRESSION ] 或 ![ exp ] 取反说明: -a和-0 需要使用测试命令进行[[]]不支持
2.13.2 方法 2 [[]]
COMMAND1 COMMAND2 #并且短路与代表条件性的AND THEN如果COMMAND1 成功将执行COMMAND2否则将不执行COMMAND2
COMMAND1 || COMMAND2 #或者短路或代表条件性的OR ELSE如果COMMAND1 成功将不执行COMMAND2否则将执行COMMAND2
!COMMAND 非取反例
[rootCentOS8 ~]#NAMEjoycee;id $NAME /dev/null echo $NAME is exist || echo $NAME is not exist
joycee is not exist[rootCentOS8 ~]#NANAMEjoycee;id $NAME /dev/null echo $NAME is exist || (useradd $NAME;echo $NAME is created)
joycee is created注意 如果和 || 混用则 要放前|| 放后
2.13 使用read命今来接受输入
使用read来把输入值分配给一个或多个shell变量read从标准输入中读取值给每个单词分配一个变量所有剩余单词都被分配给最后一个变量 格式
read [options] [name ...]常见选项:
-p 指定要显示的提示
-s 静默输入一般用于密码
-n N 指定输入的字符长度N
-d 字符输入结束符
-t N TIMEOUT为N秒[rootCentOS8 ~]#read
joyce
[rootCentOS8 ~]#echo $REPLY
joyce[rootCentOS8 ~]#read NAME TITLE
joyce babe
[rootCentOS8 ~]#echo $NAME $TITLE
joyce babe[rootCentOS8 ~]#read -p are u ok? ANSWER
are u ok?not bad
[rootCentOS8 ~]#echo $ANSWER
not bad[rootCentOS8 ~]#echo 1 2 test.txt 重定向
[rootCentOS8 ~]#read a b test.txt;echo $a; echo $b
1
2注意
[rootCentOS8 ~]#echo 1 2 | read a b | echo $a $b
1 2
[rootCentOS8 ~]#echo 1 2 | (read a b; echo $a $b)
1 2
[rootCentOS8 ~]#echo 1 2 | read a b; echo $a $b 管道里如果不加括号或|则中间和后面是两个独立的shell因此二者的ab不等
1 23 bash的配置文件
bash shell的配置文件很多可以分成下面类别
3.1 按生效范围划分两类
全局配置
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc个人配置:
~/.bash_profile
~/.bashrc3.2 shell登录两种方式分类
3.2.1 交互式登录
直接通过终端输入账号密码登录使用su - UserName切换用户
配置文件执行顺序:
/etc/profile -- /etc/profile.d/*,sh -- ~/.bash_profile -- ~/.bashrc -- /etc/bashrc3.2.2 非交互式登录
su UserName图形界面下打开的终端 执行脚本 任何其它的bash实例
执行顺序:
/etc/profile.d/*.sh -- /etc/bashrc --~/.bashrc3.3 按功能划分分类
profile类和bashrc类
3.3.1 profile类
profile类为交互式登录的shell提供配置
全局: /etc/profile,/etc/profile.d/*.sh
个人:~/.bash_profile作用
用于定义环境变量运行命令或脚本
3.3.2 Bashrc类
bashrc类:为非交互式和交互式登录的shell提供配置
全局: /etc/bashrc
个人:~/.bashrc作用
定义命令别名和函数定义本地变量
3.4 编辑配置文件生效
修改profile和bashrc文件后有生效两种方法
重新启动shell进程source 或 . 配置文件
3.5 Bash 退出任务
保存在~/.bash_logout文件中 (用户),在退出登录shell时运行
功能
创建自动备份 清除临时文件
4 流程控制
4.1 条件选择
条件判断
if
case||4.1.1 选择执行 if 语句
格式:
if CMDs; then CMDs;[ elif CMDs; then CMDs; ]... [ else CMDs; ] fi单分支:
if 判断条件;then条件为真的分支代码
fi双分支:
if 判断条件; then条件为真的分支代码
e1se条件为假的分支代码
fi多分支:
if 判断条件1; then条件1为真的分支代码
elif 判断条件2; then条件2为真的分支代码
...
e1se以上条件都为假的分支代码
fi说明:
多个条件时逐个条件进行判断第一次遇为“真”条件时执行其分支而后结束整个if语句if 语句可嵌套
4.1.2 条件判断 case 语句
格式:
case WORD in [PATTERN [| PATTERN]...) CMDs ;;]...esac此处PATTERN指通配符的模式
case 变量引用 in
PAT1)分支1;;
PAT2)分支2;;
...
*)默认分支;;
esaccase支持glob风格的通配符:
* 任意长度任意字符
? 任意单个字符
[] 指定范围内的任意单个字符
| 或如 a或bG R E E N 清理日志 GREEN清理日志 GREEN清理日志END ;;
4.2 循环
4.2.1 循环执行介绍 将某代码段重复运行多次通常有进入循环的条件和退出循环的条件
重复运行次数
循环次数事先已知循环次数事先未知
常见的循环的命令forwhileuntil 4.2.2 for循环
格式1:
for NAME [in WORDS ...] ; do COMMANDS; done(WORD之间使用空白符(空格、Tab键、回车)分割)或
for 变量名 in 列表;do循环体
done或
for 变量名 in 列表
do循环体
done执行机制依次将列表中的元素赋值给“变量名” 每次赋值后即执行一次循环体直到列表中的元素耗尽循环结束
for循环列表生成方式
直接给出列表整数列表
{start..end}
$(seq [start [step]] end)返回列表的命令:
$(COMMAND)使用glob如*.sh变量引用如$$#$*等位置参数 ( ∗ 将变量视为单个 *将变量视为单个 ∗将变量视为单个将变量视为整体)
死循环
for((;;)) ; do CMDs;done例
[rootCentOS8 ~]#for i in {001..8..2};do echo $i; done
001
003
005
007
[rootCentOS8 ~]#for i in seq 5;do echo $i; done
1
2
3
4
5
[rootCentOS8 ~]#for i in $(seq 5);do echo $i; done
1
2
3
4
5例计算123…100的和
[rootCentOS8 ~]#seq -s 100|bc
5050或
[rootCentOS8 ~]#sum0;for i in {1..100};do let sumi;done;echo $sum
5050例
[rootCentOS8 scripts]#cat sum.sh
#!/bin/bashsum0
for i in $ ;dolet sumi
doneecho $sum[rootCentOS8 scripts]#chmod x sum.sh
[rootCentOS8 scripts]#./sum.sh 1 3 4 5 6
19例九九乘法表的实现
[rootCentOS8 scripts]#cat ./9x9.sh
#!/bin/bashfor j in {1..9};dofor i in seq $j;doecho -e ${i}x$j$((i*j))\t\cdoneecho
done
[rootCentOS8 scripts]#./9x9.sh
1x11
1x22 2x24
1x33 2x36 3x39
1x44 2x48 3x412 4x416
1x55 2x510 3x515 4x520 5x525
1x66 2x612 3x618 4x624 5x630 6x636
1x77 2x714 3x721 4x728 5x735 6x742 7x749
1x88 2x816 3x824 4x832 5x840 6x848 7x856 8x864
1x99 2x918 3x927 4x936 5x945 6x954 7x963 8x972 9x981面试题要求将目录YYYY-MM-DD/中所有文件移动到YYYY-MM/DD/下
#1 yyyy-mm-dd10.sh 准备数据
#创建YYYY-MM-DD当前日期一年前365天到目前共365个目录里面有10个文件$RANDOM.Tog[rootcentos8 ~]#cat for_dir20.sh
#!/bin/bash
for i in {1..365};doDIRdate -d -$i day %Fmkdir /data/test/$DIRcd /data/test/$DIRfor n in {1..10};dotouch $RANDOM.logdone
done#2 移动到YYYY-MM/DD/下
[rootcentos8 ~]#cat for_mv20.sh
#!/bin/bash
#
DIR/data/test
cd $DIR
for DIR in *;doYYYY_MMecho $DIR |cut -d- -f1,2 #将年月和日期拆分成2部分这里是年月DDecho $DIR | cut -d- -f3 #这里是日期[ -d $YYYY_MM/$DD ] || mkdir -p $YYYY_MM/$DD /dev/nullmv $DIR/* $YYYY_MM/$DD
done面试题扫描一个网段10.0.0.0/24判断此网段中主机在线状态将在线的主机的IP打印出来
NET10.0.0
for ID in {1..254};do{ping -c1 -W1 $NET.$ID /dev/null echo $NET.$ID is up || echo $NET.$ID is down} #实现并行
done
wait #默认并行不会自动退出加上wait使其自动执行下一个命令格式2
双小括号方法即((…))格式也可以用于算术运算双小括号方法也可以使bash Shell实现C语言风格的变量操作
|10;((l)) for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do循环体
done说明:
控制变量初始化:仅在运行到循环代码段时执行一次控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算而后再做条件判断
例实现1累加到100
for ((sum0;i100;i));dolet sumi
done
echo $sum例九九乘法表的实现_2
for ((i1;i10;i));dofor((j1;ji;j));doecho -e ${j}x$i$((j*i))\t\cdoneecho
done例实现国际象棋的棋盘较垃圾
for ((i1;i8;i));doif((i%2));thenfor((x0;x4;x));dofor ((j0;j8;j));doif ((j%2));thenecho -e \E[47m \E[0m\c ;elseecho -e \E[40m \E[0m\c ;fidoneechodoneelsefor((x0;x4;x));dofor ((j0;j8;j));doif ((j%2));thenecho -e \E[40m \E[0m\c ;elseecho -e \E[47m \E[0m\c ;fidoneechodonefi
done例实现三角形
for((i1;i10;i));do#for((z0;z10-i;z));dofor((z10;z-i0;z--));doecho -e \c;donefor((j1;j2*i-1;j));doecho -e *\cdoneecho
done例加入参数实现三角形
read -p 请输入三角形的行数: line
for((i1;i$line;i));do#for((z0;z10-i;z));dofor((z$line;z-i0;z--));doecho -e \c;donefor((j1;j2*i-1;j));doecho -e *\cdoneecho
done4.2.3 while循环
格式:
while COMMANDs; do COMMANDS; donewhile CONDITION; do循环体
done说明:
CONDITION:循环控制条件进入循环之前先做一次判断每一次循环之后会再次做判断;条件为“true则执行一次循环直到条件测试状态为“false终止循环因此:CONDTION一般应该有循环控制变量而此变量的值会在循环体不断地被修正
进入条件: CONDITION为true退出条件: CONDITION为false
死循环
#方法1
while true; do循环体
done#方法2
while :; do循环体
done范例使用while实现磁盘报警
WARNING10 #阈值
while : ;doUSEdf | sed -rn /^\/dev\/sd/s#.* ([0-9])%.*#\1#p |sort -nr | head -n1if [ $USE -gt $WARNING ] ; thenecho DISK will be full from hostname -I | mail -s Disk Warning 1299575088qq.comfisleep 10 #10秒循环一次
done例死循环
[rootCentOS8 scripts]#while :;do echo ok ;sleep 1 ;done
ok
ok
ok
ok
ok4.2.4 until循环
格式:
until COMMANDS; do COMMANDS; doneuntil CONDITION; do循环体
done说明:
进入条件CONDITION为false退出条件CONDITION为true
死循环
until false; do循环体
done4.2.4 循环控制语句 continue
continue[N]提前结束第N层的本轮循环而直接进入下一轮判断最内层为第1层
格式
while CONDITION1; doCMD1...if CONDITION2; thencontinueCMDn...
done例
#1
for((i0;i10;i));dofor((j0;j10;j));do[ $j -eq 5 ] continue 1 #1可以不写代表终止该层循环的本次循环echo $jdoneecho -----------------
done
[rootCentOS8 scripts]#bash continue_for_1.sh
0
1
2
3
4
6
7
8
9
-----------------
0
1
2
3
4
6
7
8
9
-----------------
0
1
2
3
4
6
7
8
9
-----------------
0
1
2
3
4
6
7
8
9
-----------------
0
1
2
3
4
6
7
8
9
-----------------
0
1
2
3
4
6
7
8
9
-----------------
0
1
2
3
4
6
7
8
9
-----------------
0
1
2
3
4
6
7
8
9
-----------------
0
1
2
3
4
6
7
8
9
-----------------
0
1
2
3
4
6
7
8
9
-----------------
#2
for((i0;i10;i));dofor((j0;j10;j));do[ $j -eq 5 ] continue 2 #2代表终止外层循环的本次循环使外层循环进入下次循环echo $jdoneecho -----------------
done
[rootCentOS8 scripts]#bash continue_for_1.sh
0
1
2
3
4
0
1
2
3
4
0
1
2
3
4
0
1
2
3
4
0
1
2
3
4
0
1
2
3
4
0
1
2
3
4
0
1
2
3
4
0
1
2
3
4
0
1
2
3
44.2.5 循环控制语句 break
break [N]提前结束第N层整个循环最内层为第1层 格式
while CONDITION1; doCMD1...if CONDITION2; thenbreakfiCMDn例
#1
for((i0;i10;i));dofor((j0;j10;j));do[ $j -eq 5 ] break 1 #1可以不写表示结束内层循环使外层循环进入下一轮echo $jdoneecho -----------------
done
[rootCentOS8 scripts]#bash continue_for_1.sh
0
1
2
3
4
-----------------
0
1
2
3
4
-----------------
0
1
2
3
4
-----------------
0
1
2
3
4
-----------------
0
1
2
3
4
-----------------
0
1
2
3
4
-----------------
0
1
2
3
4
-----------------
0
1
2
3
4
-----------------
0
1
2
3
4
-----------------
0
1
2
3
4
-----------------#2
for((i0;i10;i));dofor((j0;j10;j));do[ $j -eq 5 ] break 2 #2表示结束外层循环即结束所有循环echo $jdoneecho -----------------
done
[rootCentOS8 scripts]#bash continue_for_1.sh
0
1
2
3
4例菜品选择
sum0
COLOR1echo -e \033[1;31m
COLOR2echo -e \033[1;32m
END\033[0mwhile :;doecho -e \033[33;1m\ccat -EOF
1)米
2)面
3)粉
4)汤
5)谷
6)肉EOFecho -e \033[0mread -p 请选择菜品 MENU
case $MENU in
1|4)$COLOR1菜价$10$ENDlet sum10;;
3|5)$COLOR1菜价$20$ENDlet sum20;;
2)$COLOR1菜价$888$ENDlet sum888;;
6)$COLOR2你点的菜品总价是$sum$ENDbreak;;
*)echo 输入错误;;esac$COLOR2你点的菜品总价是$sum$END
done4.2.6 循环控制 shift 命令
shift[n]用于将参量列表list 左移指定次数缺省为左移一次。
参量列表list 一旦被移动最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时常用到 shift
例shift批量创建用户
PASS110420
while [ $1 ];douseradd $1 echo $1 is created || echo $1 is existsecho $PASS | passwd --stdin $1shift #shift 1 一次只跳过1个2则跳过2个
done
[rootCentOS8 scripts]#bash shift_user.sh Tom Alice
Tom is created
Changing password for user Tom.
passwd: all authentication tokens updated successfully.
Alice is created
Changing password for user Alice.
passwd: all authentication tokens updated successfully.
例判断某个ip访问的次数
[rootCentOS8 data]#sed -En /^ESTAB/s#.*[: ]([^:]):[0-9] $#\1#p ss.log | sort |uniq -c1 10.0.0.1200 10.0.0.84.2.7 while read 特殊用法
while循环的特殊用法遍历文件或文本的每一行即逐行处理
支持stdin
格式
while read line; do循环体
done /PATH/FROM/SOMEFILE说明依次读取/PATH/FROM/SOMEFILE文件中的每一行且将行赋值给变量line
例
[rootcentos8 ~]#echo joyce | read X ; echo $X # 管道|开启子进程[rootcentos8 ~]#echo joyce | while read X ; do echo $X;done
joyce[rootcentos8 ~]#echo joyce | { read X ; echo $X; }
joyce[rootcentos8 ~]#echo joyce | ( read X ; echo $X )
joyce[rootcentos8 ~]#echo joyce wang zhang | ( read X Y Z; echo $X $Y $Z )
joyce wang zhang[rootcentos8 ~]#echo joyce wang zhang | while read X Y Z; do echo $X $Y $Z;done
joyce wang zhang例使用while read实现磁盘报警
WARNING10
MAIL1299575088qq.com
df |sed -nr /^\/dev\/sd/s#^([^ ]) .* ([0-9])%.*#\1 \2#p |while read DEVICE USE;doif [ $USE -gt $WARNING ] ;thenecho $DEVICE will be full,use:$USE | mail -s DISK WARNING $MAILfi
done例查看/sbin/nologin的shell类型的用户名和UID
while read line ;doif [[ $line ~ /sbin/nologin$ ]] ; thenecho $line | cut -d: -f1,3fi
done /etc/passwd例存放大量单词文件
[rootCentOS8 scripts]#wc -l /usr/share/dict/linux.words
479828 /usr/share/dict/linux.words4.2.8 select 循环与菜单
格式:
select NAME [in WORDS ... ;] do COMMANDS; doneselect variable in list ;do循环体命令
done说明
select 循环主要用于创建菜单按数字顺序排列的菜单项显示在标准错误上并显示 PS3 提示符等待用户输入用户输入菜单列表中的某个数字执行相应的命令用户输入被保存在内置变量REPLY中select 是个无限循环因此要记住用 break 命令退出循环或用exit 命令终止脚本。也可以按 ctrlc 退出循select经常和 case 联合使用与for 循环类似可以省略 in list此时使用位置参量
5 函数介绍
5.1 管理函数
函数由两部分组成函数名和函数体
帮助参看help function
5.1.1 定义函数
function name { COMMANDS ; } or name () { COMMANDS ; }#语法一:
func_name () {...函数体...
}#语法二:
function func_name {...函数体...
}#语法三:
function func_name () {...函数体...
}例创建disable_firewall_selinux函数以关闭firewalld和selinux
[rootcentos8_3 ~]#systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemonLoaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)Active: active (running) since Sat 2023-08-12 22:57:44 CST; 6min ago
[rootcentos8_3 ~]#getenforce
Enforcing# 函数主体
[rootcentos8_3 ~]#disable_firewall_selinux () {systemctl stop firewalldsystemctl disable firewalldsed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/configsetenforce 0}[rootcentos8_3 ~]#disable_firewall_selinux
Removed /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[rootcentos8_3 ~]#systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemonLoaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)Active: inactive (dead)
[rootcentos8_3 ~]#getenforce
Permissive注意函数操作后确实修改了文件因此重启后仍然保存。但是函数本身一次性使用重启后消失因此想要保存函数需要写入到文件
例分装函数与调用于2个文件可直接调用函数
#funtions文件保存函数主体
[rootcentos8_3 scripts]#cat functions
#函数1disable_firewall_selinux()
disable_firewall_selinux () {systemctl stop firewalldsystemctl disable firewalldsed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/configsetenforce 0
}#函数2yum_repo()
yum_repo() {cd /etc/yum.repos.d/mkdir backupmv *.repo backupcat base.repo EOF[BaseOS]
namealiyun BaseOS
baseurl https://mirrors.aliyun.com/centos/8/BaseOS/x86_64/os/https://repo.huaweicloud.com/centos/8-stream/BaseOS/x86_64/os/
gpgcheck1
enabled1
gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial[AppStream]
namealiyun AppStream
baseurl https://mirrors.aliyun.com/centos/8/AppStream/x86_64/os/https://repo.huaweicloud.com/centos/8-stream/AppStream/x86_64/os/
gpgcheck1
enabled1
gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial[epel]
nameExtra Packages for Enterprise Linux \$releasever - \$basearch
# It is much more secure to use the metalink, but if you wish to use a local mirror
# place its address here.
#baseurlhttps://download.example/pub/epel/\$releasever/Everything/\$basearch
metalinkhttps://mirrors.fedoraproject.org/metalink?repoepel-\$releaseverarch\$basearchinfra\$infracontent\$contentdir
enabled1
gpgcheck1
countme1
gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8[epel-debuginfo]
nameExtra Packages for Enterprise Linux \$releasever - \$basearch - Debug
# It is much more secure to use the metalink, but if you wish to use a local mirror
# place its address here.
#baseurlhttps://download.example/pub/epel/\$releasever/Everything/\$basearch/debug
metalinkhttps://mirrors.fedoraproject.org/metalink?repoepel-debug-\$releaseverarch\$basearchinfra\$infracontent\$contentdir
enabled0
gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8
gpgcheck1[epel-source]
nameExtra Packages for Enterprise Linux \$releasever - \$basearch - Source
# It is much more secure to use the metalink, but if you wish to use a local mirror
# place its address here.
#baseurlhttps://download.example/pub/epel/\$releasever/Everything/SRPMS
metalinkhttps://mirrors.fedoraproject.org/metalink?repoepel-source-\$releaseverarch\$basearchinfra\$infracontent\$contentdir
enabled0
gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8
gpgcheck1
EOF
}#函数3install_package()
install_package() {
packages
vim
tree
autofs
net-tools
apache
httpdfor i in $packages;dorpm -q $i /dev/null || yum -q -y install $i
done
}#disable_firewall_selinux.sh文件调用disable_firewall_selinux函数
[rootcentos8_3 scripts]#cat disable_firewall_selinux.sh
#!/bin/bash
. functions #引用functions文件disable_firewall_selinux#yum_repo.sh文件调用yum_repo函数
[rootcentos8_3 scripts]#cat yum_repo.sh
#!/bin/bash
. functionsyum_repo#install_package.sh文件调用install_package函数
[rootcentos8_3 scripts]#cat install_package.sh
#!/bin/bash
. functionsinstall_package
5.1.2 查看函数
#查看当前已定义的函数名
declare -F#查看当前已定义的函数定义
declare -f5.1.3 删除函数
格式:
unset func_name5.2 函数调用
函数的调用方式
可在交互式环境下定义函数可将函数放在脚本文件中作为它的一部分可放在只包含函数的单独文件中
调用函数只有被调用才会执行通过给定函数名调用函数函数名出现的地方会被自动替换为函数代码
函数的生命周期被调用时创建返回时终止。
不过调用函数时如果函数内外有同名变量调用函数后会修改函数内外的变量类似于全局变量如果要使函数只修改函数内部的变量而不影响函数外的同名变量可以在函数内声明时加上local使其成为本地变量如local NAME1
5.2.1 交互式环境调用函数
交互式环境下定义和使用函数
5.2.2 在脚本中定义及使用函数
函数在使用前必须定义因此应将函数定义放在脚本开始部分直至shell首次发现它后才能使用调用函数仅使用其函数名即可
5.2.3 使用函数文件
例调用系统函数
[rootCentOS8 ~]#. /etc/init.d/functions
[rootCentOS8 ~]#action you an me
you an me [ OK ]
[rootCentOS8 ~]#action you an medsadsad false
you an medsadsad [FAILED]5.3 函数返回值
默认情况下我们使用exit 100会返回100但用在函数里会使整个脚本退出而不执行下面的代码。
因此使用return #返回值可只退出当前函数而不退出脚本不过只在函数中使用
函数的执行结果返回值
使用echo等命令进行输出函数体中调用命令的输出结果
函数的退出状态码 默认取决于函数中执行的最后一条命令的退出状态码 自定义退出状态码其格式为 return 从函数中返回用最后状态命令决定返回值 return 0 无错误返回 return 1-255 有错误返回
5.4 环境函数
类拟于环境变量也可以定义环境函数使子进程也可使用父进程定义的函数
定义环境函数
export -f function_name
declare -xf function_name查看环境函数
export -f
declare -xf5.5 函数参数
函数可以接受参数:
传递参数给函数在函数名后面以空白分隔给定参数列表即可如: testfunc arg1 arg2…在函数体中当中可使用$1 2 . . . 调用这些参数还可以使用 2...调用这些参数还可以使用 2...调用这些参数还可以使用 ∗ * ∗#等特殊变量
5.6 函数变量
变量作用域:
普通变量只在当前shell进程有效为执行脚本会启动专用子shell进程因此本地变量的作用范围是当前shell脚本程序文件包括脚本中的函数环境变量当前shell和子shell有效本地变量函数的生命周期;函数结束时变量被自动销毁
注意:
如果函数中定义了普通变量且名称和局部变量相同则使用本地变量由于普通变量和局部变量会冲突建议在函数中只使用本地变量
在函数中定义本地变量的方法
local NAMEVALUE5.7 函数递归
函数递归函数直接或间接调用自身注意递归层数可能会陷入死循环
基例确定值链条规律
递归示例阶乘
阶乘是基斯顿·卡曼于1808 年发明的运算符号是数学术语一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积并且有0的阶乘为1自然数n的阶乘写作n!
n!1x2x3x…xn
阶乘亦可以递归方式定义: 0!1n!(n-1)!xn
n!n(n-1)(n-2)…1
n(n-1)!n(n-1)(n-2)!
例递归实现阶乘
[rootCentOS8 functions]#cat fact.sh
fact() {if [ $1 -eq 1 ];thenecho 1elseecho $[fact $[$1-1]*$1]fi
}
fact $1[rootCentOS8 functions]#bash fact.sh 5
120
fork炸弹是一种恶意程序它的内部是一个不断在 fork 进程的无限循环实质是一个简单的递归程序。由于程序是递归的如果没有任何限制这会导致这个简单的程序迅速耗尽系统里面的所有资源
参考:https://en.wikipedia.org/wiki/Fork_bomb
函数实现
:(){ :|: };: #无基例
bomb () {} bomb | bomb }; bomb脚本实现
cat Bomb.sh
#!/bin/bash
./$0|./$0OOM内存溢出
6 其它脚本相关工具
6.1 信号捕捉 trap trap ‘触发指令’ 信号 进程收到系统发出的指定信号后将执行自定义指令而不会执行原操作 trap 信号 忽略信号的操作 trap ‘-’ 信号 恢复原信号的操作 trap -p 列出自定义信号操作 trap finish EXIT 当脚本退出时执行finish函数
例
[rootCentOS8 functions]#cat signal_trap1.sh
trap echo Press ctrlc int quit #将int 和quit信号改为echo Press ctrlc
trap -p
for((i1;i10;i))
dosleep 1echo $i
donetrap int #将int信号改为空即忽略
trap -p
for((i11;i21;i ))
dosleep 1echo $i
donetrap - int #恢复int信号接下来遇到int信号将执行ctrlc
trap -p
for(( i21;i31;i))
dosleep 1echo $i
done[rootCentOS8 functions]#bash signal_trap1.sh
trap -- echo Press ctrlc SIGINT
trap -- echo Press ctrlc SIGQUIT
1
^CPress ctrlc
2
^CPress ctrlc
3
^CPress ctrlc
4
^CPress ctrlc
5
^CPress ctrlc
6
^CPress ctrlc
7
^CPress ctrlc
8
^CPress ctrlc
9
^CPress ctrlc
10
trap -- SIGINT
trap -- echo Press ctrlc SIGQUIT
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^[[A11
^[[A12
^[[A^[[A^[[A^C13
^C^C^C^C^C^C^C^C^C^C^C14
15
16
17
18
19
20
trap -- echo Press ctrlc SIGQUIT
21
22
23
24
25
26
^C6.2 创建临时文件 mktemp
mktemp命令用于创建并显示临时文件可避免冲突
格式
mktemp [OPTION]... [TEMPLATE]说明TEMPLATEfilenameXXXX至少要出现三个
常见选项:
-d 创建临时目录
-p DIR或--tmpdirDIR 指明临时文件所存放目录位置例
#默认放在tmp目录下
[rootCentOS8 functions]#mktemp
/tmp/tmp.B9CHlgxwCL
[rootCentOS8 functions]#mktemp
/tmp/tmp.ur2MYKCZhU[rootCentOS8 ~]#mktemp -d tmpdirXXXX #在当前目录下生成临时目录
tmpdirqWDe
[rootCentOS8 ~]#ll tmpdirqWDe -d
drwx------ 2 root root 6 Aug 13 14:51 tmpdirqWDe例实现rm的进阶写法
[rootCentOS8 scripts]#cat rm2.sh
DIRmktemp -d /tmp/trash-$(date %F_%H-%M-%S)XXXXX
mv $* $DIR
echo $* is move to $DIR[rootCentOS8 scripts]#bash rm2.sh 123 321
123 321 is move to /tmp/trash-2023-08-13_14-59-58BDIIO
[rootCentOS8 scripts]#ls /tmp/trash-2023-08-13_14-59-58BDIIO/
123 321
[rootCentOS8 scripts]#alias rm/data/scripts/rm2.sh
[rootCentOS8 scripts]#touch 1
[rootCentOS8 scripts]#chmod x rm2.sh
[rootCentOS8 scripts]#rm 1
1 is move to /tmp/trash-2023-08-13_15-05-24kBeQl6.3 安装复制文件 install
功能相当于cp、chmod、chown、chgrp等相关工具的集合
install命令格式
install [OPTION]... [-T] SOURCE DEST 单文件
install [OPTION]... SOURCE... DIRECTORY
install [OPTION]... -t DIRECTORY SOURCE...
insta11 [OPTION]... -d DIRECTORY...创建空目录选项:
-m MODE默认755 #改权限
-o OWNER #改所有者
-g GROUP #改所属组
-d DIRNAME例
[rootCentOS8 ~]#ll cal.txt
-rw-r--r-- 1 root root 0 Jul 28 19:29 cal.txt
[rootCentOS8 ~]#install -m 666 -o joyce -g bin cal.txt /data/test.txt
[rootCentOS8 ~]#ll /data/test.txt
-rw-rw-rw- 1 joyce bin 0 Aug 13 15:12 /data/test.txt#创建空文件夹
[rootCentOS8 ~]#install -m 700 -o joyce -g daemon -d /data/testdir/
[rootCentOS8 ~]#ll -d /data/testdir/
drwx------ 2 joyce daemon 6 Aug 13 15:13 /data/testdir/6.4 交互式转化批处理工具 expect
expect 是由 Don Libes 基于 TcI ( Tool Command Language )语言开发的主要应用于自动化交互式操作的场景借助 expect处理交互的命令可以将交互过程如ssh登录tp登录等写在一个脚本上使之自动化完成尤其适用于需要对多台服务器执行相同操作的环境中可以大大提高系统管理人员的工作效率
expect 语法:
expect [选项] [ -c cmds ] [ [ -[fIb] ] cmdfile ] [ args ]常见选项:
-c 从命令行执行expect脚本默认expect是交互地执行的
-d 可以输出输出调试信息示例:
expect -c expect \n {send pressed enter\n}
expect -d ssh.expexpect中相关命令
spawn 启动新的进程
expect 从进程接收字符串
send 用于向进程发送字符串
interact 允许用户交互
exp_continue 匹配多个字符串在执行动作后加此命令expect最常用的语法 tcl语言模式-动作 )
单一分支模式语法只生效一次遇到hi输出后即结束
[rootcentos8 test]#expect
expect1.1 expect hi {send You said hi\n}
hahahixixi
You said hi例非交互式发送文件至第二个主机自动输入yes和密码
#!/usr/bin/expect #注意不是bash
spawn scp /etc/fstab 10.0.0.7:/data
expect {yes/no { send yes\n,exp_continue }password { send 110420\n }
}
expect eof例非交互式自动登录至第二个ip主机自动输入yes和密码
[rootcentos8 scripts]#cat expect2
#!/usr/bin/expect
spawn ssh 10.0.0.209
expect {yes/no { send yes\n;exp_continue }password { send 110420\n }
}
interact
[rootCentOS8 scripts]#chmod x expect1.sh
[rootCentOS8 scripts]#./expect1.sh
spawn ssh 10.0.0.209
root10.0.0.209s password:
hello Joyce!
Nna
Activate the web console with: systemctl enable --now cockpit.socketLast login: Sun Aug 13 15:48:51 2023 from 10.0.0.201
[rootcentos8_2 ~]#hostname
centos8_2例带有参数的自动登录其他ip主机的脚本自动输入yes和密码
[rootCentOS8 scripts]#cat ./expect2.sh
#!/usr/bin/expect
set ip 10.0.0.209
set user root
set password 110420
set timeout 10
spawn ssh $user$ip
expect {yes/no { send yes\n;exp_continue }password { send $password\n }
}
interact #代表可以进行交互[rootCentOS8 scripts]#chmod x expect2.sh
[rootCentOS8 scripts]#./expect2.sh
spawn ssh root10.0.0.209
root10.0.0.209s password:
hello Joyce!
Nna
Activate the web console with: systemctl enable --now cockpit.socketLast login: Sun Aug 13 15:49:06 2023 from 10.0.0.201例使用位置参数实现自动登录其他ip的主机
[rootCentOS8 scripts]#cat ./expect3.sh
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
spawn ssh $user$ip
expect {yes/no { send yes\n;exp_continue }password { send $password\n }
}
interact
[rootCentOS8 scripts]#chmod x expect3.sh
[rootcentos8 scripts]#./expect3 10.0.0.209 root 110420
spawn ssh roota10.0.0.7
roota10.0.0.209s password:
Last login: wed Apr 29 15:34:14 2020 from 10.0.0.8例远程登陆主机并创建账号设置密码完了退出
#!usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set timeout 10
spawn ssh $user$ip
expect {yes/no { send yes\n;exp_continue }password{ send$password\n }
}
# ]#即登陆后输入内容前面的标识符
expect ]# { send useradd haha\n }
expect ]# { send echo 110420 |passwd --stdin haha\n }
send exit\n
expect eof例在bash脚本里调用expect以远程登录主机并创建账号设置密码
[rootCentOS8 scripts]#cat ./expect5.sh
#!/bin/bash
ip$1
user$2
password$3
expect EOF
set timeout 10
spawn ssh $user$ip
expect {yes/no { send yes\n;exp_continue }password{ send$password\n }
}
# ]#即登陆后输入内容前面的标识符
expect ]# { send useradd haha\n }
expect ]# { send echo 110420 |passwd --stdin haha\n }
send exit\n
expect eof
EOF[rootCentOS8 scripts]#bash expect5.sh 10.0.0.209 root 110420例批量登录不同主机并创建用户设置密码
#!/bin/bash
NET10.0.0
userroot
password110420
for ID in 209 210;do #循环遍历不同IP的主机
ip$NET.$ID
expect EOF
set timeout 20
spawn ssh $user$ip
expect {yes/no { send yes\n;exp_continue }password { send $password\n }
}
expect # { send useradd test\n }
expect # { send exit\n }
expect eof
EOF
done例批量登录不同主机并修改selinux为disabled
#!/bin/bash
NET10.0.0
userroot
password110420
for ID in 209 210;do #循环遍历不同IP的主机
ip$NET.$ID
expect EOF
set timeout 20
spawn ssh $user$ip
expect {yes/no { send yes\n;exp_continue }password { send $password\n }
}
expect # { send sed -i s/^SELINUXenforcing/SELINUXdisabled/ /etc/selinux/confiig\n }
expect # { send setenforce 0\n }
expect # { send exit\n }
expect eof
EOF
done7数组
7.1 数组介绍
变量存储单个元素的内存空间
数组存储多个元素的连续的内存空间相当于多个变量的集合
数组名和索引
索引的编号从0开始属于数值索引索引可支持使用自定义的格式而不仅是数值格式即为关联索引bash4.0版本之后开始支持bash的数组支持稀疏格式(索引不连续)
7.2 声明数组
#普通数组可以不事先声明直接使用
declare -a ARRAY_NAME#关联数组必须先声明再使用
declare -A ARRAY_NAME注意两者不可相互转换
7.3 数组赋值
数组元素的赋值 一次只赋值一个元素 ARRAY_NAME[INDEX]VALUE例 [rootCentOS8 ~]#title[0]ceo
[rootCentOS8 ~]#echo ${title}
ceo一次赋值全部元素 ARRAY_NAME(VAL1 VAL2 VAL3...例 title(ceocoocto)
num({0..10})
alpha({a..g})
file( *.sh )只赋值特定元素 ARRAY_NAME([0]VAL1 [3]VAL2 ...)交互式数组值对赋值 read -a ARRAY[rootCentOS8 ~]#read -a number
1 3 5 7 9
[rootCentOS8 ~]#echo ${number[*]}
1 3 5 7 9
[rootCentOS8 ~]#echo ${number[2]}
5
[rootCentOS8 ~]#echo ${number}
17.4 显示所有数组
显示所有数组
declare -a7.5 引用数组
引用数组元素
${ARRAY_NAME[INDEX]}
#如果省略[INDEX]表示引用下标为0的元素引用数组所有元素
${ARRAY_NAME[*]}
${ARRAY_NAME[]}例
[rootCentOS8 ~]#NUM({1..5})
[rootCentOS8 ~]#echo ${NUM[3]}
4
[rootCentOS8 ~]#echo ${NUM[2]}
3
[rootCentOS8 ~]#echo ${NUM[*]}
1 2 3 4 5
[rootCentOS8 ~]#echo ${NUM[]}
1 2 3 4 5例
[rootCentOS8 ~]#read -a number
1 3 5 7 9
[rootCentOS8 ~]#echo ${number[*]}
1 3 5 7 9
[rootCentOS8 ~]#echo ${number[2]}
5
[rootCentOS8 ~]#echo ${number}
17.6 删除数组
删除数组中的某元素会导致稀疏格式
unset ARRAY[INDEX]例
[rootcentos8 ~]#echo $title[*]}
ceo coo cto
[rootcentos8 ~]#unset title[1]
[rootcentos8 ~]#echo $ftitle[*]]
ceo cto删除整个数组
unset ARRAY例:
[rootcentos8 ~]#unset title
[rootcentos8 ~]#echo ${title[*]}
7.7 数组数据处理
数组切片
${ARRAY[]:offset:number}
offset #要跳过的元素个数
number #要取出的元素个数{ARRAY[]:offset} #取偏移量之后的所有元素例
[rootcentos8 ~]#num({0..10})
[rootcentos8 ~]#echo ${num[*]:2:3}
2 3 4
[rootcentos8 ~]#echo ${num[*]:6}
6 7 8 9 10向数组中追加元素
ARRAY[${#ARRAY[*]}]value
ARRAY[${#ARRAY[]}]value例
[rootCentOS8 ~]#num({0..10})
[rootCentOS8 ~]#echo ${num[2]}
2
[rootCentOS8 ~]#echo ${num[*]}
0 1 2 3 4 5 6 7 8 9 10
[rootCentOS8 ~]#num[11]11
[rootCentOS8 ~]#echo ${num[*]}
0 1 2 3 4 5 6 7 8 9 10 11
[rootCentOS8 ~]#echo ${#num[*]}
12
[rootCentOS8 ~]#num[${#num[*]}]12
[rootCentOS8 ~]#echo ${#num[*]}
13
[rootCentOS8 ~]#echo ${num[*]}
0 1 2 3 4 5 6 7 8 9 10 11 127.8 关联数组
declare -A ARRAY_NAME
ARRAY_NAME([idx_namel]val1 [idx_name2]val2...注意:关联数组必须先声明再调用
例
[rootCentOS8 ~]#declare -A name
[rootCentOS8 ~]#name[first]Tom
[rootCentOS8 ~]#name[second]Jack
[rootCentOS8 ~]#name[third]Case
[rootCentOS8 ~]#echo ${name[first]}
Tom
[rootCentOS8 ~]#echo ${name[*]}
Case Jack Tom
[rootCentOS8 ~]#echo ${name[third]}
Case7.9 范例
例生成包含10个随机数的数组并显示其中的最大值MAX和最小值MIN
[rootCentOS8 test]#cat random1.sh
#!/bin/bash
declare -i min max
declare -a nums
for ((i0;i10;i));donums[$i]$RANDOM[ $i -eq 0 ] min${nums[0]} max${nums[0]} continue[ ${nums[$i]} -gt $max ] max${nums[$i]}[ ${nums[$i]} -lt $min ] min${nums[$i]}
done
echo All numbers are ${nums[*]}
echo Max is $max
echo min is $min[rootCentOS8 test]#bash random1.sh
All numbers are 23203 6083 14719 18022 31925 25880 9039 10908 30266 23092
Max is 31925
min is 60838 字符串处理
8.1 字符串切片
基于偏移量取字符串
#返回字符串变量var的长度
${#var}#返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始到最后的部分offset的取值在0到${#var}-1 之间(bash4.2后允许为负值)
${var:offset]#返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始长度为number的部分
${var:offset:number}#取字符串的最右侧几个字符取字符串的最右侧几个字符注意: 冒号后必须有一空白字符
${var: -length}#从最左侧跳过offset字符一直向右取到距离最右侧lengh个字符之前的内容即:掐头去尾
${var:offset:-length}#先从最右侧向左取到length个字符开始再向右取到距离最右侧offset个字符之间的内容注意: -length前空格
${var: -length:-offset}例
[rootCentOS8 test]#str123abc哇哦
[rootCentOS8 test]#echo ${#str}
8
[rootCentOS8 test]#echo ${str:5}
c哇哦
[rootCentOS8 test]#echo ${str:5:2}
c哇
[rootCentOS8 test]#echo ${str: -2}
哇哦
[rootCentOS8 test]#echo ${str:3:-2}
abc
[rootCentOS8 test]#echo ${str: -3:-1} #取倒数3个和倒数1个之间的2个
c哇基于模式取子串
从左往右
#其中word可以是指定的任意字符,自左而右查找var变量所存储的字符串中第一次出现的word删除字符串开头至第一次出现word字符串 (含) 之间的所有字符
${var#*word}:#同上贪婪模式不同的是删除的是字符串开头至最后一次由word指定的字符之间的所有内容
${var##*word}:例
[rootcentos8 ~]#filevar/log/messages
[rootcentos8 ~]#echo ${file#*/}
log/messages
[rootcentos8 ~]#echo ${file##*/}
messages从右往左
#其中word可以是指定的任意字符,功能自右而左查找var变量所存储的字符串中第一次出现的worc删除字符串最后一个字符向左至第一次出现word字符串 (含) 之间的所有字符
${var%word*}#同上只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符
${var%%word*}例
[rootcentos8 ~]#file/var/log/messages
[rootcentos8 ~]#echo ${file%/*}
var/log
[rootcentos8 ~]#echo ${file%%/*}
var8.2 查找替换、
#查找var所表示的字符串中第一次被pattern所匹配到的字符串以substr替换之
${var/pattern/substr}#查找var所表示的字符串中所有能被pattern所匹配到的字符串以substr替换之
${var//pattern/substr}#查找var所表示的字符串中行首被pattern所匹配到的字符串以substr替换之
${var/#pattern/substr}#查找var所表示的字符串中行尾被pattern所匹配到的字符串以substr替换之
${var/%pattern/substr}8.3 查找并删除
#删除var表示的字符串中第一次被pattern匹配到的字符串
${var/pattern}#删除var表示的字符串中所有被pattern匹配到的字符串
${var//pattern}#删除var表示的字符串中所有以pattern为行首匹配到的字符串
${var/#pattern}#删除var所表示的字符串中所有以pattern为行尾所匹配到的字符串
${var/%pattern}8.4 字符大小写转换
#把var中的所有小写字母转换为大写
${var^^}#把var中的所有大写字母转换为小写
${var,,}例
[rootCentOS8 test]#echo $str
123abc哇哦
[rootCentOS8 test]#echo ${str^^}
123ABC哇哦9 高级变量
9.1 高级变量赋值
变量配置方法str 没有配置str 为空字符串str 已配置非为空字符串var${str-expr}varexprvarvar$strvar${str:-expr}varexprvarexprvar$strvar${strexpr}varvarexprvarexprvar${str:expr}varvarvarexprvar${strexpr}strexprvarexprstr 不变varstr 不变var$strvar${str:expr}strexprvarexprstrexprvarexprstr 不变var$strvar${str?expr}expr输出至stderrvarvarsstrvar${str:?expr}expr输出至stderrexpr输出至stderrvarsstr
例
[rootcentos8 ~]#titleceo
[rootcentos8 ~]#name${title-oops}
[rootcentos8 ~]#echo $name
ceo[rootcentos8 ~]#title
[rootcentos8 ~]#name${title-oops}
[rootcentos8 ~]#echo $name[rootcentos8 ~]#unset title
[rootacentos8 ~]#name$ftitle-oops}
[rootcentos8 ~]#echo $name
oops9.2 高级变量用法-有类型变量
Shell变量一般是无类型的但是bash Shell提供了declare和typeset两个命令用于指定变量的类型两个命令是等价的
declare [选项] 变量名选项
-r 声明或显示只读变量
-i 将变量定义为整型数
-a 将变量定义为数组
-A 将变量定义为关联数组
-f 显示已定义的所有函数名及其内容
-F 仅显示已定义的所有函数名
-x 声明或显示环境变量和函数相当于export
-l 声明变量为小写字母 declare -l varUPPER
-u 声明变量为大写字母 declare -u varlower9.3 变量间接引用
9.3.1 eval命令
eval命令将会首先扫描命令行进行所有的置换然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量该命令对变量进行两次扫描因此后面必须跟命令
例1
[rootCentOS8 test]#CMDhostname
[rootCentOS8 test]#$CMD
CentOS8.Joyce.person1
[rootCentOS8 test]#echo $CMD
hostname
[rootCentOS8 test]#eval $CMD
CentOS8.Joyce.person1例2
[rootCentOS8 test]#n10
[rootCentOS8 test]#for i in {1..$n};do echo $i;done
{1..10}
[rootCentOS8 test]#for i in eval echo {1..$n};do echo $i;done
1
2
3
4
5
6
7
8
9
109.3.2 间接变量引用
如果第一个变量的值是第二个变量的名字从第一个变量引用第二个变量的值就称为间接变量引用
variable1的值是variable2而variable2又是变量名variable2的值为value间接变量引用是指通过variable1获
得变量值value的行为
variablelvariable2
variable2valuebash Shell提供了两种格式实现间接变量引用
eval tempvar \$Svariable1
tempvar${!variable1}例
[rootCentOS8 test]#ceoname
[rootCentOS8 test]#nameMe
[rootCentOS8 test]#echo $ceo
name
[rootCentOS8 test]#echo $$ceo
7487ceo
[rootCentOS8 test]#echo \$$ceo
$name
[rootCentOS8 test]#eval echo \$$ceo
Me
#或
[rootCentOS8 test]#echo ${!ceo}
Me9.3.3变量引用reference
[rootcentos8 ~]#cat test.sh
#!/bin/bash
ceoME
titleceo
declare -n ref$title
[ -R ref ] echo reference
echo $ref
ceoJoyce
echo $ref[rootcentos8 ~]#bash test.sh
reference
ME
Joyce