Linux学习第二十七篇--脚本的条件判断和循环

前言

个人感觉这一部分,应该是相当重要的一部分了,前面很多地方,如果我们记得不是很清楚还可以通过查看文档来解决,但是这一部分,可以说是脚本的基础了,这一部分要是不会,那。。。麻烦了。。。本来学习linux目的是为了提高自己的竞争力,结果人问你一句怎么遍历一个数组,你回答不上来,是不是很尴尬。。。
作为一个程序,别的不说,你至少得有个逻辑判断,能够实现根据用户的不同选择,做出不同的动作,从而实现不同的结果。
这篇blog主要说的就是这么一个功能。

简单的逻辑判断表达式

其实我们之前学了好几个逻辑判断表达式了,比如&&和||这种连接多个命令的判断,还有${变量:-默认值}这种为控制赋值的表达式,还有awk命令中的表达式,等等。
这里再学一个比较好玩的逻辑判断,test命令。
test命令可以用来检验文件的类型以及比对值。
比如,我们之前进行创建文件的时候通常会使用这种命令来执行。
ls 文件名|| touch 文件名
现在我们出现了一种替代的方式,我们可以通过
test -e 文件名
这种方式来判断文件是否存在,这里需要注意的是test -e 这种方式并不会输出具体的内容,但是我们可以通过他的回传值来做处理,比如:
test -e 文件名||touch 文件名
貌似看起来更复杂了一点,但是我们可以配合待会学到的条件判断语句来使用,但是在这之前,我们还是要先学会应该怎么用test命令。

test判断文件相关选项

其实这些选项还是比较容易记忆的,大多数都是一些单词的缩写。
-e判断文件是否存在(exist)
-f判断文件是否存在且是一个文件(file)
-d判断文件是否存在且是一个目录(direct)
-b文件存在且是一个块装置文件(block)
-c文件存在且是一个字符装置文件(character)
-S文件存在且是一个Socket文件(Sockte)
-P文件存在且是一个Pipe文件(Pipe)
-L文件存在且是一个符号链接文件(Link)

test判断文件权限相关

-r文件存在且当前用户具有读权限(read)
-w文件存在且当前用户具有写权限(write)
-x文件存在且当前用户具有执行权限(execute)
-u文件存在且具有SUID权限
-g文件存在且具有SGID权限
-k文件存在且具有Sticky bit权限
-s文件存在且改文件为空白文件

test判断两个文件的关系

命令格式 test 文件1 【选项】 文件2
-nt判断文件1是否比文件2新(new than)
-ot判断文件1是否比文件2旧(old than)
-ef判断文件1和文件2是否指向同一个inode节点(我猜是不是equals file的缩写)

test判断两个数值的大小

命令格式 test 数字 【选项】数字
-eq两个数值相等(equals)
-ne两个数值不相等(not equals)
-gt第一个数大于第二个数(greater than)
-lt第一个数小于第二个数(less than)
-ge第一个数大于或等于第二个数(greater than or equals)
-le第一个数小于或等于第二个数(less than or equals)

test判断两个字符串的关系

命令格式test 字符串 【选项】字符串    PS:需要注意的是,空字符串表示为0.
-z字符串是否为0?(zero)
-n字符串是否非0?(not zero)
==两个字符串是否一致?
!=两个字符串是否不一致?

test的多重条件判断--逻辑判断

-a表示和,-a两边的表达式同时返回0,才返回0(and)
-o表示或者,-o两边的表达式有一个返回0就返回0(or)
表示非,不。将!后的表达式结果去相反的结果,比如之前为0,加上!,则表示不为0.
看起来test选项挺多的样子,其实如果真的静下心来敲一遍的话,你会惊讶的发现,貌似规律太明显,为什么辣么好记。。。
当然,我相信,过不了几天我就会又忘了。但是没关系,至少我有个大致的印象了,以后用多了自然而然就记住了。

号外号外....
在linux中还可以使用[]来代替test哟,比如我们可以通过 [ 5 -gt 3 ]来代替test 5 -gt 3 ,需要注意的是在中括号内每一个元件都要使用空格分开,包括元件和中括号之间.
脚本的默认变量

我们已经学习了可以和用户交互的命令read,但是通过read有一个缺点,用户执行完命令后,还要再根据提示输入所需的参数,那么我们可不可以实现类似我们之前使用的ls -l这种将参数直接跟在命令后面的形式呢?

和其他编程语言不同,这种跟在指令后面的参数,在脚本里,我们不需要自己定义,我们可以通过$n的形式来获取第n个参数.

比如:


注意看上图,var.sh的第二行和第三行,这里我们通过$0的形式输出了指令的名称,使用$1来输出我们第一个变量(nihao),一次类推,$2表示第2个参数...

