shell编程系列6--shell中的函数
1.函数介绍
linux shell中的函数和大多数编程语言中的函数一样
将相似的任务或者代码封装到函数中,供其他地方调用
语法格式
第一种格式
name()
{
command1
command2
......
commondn
}
第二种格式
function name
{
command1
command2
......
commondn
}
2.调用函数
直接使用函数名调用,可以将其想象成shell中的一条命令
函数内部可以直接使用参数 $1、$2...$n
调用函数:function_name $1 $2
shell终端中定义函数
[root@es01 shell]# test()
> {
> echo "test function"
> }
[root@es01 shell]#
[root@es01 shell]# test
test function
[root@es01 shell]# function greeting
> {
> echo "hello,zhangsan"
> }
[root@es01 shell]# greeting
hello,zhangsan
练习;nginx的守护进程
[root@es01 shell]# cat nginx_daemon.sh
#!/bin/bash
#
# 获取脚本子进程的pid,如果脚本名称中带nginx,也会当成nginx进程
this_pid=$$
while true
do
ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null
if [ $? -eq 0 ];then
echo "Nginx is running well"
sleep 5
else
systemctl start nginx
echo "Nginx is down,Start it..."
fi
done
[root@es01 shell]# nohup sh nginx_daemon.sh &
[1] 97855
[root@es01 shell]# nohup: ignoring input and appending output to ‘nohup.out’
[root@es01 shell]# tail -f nohup.out
Nginx is running well
Nginx is running well
Nginx is running well
Nginx is running well
4.向函数传递参数
高级语言传参
int example_1(int arg1,int arg2)
{
arg1=arg2
...
...
return null
}
高级语言函数调用
int num1=10;
int num2=20;
调用函数形式一:int num3=example_1(num1,num2);
调用函数形式二:
int num4;
num4=example_1(num1,num2);
shell中传参
function name
{
echo "Hello $1"
echo "Hello $2"
}
shell中函数调用
函数调用:name Lily Allen
[root@es01 shell]# function greeting
> {
> echo "hello zhangsan"
> }
[root@es01 shell]# greeting
hello zhangsan
# 调用参数
[root@es01 shell]# function greeeting
> {
> echo "hello $1"
> }
[root@es01 shell]# greeeting jack
hello jack
[root@es01 shell]# greeeting tom
hello tom
向函数传递参数:
函数传参和给脚本传参类似,都是使用$1 $2 $3 $4 $5 $6 $7这种方式
例子1:
需求描述:写一个脚本,该脚本可以实现计算器的功能,可以进行+-*/四种运算。
例如:sh calculate.sh 30 + 40 | sh calucate.sh 30 - 40
[root@es01 shell]# cat calucate.sh
#!/bin/bash
#
function calcu
{
case $2 in
+)
echo "`expr $1 + $3`"
;;
-)
echo "`expr $1 - $3`"
;;
\*)
echo "`expr $1 \* $3`"
;;
/)
echo "`expr $1 / $3`"
;;
esac
}
calcu $1 $2 $3
[root@es01 shell]# sh calucate.sh 20 + 30
50
[root@es01 shell]# sh calucate.sh 20 - 30
-10
5.函数的返回值
方法一 return
方法二 echo
使用return返回值
使用return返回值,只能返回1-255的整数
函数使用return返回值,通常只是用来供其他地方调用获取状态,因此通常仅返回0或1;0表示成功,1表示失败
# 判断nginx进程是否存在
[root@es01 shell]# cat nginx.sh
#!/bin/bash
#
this_pid=$$
function is_nginx_running
{
ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null
if [ $? -eq 0 ];then
return 0
else
return 1
fi
}
is_nginx_running && echo "nginx is running" || echo "nginx is stopped"
[root@es01 shell]# sh nginx.sh
nginx is running
[root@es01 shell]# systemctl stop nginx
[root@es01 shell]# sh nginx.sh
nginx is stopped
[root@es01 shell]# sh -x nginx.sh
+ this_pid=101185
+ is_nginx_running
+ ps -ef
+ grep nginx
+ grep -v grep
+ grep -v 101185
+ '[' 1 -eq 0 ']'
+ return 1
+ echo 'nginx is stopped'
nginx is stopped
使用echo返回值
使用echo可以返回任何字符串结果
通常用于返回数据,比如一个字符串值或者列表值
# 获取系统中的用户
[root@es01 shell]# cat get_sys_user.sh
#!/bin/bash
#
# 获取系统所有的用户名
function get_users
{
users=`cat /etc/passwd | cut -d: -f1`
echo $users
}
# 定义一个变量将获取用户列表赋值给这个变量
user_list=`get_users`
index=1
for u in $user_list
do
echo "the $index user is : $u"
index=$(($index+1))
done
[root@es01 shell]# sh get_sys_user.sh
the 1 user is : root
the 2 user is : bin
the 3 user is : daemon
the 4 user is : adm
the 5 user is : lp
the 6 user is : sync
the 7 user is : shutdown
the 8 user is : halt
the 9 user is : mail
the 10 user is : operator
the 11 user is : games
the 12 user is : ftp
the 13 user is : nobody
the 14 user is : systemd-network
the 15 user is : dbus
the 16 user is : polkitd
the 17 user is : sshd
the 18 user is : postfix
the 19 user is : ajie
the 20 user is : chrony
the 21 user is : elasticsearch
the 22 user is : nginx
6.shell函数中的局部变量和全局变量
不做特殊声明,shell中变量都是全局变量
大型脚本程序函数中慎用全局变量
局部变量:
在函数内部定义局部变量时,使用local关键字
函数内和函数外若同时存在变量,函数内部变量会覆盖外部变量
#
[root@es01 shell]# cat var.sh
#!/bin/bash
#
var1="Hello world"
function test
{
var2=87
}
echo $var1
echo $var2
# 因为函数test没有被调用,所以变量 $var2 没有生效,为空
[root@es01 shell]# sh var.sh
Hello world
[root@es01 shell]#
# 调用test函数后,$var2就变成了全局变量
[root@es01 shell]# cat var.sh
#!/bin/bash
#
var1="Hello world"
function test
{
var2=87
}
echo $var1
echo $var2
test # 调用test函数后,$var2就变成了全局变量
echo $var1
echo $var2
[root@es01 shell]# sh var.sh
Hello world
Hello world
87
# 在函数中也可以调用全局变量
[root@es01 shell]# cat var.sh
#!/bin/bash
#
var1="Hello world"
function test
{
var2=87
}
echo $var1
echo $var2
test
echo $var1
echo $var2
function test1
{
echo $var2
}
test1
[root@es01 shell]# sh var.sh
Hello world
Hello world
87
87
# 如果函数中声明了局部变量,当函数执行完成后局部变量就会被销毁
[root@es01 shell]# cat var.sh
#!/bin/bash
#
var1="Hello world"
function test
{
local var2=87 # 局部变量,只在函数内部生效,生命周期只在函数内部
}
test
echo $var1
echo $var2
[root@es01 shell]# sh var.sh
Hello world
[root@es01 shell]#
7.函数库
为什么需要定义函数库?
经常使用的重复代码可以封装成函数文件,功能函数,程序工具
函数库文件一般不直接执行,而是由其他脚本调用
函数库示例:
定义一个函数库,该函数库实现以下几个函数:
1.加法函数add
add 12 89
2.减法函数reduce
reduce 90 30
3.乘法函数multiple
multiple 12 10
4.除法函数divide
divide 9 3
5.打印系统运行情况的函数sys_load,该函数可以显示内存运行情况,磁盘使用情况
# 定义库函数
[root@es01 shell]# cat lib/base_function
function add
{
echo "`expr $1 + $2`"
}
function reduce
{
echo "`expr $1 - $2`"
}
function multiple
{
echo "`expr $1 \* $2`"
}
function divide
{
echo "`expr $1 / $2`"
}
function sys_load
{
echo "Memory info"
echo
free -m
echo
echo "Disk Usage"
echo
df -h
echo
}
# 测试库函数
[root@es01 shell]# . lib/base_function
[root@es01 shell]# sys_load
Memory info
total used free shared buff/cache available
Mem: 3773 123 3300 11 348 3389
Swap: 2047 0 2047
Disk Usage
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 49G 3.3G 46G 7% /
devtmpfs 1.9G 0 1.9G 0% /dev
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 1.9G 12M 1.9G 1% /run
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/sda1 297M 125M 172M 43% /boot
/dev/mapper/centos-data 49G 33M 49G 1% /data
tmpfs 378M 0 378M 0% /run/user/0
# 调用库函数
[root@es01 shell]# cat calculate.sh
#!/bin/bash
#
# 引入库函数,写绝对路径避免出错
. /data/shell/lib/base_function
add 12 23
reduce 90 30
multiple 12 12
divide 12 2
经验之谈:
库文件名的后缀是任意的,但一般使用.lib
库文件通常没有可执行权限
库文件无需和脚本放在同级目录,只需要在脚本中引用时指定
第一行一般使用#!/bin/echo,输出警告信息,避免用户执行