基于函数的bash-shell初级编写

bash运行脚本是执行父进程的子进程,脚本里的命令就为子进程
.和source运行脚本时将脚本的语句在父进程中运行
set可以显示系统当前的本地变量和环境变量,unset可以取消系统的本地变量和环境变量
 变量命名规则:变量名首字母必须为字母(a-z A-Z),下划线(_),或者美元符号($)开始。(因在shell脚本中用来表示引用参数,应避免产生歧义)
变量名只能是字母(a-z A-Z),数字(0-9),下划线(_)的组合,并且之间不能包含空格,数字不能放在变量名首位。
变量名不能使用编程语言的保留字。比如在javascript中不能使用true,false,while,case,break保留字等等。
示例:显示一个菜单给用户,提示用户给出自己的选择,正确的选择给出相应的信息,否则提示用户重新选择正确的选项
case语句作为bash shell的另外一种循环应用很广泛,因为对应服务启动脚本而言,都会接受一些诸如:start、stop、status、restart、reload等位置参数,那么这些不同的位置经过case语句的判断之后,会执行不同的代码块,这个功用就是case语句之所以应用广泛的原因
case语句的语法格式
case $变量 in
PAT1)
    分支1
    ;;
PAT2)
    分支2
    ;;
PAT3)
    分支3
    ;;
    ....
    ....
    ....
PATn)
    分支n
    ;;
esac
#!/bin/bash
 cat << EOF
cpu)display cpu information
mem)display memory information
disk)display disk information
quit)quit
EOF
read -p "Enter your option:" option
while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ];do
    echo "please input cpu ,mem , disk , quit"
    read -p "Enter your option:" option
done
if [ "$option" == "cpu" ];then
   lscpu
elif [ "$option" == "mem" ];then
   free -m
elif [ "$option" == "disk" ];then
   fdisk -l /dev/sd[a-z]
elif [ "$option" == "quit" ];then
   echo "quit"
   exit 0
fi
将上述题目改写成的判断,会使得代码的可读性增强
#!/bin/bash
cat << EOF
cpu)display cpu information
mem)display memory information
disk)display disk information
quit)quit
EOF
read -p "Enter your option:" option
while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ];do
    echo "please input cpu ,mem , disk , quit"
    read -p "Enter your option:" option
done
case $option in
cpu)
    lscpu ;;
mem)
    free -m ;;
disk)
    fdisk -l /dev/sd[a-z] ;;
quit)
   echo "quit"
   exit 0 ;;
esac
练习:写一个服务框架脚本名为create_file,接受start 、stop、 restart、 status 四个参数之一 (这个题非常重要)
1:如果参数非此四者,则提示使用帮助后退出
2:如果传递start参数,则在/var/log目录下创建一个与脚本名相同的文件,并显示启动。
3:如果传递stop参数,就在/var/log目录下删除一个与脚本名相同的文件 ,并显示停止。
4:如果传递restart参数,就先删除再创建此文件,而后显示重启完成。
5:如果传递status参数, 如果文件存在,则显示running, 否则显示为stopped
#!/bin/bash
#chkconfig: - 50 50
 prog=$(basename $0)
FILE=/var/log/$prog
case $1 in
start)
   if [ -f $FILE ];then
       echo "$prog is running yet."
    else
       touch $FILE
       [ $? -eq 0 ] && echo "start $prog ok."        #此处 $? 用来表示上一步操作是否成功
    fi
    ;;
stop)
   if [ -f $FILE ];then
        rm -f $FILE
        [ $? -eq 0 ] && echo "stop $prog finished."
    else
        echo "$prog is not running."
    fi
    ;;
restart)
    if [ -f $FILE ];then
 rm -f $FILE
       touch $FILE
       echo "restart $prog ok."
    else
       touch -f $FILE
       echo "start $prog ok."
    fi
    ;;
status)
    if [ -f $FILE ];then
        echo "$prog is running"
    else
        echo "$prog is stopped."
    fi
    ;;
*)
    echo "Usage: $prog {start | stop | restart | status}"
    exit 1
esac
函数可以将重复代码进行封装,用到时再调用即可,这样使得在很大程度上避免了垃圾代码、重复代码
函数:代码重用
    模块化编程
    结构化编程
注意:定义函数的代码段不会自动执行,在调用时执行,所谓调用函数,在代码中给定函数名称即可,函数名出现的任何位置,在代码执行时候,都会自动替换为函数代码
语法格式:
语法一:
        function f_name{
            函数体
        }
