shell脚本进阶 详解及其实例

前言在我们使用linux的过程中,脚本可以给我们省很多时间和精力,比如,我们要定期备份一些文件,如果我们纯手工去操作的话,每到一个时间段我们就要去进行备份的操作,如果某一次我们在干其他事情的时候,把这件事情忘了那可怎么办╮(╯﹏╰)╭这个时候,我们就可以把需要执行的备份命令放在一个脚本里面,通过一些语句去判断是否符合我们执行命令的条件,实现自动化0.0这样不就省时省心很多啦~老板再也不用担心我忘记备份ヽ( ̄▽ ̄)ノ那么,接下来,小编就来分享一下脚本的语法及实例。
一、条件选择、判断(if、case)1.1 if语句用法及实例当我们在脚本中遇到需要判断的时候,我们就可以用if语句来实现。具体的语法如下:
   单分支if 判断条件;then  条件为真的分支代码 
fi
   双分支if 判断条件; then
条件为真的分支代码
else
条件为假的分支代码
fi
   多分支if 判断条件1; then
条件为真的分支代码
elif 判断条件2; then
条件为真的分支代码
elif 判断条件3; then
条件为真的分支代码
else
以上条件都为假的分支代码
fi
在多分支中,系统会逐条判断你写入的条件,第一次遇到“真”条件时,执行该分支,而后结束整个if语句。
注意:1、if和fi是成对出现的
2、if语句可以嵌套。
example:
1)判断两个数字的大小
1 #!/bin/bash 2 #定义变量 3 read -p please input the first num: num1 4 read -p please input the second num: num2 5 #判断数字是否符合标准 6 if [[ $num1 =~ ^[0-9]+$ && $num2 =~ ^[0-9]+$ ]];then 7 # 判断两个数字的大小并输出判断结果 8 if [ $num1 -lt $num2 ];then 9 echo the num2 is biger than the num110 elif [ $num1 -eq $num2 ];then11 echo two numbers equal12 else 13 echo the num1 is biger than the num214 fi15 else16 echo please enter the correct number17 fi18 19 #删除变量 20 unset num1 num2
2)编写脚本/root/bin/createuser.sh,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息
1 #!/bin/bash 2 #定义变量 3 read -p 请输入一个用户名: name 4 #判断用户名是否存在 5 if `id $name &> /dev/null`;then 6 # 若存在,则输出id等信息 7 echo 用户存在,用户的id信息为:`id $name` 8 else 9 # 若不存在,则添加用户,设置密码为随机8位,下次登录时提示修改密码,同时显示id等信息 10 passwd=`cat /dev/urandom |tr -cd [:alpha:] |head -c8` 11 `useradd $name &> /dev/null` 12 `echo $passwd | passwd --stdin $name &> /dev/null` 13 echo 用户名:$name 密码: $passwd >> user.txt 14 `chage -d 0 $name` 15 echo 用户已添加,用户的id信息为:`id $name` 密码为:$passwd16 fi17 18 #删除变量 19 unset name passwd
1.2 case用法及实例当涉及到多个条件匹配的时候,我们用if可能就很麻烦了,这个时候,我们就可以用case来编写这个脚本。case的具体语法如下:
case 变量引用 in
pat1)
分支1
;;
pat2)
分支2
;;
...
*)
默认分支
;;
esac
注意:1、case每一个分支后,都是以两个“;”结尾的(最后一个可以省略)
      2、case和esac是成对出现的
example:
1)编写一个脚本,提示用户输入信息,判断其输入的是yes或no或其他信息。
1 #!/bin/bash 2 #定义变量 3 read -p yue ma?(yes or no): ans 4 #把变量中的大写转换为小写 5 ans=`echo $ans |tr [[:upper:]] [[:lower:]] ` 6 #判断输入的信息是什么并输出结果 7 case $ans in 8 yes|y) 9 echo see you tonight10 ;; 11 no|n) 12 echo sorry,i have no time13 ;; 14 *) 15 echo what’s your means?16 ;; 17 esac18 19 #删除变量 20 unset ans ans
2)编写脚本/root/bin/filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类型)
1 #!/bin/bash 2 read -p 请输入一个文件路径: file 3 #判断文件是否存在 4 `ls $file &> /dev/null` 5 #若存在,判断文件类型并输出 6 if [ $? -eq 0 ];then 7 style=`ls -ld $file | head -c1` 8 case $style in 9 -) 10 echo 这是一个普通文件11 ;; 12 d) 13 echo 这是一个目录文件14 ;; 15 l) 16 echo 这是一个链接文件17 ;; 18 *) 19 echo 这是其他类型文件20 ;; 21 esac22 #若不存在,提示并退出 23 else24 echo 该文件不存在25 exit 226 fi27 28 #删除变量 29 unset file style
二、循环语句    在我们的脚本中,肯定也少不了对某一段代码重复运行多次的操作,此时,我们就会用到循环语句。循环语句中,都是有进入条件和退出条件的,循环的次数也分为事先已知和事先未知(事先已知就是我们知道循环的具体次数,事先未知则是指当满足某一条件就进行循环,但是次数是不确定的。)。接下来,我们就来看看关于循环语句的用法。
2.1 for循环for循环的执行机制是:一次将列表中的元素赋值给“变量名”;每次赋值后即执行一次循环体;直到列表中的元素耗尽,循环结束。基本的语法有两种:
1)for 变量名 in 列表 ; do
循环体
done
关于列表的生成方法,如下:
①直接给出列表
②整数列表:
(a){start…end}
(b)`seq start end`
③返回列表的命令
    $(command)
