shell

shell.2.8 bash脚本编程:函数

 

函数:function,过程式编程,可用来实现代码重用;函数能实现2种功能,模块化编程、结构化编程;

把一段独立功能的代码当做一个整体,并为之取一个名字;命名的代码段即为函数;
定义函数的代码段不会自动执行,在调用时才执行;
调用函数时,在代码中给定函数名即可;
函数名出现的任何位置,在代码执行时都会被自动替换为函数代码;

1、函数的语法结构

语法一:
function f_name {
     函数体
}

语法二:
f_name() {
     函数体
}

2、函数的生命周期:每次被调用时创建,返回时终止
函数的状态返回结果为函数体中运行的最后一条命令的状态结果;
自定义状态返回值,需使用’return’命令;取值范围[0-255];’0’表示成功,非’0’表示失败;

示例理解1:给定一个用户名,取得用户的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

username=$2
userinfo

#后面的2个userinfo 表示调用前面定义的函数;

示例理解2:传递参数;

#!/bin/bash
#

lockfile=/var/lock/subsys/$0

if [ $# -lt 1 -o $# -gt 1 ]; then
  echo "$0 's arg : {start|stop|restart|status}."
  exit 22
fi

b_name=$(basename $0)
blockfile=/var/lock/subsys/$b_name


start() {
  if [ -f $lockfile ]; then
    echo "file is already exitses. it is started."
  else
    touch $lockfile
    [ $? -eq 0 ] && echo "start:file is created."
  fi
}
stop() {
  if [ -f $lockfile ]; then
    rm -rf $lockfile
    [ $? -eq 0 ] && echo "stop:file is delete."
  else
    echo "it is already stop."
  fi
}

status() {
  if [ -f $lockfile ]; then
    echo "running : start status."
  else
    echo "stopped : stop status."
  fi
}
us_age() {
  echo "$0 's arg : {start|stop|status|restart}"
  echo "quit"
  exit 11
}


case $1 in
start)
  start
  ;;
stop)
  stop
  ;;
restart)
  stop
  start
  ;;
status)
  status
  ;;
*)
  us_age
  exit 11
  ;;
esac

3、函数返回值

函数的执行结果返回值:
1> 使用echo或printf命令进行输出;
2> 函数体中调用的命令的执行结果;

函数的退出状态码:
1> 默认取决于函数体中执行的最后一条命令的退出状态码;
2> 自定义:return;

4、函数可以接受参数
函数在被调用的时候,可以传递参数给函数:
在函数体中,可以使用位置变量”$1,$2…”,引用这些位置变量给函数传递参数;
还可以在函数体中使用”$*或者$@”,表示引用所有参数,”$#”表示引用传递的参数的个数(数字);
在调用函数时,在函数名后面以空白字符为分隔,后接具体的参数值列表,分别对应函数体中的各个位置变量;

所以,函数体中使用的位置变量与传递给脚本的位置变量不是同一概念!!!!

示例理解3:添加10个用户,使用函数功能实现;用户名当做函数的参数值传递给函数;

