shell循环与函数

刚开始没有服务器的时候,用脚本做监控

后期有服务器了之后,用监控软件进行监控

1、循环语句

在实际工作中,经常会遇到某项任务需要多次执行的情况,而每次执行时仅仅是处理的对象不一样,其他命令相同。例如,根据通讯录中的姓名列表创建系统账号,根据服务器清单检查各主机的存活状态

2、 for循环(以次数循环)

以次数循环 , 依次将列表中的元素(变量和命令)赋值给变量名 , 每次复制后会执行一个循环体 , 直到列表中的元素耗尽 , 循环结束

1.1语法结构


(1)列表循环

(3)类C风格的for循环

遍历
for 变量名 in {list}
do
    command
done

for i in {a..c}
do
        echo $i
done

for i in {1..5}         //{}里面不识别变量
do
        echo $i
done


for i in `seq 5`      //seq 5=1、2、3、4、5序列
do      
        echo $i
done

a=10
for i in `seq $a`     //seq可以引用变量
do
        echo $i
done


for 变量名 in a b c
do
    command
done

for i in a b c   //i这里实际没有调用,所以就相当于in后面几个参数就循环几次
do
        echo 123
done

for i in a b c    //这里调用到i变量了,所以就正常显示i的值(a\b\c)
do
        echo $i
done

案列

例1:打印1-5这5个数字

[root@server ~]# vim for.sh

#!/bin/bash

for i in {1..5}
  do
        echo $i
  done

例2:打印5次hello world
注意:虽然我们定义了一个变量i,但是没有使用它,它只是控制循环次数

[root@server ~]# vim for.sh

#!/bin/bash

for i in {1..5}
  do
        echo hello world
  done

例3:打印abcde

[root@server ~]# vim for.sh

#!/bin/bash

for i in a b c d e
  do
        echo $i
  done

例4:输出0-50之间的偶数

[root@server ~]# vim for1.sh

#!/bin/bash
for i in {0..50..2}  //..2代表步长为2,每隔2个
do
        echo $i
done

附1小技巧:花括号{}和seq在for循环的应用:

for i in {1..50..2}        1-50的奇数

for i in {2..50..2}        1-50的偶数

for i in {10..1}            1-10倒序排列

for i in $(seq 10)       1-10正序排列

for i in $(seq 10 -1 1)    1-10倒序排列

for i in $(seq 1 2 10)     1-10的奇数,中间为步长

for i in $(seq 0 2 10)     1-10的偶数,中间为步长

(2)不带列表循环

不带列表循环执行时由用户指定参数和参数的个数决定的

for 变量名 
do
    command
done


例1:打印hello

#!/bin/bash
for i
do
        echo hello
done

[root@server ~]# . for2.sh   //没有给脚本传参所以执行了没有结果

[root@server ~]# . for2.sh a   //把a赋值给变量i,i有值了它就开始执行do..done了
hello



for i
do
        echo $i
done
[root@client ~]# bash for.sh hello
hello


(3)类C风格的for循环

for ((expr1;expr2;expr3))
do
       command
done

expr1:定义变量并赋初值
expr2:决定是否循环
expr3:决定循环变量如何改变,决定循环什么时候退出

例1:打印1-5
迭代
[root@server ~]# vim for3.sh
#!/bin/bash
for ((i=1;i<=5;i++))
do
     echo $i
done


注:i++ : i=1+1 先赋值再运算 i=1 之后 再 +1
       ++i : 1+1=i 先运算再赋值 1+1 之后 再=i

例2:打印1-10的奇数

[root@server ~]# vim for3.sh
#!/bin/bash
for ((i=1;i<=10;i+=2))   //i=i+2
do
     echo $i
done

附2:类C风格运算符用法
++    自身变量+1
--      自身变量-1
+=5    自身变量+5
-=5     自身变量-5
*=5     自身变量*5
/=5     自身变量/5
%=5    自身变量%5

例3:计算1-100的奇数和

[root@server ~]# vim for3.sh 

#!/bin/bash
sum=0
for ((i=1;i<=100;i+=2))
do
     let sum=($i+$sum)
done
echo "1-100的奇数和为:" $sum

[root@localhost for]# sh for3.sh
1-100奇数和为 2500

案例:
例1、批量添加用户两种方式

①以后缀批量变化添加
for i in {1..5}
do
        useradd stu$i
        echo "123" | passwd --stdin stu$i
done

