建议用 .sh 结尾,第一行用 #!/bin/bash 来指定脚本的运行环境
#!/bin/bash
#Auther: cao
#Created Time: 2021/08/14 16:30
#Script Description: oracl install
一、语法
1、特殊符号
~ 用户的家目录
! 执行历史命令 !! 执行上一条命令
$ 变量中取内容符
+ - * / % 数学运算加、减、乘、除、取余
& 后台执行
* 匹配所有
? 匹配除回车以外的第一个字符
; 可以在shell中一行执行多个命令,命令之间用 ; 隔开
| 管道符 上一个命令的输出作为下一个命令的输入 cat filename | grep "abc"
\ 转义符
`` 反引号 命令中执行命令 echo "today is:`date +%F`"
'' 单引号,字符串可以用单引号,单引号是强引,不解释变量
"" 双引号,字符串可以用双引号,单引号是弱引,可以变量传参
> 重定向输入 覆盖原数据
>> 重定向追加输入,在源数据的末尾加上
< 重定向输出 wc < /etc/passwd
<< 重定向追加输出 fdisk /dev/sdb <<EOF ...... EOF
expr、let 算数运算
$(()) 算数运算 $((10-2))
exit num 退出脚本,释放系统资源,并返回一个num数值(1-255) 返回值可以用 $? 来查询
1.1、磁盘分区案例(EOF)
#!/bin/bash
# 需要交互的内容顶格写入EOF块中
fdisk /dev/sdb <<EOF
n
p
3
+534M
W
EOF
1.2、判断是否位整数(expr let)
expr 7 + 1 &> /dev/null ; echo $?
# 结果0为整数,非0不为整数
let sum=1+1 ; echo $sum
# let只能整数做计算
1.3、查询内存使用率(bc运算,scale截取小数点位数)
echo "当前内存的使用率是:`echo "scale=2;141*100/7966"|bc`%"
2、格式化输出
2.1、echo
命令选项: -n 不换行 echo -n “date:”;date +%F -e 解释转义字符,就是解释输出一个变量
转义字符: \a 发出警告声 \t 插入tab \n 换行且光标移至行首 \b 删除前一个字符
\c 最后不加上换行符号 \f 换行但光标仍停留在原来的位置 \r 光标移至行首但不换行 \v 与 \f 相同 \插入\字符 \nnn插入nnn(八进制)所代表的ASCII字符 -help 显示帮助信息 -version 显示版本信息
#!/bin/bash
# -e来实现倒计时
for time in `seq 9 -1 0`;do
echo -n -e "\b$time"
sleep 1
done
2.2、字体颜色
shell脚本中echo显示内容带颜色显示,echo显示带颜色,需要使用参数-e
格式: echo -e "\033[字背景颜色;文字颜色m字符串\033[0m"
例如: echo -e "\033[41;36m something here \033[0m"
其中41的位置代表底色, 36的位置是代表字的颜色
注:
1、字背景颜色和文字颜色之间是英文的""
2、文字颜色后面有个m
3、字符串前后可以没有空格,如果有的话,输出也是同样有空格
例:
echo -e “\033[31m 红色字 \033[0m”
echo -e “\033[34m 黄色字 \033[0m”
echo -e “\033[41;33m 红底黄字 \033[0m”
echo -e “\033[41;37m 红底白字 \033[0m”
字颜色:30—–37
echo -e “\033[30m 黑色字 \033[0m”
echo -e “\033[31m 红色字 \033[0m”
echo -e “\033[32m 绿色字 \033[0m”
echo -e “\033[33m 黄色字 \033[0m”
echo -e “\033[34m 蓝色字 \033[0m”
echo -e “\033[35m 紫色字 \033[0m”
echo -e “\033[36m 天蓝字 \033[0m”
echo -e “\033[37m 白色字 \033[0m”
字背景颜色范围:40—–47
echo -e “\033[40;37m 黑底白字 \033[0m”
echo -e “\033[41;37m 红底白字 \033[0m”
echo -e “\033[42;37m 绿底白字 \033[0m”
echo -e “\033[43;37m 黄底白字 \033[0m”
echo -e “\033[44;37m 蓝底白字 \033[0m”
echo -e “\033[45;37m 紫底白字 \033[0m”
echo -e “\033[46;37m 天蓝底白字 \033[0m”
echo -e “\033[47;30m 白底黑字 \033[0m”
最后面控制选项说明
\033[0m 关闭所有属性
\033[1m 设置高亮度
\033[4m 下划线
\033[5m 闪烁
\033[7m 反显
\033[8m 消隐
\033[30m — \33[37m
设置前景色
\033[40m — \33[47m 设置背景色
\033[nA 光标上移n行
\033[nB 光标下移n行
\033[nC 光标右移n行
\033[nD 光标左移n行
\033[y;xH设置光标位置
\033[2J 清屏
\033[K 清除从光标到行尾的内容
\33[s 保存光标位置
\033[u 恢复光标位置
\033[?25l 隐藏光标
\033[?25h 显示光标
3、交互
让用户输入
3.1、read
-p 打印信息 -t 限定时间 -s 不回显 -n 输入字符个数
#!/bin/bash
#echo -n "name:"
#read name
read -p "name:" name
echo -n "password:"
read -s -t5 -n6 pwd
echo "名字是:$name 密码是:$pwd"
4、变量
将字符串值临时存放在内存变量里,即变量和字符串值是对照关系
4.1、变量的分类
本地变量:用户私有变量,只有本用户可以使用,保存在家目录下的.bash_profile、.bashrc文件中
全局变量:所有用户都可以使用,保存在/etc/profile、/etc/bashrc文件中
用户自定义变量:用户自定义,比如脚本中的变量
变量名命名规则:
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
中间不能有空格,可以使用下划线(_)。
不能使用标点符号。
不能使用bash里的关键字(可用help命令查看保留关键字)。
4.2、变量的基本使用
变量格式:变量名=值 (在shell编程中的变量名和等号之间不能有空格)
读取方法:$变量名
取消变量:unset 变量名
全局变量:export name='baism'
本地永久变量:tail -1 ~/.bash_profile
全局永久变量:tail -1 /etc/profile
4.3、特殊变量
$* 代表所有参数,其间隔为IFS内参数的第一个字元
$@ 与 * 类同,不同之处在于不参照IFS
%# 代表参数数量
$ 执行上一个指令的返回值
$~ 最近执行的 foreground pipeline 的选项参数
$$ 本身的 Process ID
$ 执行上一个背景指令的PID
$_ 显示出最佳的一个执行命令
$N shell脚本的第几个外传参数(0为脚本名称)
5、数组
可以将多个值赋予给一个变量,用索引区分
5.1、数组的基本使用
数组名称=(元素1 元素2 元素3 ...)
取值:${数组名称}[索引] 默认第一个从0开始
查看数组:declare -A 数组名
访问数组元数:
# echo ${array1[0]} 访问数组中的第一个元素
# echo ${array1[@]} 访问数组中所有元素 等同于 echo ${array1[*]}
# echo ${#array1[@]} 统计数组元素的个数
# echo ${!array2[@]} 获取数组元素的索引
# echo ${array1[@]:1} 从数组下标1开始
# echo ${array1[@]:1:2} 从数组下标1开始,访问两个元素
5.2、关联数组
一: 一次赋一个值 数组名[索引]=变量值
ass_array1[index1]=pear
ass_array1[index2]=apple
ass_array1[index3]=orange
ass_array1[index4]=peach
二: 一次赋多个值
ass_array2=([index1]=tom [index2]=jack [index3]=alice [index4]=’bash shell’)
5.3、案例
/bin/bash
for ((i=0;i<3;i++))
do
read -p "输入第$((i + 1))个人名: " name[$i]
read -p "输入第$[$i + 1]个年龄: " age[$i]
read -p "输入第`expr $i + 1`个性别: " gender[$i]
done
clear
echo -e "\t\t\t\t学员查询系统"
while :
do
cp=0
# echo -e "\t\t\t\t学员查询系统"
read -p "输入要查询的姓名: " xm
[ $xm == "Q" ]&&exit
for ((i=0;i<3;i++))
do
if [ "$xm" == "${name[$i]}" ];then
echo "${name[$i]} ${age[$i]} ${gender[$i]}"
cp=1
fi
done
[ $cp -eq 0 ]&&echo "not found student"
done
6、流程控制
6.1、判断比较符号
数学判断
-eq 等于
-gt 大于
-lt 小于
-ge 大于或等于
-le 小于或等于
-ne 不等于
字符串判断(字符串要用引号引起来)
== 等于
!= 不等于
-n 检查字符串的禅古是否大于0
-z 检查字符串的长度是否为0
文件判断
-d 检查文件是否存在且为目录
-e 检查文件是否存在
-f 检查文件是否存在且为文件
-r 检查文件是否存在且可读
-s 检查文件是否存在且不为空
-w 检查文件是否存在且可写
-x 检查文件是否存在且可执行
-O 检查文件是否存在且被当前用户所拥有
-G 检查文件是否存在且默认组为当前用户组
test file1 -nt file2;echo $? 检查file1是否比file2新
test file1 -ot file2;echo $? 检查file1是否比file2旧
逻辑判断
&& 与
|| 或
! 非
赋值判断
= 赋值运算符 a=10 name="cao"
6.2、if语法
1、一步判断:
if [ 条件 ]
then
满足条件后的执行语句
fi
例:
if [ ! -d /usr/local/cao ]
then
mkdir /usr/local/cao
echo "Create Directory is OK"
fi
2、二种判断:
if [ 条件 ]
then
满足条件后的执行语句
else
不满足的执行语句
fi
3、三种或以上判断:
if [ 条件 ]
then
满足条件后的执行语句
elif [ 条件 ]
then
满足elif条件后的执行语句
else
不满足执行
fi
6.3、if高级应用
1、条件符号使用双圆括号,可以在条件中植入数学表达式
双小圆括号中的比较运算符 使用的是我们传统的比较运算符(>,>=,==,<,<=,!=)
#!/bin/bash
if (( 1+1 == 1 ));then
echo "结果相等"
else
echo “结果不等”
fi
2、使用双方括号,可以在条件中使用通配符
为字符串提供高级功能,模式匹配 r* 匹配r开头的字符串
#!/bin/bash
for var in ab ac rx bs rvv vr
do
if [[ "$var" == r* ]];then
echo "$var"
fi
done
6.4、for循环
1、常规式写法
for var in value1 value2 .....
do
commands
done
例:
for i in `seq 1 9`;do
echo "$i"
done
2、C式写法
for (( 变量;条件;自增减运算 ));do
代码块
done
3、无限循环
for ((;;));do
代码块
done
6.5、循环的控制语句
sleep N 脚本执行到这里休眠N秒
continue 跳过本次循环
break 终止本次循环(可以在后边加数字,表示终止第几层的循环)
6.6、while循环
当条件为true循环,为false停止
while [ 条件 ]:do
代码块
done
while遍历文本内容:(./test.sh test.sh)
#!/bin/bash
while read i;do
echo "$i"
done < $1
while读出文件中的列,IFS指定默认的列分隔符
#!/bin/bash
IFS=$":"
while read f1 f2 f3 f4 f5 f6;do
echo "$f1 $f2 $f3 $f4"
done < /etc/passwd
6.7、utile循环
当条件为false循环,为true停止
untile [ 条件 ]:do
代码块
done
6.8、case语句
case 变量 in
条件1)
执行代码块
;;
条件2)
执行代码块
;;
......
esac
例:
read -p "num:" n
case $n in
1)
echo "你好"
;;
2)
echo "我好"
;;
*)
echo "bye bye"
;;
esac
二、函数
函数的两种定义 函数名(){} function 函数名{}
start () {
echo "我在这里定义了函数"
}
start
三、实战
1、nginx启动管理脚本
#!/bin/bash
#=====================variables
nginxdoc="/usr/local/nginx"
nginxd="$nginxdoc/sbin/nginx"
pid="$nginxdoc/logs/nginx.pid"
conf="$nginxdoc/conf/nginx.conf"
#====================function
mystart () {
if [ -f $pid ] && pstree -p |grep `cat $pid` &>/dev/null;then
echo "nginx already run..."
exit 0
else
if $nginxd ;then
echo -e "nginx start\t\t\t\t[\033[32m OK \033[0m]"
else
echo -e "nginx start\t\t\t\t[\033[31m FAIL \033[0m]"
fi
fi
}
mystop () {
if [ -f $pid ] && pstree -p |grep `cat $pid` &>/dev/null;then
if killall -s QUIT $nginxd;then
echo -e "nginx stop\t\t\t\t[\033[32m OK \033[0m]"
else
echo -e "nginx stop\t\t\t\t[\033[31m FAIL \033[0m]"
fi
else
echo "nginx already stop...."
fi
}
myrestart () {
mystop;sleep 2 ;mystart
}
myreload () {
if [ -f $pid ] && pstree -p |grep `cat $pid` &>/dev/null;then
if killall -s HUP $nginxd;then
echo -e "nginx reload\t\t\t\t[\033[32m OK \033[0m]"
else
echo -e "nginx reload\t\t\t\t[\033[31m FAIL \033[0m]"
fi
else
echo "nginx is stop...."
fi
}
mystatus () {
if [ -f $pid ] && pstree -p |grep `cat $pid` &>/dev/null;then
echo "nginx is open"
else
echo "nginx is stop"
fi
}
#===================main
#calld function
case $1 in
start|START)
mystart
;;
stop) mystop ;;
restart) myrestart ;;
reload) myreload ;;
status) mystatus ;;
esac
2、正则表达式
. 匹配除回车以外的任意字符
( ) 字符串分组
[ ] 定义字符类,匹配括号中的一个字符
[ ^ ] 表示否定括号中出现字符类中的字符,取反。
\ 转义字符
* 某个字符之后加星号表示该字符出现 0次或多次
? 与星号相似,但略有变化,表示该字符出现 0次或1次
+ 与星号相似,表示其前面字符出现 1次或多次
{n,m} 某个字符之后出现,表示该字符最少n次,最多m次
{m} 正好出现了m次
POSIX特殊字符(都是匹配一个字节):
[:alnum:] 匹配任意字母字符0-9 a-z A-Z
[:alpha:] 匹配任意字母,大写或小写
[:digit:] 数字 0-9
[:graph:] 非空字符( 非空格控制字符)
[:lower:] 小写字符a-z
[:upper:] 大写字符A-Z
[:cntrl:] 控制字符
[:print:] 非空字符( 包括空格)
[:punct:] 标点符号
[:blank:] 空格和TAB字符
[:xdigit:] 16 进制数字
[:space:] 所有空白字符( 新行、空格、制表符)
第一个中括号是匹配符[] 匹配中括号中的任意一个字符,第二个[]是格式 如[:digit:]
egrep "^a[[:alnum:]]c$" file
案例一 匹配合法的IP地址
egrep ‘^((25[0-5]|2[0-4][[:digit:]]|[01]?[[:digit:]][[:digit:]]?).){3}(25[0-5]|2[0-4][[:digit:]]|[01]?[[:digit:]][[:digit:]]?)$’ —color ip_base
案例二 匹配座机电话号码
egrep “^[[:graph:]]{12}$” number |egrep “^(0[1-9][0-9][0-9]?)-[1-9][0-9]{6,7}$”
3、sed文件行操作
对文本中的行进行操作,默认是修改缓存数据而不是源文件
语法:
sed [options] '{command}[flags]' [filename]
命令选项
-e script 将脚本中指定的命令添加到处理输入时执行的命令中 多条件,一行中要有多个操作
-f script 将文件中指定的命令添加到处理输入时执行的命令中,一行一个命令
-n 抑制自动输出,只显示修改的内容
-i 编辑文件内容
-i.bak 修改时同时创建.bak备份文件。
-r 使用扩展的正则表达式
! 取反 (跟在模式条件后与shell有所区别)
sed常用内部命令
a 在匹配后面添加
i 在匹配前面添加
p 打印
d 删除
s 查找替换
c 更改
y 转换 N D P
flags
数字 表示新文本替换的模式
g: 表示用新文本替换现有文本的全部实例
p: 表示打印原始的内容
w filename: 将替换的结果写入文件
例:将data1文本中4 the一行后面插入hello world
sed '/4 the/a hello world' data1
例:将nginx.conf中#开头,包含#,以空格开头的全删掉
sed -r '/(^#|#|^$)/d' nginx.conf
例:将data1文本中cat替换成dog
sed 's/cat/dog/' data1
技巧1:打印行号
sed -n '$=' data1
4、DNS检测WEB状态,并通过DNS对域名做负载均衡
#!/bin/bash
CP1=0
CP2=0
while :
do
#tong
ping -c1 192.168.18.240 > /dev/null
if [ $? -eq 1 ] && [ $CP1 -eq 0 ]
then
sed -i '/192.168.18.240/s/^/;/' /var/named/baidu.zone
/etc/init.d/named reload
CP1=1
fi
#butong
ping -c1 192.168.18.240 > /dev/null
if [ $? -eq 0 ] && [ $CP1 -eq 1 ]
then
sed -i '/192.168.18.240/s/;//' /var/named/baidu.zone
/etc/init.d/named reload
CP1=0
fi
ping -c1 192.168.18.241 > /dev/null
if [ $? -eq 1 ] && [ $CP2 -eq 0 ]
then
sed -i '/192.168.18.241/s/^/;/' /var/named/baidu.zone
/etc/init.d/named reload
CP2=1
fi
ping -c1 192.168.18.241 > /dev/null
if [ $? -eq 0 ] && [ $CP2 -eq 1 ]
then
sed -i '/192.168.18.241/s/;//' /var/named/baidu.zone
/etc/init.d/named reload
CP2=0
fi
sleep 5
done
5、awk输出流操作
awk是一种可以处理数据、产生格式化报表的语言,功能十分强大。awk 认为文件中的每一行是一条记录 记录与记录的分隔符为换行符,每一列是一个字段 字段与字段的分隔符默认是一个或多个空格或tab制表符.
awk的工作方式是读取数据,将每一行数据视为一条记录(record)每条记录以字段分隔符分成若干字段,然后输出各个字段的值.
awk [options] [BEGIN]{program}[END] [file]
常用命令选项
-F fs 指定描绘一行中数据字段的文件分隔符 默认为空格
-f file 指定读取程序的文件名
-v var=value 定义awk程序中使用的变量和默认值
注意:awk 程序脚本由左大括号和右大括号定义。脚本命令必须放置在两个大括号之间。由于awk命令行假定脚本是单文本字符串,所以必须将脚本包括在单引号内。
awk程序运行优先级是:
1)BEGIN: 在开始处理数据流之前执行,可选项
2)program: 如何处理数据流,必选项
3)END: 处理完数据流后执行,可选项
例:awk -F ":" 'NR==1{print $1 "-" $2 "-" $3}' passwd
例:head -2 /proc/meminfo | awk 'NR==1{z=$2}NR==2{f=$2}END{print(z-f)*100/z "%"}'
$0 表示整行文本
$1 表示文本行中的第一个数据字段
$2 表示文本行中的第二个数据字段
$N 表示文本行中的第N个数据字段
$NF 表示文本行中的最后一个数据字段
NR: 指定行号
例:awk '{print $0}' test
例:awk 'NR==3{print $0}' test
赋值运算 =
比较运算 > >= == < <= !=
数学运算 + - / % * ++ —
逻辑运算 && ||
匹配运算 ~ !~
FIELDWIDTHS 以空格分隔的数字列表,用空格定义每个数据字段的精确宽度
FS 输入字段分隔符号
OFS 输出字段分隔符号
RS 输入记录分隔符
ORS 输出记录分隔符号
if 判断语句
for 循环语句
while 循环语句
do…while 语句
break 循环控制停止
6、awk小技巧
[root@www ~]# cat test
1 the quick brown fox jumps over the lazy cat . dog
2 the quick brown fox jumps over the lazy cat . dog
3 the quick brown fox jumps over the lazy cat . dog
4 the quick brown fox jumps over the lazy cat . dog
5 the quick brown fox jumps over the lazy cat . dog
打印test文本的行数
[root@www ~]# awk 'END{print NR}' test
5
打印test文本最后一行内容
[root@www ~]# awk 'END{print $0}' test
5 the quick brown fox jumps over the lazy cat . dog
打印test文本列数
[root@www ~]# awk 'END{print NF}' test
12