Shell脚本命令的工作方式有2种:交互式和批处理!
交互式:用户每输入一条命令就立即执行
批处理:由用户事先写好一个完整的Shell脚本,Shell会一次性执行脚本中的所有命令
[root@localhost ~]# echo $SHELL # 当前系统默认的终端解释器/bin/bash
编写简单的脚本
[root@localhost ~]# touch chd.sh # 创建chd.sh文件[root@localhost ~]# vim chd.sh # 编辑chd.sh文件[root@localhost ~]# cat chd.sh # 查看chd.sh文件#!/bin/bashpwdls -ld[root@localhost ~]# bash chd.sh # 执行chd.sh文件/rootdr-xr-x---. 17 root root 4096 7月 10 12:07 .[root@localhost ~]#
编写好Shell脚本之后,执行脚本有3种方法:
① bash脚本:bash chd.sh
② 添加可执行权限来执行Shell脚本路径:./chd.sh
③ source : source chd.sh
[root@localhost ~]# chmod +x chd.sh 给chd.sh文件添加可执行权限[root@localhost ~]# ./chd.sh /rootdr-xr-x---. 17 root root 4096 7月 10 12:07 .[root@localhost ~]# [root@localhost ~]# source chd.sh/rootdr-xr-x---. 17 root root 4096 7月 10 12:07 .[root@localhost ~]#
接收用户的参数
为了让Shell脚本程序更好的满足用户的实时需求,以便灵活完成工作,需要让脚本程序接收用户输入的参数
[root@localhost ~]# vim chd.sh[root@localhost ~]# cat chd.sh#!/bin/bashecho "The current script name is $0."echo "There are a total of $# parameters, which are $*."echo "The first parameter is $1, the fifth is $5."[root@localhost ~]# [root@localhost ~]# bash chd.sh 1 2 3 4 5 6The current script name is chd.sh.There are a total of 6 parameters, which are 1 2 3 4 5 6.The first parameter is 1, the fifth is 5.[root@localhost ~]#
判断用户的参数
Shell 脚本有时还要判断用户输入的参数,例如像 mkdir 命令一样,当目录不存在则创建,若存在则报错
[root@localhost ~]# [ -d /etc/fstab ] # 测试 /etc/fstab 是否为目录,返回值为1,即fstab不是目录[root@localhost ~]# echo $?1[root@localhost ~]# [ -f /etc/fstab ] # 测试 /etc/fstab 是否为文件,返回值为0,即fstab是文件[root@localhost ~]# echo $?0[root@localhost ~]#
符号 && 代表逻辑上的"与",当前面的命令执行成功才会执行后面的命令,判断 /dev/cdrom 设备是否存在,若存在则输出Exist
[root@localhost ~]# [ -e /dev/cdrom ] && echo "Exist"Exist
[root@localhost ~]# echo $USERroot[root@localhost ~]# [ $USER =root ] && echo "user"user[root@localhost ~]# [ $USER =root ] && echo "user" || echo "root"user[root@localhost ~]#
这里要注意一下:&& 和 || 的逻辑含义,因为前面的 && 不成立,所以后面的 || 才会执行
[root@localhost ~]# [ $USER != root ] && echo "user" || echo "root"root
[root@localhost ~]# [ 8 -gt 8 ][root@localhost ~]# echo $?1[root@localhost ~]# [ 8 -eq 8 ][root@localhost ~]# echo $?0[root@localhost ~]#
判断String变量是否为空值,来判断是否定义了这个变量
[root@localhost ~]# [ -z $String ] # 判断String 变量是否为空值[root@localhost ~]# echo $?0 [root@localhost ~]#
[root@localhost ~]# echo $LANG # 输出当前系统语言zh_CN.utf8[root@localhost ~]# [ $LANG!="en.us" ] && echo "Not en.US" # 判断当前系统语言是否为英文Not en.US [root@localhost ~]#
输入输出重定向
①输出重定向:将命令输出重定向到文件
有时候你想要保存某个命令的输出而不仅仅只是让它显示在显示器上,可以将命令的输出重定向到另一个位置(比如:文件)也可以将文件重定向到命令输入,最基本的重定向将命令的输出发送到一个文件中
[root@localhost ~]# touch chd.txt # 创建 chd.txt 文件[root@localhost ~]# date > chd.txt # 将date命令的输出重定向到chd.txt文件中[root@localhost ~]# ls -la chd.txt # 查看 chd.txt 文件内容-rw-r--r--. 1 root root 43 7月 10 16:47 chd.txt[root@localhost ~]# [root@localhost ~]# who > chd.txt # 重定向操作符会用新的文件数据覆盖已有文件[root@localhost ~]# cat chd.txt # 查看 chd.txt 文件内容root :0 2020-07-10 11:48 (:0)root pts/0 2020-07-10 11:48 (:0)[root@localhost ~]# [root@localhost ~]# date >> chd.txt # 如果不想覆盖原有内容,而是将命令的输出追加到已有文件中,可以用双大于号(>>)来追加数据[root@localhost ~]# cat chd.txt # 查看 chd.txt 文件内容root :0 2020-07-10 11:48 (:0)root pts/0 2020-07-10 11:48 (:0)2020年 07月 10日 星期五 16:53:12 CST[root@localhost ~]#
②输入重定向:将文件的内容重定向到命令,输入重定向符号是小于号(
[root@localhost ~]# wc < chd.txt # 通过将文本文件重定向到 wc 命令,就可以的到文件中的行、词和字节的计数 3 16 131[root@localhost ~]#
管道 |
有时候将一个命令的输出作为另一个命令的输入用重定向来实现会比较繁琐,这就牵涉到管线的命令了,管线命令使用[ | ]这个界定符号
[root@localhost ~]# ls | grep chd # 用管道将ls命令的输出送入grep命令对其过滤并显示chd.shchd.txt[root@localhost ~]#
方括号 [ ]
在 bash 中,在将一个数学运算结果赋给某个变量时,可以用美元符$ 和方括号[ ] 将数学表达式围起来
[root@localhost ~]# chd=$[ 1 + 5 ][root@localhost ~]# echo $chd6[root@localhost ~]# chd2=$[ $chd * 2 ][root@localhost ~]# echo $chd212[root@localhost ~]#
流程控制语句
条件测试语句能够让 shell 脚本根据实际工作灵活调整工作内容,例如判断系统的状态后执行指定的工作,或创建指定数量的用户,批量修改用户密码,这些都可以让 shell 脚本通过条件测试语句完成!
IF条件语句
if条件语句分为:单分支结构、双分支结构、多分支结构,复杂度逐级上升,但却可以让 shell 脚本更加的灵活,首先来说单分支结构,仅用 if 、then、fi 关键词组成,只在条件成立后执行
单分支if语句:判断/usr/local目录是否存在,若不存在则自动创建
[root@localhost ~]# vim chd.sh[root@localhost ~]# cat chd.sh#!/bin/bashchuid="/usr/local" # 变量if [ ! -e $chuid ] # 如果不存在 $chuidthen # 则mkdir -p $chuid # 创建 $chuidfi[root@localhost ~]# bash chd.sh[root@localhost ~]# ls -d /usr/local/usr/local[root@localhost ~]#
为了让Shell语句简单易懂,在接下来的实例中,我会使用数学中比大小的方式进行
实例1 if ... fi 语句
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/basha=100b=200if [ $a == $b ]then echo "a>b"fiif [ $a != $b ]then echo "afi[root@localhost ~]# chmod +x chuid.sh[root@localhost ~]# bash chuid.sha[root@localhost ~]#
双分支结构是由 if、then、else、fi 关键词组成,做条件成立或条件不成立的判断
实例2 if ... else ... fi 语句
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/basha=100b=200if [ $a == $b ]then echo "a>b"else echo "afi[root@localhost ~]# bash chuid.sha[root@localhost ~]#
实例2.1 if ... else ... fi 语句
[root@localhost ~]# vim chd.sh[root@localhost ~]# cat chd.sh#!/bin/bashread -p "我今年多大了:" aif [ $a == 27 ] # 正确答案是27岁,如果输入其他年龄都会显示“回答错误”then echo "恭喜你,答对了!"else echo "回答错误"fi[root@localhost ~]# bash chd.sh我今年多大了:26回答错误[root@localhost ~]# bash chd.sh我今年多大了:27恭喜你,答对了![root@localhost ~]#
多分支结构相对就比较复杂了,是由 if、then、else、elif、fi 关键词组成,根据多种条件成立的可能性执行不同的操作
实例3 if ... elif ... fi 语句
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/basha=100b=200if [ $a == $b ] then echo "a=b"elif [ $a -gt $b ]then echo "a>b"elif [ $a -lt $b ]then echo "aelse echo "None"fi[root@localhost ~]# bash chuid.sha[root@localhost ~]#
实例3.1 if ... elif ... fi语句
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/bashread -p "Enter your grade(0-120):" aif [ $a -ge 90 ] && [ $a -le 120 ] ; # a>90且<120,则成绩优秀then echo "$a is Excellent" # 优秀elif [ $a -ge 75 ] && [ $a -le 89 ] ; # a>75且<89,则成绩良好 then echo "$a is Good" # 良好elif [ $a -ge 60 ] && [ $a -le 74 ] ; # a>60且<74,则成绩合格then echo "$a is Pass" # 合格else echo "$a is Fail" # 不及格 # 否则成绩不及格fi[root@localhost ~]# bash chuid.shEnter your grade(0-120):9999 is Excellent[root@localhost ~]# bash chuid.shEnter your grade(0-120):8888 is Good[root@localhost ~]# bash chuid.shEnter your grade(0-120):7373 is Pass[root@localhost ~]# bash chuid.shEnter your grade(0-120):6666 is Pass[root@localhost ~]# bash chuid.shEnter your grade(0-120):5959 is Fail[root@localhost ~]#
FOR条件循环语句
for 条件语句会先读取多个不同的变量值,然后逐一执行同一组命令
实例4 for循环语句
[root@localhost ~]# vim chd.sh[root@localhost ~]# cat chd.sh#!/bin/bash#使用for循环跨越通过给定的数字列表for chd in 0 1 2 4 6 8 10 12do echo $chddone[root@localhost ~]# bash chd.sh0124681012[root@localhost ~]#
用for循环语句让脚本从文本中自动读取主机列表,然后自动逐个测试这些主机是否在线
[root@localhost ~]# vim ipadds.txt192.168.1.8192.168.1.9192.168.1.10[root@localhost ~]# vim chd.sh#!/bin/basha=$(cat ~/ipadds.txt) # a是变量for IP in $adoping -c 3 -i 0.2 -W 3 $IP &> /dev/null # 将多余的信息通过输出重定向符转移到/dev/null黑洞文件中if [ $? -eq 0 ] ; then # 使用$?判断这条命令是否执行成功echo "Host $IP is On-line." # 主机在线elseecho "Host $IP is Off-line." # 主机不在线fidone[root@localhost ~]# bash chd.shHost 192.168.1.8 is On-line.Host 192.168.1.9 is Off-line.Host 192.168.1.10 is Off-line.
ping命令中的参数解释:
-c参数来规定尝试的次数,-i参数定义每个数据包的发送间隔,-W参数定义等待超时时间,&> /dev/null表示的是用完的参数自动存入一个没有回收功能的垃圾箱,$?参数表示的是若前面的语句执行成功,则会返回0,若执行不成功,则会返回非0数据
[root@localhost ~]# vim chd.sh#使用ping命令来测试与对方主机的网络联通性#!/bin/bashping -c 3 -i 0.2 -W 3 $1 &> /dev/null # 其中$1表示输入的参数if [ $? -eq 0 ] #如果结果等于0 thenecho "Host $1 is On-line."elseecho "Host $1 is Off-line."fi[root@localhost ~]# bash chd.sh 192.168.1.8Host 192.168.1.8 is On-line.
WHILE条件循环语句
while 条件语句用于重复测试某个条件,当条件成立时则继续重复执行
[root@localhost ~]# vim chd.sh[root@localhost ~]# cat chd.sh#!/bin/basha=$(expr $RANDOM % 100)times=0echo "商品价格在0-99之间,猜猜是多少"while truedoread -p "请输入你猜的价格:" intlet times++if [ $int -eq $a ] ;then echo "恭喜你答对了,价格是 $a" echo "你总共猜测了 $times 次"exit 0elif [ $int -gt $a ] ;then echo "太高了!"else echo "太低了!"fidone[root@localhost ~]# bash chd.sh商品价格在0-99之间,猜猜是多少请输入你猜的价格:40太高了!请输入你猜的价格:20太高了!请输入你猜的价格:10恭喜你答对了,价格是 10你总共猜测了 3 次[root@localhost ~]#
case条件测试语句
case 条件语句可以依据变量的不同取值,分别执行不同的命令操作
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/bashread -p " 请输入一个字符,并按Enter键确认:" acase "$a" in[A-Z]|[a-z])echo "你输入的是字母!";;[0-9])echo "你输入的是数字!";;*)echo "你输入的是空格、功能键或其他字符!"esac[root@localhost ~]# bash chuid.sh 请输入一个字符,并按Enter键确认:2你输入的是数字![root@localhost ~]# bash chuid.sh 请输入一个字符,并按Enter键确认:A你输入的是字母![root@localhost ~]# bash chuid.sh 请输入一个字符,并按Enter键确认:&你输入的是空格、功能键或其他字符![root@localhost ~]#
until命令
until 命令和 while 命令工作方式相反,until 命令要求你指定一个返回非零退出状态码的测试命令,如果返回的退出状态码为零,循环就结束了
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/basha=100until [ $a -eq 0 ]do echo $a a=$[ $a - 20 ]done[root@localhost ~]# bash chuid.sh10080604020[root@localhost ~]#
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/basha=100until echo $a [ $a -eq 0 ]do echo Inside the loop: $a a=$[ $a - 20 ]done[root@localhost ~]# bash chuid.sh100Inside the loop: 10080Inside the loop: 8060Inside the loop: 6040Inside the loop: 4020Inside the loop: 200[root@localhost ~]#
嵌套循环(混用 until 和 while 循环)
嵌套循环也称为内部循环,会在外部循环的每次迭代中遍历一次它所有的值。(两个循环的 do 和 done 命令没有任何差别)
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/basha=3until [ $a -eq 0 ]doecho " 其它语句:$a "b=1while [ $b -lt 5 ]doc=$( echo " scale=4; $a / $b " | bc )echo " 内部语句:$a / $b = $c "b=$[ $b +1 ]donea=$[ $a -1 ]done[root@localhost ~]# bash chuid.sh 其它语句:3 内部语句:3 / 1 = 3.0000 内部语句:3 / 2 = 1.5000 内部语句:3 / 3 = 1.0000 内部语句:3 / 4 = .7500 其它语句:2 内部语句:2 / 1 = 2.0000 内部语句:2 / 2 = 1.0000 内部语句:2 / 3 = .6666 内部语句:2 / 4 = .5000 其它语句:1 内部语句:1 / 1 = 1.0000 内部语句:1 / 2 = .5000 内部语句:1 / 3 = .3333 内部语句:1 / 4 = .2500 [root@localhost ~]#
外部的 until 循环以值数3开始,并继续执行到数值等于零。内部 while 循环以数值1开始并一直执行,只要小于5。每个循环都必须改变测试条件中用到的值,否则循环就会无止尽进行下去
控制循环 break命令跳出循环
当 shell 执行break命令时,它会尝试跳出(终止)当前正在执行的循环
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/bash#(break)跳出单个循环for a in 2 4 6 8 10 12 14 16 18 20do if [ $a -eq 16 ]then breakfi echo "迭代数字 : $a"done echo "for循环完成"[root@localhost ~]# bash chuid.sh迭代数字 : 2迭代数字 : 4迭代数字 : 6迭代数字 : 8迭代数字 : 10迭代数字 : 12迭代数字 : 14for循环完成[root@localhost ~]#
[root@localhost ~]# vim chuid.sh[root@localhost ~]# cat chuid.sh#!/bin/bash#(break)跳出内部循环for (( a = 1; a < 4; a++ ))do echo "其它循环 : $a"for (( b = 1; b< 100; b++ ))do if [ $b -gt 4 ]then break 2fi echo "内部循环 : $b"donedone[root@localhost ~]# bash chuid.sh其它循环 : 1内部循环 : 1内部循环 : 2内部循环 : 3内部循环 : 4[root@localhost ~]#
计划任务服务程序
能够让系统自动化运行,无需人工的干预就可以让各个服务、命令在指定的时间段运行、停止。实际上这些操作都是由系统的计划任务功能完成的,计划任务可分为:①一次性 ② 长期性
一般用 at 命令创建计划任务,有交互式和非交互式2种(输入完成后敲击 ctrl+d 来保存退出)
[root@localhost ~]# at 23:30 # 23:30安排一次性任务at> systemctl start httpd # 启动httpd服务at> job 1 at Sat Jul 11 23:30:00 2020[root@localhost ~]# [root@localhost ~]# atq # 查看任务列表1 Sat Jul 11 23:30:00 2020 a root[root@localhost ~]# [root@localhost ~]# atrm 1 # 删除任务[root@localhost ~]# atq[root@localhost ~]#
crond 服务是用来创建长期可循环的计划任务
创建、编辑计划任务:crontab -e [-u 用户名]
查看计划任务:crontab -l [-u 用户名]
删除计划任务:crontab -r [-u 用户名]
cron 脚本默认配置了4个基本目录:hourly、daily、monthly、weekly
如果脚本需要每天运行一次,只要将脚本复制到 daily 目录,cron 就会每天执行它
[root@localhost ~]# ls /etc/cron.*ly #查看cron目录/etc/cron.daily:0yum-daily.cron logrotate man-db.cron mlocate rhsmd/etc/cron.hourly:0anacron 0yum-hourly.cron/etc/cron.monthly:/etc/cron.weekly:[root@localhost ~]#
在默认情况下用户的 cron 时间表并不存在,要为 cron 时间表添加条目可以用 -e 选项
[root@localhost ~]# crontab -e -u root #创建、编辑计划任务crontab: installing new crontab[root@localhost ~]# crontab -l # 查看计划任务20 6 * * * /etc/init.d/sshd start # 每天早上6:20启动sshd服务15 23 * * * /etc/init.d/sshd stop # 每天晚上23:15停止sshd服务[root@localhost ~]#[root@localhost ~]# crontab -r -u root # 删除计划任务[root@localhost ~]# crontab -lno crontab for root[root@localhost ~]#
计划任务中的“分”字段必须有数值,绝对不能为空或是*号,而“日”和“星期”字段不能同时使用,否则就会发生冲突