②脚本批量添加用户
#!/bin/bash
USERS=$(cat /root/users.txt) 

for UNAME in $USERS
do
useradd $UNAME
echo "123456" | passwd --stdin $UNAME &>/dev/null 
done

例1、批量删除用户的脚本

vim udelfor.sh    

#!/bin/bash
ULIST=$(cat /root/users.txt) 
for UNAME in $ULIST
do
userdel -r $UNAME &>/dev/null 

done

例2、根据 IP 地址列表检查主机状态,
-c 发送包的数量;-i 发送 ping 包间隔;-W 超时时间
①根据文本查看

#!/bin/bash
HLIST=$(cat /root/ipadds.txt)
for IP in $HLIST
do
ping -c 3 -i 0.2 -W 3 $IP &> /dev/null

if [ $? -eq 0 ] then
    echo "Host $IP is up."
else
    echo "Host $IP is down."
fi 
 done


②根据段查看
 network="192.168.10"
for addr in {1..254}
do
ping -c 2 -i 0.5 -W 3 $network.$addr &> /dev/null
        if [ $? -eq 0 ];then
        echo "$network.$addr is up"
        else
        echo "$network.$addr is down"
        fi
done

#!/bin/bash
#需求:用户输入密码,脚本判断密码是否正确,输入正确提示正确信息,连续输入错误3次报警
#1、定义输入次数变量
for i in {1..3}
do
  read -p "请输入密码(仅数字):" PD
  if [ $PD -eq 123 ];then
    echo "密码正确"
    exit
  else
    echo "密码错误,请重新输入"
  fi
done
echo "输入错误3次,报警了奥"

#幸运会员

a=0
b=0
c=0    //3个用户


for ((i=1;i<=12;i++))
do
  NUM=$(expr $[ RANDOM%3+1 ])     //1-3 而不是 0-2
  或
  NUM=$[ RANDOM%3+1 ]    //有时候可能会报错
  LT=$(cat /opt/name.txt|grep "$NUM"|awk -F: '{print $2}')
  case $LT in
    zhangsan)
      let a++
    ;;
    lisi)
      let b++
    ;;
    wangwu)
      let c++
    ;;
    *)
      let d++
  esac  
done
echo "zhangsan:$a,lisi:$b,wangwu:$c"

2.while循环语句的结构(周期性重复操作)

while循环一般用于有条件判断的循环 , 判断条件为真 ,则进入循环 ,当条件为假 ,则跳出循环


while循环
1、语法结构
2、死循环

2.1 语法结构

while 表达式
do
    command
done

例1:打印1-5

[root@server ~]# vim while.sh
#!/bin/bash
i=1
while [ $i -le 5 ]
do
    echo $i
    let i++   //注意这里如果不改变$i的值,会变成死循环
#    i=$[$i+1]  //两种写法
done
echo "最后i的值为: $i"

例2:输出1-100之间不能被3整除的数字

[root@server myscripts]# vim 33.sh 

#!/bin/bash
i=1
while [ $i -le 100 ]
 do
 if [[ $i%3 -ne 0 ]]
 then echo "$i"
 fi
 let i++
done

例3:打印1-100的和
#!/bin/bash
i=1
sum=0
while [ $i -le 100 ]
do
        let sum=$i+$sum           //前面一定要加let,+前后不要空格
        let i++
done
echo $sum

 

例4:监控某服务(httpd)运行状态

while ps aux | grep httpd | grep -v grep &> /dev/null
do
echo "httpd 正在运行中"
sleep 2              //每隔2秒执行一次
done
echo "httpd 不在运行"

2.2 while死循环

表达式永远为真,脚本一直运行下去,占用内存,别弄!

while [ 1 -eq 1 ]  //写一个永远为真的表达式,1等于1这个条件永远为真,所以这个脚本会一直循环下去
do
    command
done


while true
do
    command
done


while :
do
    command
done

例1:猜数字,猜不对就一直猜
num=10
while true
do
read -p "请输入数字:" shu
if [ $shu -eq $num ];then
        echo "你猜对了"
        break
elif [ $shu -gt $num ];then
        echo "你猜大了"
elif [ $shu -lt $num ];then
        echo "你猜小了"
fi
done

例2
1.批量添加规律编号的用户
#!/bin/bash
USERS="stu"
i=1
while [ $i -le 20 ] 
do
useradd ${USERS}$i
echo "123456" | passwd --stdin ${USERS}$i &> /dev/null 
let i++
done

