shell脚本——函数(包含应用案例)

前言

其实shell的函数很简单 对于学过其他编程语言的同学来说 就是轻而易举

什么是函数

  • shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数

  • 给这段代码起个名字称为函数名,后续可以直接调用该段代码的功能

  • 在shell种定义函数可以使用代码模块化,便于复用代码

  • 函数必须先定义才可以使用

如何定义函数

方法一

函数名()
{
    
    
  函数体(一堆命令的集合,来实现某个功能)   
}

方法二

function 函数名()
{
    
    
   函数体(一堆命令的集合,来实现某个功能)
}

熟悉函数写法

  1. 阶乘
#!/bin/bash
factorial() {
    
    
factorial=1
for((i=1;i<=5;i++))
do
        factorial=$[ $factorial * $i ]
        echo "$factorial"
done
echo "5的阶乘是:$factorial"
}
factorial

#!/bin/bash
function factorial {
    
    
a=1
for ((i=1;i<=10;i++))
do
        a=$[ $a * $i ]
        echo "$a"
done
echo "10的阶乘是:$a"
}
factorial
  1. 传参
#!/bin/bash
factorial() {
    
    
factorial=1
for((i=1;i<=$1;i++))
do
        factorial=$[ $factorial * $i ]
        echo "$factorial"
done
echo "$1 的阶乘是:$factorial"
}

factorial $1
factorial $2
factorial $3

# 执行函数
bash factorial.sh 10 8 5
10 的阶乘是:3628800
8 的阶乘是:40320
5 的阶乘是:120


#!/bin/bash
factorial() {
    
    
a=1
for i in `seq $1`
do    
        let a*=$i				
        echo "$a"
done
echo "$1 的阶乘是:$a"
}

factorial $1

# 执行函数
[root@maomao ~]# bash cheng.sh 10
1
2
6
24
120
720
5040
40320
362880
3628800
10 的阶乘是:3628800


#!/bin/bash
fun () {
    
    
read -p "请输入一个数字计算他的阶乘:" num 
fun=1
for((i=1;i<=$num;i++))
do
        fun=$[ $fun * $i ]
        echo "$fun"
done

}
fun $num

函数返回值

  • 函数返回值是函数最后一条命令
  • shell返回值最高是255
#!/bin/bash
re() {
    
    
read -p "enter num:" num 
return $[2*$num]
}

re
echo "re return value:$?"


#!/bin/bash
fun() {
    
    
read -p "enter num:" num 
echo $[2*$num]
}

result=`fun`
echo "fun return value:$result"		
#这个返回值不是真的返回值

函数中return说明:

  • return可以结束一个函数。类似于循环控制语句break(结束当前循环,执行循环体后面的代码)。
  • return默认返回函数中最后一个命令状态值,也可以给定参数值,范围是0-256之间。
  • 如果没有return命令,函数将返回最后一个指令的退出状态值。

return可以结束一个函数

#!/bin/bash
fun(){
    
    
	echo 'maomao'
	echo 'zhuzhu'
	return
	echo 'niuniu'
}
fun

# 执行脚本
[root@maomao ~]# bash test.sh
maomao
zhuzhu

return默认返回函数中最后一个命令状态值

#!/bin/bash
fun(){
    
    
	echo 'zhuzhu'
	echo 'maomao'
	return 88
	echo 'niuniu'
}
fun

# 执行脚本
[root@maomao ~]# bash test1.sh
zhuzhu
maomao
[root@maomao ~]# echo $?
88

函数传参 位置参数

