Shell 函数 function [转]

简介: 本文也即《Learning the bash Shell》3rd Edition的第四章Basic Shell Programming之读书笔记,但我们将不限于此。 运行shell脚本程序   一个包含shell命令的脚本就是一个shell程序,例如.bash_profile。

本文也即《Learning the bash Shell》3rd Edition的第四章Basic Shell Programming之读书笔记,但我们将不限于此。

运行shell脚本程序

  一个包含shell命令的脚本就是一个shell程序,例如.bash_profile。我们创建shell脚本,允许的时候可以通过两种方式:一、source ;二、只敲入文件名,按回车就可以执行,这种方式更为便捷。我们需要将文件放置在命令搜索路径下(在Linux Bash学习(六):设置环境参数 中介绍),否则需要指出绝对路径,例如在当前目录,使用./, 另外我们还需要将文件的权限设置为可执行文件,采用$ chmod +x 的方式设置,+x表示增加执行的权限。

  这两种方式是由区别的。采用source就如同我们在terminal上敲入命令一样。采用后一种方式,系统运行一个子进程,它copy了shell,叫作subshell,主shell等待子shell运行结束。另外我们设置让子shell后台运行,即 &

  这个区别还体现在export 的使用上,例如我们设置aa=hello, world,这个变量在命令行中有效,但是在脚本文件是无效,需要使用export aa='hello, world ' 来保证在subprocess中也是有效,即可以用于脚本文件中。

函数Functions

  使用function有两个原因:一、function存放在系统的内存,所以调用的使用,效率更高;二、更好地组织长的bash,使之模块化。定义function,有两个方式:

function functname {
    shell commands
}
functname ( ){
    shell commands
}

  上面两种方式没有区别。我们可以通过unset –f functname 来删除函数的定义。 当我们定义一个function,将它的名字和定义存放在内存,我们可以象调用shell脚本的方式来调用它。我们通过declare -f 来查看当前已经定义的function情况,如果我们只查看function名字,使用declare -F 。我们可以在命令行中敲入一个function来检验,如果我们将function定义在一个文件中,例如在文件a,可以用source a 来是指生效,如果我们将a设定为可执行文件,这function的定义只在该脚本中有效,如果需要使之仍然有效,保留环境,采用$. ./a ,而不只是$./a

Function作为一个整体运行,不会分割为子进程,此外Function的优先级别高于脚本。如果有重名,优先级别依次如下:

  1. Aliases
  2. 关键字,例如function,if,for
  3. Functions
  4. Built-ins,例如cd,type
  5. 在命令搜索路径PATH下的脚本和可执行文件

  如果我们需要查看所使用命令属于哪种,用type name ,例如aa是个alias(表示pwd),同样我们也定义了它作为一个function,根据优先级别,aa优先作为alias,type aa,我们可以得到aa is aliased to ‘pwd’,可以用type –a(或者-all) name ,来查看aa代表的所有含义。如果使用非最优先级别或者重新定义优先级别的先后顺序,在书的第7章,我们先放下此话题不表。上述的命令将显示详细内容,可以用type –t name 的方式,查看类型,将返回alias | keyword | function | builtin | file。type –p name 用于查看file的路径,如果类型不是file将没有返回,而type –P name 则强制查找file的路径。例如一个重名,它是一个alias,也是一个在PATH目录下的可执行文件。-p则没有返回,-P这返回文件的绝对路径。

位置参数

  在脚本命令中,有时是带有参数,这些参数可以通过位置变量来获取。例如我们有个脚本文件叫做test,执行的使用带参数,即$./test param1 param2 param3,我们可以在脚本中来获取参数的值。使用$N,其中$0是./test,它表示执行的脚本名字,剩余的为所带参数,$1为param1,$2 为param2,如此类推,如果N大于实际参数的数目,为空。我们一般将位置变量是从$1开始。

$* 表示所有参数组成的一个字符串,在上面的例子中,为param1 param2 param3。这些参数之间的间隔是IFS的首个字母即空格,IFS包括TAB,空格,换行等字符。

$@ 等同于"$1" "$2"... "$N"。

$# 表示参数的个数,在上面的例子中为3。

  这些位置变量都是只读,不能赋值的。$*和$@非常相似,一般而言输出是一样的。$*的分割是在IFS的字符,我们可以重新定义IFS的字符,将导致不同的输出结果。我们在脚本中定义IFS=, ,即可将输出改用逗号做为分割,这个脚本名字为a,运行./a h1 h2,则$#=2,表示有两个参数,$@为h1 h2,$*为h1,h2 ,输出结果不一样。

  同样这些位置变量可以用于function中,并对function的参数进行体现,即是local的,属于function,但是$0是例外,他表示脚本的名字,这个参数是gobal的。下面是个例子。脚本a内容如下:

