Shell脚本—函数


文章目录

  • Shell脚本—函数
  • 1.函数基本概述
  • 2.函数的基本语法
  • 3.函数的传参
  • 4.函数状态返回
  • 5.函数练习
  • 6.shell 数组
  • 7.数组的遍历与循环


1.函数基本概述

1.什么是shell函数

函数就是一堆命令的集合,用来完成特定功能的代码块

2.为什么要使用函数

比如:我们经常需要使用判断功能,完全可以将其封装为一个函数,这样在写程序过程中可以在任何地方调用该函数,不必重复编写,这样能减少代码冗余,可读性更强

2.函数的基本语法

1.定义shell函数,可以通过以下两种方式进行定义

#方式1:
name(){
   command1
   command2
   ....
   commandN
}

#方式2:
function name {
   command1
   command2
   ...
   commandN
}

2.如何调用函数,直接使用函数名调用(可以理解为shell的一条命令)

[root@manage functions]# fun () { echo "123"; }
#调用函数
[root@manage functions]# fun
123

3.函数的传参

在函数内部也可以使用参数$1 $2 …,调用函数function_name $1 $2 …

1.函数中传递参数

[root@manage functions]# fun () { echo "123 $1"; }

#调用
[root@manage functions]# fun 456
123 456

2.函数中接收多个参数

[root@manage functions]# fun1 () { echo "123 $1 $2 $3 $4"; }
[root@manage functions]# fun1 11 22 33 44
123 11 22 33 44

需求1:写一个脚本,该脚本可以实现计算器的功能,可以进行+ - * / 四种计算

eg:sh cash.sh 30 + 40 | sh cash.sh 30 -40 | sh cash.sh 30 * 40 | sh cash.sh 30 / 40

[root@manage functions]# cat fun01.sh 
#!/bin/bash
fun (){
case  $2 in
       +)
       echo $1 + $3 = $[ $1 + $3 ]
       ;;
       -)
       echo $1 - $3 = $[ $1 - $3 ]
       ;;
       x)
       echo $1 x $3 = $[ $1 * $3 ]
       ;;
       /)
       echo $1 / $3 = $[ $1 / $3 ]
       ;;
esac
}
       fun $1 $2 $3
       
       
[root@manage functions]# sh  fun.sh 1 + 2
1 + 2 = 3

需求2:写一个nginx启停脚本,把公用部分写为函数

[root@manage functions]# cat fun02.sh 
#!/bin/bash
nginx_status (){
     systemctl $1 nginx
     if [ $? -eq 0 ];then
          echo "nginx $1 ok"
      else
          echo "nginx $1 err"
          exit
     fi

}
case  $1 in
     start)
     nginx_status $1
     ;;
     stop)
     nginx_status $1
     ;;
     restart)
     nginx_status $1
     ;;
     *)
     echo "USAGE:请输入一个参数: start | stop | restart"
esac

4.函数状态返回

shell的函数返回值,也算是退出的状态,在shell中只有echo、return两种方式

1.return返回值:只能返回1-255的整数,函数使用return返回值,通常只是用来提供其他地方调用获取状态,因此通常返回0或1;0表示成功,1表示失败

2.echo返回值:使用echo可以返回任何字符串结果,通常用于返回数据,比如一个字符串值或者列表值

1.shell函数echo返回字符串结果示例1

#函数实例脚本: echo
echo "The 1 user is : root"
echo "The 2 user is : bin"


[root@manage functions]# cat fun03.sh 
#!/bin/bash
get_users () {
         user=$(awk -F ":" '{print $1}' /etc/passwd)
         echo $user
}

user_list=$(get_users)
index=1
for u in ${user_list}
do
       echo "This $index user is :$u"
       let index++
done


[root@manage functions]# sh fun03.sh 
This 1 user is :root
This 2 user is :bin
This 3 user is :daemon
This 4 user is :adm
This 5 user is :lp
#函数脚本示例:return
[root@manage functions]# cat fun04.sh 
#!/bin/bash
file=$1            #定义文件

t_file(){                   #函数判断
    if [ -f $file ];then
        return 0
    else
        return 1
    fi
}

$?
t_file
rc=$?

if [ $rc -eq 0 ];then
	echo "该文件存在 $file"
else
	echo "该文件不存在 $file"
fi
[root@manage functions]# cat fun05.sh 
#!/bin/bash
fun () {
	systemctl status nginx &>/dev/null

	if [ $? -eq 0 ];then
		return 0
	else
		return 100
	fi

}
fun
echo $?

retrun: 主要控制函数的返回值 可以理解是命令执行后的结果
echo: 主要控制函数的返回数据

根据用户传递的服务名称,获取不同服务的状态

[root@manage functions]# cat fun06.sh 
#!/bin/bash
is_server_running(){
	systemctl status $1 &>/dev/null
    if [ $? -eq 0 ];then
        return 0
    else
        return 1
    fi
}
#调用函数,并根据函数返回状态码进行输出
is_server_running $1 && echo "$1 is Running" || echo "$1 is stoped"

5.函数练习

需求1:使用函数、循环、case实现系统管理工具箱

Command action
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序