例3
猜商品价格游戏
$random用于生成0—32767的随机数

第一种方法

#!/bin/bash
PRICE=$(expr $RANDOM % 1000)
a=0
echo "商品实际价格范围为 0-999,猜猜看是多少?" 
while true
do
read -p "请输入你猜测的价格数目:" n 
let a++
if [ $n -eq $PRICE ] ; then
echo "恭喜你答对了,实际价格是 $PRICE" 
echo "你总共猜测了 $a 次"
exit 0           //一定要退出,否则一直循环
elif [ $n -gt $PRICE ] ; then
 echo "你猜高了!"
else
echo "你猜低了!"
fi 
done


第二种方法
#!/bin/bash
sorce=$[$RANDOM % 1000]
a=1
num=0
while[ $a -lt 2 ]
do
read -p "请输入你猜的价格(1-999之 间) :"  price
if [ $price -eq $sorce ] ; then
echo "恭喜你猜对了!"
let num++
let a++
elif [ $price -gt $sorce ] ; then
echo "你猜高了!"
let num++
elif[ $price -lt $sorce ] ; then
echo "你猜小了!"
let num++
fi
done
echo "你一共猜了$num次!"

 

例4 、实时监控本机内存和硬盘剩余空间,剩余内存小于500M、根分区剩余空间小于1000M 时,发送报警邮件给 root 管理员(500*1024=512000 、1000*1024=1024000)
#!/bin/bash
#提取根分区剩余空间
disk_size=$(df / |awk '/\//{print $4}')
#提取内存剩余空间
mem_size=$(free |awk '/Mem/{print $4}') 
while :             //一直循环
do
#注意内存和磁盘提取的空间大小都是以Kb 为单位
if [ $disk_size ‐le 512000 -a $mem_size ‐le 1024000 ];then 
mail ‐s Warning root <<EOF
Insufficient resources,资源不足EOF
fi 
done

例5 定义网卡流量
#!/bin/bash
 
#定义流量单位
DW=kb/s
 
while :
do
    #定义某一时间点的提取网卡流量数值,我这里的网卡是ens33
    OLD_IN=$(cat /proc/net/dev |  awk '$1~/ens33/{print $2}')
    OLD_OUT=`cat /proc/net/dev | awk '$1~/ens33/{print $10}'`
    sleep 5
 
    #定义下一个时间点的提取网卡流量数值。
    NEW_IN=$(cat /proc/net/dev | awk '$1~/ens33/{print $2}')
    NEW_OUT=`cat /proc/net/dev | awk '$1~/ens33/{print $10}'`
 
    #进行流量的计算,默认是Bytes,转换成kb/s
    IN=$[$[$NEW_IN - $OLD_IN]/1024]$DW
    OUT=$[$[$NEW_OUT - $OLD_OUT]/1024]$DW
    sleep 5
 
    #打印对应的值
    echo -e "接收数据:${IN}\t发送数据:$OUT"

#!/bin/bash
i=1
sum=0
while [ $i -le 5 ]
do
  echo "进入第$i家商店"
  read -p "是否进入看看(yes/no)" doing
  while [ $doing = "yes" ]
    do
       echo "1:衣服¥200"
       echo "2:鞋子¥150"
       echo "3:手套¥40"
       echo "4:裤子¥155"
       read -p "请选择需要购买的商品序列:" num
       case $num in
           1)
             echo "衣服购买成功"
             expr $[sum+=200] &> /dev/null
           ;;
           2)
             echo "鞋子购买成功"
             expr $[sum+=150] &> /dev/null
           ;;
           3)
             echo "手套购买成功"
             expr $[sum+=40] &> /dev/null
           ;;
           *)
             echo "裤子购买成功"
             expr $[sum+=155] &> /dev/null
      esac
      read -p "是否继续进行购买(yes/no)" doing


   done
   let i++
   if [ $doing = "no" ]
     then
     continue
   fi
done
   echo "购物总价:$sum"


3.until循环


跟while相反,条件为假进入循环,条件为真退出循环
语法结构
until 表达式
do
    command
done


例1:计算1-50的和1275两种写法第一种======

#!/bin/bash
i=0;s=0
until [ $i -eq 51 ] 
do
let s+=i    #s+=i,等价于s=s+i,使用加赋值
let i++    
done
echo $s