语法二:
        f_name(){
            函数体
        }
函数的生命周期:每次被调用时,被创建,返回时,终止
其状态返回结果为函数体中运行的最后一条命令的状态结果
自定义状态返回值,需要使用:return
return [0-255]
    0: 成功
    1-255:失败
示例:给定一个用户名,取得用户名的ID号,和默认的 shell
#!/bin/bash
userinfo(){
     if id "$username" &> /dev/null;then
          grep "^$username\>" /etc/passwd |cut -d: -f3,7
      else
           echo "No such user"
      fi
}
username=$1
userinfo


函数的返回值分为两类
    (1)函数的执行结果返回值
        1:使用echo或printf命令进行输出
        2:函数体中调用的命令的执行结果
    (2)函数的退出状态码
        1:默认取决于函数体中执行的最后一条命令的退出状态码
        2:自定义:return (相当于脚本中的exit)
函数可以接受参数:在调用函数的时候可以给函数传递参数
在函数体中,可以使用$1, $2...引用传递给函数的参数,还可以使用$* 或$@调用所有的参数,$#表示传递的参数的个数
在调用函数时候,在函数名后面以空白字符分割给定参数列表即可,例如:functionName arg1 arg2 arg3 arg4...
示例:添加10个用户,添加用户的功能使用函数实现,用户名作为参数传递给函数。这里有一个注意点,就是如果直接return $? ,在函数外面是不能拿到值的
!/bin/bash
addusers(){
      if id $1 &> /dev/null;then
           return 5
      else
           useradd $1
           retval=$?
           return $retval
      fi
}
for i in {1..10}; do
     addusers ${1}${i}
     retval=$?
     if [ $retval -eq 0 ];then
         echo "Add user ${1}${i} finished"
     elif [ $retval -eq 5 ]; then
         echo "user ${1}${i} exists"
     else
         echo "Unknow Error"
     fi
done
写一个脚本:要求
(1)使用函数实现ping一个主机来测试主机的在线状态,主机地址通过参数传递给函数
(2)主程序:测试192.168.7.130 - 192.168.7.139 范围内的各个主机的在线状态
(3)如果主机在线,那么打印黄色的Online字符串,如果主机不在线打印红色的Offline字符串
(4)字符串打印变颜色实现方式,请参照博客:http://yhyblog.cn
综合练习1:
#!/bin/bash
if [ $# -lt 2 ];then
    echo "请输入两个主机地址作为IP地址的检测范围"
    exit 1
fi
START=$1
END=$2
ping(){                                 #检测IP的范围
      ping -c1 -w1 172.16.19.1$1 &> /dev/null && echo -e "\E[1;33 172.16.19.1$1 Online \033[0m" || echo -e "\E[1;31m 172.16.19.1$1 Offline \033[0m"
}
  for i in `seq $1 $2`; do
      ping $i
done
综合练习2:写一个脚本 :要求
打印NN乘法表,使用函数实现, 例如:给脚本传递了一个11,那么就是打印11 X 11 的乘法表
#!/bin/bash
for((i=1;i<=$1;i++));do
    for((j=1;j<=$i;j++));do
         echo -n "$j x $i = $[ $j*$i ]"
    done
    echo
done
在bash shell编程的脚本里,变量作用域可以分为两种,一种是局部变量,一种是本地变量。
局部变量:作用域是函数的生命周期,在函数结束时被自动销毁。定义局部变量的方法:local 变量=值
本地变量:作用域是运行脚本的shell进程的生命周期,因此,其作用域范围是当前的shell脚本程序文件
示例:
#!/bin/bash
setname(){
  local name=jerry   # 记得以后为了避免函数中的变量与本地变量同名,如果同名,会使得具备变量修改本地变量的值,使得本地变量的指针直接指向函数中变量的存储空间。为了避免同名产生的错误,以后在函数中定义的变量都使用局部变量,在变量名前面加上一个local关键字
  echo "Function: $name"
}
setname
echo "shell: $name"
bash shell中和其他编程语言一样可以使用递归。那什么是递归:程序调用自身技巧称为递归( recursion)
示例:写一个脚本,给脚本传递一个数值,脚本输出这个数值的阶乘。
#!/bin/bash
func(){
     if [ $1 -eq 0 -o $1 -eq 1 ];then
         echo 1
     else
         echo $[$1*$(func $[$1-1])]
     fi
}
func $1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值