10@函数
文章目录
函数
一、函数介绍
1、什么是函数
函数就是用来盛放一组代码的容器,函数内的一组代码完成一个特定的功能,称之为一组代码块,调用函数便可触发函数内代码块的运行,这可以实现代码的复用,所以函数又可以称之为一个工具
2、为何要用函数
#1、减少代码冗余
#2、提升代码的组织结构性、可读性
#3、增强扩展性
二、函数的基本使用
具备某一功能的工具=>函数
事先准备好哦工具=>函数的定义
遇到应用场景,拿来就用=>函数的调用
所以函数的使用原则:先定义,后调用
1、定义函数
#语法:
[ function ] funname [()]
{
命令1;
命令2;
命令3;
...
[return int;]
}
# 示例1:完整写法
function 函数名() {
函数要实现的功能代码
}
# 示例2:省略关键字(),注意此时不能省略关键字function
function 函数名 {
函数要实现的功能代码
}
# 示例3:省略关键字function
函数名() {
函数要实现的功能代码
}
2、调用函数
# 语法:
函数名 # 无参调用
函数名 参数1 参数2 # 有参调用
# 示例
function test1(){
echo "执行第一个函数"
}
function test2 {
echo "执行第二个函数"
}
test3(){
echo "执行第三个函数"
}
# 调用函数:直接引用函数名字即调用函数,会触发函数内代码的运行
test1
test2
test3
# ps:关于有参调用见下一小节
三、函数参数
如果把函数当成一座工厂,函数的参数就是为工厂运送的原材料
1、调用函数时可以向其传递参数
# 调用函数test1,在其后以空格为分隔符依次罗列参数
test1 111 222 333 444 555
在函数体内部,通过
$n
的形式来获取参数的值,例如,$1
表示第一个参数,$2
表示第二个参数…当n>=10时,需要使用${n}
来获取参数
[root@egon ~]# cat b.sh
function test1(){
echo "...start..."
echo $1
echo $2
echo $3
echo "...end..."
}
test1 111 222 333 444 555 # 为函数体传参
[root@egon ~]# ./b.sh
...start...
111
222
333
...end...
ps:在脚本内获取脚本调用者在命令行里为脚本传入的参数,同样使用的是$n,不要搞混
[root@egon ~]# cat b.sh
function test1(){
echo "...start..."
echo "这是函数内:$1"
echo "这是函数内:$2"
echo "这是函数内:$3"
echo "...end..."
}
# test1 111 222 333 444 555
test1
echo "这是脚本级的参数$1"
echo "这是脚本级的参数$2"
echo "这是脚本级的参数$3"
[root@egon ~]#
[root@egon ~]#
[root@egon ~]# ./b.sh xxx yyy zzz mmm nnn
...start...
这是函数内:
这是函数内:
这是函数内:
...end...
这是脚本级的参数xxx
这是脚本级的参数yyy
这是脚本级的参数zzz
[root@egon ~]#
2、案列:(编写简易计算器)
#!/bin/basha
read -p "请输入第一个整数:" num1
read -p "请输入计算方式:" num2
read -p "请输入第二个整数:" num3
function hzl() { #函数编写
echo "= $(($1$2$3))"
}
hzl $num1 "$num2" $num3 #函数调用
[root@web01 opt]# sh hzl.sh
请输入第一个整数:5
请输入计算方式:*
请输入第二个整数:8
= 40
[root@web01 opt]# sh hzl.sh
请输入第一个整数:9
请输入计算方式:/
请输入第二个整数:8
= 1
[root@web01 opt]# sh hzl.sh
请输入第一个整数:7
请输入计算方式:+
请输入第二个整数:3
= 10
3、案列(简易nginx安装脚本编写)
#!bin/bash
#安装nginx、启动|停止nginx、监控nginx #脚本编写
#初始化系统一些函数
. /etc/init.d/functions
#打印输出内容
function print_action() {
if [ $2 -eq 0 ]; then
action "$1" /bin/true
else
action "$1" /bin/false
fi
}
function check_nginx() {
rpm -q nginx
if [ $? -eq 0 ];then
print_action "nginx已安装" 0
else
print_action "nginx未安装" 1
fi
}
function repo_nginx() {
cat > /etc/yum.repos.d/nginx.repo <<EOF
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/7/\$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF
yum clean all
yum makecache
if [ $? -eq 0 ];then
print_action "nginx.repo源安装成功" 0
fi
install_nginx
restart_nginx
}
function install_nginx() {
a=`nginx -t`
yum install nginx -y
if [ $? -eq 0 ];then
print_action "安装成功" 0
elif [ $a -eq 0 ];then
print_action "nginx_file ok"
else
echo "nginx.repo源正在创建及安装"
yum repolist
repo_nginx
fi
}
function status_nginx() {
systemctl status nginx
if [ $? -eq 0 ];then
print_action "检查成功" 0
else
print_action "检查失败" 1
fi
}
function stop_nginx() {
systemctl stop nginx
if [ $? -eq 0 ];then
print_action "nginx已停止" 0
else
print_action "nginx停止失败" 1
fi
}
function restart_nginx() {
systemctl restart nginx
if [ $? -eq 0 ];then
print_action "nginx启动成功" 0
else
print_action "nginx启动失败" 1
fi
}
function main() {
PS3="请选择需要的项目:"
select i in check_nginx install_nginx stop_nginx restart_nginx status exit
do
case $i in
check_nginx)
check_nginx
;;
install_nginx)
install_nginx
;;
stop_nginx)
stop_nginx
;;
restart_nginx)
restart_nginx
;;
status)
status_nginx
;;
exit)
print_action "成功退出" 0
exit
;;
*)
echo "输入有误,暂未添加,请重新开始"
print_action "已退出" 0
exit
esac
done
}
main
[root@web01 yum.repos.d]#
[root@web01 ~]# sh hzl.sh
1) check_nginx 3) stop_nginx 5) status
2) install_nginx 4) restart_nginx 6) exit
请选择需要的项目:1
nginx-1.20.1-1.el7.ngx.x86_64
nginx已安装 [ 确定 ]
请选择需要的项目:5
● nginx.service - nginx - high performance web server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
Active: active (running) since 二 2021-06-22 04:41:14 CST; 3min 35s ago
Docs: http://nginx.org/en/docs/
Process: 2075 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Main PID: 2076 (nginx)
CGroup: /system.slice/nginx.service
├─2076 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
└─2077 nginx: worker process
6月 22 04:41:14 web01 systemd[1]: Starting nginx - high performance web server...
6月 22 04:41:14 web01 systemd[1]: PID file /var/run/nginx.pid not readable (yet?) after start.
6月 22 04:41:14 web01 systemd[1]: Started nginx - high performance web server.
检查成功 [ 确定 ]
请选择需要的项目:
温故知新
参数处理 | 说明 |
---|---|
$# | 传递到脚本或函数的参数个数 |
$* | 所有参数 |
$@ | 所有参数,与$*类似 |
$$ | 当前脚本进程的ID号 |
$? | 获取上一条命令执行完毕后的退出状态。0表示正确,非0代表错误,如果执行的是函数那么$?取的是函数体内return后的值 |
ps:
#1、当$*和$@没有被引号引用起来的时候,它们确实没有什么区别,都会把位置参数当成一个个体。
#2、"$*" 会把所有位置参数当成一个整体(或者说当成一个单词),如果没有位置参数,则"$*"为空,如果有两个位置参数并且分隔符为空格时,"$*"相当于"$1 $2"
#3、"$@" 会把所有位置参数当成一个单独的字段,如果没有位置参数,则"$@"展开为空(不是空字符串,而是空列表),如果存在一个位置参数,则"$@"相当于"$1",如果有两个参数,则"$@"相当于"$1" "$2"等等
四、示例
[root@egon ~]# cat b.sh
echo "=======函数test1==========="
function test1(){
echo "$*" # 111 222 333 444 555
echo "$@" # 111 222 333 444 555
echo $# # 5
echo $$ # 87380
echo $? # 0
}
test1 111 222 333 444 555
echo "=======函数test2==========="
function test2(){
for i in "$*" # 注意:$*不加引号结果与$@一模一样
do
echo $i
done
}
test2 111 222 333 "444 555" # 注意"444 555"被引号引成了一个参数
# 运行结果为:111 222 333 444 555
echo "=======函数test3==========="
function test3(){
for i in "$@" # 注意:$*不加引号结果与$@一模一样
do
echo $i
done
}
test3 111 222 333 "444 555" # 注意"444 555"被引号引成了一个参数
# 运行结果为:
# 111
# 222
# 333
# 444 555
五、 函数的返回值
如果把函数当成一座工厂,函数的返回值就是工厂的产品,在函数内使用return关键字返回值,函数内可以有多个return,但只要执行一个,整个函数就会立刻结束
[root@egon ~]# cat b.sh
function test1(){
echo 111
return
echo 222
return
echo 333
}
test1
[root@egon ~]# chmod +x bbbb.sh
[root@egon ~]# ./b.sh
111
需要注意的是shell语言的函数中,通常用return返回函数运行是否成功的状态,0代表成功,非零代表失败,需要用$?获取函数的返回值
1、return
如果函数内没有return,那么将以最后一条命令运行结果(命令运行成功结果为0,否则为非0)作为返回值
[root@egon ~]# cat b.sh
function test1(){
echo 111
echo 222
echo 333
xxx # 运行该命令出错
}
test1
echo $?
[root@egon ~]# ./b.sh
111
222
333
./b.sh:行5: xxx: 未找到命令
127
2、retrn的使用
如果函数内有return,那么return后跟的只能是整型值并且范围为0-255,用于标识函数的运行结果是否正确, 与C 语言不同,shell 语言中 0 代表 true,0 以外的值代表 false
[root@egon ~]# cat b.sh
function test1(){
echo 111
echo 222
echo 333
return 0
}
test1
echo $? # 用$?获取函数的返回值
[root@egon ~]# ./b.sh
111
222
333
0
六、 变量的作用域
Shell 变量的作用域(Scope),就是 Shell 变量的有效范围(可以使用的范围)。
1、局部变量:只能在函数内访问
使用local关键字定义在函数内的变量属于局部范围,只能在函数内使用,如下所示
[root@localhost shell]# cat hello.sh
#!/bin/bash
# 定义函数
function test(){
local x=111
echo "函数内访问x:$x"
}
# 调用函数
test
echo "在函数外即全局访问x:$x" # 无法访问函数内的局部变量
#执行结果
[root@localhost shell]# ./hello.sh
函数内访问x:111
在函数外即全局访问x:
2、全局变量:可以在当前shell进程中使用
所谓全局变量,就是指变量在当前的整个 Shell 进程中都有效。每个 Shell 进程都有自己的作用域,彼此之间互不影响。在 Shell 中定义的变量,默认就都是全局变量。
[root@localhost shell]# cat hello.sh
#!/bin/bash
x=2222
function test(){
echo "函数内访问x:$x"
}
test
echo "在函数外即全局访问x:$x"
#执行结果
[root@localhost shell]# ./hello.sh
函数内访问x:2222
在函数外即全局访问x:2222
七、注意 (全局变量)
1)在函数内定义的变量,如果没有用local声明,那么默认也是全局变量,shell变量语法的该特性与js的变量是类似的(在js函数内部定义的变量,默认也是全局变量,除非加上关键字var)
[root@localhost shell]# cat hello.sh
#!/bin/bash
function test(){
x=2222 # 全局变量
}
test
echo "在函数外即全局访问x:$x"
[root@localhost shell]# ./hello.sh
在函数外即全局访问x:2222
2)每执行一个解释器,都会开启一个解释的shell进程,每个shell进程都有自己的作用域彼此互不干扰
[root@localhost shell]# x=111 # 该变量仅仅只在当前shell进程中有效,对新的shell进程无影响
[root@localhost shell]# echo $x
111
[root@localhost shell]# bash # 执行bash解释器,则开启一个新的进程,或者干脆直接打开一个新的终端
[root@localhost shell]# echo $x
[root@localhost shell]#
需要强调:
全局变量的作用范围是当前的 Shell 进程,而不是当前的 Shell 脚本文件,它们是不同的概念。打开一个 Shell 窗口就创建了一个 Shell 进程,打开多个 Shell 窗口就创建了多个 Shell 进程,每个 Shell 进程都是独立的,拥有不同的进程 ID。在一个 Shell 进程中可以使用 source 命令执行多个 Shell 脚本文件,此时全局变量在这些脚本文件中都有效。
[root@localhost shell]# echo $x
[root@localhost shell]# cat hello.sh
#!/bin/bash
function test(){
x=2222 # 全局变量
}
test
[root@localhost shell]# source hello.sh # 在当前shell进程中执行,产生一个全局变量x
[root@localhost shell]# echo $x # 在当前shell进程中访问全局变量x,可以看到
2222
[root@localhost shell]#
[root@localhost shell]#
[root@localhost shell]# cat aaa.sh
#!/bin/bash
echo $x
[root@localhost shell]# source aaa.sh # 在当前shell进程中访问全局变量x,同样可以看到
2222
# 结论:函数test内的全局变量x早已超越了文件,即全局变量是超越文件的,作用范围是整个当前bash进程
3)环境变量:在当前进程的子进程中都可以使用**
全局变量只在当前 Shell 进程中有效,对其它 Shell 进程和子进程都无效。如果使用
export
命令将全局变量导出,那么它就在所有的子进程中也有效了,这称为“环境变量”。
环境变量被创建时所处的 Shell 进程称为父进程,如果在父进程中再创建一个新的进程来执行 Shell 命令,那么这个新的进程被称作 Shell 子进程。当 Shell 子进程产生时,它会继承父进程的环境变量为自己所用,所以说环境变量可从父进程传给子进程。不难理解,环境变量还可以传递给孙进程。
[root@localhost shell]# export y=333 # 爷爷
[root@localhost shell]# bash # 爸爸
[root@localhost shell]# echo $y
333
[root@localhost shell]# bash # 孙子
[root@localhost shell]# echo $y
333
#ps:通过exit命令可以一层一层地退出 Shell
#ps:命令set 和 env
set:显示所有变量
env:环境变量
#注意
1)环境变量只能向下传递而不能向上传递,即“传子不传父”。
2)两个没有父子关系的 Shell 进程是不能传递环境变量的
我们一直强调的是环境变量在 Shell 子进程中有效,并没有说它在所有的 Shell 进程中都有效;如果你通过终端创建了一个新的 Shell 窗口,那它就不是当前 Shell 的子进程,环境变量对这个新的 Shell 进程仍然是无效的。
4)环境变量也是临时的
[root@localhost ~]# ps aux |grep bash$ |grep -v grep
root 123436 0.0 0.1 116356 2960 pts/0 Ss 21:52 0:00 -bash
root 123492 0.0 0.1 116472 2932 pts/0 S 21:54 0:00 bash
root 123520 0.0 0.1 116440 2988 pts/0 S 21:54 0:00 bash
#注意:
# -开头的bash代表是在登录终端登录的顶级shell进程
# 非-开头的bash代表的是子shell进程
#一旦退出了在终端登录的顶级shell,那么该终端下开启的所有子shell都会被回收,export设置的环境变量随即消失
#所以说环境变量也是临时的,如果想设置成永久的,需要将变量写入shell配置文件中才可以,Shell 进程每次启动时都会执行配置文件中的代码做一些初始化工作,如果将变量放在配置文件中,那么每次启动进程都会定义这个变量。请看下一小节
六、 登录shell与非登录shell
1、BASH的两种类型
1)登录shell:就是通过输入用户名 密码后 或 su - 获得的shell
2)非登录shell:则是通过bash命令和脚本开启的shell环境
2、那么他们有什么区别呢?和我们永久设定环境变量又有什么关系呢?
我们知道在linux里一切皆为文件,同样,shell的属性加载也是写到文件里的
在登陆时就会加载对应文件的内容来初始化shell环境,
非登录与登录区别就在于加载的文件不同 从而导致获得的shell环境不同
我们看看登录shell都加载了那些文件
--> /etc/profile
--> /etc/profile.d/*.sh
--> $HOME/.bash_profile
--> $HOME/.bashrc
--> /etc/bashrc
再看非登录shell加载的文件,非登录shell加载的文件要少很多
--> $HOME/.bashrc
--> /etc/bashrc
--> /etc/profile.d/*.sh
通常,我们会将环境变量设置在 `$HOME/.bash_profile` 中
但如果不管哪种登录shell都想使用的变量 可以考虑设置在 $HOME/.bashrc或者/etc/bashrc中,因为它们都属于无论如何都会执行的文件,但是,如果我们真的在这类文件中添加了变量,那么意味着每次执行shell都会重新定义一遍该变量,而定义变量是要耗费内存资源的,这非常不可取,所以我们通常会结合export在/etc/profile文件中声明一个全局变量,这样在每次登录用户时产生的顶级shell里会有一个全局变量,所有的子shell都可以看到了,无需重复定义
[root@localhost ~]# vim /etc/profile
[root@localhost ~]# head -2 /etc/profile
# /etc/profile
name="egon"
[root@localhost ~]# echo $name
[root@localhost ~]# source /etc/profile # 可以在当前shell中立即生效,也可以退出后重新登录终端
[root@localhost ~]# echo $name
egon
七、计算器代码编写
开发一个计算器程序如下,引入函数减少代码冗余
[root@egon ~]# cat b.sh
#!/bin/bash
echo " ----------------------------------"
echo "|这是一个简单的整数计算器,biubiu |"
echo " ----------------------------------"
echo
# 接收第一个整数,并校验
while :
do
read -p "请输入第一个整数: " num1
expr $num1 + 0 &> /dev/null
if [ $? -eq 0 ];then
break
else
echo "必须输入整数"
fi
done
# 接收第二个整数,并校验
while :
do
read -p "请输入第二个整数: " num2
expr $num2 + 0 &> /dev/null
if [ $? -eq 0 ];then
break
else
echo "必须输入整数"
fi
done
# 接收输入的操作
echo "-------------------"
echo "| 1.加法 |"
echo "| 2.减法 |"
echo "| 3.乘法 |"
echo "| 4.除法 |"
echo "-------------------"
read -p "请输入您想执行的操作:" choice
case $choice in
"1")
res=`expr $num1 + $num2`
echo "$num1+$num2=$res"
;;
"2")
res=`expr $num1 - $num2`
echo "$num1+$num2=$res"
;;
"3")
res=`expr $num1 \* $num2`
echo "$num1*$num2=$res"
;;
"4")
res=`expr $num1 / $num2`
echo "$num1/$num2=$res"
;;
*)
echo "未知的操作"
esac
八、nginx安装脚本编写
[root@web01 opt]# cat test.sh
#!/bin/bash
# 1、编写一个脚本,支持安装nginx、启动|停止nginx、监控nginx
[root@web01 opt]# cat hzl.sh
#!/bin/bash
#初始化系统一些函数
. /etc/init.d/functions
#打印输出内容
print_action() {
if [ $2 -eq 0 ]; then
action "$1" /bin/true
else
action "$1" /bin/false
fi
}
#启动nginx,调用函数
start() {
nginx -t
if [ $? -eq 0 ]; then
print_action "nginx配置文件正确" 0
systemctl start nginx
if [ $? -eq 0 ]; then
print_action "Nginx 启动成功" 0
else
print_action "启动失败,请检查端口是否被占用"
fi
else
print_action "nginx配置文件错误,请检查" 1
fi
}
stop() {
systemctl stop nginx
if [ $? -eq 0 ]; then
print_action "Nginx 停止成功" 0
else
print_action "Nginx 停止失败" 1
fi
}
restart() {
stop
sleep 1
start
}
status() {
systemctl status nginx
if [ $? -eq 0 ]; then
print_action "正在查看状态" 0
else
print_action "Nginx未启动" 1
fi
}
rpm -ql nginx >/dev/null
if [ $? -ne 0 ]; then
PS3="Nginx尚未安装,是否安装>>:"
select item in {"安装","不安装"}; do
case $item in
安装)
cat >/etc/yum.repos.d/nginx.repo <<EOF
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/7/\$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF
yum clean all
yum makecache
yum install nginx -y
print_action "Nginx安装成功,请重启脚本" 0
exit
;;
不安装)
exit
;;
esac
done
else
PS3="请输入对nginx的操作编号>>:"
select item in start stop status restart exit; do
case $item in
"start")
start
;;
"stop")
stop
;;
"restart")
restart
;;
"status")
status
;;
"exit")
exit
;;
*)
print_action "请准确输入操作选项" 1
;;
esac
done
fi
[root@web01 opt]#
[root@web01 opt]# sh hzl.sh
1) start
2) stop
3) status
4) restart
5) exit
请输入对nginx的操作编号>>:1
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
nginx配置文件正确 [ 确定 ]
Nginx 启动成功 [ 确定 ]
请输入对nginx的操作编号>>:3
● nginx.service - nginx - high performance web server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
Active: active (running) since 二 2021-06-22 03:25:01 CST; 5s ago
Docs: http://nginx.org/en/docs/
Process: 2323 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Main PID: 2324 (nginx)
CGroup: /system.slice/nginx.service
├─2324 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
└─2325 nginx: worker process
6月 22 03:25:01 web01 systemd[1]: Starting nginx - high performance web server...
6月 22 03:25:01 web01 systemd[1]: Failed to read PID from file /var/run/nginx.pid: Invalid argument
6月 22 03:25:01 web01 systemd[1]: Started nginx - high performance web server.
正在查看状态 [ 确定 ]
请输入对nginx的操作编号>>:
本文来自博客园,作者:ଲ小何才露煎煎饺,转载请注明原文链接:https://www.cnblogs.com/zeny/p/15121520.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报