四、Shell脚本
[TOC]
编写自定义脚本的时候,能够在用户的家目录下的创立一个 bin 目录,而后将自定义脚本文件退出到刚创立的 bin目录中,而后咱们就能够间接在以后用户下执行脚本文件了,因为在用户的家目录下的 用户环境变量文件(.bash_profile) 中曾经执行 $HOME/bin 了。所以能够间接应用!
2.shell根本运算
因为原生的bash是不反对数学运算的,所以能够应用
expr
看来实现数学运算,应用根本形式:应用反引号将expr表达式包裹起来;==留神==:条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是谬误的,必须写成 [
$a == $b ]。
vi a.sh#!/bin/bash# 定义一个变量名叫 val,要计算的两个字符之间要有空格进行分隔val=`expr 2 + 2`# 调用自定义变量进行输入的时候应用 $ 符号echo "两数字之和: $val"
(1).算数运算符
运算符 | 阐明 | 举例 |
---|---|---|
+ | 加法 | expr $a + $b 后果为 30。 |
- | 减法 | expr $a - $b 后果为 -10。 |
* | 乘法 | expr $a \* $b 后果为 200。 |
/ | 除法 | expr $b / $a 后果为 2。 |
% | 取余 | expr $b % $a 后果为 0。 |
= | 赋值 | a=$b 将把变量 b 的值赋给 a。 |
== | 相等。用于比拟两个数字,雷同则返回 true。 | [ $a == $b ] 返回 false。 |
!= | 不相等。用于比拟两个数字,不雷同则返回 true。 | [ $a != $b ] 返回 true。 |
(2).关系运算符
运算符 | 阐明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测右边的数是否大于左边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测右边的数是否小于左边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测右边的数是否大于等于左边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测右边的数是否小于等于左边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
(3).布尔运算符
运算符 | 阐明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o \$b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a \$b -gt 100 ] 返回 false。 |
(4).逻辑运算符
运算符 | 阐明 | 举例 | ||||
---|---|---|---|---|---|---|
&& | 逻辑的 AND | [[ $Misplaced &a -lt 100 && $b -gt 100 ]] 返回 false | ||||
\ | \ | 逻辑的 OR | [[ $a -lt 100 \ | \ | $b -gt 100 ]] 返回 true |
(5).字符串运算符
运算符 | 阐明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否不为 0,不为 0 返回 true。 | [ -n "$a" ] 返回 true。 |
$ | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
3.shell流程管制
(1),if/then/elif/else/fi 构造
# 编写脚本$ vi equals.sh# 指定脚本解析器的类型是bash#!/bin/basha=10b=20if [ $a != $b ]then echo "$a != $b : a不等于b"else echo "$a == $b : a等于b"fi# 2,编写实现脚本之后,须要对脚本文件赋予可执行的权限$ chmod 755 equals.sh# 3,执行脚本$ sh equals.sh
(2).case/esac 构造
# 1,编写脚本内容$ vi case.sh #!/bin/bash# 打印提示信息echo "当初是早上吗?请输出你的抉择:"# 示意须要用户输出一个变量read yes_or_no# 依据用户输出的变量,进行case的判断,而后in之后的每个选项指定命令最初都应用 ;; 示意完结case "$yes_or_no" inyes|y|Yes|YES) # 示意输出以以下选项的 echo "Good Morning!";;[nN]*) # 示意你输出以n结尾的都能够提醒你下午好 echo "Good Afternoon!";;*) # 输出其余字符的时候,提醒输出有误 echo "对不起,输出有误!" exit 1;;# case语句的完结esacexit 0# 2,编写实现脚本之后,须要对脚本文件赋予可执行的权限$ chmod 755 case.sh# 3,执行脚本$ sh case.sh
(3).for/do/done 构造
1).案例需要
请应用for循环在指定目录下"/root/test"目录下创立是个文件。
test-1.shtest-2.shtest-3.shtest-4.shtest-5.shtest-6.shtest-7.shtest-8.shtest-9.shtest-10.sh
2),shell脚本
#!/bin/sh# 先判断以后指定的文件夹是否存在if [ ! -d /root/forTest ] then mkdir -p /root/forTestfi# 循环1-10之间的所有数for num in {1..10} # 在循环内执行以下命令 do touch /root/forTest/test-${num}.sh #因为创立文件到指定目录,所以创立时最好用全门路; done
(4),while/do/done 构造
1),案例需要
需要1:验证用户输出的明码,直到用户输出正确为止;
需要2:验证用户输出的明码,用户输十次还是不正确则退出;
2),shell脚本
shell脚本1
#!/bin/bashecho "请输出明码:"# 获取用户输出的字符read trywhile [ "$try" != "111111" ];do echo "输出谬误,请从新输出:" read trydone
shell脚本2
#!/bin/bashecho "请输出明码:"read try# 定义计数器,控制变量counter=1# 此时的 "-a" 示意 "and","-lt" 示意 "小于"while [ "$try" != "111111" -a "$counter" -lt 3 ];do echo "输出谬误,请从新输出:" # 其中 $(()) 中的Shell变量取值将转换成整数,另外 $[] 示意同样的含意 counter=$(($counter+1)) # 在循环中再次读入用户输出的变量 read trydone# 当循环完结之后,弹出提示信息echo "3次机会用尽!!"
(5).break 与 continue
break跳出,continue跳过。
break[n]能够指定跳出几层循环,continue跳过本次循环步,没跳出整个循环。
(6),Shell中对字符串的解决
1),字符串的截取
格局 | 阐明 |
---|---|
${string: start :length} | 从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。 |
${string: start} | 从 string 字符串的右边第 start 个字符开始截取,直到最初。 |
${string: 0-start :length} | 从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。 |
${string: 0-start} | 从 string 字符串的左边第 start 个字符开始截取,直到最初。 |
${string#*chars} | 从 string 字符串第一次呈现 chars 的地位开始,截取 chars 左边的所有字符。 |
${string##*chars} | 从 string 字符串最初一次呈现 chars 的地位开始,截取 chars 左边的所有字符。 |
${string%*chars} | 从 string 字符串第一次呈现 chars 的地位开始,截取 chars 右边的所有字符。 |
${string%%*chars} | 从 string 字符串最初一次呈现 chars 的地位开始,截取 chars 右边的所有字符。 |
2),获取字符串长度等操作
示例代码 与 执行后果
str="http://www.fengbohello.xin3e.com/blog/shell-truncating-string"echo "string : [${str}]"length=${#str}echo "length : [${length}]"## 执行后果string : [http://www.fengbohello.xin3e.com/blog/shell-truncating-string]length : [61]
4.shell参数 和 非凡变量
$0 就是你写的shell脚本自身的名字,$1 是你给你写的shell脚本传的第一个参数,$2 是你给你写的shell脚本传的第二个参数.
其余罕用非凡变量
$# # 相当于C语言main函数的argc - 1,留神这里的#前面不示意正文$@ # 示意参数列表"$1" "$2" ...,例如能够用在for循环中的in前面。$* # 示意参数列表"$1" "$2" ...,同上$? # 上一条命令的Exit Status$$ # 以后过程号
# 编写脚本文件$ vi special.sh#!/bin/bashecho "shell脚本自身的名字: $0"echo "传给shell脚本的第一个参数: $1"echo "传给shell脚本的第二个参数: $2"# 赋予权限、执行脚本$ chmod 755 special.sh$ sh special.sh xxx01 xxx02
5.shell的文件蕴含
. filename # 留神点号(.)和文件名两头有一空格或者source filename
6.脚本的执行
一个标准的Shell脚本在第一行会指出由哪个程序(解释器)来执行脚本中的内容,这一行内容在Linux bash的编程个别为:
\#!/bin/bash
或者
\#!/bin/sh
留神:
(1)在Shell中如果一行的第一个字母是#,则是正文,然而下面两个是写在第一行,所以不是脚本正文行,如果写在某个命令之后,则变成正文行。
(2)sh为bash的软链接,大多数状况下,脚本的结尾应用“#!/bin/bash”和“#!/bin/sh”是没有区别的,但更标准的写法是在脚本的结尾应用“#!/bin/bash”。
(1),应用"./脚本"的形式运行
# 进入脚本所在的工作目录,应用 ./脚本形式执行./test.sh
(2),"sh 脚本"执行
# 应用脚本对应的sh或者bash来接着脚本执行sh test.shbash test.sh
(3),shell环境运行
# 在以后shell环境中执行,能够应用 ". 脚本" 或者 "source 脚本". test.shsource test.sh
7.定时工作(清理日志)
1.应用命令:cat /etc/crontab查看定时工作的工夫格局,2.应用命令:vi /etc/crontab编辑你的定时工作,3.应用命令:service crond status查看以后定时工作是否启动.4.应用命令:service crond start 来启动crond工作.
# 常见的定时工作# 0 0 * * * sh /root/bin/demo02.sh每分钟执行 */1 * * * * command每小时0分执行 0 * * * * command每天0点执行 0 0 * * * command每周日0点执行 0 0 * * 0 command每月1号执行 0 0 1 * * command每年1月1日执行 0 0 1 1 * command
(1),定时清理日志
1),找到对应的日志目录
## find 对应目录 -mtime +天数 -name "文件名" -exec rm -rf {} \;find /home/apache-tomcat-7.0.55-13-990*/webapps/ProxyServer2.0/WEB-INF/logs/ -mtime +10 -name "*.log.*" -exec rm -rf {} \;find /app/datacheck/logs/ -mtime +10 -name "*.log.*"## 阐明:find:Linux查找命令,用户查找指定条件的文件/home/apache-tomcat-7.0.55-13-990*/webapps/HollyProxyServer2.0/WEB-INF/logs/:须要进行清理的目标目录-mtime:规范语句写法+10 :数字代表天数-name "*.log.*":指标文件的类型,带有log的所有文件-exec:固定写法rm -rf:强制删除包含目录在内的文件{} \;:固定写法,一对大括号+空格+\+;
2),设置定时工作
创立shell脚本
touch /home/apache-tomcat-7.0.55-13-990*/webapps/ProxyServer2.0/WEB-INF/bin/auto-del-log.sh chmod u+x auto-del-log.shvi auto-del-log.sh#!/bin/shfind /home/apache-tomcat-7.0.55-13-990*/webapps/ProxyServer2.0/WEB-INF/logs/ -mtime +10 -name "*.log.*" -exec rm -rf {} \;
编辑定时工作
# 进入定时工作编辑页面,按i底部呈现INSERT,开始进行工作脚本编辑,将auto-del-log.sh执行脚本退出到零碎打算工作,到点主动执行:crontab e # 追加如下内容30 0 * * * /home/apache-tomcat-7.0.55-13-990*/webapps/ProxyServer2.0/WEB-INF/logs/ auto-del-log.sh设置每天凌晨0:30执行auto-del-log.sh文件进行数据清理工作。编辑实现按Ctrl+c,输出:quit,之后再输出:w!实现保留,ctrl+c,:quit退出。
### (2),依据文件大小清理日志
1),编辑文件
vi xxx.sh## 追加以下内容,判断/app/datacheck/logs/dev.log文件的大小#!/bin/bashif [ `/bin/ls -lt /app/datacheck/logs/dev.log | head -1 | /bin/awk '{print $5}'` -gt $((1024*1024*10)) ]then echo > /app/datacheck/logs/dev.logfi
2),编辑定时工作
crontab -e## 追加以下内容: 每个六个小时执行一次0 */6 * * * sh /root/bin/clean_log.sh
(3),将大的日志文件进行拆分
#!/bin/bash current_date=`date -d "-1 day" "+%Y%m%d"` split -b 65535000 -d -a 4 /home/alvin/nohup.out /home/alvin/log/log_${current_date}_ cat /dev/null > nohup.out# 1,先获取以后工夫的前一天date -d "-1 day"示意获取前一天的日期,就是说咱们明天操作的话是切割昨天的日志。+%Y%m%d是具体的日期格局,也就是年月日格局,比方:20181005。# 2,而后对日志文件进行切分其中,65535000是60M,也就是日志文件按60M大小进行切割,可自定义大小。-d -a 4示意文件后缀是4位。咱们将文件切割后要按秩序进行编号,比方0000,0001,0002……这个4就代表编号的位数。# 3,将依据指定大小拆分之后的日志输入的文件中再之后的./log/log${current_date}就是切割后日志文件的前缀,外面就带入了以后日期。所以,最终的输入格局相似于:log_20181005_0001。# 4,最初将原始文件中内容置空
8,循环开启端口
#!/bin/shCount=0;cat ./xxx | while read linedo Count=`expr $Count + 1`; echo "Test($Count),$line..."; firewall-cmd --add-port="${line}"/tcp --permanent; sleep 0.1;done;echo "从新加载规定:"firewall-cmd --reload;echo "以后已开启的端口有:"firewall-cmd --list-port;
9,合并清理日志文件脚本
- 生成测试文件脚本
#!/bin/sh# 循环生成文件,因为创立文件到指定目录,所以创立时最好用全门路;for num in {1..99} # 在循环内执行以下命令 do touch /root/aaa/test-${num}.sh done
- 理论合并清理日志文件脚本
1,工夫格式化
- -d "day ago" 获取前一天; 不加的话就间接取当天
2,判断文件夹是否存在
3,挪动文件的时候,防止出现,挪动文件过多,导致报错(mv argument list too long谬误)
#!/bin/sh# 获取前一天的时候生成TODAY_DATE=`date -d "day ago" +"%Y%m%d"`;if [ -d /root/aaa/dir-1 ] then mkdir -p /root/aaa/dir-1/bak-${TODAY_DATE};find /root/aaa/dir-1 -type f -name '*.sh' -not -path "/root/aaa/dir-1/bak-${TODAY_DATE}*" -exec mv {} /root/aaa/dir-1/bak-${TODAY_DATE} \;fiif [ -d /root/aaa/dir-2 ] then mkdir -p /root/aaa/dir-2/bak-${TODAY_DATE};find /root/aaa/dir-2 -type f -name '*.sh' -not -path "/root/aaa/dir-2/bak-${TODAY_DATE}*" -exec mv {} /root/aaa/dir-2/bak-${TODAY_DATE} \;fiif [ -d /root/aaa/dir-3 ] then mkdir -p /root/aaa/dir-3/bak-${TODAY_DATE};find /root/aaa/dir-3 -type f -name '*.sh' -not -path "/root/aaa/dir-3/bak-${TODAY_DATE}*" -exec mv {} /root/aaa/dir-3/bak-${TODAY_DATE} \;fi# 定时工作: 每天0点之执行 crontab -e# 0 0 * * * sh /root/bin/demo02.sh
- 补充脚本阐明
#!/bin/sh# 获取以后工夫TODAY_DATE=`date +"%Y%m%d"`;if [ -d /home/zazt/yuanxun/ATOSLog ] then mkdir -p /home/zazt/yuanxun/ATOSLog/bak-${TODAY_DATE};find /home/zazt/yuanxun/ATOSLog -maxdepth 1 -type f -name '*.json' -not -path "/home/zazt/yuanxun/ATOSLog/bak-${TODAY_DATE}*" -exec mv {} /home/zazt/yuanxun/ATOSLog/bak-${TODAY_DATE} \;fiif [ -d /home/zazt/yuanxun20002/ATOSLog ] then mkdir -p /home/zazt/yuanxun20002/ATOSLog/bak-${TODAY_DATE};find /home/zazt/yuanxun20002/ATOSLog -maxdepth 1 -type f -name '*.json' -not -path "/home/zazt/yuanxun20002/ATOSLog/bak-${TODAY_DATE}*" -exec mv {} /home/zazt/yuanxun20002/ATOSLog/bak-${TODAY_DATE} \;fiif [ -d /home/zazt/card/ATOSLog ] then mkdir -p /home/zazt/card/ATOSLog/bak-${TODAY_DATE};find /home/zazt/card/ATOSLog -maxdepth 1 -type f -name '*.json' -not -path "/home/zazt/card/ATOSLog/bak-${TODAY_DATE}*" -exec mv {} /home/zazt/card/ATOSLog/bak-${TODAY_DATE} \;fiif [ -d /home/zazt/review/ATOSLog ] then mkdir -p /home/zazt/review/ATOSLog/bak-${TODAY_DATE};find /home/zazt/review/ATOSLog -maxdepth 1 -type f -name '*.json' -not -path "/home/zazt/review/ATOSLog/bak-${TODAY_DATE}*" -exec mv {} /home/zazt/review/ATOSLog/bak-${TODAY_DATE} \;fiif [ -d /home/zazt/BackgroundCheck/ATOSLog ] then mkdir -p /home/zazt/BackgroundCheck/ATOSLog/bak-${TODAY_DATE};find /home/zazt/BackgroundCheck/ATOSLog -maxdepth 1 -type f -name '*.json' -not -path "/home/zazt/BackgroundCheck/ATOSLog/bak-${TODAY_DATE}*" -exec mv {} /home/zazt/BackgroundCheck/ATOSLog/bak-${TODAY_DATE} \;fi
#!/bin/sh# 获取以后工夫MONTH_DATE=`date +"%Y%m"`;if [ -d /home/zazt/yuanxun/ATOSLog ] then mkdir -p /home/zazt/yuanxun/ATOSLog/month-bak-${MONTH_DATE}; mv /home/zazt/yuanxun/ATOSLog/bak-* /home/zazt/yuanxun/ATOSLog/month-bak-${MONTH_DATE};fiif [ -d /home/zazt/yuanxun20002/ATOSLog ] then mkdir -p /home/zazt/yuanxun20002/ATOSLog/month-bak-${MONTH_DATE}; mv /home/zazt/yuanxun20002/ATOSLog/bak-* /home/zazt/yuanxun20002/ATOSLog/month-bak-${MONTH_DATE};fiif [ -d /home/zazt/card/ATOSLog ] then mkdir -p /home/zazt/card/ATOSLog/month-bak-${MONTH_DATE}; mv /home/zazt/card/ATOSLog/bak-* /home/zazt/card/ATOSLog/month-bak-${MONTH_DATE};fiif [ -d /home/zazt/review/ATOSLog ] then mkdir -p /home/zazt/review/ATOSLog/month-bak-${MONTH_DATE}; mv /home/zazt/review/ATOSLog/bak-* /home/zazt/review/ATOSLog/month-bak-${MONTH_DATE};fiif [ -d /home/zazt/BackgroundCheck/ATOSLog ] then mkdir -p /home/zazt/BackgroundCheck/ATOSLog/month-bak-${MONTH_DATE}; mv /home/zazt/BackgroundCheck/ATOSLog/bak-* /home/zazt/BackgroundCheck/ATOSLog/month-bak-${MONTH_DATE};fi
- 补充工夫解决参考脚本
#!/bin/sh echo "打印明天之前间断的十个工夫戳"TODAY_DATE=`date`date_range=$(seq 10) # 数组#echo ${date_range[@]}for i in ${date_range[@]}do INSTANCE_DATE=`date -d "${TODAY_DATE} $i day ago" +"%Y%m%d"`; echo ${INSTANCE_DATE}done echo "打印指定工夫之前的十天"date_var=20170909for i in $(seq 20)do current=`date -d "${date_var} $i day ago" +"%Y%m%d"` echo ${current}done #TODAY_DATE=`date +%Y%m%d`#INSTANCE_DATE=`date -d "${TODAY_DATE} 2 day ago"`;#INSTANCE_DATE_NEXT=`date -d "${INSTANCE_DATE} 1 day" +"%Y%m%d"`;