hello ()
{
    var="hello";
    echo "Hello"
    echo "Hello: param num is $#"
    echo "Hello: $@"
    echo "Hello: $*"
    echo "Hello: $0 $1 $2"
    echo "Hello: var=$var";
}
var="hello";
echo "main: param num is $#"
echo "main: $@"
echo "main: $*"
echo "main: $0 $1 $2"
echo "main: var=$var";
hello h1 h2

 

  我们执行./a a1 a2 a3

main: param num is 3
main: a1 a2 a3
main: a1 a2 a3
main: ./a a1 a2
main: var=main
Hello
Hello: param num is 2
Hello: h1 h2
Hello: h1 h2
Hello: ./a h1 h2
Hello: var=hello

  除了$0外,所有的位置变量都是local的,即如果在function中,则在function中有效。同样,用户定义的其他变量,也是 local的,即在最近的{}内有效。见上面例子中的用户变量var。我们可以在function中定义var加上local来特别标明这是一个本地参 数,上面的例子在函数hello,可以使用local var=”hello”

避免歧义的变量定义

  实际上我们使用$varname,是${varname} 的一个缩写。有时我们不能使用缩写,例如我们需要获取第10个参数,使用$10,这实际是第一个参数加上“0”,需要使用${10}。又例如,我们希望显 示进程号,并在后面仅跟_、字母或者数字,我们使用echo $UID_,会见UID_看作一个整体,即echo ${UID_},因此是空,需要使用echo ${UID}_,假设进程号为1000,则为1000_。如果一个变量后面紧跟着_、字母或者数字,安全起见,需要用大括号。

目录
相关文章
|
2天前
|
JavaScript 前端开发
在JavaScript中,函数原型(Function Prototype)是一个特殊的对象
JavaScript中的函数原型是一个特殊对象,它为所有函数实例提供共享的方法和属性。每个函数在创建时都有一个`prototype`属性,指向原型对象。利用原型,我们可以向所有实例添加方法和属性,实现继承。例如,我们定义一个`Person`函数,向其原型添加`greet`方法,然后创建实例`john`和`jane`,它们都能调用这个方法。尽管可以直接在原型上添加方法,但推荐在构造函数内部定义以封装数据和逻辑。
8 2
|
5天前
|
存储 算法 对象存储
【C++入门到精通】function包装器 | bind() 函数 C++11 [ C++入门 ]
【C++入门到精通】function包装器 | bind() 函数 C++11 [ C++入门 ]
14 1
|
12天前
|
存储
function(函数)
在 Lua 中,函数作为第一类值可存储于变量,如示例所示:`factorial1` 和 `factorial2` 存储相同函数。此外,函数可作为参数传递,如 `testFun` 接收一个表和一个匿名函数,该匿名函数在迭代中处理键值对,输出 `key1=val1` 和 `key2=val2`。
|
14天前
|
JavaScript 前端开发
【专栏】`Function.prototype.apply` 在JavaScript中用于动态设定函数上下文(`this`)和参数列表
【4月更文挑战第29天】`Function.prototype.apply` 在JavaScript中用于动态设定函数上下文(`this`)和参数列表。它接受两个参数:上下文对象和参数数组。理解`apply`有助于深入JS运行机制。文章分三部分探讨其原理:基本概念和用法、工作原理详解、实际应用与注意事项。在应用中要注意性能、参数类型和兼容性问题。`apply`可用于动态改变上下文、传递参数数组,甚至模拟其他语言的调用方式。通过深入理解`apply`,能提升代码质量和效率。
|
15天前
|
Serverless 应用服务中间件 数据安全/隐私保护
Serverless 应用引擎操作报错合集之在阿里函数计算中,函数执行超时,报错Function time out after如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
18 4
|
1月前
|
Shell 应用服务中间件 nginx
shell学习(七) 【shell 函数】
shell学习(七) 【shell 函数】
12 1
|
1月前
|
人工智能 机器人 Shell
【shell】shell函数操作(有参、无参、有返回值、无返回值)
【shell】shell函数操作(有参、无参、有返回值、无返回值)
|
1月前
|
资源调度 Serverless 计算机视觉
高斯函数 Gaussian Function
**高斯函数,或称正态分布,以数学家高斯命名,具有钟形曲线特征。关键参数包括期望值μ(决定分布中心)和标准差σ(影响分布的宽度)。当μ=0且σ²=1时,分布为标准正态分布。高斯函数广泛应用于统计学、信号处理和图像处理,如高斯滤波器用于图像模糊。其概率密度函数为e^(-x²/2σ²),积分结果为误差函数。在编程中,高斯函数常用于创建二维权重矩阵进行图像的加权平均,实现模糊效果。
20 1
|
2月前
|
算法 Serverless C语言
CMake函数和宏(function和macro):使用函数和宏提高代码可读性
CMake函数和宏(function和macro):使用函数和宏提高代码可读性
35 1
|
2月前
|
存储 安全 编译器
【C++ 包装器类 std::function 和 函数适配器 std::bind】 C++11 全面的std::function和std::bind的入门使用教程
【C++ 包装器类 std::function 和 函数适配器 std::bind】 C++11 全面的std::function和std::bind的入门使用教程
34 0