if [ $# -lt 1 -o $# -ge 2 ]; then
  echo "usage: $b_name arg is singel one."
  exit 11
fi


add_user() {
  if id $1 &> /dev/null; then
    return 5
  else
    useradd $1
    retval1=$?
    return=$retval1
  fi
}

b_name=$(basename $0)


for i in {1..10}; do
  add_user ${1}${i}
  retval2=$?
  if [ $retval2 -eq 0 ]; then
    echo "add user ${1}${i} finished."
  elif [ $retval2 -eq 5 ]; then
    echo "user ${1}${i} exists."
  else
    echo "unknow error."
  fi
done

示例理解4: 使用函数功能实现ping一个主机来测试主机在线状态;主机地址通过参数传递给函数

#!/bin/bash
#
declare -i i=1
declare -i up_hosts=0
declare -i down_hosts=0

p2_ing() {
  ping -W 1 -c 1 $1 &> /dev/null
  sub_return=$?
  if [ $sub_return -eq 0 ]; then
    echo "$1 is UP."
    return 0
  else
    echo "$1 is DOWN."
    return 4
  fi
}

while [ $i -le 67 ]; do
  p2_ing 172.16.$i.1
  [ $? -eq 0 ] && let up_hosts++ || let down_hosts++
  let i++
done

echo "UP hosts is $up_hosts ; DOWN hosts is $down_hosts."

 

p2_ing() {
  ping -c 5 $1 &> /dev/null
  sub_return=$?
  if [ $sub_return -eq 0 ]; then
    return 0
  else
    return 4
  fi
}

declare -i i=1
declare -i up_hosts=0
declare -i down_hosts=0

while [ $i -le 67 ]; do
  h_ost=172.16.$i.1
  p2_ing $h_ost
  sub2_return=$?
  if [ $sub2_return -eq 0 ]; then
    echo "$h_ost alive."
    let up_hosts+=1
  elif [ $sub2_return -eq 4 ]; then
    echo "$h_ost dead."
    let down_hosts+=1
  else
    echo "unknow error."
  fi
  let i++
done

echo "UP hosts is $up_hosts ; DOWN hosts is $down_hosts."

示例理解5:打印NN乘法表; 向脚本传递一个数字(正整数);

#!/bin/bash
#

multi_tab() {
  echo -e -n "${1}x${2}=$[${1}*${2}]\t"
}

declare -i i=1

while [ $i -le $1 ]; do
  declare -i j=1
  while [ $j -le $i ]; do
    multi_tab $j $i
    let j++
  done
  let i++
  echo
done

 

5、函数的变量的作用域

函数的变量属于局部变量;

局部变量的作用域:在函数被调用结束时会被自动销毁;
定义局部变量的方法:local VARIABLE=VALUE

本地变量的作用域:运行脚本的shell进程的生命周期,作用范围是当前shell脚本程序文件;

局部变量可以引用本地变量,如果不想让局部变量引用本地变量,可手动定义局部变量;

示例理解6:本地变量与局部变量的作用域;

#!/bin/bash
#

name=lucifer

set_name() {
  name=fitz
  echo "Function:$name."
}

set_name

echo "shell:$name"


#脚本执行结果:

[root@KOU abc]# 
[root@KOU abc]# bash 9.sh
Function:fitz.
shell:fitz
[root@KOU abc]#
#!/bin/bash
#

name=lucifer

set_name() {
  local name=fitz
  echo "Function:$name."
}

set_name

echo "shell:$name"


#脚本执行结果:

[root@KOU abc]# 
[root@KOU abc]# bash 9.sh
Function:fitz.
shell:lucifer
[root@KOU abc]#

==================================== 以下开启烧脑模式 =====================================

6、函数递归

阶乘: 传递一个正整数给脚本;

10!=10*9!=10*9*8!=10*9*8*7!=10*9*8*7*6!=…

#!/bin/bash
#

fact() {
  if [ $1 -eq 0 -o $1 -eq 1 ]; then
    echo 1
  else
    echo $[$1*$(fact $[$1-1])]
  fi
}

fact $1
运算过程: 以传递参数为'4',观看运算过程;

+ fact 4
+ '[' 4 -eq 0 -o 4 -eq 1 ']'
++ fact 3
++ '[' 3 -eq 0 -o 3 -eq 1 ']'
+++ fact 2
+++ '[' 2 -eq 0 -o 2 -eq 1 ']'
++++ fact 1
++++ '[' 1 -eq 0 -o 1 -eq 1 ']'
++++ echo 1
+++ echo 2
++ echo 6
+ echo 24
24

斐波那契数列:

1  1  2  3  5  8  13  21  34  55  89  144  233 …

从第三项开始,每个数字都是前2位数字之和;

#!/bin/bash
#

fab() {
  if [ $1 -eq 1 ]; then
    echo  -n "1 "
  elif [ $1 -eq 2 ]; then
    echo -n "1 "
  else
    echo -n "$[$(fab $[$1-1])+$(fab $[$1-2])] "
  fi
}

for i in $(seq 1 $1); do
  fab $i
done
echo

 

Leave a Reply

Your email address will not be published. Required fields are marked *