#!/bin/bash
if [ $# -ne 3 ];then
        echo "useage:`basename $0` par1 par2 par3"
        exit
fi

fun3() {
    
    
        echo "$(($1 * $2 * $3 ))" 
}

result=`fun3 $1 $2 $3`		这个$1 $2 $3是外面的参数赋给函数里的$1 $2 $3
echo "$result"				你传给程序 程序传给函数

# 执行脚本
[root@maomao ~]# bash parameter.sh 1 2 3
6
[root@maomao ~]# bash parameter.sh 2 3 4
24

如果result=`fun3 $3 $3 $3`  	三个$3相乘 3*3*3
[root@maomao ~]# bash parameter.sh 1 2 3
27

函数传参 数组变量

计算数组里的值之乘

#!/bin/bash
num1=(1 2 3 4 5)
num2=(2 4 6 8 10) 
array() {
    
    
        local array=1
        for i in $*
        do  
                array=$[ array * $i ]
        done
        echo "$array"
}

array ${num1[*]}    
array ${num2[@]}

# 执行脚本
[root@maomao ~]# bash array.sh 
120
3840

数组传参 变成一个新的数组

#!/bin/bash
num=(1 2 3 4 5)
num2=(2 4 6 8 10)
array() {
    
    
        local newarray=($*)
        local i
        for((i=0;i<$#;i++))
        do  
                outarray[$i]=$(( ${newarray[$i]} * 5 ))
        done
        echo "${outarray[*]}"
}
result=`array ${
     
     num[*]}`
echo ${result[*]}

result=`array ${
     
     num2[@]}`
echo ${result[@]}

# 执行脚本
[root@maomao ~]# bash array1.sh
5 10 15 20 25
10 20 30 40 50

将原数组的值改变

#!/bin/bash
num=(2 4 6 8 10)
array() {
    
    
        local newarray=()
        local i
        for i
        do
                newarray[i++]=$[ $i * 10 ]
        done
        echo "${newarray[*]}"

}
result=`array ${
     
     num[*]}`
echo "${result[*]}"

# 执行脚本
[root@maomao ~]# bash array2.sh 
20 40 60 80 100


  • 函数接受位置参数 $1 $2 $3 … $n
  • 函数接受数组变量 $@ $*
  • 函数将接收到所有参数赋值给数组 newarry=($*)

应用案例

  1. 写一个脚本收集用户输入的基本信息(姓名,性别,年龄),如不输入一直提示输入
  2. 最后根据用户的信息输出相对应的内容
#!/bin/bash
#该函数实现用户如果不输入内容则一直循环直到用户输入为止,并且将用户输入的内容打印出来
input_fun()
{
    
    
  input_var=""
  output_var=$1
  while [ -z $input_var ]
    do
    	read -p "$output_var" input_var
    done
    echo $input_var
}

input_fun 请输入你的姓名:

或者
#!/bin/bash
fun()
{
    
    
    read -p "$1" var
    if [ -z $var ];then
        fun $1
    else
        echo $var
    fi
}


#调用函数并且获取用户的姓名、性别、年龄分别赋值给name、sex、age变量
name=$(input_fun 请输入你的姓名:)
sex=$(input_fun 请输入你的性别:)
age=$(input_fun 请输入你的年龄:)

#根据用户输入的性别进行匹配判断
case $sex in
            man)
            if [ $age -gt 18 -a $age -le 35 ];then
                echo "中年大叔你油腻了吗?加油"
            elif [ $age -gt 35 ];then
                echo "保温杯里泡枸杞"
            else
                echo "年轻有为。。。"
            fi
            ;;
            woman)
            xxx
            ;;
            *)
            xxx
            ;;
esac

综合案例

任务背景
现有的跳板机虽然实现了统一入口来访问生产服务器,yunwei用户权限太大可以操作跳板机上的所有目录文件,存在数据被误删的安全隐患,所以希望你做一些安全策略来保证跳板机的正常使用。

具体要求

  1. 只允许yunwei用户通过跳板机远程连接后台的应用服务器做一些维护操作
  2. 公司运维人员远程通过yunwei用户连接跳板机时,跳出以下菜单供选择:
欢迎使用Jumper-server,请选择你要操作的主机:
3. DB1-Master
4. DB2-Slave
5. Web1
6. Web2
h. help
q. exit
  1. 当用户选择相应主机后,直接免密码登录成功
  2. 如果用户不输入一直提示用户输入,直到用户选择退出

综合分析

  1. 将脚本放到yunwei用户家目录里的.bashrc文件里(/shell05/jumper-server.sh)
  2. 将菜单定义为一个函数[打印菜单],方便后面调用
  3. 用case语句来实现用户的选择【交互式定义变量】
  4. 当用户选择了某一台服务器后,进一步询问用户需要做的事情 case…esac 交互式定义变量
  5. 使用循环来实现用户不选择一直让其选择
  6. 限制用户退出后直接关闭终端 exit
#!/bin/bash
# jumper-server
# 定义菜单打印功能的函数
menu()
{
    
    
cat <<-EOF
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
    EOF
}
# 屏蔽以下信号
trap '' 1 2 3 19
# 调用函数来打印菜单
menu
#循环等待用户选择
while true
do
# 菜单选择,case...esac语句
read -p "请选择你要访问的主机:" host
case $host in
    1)
    ssh [email protected]
    ;;
    2)
    ssh [email protected]
    ;;
    3)
    ssh [email protected]
    ;;
    h)
    clear;menu
    ;;
    q)
    exit
    ;;
esac
done


将脚本放到yunwei用户家目录里的.bashrc里执行:
bash ~/jumper-server.sh
exit

进一步完善需求
为了进一步增强跳板机的安全性,工作人员通过跳板机访问生产环境,但是不能在跳板机上停留。

#!/bin/bash
#公钥推送成功
trap '' 1 2 3 19
#打印菜单用户选择
menu(){
    
    
cat <<-EOF
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
EOF
}

#调用函数来打印菜单
menu
while true
do
read -p "请输入你要选择的主机[h for help]:" host

#通过case语句来匹配用户所输入的主机
case $host in
    1|DB1)
    ssh [email protected]
    ;;
    2|DB2)
    ssh [email protected]
    ;;
    3|web1)
    ssh [email protected]
    ;;
    h|help)
    clear;menu
    ;;
    q|quit)
    exit
    ;;
esac
done

自己完善功能:
1. 用户选择主机后,需要事先推送公钥;如何判断公钥是否已推
2. 比如选择web1时,再次提示需要做的操作,比如:
clean log
重启服务
kill某个进程

补充

1) SIGHUP             重新加载配置    
2) SIGINT            键盘中断^C
3) SIGQUIT          键盘退出
9) SIGKILL             强制终止
15) SIGTERM            终止(正常结束),缺省信号
18) SIGCONT           继续
19) SIGSTOP           停止
20) SIGTSTP         暂停^Z

猜你喜欢

转载自blog.csdn.net/Cantevenl/article/details/115306150