2.vi/vim编辑器的熟练使用。SSH客户端软件的设置。
3.基础的服务,系统服务ntpcrond,网络服务nfsrsyncinotifysersyncsshlamplnmp
Shell是一个命令解释器,是linux/unix操作系统的最外层,负责直接与用户对话,把用户输入的命令解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕给用户。
3.什么是shell脚本?
当命令或者语句不在命令行执行,而是通过一个程序文件执行时,该程序或文件就被成为shell脚本或者shell程序,shell程序类似DOS系统下的批处理程序。
4.简单的例子
[root@yangjianboinbeijingday1]#catdel_messages.shcd/var/logcat/dev/null>messagesecho"messagesisnull!"这个脚本的缺点:缺乏基本的逻辑判断,会导致前面的命令出错后,后面的命令无法正确执行。
上面脚本的升级版:
#!/bin/bash#清除messages日志脚本,版本2--yangjianboLOG_DIR=/var/logROOT_UID=0if["$UID"-ne"$ROOT_UID"]thenecho"Youmustberoot."exit1ficd$LOG_DIR||{echo"pleasechangeto/var/log/">&2exit1}cat/dev/null>messages&&echo"messagesiscleanedup"exit03.Shell程序在运维工作中的作用和地位Shell脚本很擅长处理纯文本类型的数据,而linux中几乎所有的配置文件和日志文件都是纯文本类型的文件。
贴近系统层的操作,shell是最佳的。shell的伙伴(2000个linux命令,awk,sed,grep)
1.主要分为两大类
Bourneshell
Cshell
2.高级运维或者开发型运维常用的脚本语言
php
perl
python
Linuxbash
Solaris和FreeBSDsh
AIXksh
HP-UXsh
如何查看系统的默认shell
查看系统的shell版本
bash--version
1.shell脚本组成:Unix/linux命令bashshell命令注释程序结构控制语句
第一行指出是由哪个解释器来执行。
#!/bin/bash或者#!/bin/sh
#!/bin/awk
#!/bin/sed
注释:使用的是#
1.方法
第一种:当脚本本身没有执行权限,使用bash脚本或者sh脚本。文件权限没有x
/bin/bash1.sh
bash1.sh
sh1.sh
第二种:需要脚本有权限,使用./脚本名执行或者全路径。文件权限必须得有x
./1.sh
第三种:sourcescript-name或者.script-name
第三种与第一种和第二种的区别:
举例来说明:
面试题:cattest.shuser=`whoami`shtest.shecho$user结果是什么?结果为空,这是为什么呢?当使用第一种方法和第二种方法执行sh文件,系统会给一个新的bash执行让我们执行sh里面的命令,因此变量都是子进程的bash中执行的。当sh执行完毕后,子进程bash内的所有数据被删除,因此为空。但是使用第三种方法就不一样了,因为是在自己的进程中执行sh,不会产生子进程,所以不会为空。8.Shell脚本开发规范和习惯1.开头指定脚本解释器
3.脚本中不用中文注释
4.脚本以.sh为扩展名
5.代码书写的优秀习惯
成对出现的符号一次性写完。
for循环要一次写完。
if语句要一次性写完。
通过手工缩进让代码更容易读。让代码有层次感。
1.分类:环境变量和局部变量
环境变量也称为全局变量,可以在创建它们的shell及其派生出来的任意子进程shell中使用。
局部变量只能在它们自己的shell中或脚本中使用。
2.环境变量
环境变量可以在命令行设置,但是注销就消失,所以需要在用户的家目录.bash_profile或者全局配置/etc/profile或者/etc/profile.d/中定义。
环境变量均为大写,必须用export导出。
3.环境变量读取配置文件,分为两种情况。
1.loginshell
3.su-username
2.non-loginshell
1.suusername
2.图形界面下打开的终端
3.执行脚本
4.通过ssh免密钥的方式,直接执行命令。
sshjava@192.168.1.100'echo$TESTZZ'注意在命令行使用单引号,脚本使用双引号
3.配置文件分类
1.按生效范围划分
1.全局
/etc/profile
/etc/bashrc
/etc/profile.d/*.sh
2.个人
~/.bash_profile
~/.bashrc
2.按功能划分
用途:定义环境变量
运行命令或脚本
全局:/etc/profile
个人:~/.bash_profile
用途:定义命令别名
定义本地变量
全局:/etc/bashrc
个人:~/.bashrc
/etc/profile-->/etc/profile.d/*.sh-->~/.bash_profile-->~/.bashrc-->/etc/bashrc
~/.bashrc-->/etc/bashrc-->/etc/profile.d/*.sh
4.查看环境变量
env:列出所有的环境变量
set:查看所有变量(含环境变量与自定义变量)
export:自定义变量转成环境变量
1.显示echo$LANG
2.env命令
3.set命令
4.取消环境变量
unset变量名
1.本地变量
1.定义:本地变量在用户当前shell生存期的脚本中使用。退出或者进入另外一个进程,就会失效。
2.变量定义:
例子1:
[root@yangjianboinbeijingday1]#a=192.168.1.2[root@yangjianboinbeijingday1]#b='192.168.1.2'[root@yangjianboinbeijingday1]#c="192.168.1.2"[root@yangjianboinbeijingday1]#echo"a=$a""b=$b""c=${c}"a=192.168.1.2b=192.168.1.2c=192.168.1.2例子2:
3.变量的命名规范
1.都使用大写
2.不能以数字开头
3.等号两边不能直接有空格,如果需要使用空格,需要加引号。
4.把命令作为变量
需要使用反引号。
也可以使用$()
批量创建目录mkdir`seq5`mkdir$(echo{a..e})mkdir{o..w}5.关于awk引用shell变量的使用情况
1.位置变量
$0获取当前执行的shell脚本的文件名,包括路径。
[root@yangjianboinbeijingday1]#cat0.sh#!/bin/bashecho$0[root@yangjianboinbeijingday1]#sh0.sh#取文件名0.sh[root@yangjianboinbeijingday1]#sh/server/scripts/day1/0.sh#取完整路径和文件名/server/scripts/day1/0.sh[root@yangjianboinbeijingday1]#cat0.sh#!/bin/bashdirname$0从$0中取路径basename$0从$0中取文件名[root@yangjianboinbeijingday1]#sh/server/scripts/day1/0.sh/server/scripts/day10.sh
想单独获得路径和文件名
dirname/server/scripts/0.sh
basename/server/scripts/0.sh
$n获取当前执行的shell脚本的第n个参数值,当n大于9,用大括号括起来${10}。
[root@yangjianboinbeijingday1]#catn.sh#!/bin/bashecho$1$2$3${10}[root@yangjianboinbeijingday1]#bashn.sh{1..11}12310[root@yangjianboinbeijingday1]#bashn.sh`seq11`12310$#获取当前执行的shell脚本的传入的参数个数。
[root@yangjianboinbeijingday1]#catn.sh#!/bin/bashecho$1$2$3${10}echo$#[root@yangjianboinbeijingday1]#shn.sh12341234[root@mysql-37scripts]#/bin/bashcanshu.sh{a..z}传入的参数个数为26,但实际接收的参数个数位为4abcd26
用于判断shell脚本参数个数的时候。实战例子:[root@yangjianboinbeijingday1]#catbijiao.sh#!/bin/bashif[$#-ne3];thenecho"pleaseinput3args!"elseecho"inputOK"fi[root@yangjianboinbeijingday1]#shbijiao.shpleaseinput3args![root@yangjianboinbeijingday1]#shbijiao.sh1pleaseinput3args![root@yangjianboinbeijingday1]#shbijiao.sh12pleaseinput3args![root@yangjianboinbeijingday1]#shbijiao.sh123inputOK[root@yangjianboinbeijingday1]#shbijiao.sh1234pleaseinput3args!
$*获取当前shell传入的所有的参数
#!/bin/bashuser=`whoami`echo$*[zhangshaohua1510@mysql-37scripts]$/bin/bashtest.sh123123
$@获取当前shell所有传参的参数
#!/bin/bashuser=`whoami`echo$@[zhangshaohua1510@mysql-37scripts]$/bin/bashtest.sh123123$*与$@的区别在于,如果不加双引号,那么它们的结果是一样;如果加上双引号,$*输出的结果是"$1$2$3",而$@输出的结果是"$1","$2","$3"。
不带引号的结果:
#!/bin/bashecho$*foriin$*;doecho$idoneecho$@foriin$@;doecho$idoneshtest.sh"Iam"yangjianbo不带双引号的时候,两个输出的结果是一样的。Iamyangjianbo这是$*IamyangjianboIamyangjianbo这是$@Iamyangjianbo带双引号的结果:
#!/bin/bashecho$*foriin"$*";doecho$idoneecho$@foriin"$@";doecho$idoneshtest.sh"Iam"yangjianbo带双引号的时候,$*与$@的结果完全不一样。Iamyangjianbo这是$*Iamyangjianbo$*带引号以后,把$1$2$3当做一个整体,输出了。Iamyangjianbo这是$@Iam$@带引号以后,把参数一个一个输出了。yangjianbo
1.$:获取上一个指令的返回值(0为成功,非零为失败)
0成功
2权限拒绝
1~125运行失败,脚本命令,系统命令错误或参数传递错误
126找到该命令了,但是无法执行
127未找到要运行的命令
>128命令被系统强制结束
[root@mysql-37scripts]#catfanhui.sh#!/bin/bashif[$#-ne2];thenecho"USAGE:$0mustbetwoargs."exit119elseechoyangianbofi[root@mysql-37scripts]#/bin/bash/server/scripts/fanhui.shUSAGE:/server/scripts/fanhui.shmustbetwoargs.[root@mysql-37scripts]#echo$119
[root@mysql-37scripts]#/bin/bash/server/scripts/fanhui.sh12yangianbo$返回值的用法如下:
1.判断命令或脚本或函数等程序是否执行成功。
2.若在脚本中调用执行"exit数字",则会返回这个数字给"$"变量。
3.如果是在函数里,则通过"return数字"把这个数字以函数返回值的形式传给"$"。
2.$$:获取当前执行的shell脚本的进程号
#!/bin/bashuser=`whoami`echo$$[zhangshaohua1510@mysql-37scripts]$/bin/bashtest.sh117683.$_:获取上一条命令的最后一个参数值
[root@192tmp]#shtest.sh"Iam"yangjianboIamyangjianboIamyangjianboIamyangjianboIamyangjianbo[root@192tmp]#echo$_bo4.$!:获取上一次执行脚本的pid
1.echo在屏幕上输出信息
语法:echoargs#后面跟字符串或者变量
-n:不换行输出
-e:解析转义字符
常用的转义字符:
\n:换行
\r:回车
\t:制表符
\b:退格
\v:纵向制表符
[root@mysql-37scripts]#echo"yangjianbo";echo"liudehua"默认自动换行yangjianboliudehua[root@mysql-37scripts]#echo-n"yangjianbo";echo"liudehua"-n不换行yangjianboliudehua[root@mysql-37scripts]#echo-e"yangjianbo\nliudehua"\n换行yangjianboliudehua[root@mysql-37scripts]#echo-e"yangjianbo\tliudehua"\t制表符tabyangjianboliudehua[root@mysql-37scripts]#echo-e"yangjianbo\bliudehua"\b退格,可以看到少了一个oyangjianbliudehua[root@mysql-37scripts]#echo-e"yangjianbo\vliudehua"\v纵向制表符yangjianboliudehua2.eval执行到eval语句,shell读取参数,并将他们组成一个新的命令
#!/bin/bashecho\$$#输出的结果为$2[sysadmin@192tmp]$sudo/bin/bashtest.shyangjianboliudehua$2#!/bin/basheval"echo\$$#"eval重新组合了echo$2,所以可以输出liudehua[sysadmin@192tmp]$sudo/bin/bashtest.shyangjianboliudehualiudehua3.exec在不创建新的进程的情况,执行指定的命令,执行完以后,该进程也就结束了。
[sysadmin@192tmp]$execdate2021年10月26日星期二11:22:10CST执行完以后,直接退出注销了。4.read标准输入,传给指定变量
[root@yangjianboinbeijingday2]#catread.shread-p"pleaseinputyourname:"usernameecho$username[root@yangjianboinbeijingday2]#shread.shpleaseinputyourname:yangjianboyangjianbo5.history查看历史记录
6.printf格式化打印
7.ulimit文件系统与程序的限制
8.shift位置参数偏移量,每执行一次,向左移动一个位置
[root@yangjianboinbeijingday2]#set--"Iam"handsomeoldboy.[root@yangjianboinbeijingday2]#echo$#3[root@yangjianboinbeijingday2]#echo$1Iam[root@yangjianboinbeijingday2]#echo$2handsome[root@yangjianboinbeijingday2]#echo$3oldboy.[root@yangjianboinbeijingday2]#shift[root@yangjianboinbeijingday2]#echo$1handsome[root@yangjianboinbeijingday2]#echo$2oldboy.[root@yangjianboinbeijingday2]#echo$3[root@yangjianboinbeijingday2]#echo$0-bash9.exit退出shell
1.返回变量的内容
[root@yangjianboinbeijingday2]#OLDBOY="Iamoldboy"[root@yangjianboinbeijingday2]#echo$OLDBOYIamoldboy[root@mysql-37scripts]#echo${OLDBOY}Iamoldboy2.返回变量值的长度
[root@yangjianboinbeijingday2]#echo${#OLDBOY}113.截取变量值
[root@yangjianboinbeijingday2]#echo${OLDBOY:2}从索引为2的开始截取,包含2amoldboy[root@yangjianboinbeijingday2]#echo${OLDBOY:3}从索引为3的开始截取,包含3moldboy3.截取其中固定的变量值,第一个参数为索引值,第二个为步长
[root@yangjianboinbeijingday2]#echo${OLDBOY:5:2}从索引为5的开始截取,截取2个长度ol4.从开头删除匹配的子字符串###
[root@mysql-37scripts]#OLDBOY="abcABC123ABCabc"[root@mysql-37scripts]#echo$OLDBOYabcABC123ABCabc[root@mysql-37scripts]#echo${OLDBOY#a*c}从头开始删除最短匹配a*c的字符串ABC123ABCabc[root@mysql-37scripts]#echo${OLDBOY##a*c}从头开始删除最长匹配a*c的字符串,所以整个都删掉了
5.从字符串的结尾开始删除%%%
[root@mysql-37scripts]#echo${OLDBOY}abcABC123ABCabc[root@mysql-37scripts]#echo${OLDBOY%a*c}从尾部开始删除最短匹配的a*cabcABC123ABC[root@mysql-37scripts]#echo${OLDBOY%%a*c}从尾部开始删除最长匹配的a*c,所以整个都删掉了6.字符串替换
语法:${变量名/子字符串/替换以后的字符串}从头开始查找子字符串进行替换,替换第一个
[root@yangjianboinbeijingday2]#echo$OLDBOYIamoldboyam[root@yangjianboinbeijingday2]#echo${OLDBOY/I/is}isamoldboyam语法:${变量名//子字符串/替换以后的字符串}替换匹配的所有字符串
[root@yangjianboinbeijingday2]#echo${OLDBOY//am/is}isisoldboyis7.生产实例
1.批量删除文件名称中的固定字符串。
[root@yangjianboinbeijingday2]#virename.sh#!/bin/bashBASEDIR=/server/scripts/day2/testdirif[-d$BASEDIR];thencd$BASEDIRforfilein`ls*.bak`;domv$file${file//_20190910/}.bak;替换为空donefi2.修改文件的扩展大写变小写,从结尾开始匹配
forfilein`ls*.HTML`;domv$file${file//HTML/html};done3.把文件名修改为大写。
ls*_20180405.bak|awk-F"_20180405"'{print"mv"$0,$1$2}'|bash4.使用rename命令修改。
rename"_20180405"""*.bakrename"HTML""html"*.HTML16.bash变量子串的深入介绍与系统案例分析1.${value:-word}
当变量未定义或者值为空,返回值为word的内容,否则返回变量的值。这个功能用来判断变量是否已定义。如果没有定义,就返回word,定义了就返回定义的值。
[root@yangjianboinbeijingtestdir]#result=${test:-word}[root@yangjianboinbeijingtestdir]#echo$test[root@yangjianboinbeijingtestdir]#echo$resultword2.${value:=word}
当变量未定义或者值为空,返回word的值的同时将word值赋给value.这个变量的功能可以解决变量没有定义的问题,并确保没有定义的变量始终有值。
[root@yangjianboinbeijingtestdir]#result=${test:=word}[root@yangjianboinbeijingtestdir]#echo$test之前test的值是空的,但是现在已经被赋值word了,这就是与-word的区别word[root@yangjianboinbeijingtestdir]#echo$resultword3.${value:"word"}
当变量未定义或者值为空,返回word,否则返回定义的值。这个功能用来设定由于变量未定义而报错的具体内容。
[root@yangjianboinbeijingtestdir]#result=${test:word}-bash:test:word[root@yangjianboinbeijingtestdir]#result=${test:"notdefined"}-bash:test:notdefined4.${value:+word}
测试变量是不是存在。如果返回了值,那么说明变量被定义了。否则就是变量没有定义。
[zhangshaohua1510@mysql-37~]$oldboy=${oldgirl:+yangjianbo}[zhangshaohua1510@mysql-37~]$echo$oldboyolboy值为空[zhangshaohua1510@mysql-37~]$echo$oldgirloldgirl值为空[zhangshaohua1510@mysql-37~]$oldgirl=20[zhangshaohua1510@mysql-37~]$oldboy=${oldgirl:+yangjianbo}定义了oldgirl,则oldboy返回,后面的yangjianbo[zhangshaohua1510@mysql-37~]$echo$oldboyyangjianbo[zhangshaohua1510@mysql-37~]$echo$oldgirl205.生产实例
[root@mysql-37scripts]#catdel20190910.sh#!/bin/bashfind${path-/tmp}-name"*.tar.gz"-typef-mtime+7|xargsrm-rf{}#没有定义path,那么就使用/tmp作为路径17.变量的数值计算常用的算术运算符
常用的算术运算命令
1.(())常用,效率最高,只适合整数
1.简单运算
[root@mysql-37scripts]#((a=1+1))[root@mysql-37scripts]#echo$a2[root@mysql-37scripts]#echo$((5*9))45
2.复杂运算
[root@mysql-37scripts]#echo$((100*(100+1)/2))50503.利用双括号进行比较判断
[root@mysql-37scripts]#echo$((3>8))0[root@mysql-37scripts]#echo$((3<8))1[root@mysql-37scripts]#if((8<3))>then>echo1>else>echo0>fi04.在变量前后使用--和++特殊运算符的表达式
赋值操作[root@yangjianboinbeijingsystemd]#echo$((a+=10))10
增长减少操作[root@yangjianboinbeijingsystemd]#a=1[root@yangjianboinbeijingsystemd]#echo$((a++))1[root@yangjianboinbeijingsystemd]#echo$((a++))2[root@yangjianboinbeijingsystemd]#echo$((a++))3[root@yangjianboinbeijingsystemd]#echo$((a++))4
注意:a++与++a的区别,a++先赋值再运算,++a先运算再赋值
从1加到100的和是多少?
[root@yangjianboinbeijingsystemd]#echo$((100*(100+1)/2))5050
使用命令行的方式,实现一个加减乘除的计算器。
[root@yangjianboinbeijingday2]#vi02.shecho$(($1))
[root@yangjianboinbeijingday2]#cat03.shecho$(($1$2$3))[root@yangjianboinbeijingday2]#sh03.sh1212[root@yangjianboinbeijingday2]#sh03.sh1+23[root@yangjianboinbeijingday2]#sh03.sh1+34[root@yangjianboinbeijingday2]#sh03.sh1+23[root@yangjianboinbeijingday2]#sh03.sh1+2+53[root@yangjianboinbeijingday2]#sh03.sh1+2+811
2.let命令这是shell的内置命令
实际操作:
[root@yangjianboinbeijingday2]#i=2[root@yangjianboinbeijingday2]#leti=i+8[root@yangjianboinbeijingday2]#echo$i10注意:如果去掉let,相当于给i赋值:i+83.expr命令
用于整数计算
[root@yangjianboinbeijingday2]#expr2+22+2[root@yangjianboinbeijingday2]#expr2+24[root@yangjianboinbeijingday2]#expr2*2expr:语法错误[root@yangjianboinbeijingday2]#expr2\*24注意:运算符左右都需要有空格,乘号要使用\进行转义。[root@yangjianboinbeijingday2]#expr$i+57
[root@yangjianboinbeijingday2]#expr$[2+8]10
expr可以统计字符串的长度
[root@yangjianboinbeijingday2]#exprlength"zhongguoren"11
[root@yangjianboinbeijingday2]#exprsubstr"yangjianbo"22an
注意:它的截取子串,开始位置为1,而不是变量子串的从0开始。
4.bc命令的用法
bc是unix/linux下的计算器,可以处理小数。
[root@yangjianboinbeijing~]#seq-s"+"1001+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100[root@yangjianboinbeijing~]#seq-s"+"100|bc50505.awk命令的用法
适合计算整数和小数。
[sysadmin@192~]$echo"73"|awk'{print($1-$2)}'4[sysadmin@192~]$echo"7.83.6"|awk'{print($1-$2)}'4.26.使用$[]做计算
7.计算变量值的长度的方法比较
1.echo${#变量名}
2.echo$(exprlength变量名)
3.echo${变量名}|wc-m
结论:使用内部函数耗时小,建议使用第一种方式。
8.read用法
-p:提示符
-t:超时
[root@yangjianboinbeijingday3]#catread.sh#!/bin/bashread-t5-p"inputyournumber":var1输入一个值,给变量var1,注意var1前面有空格echo$var1read-p的功能可以用echo-n替换。
1.条件测试语法
1.test<测试表达式>
[root@yangjianboinbeijingday3]#test-ffile&&echotrue||echofalsefalse[root@yangjianboinbeijingday3]#touchfile[root@yangjianboinbeijingday3]#test-ffile&&echotrue||echofalsetruetest!非的用法
[root@yangjianboinbeijingday3]#test!-ffile&&catfilecat:file:没有那个文件或目录[root@yangjianboinbeijingday3]#touchfile[root@yangjianboinbeijingday3]#test!-ffile&&catfile2.[<测试表达式>]
[root@yangjianboinbeijingday3]#[-ffile]&&echo1||echo00[root@yangjianboinbeijingday3]#ll总用量4-rw-r--r--1rootroot634月320:50read.sh[root@yangjianboinbeijingday3]#touchfile[root@yangjianboinbeijingday3]#[-ffile]&&echo1||echo01[root@yangjianboinbeijingday3]#[!-ffile]&&echo1||echo00[root@yangjianboinbeijingday3]#ll总用量4-rw-r--r--1rootroot04月321:07file-rw-r--r--1rootroot634月320:50read.sh[root@yangjianboinbeijingday3]#rm-rfilerm:是否删除普通空文件"file"?y[root@yangjianboinbeijingday3]#[!-ffile]&&echo1||echo01
3.[[<测试表达式>]]
说明:1和2是等价的,3为扩展的test命令。
在3中可以使用通配符进行模式匹配。
&&||><操作可以应用于[[]]中,但不能应用于[]中。
对整数进行关系运算,也可以使用shell的算术运算符。
2.文件测试表达式
1.关于某个文件名的文件类型判断。
-f该文件名是否存在且为文件
-d该文件名是否存在且为目录
-e该文件名是否存在
-s该文件名是否存在且为“非空”文件
2.关于某个文件名的权限检测。
-r该文件名是否存在且有可读的权限
-w该文件名是否存在且有可写的权限
-x该文件名是否存在且有可执行的权限
3.关于两个文件的之间的比较
-ntnewerthan判断file1是否比file2新
-otolderthan判断file1是否比file2旧
-ef判断两个文件是不是指向同一个inode
4.例子
1.如果测试的是变量,那么变量需要添加引号,否则会有误判。
[root@192~]#echo$oldboy[root@192~]#[-f$oldboy]&&echo1||echo01[root@192~]#[-f"$oldboy"]&&echo1||echo002.如果测试的是实体路径,那么有没有双引号,结果都是一样的。
[root@192~]#[-f/root/vhost.sh]&&echo1||echo01[root@192~]#[-f"/root/vhost.sh"]&&echo1||echo013.字符串测试表达式
注意:字符串测试一定要加双引号,如果不加,会带来逻辑错误。
=和!=两边一定要有空格,如果没有空格,会带来逻辑错误
=和!=可以判断两个字符串是否相同
4.整数二元比较
1.建议最好都是用-eq,-ne这些比较符号,因为<>在[]中会出现逻辑错误,如下面的例子
[root@yangjianboinbeijingday2]#[2>1]&&echo1||echo01[root@yangjianboinbeijingday2]#[2<1]&&echo1||echo01[root@yangjianboinbeijingday2]#[[2<1]]&&echo1||echo00如果是单中括号,不要使用符号,使用-eq,-ne,-gt,-lt等;或者使用双中括号。双中括号也可以使用-eq-ne-gt2.整数变量的比较
[root@192~]#a=55[root@192~]#b=66[root@192~]#[$a-gt$b]&&echo1||echo00[root@192~]#[$a-lt$b]&&echo1||echo015.逻辑操作符
1.例子
[root@192~]#[-f/etc/hosts-a-f/etc/resolv.conf]&&echo1||echo01如果在[]中使用&&||会有报错。-bash:[:missing`]'-bash:-f:commandnotfound[root@192~]#[[-f/etc/hosts&&-f/etc/resolv.conf]]&&echo1||echo01如果在[[]]中使用-a-o也会有报错-bash:syntaxerrorinconditionalexpression-bash:syntaxerrornear`-a'6.测试表达式的区别
1.单分支结构
1.语法:
if[条件]
then
指令
fi
或者
if[条件];then
2.单分支结构举例
1.比较两个数字的大小
[root@yangjianboinbeijingday4]#viif1.sh#!/bin/bashif[3-gt2];thenecho1firead读入参数[root@yangjianboinbeijingday4]#catif2.sh#!/bin/bashread-p"inputnum1":num1read-p"inputnum2":num2if[$num1-gt$num2];thenecho1fi以位置参数的形式输入值。[root@yangjianboinbeijingday4]#catif3.sh#!/bin/bashif[$1-gt$2];thenecho1fi/bin/bashif3.sh312.开发脚本实现如果/server/scripts/下面存在if4.sh就输出到屏幕。
注意:如果执行脚本后发现该if4.sh不存在,就自动创建这个if4.sh脚本。
#!/bin/bashscriptname=/server/scripts/day4/if4.shif[-e$scriptname];thenecho"existif4.sh"else`touch$scriptname`fi变量名称最好用大写,当然小写也没有问题。3.判断系统内存大小,小于100M,就邮件报警。
[root@yangjianboinbeijingday4]#catif-free.sh#!/bin/bashMEMORY=`free-m|awk'NR==3{print$4}'`if[$MEMORY-lt2000];thenecho"memoryis$MEMORY"|mail-s"memory"329624434@qq.comfi4.判断系统的根目录剩余空间大小,小于50G,就邮件报警
#!/bin/bashFREE_DISK=`df-h|awk'NR==2{print$4}'`JIELUN=`echo"${FREE_DISK//G/}<50"|bc`if[${JIELUN}-eq1];thenecho"free_diskis${FREE_DISK}"|mail-s"free_disk"329624434@qq.comfi3.if双分支结构讲解和实例
1.双分支结构
if[条件一];then
执行语句
else
2.实例
1.比较两个整数的大小。
[root@yangjianboinbeijingday4]#catif-double.sh#!/bin/basha=10b=11if[$a-gt$b];thenecho$aelseecho$bfi2.使用传参的方式。
[root@yangjianboinbeijingday4]#catif-double2.sh#!/bin/bashif[$1-gt$2];thenecho$1elseecho$2fi3.脚本判断需要添加几个参数,如果参数不正确就退出,并报错
[root@yangjianboinbeijingday4]#catif-double3.sh#!/bin/bashif[$#-ne2];thenecho"ERROR:$0num1num2"exit1fiif[$1-gt$2];thenecho$1elseecho$2fi4.判断输入的参数是不是数字,使用sed命令。
[root@yangjianboinbeijingday4]#catif-double5.sh#!/bin/bashif[$#-ne2];thenecho"ERROR:$0num1num2"exit1fi[-z"`echo$1|sed's/[a-z]//g'`"]&&{echo"num1mustbeint."exit1}[-z"`echo$2|sed's/[a-z]//g'`"]&&{echo"num2mustbeint."exit1}if[$1-gt$2];thenecho$1elseecho$2fi5.使用read读入变量参数,判断为数字,不能为字符串,比较两个数字的大小。
#!/bin/bashread-p"pleaseinputyournumber:"num1num2if[-z$num1];thenecho"$0needtwoargs!"exit1elif[-z$num2];thenecho"$0needtwoargs!"exit1else[-z`echo$num1|sed's/[a-z]//g'`]&&{echo"num1mustbeint"exit1}[-z`echo$num2|sed's/[a-z]//g'`]&&{echo"num2mustbeint"exit1}if[$num1-gt$num2];thenecho"$num1>$num2"elif[$num1-lt$num2];thenecho"$num1<$num2"elseecho"$num1=$num2"fifi4.if条件语句企业实例
1.生产监控mysql服务
1.监控mysql服务是否正常启动,如果未正常启动,就启动mysql服务。
通过端口来判断,mysql服务是不是在运行中。[root@yangjianboinbeijingday4]#catmonitor_mysql.sh#!/bin/bash#monitormysqlserverlsof-i:3306>/dev/null&&echo$>/dev/nullif[$-eq0];thenecho"mysqlserverisstarting!"elseecho`systemctlstartmysqld.service`>/dev/nullecho"mysqld.servicestartsuccessful!"fi或者使用netstat-lnt|grep3306|wc-lps-ef|grepmysqld注意:如果过滤进程数,不要让脚本带有mysql字样。涉及到数据库,脚本使用db字样。
如果没有启动,就启动,再对启动的结果进行判断,如果发现没有成功,就彻底杀死,再启动mysql。
2.监控mysql服务,通过连接mysql监控。
[root@yangjianboinbeijingday4]#catmonitor_mysql_pid_port.sh#!/bin/bash#monitormysqlservermysql-uroot-p123456-e"selectversion();">/dev/null&&echo$>/dev/nullif[$-eq0];thenecho"mysqlserverisstarting!"elseecho`systemctlstartmysqld.service`>/dev/nullecho"mysqld.servicestartsuccessful!"fi3.监控mysql服务,通过PHP/JAVA程序监控mysql。
2.监控apache和nginx服务
1.通过本地端口或进程监控。
#!/bin/bashNGX_NUM=`netstat-lntp|grepnginx|wc-l`if[$NGX_NUM-gt0];thenecho"nginxisstarting"else/etc/init.d/nginxstartecho"nginxisstartsucessful"fi2.通过远程URL监控。wget或者curl。
1.使用传参的方式(要判断传入的参数的个数和传入的是否是整数)
#!/bin/basha=$1b=$2if[$#-ne2];thenecho"USAGE:$0numberistwo"exit200fiexpr$a+1>/dev/nullRET_a=$expr$b+1>/dev/nullRET_b=$if[$RET_a-ne0-o$RET_b-ne0];thenecho"thenumbermustbeint"exit100fiif[$a-gt$b];thenecho"$a>$b"elif[$a-lt$b];thenecho"$a<$b"elseecho"$a=$b"fi2.使用read读取的方式
#!/bin/bashread-p"inserttotwonumber:"abexpr$a+0>/dev/nullRET_a=$expr$b+0>/dev/nullRET_b=$if[-z"$a"]||[-z"$b"];thenecho"thenumberistwo"exit200fiif[$RET_a-ne0-o$RET_b-ne0];thenecho"thenumbermustbeint"exit100fiif[$a-gt$b];thenecho"$a>$b"elif[$a-lt$b];thenecho"$a<$b"elseecho"$a=$b"fi20.shell函数1.函数的定义
function函数名(){指令returnn}2.函数的调用
1.不带参数
函数名
2.带参数
函数名参数1参数2
3.函数的使用说明
1.执行函数时,不需要function和函数后的小括号
2.函数的定义必须在执行的程序前面定义或加载
3.shell执行系统中各种程序的执行顺序为:系统别名-函数-系统命令-可执行文件
4.函数执行时,会调用环境变量,还有自己定义的局部变量以及特殊位置参数
5.在shell函数,return的功能与exit类似,return的作用是退出函数,而exit是退出脚本文件
6.如果函数在一个单独的文件中,被脚本加载时,需要使用source或者.来加载(一个点)
4.范例
1.基本
[root@mysql-37scripts]#cathanshu.sh#!/bin/basholdboyoldboy(){echo"Iamyangjianbo!"}functionoldgirl(){echo"Iamqiwei!"}oldboyoldgirl2.分离函数体和执行函数
1.函数体
[root@mysql-37scripts]#cathanshu_fenli.sh#!/bin/bash#createdbyyangjianboat2019-09-17functionyangjianbo(){echo"Iamliudehua!"}只是定义了函数,但是没有执行函数
2.执行函数的脚本
[root@mysql-37scripts]#cathanshu_diaoyong.sh#!/bin/bash[-f/server/scripts/hanshu_fenli.sh]&&source/server/scripts/hanshu_fenli.sh||exit1yangjianbo注意函数体的脚本,要使用source或者.执行,否则提示找不到函数yangjianbo.
3.带参数[root@mysql-37scripts]#cathanshu_fenli.sh
#!/bin/bash#createdbyyangjianboat2019-09-17functionyangjianbo(){echo"Iamliudehua!$1"}[root@mysql-37scripts]#cathanshu_diaoyong.sh#!/bin/bash[-f/server/scripts/hanshu_fenli.sh]&&source/server/scripts/hanshu_fenli.sh||exit23yangjianbo$14.检查网站url
采用传入参数的方式
#!/bin/bash./etc/init.d/functionsfunctionusage(){echo"USAGE$0:onlyone"exit1}functioncheck_url(){wget--spider-q-o/dev/null--tries=1-T5$1if[$-eq0];thenaction"thewebserverisOK"/bin/trueelseaction"thewebserverisnotOK"/bin/falsefi}functionmain(){if[$#-ne1];thenusageficheck_url$1}main$*执行脚本:/bin/bashtest.shwww.baidu.com5.简单例子:
[root@yangjianboinbeijingday5]#catscript1.sh#!/bin/bash#Soursefunctionlibrary../etc/init.d/functionsif["$1"=="start"]thenaction"nginxstarting."/bin/trueelif["$1"=="stop"]thenaction"nginxisstopped."/bin/trueelseaction"nginxisstart"/bin/falsefi[root@yangjianboinbeijingday5]#shscript1.shnginxisstart[失败][root@yangjianboinbeijingday5]#shscript1.shstartnginxstarting.[确定][root@yangjianboinbeijingday5]#shscript1.shstopnginxisstopped.[确定]6.利用shell函数开发一键优化系统脚本
1.针对centos6的一键优化
1.服务启动脚本
#!/bin/bashif[$#-ne1];thenecho$"usage:$0{start|stop|restart}"exit1fiif["$1"=="start"];thenrsync--daemonsleep2if[`netstat-lntp|greprsync|wc-l`-ge1];thenecho"rsyncdisstarted."exit0fielif["$1"=="stop"];thenkillallrsync&>/dev/nullsleep2if[`netstat-lntp|greprsync|wc-l`-eq0];thenecho"rsyncdisstopped."exit0fielif["$1"=="restart"];thenkillallrsyncsleep1killpro=`netstat-lntp|greprsync|wc-l`rsync--daemonsleep1startpro=`netstat-lntp|greprsync|wc-l`if[$killpro-eq0-a$startpro-ge1];thenecho"rsyncdisrestarted."exit0fielseecho$"usage:$0{start|stop|restart}"exit1fi2.改造为函数
#!/bin/bashfunctioncheck_canshu(){echo$"usage:$0{start|stop|restart}"exit1}functionstart(){rsync--daemonsleep2if[`netstat-lntp|greprsync|wc-l`-ge1];thenecho"rsyncdisstarted."exit0fi}functionstop(){killallrsync&>/dev/nullsleep2if[`netstat-lntp|greprsync|wc-l`-eq0];thenecho"rsyncdisstopped."exit0fi}functionrestart(){killallrsyncsleep1killpro=`netstat-lntp|greprsync|wc-l`rsync--daemonsleep1startpro=`netstat-lntp|greprsync|wc-l`if[$killpro-eq0-a$startpro-ge1];thenecho"rsyncdisrestarted."exit0fi}functionmain(){if[$#-ne1];thencheck_canshufiif["$1"=="start"];thenstartelif["$1"=="stop"];thenstopelif["$1"=="restart"];thenrestartelsecheck_canshufi}main21.case条件语句的应用实践1.语法
case"条件"in
值1)执行1
;;
值2)执行2
*)执行3
esac
1.根据用户的输入判断用户输入的是哪个数字
#!/bin/bashread-p"inputyournumber:"numbercase"$number"in1)echo"youinputthenumberis1";;2)echo"youinputthenumberis2";;[3-9])echo"youinputthenumberis$number";;*)echo$"usage:$0youinput1-9number"esac2.往某个文件添加用户
#!/bin/bash./etc/init.d/functionsFILE_PATH=/etc/openvpn_authfile.conf[!-f$FILE_PATH]&&touch$FILE_PATHusage(){cat<
while<条件表达式>do指令done2.while循环执行流程的逻辑图
3.until循环的语法
until<条件表达式>do指令done4.当型和直到型循环的基本范例
1.持续查看uptime
#!/bin/bashwhiletruedouptimesleep2done5.shell脚本后台运行
2.例子
开启两个脚本,都放到后台执行
/bin/bashwhile.sh&
/bin/bashwhile2.sh&
通过jobs命令,查看当前任务的编号
想把其中一个放到前台执行,fg1
如果想把1又放到后台执行,先ctrl+z暂停,然后执行bg1,就放到后台执行了。
想杀掉一个任务,kill%1
6.while和until的例子
1.打印出54321
#!/bin/bashi=5while[$i-gt0]doecho$i>>/tmp/1.txt((i--))done#!/bin/bashi=5until[$i-lt1]doecho$i>>/tmp/2.txt((i--))done2.计算从1加到100之和
#!/bin/bashi=1sum=0while[$i-le100]do((sum=$sum+$i))((i++))doneecho$sum7.企业实战
1.使用while守护进程的方式监控网站,每隔10秒确定一次网站是否正常
#!/bin/bashsum=0exec<$1whilereadlinedosize=`echo$line|awk'{print$10}'`expr$size+1&>/dev/nullif[$-ne0];thencontinuefi((sum=sum+$size))doneecho"$1:total:${sum}bytes=`echo$((${sum}/1024))`KB"其它方法
awk'{print$10}'/usr/local/nginx/logs/test.zhenpin.com.log|awk'{sum+=$1}END{printsum}'4.分析nginx的访问日志,每一个小时一次,并且把访问的web的ip的PV次数超过500的,通过iptables禁止掉。
#!/bin/bashfile=$1whiletruedoawk'{print$1}'access.log|sort|uniq-c>/tmp/ip.txtexec>/tmp/iptables_drop.txtfidonesleep3600done5.分析系统的网络连接数
#!/bin/bashwhiletruedonetstat-ntp|awk-F'[:]+''{print$(NF-4)}'|sort|uniq-c>/tmp/ip.txtwhilereadlinedoip=`echo$line|awk'{print$2}'`count=`echo$line|awk'{print$1}'`if[$count-gt500]&&[`iptables-L-n|grep"$ip"|wc-l`-lt1];theniptables-IINPUT-s$ip-jDROPecho"$lineisdropped">>/tmp/iptables_drop.txtfidonesleep3600done8.while循环按行读文件的方式
1.使用exec方式
exec cata.txt|whilereadlinedocmddone3.结尾使用<输入重定向 whilereadlinedocmddone 1.语法:for变量in<变量取值列表> do 循环体 done 第二种语法: for((exp1;exp2;exp3)) 例子: for((i=1;i<=3;i++)) echo$i 2.for循环执行过程 2.for循环语句的基础实践 1.取值列表为普通数字或字符串 #!/bin/bashforiin12345doecho$idone2.取值列表为{}大括号的数字序列 #!/bin/bashforiin{5..10}doecho$idone3.取值列表为某个命令的输出结果 #!/bin/bashforiin`seq10100`doecho$idone #!/bin/bashforiin$(seq510)doecho$idone4.列出某个目录下的所有文件和目录 #!/bin/bashforiin`ls`doecho$idone5.批量修改文件名称 #!/bin/bashforfilein`find/data/vendor/653/-typef`donewfile=`echo$file|sed's/%//g'`mv$file$newfiledone #!/bin/bashforiin`ls`dorename".txt"".gif"$idone6.九九乘法表 #!/bin/bashCOLOR='\E[47;30m'RES='\E[0m'fornum1in`seq9`dofornum2in`seq9`doif[$num1-ge$num2];thenif(((num1*num2)>9));thenecho-ne"${COLOR}$num1*$num2=$((num1*num2))$RES"后面跟了一个空格elseecho-ne"${COLOR}$num1*$num2=$((num1*num2))$RES"后面跟了两个空格fifidoneecho""使用echo是为了换行done7.计算从1加到100的和 #!/bin/bashfor((i=1;i<=100;i++))do((sum=sum+i))doneecho$sum8.每5秒访问一次百度 1.mysql分库备份脚本 #!/bin/bashUSER=rootPASSWD="123.com"BACK_PATH=/server/backupMYSQL_CMD="mysql-u$USER-p$PASSWD"MYSQL_DUMP="mysqldump-u$USER-p$PASSWD-B"[!-d$BACK_PATH]&&mkdir-p$BACK_PATHfordbnamein`$MYSQL_CMD-e"showdatabases"|grep-Ev"mysql|performance_schema|information_schema|password|Database|sys"`do`$MYSQL_DUMP${dbname}|gzip>$BACK_PATH/${dbname}_$(date+%F).sql.gz`done2.mysql分库分表备份脚本 4.批量创建10个账号,密码随机 #!/bin/bash#createdbyyangjianborm-rf/tmp/password.logfornumin`seq-w10`douseraddoldboy_user${num}password=`echo$RANDOM|md5sum|cut-c1-8`echo${password}|passwd--stdinoldboy_user${num}echo-e"username:oldboy_user${num}\tpassword:${password}">>/tmp/password.logdone4.linux系统产生随机数的6种方法 1.通过系统环境变量($RANDOM) RANDOM的随机数范围为0~32767,加密性不是很好,可以使用md5sum并截取结果的后n位 [root@192scripts]#echo$RANDOM|md5sum|cut-c1-8af861e2e 2.通过openssl产生随机数 [root@192scripts]#opensslrand-base6460|md5sum|cut-c2-972d02d47 3.通过date获得随机数 [root@192scripts]#date+%s$N1637826212 4.通过/dev/urandom配合chksum生成随机数 [root@192~]#head/dev/urandom|cksum 34835419542747 5.通过UUID生成随机数 [root@192~]#cat/proc/sys/kernel/random/uuidcfd1f306-4a1e-4770-9383-963e18851062 6.通过expect附带的mkpasswd生成随机数 yuminstallexpect-y 7.以上所有命令需要结合md5sum使用 5.select循环语句 1.语法 select变量名in[菜单取值列表] 2.案例 1.打印菜单 #!/bin/bashselectnameinyangjianboluoyinyichangkundoecho$namedone2.使用数组做变量列表 #!/bin/basharray=(liudehuazhangxueyoulimingguofucheng)selectnamein"${array[@]}"doecho$namedone3.调整select的默认提示符 #!/bin/basharray=(liudehuazhangxueyoulimingguofucheng)PS3="pleaseselectanumfrommenu:"selectnamein"${array[@]}"doecho$namedone24.循环控制及状态返回值的应用实践1.break,continue,exit,return的区别和对比 2.break,continue,exit功能执行流程图 1.break执行流程图 2.continue执行流程图 3.exit的执行流程图 3.break,continue,exit,return的基础案例 #!/bin/bashif[$#-ne1];thenecho"usage:break|continue|exit|return"fifunctiontest(){for((i=0;i<5;i++))doif[$i-eq3];then$*;fiecho$idoneecho"Iaminfunc"}test$*func_test=$if[`echo$*|grepreturn|wc-l`-eq1];thenecho"functionisexitstatus:$func_test"fiecho"ok"1.传入的参数为break,当for循环条件成立,那么直接跳出了for循环 [root@192scripts]#/bin/bashtest_break.shbreak012Iaminfuncok2.传入的参数为continue,当for循环成立,跳出了本次循环,进入了下一次循环 [root@192scripts]#/bin/bashtest_break.shcontinue0124Iaminfuncok3.传入的参数为exit,当for循环成立,直接退出了脚本,后面的代码就没有执行 [root@192scripts]#/bin/bashtest_break.shexit0124.传入的参数为return,当for循环成立,退出了函数,后面的代码仍然执行了。 [root@192scripts]#/bin/bashtest_break.shreturn012functionisexitstatus:0ok4.企业案例 1.服务器上添加或删除网卡的ip地址 2.把日志中每行的访问字节数所对应的字段数字相加,计算出总的访问量。 #!/bin/bashsum=0exec<$1whilereadlinedosize=`echo$line|awk'{print$10}'`expr$size+1&>/dev/nullif[$-ne0];thencontinuefi((sum=sum+$size))doneecho"$1:total:${sum}bytes=`echo$((${sum}/1024))`KB"3.提供了一个字符串(RANDOM随机数采用md5sum加密后取出连续10位的结果),请破解字符串对应的md5sum前的数字。 foriin{0..32767};doecho`echo$i|md5sum`,$i>>/tmp/1.txt;done#!/bin/bashmd5char="4fe8bf20ed"whilereadlinedoif[`echo$line|grep"$md5char"|wc-l`-eq1];thenecho$linebreakfidone shell数组就是一个元素集合 2.数组的定义与增删改查 1.定义 语法:array=(value1value2value3...) 2.定义变量的方式 1.小括号直接赋值 [root@192scripts]#a=(123)[root@192scripts]#echo${a[*]}1232.小括号内采用键值对 [root@192scripts]#a=([15]=1[13]=2[14]=3)[root@192scripts]#echo${a[*]}2313.分别定义数组变量 [root@192scripts]#a[0]=yangjianbo;a[1]=luoying;a[2]=yichangkun[root@192scripts]#echo${a[*]}yangjianboluoyingyichangkun4.动态定义数组变量 [root@192scripts]#echo${a[*]}1.gif2.gif3.gifcase.shcheck_ip.shcheck_netstat.shcheck_url.shindex.htmlls_test.shmemeory_free.shopenvpn_user.shrsyndrsynd-funcationsolrslow.shtest_break.shtest_centos7.shtest_random.shtest_select.shtest.shtest_url.shuntil.shwhile2.shwhile.sh3.打印数组元素 echo${a[0]}默认下标从0开始的 echo${a[*]}打印出所有的元素 4.打印数组元素的个数 echo${#a[*]} echo${#a[@]} 5.数组赋值 [root@192scripts]#a[0]=liudehua[root@192scripts]#echo${a[0]}liudehua6.数组删除 [root@192scripts]#unseta[0]删除某个元素[root@192scripts]#unseta删除整个变量7.数组内容的截取和替换 1.内容截取 [root@192~]#echo${a[*]}abcdefghijklmnopqrstuvwxyz[root@192~]#echo${a[*]:1:4}第一个冒号后面的数字表示从下标为1开始,第二个冒号后面的数字表示截取的长度bcde2.内容替换 [root@192~]#echo${a[*]/one/1}1twothreefourfivesixseveneightnineten3.shell数组开发实践 1.通过C语言型的for循环语句打印数组元素 #!/bin/basha=(onetwothreefourfive)for((i=0;i<${#a[*]};i++))doecho${a[i]}done使用普通的for循环 #!/bin/basha=(onetwothreefourfive)foriin${a[*]}doecho$idone2.通过while循环语句打印数组元素 #!/bin/basha=(onetwothreefourfive)i=0while((i<${#a[*]}));doecho${a[i]}((i++))done3.将命令结果作为数组元素定义并打印 #!/bin/basha=($(ls/root))foriin${a[*]};doecho$idone4.高级实战案例 1.利用bashfor循环打印下面这句话中字母数不大于6的单词 Iamoldboyteacherwelcometooldboytrainingclass 1.通过数组实现 #!/bin/basha=(Iamoldboyteacherwelcometooldboytrainingclass)for((i=0;i<${#a[*]};i++))doif[${#a[i]}-le6];thenecho${a[i]}fidone2.通过for循环实现 #!/bin/basha="Iamoldboyteacherwelcometooldboytrainingclass"foriin$a;doif[${#i}-le6];thenecho$ifidone3.通过awk实现 [root@192scripts]#a="Iamoldboyteacherwelcometooldboytrainingclass"[root@192scripts]#echo$a|awk'{for(i=1;i<=NF;i++)if(length($i)<=6)print$i}'2.批量检查多个网站地址是否正常 #!/bin/shUSER=rootPASSWORD=123456PORT=3307error=(11581159100810071062)MYSQLCMD="mysql-u$USER-p$PASSWORD-S/data/$PORT/mysql.sock"is_run(){[`lsof-i:$PORT|wc-l`-lt2]&&{echo"mysqlserverisstopped"exit1}}status_array(){status=($($MYSQLCMD-e"showslavestatus\G"|egrep"_Running|Last_Errno|Behind_Master"|awk'{print$NF}'))}status_error(){for((i=0;i<${#error[*]};i++))doif["$1"=="${error[$i]}"]then$MYSQLCMD-e"stopslave;setglobalsql_slave_skip_counter=1;startslave;"elseecho"MySQLslaveisfailed,errornois$1"fidone}judge_slave(){status_arrayif["${status[0]}"=="Yes"-a"${status[1]}"=="Yes"-a"${status[3]}"="0"]thenecho"MySQLslaveisok"elsestatus_error${status[2]}fi}main(){whiletruedois_runjudge_slavesleep60done}main26.shell脚本开发规范1.脚本基本规范 1.第一行指定脚本解释器。/bin/bash 2.从第二行开始添加日期,作者,功能介绍,版本号 3.脚本命名以sh结尾 4.成对出现的符号,一次性写完 5.流程控制语句一次性写完 6.代码缩进让代码易读 7.字符串赋值给变量要加双引号 2.shell变量命名及引用变量规范 1.全局变量 必须大写 2.局部变量 驼峰语法 首字母大写 3.变量的引用规范 使用大括号引用变量${变量名} 变量内容为字符串时,加双引号"${变量名}" 变量内容为整数时,直接使用$变量名来引用 3.shell函数的命名及函数定义规范 1.函数名首字母大写 4.shell脚本高级命名规范 1.常规shell使用.sh后缀 2.模块的启动或停止start_模块名.shstop_模块名.sh 3.监控脚本*_mon.sh 4.控制脚本*_ctl.sh 1.常见脚本错误范例 1.if条件语句缺少结尾关键字 2.循环语句缺少关键字 3.成对符号落了单 4.中括号两端没空格 2.shell脚本调试技巧 1.使用dos2unix命令处理在windows下开发的脚本 dos2unixwhile.sh yuminstalldos2unix-y 2.使用echo命令调试 3.使用bash命令参数调试 -n不会执行脚本,只会检查语法 -v先将脚本的内容输出到屏幕上,然后执行脚本,如果有错误,也会给出错误提示 -x将执行的脚本内容及输出显示到屏幕上,常用的参数 1.配置文件.vimrc的重要参数 1.安装Expect软件 2.Expect程序自动交互的重要命令及实践 1.spawn命令 语法:spawn[选项][需要自动交互的命令或程序] spawnsshroot@192.168.10.200uptime 2.expect命令 获取spawn命令执行后的信息,看是否匹配,匹配就执行expect后面的动作 语法:expect表达式[动作] expect"*password"{send"123456\r"} expecteof 或者expect与send放在不同行 expect"*password" send"123456\r" 多次匹配不同的字符串 expect{ "yes/no"{exp_send"yes\r";exp_continue} "*password"{exp_send"123456\r"} } 3.send命令 \r表示回车 \n表示换行 \t表示制表符 4.exp_continue命令 表示继续匹配 5.常用命令总结 3.expect程序变量 1.普通变量 语法:set变量名变量值 setpassword"123456" 打印变量 puts$变量名 2.特殊参数变量 1.位置参数 语法:[lindex$argvn] #!/usr/bin/expect#definevarsetfile[lindex$argv0]sethost[lindex$argv1]setdir[lindex$argv2]send_user"$file\t$host\t$dir\n"puts"$file\t$host\t$dir\n"结果: [root@192scripts]#expectteshu.expyangjianbo.log192.168.1.130/tmpyangjianbo.log192.168.1.130/tmpyangjianbo.log192.168.1.130/tmp2.传参的个数和脚本名参数 #!/usr/bin/expect#definevarsetfile[lindex$argv0]sethost[lindex$argv1]setdir[lindex$argv2]send_user"$file\t$host\t$dir\n"puts"$file\t$host\t$dir\n"puts"$argc\n"传参个数$argcputs"$argv0\n"传参脚本名$argv0,没有空格的4.expect的if条件语句 if{条件表达式}{指令}if{条件表达式}{指令}else{#固定格式,不能修改指令}2.例子 1.判断传参个数 #!/usr/bin/expectif{$argc!=3}{send_user"usage:expect$argv0filehostdir\n"exit}#definevarsetfile[lindex$argv0]sethost[lindex$argv1]setdir[lindex$argv2]send_user"$file\t$host\t$dir\n"puts"$file\t$host\t$dir\n"puts"$argc\n"puts"$argv0\n"2.判断传参个数,不管是否符合都给予提示 #!/usr/bin/expectif{$argc!=3}{send_user"usage:expect$argv0filehostdir\n"exit}else{puts"good."}#definevarsetfile[lindex$argv0]sethost[lindex$argv1]setdir[lindex$argv2]send_user"$file\t$host\t$dir\n"puts"$file\t$host\t$dir\n"puts"$argc\n"puts"$argv0\n"5.expect中的关键字 1.eof 用于匹配结束符 2.timeout 6.生产场景下的实例 1.批量执行命令 #!/usr/bin/expectif{$argc!=2}{send_user"usage:expect$argv0ipcmd\n"exit}#definevarsetip[lindex$argv0]setcmd[lindex$argv1]setpassword"**********"spawnssh-p11984zhangshaohua1510@$ip$cmdexpect{"yes/no"{send"yes\r";exp_continue}"*password"{send"$password\r"}}expecteof再加一个shell脚本,for循环,用来遍历多个机器ip #!/usr/bin/expectif{$argc!=3}{puts"usage:expect$argv0filehostdir"exit}#definevarsetfile[lindex$argv0]sethost[lindex$argv1]setdir[lindex$argv2]setpassword"***************"spawnscp-P11984-rp$filezhangshaohua1510@$host:$direxpect{"yes/no"{send"yes\r";exp_continue}"*password"{send"$password\r"}}expecteof再加一个脚本,执行for循环,遍历多台机器 #!/usr/bin/expectif{$argc!=2}{send_user"usage:expect$argv0filehost\n"exit}#definevarsetfile[lindex$argv0]sethost[lindex$argv1]setpassword"huazai007@zhenpin.com"spawnssh-copy-id-i$file"-p11984zhangshaohua1510@$host"expect{"yes/no"{send"yes\r";exp_continue}"*password"{send"$password\r"}}expecteof加一个for循环脚本,遍历多个机器 #!/bin/bashforiin191192193194doexpect/server/scripts/ssh-copy.exp~/.ssh/id_rsa.pub192.168.2.$idone