第二种
vim 50.sh
#!/bin/bash
i=1
sum=0
until [ $i -eq 51 ]   //这里注意如果是50的话条件为真循环结束它计算的是1-49的和,until [ $i -gt 50 ]也行
  do
  sum=$[$i+$sum]
  let i++
  done
echo "$sum"

死循环结构
until false
do
    command
done

until [ 1 -ne 1 ]
do
    command
done

案例2、登录zhangsan用户 使用root 发消息给zhangsan   ================

#!/bin/bash
username=$1
#判断信息格式
if [ $# -lt 1 ];then
  echo "Usage:`basename $0` <username> [<message>]" 
  exit 1
fi
#判断用户是否存在
if grep "^$username:" /etc/passwd >/dev/null ;then : 
else
   echo "用户不存在"
   exit 1
fi

#用户是否在线,如果不在线每5秒联系一次
until who|grep "$username" >/dev/null
do
    echo "用户不存在"
        sleep 5
done

mes=$* 
echo $mes | write $username


注:测试时切换下用户

4、循环控制语句


for循环一般会搭配条件判断语句和流程控制语句一起执行,那么就会出现需要跳过循环和中止循环的情况,控制循环的命令有以下3个

4.1 continue


继续,但不会执行循环体内下面的代码了,开始重新开始下一次循环

例1:打印1-5的数字,3不打印

[root@server ~]# vim for4.sh

#!/bin/bash
for ((i=1;i<=5;i++))
do
        if [ $i -eq 3 ];then
        continue            //  退出当前 一次 循环,继续for循环
        else
        echo $i
        fi
done
结果是1245,3不输出,因为跳出后面的echo语句执行下一次循环了

4.2 break


打断,马上停止本次循环,执行循环体外的代码

例2:1-10的数字,7后面的都不打印

[root@server ~]# vim for4.sh

#!/bin/bash
for ((i=1;i<=10;i++))
do
        if [ $i -eq 8 ];then
        break               //跳出当前for循环
        else
        echo $i
        fi
done


4.3 exit


直接跳出程序,后面可跟状态返回码如exit 1等等

for i in {1..5}
do
if [ $i -eq 3 ];then
        exit  100             //整个退出
else
        echo $i
fi

done
echo hi
直接跳出程序所以不会执行最后的echo hi,并且返回码是100通过$?查看

1

2


5、shell函数


函数的作用

5.1 函数的定义(两种方式)


1
function 函数名 {
command
}       //这是一种规范写法

2
函数名(){     //最常用因为最简洁
command

函数定义完之后并不会自动执行,需要调用才行,好处在于可以写一段功能代码作为函数,有需要就直接调用
定义的时候哪怕出现语法错误也没关系,不调用就不会报错
当然我们写函数最终目的还是为了调用,为了实现某个功能块


函数返回值:
return表示退出函数并返回一个退出值,脚本中可以用$?变量显示该值
使用原则:
1、函数一结束就取返回值,因为$?变量只返回执行的最后一条命令的退出状态码
2、退出状态码必须是0~255,超出时值将为取余256 

444 % 256

5.2 函数的调用


直接在脚本里定义函数的代码块后写函数名即可完成调用

#!/bin/bash
function fun1 {     //定义了一个函数叫做fun1
echo "this is a function!"    //函数体的功能是打印"this is a function!
}

fun1    //直接写函数名就会运行函数体内的代码

[root@server myscripts]# . fun.sh
this is a function!
-----------------------------------

注意①:函数名必须是唯一,如果先定义了一个,再用同样的名称定义,第二个会覆盖第一个的功能,出现了你不想要的结果,所以这里一定要注意不要重名!
#!/bin/bash
f1 (){
echo hello
}

f1 (){
echo world
}

f1
[root@localhost ~]# . f1.sh 
world
---------------------------------------
注意②:调用函数之前必须先进行定义!

#!/bin/bash
f1 (){
echo hello
}


f3 (){
echo "$(f1) $(f2)"
}

f2 (){
echo world
}

f3
------------------------------------------
[root@localhost ~]# bash f1.sh   //因为f3函数里调用了f2,调用了f3的时候并不能知道f2的定义,因为f2在f                                                      运行之后才被定义,所以运行的脚本会报错
f1.sh:行8: f2: 未找到命令
hello 


#!/bin/bash
f1 (){
echo hello
}


f3 (){
echo "$(f1) $(f2)"    //这里虽然提前调用了f2,但是f2的函数还是在运行f3之前定义的所以他能够找到
}


f2 (){
echo world
}

f3


注意③:不一定要在脚本开头就定义函数,只要调用之前定义就可以

--------------------------------------------
如果是在其他地方嵌套调用等情况,不可以直接写函数的值,避免无法识别,可以用反撇号引起来,相当于是调用函数的结果
#!/bin/bash
f1 (){
echo hello
}

f2 (){
echo world
}

f3 (){
echo "`f1` `f2`"    //这里如果直接是f1和f2的话,打印出来的不会是hello world而会是f1 f2
}

f3
------------------------------


cat <<EOF >/etc/yum.repos.d/local.repo
[local]
name=local
baseurl=file:///mnt
enabled=1
gpgcheck=0
EOF

vim localrepo. sh
#!/bin/bash
function backuprepo {
cd /etc/yum.repos.d
mkdir repo.bak
mv * .repo repo.bak
mount /dev/sr0 /mnt > /dev/null
}

makelocalrepo () {

cd /etc/yum.repos.d
echo '[local]
name= local
baseurl=file: ///mnt
enabled=1
gpgcheck=0' > local.repo

}

uselocalrepo (){
yum clean all > /dev/null
yum makecache > /dev/null
yum install -y httpd > /dev/null

if [ $? -eq 0 ];then                  可以加个判断

  echo "yum源更新完成"

else


}
######main#######
backuprepo
makelocalrepo
uselocalrepo

--------return---------
#!/bin/bash
function test1 {
read -p "请输入一个数字" num
return $[$num*2]
}
test1
echo $?


test2 () {
read -P "请输入值2:" NUM
echo $[$NUM*2]
}
res=$(test2)
echo $[$res *2]


5.3 函数传参

1.两个数求和
#!/bin/bash 
sum(){
read -p "请输入第一个数:" NUM1 
read -p "请输入第二个数:" NUM2
echo "你输入的两个数为: $NUM1 和$NUM2 "
SUM=$(( NUM1+$NUM2))
echo “两个数的和为: $SUM”
}
sum

5.4 函数的作用范围


在 Shell 脚本中函数的执行并不会开启一个新的子 Shell,而是仅在当前定义的 Shell 环境中有效。如果Shell脚本中的变量没有经过特殊设定,默认在整个脚本中都是有效的。在编写脚本时,有时需要将变量的值限定在函数内部,可以通过内置命令local来实现。函数内部变量的使用,可以避免函数内外同时出现同名变量对脚本结果的影响。

shell脚本中变量默认全局有效
local命令:将变量限定在函数内部使用

[root@localhost ~]# vim myfun.sh
myfun ()
{
local i 
i=8              //函数内部
echo $i
}

myfun 
i=9            //全局
echo $i

上述脚本中myfun 函数内部使用了local命令设置变量i,其作用是将变量i限定在函数内部。myfun 函数外部同样定义了变量i,内部变量i和全局变量i互不影响。脚本执行时先调用了函数myfun,函数内部变量i为8,所以输出结果是8。调用完函数之后,给变量i赋值为9,再打印外部变量i,所以又输出 9

myfunc() {
a=8 
echo $a
}
myfunc
echo $a

#!/bin/bash
myfunc() {
a=8
echo $a

}
myfunc
a=9
echo $a I

5.5 函数的参数


函数的传参


函数的参数
计算位置变量$1和$2的和
#!/bin/bash
add (){
let sum=$1+$2   //这里的位置变量是函数的位置变量,所以要写在调用函数的后面,如果是调用脚本时使用则                           不能成功
echo $sum
}

add 4 5

脚本的参数
#!/bin/bash
add (){
let sum=$1+$2
echo $sum
}

add $1 $2   //这里相当于调用了脚本的参数了,然后把脚本的位置变量传递给函数进行计算


通过脚本传递参数给函数中的位置参数$1 
#!/bin/bash
fun1(){
rm -rf $1
}
fun1 $1
调用函数时直接传递参数
#!/bin/bash fun1(){
rm -rf $1
}
fun1 /root/a.txt
函数中多参数传递和使用方法


案例:阶乘
#!/bin/bash
jiecheng (){
cheng=1
for i in {1..6}
do
let cheng=$i*$cheng
done
echo $cheng
}

jiecheng


优化版:根据用户需求算几的阶乘
#!/bin/bash
jiecheng (){
cheng=1
read -p "请问您想算几的阶乘:" num   //①给用户提示输入
for i in `seq $num`
do
let cheng=$i*$cheng
done
echo $cheng
}

jiecheng

#!/bin/bash
jiecheng (){
cheng=1
for i in `seq $1`    //②用位置变量的方式
do
let cheng=$i*$cheng
done
echo $cheng
}

jiecheng $1

函数的返回值,用return来自定义返回码
函数的返回值就是函数当中运行最后一条命令的状态码,默认成功为0,失败为非0值,可以通过$?查看
但是可以自己自定义返回码,用return
1、return的值范围是0-255
2、遇到return即结束函数不会再往下执行


#!/bin/bash
HELLO (){
echo "hello world"
}

HELLO    //执行成功 echo $?为0

#!/bin/bash
HELLO (){
echo "hello world"
ls xxxx
}

HELLO    //执行失败 echo $?为非0,因为没有xxxx的文件

#!/bin/bash
HELLO (){
echo "hello world"
return 11
}

HELLO    //执行成功 echo $?为11


#!/bin/bash
HELLO (){
echo "hello world"
return 11    //返回码为11,不会执行下面的命令了
ls xxxxx
return 22
}

HELLO


例1:测试文件是否存在
#!/bin/bash
file=/etc/xxxx

f1 (){
if [ -f $file ];then
return 100
else
return 200
fi
}

f1
echo $?   //返回码为200,我们可以根据返回值来判断我们想要的结果

例2:两个数之和
#!/bin/bash
SUM (){
let sum=$1+$2
echo $sum
return 100
}

SUM 5 5
echo $?

[root@localhost ~]# . re2.sh 
10
100

#!/bin/bash
SUM (){
let sum=$1+$2
echo $sum
return 100
}

SUM 5 5
num=`SUM 5 5`    //注意这里函数是有参数的
echo $?
echo $num
这个脚本返回码为
10         //先执行了函数,函数的结果是10
100       //执行函数之后返回码是100
10          //把函数的结果10赋值给了$num,所以是10


本地变量与全局变量

在脚本里定义的变量或者在函数体没有声明为本地变量的都为全局变量,意思是在当前shell环境都识别
如果需要这个变量只在函数中使用则可以在函数中用local关键字声明,这样即使函数体外有个重名的变量也没关系,不影响在函数体的使用
如果是用source执行脚本的话就能看出差别
[root@localhost ~]# a=nihao
#!/bin/bash     //写一个函数,首先打印a的值,然后改变a的值再打印
f1 (){
echo $a          //全局变量
a=world
echo $a          //本地变量
}

f1
[root@localhost ~]# source f1.sh     //用source执行脚本,会发现a的值改变了
nihao
world
[root@localhost ~]# echo $a
world

在函数体中用local定义变量a的值
#!/bin/bash
f1 (){
echo $a
local a=world
echo $a
}

f1
[root@localhost ~]# source f1.sh   //执行脚本发现a的值并没有改变
world
world


#!/bin/bash
f1 (){
echo $a
local a=world
echo $a
}

f1
echo $a

[root@localhost ~]# a=hello
[root@localhost ~]# source f1.sh   //可以看成变量a的值在函数体设为了本地变量所以只在函数体中生效
hello
world
hello

#!/bin/bash
function fun1 {
num1=$[var1*2]
}
read -p "input a num:" var1 fun1
echo the new value is: $num1

通过一个简单的例子感受一下函数的用法:
将之前写过的算数字总和和算奇数和偶数和的脚本融合在一个脚本中并用函数根据用户的输入来调用它们
#!/bin/bash
SUM (){
sum=0
read -p "计算1到几的和:" num
for i in `seq $num`
do
let sum=$i+$sum
let i++
done
echo $sum
}

oushu (){
sum=0
read -p "计算1到几的偶数和:" num
for i in `seq $num`
do
if [ $((i%2)) -eq 0 ];then
let sum=$i+$sum
fi
let i++
done
echo $sum
}

if [ $1 == SUM ];then
SUM
elif [ $1 == oushu ];then
oushu
else
        echo "参数错误"
fi


5.6 函数的递归


函数自己调用自己的本身
列出目录内文件列表,目录用蓝色表示,文件显示层级关系

#!/bin/bash
list(){
for i in $1/*
do
        if [ -d $i ];then
        echo -e "\e[34m$i\e[0m"
        list $i " $2"
        else
        echo "$2$i"
fi
done
}
list $1 $2

计算5的阶乘
#阶乘  5! 5*4*3*2*1 
#!/bin/bash
fa () {
if [ $1 -eq  1 ]
then
echo 1
else
 local tp=$[$1 - 1]
 local res=$(fa $tp)
 echo $[ $1 * $res ]
# 5 * $res(4*$res(3*$res(2*$res(1)))) 
fi

}

5
fa 5 $1=5 tp=4 res=fa 4 echo 5 * fa 4    5*4*3*2*1
fa 4 $1=4 tp=3 res=fa 3 echo 4 * fa 3    4*3*2*1
fa 3 $1=3 tp=2 res=fa 2 echo 3 * fa 2    3*2*1
fa 2 $1=2 tp=1 res=fa 1 echo 2 * fa 1     2*1
fa 1 $1=1               echo 1  

read -p "请输入:"  num
res=$(fa $num)
echo $res

#!/bin/bash
function list_files()
{
for f in `ls $1`; 
do
if [ -d "$1/$f" ]; then 
echo "$2$f"
list_files "$1/$f" "$2"
else 
echo "$2$f"
fi

done
}

list_files "/var/log" ""


5.7 数组的定义

数组是存放相同类型数据的集合,在内存中开辟了连续的空间,通常配合循环使用

5.7.1 数组的分类


普通数组:不需要声明直接定义,下标索引只能是整数
关联数组:需要用declare -A声明否则系统不识别,索引可以是字符串

5.7.2 数组的定义方式


(30 20 10 60 50 40)
 0   1  2  3  4   5             索引

第一种:直接把要加入数组的元素用小括号括起来,中间用空格分开
num=(11 22 33 44)

数组名= (value0 value1 value2)

${#num}          显示字符变量的长度     

${#num[*]}       显示数组长度(元素个数)   

${num[*]}         显示数值

第二种:精确的给每一个下标索引定义一个值加入数组,索引数字可以不连续
num=([0]=55 [1]=66 [2]=77 [4]=88)

数组名=([0]=value [1] =value  [2] =value...)


第三种:先把要加入数组的元素全部先赋值给一个变量,然后引用这个变量加入到数组
list=“11 12 13 14”
num=($list)

方法三:
列表名="value0 value1 value2....”
数组名=($列表名)


第四种 根据下标定义
数组名[0]=“11”
数组名[0]=“22”
数组名[0]=“33”

数组名[0]="value"
数组名[1]="value"
数组名[2]="value"

---------------

数组包括的数据类型
数值类型
字符类型:
使用“ ” 或 ‘ ’ 定义

获取数组的长度
arr_number=(10 20 30 40 50)
arr_length=${#arr_number[*]}
           ${#arr_number[@]}

echo $arr_length

echo ${arr[*]}

获取数据列表
echo ${arr_number[*]}
echo ${arr_number[@]}

读取某下标赋
arr_ index2=$ {arr__number[2]}
echo $arr index2

数组元素遍历

#!/bin/bash
arr=(1 2 3 4 5 6)
for i in ${arr[*]}   或for i in ${arr[@]}
do
echo $i
done

元素切片


arr=(1 2 3 4 5 6 7 8)
echo ${arr[*]}    #输出整个数组
echo ${arr[*]:2:3}     #提取从索引2开始的3个元素

echo ${arr[@]:2:2}      

echo ${arr[*]:0:2}
 v 

数组(元素)替换
arr=(1 2 3 4 5)
echo ${arr[@]/3/55}   //${数组名[@或*]/查找字符/替换字符}
echo ${arr[@]}        //并不会替换数组原有内容
arr=(${arr[@]/3/55})   //要实现改变原有数组,可通过重新赋值实现   arr=${arr[@]/3/55}   arr=(${arr[@]/3/55})
echo ${arr[@]}

arr=(5 1 2 3 4 5) 定义下标修改 

数组删除
arr=(1 2 3 45)
unset arr            //删除数组
echo $ { arr[* ]}

arr=(1 2 3 4 5)
unset arr[4]      //删除第四个元素
echo $ {arr[*]}

{55 44 90 78 20}

数组排序算法:冒泡排序
类似气泡上涌的动作,会将数据在数组中从小到大或者从大到小不断的向前移动。
基本思想:
冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部。
算法思路
冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一般为要排序的数组长度减1次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序了。而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置,对比和交换次数随排序轮数而减少。

a=10
b=20

tmp=$a
a=$b
b=$tmp

希望a和b的值对调位置
结果
b=10
a=20

排序score=(73 64 86 99 43)
------------第一轮------i-------
73 64 86 99 43     第一次对比      数组长度-1   第一轮比较厚,最后一位是最大值  99
64 73 86 99 43     第二次对比
64 73 86 99 43     第三次对比
64 73 86 99 43     第四次对比
64 73 86 43 99     
------------第二轮-------------
64 73 86 43 99     第一次对比      数组长度-2   第二轮比较后,第二大的数字  88
64 73 86 43 99     第二次对比
64 73 86 43 99     第三次对比
64 73 43 86 99

------------第三轮-------------
64 73 43 86 99     第一次对比      数组长度-3  第三轮比较后,第三大的数字  73
64 73 43 86 99     第二次对比
64 43 73 86 99     
------------第四轮轮-------------
64 43 73 86 99     第一次对比      数组长度-4  第三轮比较后,第四大的数字  64
43 64 73 86 99 


算法1
#!/bin/bash
array=(90 70 60 40 50 30)
echo "old_array:${array[*]}"
lt=${#array[*]}
#定义比较轮数,比较轮数为数组长度减1,从1开始
for ((i=1; i<$lt; i++))
do
  #确定比较元素的位置,比较相邻两个元素,较大的数往后放,比较次数随比较轮数而减少
  for ((j=0; j<$lt-i; j++))
  do
    #定义第一个元素的值
    first=${array[$j]}
    #定义第二个元素的值
    k=$[$j+1]
    second=${array[$k]}
    #如果第一个元素比第二个元素大就互换
    if [ $first -gt $second ]
    then
      #把第一个元素值保存到临时变量中
      temp=$first
      #把第二个元素值赋给第一个元素
      array[$j]=$second
      #把临时变量(也就是第一个元素原值)赋给第二个元素
      array[$k]=$temp
    fi
  done
done
#输出排序后的数组
echo "new_array:${array[*]}"

冒泡排序
#!/bin/bash
num=(90 70 60 40 50 30)
for ((i=0;i<${#num[*]};i++))
  do
    for ((j=i+1;j<${#num[*]};j++))
     do
      if [ ${num[$i]} -gt ${num[$j]} ]
      then
       temp=${num[$i]}
       num[$i]=${num[$j]}
       num[$j]=$temp
      fi
     done
  done
echo ${num[*]

#!/bin/bash
#存入元素
#set -x
k=0
while true
do
read -p "是否存入元素:" doing
if [ $doing == "no" ];then
break
fi
read -p "请输入第$[$k+1]个元素:" key
score[$k]=$key
let k++
done
#外层为轮
for ((i=1;i<${#score[*]};i++));do
#内层为次
  for ((j=0;j<${#score[*]}-i ;j++));do
#两数交换
    if [ ${score[$j]} -gt ${score[ `expr $j + 1`]} ];then
    tmp=${score[`expr $j + 1`]}
    score[ `expr $j + 1` ]=${score[$j]}
    score[$j]=$tmp
    fi
  done
done
echo ${score[*]

#定义一个初始数组
arr=(30 10 50 60 40 20)
echo “原数组的顺序为: ${arr[@]}"
#获取数组的长度
length=${#arr[@]}
#冒泡排序:
#定义比较轮数,为数组长度减一,并且要从1开始
for ( (i=1; i<$length; i++))
do
#确定每次比较的元素下标,比较相邻2个元素,大的往后放,小的往前放,并且每轮比较的次数要随着轮数递减
for ((j=0; j<$length-$i; j++))
do
#获取第一个元素的值
first=${arr[$j]}   
#获取第二个元素的值
k=$[$j + 1]
second=${arr[$k]}
#比较第一个元素和第二个元素的值,如果第一个元素值大于第二个元素值则两个元素位置交换
if [ $first -gt $second ];then
#先把第一个元素的值保存在临时变量temp中
temp=${arr[$j]}
#把第二个元素的值赋给第一个元素
arr[$j]=$second
#把原来第一个元素的值赋给第二个元素
arr[$k]=$temp
done
done
echo "排序后新的数组的顺序为:${arr[@]}"


sh [参数] 文件名.sh
-n 不要执行script,仅查询语法
-v 在执行script之前,先将script的内容输出到屏幕上
-x 将使用的脚本的内容输出到屏幕,该参数经常被使用
-c “string” 从strings中读取命令

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值