Q132284591 发表于 2018-8-20 06:34:50

shell脚本循环及函数

  16.循环执行
  将代码段重复运行多次
  重复运行多少次;
  循环次数事先已知
  循环次数事先未知
  有进入条件和退出条件
  for,while,until
  for循环
  for 变量名 in 列表;do
  循环体
  done
  执行机制:
  依次将列表中的元素赋值给“变量名”;每次赋值后即执行一次循环体;直到列表中的元素耗尽,循环结束
  列表生成方式:
  1.直接给出列表
  2.整数列表:
  (a){1..10}
  (b) $(seq 1 10)
  3.返回列表的命令
  $(command)
  4.使用glob,如*.sh
  5.变量引用:$@,$*
  案例练习:
  1、判断/var/目录下所有文件的类型
#!/bin/bash  
#
  
a=`echo /var/ | sed -r 's@(.*)/@\1@'`
  
for b in `ls -A /var/`
  
do
  
c=`ls -dl $a/$b | cut -c1`
  
    case $c in
  
    f)
  
    echo "$b iWJ"
  
    ;;
  
    d)
  
    echo "$b ML"
  
    ;;
  
    *)
  
    echo "$b NO ZD"
  
    esac
  
done
  2、添加10个用户user1-user10,密码同用户名
#!/bin/bash  
#
  
u=user1
  
for i in {1..10};do
  
    if id -u $u$i &>/dev/null;then
  
    echo "$u$i CZ"
  
      else
  
      useradd $u$i &> /dev/null
  
      echo "$u$i useradd success!!"
  
      echo $u$i |passwd --stdin $u$i &> /dev/null
  
      echo "$u$i passwd success!!"
  
      fi
  
done
  3、/etc/rc.d/rc3.d目录下分别有多个以K开头和以S开头的 文件;分别读取每个文件,以K开头的文件输出为文件加stop ,以S开头的文件输出为文件名加start; “K34filename stop” “S66filename start”
#!/bin/bash  
#
  
file=`ls -A /etc/rc.d/rc3.d/`
  
for i in $file ;do
  
s=`echo $i | cut -c1`
  
    case $s in
  
    K)
  
    echo "$i stop"
  
    ;;
  
    S)
  
    echo "$i start"
  
    ;;
  
    esac
  
done
  4、写一个脚本,提示输入正整数n的值,计算1+2+3+…n的 总和
#!/bin/bash  
#
  
read -p "SRSZ:" n
  
#m=`echo "$n" | grep -E "^[[:digit:]]+"`
  
if [ $n -eq 0 ];then
  
echo "zheshi 0"
  
fi
  
    for i in `seq $n`
  
    do
  
    sum=$(($sum+$i))
  
    done
  
echo `seq -s + 1 $n`=$sum
  5、写一个脚本,提示请输入网络地址,如192.168.0.0,判 断输入的网段中主机在线状态
#!/bin/bash  
#
  
read -p"shuru IP:" ip
  
num=`echo $ip |sed -r 's@(.*).$@\1@'`
  
if `echo $ip |egrep '\' &>/dev/null`
  
then
  
            for i in `seq 113 116`
  
            do
  
            ping -c1 -W2 $num$i &>/dev/null && echo "$num$i success!" || echo "$num$i error"
  
            done
  
    else
  
    echo "$ip bibi"
  
    fi
  6、打印九九乘法表
#!/bin/bash  
#
  
for i in `seq 9`
  
do
  
    for b in `seq 1 $i`
  
    do
  
    echo -ne "$b*$i=$(($b*$i))\t"
  
    done
  
    echo
  
    done
  
echo = = = = = = = = = = = = = = 2 = = = = = = = = = = = = =
  