[root@manage functions]# cat fun07.sh 
#!/bin/bash
meminfo (){
cat <<-EOF
----------------------------
	Command action
	h 显示命令帮助
	f 显示磁盘分区
	d 显示磁盘挂载
	m 查看内存使用
	u 查看系统负载
	q 退出程序
---------------------------
EOF
}
     meminfo

while true
do
     read -p "请输入你要选择的选项:" Action
case $Action in
          h)
           help
           ;;
          f)
           lsblk
           ;;
          d)
           df -h
           ;;
          m)
           free -m
           ;;
          u)
           uptime
           ;;
          q)
           exit 1
           ;;
          *)
           continue
esac 
done

需求2:使用case、循环、函数、实现JumpServer跳板机功能。
1.用户登陆该服务器则自动执行该脚本。 pass
2.脚本提示可连接主机列表。
3.该脚本无法直接退出。 pass

[root@manager functions]# cat fun11.sh 
#!/bin/bash
meminfo(){
        cat <<-EOF
        -------------------------------
        |       1) lb01-172.16.1.5      |
        |       2) lb02-172.16.1.6      |
        |       3) web01-172.16.1.7     |
        |       4) web02-172.16.1.8     |
        |       h) help                 |
        ---------------------------------
	EOF
}
	meminfo
	trap "" HUP INT TSTP

while true
do
	read -p "请输入你要登录的主机: " Action
	
	case $Action in
		1|lb01)
			ssh root@172.16.1.5
		;;
		2|lb02)
			ssh root@172.16.1.6
		;;
		3|web01)
			ssh root@172.16.1.7
		;;
		4|web02)
			ssh root@172.16.1.8
		;;
		h)
			clear
			meminfo
		;;
		exec)
			exit
			;;
		*)
			continue
	esac
done

需求3:case场景示例,实现多级菜单功能,需要使用到函数、case、循环、if判断、变量

[root@manage functions]# cat fun08.sh 
#!/bin/bash

mem_info_1 () {
 cat <<-EOF
        +-------------------+
        |  command action   |
        +-------------------+
        | (1) Install Nginx |
        | (2) Install PHP   |
        | (3) Install Mysql |
        | (4) quit          |
        +-------------------+
EOF
}

mem_info_2 () {
         cat <<-EOF
        +-----------------------+
        |      nginx-version    |
        +-----------------------+
        | (1) Install Nginx 1.12|
        | (2) Install Nginx 1.13|
        | (3) Install Nginx 1.14|
        | (4) 返回上级菜单      |
        +-----------------------+
EOF
}
mem_info_3 () {
         cat <<-EOF
        +-----------------------+
        |      php-version      |
        +-----------------------+
        | (1) Install PHP 1.12  |
        | (2) Install PHP 1.13  |
        | (3) Install PHP 1.14  |
        | (4) 返回上级菜单      |
        +-----------------------+
EOF
}
mem_info_4 () {
         cat <<-EOF
        +-----------------------+
        |      mysql-version    |
        +-----------------------+
        | (1) Install Mysql 1.12|
        | (2) Install Mysql 1.13|
        | (3) Install Mysql 1.14|
        | (4) 返回上级菜单      |
        +-----------------------+
EOF
}
while true
do
        #打印第一个菜单
        mem_info_1
        read -p "请输入你要进入的菜单:" mem_1 
case $mem_1 in
         1)
              clear
              mem_info_2
while true
do
              read -p "请输入要安装的版本:" mem_2
                case $mem_2 in
                    1)
                     echo "Install Nginx 1.12"
                     ;;
                    2)
                     echo "Install Nginx 1.13"
                     ;;
                    3)
                     echo "Install Nginx 1.14"
                     ;;
                    4)
                      clear
                      mem_info_1
                      continue
                esac
done
         ;;
         2)
              clear
              mem_info_3
while true
do
              read -p "请输入要安装的版本:" mem_2
                case $mem_2 in
                    1)
                     echo "Install PHP 1.12"
                     ;;
                    2)
                     echo "Install PHP 1.13"
                     ;;
                    3)
                     echo "Install PHP 1.14"
                     ;;
                    4)
                      clear
                      mem_info_1
                      continue
                esac
done
          ;;
         3)
              clear
              mem_info_4
while true
do
              read -p "请输入要安装的版本:" mem_2
                case $mem_2 in
                    1)
                     echo "Install Mysql 1.12"
                     ;;
                    2)
                     echo "Install Mysql 1.13"
                     ;;
                    3)
                     echo "Install Mysql 1.14"
                     ;;
                    4)
                      clear
                      mem_info_1
                      continue
                esac
done
          ;;
         4)
                      clear
                      mem_info_1
                      break

esac
done

6.shell 数组

1.什么是数组

数组其实也是变量的意思,传统的变量只能存储一个值,但属组可以存储多个值

2.数组的分类

shell数组分为普通数组和关联数组

普通数组:只能使用整数作为数组索引

关联数组:可以使用字符串作为数组索引

books=(linux nginx shell)   普通数组   python(列表)
------------------------
|linux | nginx | shell |
------------------------
|   0  |   1   |   2   |    索引(下标)
ps :普通数组下标只能是整数

