目录
函数就是将一组相对独立的代码集中起来,形成一个代码块,已完成一个具体的功能。和其他编程语言中的函数是一样的,从本质上讲,函数是一个函数名到某一块代码块的映射。
Shell中函数定义有两种方式,结果是一样的。
- #第一种定义方式
- function_name ()
- {
- statement1
- ...
- }
-
- #第二种定义方式
- function function_name ()
- {
- statement1
- ...
- }
第二种定义方式前面多了一个function关键字。function_name表示函数名,命名规则和变量名一样:可以包含字母,数字,下划线;只能以字母或者下划线开头。用户应该尽量用有意义的英文单词来命名。
在Shell语言中,函数定义必须在函数调用之前,不然会报错
command not found
调用函数的方式和调用Shell脚本的方式是一样的,调用语法如下:
function_name param1 param2 ...
下面看个简单的例子:
- #!/bin/bash
- #定义函数
- getCurrentTime()
- {
- echo "`date`"
- }
-
- #调用函数
- getCurrentTime
结果如下:
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ ./6-2.sh
Thu 28 Jul 2022 02:17:28 AM PDT
Shell里的函数也和常用的编程语言一样,可以嵌套调用,一个函数里面可以调用另外一个函数,但是也是遵循先定义后调用的原则,下面看示例:
- #!/bin/bash
-
- Lea()
- {
- echo "Hello, I am Lea!"
- }
-
- Eden()
- {
- echo "Hello, I am John!"
- }
-
- sayHello()
- {
- Lea
- Eden
- }
-
- sayHello
结果如下:
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ ./6-3.sh
Hello, I am Lea!
Hello, I am John!
这里与其他编程语言有比较大的差别。
首先第一种就是不返回值,执行完操作就达到目的了。这在Shell中非常常见。
如果一定要返回值,有如下两种方式:
我们可以用return返回,然后使用$?系统变量获取到return的值
Shell的return返回只能返回0~255之间的整数,就是所谓的状态码。如果超过这个范围,返回的值就不对了,下面举个简单例子:
- #!/bin/bash
- func()
- {
- return 257
- }
- func
- echo $?
结果如下:
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ ./6-4.sh
1
在函数中,用户将需要返回的数据写入到标准输出(stdout),一般使用echo语句来完成,然后在调用程序中将函数的执行结果赋给一个变量,就是我前面文章讲的 命令替换 。
使用``或者$()命令获取函数输出到标准输出的值赋值给一个左值,请看示例:
- #!/bin/bash
- func1()
- {
- echo "123"
- }
-
- result=$(func1)
- result1=`func1`
-
- echo $result
- echo $result1
结果是:
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ ./6-4.sh
123
123
这种方式可以返回任意形式的值,不局限于整数,比return的方式更加的强大。
如果我们在一个函数里调用echo两次结果会是怎么样呢?看例子:
- #!/bin/bash
- func1()
- {
- echo "Hello world"
- echo "123"
- }
-
- func1
- result="$(func1)"
- result1=`func1`
-
- echo $result
- echo $result1
结果是:
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ ./6-4.sh
Hello world
123
Hello world 123
Hello world 123
从结果上来看,返回的值把两个echo的输出结合在一起了,中间加了一个空格。
在Shell中,与函数比较相似的一个概念是别名。一个别名是一个Shell命令的缩写或者映射,别名的语法如下:
#设置别名
alias alias_name="command"
#删除别名
unalias alias_name
command命令是一条完整的命令,可以带参数。
与函数相比,别名的功能相对简单,其中主要区别如下:
下面我们举个别名调用的例子:
- #!/bin/bash
- shopt -s expand_aliases
- alias ls="ls -l"
- ls
结果如下
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ ./6-5.sh
total 16
-rwxrwxr-x 1 eden_ubuntu eden_ubuntu 95 Jul 28 02:17 6-2.sh
-rwxrwxr-x 1 eden_ubuntu eden_ubuntu 135 Jul 28 02:21 6-3.sh
-rwxrwxr-x 1 eden_ubuntu eden_ubuntu 181 Jul 28 03:09 6-4.sh
-rwxrwxr-x 1 eden_ubuntu eden_ubuntu 56 Jul 28 03:26 6-5.sh
如果没有第2行的 shopt -s expand_aliases,在Shell脚本中alias命令就是无效的。但是在Shell控制台中不需要,我们可以试试:
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ alias ls="ls -l"
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ ls
total 16
-rwxrwxr-x 1 eden_ubuntu eden_ubuntu 95 Jul 28 02:17 6-2.sh
-rwxrwxr-x 1 eden_ubuntu eden_ubuntu 135 Jul 28 02:21 6-3.sh
-rwxrwxr-x 1 eden_ubuntu eden_ubuntu 181 Jul 28 03:09 6-4.sh
-rwxrwxr-x 1 eden_ubuntu eden_ubuntu 56 Jul 28 03:26 6-5.sh
函数可以直接在Shell控制台输入定义:
命令如下:
unset function_name
局部变量在函数中定义,在定义的变量名前加local关键字。除了这样,其他定义的变量都为全局变量。包括在函数中定义的变量。
之前有篇文章专门讲过传参:Shell系统学习之向Shell脚本传递参数
主要熟悉$#,$n,$@,$*,#?,getopts,getopt,shift的用法
所谓间接传参就是通过一个变量的值当作另外一个变量的变量名来传参,中间绕了一下。语法如下:
${!var_name}
比方说存在两个变量
- var=name
- name=Eden
我们可以将Eden这个值通过${name}传递过去,也可以用${!var}传递过去。
严格的来说,Shell并不支持将数组作为参数传递给函数,但是用户仍然可以通过一些变通的方法数显数组的传递。
用户可以将数组的元素展开,然后作为多个由空格隔开的参数传递给函数。示例如下:
- #!/bin/bash
- func()
- {
- echo "number of elements is $#."
- while [ $# -gt 0 ]
- do
- echo "$1"
- shift
- done
- }
-
- array=(a b "c d" e)
- func "${array[@]}"
结果如下:
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ ./6-6.sh
number of elements is 4.
a
b
c d
e
通过"${array_name[@]}"或者"${array_name[*]}"都可以实现目标
创建一个函数库文件类似于编写一个Shell脚本,区别在于函数库文件只包含函数,没有外部可执行代码。举个简单的例子:
- #!/bin/bash
- error()
- {
- echo "ERROR:" $@ 1>&2
- }
上述内容就是一个函数库文件,只有函数。由于函数库文件是由主程序载入执行的,所以用户无需拥有可执行权限,有用可读权限即可。
在Shell中,载入函数库文件的命令为 . ,即一个原点,其语法如下:
. filename
filename表示库文件的名称,可以使用相对路径,也可使用绝对路径。示例如下:
- #!/bin/bash
- #载入库文件
- . 6-7.sh
-
- error "cannot find file"
结果如下:
eden_ubuntu@edenubuntu:~/Documents/Shell/6$ ./6-8.sh
ERROR: cannot find file
必须在调用对应的函数之前载入对应的函数库文件,不然会报错:command not found.
本篇文章主要讲述函数的定义,调用,返回值,传参,以及函数库文件的定义和调用。重点关注下返回值,传参,函数库文件的使用。