创建函数

news/2025/3/6 3:18:23/

章节目录:

    • 一、脚本函数基础
      • 1.1 创建函数
      • 1.2 使用函数
    • 二、函数返回值
      • 2.1 默认的退出状态码
      • 2.2 使用 return 命令
      • 2.3 使用函数输出
    • 三、在函数中使用变量
      • 3.1 向函数传递参数
      • 3.2 在函数中处理变量
    • 四、数组变量和函数
      • 4.1 向函数传递数组
      • 4.2 从函数返回数组
    • 五、函数递归
    • 六、创建库
    • 七、在命令行中使用函数
      • 7.1 在命令行中创建函数
      • 7.2 在 .bashrc 文件中定义函数
    • 八、结束语

本章内容:

  • 脚本函数基础
  • 函数返回值
  • 在函数中使用变量
  • 数组变量和函数
  • 函数递归
  • 创建库
  • 在命令行中使用函数

一、脚本函数基础

函数是一段脚本代码块,你可以为其命名并在脚本中的任何位置重复使用,从而避免重复编写相同的代码。

1.1 创建函数

bash shell 脚本中创建函数的语法有两种

  • 第一种,使用关键字 function
# name:定义了该函数的唯一名称。脚本中的函数名不能重复。# commands:是组成函数的一个或多个 bash shell 命令。function name {commands
}
  • 第二种,接近其他编程语言中定义函数的方式
# 函数名后的空括号表明正在定义的是一个函数。
name() {commands
}

1.2 使用函数

要在脚本中使用函数,只需像其他 shell 命令一样写出函数名即可

  • 应用示例
# 1.脚本内容。(分别调用两种不同方式定义的函数。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
#
function sayHi() {echo "hi!"
}
#
sayHello() {echo "hello!"
}
#
sayHi
sayHello# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh 
hi!
hello!
[root@VM-8-11-centos testdir]# 
  • 注意事项
    • 函数名必须是唯一的,否则就会出问题。(如果定义了同名函数,那么新定义就会覆盖函数原先的定义,而这一切不会有任何错误消息。)
    • 函数必须先定义后调用。

二、函数返回值

bash shell 把函数视为一个小型脚本,运行结束时会返回一个退出状态码。有 3 方法能为函数生成退出状态码

2.1 默认的退出状态码

在默认情况下,函数的退出状态码是函数中最后一个命令返回的退出状态码。

  • 函数执行结束后,可以使用标准变量 $? 来确定函数的退出状态码。
  • 使用函数的默认退出状态码是一种危险的做法
# 1.脚本内容。($? 得到的是最后一个命令执行的状态。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
func1() {ls -l badfile
}func1
echo "status is: $?"# 2.执行脚本。(此时返回退出状态码是2。)
[root@VM-8-11-centos testdir]# ./test.sh 
ls: cannot access badfile: No such file or directory
status is: 2# 3.修改脚本内容。(在调用函数后加一句echo。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
func1() {ls -l badfile
}func1
#
echo
#
echo "status is: $?"# 4.再次执行脚本。(返回退出状态码变为了0。)
[root@VM-8-11-centos testdir]# ./test.sh 
ls: cannot access badfile: No such file or directorystatus is: 0
  • 函数中的最后一个命令执行失败了。但你无法知道该函数中的其他命令是否执行成功

2.2 使用 return 命令

return 命令允许指定一个整数值作为函数的退出状态码,从而提供了一种简单的编程设定方式。

  • 应用示例
# 1.脚本内容。(将输入值作为退出状态码。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
func1() {read -p "Enter a value: " valuereturn "$value"
}func1
echo "status is: $?"# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh 
Enter a value: 200
status is: 200
  • 当用这种方法从函数中返回值时,一定要小心。为了避免出问题,牢记以下两个技巧

    • 函数执行一结束就立刻读取返回值。( $? 变量提取函数返回值之前执行了其他命令,那么函数的返回值会丢失。)
    • 退出状态码必须介于 0~255。(大于 255 的任何数值都会产生错误的值。)
  • 如果需要返回较大的整数值字符串,就不能使用 return 方法。

2.3 使用函数输出

正如可以将命令的输出保存到 shell 变量中一样,也可以将函数的输出保存到 shell 变量中

  • 应用示例
# 1.脚本内容。(将输出保存到变量。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
func1() {read -p "Enter a value: " valueecho "$value"
}result=$(func1)
echo "status is: $result"# 2.执行脚本。(得到字符串类型的返回值。)
[root@VM-8-11-centos testdir]# ./test.sh 
Enter a value: 1000
status is: 1000
  • 该脚本会获取 func1 函数的输出,而不是查看退出状态码

  • 这种方法还可以返回浮点值字符串,这使其成为一种获取函数返回值的强大方法。