[root@manage functions]# book=(linux nginx shell)
[root@manage functions]# echo $book
linux
[root@manage functions]# echo ${book[3]}

[root@manage functions]# echo ${book[2]}
shell
[root@manage functions]# echo ${book[1]}
nginx


info=([name]=abc [age]=18 [skill]=linux)  关联数组   python(字典)
----------------------
| abc  | 18  | linux |
| name | age | skill |     索引(下标)
----------------------
PS:关联数组的下标可以是字符串

#需要先声明
[root@manage functions]# declare -A init
[root@manage functions]# init=([name]=abc [age]=18 [skill]=linux)
[root@manage functions]# echo ${init[name]}
abc
[root@manage functions]# echo ${init[age]}
18
[root@manage functions]# echo ${init[skill]}
linux
[root@manage functions]# echo ${init[*]}
abc 18 linux
#还可以取出索引
[root@manage functions]# echo ${!init[@]}
name age skill

3.普通数组仅能使用整数来作为索引

1.普通数组的赋值

#方式1:针对每个索引进行赋值(数组名[索引]=变量值)
[root@manage functions]# array1[0]=pear
[root@manage functions]# array1[1]=apple
[root@manage functions]# array1[2]=orange
[root@manage functions]# echo ${array1[1]}
apple
[root@manage functions]# echo ${array1[0]}
pear
[root@manage functions]# echo ${array1[2]}
orange

#方式2:一次赋多个值(数组名=(多个变量值))
[root@manage functions]# array2=(tom jack ali)
[root@manage functions]# array3=(tom jack ali "bash shell")
[root@manage functions]# array4=(1 2 3 "bash shell" [20]=docker)
[root@manage functions]# echo ${array2[0]}
tom
[root@manage functions]# echo ${array2[2]}
ali
[root@manage functions]# echo ${array3[2]}
ali
[root@manage functions]# echo ${array3[3]}
bash shell
[root@manage functions]# echo ${array4[5]}

[root@manage functions]# echo ${array4[4]}

[root@manage functions]# echo ${array4[3]}
bash shell
[root@manage functions]# echo ${array4[20]}
docker

7.数组的遍历与循环

1.数组的遍历与循环是啥?

其实就是使用对数组进行批量赋值,然后通过循环方式批量取出数组的值对其进行统计

2.如果需要统计一个文件中某个字段出现的次数,怎么办?

思路就是:要统计谁就将谁作为数组的索引,注意仅支持关联数组。

3.如上的方式可以实现数组的赋值,但数组赋值后还需要遍历结果,才能完成统计需求,遍历的方式有以下2种

1. 通过数组的个数进行遍历(不推荐)
   2. 通过数组的索引进行遍历(推荐)

1.普通数组赋值与遍历示例

[root@manage array]# cat array01.sh 
#!/bin/bash

while read line
do
     host[i++]=$line
done </etc/hosts

for item in ${!host[@]}
do
          echo "你的索引是:$item 你对应的值是:${host[$item]}"
done

[root@manage array]# sh array01.sh 
你的索引是:0 你对应的值是:127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
你的索引是:1 你对应的值是:::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@manage array]# cat array02.sh 
#!/bin/bash
declare -A login

while read line
do
     types=$(echo $line |awk -F ":" '{print $NF}')
     let login[$types]++
 
done</etc/passwd

for item in ${!login[@]}
do
       echo "你的索引是:$item 索引出现的次数是:${login[$item]}"
done


[root@manage array]# sh array02.sh 
你的索引是:/sbin/nologin 索引出现的次数是:21
你的索引是:/bin/sync 索引出现的次数是:1
你的索引是:/bin/bash 索引出现的次数是:35
你的索引是:/sbin/shutdown 索引出现的次数是:1
你的索引是:/sbin/halt 索引出现的次数是:1
[root@manage array]# cat sex.txt 
jack m
alice f
tom m
rose f
robin m
abc m
ttt f


[root@manage array]# cat array03.sh 
#!/bin/bash
declare -A sex
while read line
do
      #1.取出文件的行,将我们需要统计的列给提取出来
      types=$(echo $line |awk '{print $2}')
      #2.要统计什么,就将谁作为索引名称:sex[索引]=值
      let sex[$types]++
done<sex.txt

      #3.遍历索引
for item in ${!sex[@]}
do
    echo "你的索引是:$item  该索引出现的次数是:${sex[$item]}"
done

需求1:使用shell数组统计 nginx的访问日志,统计TOP10的IP

需求2:使用shell数组统计 nginx的访问日志,统计TOP10的URI

[root@manage array]# cat array04.sh 
#!/bin/bash
declare -A sex
while read line
do
      #1.取出文件的行,将我们需要统计的列给提取出来
      types=$(echo $line |awk '{print $1}')
      #2.要统计什么,就将谁作为索引名称:sex[索引]=值
      let sex[$types]++
done<access.log

      #3.遍历索引
for item in ${!sex[@]}
do
    echo "${sex[$item]} $item"
done


#用awk数组取值
 awk '{array[$1]++} END { for (key in array) print array[key],key }' access.log | sort -rn |head