shell 编程之函数

简介

把一段独立功能的代码当作一个整体,并为之一个名字;命名的代码段,此即为函数。函数存在的意义,就是为了可以更加方便地进行代码重用。

函数不会自动执行,只有在代码中调用函数名称,才会在调用位置执行函数所包含的代码段。

shell 编程的函数有两种语法:

# 语法一:
function  f_name  {
    ...函数体...
}

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

返回值与返回状态

函数的返回值,即函数内代码段执行的输出结果,比如:

test_fuc() {
    echo 123
}
test_fuc

则此函数的返回值,就是 123

函数的返回状态,即函数体中运行的最后一条命令的状态结果,也可以使用 return 进行自定义返回状态。

test_fuc() {
    id hzz
    return_id=$?
    return $return_id
}
test_fuc
echo $?

执行到 return 后,函数会中断并退出,且返回 return 后面所跟的状态值。

接收参数

函数可以使用脚本中定义的变量,也可以接收脚本提供的参数。

# 直接使用脚本变量
iname=hzz
id_name() {
    id $iname
}
id_name

# 接收脚本参数
iname=hzz
id_name() {
    id $1
}
id_name $iname

注意:函数体内所获取的 $1 ,不是脚本的 $1 参数,而是脚本传递给函数体的 $1 参数,其他传参类似。其实可以将整个函数体看做是一个完整的脚本,引用函数可看做是调用并执行脚本文件。

局部变量

在 shell 脚本中,直接定义的变量只在脚本中生效。同样的,在函数中,也可以并且推荐使用 local 定义局部变量,使得变量只在函数中生效。

函数内部尽量使用局部变量,以免跟主程序冲突。除非此函数的备份功能是为了改变主程序的变量。

iname=hzz
id_name() {
    local iname=xyz
    echo $iname
}
id_name
echo $iname

从执行结果可以看到,iname 并没有被函数改变,因为函数定义的是局部变量。

函数递归

函数递归,即函数直接或间接调用其本身。要小心使用,避免造成死循环。

test_fuc() {
    iname=$1
    if [[ "$iname" == "hzz" ]]; then
        echo right
        iname=xyz
        test_fuc $iname
    else
        echo wrong
        return 1
    fi
}
test_fuc hzz

示例

服务脚本框架

#!/bin/bash
#
# chkconfig: - 50 50
# description: test service script
#
prog=$(basename $0)
lockfile=/var/lock/subsys/$prog

start() {
    if [ -f $lockfile ]; then
        echo "$prog is running yet."
    else
        touch $lockfile
        [ $? -eq 0 ] && echo "start $prog finshed."
    fi
}

stop() {
    if [ -f $lockfile ]; then
        rm -f $lockfile
        [ $? -eq 0 ] && echo "stop $prog finished."
    else
        echo "$prog is not running."
    fi
}
status() {
    if [ -f $lockfile ]; then
        echo "$prog is running"
    else
        echo "$prog is stopped."
    fi
}

usage() {
    echo "Usage: $prog {start|stop|restart|status}"
}

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

根据参数创建10个用户

#!/bin/bash
#
# 5: user exists

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 "Unkown Error."
    fi
done

计算 N! 运算

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

fact $1

序列

1,1,2,3,5,8... 后一个数是前面的数字之和。

#!/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

打印 NN 乘法表

#!/bin/bash
#
max=$1
m_table() {
    local max=$max
    for ((i=1;i<=$max;i++)); do
        for ((j=1;j<=$i;j++)); do
            echo -n "$j*$i=$[$i*$j] "
        done
        echo
    done
}
m_table
消息盒子

# 暂无消息 #

只显示最新10条未读和已读信息