除了$数字的形式,还有三个比较特殊的变量.

$#.通过$#可以获取当前命令后面跟的参数的个数.

$@表示获取所有的参数.

$*也表示获取素有的参数,和$@展示形式不一样.

写个脚本看一下.


然后测试一下:


默认变量的偏移

在脚本厉害还有一个挺好玩的东西,也是关于默认变量的,我们可以通过shift n 的形式删除掉前面n个变量,如果只写shift不写数字的话,表示删除一个变量.
额,做个试验,说起来感觉怪怪的.

看下执行结果.


看画红框的地方,是不是第一个变量没了,看起来挺好玩的,但是我还没有想到应用场景.

条件判断语句ifthen

终于到最好玩的地方了,记录这篇blog的时候,我老是想要跳过前面的内容,直接写这个位置,毕竟前面的太枯燥了.
简单的条件判断语句,主要记住两个关键词if和then.
具体怎么用呢.
if[条件判断式]; then 怎么做 fi.这里的fi是if反过来,表示结束这个if.
看个例子


当然是用原生的test也是可以的.

如果使用中括号的形式,可以使用&&代替-a选项,使用||代替-o 选项.
比如:

用什么样的方式,按照个人习惯吧,我个人还是比较喜欢中括号的形式,和以前学过的编程相似度高一点.
下面写一个小例子玩一下,还是之前的计算器吧,

我试了一下这个小例子,发现一个问题,就是乘法的时候,传递的不是*号本身,还是当前目录所有文件名,这个很尴尬,最前面的#@目的是为了打印出参数.
可以通过\* 来使用功能,获取结果,当然也可以修改乘法的符号,比如换成字母X.
这样一个简单的小计算器就实现了,不过这么多判断,好多if,是不是有点过分了,而且,在判断使用的计算方法时,这四个方法他们是不可能同时存在的,我们完全可以提出来,
这样,就用到了if...then...elif...else....fi多重条件判断,看起来稍微复杂了,其实和之前还是一样的,没有多难.

多重条件判断

多重条件判断如果用俗语说的话,就是,当怎样怎样的时候,我们就怎么做,或者当怎样怎样的时候,我们这么做,不然,我们就怎么做.
个人感觉应该还算是比较简单的.
下面搞一个最简单的练练手.

目测看起来,也没有什么难的.下面试一下书中的例子,通过netstat来判断当前主机启动的服务.
netstat命令用来显示网络链接,路由表,接口状态,伪装链接,网络链路信息和组播成员组,听起来非常高大上,接下来我们会使用到他的t,u,n,l选项,所以这里先看一下这几个选项的作用.
t选项表示显示tcp链接,
u选项表示显示udp链接,
n表示显示IP地址,而不是主机名称.
l表示显示正在监听的服务.
先不使用书里的脚本,按照自己的思路来一份.先看看本机启动的服务.

先看一下前两行数据,其实有点类似于标题和列名,所以对于我们分析数据来说是用不到的.
然后我们主要是看一下有没有启动22SSH服务,和80网络服务,所以我们要对这些数据剔除第二行然后使用空格分割取第三部分,然后判断里面的内容是否有22端口或者80端口.然后打印出数据.
 netstat -utnl|awk '{if (NR>2){print $4}}'|awk -F ':' '{ print $2}'|grep ^[1-9]
写一个shell判断是否启用了服务.

执行下,看看效果:

ok,通过这个shell基本就了解了用法.这一块是条件语句的学习,
条件语句还有一种类型.case in.

分支语句

先看一个比较简单的shell.然后在理解case in.

上图这是一个比较简单的case...in的示例,
先说一下他的作用,在我们日常生活中case通常表示一种状况.case...in..语句的含义就是,当..处于某一种状态的情况下.要怎么去做.
这个命令的格式是这样的:
case 变量 in
变量内容)
;;
esac
看第一行,这里的变量其实就是我们用来比较多数据,就像上图中的$1,我们主要是处理这个变量的各种状况.in 表示后面跟的是状态,比如上图的nihao,注意nihao后面还有一个),这个反括号是不能被省略的哟.而在反括号后面就可以跟处理这种状况的语句了,当出现;;的时候表示这种状况结束,注意这里是两个分号.
这样,我们尝试分析一下上图中,表示当$1这个变量的值是nihao的时候,我们就打印出依据hello.
比较容易理解吧.
这样,下面我们修改一下之前的计算器,实际使用case in 操作一下.

注意看上图中倒数第五行,那个*表示默认,如果上面的条件都不满足的话,就会走这个默认的。
效果没啥意思,就不演示了。

函数式编程

不知道有木有学过javaScript,或者其他编程语言,在js中我们可以通过

function 方法名(参数列表){

函数内容

}

