20.1 shell 脚本介绍
shell是一种脚本语言
可以使用逻辑判断、循环等语法
可以自定义函数
shell是系统命令的集合
shell脚本可以实现自动化运维,能大大增加我们的运维效率
20.2 shell 脚本结构和执行
开头需要加 #!/bin/bash,不加开头在本机上可以运行,换台机器就不一定能执行。在行首文件头处指定接下来要运行的命令是通过哪一个解释器进行操作的。
以#开头的行作为解释说明,脚本的名字以 .sh 结尾,用于区分这是一个 shell 脚本
执行方法有两种:
1、/bin/bash 实际上就是 /bin/sh
[root@arslinux-01?~]#?ll?/bin/sh lrwxrwxrwx.?1?root?root?4?3月??14?05:51?/bin/sh?->?bash [root@arslinux-01?~]#?ll?/bin/bash -rwxr-xr-x.?1?root?root?964608?10月?31?2018?/bin/bash
2、给文件执行权限,chmod a+x 1.sh 才可以 ./1.sh
[root@arslinux-01?shell]#?./1.sh -bash:?./1.sh:?权限不够 [root@arslinux-01?shell]#?chmod?a+x?1.sh [root@arslinux-01?shell]#?./1.sh 123 22:43:46?up??2:39,??1?user,??load?average:?0.10,?0.09,?0.13 USER?????TTY??????FROM?????????????LOGIN@???IDLE???JCPU???PCPU?WHAT root?????pts/0????192.168.194.1????20:08????2.00s??2:44???0.00s?/bin/bash?./1.sh 1.sh
3、如果没有权限,可以 /bin/bash 1.sh
[root@arslinux-01?shell]#?/bin/bash?1.sh [root@arslinux-01shell]#?/bin/bash?1.sh 123 22:48:59?up??2:44,??1?user,??load?average:?0.01,?0.05,?0.11 USER?????TTY??????FROM?????????????LOGIN@???IDLE???JCPU???PCPU?WHAT root?????pts/0????192.168.194.1????20:08????3.00s??2:51???0.00s?/bin/bash?1.sh 1.sh
查看脚本执行过程: bash -x 1.sh
查看脚本是否语法错误: ?bash -n 1.sh
20.3 date 命令用法
[root@arslinux-01?~]#?date 2019年?06月?15日?星期六?23:11:02?CST
date??+%Y-%m-%d, date +%y-%m-%d????年月日
[root@arslinux-01?~]#?date?+%Y-%m-%d 2019-06-15 [root@arslinux-01?~]#?date?+%y-%m-%d 19-06-15 [root@arslinux-01?~]#?date?+%Y????????//年 2019 [root@arslinux-01?~]#?date?+%M????????//分钟 14 [root@arslinux-01?~]#?date?+%D 06/15/19 [root@arslinux-01?~]#?date?+%F 2019-06-15 [root@arslinux-01?~]#?date?+%S????????//秒 09 [root@arslinux-01?~]#?date?+%s????????//时间戳,距离?1970.01.01.00:00:00?多少秒 1560611775
date?+%H:%M:%S = date +%T????时间
[root@arslinux-01?~]#?date?+%H:%M:%S 23:18:23 [root@arslinux-01?~]#?date?+%T 23:18:29 [root@arslinux-01?~]#?date?+%h 6月 [root@arslinux-01?~]#?date?+%m 06
date +%s???? 时间戳
[root@arslinux-01?~]#?date?+%s 1560612094 距离?1970.01.01.00:00:00?多少秒
date +%w, date +%W????星期
[root@arslinux-01?~]#?date?+%w????????//星期几 6 [root@arslinux-01?~]#?date?+%W????????//几年的第几周 23
cal????日历形式查看日期
[root@arslinux-01?~]#?cal 六月?2019 日?一?二?三?四?五?六 1 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
date -d "-1 day"????一天前
[root@arslinux-01?~]#?date?-d?"-1?day" 2019年?06月?14日?星期五?23:26:15?CST [root@arslinux-01?~]#?date?-d?"-1?day"?+%F 2019-06-14
date -d "+1day"???? 一天后
[root@arslinux-01?~]#?date?-d?"+1?day"?+%F 2019-06-16
date -d "-1 month"????一月前
[root@arslinux-01?~]#?date?-d?"-1?month"?+%F 2019-05-15 [root@arslinux-01?~]#?date?-d?"-1?year"?+%F 2018-06-15 [root@arslinux-01?~]#?date?-d?"-1?week"?+%F 2019-06-08
date -d "-1 min"???? 一分钟前
[root@arslinux-01?~]#?date?-d?"-1?min"?+%T 23:28:02
date -d @1504620492????根据时间戳换算成日期
[root@arslinux-01?~]#?date?-d?@1504620492 2017年?09月?05日?星期二?22:08:12?CST
date +%s -d "2019-09-09 09:09:09"????把具体的日期换算成时间戳
[root@arslinux-01?~]#?date?+%s?-d?"2019-09-09?09:09:09" 1567991349
20.4 shell 脚本中的变量
当脚本中使用某个字符串较频繁并且字符串长度很长时就应该使用变量代替
使用条件语句时,常使用变量? ? if [ $a -gt 1 ]; then ... ; fi
引用某个命令的结果时,用变量替代? ?n=`wc -l 1.txt`
写和用户交互的脚本时,变量也是必不可少的??read -p "Input a number: " n; echo $n? ?如果没写这个n,可以直接使用$REPLY
内置变量 $0, $1, $2…? ? $0表示脚本本身,$1 第一个参数,$2 第二个 ....? ?? ? $#表示参数个数
数学运算a=1;b=2; c=$(($a+$b))或者$[$a+$b]
20.5 shell 脚本中的逻辑判断
格式1:if 条件;then 语句;fi
[root@arslinux-01?~]#?vim?01.sh #/bin/bash a=5 if?[?$a?-gt?3?] then ????echo?ok fi
格式2:if 条件;then 语句;else 语句;fi
[root@arslinux-01 shell]# vim 02.sh
#/bin/bash a=1 if?[?$a?-gt?3?] then ????echo?ok else ????echo?not?ok fi
[root@arslinux-01?shell]#?sh?-x?02.sh +?a=1 +?'['?1?-gt?3?']' +?echo?not?ok not?ok
格式3:if ...;then ...;elif ...;then ...;else ...;fi
[root@arslinux-01?shell]#?vim?03.sh #/bin/bash a=3 if?[?$a?-gt?4?] then ????echo?">4" elif?[?$a?-lt?6?] then ????echo?"<6?&&?>1" else ????echo?not?ok fi
[root@arslinux-01?shell]#?sh?-x??03.sh +?a=3 +?'['?3?-gt?4?']' +?'['?3?-lt?6?']' +?echo?'<6?&&?>1' <6?&&?>1
[root@arslinux-01?shell]#?vim?03.sh #/bin/bash a=5 if?[?$a?-lt?4?] then ????echo?"<4" elif?[?$a?-gt?6?] then ????echo?">6" else ????echo?not?ok fi
[root@arslinux-01?shell]#?sh?-x??03.sh +?a=5 +?'['?5?-lt?4?']' +?'['?5?-gt?6?']' +?echo?not?ok not?ok
逻辑判断表达式:
if [ $a -gt $b ]; -gt (>); 大于
if [ $a -lt 5 ]; -lt(<); 小于
if [ $b -eq 10 ]等 -eq(==); 等于
-le(<=);-ge(>=); -ne(!=) 注意到处都是空格
·如果非要用 > < ,可以用(( ))
[root@localhost?shell]#?if?(($a>1));then?echo?ok;fi ok
·可以使用 && || 结合多个条件
if [ $a -gt 5 ] && [ $a -lt 10 ]; then 并且
if [ $b -gt 5 ] || [ $b -lt 3 ]; then 或者
20.6 文件目录属性判断
·[ -f file ] 判断是否是普通文件,且存在
·[ -d file ] 判断是否是目录,且存在
·[ -e file ] 判断文件或目录是否存在
·[ -r file ] 判断文件是否可读
·[ -w file ] 判断文件是否可写
·[ -x file ] 判断文件是否可执行
[ -f file ] 判断是否是普通文件,且存在
[root@arslinux-01?shell]#?vim?04.sh #/bin/bash f="/tmp/arslinux" if?[?-f?$f?] then ????echo?$f?exist. else ????touch?$f fi
[root@arslinux-01?shell]#?sh?-x?04.sh +?f=/tmp/arslinux +?'['?-f?/tmp/arslinux?']' +?touch?/tmp/arslinux [root@arslinux-01?shell]#?sh?-x?04.sh +?f=/tmp/arslinux +?'['?-f?/tmp/arslinux?']' +?echo?/tmp/arslinux?exist. /tmp/arslinux?exist.
[ -d file ] 判断是否是目录,且存在
[root@arslinux-01?shell]#?vim?file2.sh #/bin/bash f="/tmp/arslinux" if?[?-d?$f?] then ????echo?$f?exist. else ????touch?$f fi
[root@arslinux-01?shell]#?sh?-x?file2.sh +?f=/tmp/arslinux +?'['?-d?/tmp/arslinux?']' +?touch?/tmp/arslinux
[ -e file ] 判断文件或目录是否存在
[root@arslinux-01?shell]#?vim?file3.sh #/bin/bash f="/tmp/arslinux" if?[?-e?$f?] then ????echo?$f?exist. else ????touch?$f fi
[root@arslinux-01?shell]#?sh?-x?file3.sh +?f=/tmp/arslinux +?'['?-e?/tmp/arslinux?']' +?echo?/tmp/arslinux?exist. /tmp/arslinux?exist.
[ -r file ] 判断文件是否可读
[root@arslinux-01?shell]#?vim?file4.sh #/bin/bash f="/tmp/arslinux" if?[?-r?$f?] then ????echo?$f?readable. fi
[root@arslinux-01?shell]#?sh?-x?file4.sh +?f=/tmp/arslinux +?'['?-r?/tmp/arslinux?']' +?echo?/tmp/arslinux?readable. /tmp/arslinux?readable.
[ -w file ] 判断文件是否可写
[root@arslinux-01?shell]#?vim?file4.sh #/bin/bash f="/tmp/arslinux" if?[?-w?$f?] then ????echo?$f?writeable. fi
[root@arslinux-01?shell]#?sh?-x?file4.sh +?f=/tmp/arslinux +?'['?-w?/tmp/arslinux?']' +?echo?/tmp/arslinux?writeable. /tmp/arslinux?writeable.
[ -x file ] 判断文件是否可执行
[root@arslinux-01 shell]# vim file4.sh
#/bin/bash f="/tmp/arslinux" if?[?-x?$f?] then ????echo?$f?exeable. fi
[root@arslinux-01?shell]#?sh?-x?file4.sh +?f=/tmp/arslinux +?'['?-x?/tmp/arslinux?']'
简单写法
#!/bin/bash f="/tmp/alex" if?[?-f?$f?] then rm?-f?$f fi
可以不用 if 判断写成
#!/bin/bash f="/tmp/alex" [?-f?$f?]?&&?rm?-f?$f
#!/bin/bash f="/tmp/alex" if?[?-f?$f?] then ????rm?-f?$f else ????touch?$f fi
可以反写为
#!/bin/bash f="/tmp/alex" if?[?!?-f?$f?] then ????touch?$f fi
可以不用 if 判断,写成
#!/bin/bash f="/tmp/alex" [?-f?$f?]?||?touch?$f
20.7 if 特殊用法
if [ -z "$a" ]??这个表示当变量 a 的值为空时会怎么样
#!/bin/bash n=`wc?-l?/tmp/bababa` if?[?-z?"$n"?] then ????echo?error else ????if?[?$n?-gt?100] ????then ????????echo?ok ????fi fi
可以优化为:
#!/bin/bash n=`wc?-l?/tmp/bababa` if?[?-z?"$n"?] then ????echo?error exit elif?[?$n?-gt?100] then ????echo?ok fi
可以再优化:
#!/bin/bash if?[?-f?/tmp/babala?] then ????echo?"/tmp/babala?isn't?exist." ????exit fi n=`wc?-l?/tmp/bababa` if?[?-z?"$n"?] then ????echo?error ????exit elif?[?$n?-gt?100] then ????echo?ok fi
if [ -n "$a" ] 表示当变量 a 的值不为空
[root@arslinux-01?shell]#?if?[?-n?01.sh?];then?echo?ok;fi ok [root@arslinux-01?shell]#?if?[?-n?"$b"?];then?echo?"$b";else?echo?"b?is?null";fi b?is?null
命令可以作为判断结果
if grep -q '123' 1.txt; then??表示如果1.txt中含有'123'的行时会怎么样
[root@arslinux-01?shell]#?if?grep?-w?'user1'?/etc/passwd;then?echo?"user1?exist";fi user1:x:1001:1001::/home/user1:/bin/bash user1?exist [root@arslinux-01?shell]#?if?grep?-wq?'user1'?/etc/passwd;then?echo?"user1?exist";fi user1?exist
grep -q 静默输出
if [ ! -e file ]; then 表示文件不存在时会怎么样
if (($a<1)); then …等同于 if [ $a -lt 1 ]; then…
[ ] 中不能使用<,>,==,!=,>=,<=这样的符号
20.8/20.9 case 判断
格式:case??变量名 in
????????????????value1)
????????????????????command
????????????????????;;
????????????????value2)?
????????????????????command
????????????????????;;
????????????????*)
????????????????????commond
????????????????????;;
????????????????esac
:: 表示一个判断结束,进入下一个判断
在case程序中,可以在条件中使用|,表示或的意思, 比如
2|3)
?? ? command
? ? ;;
*)除以上所有之外的
shell 脚本案例
#!/bin/bash read?-p?"Please?input?a?number:?"?n???????????//从标准输入读取输入并赋值给变量?n if?[?-z?"$n"?] then ????echo?"Please?input?a?number." exit?1 fi n1=`echo?$n|sed?'s/[0-9]//g'`????????//从变量n中将数字替换为空,如果n1不为空,则不是纯数字,那么现实输入一个数字并退出 if?[?-n?"$n1"?] then ????echo?"Please?input?a?number." exit?1 fi if?[?$n?-lt?60?]?&&?[?$n?-ge?0?]//纯数字往下接着判断 then ????tag=1????????????????????????????????//标记tag elif?[?$n?-ge?60?]?&&?[?$n?-lt?80?] then ????tag=2 elif?[?$n?-ge?80?]??&&?[?$n?-lt?90?] then ????tag=3 elif?[?$n?-ge?90?]?&&?[?$n?-le?100?] then ????tag=4 else ????tag=0 fi case?$tag?in ????1) ????????echo?"not?ok" ????????;; ????2) ????????echo?"ok" ????????;; ????3) ????????echo?"great" ????????;; ????4) ????????echo?"brilliant" ????????;; ????*) ????????echo?"The?number?range?is?0-100." ????????;; esac
执行脚本看结果:
输入符合条件的纯数字
[root@arslinux-01?shell]#?sh?-x?case.sh +?read?-p?'Please?input?a?number:?'?n Please?input?a?number:?77 +?'['?-z?77?']' ++?echo?77 ++?sed?'s/[0-9]//g' +?n1= +?'['?-n?''?']' +?'['?77?-lt?60?']' +?'['?77?-ge?60?']' +?'['?77?-lt?80?']' +?tag=2 +?case?$tag?in +?echo?ok ok
输入含字母的数字组合
[root@arslinux-01?shell]#?sh?-x?case.sh +?read?-p?'Please?input?a?number:?'?n Please?input?a?number:?l33l +?'['?-z?l33l?']' ++?echo?l33l ++?sed?'s/[0-9]//g' +?n1=ll +?'['?-n?ll?']' +?echo?'Please?input?a?number.' Please?input?a?number. +?exit?1
输入大于 100 的数字
[root@arslinux-01?shell]#?sh?-x?case.sh +?read?-p?'Please?input?a?number:?'?n Please?input?a?number:?234 +?'['?-z?234?']' ++?echo?234 ++?sed?'s/[0-9]//g' +?n1= +?'['?-n?''?']' +?'['?234?-lt?60?']' +?'['?234?-ge?60?']' +?'['?234?-lt?80?']' +?'['?234?-ge?80?']' +?'['?234?-lt?90?']' +?'['?234?-ge?90?']' +?'['?234?-le?100?']' +?tag=0 +?case?$tag?in +?echo?'The?number?range?is?0-100.' The?number?range?is?0-100.
20.10 for 循环
语法:for 变量名 in 条件; do …; done
案例1
计算1到100数字的和
[root@arslinux-01?shell]#?vim?for1.sh #!/bin/bash sum=0 for?i?in?`seq?1?100` do ????sum=$[$sum+$i] done echo?$sum
案例2
列出/etc/下的目录或子目录
[root@arslinux-01?shell]#?sh?for2.sh #!/bin/bash/ cd?/etc/ for?a?in?`ls?/etc/` do ????if?[?-d?$a?] ????then ????????ls?-d?$a ????fi done
ls 是用空格或回车作为分隔符,for 循环以他为对象,那么可能会出错
20.11/20.12 while循环
语法:while 条件; do … ; done
案例1
每隔半分钟检查系统负载,当负载大于10时,发邮件
[root@arslinux-01?shell]#?vim?while.sh #!/bin/bash while?: do ????load=`w|head?-1|awk?-F?'load?average:?'?'{print?$2}'|cut?-d.?-f1` ????if?[?$load?-gt?10] ????then ????????/usr/local/sbin/mail.py?xxx@163.com?"load?high"?"$load" ????fi ????sleep?30 done
: 表示死循环 或者写成 while true
案例2
做一个让人让用户不停输入东西的脚本
[root@arslinux-01?shell]#?vim?while2.sh #!/bin/bash while?: do ????read?-p?"Please?input?a?number:?"?n ????if?[?-z?"$n"?] ????then ????????echo?"you?need?input?sth." ????????continue ????fi ????n1=`echo?$n|sed?'s/[0-9]//g'` ????if?[?-n?"$n1"?] ????then ????????echo?"you?just?only?input?numbers." ????????continue ????fi ????break done echo?$n
continue 指继续重新再来一遍循环
continue 从头继续重新再来一遍循环
break 退出 while 循环
20.13 break跳出循环
[root@arslinux-01?shell]#?vim?break.sh #!/bin/bash for?i?in?`seq?1?5` do ????echo?$i ????if?[?$i?-eq?3?] ????then ????????break ????fi ????echo?$i done echo?jjjjj
[root@arslinux-01?shell]#?sh?-x?break.sh ++?seq?1?5 +?for?i?in?'`seq?1?5`' +?echo?1 1 +?'['?1?-eq?3?']' +?echo?1 1 +?for?i?in?'`seq?1?5`' +?echo?2 2 +?'['?2?-eq?3?']' +?echo?2 2 +?for?i?in?'`seq?1?5`' +?echo?3 3 +?'['?3?-eq?3?']' +?break +?echo?jjjjj jjjjj
原本在 i 为 3 之前,脚本一直执行到done,然后在从头循环,而 为 3 时,之间break跳出循环,
echo ?aaaaaaa
break 用在循环语句里,for 也行,while 也行
20.14 continue结束本次循环
忽略continue之下的代码,直接进行下一次循环
[root@arslinux-01?shell]#?vim?continue.sh #!/bin/bash for?i?in?`seq?1?5` do ????echo?$i ????if?[?$i?-eq?3?] ????then ????????continue ????fi ????echo?$i done echo?jjjjj
[root@arslinux-01?shell]#?sh?-x?continue.sh ++?seq?1?5 +?for?i?in?'`seq?1?5`' +?echo?1 1 +?'['?1?-eq?3?']' +?echo?1 1 +?for?i?in?'`seq?1?5`' +?echo?2 2 +?'['?2?-eq?3?']' +?echo?2 2 +?for?i?in?'`seq?1?5`' +?echo?3 3 +?'['?3?-eq?3?']' +?continue +?for?i?in?'`seq?1?5`' +?echo?4 4 +?'['?4?-eq?3?']' +?echo?4 4 +?for?i?in?'`seq?1?5`' +?echo?5 5 +?'['?5?-eq?3?']' +?echo?5 5 +?echo?jjjjj jjjjj
break会跳出循环,不再执行循环,而continue会结束本次循环,从头开始执行循环
20.15 exit退出整个脚本
[root@arslinux-01?shell]#?vim?exit.sh #!/bin/bash for?i?in?`seq?1?5` do ????echo?$i ????if?[?$i?-eq?3?] ????then ????????exit ????fi ????echo?$i done echo?jjjjj
[root@arslinux-01?shell]#?sh?-x?exit.sh ++?seq?1?5 +?for?i?in?'`seq?1?5`' +?echo?1 1 +?'['?1?-eq?3?']' +?echo?1 1 +?for?i?in?'`seq?1?5`' +?echo?2 2 +?'['?2?-eq?3?']' +?echo?2 2 +?for?i?in?'`seq?1?5`' +?echo?3 3 +?'['?3?-eq?3?']' +?exit
break 在跳出后还会执行最后的 echo,而 exit 直接退出
给 exit 定义退出的数字
[root@arslinux-01?shell]#?vim?exit.sh #!/bin/bash for?i?in?`seq?1?5` do ????echo?$i ????if?[?$i?-eq?3?] ????then ????????exit?2 ????fi ????echo?$i done echo?jjjjj
[root@arslinux-01?shell]#?sh?-x?exit2.sh ++?seq?1?5 +?for?i?in?'`seq?1?5`' +?echo?1 1 +?'['?1?-eq?3?']' +?echo?1 1 +?for?i?in?'`seq?1?5`' +?echo?2 2 +?'['?2?-eq?3?']' +?echo?2 2 +?for?i?in?'`seq?1?5`' +?echo?3 3 +?'['?3?-eq?3?']' +?exit?2 [root@arslinux-01?shell]#?echo?$? 2
continue 结束本次循环,继续循环,忽略后面的代码
break 结束整个循环,跳出
exit 直接退出整个脚本
扩展
select用法 http://www.apelearn.com/bbs/thread-7950-1-1.html
入职后的流程:http://ask.apelearn.com/question/18013