建议用 .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 ...... EOFexpr、let 算数运算$(()) 算数运算 $((10-2))exit num 退出脚本,释放系统资源,并返回一个num数值(1-255) 返回值可以用 $? 来查询
1.1、磁盘分区案例(EOF)
#!/bin/bash# 需要交互的内容顶格写入EOF块中fdisk /dev/sdb <<EOFnp3+534MWEOF
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`;doecho -n -e "\b$time"sleep 1done
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、文字颜色后面有个m3、字符串前后可以没有空格,如果有的话,输出也是同样有空格例: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—–37echo -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—–47echo -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 nameread -p "name:" nameecho -n "password:"read -s -t5 -n6 pwdecho "名字是:$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]=pearass_array1[index2]=appleass_array1[index3]=orangeass_array1[index4]=peach二: 一次赋多个值ass_array2=([index1]=tom [index2]=jack [index3]=alice [index4]=’bash shell’)
5.3、案例
/bin/bashfor ((i=0;i<3;i++))doread -p "输入第$((i + 1))个人名: " name[$i]read -p "输入第$[$i + 1]个年龄: " age[$i]read -p "输入第`expr $i + 1`个性别: " gender[$i]doneclearecho -e "\t\t\t\t学员查询系统"while :docp=0# echo -e "\t\t\t\t学员查询系统"read -p "输入要查询的姓名: " xm[ $xm == "Q" ]&&exitfor ((i=0;i<3;i++))doif [ "$xm" == "${name[$i]}" ];thenecho "${name[$i]} ${age[$i]} ${gender[$i]}"cp=1fidone[ $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 ]thenmkdir /usr/local/caoecho "Create Directory is OK"fi2、二种判断:if [ 条件 ]then满足条件后的执行语句else不满足的执行语句fi3、三种或以上判断:if [ 条件 ]then满足条件后的执行语句elif [ 条件 ]then满足elif条件后的执行语句else不满足执行fi
6.3、if高级应用
1、条件符号使用双圆括号,可以在条件中植入数学表达式双小圆括号中的比较运算符 使用的是我们传统的比较运算符(>,>=,==,<,<=,!=)#!/bin/bashif (( 1+1 == 1 ));thenecho "结果相等"elseecho “结果不等”fi2、使用双方括号,可以在条件中使用通配符为字符串提供高级功能,模式匹配 r* 匹配r开头的字符串#!/bin/bashfor var in ab ac rx bs rvv vrdoif [[ "$var" == r* ]];thenecho "$var"fidone
6.4、for循环
1、常规式写法for var in value1 value2 .....docommandsdone例:for i in `seq 1 9`;doecho "$i"done2、C式写法for (( 变量;条件;自增减运算 ));do代码块done3、无限循环for ((;;));do代码块done
6.5、循环的控制语句
sleep N 脚本执行到这里休眠N秒continue 跳过本次循环break 终止本次循环(可以在后边加数字,表示终止第几层的循环)
6.6、while循环
当条件为true循环,为false停止while [ 条件 ]:do代码块donewhile遍历文本内容:(./test.sh test.sh)#!/bin/bashwhile read i;doecho "$i"done < $1while读出文件中的列,IFS指定默认的列分隔符#!/bin/bashIFS=$":"while read f1 f2 f3 f4 f5 f6;doecho "$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:" ncase $n in1)echo "你好";;2)echo "我好";;*)echo "bye bye";;esac
二、函数
函数的两种定义 函数名(){} function 函数名{}start () {echo "我在这里定义了函数"}start
三、实战
1、nginx启动管理脚本
#!/bin/bash#=====================variablesnginxdoc="/usr/local/nginx"nginxd="$nginxdoc/sbin/nginx"pid="$nginxdoc/logs/nginx.pid"conf="$nginxdoc/conf/nginx.conf"#====================functionmystart () {if [ -f $pid ] && pstree -p |grep `cat $pid` &>/dev/null;thenecho "nginx already run..."exit 0elseif $nginxd ;thenecho -e "nginx start\t\t\t\t[\033[32m OK \033[0m]"elseecho -e "nginx start\t\t\t\t[\033[31m FAIL \033[0m]"fifi}mystop () {if [ -f $pid ] && pstree -p |grep `cat $pid` &>/dev/null;thenif killall -s QUIT $nginxd;thenecho -e "nginx stop\t\t\t\t[\033[32m OK \033[0m]"elseecho -e "nginx stop\t\t\t\t[\033[31m FAIL \033[0m]"fielseecho "nginx already stop...."fi}myrestart () {mystop;sleep 2 ;mystart}myreload () {if [ -f $pid ] && pstree -p |grep `cat $pid` &>/dev/null;thenif killall -s HUP $nginxd;thenecho -e "nginx reload\t\t\t\t[\033[32m OK \033[0m]"elseecho -e "nginx reload\t\t\t\t[\033[31m FAIL \033[0m]"fielseecho "nginx is stop...."fi}mystatus () {if [ -f $pid ] && pstree -p |grep `cat $pid` &>/dev/null;thenecho "nginx is open"elseecho "nginx is stop"fi}#===================main#calld functioncase $1 instart|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 Pflags数字 表示新文本替换的模式g: 表示用新文本替换现有文本的全部实例p: 表示打印原始的内容w filename: 将替换的结果写入文件例:将data1文本中4 the一行后面插入hello worldsed '/4 the/a hello world' data1例:将nginx.conf中#开头,包含#,以空格开头的全删掉sed -r '/(^#|#|^$)/d' nginx.conf例:将data1文本中cat替换成dogsed 's/cat/dog/' data1技巧1:打印行号sed -n '$=' data1
4、DNS检测WEB状态,并通过DNS对域名做负载均衡
#!/bin/bashCP1=0CP2=0while :do#tongping -c1 192.168.18.240 > /dev/nullif [ $? -eq 1 ] && [ $CP1 -eq 0 ]thensed -i '/192.168.18.240/s/^/;/' /var/named/baidu.zone/etc/init.d/named reloadCP1=1fi#butongping -c1 192.168.18.240 > /dev/nullif [ $? -eq 0 ] && [ $CP1 -eq 1 ]thensed -i '/192.168.18.240/s/;//' /var/named/baidu.zone/etc/init.d/named reloadCP1=0fiping -c1 192.168.18.241 > /dev/nullif [ $? -eq 1 ] && [ $CP2 -eq 0 ]thensed -i '/192.168.18.241/s/^/;/' /var/named/baidu.zone/etc/init.d/named reloadCP2=1fiping -c1 192.168.18.241 > /dev/nullif [ $? -eq 0 ] && [ $CP2 -eq 1 ]thensed -i '/192.168.18.241/s/;//' /var/named/baidu.zone/etc/init.d/named reloadCP2=0fisleep 5done
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 test1 the quick brown fox jumps over the lazy cat . dog2 the quick brown fox jumps over the lazy cat . dog3 the quick brown fox jumps over the lazy cat . dog4 the quick brown fox jumps over the lazy cat . dog5 the quick brown fox jumps over the lazy cat . dog打印test文本的行数[root@www ~]# awk 'END{print NR}' test5打印test文本最后一行内容[root@www ~]# awk 'END{print $0}' test5 the quick brown fox jumps over the lazy cat . dog打印test文本列数[root@www ~]# awk 'END{print NF}' test12