④使用glob通配符如:
      *.sh
⑤变量引用
$i,$*
2)for (( exp1; exp2; exp3 )); do
循环体
done
   更清晰的可以从下图中看出:
example:
1)打印九九乘法表
1 #!/bin/bash 2 #判断i的值是否在1-9 3 for i in {1..9};do 4 # 判断j的值是否在1-$i 5 for j in `seq 1 $i`;do 6 # 若在,则打印i*j的值 7 echo -en $i*$j = $[$i*$j]\t 8 done 9 echo10 done11 12 #删除变量 13 unset i j
2)输入正整数n,计算1+…+n的和
1 #!/bin/bash 2 #定义变量 3 sum=0 4 read -p 请输入一个正整数: num 5 #判断num是否是正整数 6 if [[ $num =~ ^[[:digit:]]+$ ]];then 7 # 若是,当i在1-$num时,输出sum值 8 for i in `seq 1 $num`;do 9 let sum+=$i 10 done 11 echo sum=$sum12 #若不是,提示输出正整数 13 else 14 echo 请输入一个正整数!15 fi16 17 #删除变量 18 unset i sum num
2.2 while循环while循环比for循环略复杂一些,具体语法如下:
while condition; do
      循环体
done
注意:1、进入条件:condition为true;退出条件:condition为false。
      2、condition为循环控制条件:进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;知道条件测试状态为“false”终止循环。
      3、condition一般应该有循环控制变量;此变量的值会在循环体不断地被修正。
example:
1)计算100以内所有正奇数之和
1 #!/bin/bash 2 #定义变量 3 i=1 4 sum=0 5 #当i10时,退出循环 5 until [ $i -gt 10 ];do 6 # 输出i的值,i=i+1 7 echo $i 8 let i+=1 9 done10 11 #删除变量 12 unset i
2.4 select循环   select循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示ps3提示符,等待用户输入。
   用户输入菜单列表中的某个数字,执行相应的命令。
   用户输入被保存在内置变量reply中。
   select的具体语法如下:
select variable in list; do
   循环体命令
done
注意:①select是个无线循环,因此要记住用break命令退出循环,或用exit命令终止脚本。也可以按ctrl+c退出循环。
②select经常和case联合使用。
③与for循环类似,可以省略in list,此时使用位置变量。
example:
1)生成菜单,并显示选中的价钱。
1 #!/bin/bash 2 #定义ps3提示符 3 ps3=please choose the menu: 4 #输出菜单 5 select menu in yangroutang mifan hulatang jiaozi lamian huimian quit 6 do 7 # 判断选择 8 case $reply in 9 1|4) 10 echo the price is 2011 ;; 12 2|5) 13 echo the price is 1214 ;; 15 3|6) 16 echo the price is 1017 ;; 18 7) 19 break 20 ;; 21 *) 22 echo choose error23 ;; 24 esac25 done
2.5 循环小补充2.5.1 循环控制语句 continue&break   循环控制语句用于循环体中,常见的控制语句有两种,continue和break。接下来我们就来看看两者的区别:
continue语句结束的是本轮循环,直接进入下一轮判断;最内层是第1层。
break语句结束的则是整个循环,最内层为第1层。
example:
1)求(1+3+…+49+53+…+99)的和
1 #定义变量 2 sum=0 3 for ((i=1;i<=100;i++));do 4 # 当i为奇数时,继续执行 5 if [ $[i%2] -eq 1 ];then 6 # 当i=51时,跳过该循环 7 if [ $i -eq 51 ];then 8 continue 9 fi 10 let sum+=$i 11 fi 12 done13 echo sum=$sum14 15 #删除变量 16 unset i sum
2)求(1+3+…+49)的和
1 #!/bin/bash 2 #定义变量 3 sum=0 4 for ((i=1;i<=100;i++));do 5 # 当i为奇数时,继续执行 6 if [ $[i%2] -eq 1 ];then 7 # 当i=51时,跳出整个循环 8 if [ $i -eq 51 ];then 9 continue 10 fi 11 let sum+=$i 12 fi 13 done14 echo sum=$sum15 16 #删除变量 17 unset i sum
2.5.2 循环控制命令shift   位置参数可以用shift命令左移,比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1,$2,$3丢弃,$0不移动。不带参数的shift命令相当于shift 1。
   我们知道,对于位置变量或命令行参数,其个数必须是确定的,或者当shell程序不知道其个数时可以把所有参数一起赋值给变量$*。当用户要求shell在不知道位置变量个数的情况下,还能逐个的把参数一一进行处理,也就是在$1后为$2等。在shift命令执行前变量$1的值在shift命令执行后就不可用了。