三、在函数中使用变量

3.1 向函数传递参数

bash shell 会将函数当作小型脚本来对待。这意味着你可以像普通脚本那样向函数传递参数。

  • 函数可以使用标准的位置变量( $0、$1、…、$#。)来表示在命令行中传给函数的任何参数
  • 在脚本中调用函数时,必须参数函数名放在同一行然后函数可以用位置变量来获取参数值
  • 脚本内部调用函数时,传入位置参数
# 1.脚本内容。(参数个数为2作加法,否则返回-1。)
# 调用函数时,传入位置变量。(第一次调用传入5和6,第二次调用不传值。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
add() {if [ $# -eq 2 ]; thenresult=$(($1 + $2))echo "$1+$2=$result"elseecho -1fi
}value=$(add 5 6)
echo "$value"
#
value=$(add)
echo "$value"# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh 
5+6=11
-1
  • 运行脚本时,传入位置参数
# 1.脚本内容。(检查调用脚本时传入的位置参数,两个就调用add()方法,否则返回-1。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
#
add() {result=$(($1 + $2))echo "$1+$2=$result"
}
#
if [ $# -eq 2 ]; thenvalue=$(add $1 $2)echo "$value"
elseecho -1
fi# 2.执行脚本。(不传位置参数进行调用。)
[root@VM-8-11-centos testdir]# ./test.sh 
-1# 3.执行脚本。(传正确个数的位置参数进行调用。)
[root@VM-8-11-centos testdir]# ./test.sh 10 10
10+10=20

3.2 在函数中处理变量

函数有两种类型的变量:

  • 全局变量。
  • 局部变量。

3.2.1 全局变量

全局变量是在 shell 脚本内任何地方都有效的变量。

  • 默认情况下,在脚本中定义的任何变量都是全局变量。
  • 函数外定义的变量可在函数内正常访问
  • 应用示例
# 1.脚本内容。
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
func1() {temp=$((value + 1))
}
#
temp=0
value=3
#
echo "before: temp:$temp , value:$value"
func1
echo "after: temp:$temp , value:$value"# 2.执行脚本。(函数中用到了$temp 变量,因此它的值在脚本中使用时受到了影响。)
[root@VM-8-11-centos testdir]# ./test.sh 
before: temp:0 , value:3
after: temp:4 , value:3
  • 如果变量在函数内被赋予了新值,那么在脚本中引用该变量时,新值仍可用。
  • 这种情况其实很危险,尤其是想在不同的 shell 脚本中使用函数的时候,因为这要求你清清楚楚地知道函数中具体使用了哪些变量,包括那些用来计算非返回值的变量。

3.2.2 局部变量

无须在函数中使用全局变量,任何在函数内部使用的变量都可以被声明为局部变量

  • 只需在变量声明之前加上 local 关键字即可:

  • local 关键字保证了变量仅在该函数中有效

  • 如果函数之外有同名变量,那么 shell 会保持这两个变量的值互不干扰

  • 意味着你可以轻松地将函数变量脚本变量分离开,只共享需要共享的变量

  • 应用示例

# 1.脚本内容。(使用local关键字修饰局部变量。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
func1() {local temp=$((value + 1))
}temp=0
value=3
#
echo "before: temp:$temp , value:$value"
func1
echo "after: temp:$temp , value:$value"# 2.执行脚本。(函数中用到了$temp 变量,但没有影响到全局的值。)
[root@VM-8-11-centos testdir]# ./test.sh 
before: temp:0 , value:3
after: temp:0 , value:3

四、数组变量和函数

4.1 向函数传递数组

  • 如果试图将数组变量作为函数参数进行传递,则函数只会提取数组变量的第一个元素
  • 要解决这个问题,必须先将数组变量拆解成多个数组元素,然后将这些数组元素作为函数参数传递
  • 应用示例
# 1.脚本内容。(newArray将所有的参数重新组合成一个新的数组变量,之后进行遍历累加。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
addArray() {local sum=0local newArraynewArray=("$@")#for value in "${newArray[@]}"; dosum=$((sum + value))done#echo $sum
}
#
args=(1 2 3 4 5)
reslut=$(addArray "${args[@]}")
echo "reslut=$reslut"
#
exit# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh 
reslut=15

4.2 从函数返回数组

函数向 shell 脚本返回数组变量也采用类似的方法。

  • 应用示例
# 1.脚本内容。(将原始数组的值翻倍后赋值给新数组,并返回新的数组。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
elementDoubling() {local origArray=("$@")local newArray=("$@")local length=$(($# - 1))for ((i = 0; i <= length; i++)); donewArray[i]=$((origArray[i] * 2))doneecho "${newArray[*]}"
}
#
args=(1 2 3 4 5)
reslut=$(elementDoubling "${args[@]}")
echo "reslut=$reslut"
#
exit# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh 
reslut=2 4 6 8 10

五、函数递归

局部函数变量的一个特性是自成体系self-containment )。

  • 这个特性使得函数可以递归地调用,也就是说函数可以调用自己来得到结果。
  • 递归函数通常有一个最终可以迭代到的基准值。
  • 许多高级数学算法通过递归对复杂的方程进行逐级规约直到基准值
  • 递归算法的经典例子是计算阶乘。(一个数的阶乘是该数之前的所有数乘以该数的值。)
  • 应用示例
# 1.脚本内容。(输入一个数,计算该数的阶乘。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
factorial() {inputValue=$1if [ $inputValue -eq 1 ]; thenecho 1elselocal temp=$(($inputValue - 1))local result=$(factorial $temp)echo $((result * $inputValue))fi
}
#
read -p "Enter value: "
result=$(factorial "$REPLY")
echo "The factorial of $REPLY is: $result"
#
exit# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh 
Enter value: 5
The factorial of 5 is: 120

六、创建库

bash shell 允许创建函数库文件,然后在多个脚本引用此库文件。

  • 使用函数库的关键在于 source 命令(别名,称作点号操作符)。

  • source 命令会在当前 shell 的上下文中执行命令,而不是创建新的 shell 并在其中执行命令。

  • 可以用 source 命令在脚本中运行库文件。这样脚本就可以使用库中的函数了。

  • 应用示例

# 1.脚本内容。(可以通过source或者点号引入库文件。)
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
lib_path="/home/lib/myfuncs.sh"
#source "$lib_path"
. "$lib_path"
#
sayHello
exit# 2.自定义的库文件内容。
[root@VM-8-11-centos testdir]# cat /home/lib/myfuncs.sh
#!/bin/bash
sayHello() {echo "hello world!"
}# 3.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh 
hello world!

七、在命令行中使用函数

就像在 shell 脚本中将脚本函数当作命令使用一样,在命令行界面中也可以这样做。

7.1 在命令行中创建函数

  • 因为 shell 会解释用户输入的命令,所以可以在命令行中直接定义一个函数。

  • 应用示例

# 1.单行定义。(命令行中定义函数时,必须在每个命令后面加个分号,这样 shell 就能知道哪里是命令的起止了。)
[root@VM-8-11-centos testdir]# sayHi(){ echo "hi"; echo "hello"; }
[root@VM-8-11-centos testdir]# sayHi
hi
hello# 2.多行定义。(使用这种方法,无须在每条命令的末尾放置分号,只需按下回车键即可。)
# 当输入函数尾部的花括号后,shell 就知道你已经完成函数的定义了。
[root@VM-8-11-centos testdir]# sayHello() {
> echo "hello"
> }
[root@VM-8-11-centos testdir]# sayHello
hello
  • 注意事项:在命令行创建函数时要特别小心。如果给函数起了一个跟内建命令或另一个命令相同的名字,那么函数就会覆盖原来的命令。

7.2 在 .bashrc 文件中定义函数

命令行中直接定义 shell 函数的一个明显缺点是,在退出 shell 时,函数也会消失。将函数定义在每次新 shell 启动时都会重新读取该函数的地方。.bashrc 文件就是最佳位置

  • 直接定义函数
# 1.可以直接在用户主目录的.bashrc 文件中定义函数。
# 大多数 Linux 发行版已经在该文件中定义了部分内容,注意不要误删,只需将函数放在文件末尾即可。
# 该函数会在下次启动新的 bash shell 时生效。
[root@VM-8-11-centos testdir]# cat $HOME/.bashrc
# .bashrc# User specific aliases and functionsalias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'# Source global definitions
if [ -f /etc/bashrc ]; then. /etc/bashrc
fi# ----------user defined-----------sayYes() {echo "yes."
}[root@VM-8-11-centos testdir]# # 2.开启新的bash会话。(或者重启终端。)
[root@VM-8-11-centos testdir]# bash# 3.调用函数。
[root@VM-8-11-centos testdir]# sayYes
yes.# 4.退出临时会话。
[root@VM-8-11-centos testdir]# exit
exit
[root@VM-8-11-centos testdir]# 
  • 源引函数文件
# 1.只要是在 shell 脚本中,就可以用 source 命令(或者其别名,即点号操作符)将库文件中的函数添加到.bashrc 脚本中。
[root@VM-8-11-centos ~]# cat $HOME/.bashrc
# .bashrc# User specific aliases and functionsalias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'# Source global definitions
if [ -f /etc/bashrc ]; then. /etc/bashrc
fi# ----------user defined-----------. /home/lib/myfuncs.sh# 2.引入的库文件内容。
[root@VM-8-11-centos ~]# cat /home/lib/myfuncs.sh
#!/bin/bash
sayHello() {echo "------------"echo "hello world!"echo "------------"
}# 3.开启新的bash会话。(或者重启终端。)
[root@VM-8-11-centos ~]# bash# 4.命令行调用函数。
[root@VM-8-11-centos ~]# sayHello
------------
hello world!
------------# 4.退出临时会话。
[root@VM-8-11-centos ~]# exit
exit
[root@VM-8-11-centos ~]# 
  • 脚本中引入 .bashrc 文件
# 1.启动文件.bashrc源引函数。
[root@VM-8-11-centos testdir]# cat $HOME/.bashrc
# .bashrc# User specific aliases and functionsalias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'# Source global definitions
if [ -f /etc/bashrc ]; then. /etc/bashrc
fi# ----------user defined-----------. /home/lib/myfuncs.sh# 2.脚本内容。(脚本中引入.bashrc文件。)
# 这么做的好处:方便统一维护。
[root@VM-8-11-centos testdir]# cat test.sh 
#!/bin/bash
#
. $HOME/.bashrc
#
sayHello
exit# 3.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh 
------------
hello world!
------------

八、结束语


“-------怕什么真理无穷,进一寸有一寸的欢喜。”

微信公众号搜索:饺子泡牛奶


http://www.ppmy.cn/news/546448.html

相关文章

django公交线路查询系统-计算机毕设 附源码85021

django公交线路查询系统 摘 要 本论文主要论述了如何使用django框架开发一个公交线路查询系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述该系统的当前背景以及系统开发的目的&…

【spring cloud学习】2、Eureka服务注册与发现

前言 一套微服务架构的系统由很多单一职责的服务单元组成&#xff0c;而每个服务单元又有众多运行实例。由于各服务单元颗粒度较小、数量众多&#xff0c;相互之间呈现网状依赖关系&#xff0c;因此需要服务注册中心来统一管理微服务实例&#xff0c;维护各服务实例的健康状态…

[韓劇精華]韓國人的128條定律

http://www.tianya.cn/new/Publicforum/Content.asp?idWriter0&Key0&strItemfuninfo&idArticle1007845&flag1 01、手机在韩剧里必备,都是当时最新款,而且感觉每部剧里的人物手机都用的一样的!手机业很发达&#xff0c;韩剧里很穷的人手机还算蛮好的&#xff0…

《月薪5千与月薪5万的文案区别》!如何用立体思维去解决问题

如果你是相关领域的从业者一定要读完这篇文章&#xff0c;如果你不是也不妨看看这篇文章&#xff0c;它将教你如何用立体的思维模式&#xff0c;提高你解决问题的能力。 那么如何写好一个互联网思维的文案呢&#xff1f; 互联网初创公司无不把产品分割成一个个独立属性。拿小米…

月薪5千与月薪5万文案的区别

如果你是相关领域的从业者一定要读完这篇文章&#xff0c;如果你不是也不妨看看这篇文章&#xff0c;它将教你如何用立体的思维模式&#xff0c;提高你解决问题的能力。 那么如何写好一个互联网思维的文案呢&#xff1f; 互联网初创公司无不把产品分割成一个个独立属性。拿小米…

数据版“吐槽大会”: 国产综艺节目年终盘点

前言 2018刚刚翻篇&#xff0c;每个人在2018都会留下许多难忘的回忆&#xff0c;有欢笑&#xff0c;有泪水&#xff0c;亦有成长。2018年诞生了许多的国产综艺节目&#xff0c;随着各大视频网站对自制综艺节目不断加大投入&#xff0c;我们有幸看到了更加多元化的综艺节目。 本…

即兴演讲的秘诀结构(一)

在这里介绍一个有效的即兴演讲的结构&#xff0c;让你在突然的情境下也能出口成章。第一种是“PRS”结构&#xff0c;也就是Problem &#xff08;承认问题&#xff09;&#xff0c;Reason&#xff08;解释原因&#xff09;&#xff0c;Solution&#xff08;给出解决方案&#x…

完善口语第一步

因为最近想提高自己的英语水平 , 所以无意间看到一本书 书名是 :《1368个单词就够了》 简介 : 主要是讲如果将思维扩展开来 , 一词多用 ... 内容讲得挺好的 ! 但是要自己熟练使用 恐怕还是有点难的 ... 主要是让我们提高自己的英语思维 和口语能力 因为是电子书, 所以我必须要…