for ((i=1; i /dev/null
  
    if [ $? -eq 0 ];then
  
    who >> /var/log/login.log
  
    echo"hacker login exit!!!!"
  
    exit
  
    sleep 3
  
    fi
  
done
  2、随机生成10以内的数字,实现猜字游戏,提示比较大或小 ,相等则退出。
#!/bin/bash  
n=$[$RANDOM%10+1]
  
i=0
  
echo "猜数字游戏开始啦!"
  
while true
  
do
  
read -p "shuru:" in
  
let i++
  
    if [ $in -eq $n ];then
  
    echo "猜对喽! $n"
  
    echo "一共猜了$i次"
  
    exit 0
  
      elif [ $in -gt $n ];then
  
      echo "有点高了,数字小一点试试"
  
            else
  
            echo "有点小了,数字大一点试试"
  
    fi
  
done
  特殊用法
  while循环的特殊用法(遍历文件的每一行)
  while read line;do
  循环体
  done < /PATH/FROM/SOMEFILE
  依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将每行赋值给变量line
  案例练习:
  1.扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填 充用户名和单位电话为62985600,并提示该用户的GECOS信 息修改成功
#!/bin/bash  
#
  
file="/etc/passwd"
  
while read line
  
do
  
u=$(echo $line |cut -d: -f1)
  
g=$(echo $line |cut -d: -f5)
  
chfn -f $u -p 62985600 $u &> /dev/null
  
if [ -z $g ];then
  
    echo "$u GECOS sccuess"
  
      else
  
      echo "$u NOweikong"
  
      #usermod -c "" $u
  
fi
  
done < $file
  特殊用法:
  双小括号方法:即((...))格式,也可以用于算术运算
  双小括号方法也可以使bash shell 实现c语言风格的变量操作
  #I=10
  #((I++))
  for循环的特殊格式:
  for((控制变量初始化;条件判断表达式;控制变量的修正表达式))
  do
  循环体
  done
  控制变量初始化:仅在运行到循环代码段时执行一次
  控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后在做条件判断
  这种用法就像我们上面写的99乘法表一样,使用的是c语言风格的
#!/bin/bash  
#
  
for ((i=1; i }
  定义该函数后,若在$后面键入dir,其显示结果同ls -l的 作用相同。
  $dir
  该dir函数将一直保留到用户从系统退出,或执行了如下 所示的unset命令: $ unset dir
  在脚本中定义及使用函数
  函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至 shell首次发现它后才能使用
  调用函数仅使用其函数名即可。
  示例: $cat func1
  #!/bin/bash
  # func1
  hello()
  {
  echo "Hello there today's date is `date +%F`"
  }
  echo "now going to the function hello"
  hello
  echo "back from the function"
  使用函数文件
  可以将经常使用的函数存入函数文件,然后将函 数文件载入shell。
  文件名可任意选取,但最好与相关任务有某种联 系。例如:functions.main
  一旦函数文件载入shell,就可以在命令行或脚本 中调用函数。可以使用set命令查看所有定义的函 数,其输出列表包括已经载入shell的所有函数。
  若要改动函数,首先用unset命令从shell中删除 函数。改动完毕后,再重新载入此文件。
  函数文件示例:
#!/bin/bash  
#functions.main
  
findit()
  
{
  
if [ $# -lt 1 ] ;then
  
echo "Usage:findit file"
  
return 1
  
fi
  
find / -name $1 –print
  
}
  载入函数:
  函数文件已创建好后,要将它载入shell
  定位函数文件并载入shell的格式:. filename 或 source   filename
  注意:此即    这里的文件名要带正确路径
  示例:上例中的函数,可使用如下命令: $ . functions.main
  检查载入函数:
  使用set命令检查函数是否已载入。set命令将在shell中显示 所有的载入函数。
  示例:
$set  
findit=( )
  
{
  
      if [ $# -lt 1 ]; then
  
      echo "usage :findit file";
  
      return 1
  
      fi
  
      find / -name $1 -print
  
}
  执行shell函数
  要执行函数,简单地键入函数名即可:
  示例:
  $findit groups
  /usr/bin/groups
  /usr/local/backups/groups.bak
  删除shell函数
  现在对函数做一些改动。首先删除函数,使其对shell不可用 。使用unset命令完成此功能.
  命令格式为: unsetfunction_name
  示例:$unset findit 再键入set命令,函数将不再显示
  函数参数:
  函数可以接受参数:
  传递参数给函数:调用函数时,在函数名后面以空白分隔 给定参数列表即可;例如“testfunc arg1 arg2 ...”
  在函数体中当中,可使用$1, $2, ...调用这些参数;还 可以使用$@, $*, $#等特殊变量函数变量
  变量作用域:
  环境变量:当前shell和子shell有效
  本地变量:只在当前shell进程有效,为执行脚本会启动
  专用子shell进程;因此,本地变量的作用范围是当前shell脚本 程序文件,包括脚本中的函数。
  局部变量:函数的生命周期;函数结束时变量被自动销毁
  注意:如果函数中有局部变量,如果其名称同本地变量,使 用局部变量。
  在函数中定义局部变量的方法 local NAME=VALUE
  函数递归:
  函数直接或间接调用自身
  注意递归层数
  递归实例:
  阶乘是基斯顿·卡曼于 1808 年发明的运算符号,是数学术语 一个正整数的阶乘(factorial)是所有小于及等于该数的正整 数的积,并且有0的阶乘为1。自然数n的阶乘写作n!。 n!=1×2×3×...×n。
  阶乘亦可以递归方式定义:
  0!=1
  n!=(n-1)!×n
  n!=n(n-1)(n-2)...1
  n(n-1)! = n(n-1)(n-2)!
  函数示例:
            #!/bin/bash  
            # fact()
  
            {
  
                      if [ $1 -eq 0 -o $1 -eq 1 ]; then
  
                      echo 1
  
                      else
  
                      echo $[$1*$(fact $[$1-1])]
  
                      fi
  
            }
  
            fact $1
  案例练习:
  1、编写服务脚本/root/bin/testsrv.sh,完成如下要求
  (1) 脚本可接受参数:start, stop, restart, status
  (2) 如果参数非此四者之一,提示使用格式后报错退出
  (3) 如是start:则创建/var/lock/subsys/SCRIPT_NAME, 并显示“启动成功” 考虑:如果事先已经启动过一次,该如何处理?
  (4) 如是stop:则删除/var/lock/subsys/SCRIPT_NAME, 并显示“停止完成” 考虑:如果事先已然停止过了,该如何处理?
  (5) 如是restart,则先stop, 再start 考虑:如果本来没有start,如何处理?
  (6) 如是status, 则如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示 “SCRIPT_NAME is running...” 如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is stopped...” 其中:SCRIPT_NAME为当前脚本名
  (7)在所有模式下禁止启动该服务,可用chkconfig 和 service命令管理
#!/bin/bash  
    #
  
file=$(basename $0)
  
SCRIPTS="/var/lock/subsys/$file"
  
function start () {
  
    if [ ! -e $SCRIPTS ];then
  
    touch $SCRIPTS
  
    sleep 1
  
    echo "service $file start sccuess!"
  
      else
  
      echo "service $file running....."
  
    fi
  
}
  
function stop () {
  
    if [ -e $SCRIPTS ];then
  
    rm -rf $SCRIPTS
  
    sleep 1
  
    echo "service $file stop sccuess!"
  
      else
  
      echo "service $file statusstop!"
  
      fi
  
}
  
function status () {
  
if [ -e $SCRIPTS ];then
  
echo "$file is running..."
  
    else
  
    echo "$file is stopped..."
  
fi
  
}
  
      case $1 in
  
      start)
  
      start
  
      ;;
  
      stop)
  
      stop
  
      ;;
  
      restart)
  
      stop
  
      start
  
      ;;
  
      status)
  
      status
  
      ;;
  
      *)
  