这种方式来定义一些方法块,在需要使用的时候只要通过方法名(参数)这种形式就可以调用定义的这个方法了,在linux中也支持这种函数式的编程。

他的格式类似于js,

function 方法名(){

操作

}

需要注意的是,linux的函数式编程并没有参数列表,我们在使用参数的时候可以通过$n这种方式来获取第n个参数。

下面 我们改写一下上文中的计算器,使用函数式编程。

看一下之前的代码,我们可以提取出校验数字内容的方法和casein方法。


不过还有点需要注意的地方是,我们自定义的函数必须卸载最前面。这点和js是不同的!

ok,截止到目前为止,还都是相对比较简单的。虽然接下来的也很简单.

循环

在编程中,肯定不可能只有条件分支语句,还要有循环语句.循环语句的作用就是在满足某些条件下一直重复的做一些事.

在我们linux脚本中,有三种常用的循环方式,分别是:

1.while do done

2.until do done

3.for  do done

分别看一下这三种循环的用法.

while循环

先看一个小例子.


while循环好像没啥好说的,只要说一下他的结构就好了.

while [条件]

do

    做一些操作

done.

用于,当满足某一些条件的时候,就进行一些操作.

unitl循环

unitl [条件]

do

    做一些操作
done.
用于,当满足条件的时候才停止循环.不然就一直执行动作.

看这个两个循环,他们有一个共同的特点,就是他们循环的次数是不确定的,可能在第一次循环的之后,他就停了,也有可能在一万次循环之后,他还健在.
我们讲这种循环成为不定循环.

当然除了不定循环,我们还有次数固定的循环方式.

for循环

对于for循环有两种方式.
第一种方式是:
for 变量 in 集合
do 做一些操作
done
做一个简单的小例子.

貌似也挺简单的.

另一种形式.


要注意上面的是双括号...

这种形式的结构是这样滴:

for((初始值;限制条件;执行步阶))

do

  一些操作

done

可以看着上图的实例来理解.

到这的话,我们就学完了条件判断和循环.接下来用这两个做一个小训练,巩固一下.


画个菱形

分析


看上图这个菱形,这个是我们想要得到的结果,看看他有什么规律

看上图可以发现将菱形分为两部分,一部分是正三角,一部分是倒三角.
下面根据这个规律画一下.


上面就是绘制菱形的代码了。
再贴一份代码
#!/bin/bash
#定义一个绘制的函数
function draw(){
#无参数则跳出
  test -z $1&&exit 1;
#判断绘制正三角还是倒三角
  line=1;
#控制打印的次数,即菱形的高度
  while [ "$line" -le "$1" ]
#!/bin/bash
#定义一个绘制的函数
function draw(){
#无参数则跳出
  test -z $1&&exit 1;
#判断绘制正三角还是倒三角
  line=1;
#控制打印的次数,即菱形的高度
  while [ "$line" -le "$1" ]
  do
  content="";
#计算出菱形中间的位置(所处行数)
  let mid=$1/2+1;
  if [ "$line" -le "$mid" ];
  then
#先拼接空格,计算出空格数量
    let blank_number=$1+1-2*$line;
    for((b=0;b<$blank_number;b++))
    do
      content=$content" ";
    done
#拼接*号,计算出*号的个数
    let start_number=2*$line-1;
    for ((s=0;s<$start_number;s++))
    do
      content=$content"* ";
    done
#绘制倒三角
  else
#计算空格数量
   let "blank_Number=2*($line-($1/2+1))";
#拼接空格
    for((b=0;b<$blank_Number;b++))
    do
      content=$content" ";
    done
#计算*号的数量
    let start_Number=2*$1-2*$line+1;
#拼接*号
    for((s=0;s<$start_Number;s++))
    do
      content=$content"* ";
    done
  fi
#输出这一行的内容  
  echo -e "$content";
  let line++;
  done
}
#调用绘制菱形方法
declare -i height;
test -z $1&&height=5||height=$1;
#因为上面方法的规律是针对奇数高度的菱形,所以如果用户输入的是偶数,还要在处理一下。
[ $(($height%2)) -eq 0 ] && height=$(($height+1));
draw $height;
到这基本就学完了shell的基本编写。
因为写这篇blog的时候,项目已经启动了,所以前前后后用了一个多周才写完这篇blog。

sh脚本的debug

sh命令好像还很简单的,之前想专门写一遍blog记录一下的,最后想了想就那么点东西的话,还是放在这儿吧。
sh -n  脚本,编译指定脚本,检查语法错误。
sh -v  在执行脚本前,将脚本的内容输出出来。
sh -x 执行脚本,并输出脚本的执行过程。
虾米?看不懂?试一下就知道了。。。。so easy。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值