example:
1)测试shift命令
1 #!/bin/bash 2 until [ $# -eq 0 ];do3 echo the first argument is:$1,the number of arguments is:$#4 shift5 done
2.5.3 信号捕捉trap   trap是一个shell内建命令,它用来在脚本中指定信号如何处理。比如,按ctrl+c会使脚本终止执行,实际上系统发送了sigint信号给脚本进程,sigint信号的默认处理方式就是退出程序。如果要在ctrl+c不退出程序,那么就得使用trap命令来指定一下sigint的处理方式了。trap命令不仅仅处理linux信号,还能对脚本退出(exit)、调试(debug)、错误(err)、返回(return)等情况指定处理方式。
   基本格式语法如下:
   trap ‘触发指令’ 信号   自定义进程收到系统发出的指定信号后,将执行触发指令,而不是执行原操作
       trap ‘’ 信号   忽略信号的操作
   trap ‘-’ 信号   恢复原信号的操作
       trap -p   列出自定义信号的操作,即提示当前使用的trap操作是什么。
注意:①信号的表示方法:可以是完整信号/简写/数字(具体内容通过kill -l查询)
②信号9,强制杀死,捕获不到。
example:
1)打印0-9,ctrl+c终止无效
1 #!/bin/bash 2 #设置信号捕获 3 trap 'echo press ctrl+c' 24 for ((i=0;i<10;i++));do5 sleep 16 echo $i 7 done
2)打印0-9,3之前ctrl+c不能终止,3之后恢复,能终止
1 #!/bin/bash 2 #设置信号捕获 3 trap '' 2 4 trap -p 5 for ((i=0;i<3;i++));do 6 sleep 1 7 echo $i 8 done 9 trap '-' sigint 10 for ((i=3;i /dev/null && \ 11 echo $ip$i is up 12 }& 13 done14 wait15 16 #删除变量 17 unset net ip i
三、小补充      介绍了这么多语法,我们来玩一些好玩的吧~下面是小编给大家分享的几个有意思的脚本
1)打印等腰三角形(带闪烁)
1 #!/bin/bash 2 #num=总行号 i=第几行 j=*个数 k=空格个数 3 read -p 请输入一个数字: num 4 for i in `seq 1 $num`;do 5 for k in `seq 1 $[$num-$i]`; do 6 echo -n 7 done 8 for j in `seq 1 $[2*$i-1]`;do 9 if [ $j -eq 1 ] || [ $j -eq $[2*$i-1] ] || [ $i -eq $num ];then10 color=$[random%5+31] 11 echo -en \033[1;$color;5m*\033[0m12 else13 echo -n *14 fi 15 done16 echo17 done18 19 #删除变量 20 unset num i j k color
具体的效果大家可以自己去尝试,就是下面两张图配合出来的效果:
2)打印国际象棋棋盘
1 #!/bin/bash 2 #定义变量 3 color_1=\033[1;44m \033[0m 4 color_2=\033[1;45m \033[0m 5 for (( i=1;$i <=8;i++ ));do 6 for (( j=1;$j <=8;j++ ));do 7 if [ $[$i%2] == 1 ] && [ $[$j%2] == 1 ];then 8 echo -en $color_1$color_2 9 elif [ $[$i%2] == 0 ] && [ $[$j%2] == 0 ];then10 echo -en $color_2$color_111 fi 12 done13 echo14 done15 16 #删除变量 17 unset color_1 color_2 i j
具体的颜色大家可以根据自己的喜好来调整~

电磁理论及涡旋电磁波技术的公式原理解析
云计算与DevOps的异同及应用综述
Chrome 88新版来袭:修复重要安全漏洞
重庆两江人工智能学院正式挂牌 明年添加新专业
将机器改造为具有IoT功能是一种有效的方法
shell脚本进阶 详解及其实例
采用温度传感器和TLC272设计的接近检测器电路
苹果为何布局汽车领域?
消费者应注意数字电视病毒风险
「方案分享」物联网智能家居无线传输解决方案
海康威视:绝大多数美国器件均可替代,必要时可自研
深度学习怎么实现图像到图像的翻译
全新智能化妆镜,带你感受一种不一样的化妆体验
学校宿舍预付费售电管理系统 时控费控负控
磁盘被写保护怎么办?u盘写保护怎么去掉?
华为哈勃投资ToF传感器厂商:芯视界
导热氧化铝填料如何搭配才能获得高导热硅胶?
如何提高C++性能的编程技术
C++基础语法梳理之Windows 的动态链接库
园区环境监测系统介绍