echo "$file usage {start|stop|status|restart}"
  
exit 1
  
;;
  
      esac
  2、编写脚本/root/bin/copycmd.sh
  (1) 提示用户输入一个可执行命令名称
  (2) 获取此命令所依赖到的所有库文件列表
  (3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下; 如:/bin/bash ==> /mnt/sysroot/bin/bash /usr/bin/passwd ==> /mnt/sysroot/usr/bin/passwd
  (4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下: 如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ldlinux-x86-64.so.2
  (5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命 令,并重复完成上述功能;直到用户输入quit退出
#!/bin/bash  
#
  
file=/mnt/sysroot/
  
libfile=/mnt/sysroot/lib64/
  
copycmd(){
  
[ -e /mnt/sysroot ] ||mkdir /mnt/sysroot
  
cmd=`which --skip-alias $p`
  
cp $cmd $file && echo "Copy command success."
  
}
  

  
copylib(){
  
lib=$(ldd `which --skip-alias $p` |grep -E -o "/.*" | cut -d" " -f1)
  
cp $lib $libfile
  
[ $? -eq 0 ] && echo "Copy lib success."
  
}
  
while true
  
do
  
read -p " 请输入命令:" p
  
if [[ $p == "quit" ]];then
  
exit
  
fi
  
    if which --skip-alias $p &> /dev/null ;then
  
    copycmd
  
    copylib
  
         else
  
         read -p " 不是命令, 请输入命令:" p
  
fi
  
done


页: [1]
查看完整版本: shell脚本循环及函数