20.Linux Shell自定义函数

文章目录

  • Linux Shell自定义函数
    • 1)函数的定义与使用
    • 2)函数的返回值
      • 默认情况
      • 使用`return`命令
      • 捕获函数输出
    • 3)函数参数
    • 4)函数变量
    • 5)数组与函数
      • 数组作为函数参数
      • 数组作为函数的返回值
    • 6)创建`shell`函数库


欢迎访问个人网络日志🌹🌹知行空间🌹🌹


Linux Shell自定义函数

在脚本中一遍又一遍地编写同样的代码会很烦人,为了避免这种麻烦,可以将代码封装成函数,多次引用。

1)函数的定义与使用

Linux Shell中函数的定义有两种方式:

  • 采用关键字function
function name {commands
}
  • 函数名后跟空括号
name() {commands
}

使用函数:

#!/bin/bashsayHellofunction sayHello {echo "Hello, Bash Shell."
}sayHi() {echo "Hi, Bash Shell."
}sayHello
sayHisayHi() {echo "Hi2, Bash Shell."
}sayHi

执行,

$ ./test.sh 
# ./test.sh: 行 3: sayHello:未找到命令
# Hello, Bash Shell.
# Hi, Bash Shell.
# Hi2, Bash Shell.

每次引用函数名时,bash shell会找到函数的定义并执行在那里定义的命令。

从上面的例子可以看到,

  • 使用未定义的函数脚本会报错
  • 函数可以被重定义,调用时会使用最新的定义,原来的定义会被覆盖

2)函数的返回值

通常,在使用函数时为了与调用者交互,会希望函数能给出局部逻辑执行后的返回值,如运算结果,执行有没有出错。

默认情况

bash shell中,默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码。函数执行结束后,可以用标准变量 $? 来确定函数的退出状态码

#!/bin/bash
function sayHello {echo "Hello, Bash Shell."
}
sayHello
echo ret value: $?sayHi() {echo "Hi2, Bash Shell."ls -al rob
}sayHi
echo ret value: $?sayHi() {ls -al robecho "Hi2, Bash Shell."
}

执行,

$ ./test.sh# Hello, Bash Shell.
# ret value: 0
# Hi2, Bash Shell.
# ls: 无法访问 'rob': 没有那个文件或目录
# ret value: 2
# ls: 无法访问 'rob': 没有那个文件或目录
# Hi2, Bash Shell.
# ret value: 0

可以看到,在sayHi函数中执行最后一行指令ls -al rob时出错,因此$?的值是2。但是,看上面的例子中,前后两个sayHi函数因为出错语句位置的不同,函数的退出状态也不同。因此,使用$?判断函数的状态是很不可靠的。

使用return命令

bash shell使用 return 命令来退出函数并返回特定的退出状态码。 return 命令允许指定一个整数值来定义函数的退出状态码。

  • return返回的状态码也在$?中,必须函数一结束就返回,否则返回值会结束
  • 退出状态码必须是0-255,任何大于256的值都会产生一个错误值。
#!/bin/bashdoubleCount(){read -p "Please Input A Value:" ivalecho doubling the value...return $[ $ival * 2 ]
} doubleCount
echo "The New Value:" $?

执行,

$ ./test.sh 
# Please Input A Value:100
# doubling the value...
# The New Value: 200
$ ./test.sh 
# Please Input A Value:200
# doubling the value...
# The New Value: 144

可以看到输入200时,输出本应该是400,但因为其超出了256的范围,因此输出错误。

捕获函数输出

可以将函数的输出保存到shell变量中。

#!/bin/bashdoubleCount(){read -p "Please Input A Value:" ivalecho $[ $ival * 2 ]
} r=$(doubleCount)
echo "The New Value:" $r

执行,

$ ./test.sh 
# Please Input A Value:200
# The New Value: 400

从上面的例子可以看到两点和以前不一样的地方:

  • 函数echo语句的输出赋值给了接收函数返回值的变量
  • 返回值可以大于256了,其实这种方式还可以返回浮点值和字符串值

3)函数参数

前面讲bash shell会将函数当作小型脚本来对待。这意味着可以像普通脚本那样向函数传递参数,并可以用$1$2这样获取传递给函数的参数值。

#!/bin/bash
function add {if [ $# -eq 0 ] || [ $# -gt 2 ]thenecho -1elif [ $# -eq 1 ]thenecho $[ $1 + $1 ]elseecho $[ $1 + $2 ]fi
}echo -n "Adding 10 and 15: "
value=$(addem 10 15)
echo $valueecho -n "Try adding just one number: "
value=$(addem 10)
echo $valueecho -n "Trying adding no numbers: "
value=$(addem)
echo $valueecho -n "Try adding three numbers: "
value=$(addem 10 15 20)
echo $value

执行,

$ ./test.sh 
# Adding 10 and 15: 25
# Try adding just one number: 20
# Trying adding no numbers: -1
# Try adding three numbers: -1

上面这个函数实例给出了如何在函数中获取参数,如何传递参数给函数。不过呢,由于在函数中使用$1是获取传递给函数的参数,因此,函数中没有办法直接获取传给脚本的命令行参数,只能以函数参数的方式传递给函数

4)函数变量

全局变量是在shell脚本中任何地方都有效的变量。如果在脚本的主体部分定义了一个全局变量,那么可以在函数内读取它的值。

#!/bin/bashfunction multiply2 {v=$[ $v * 2 ]
}read -p "Enter a value: " v
multiply2
echo "The New Value Is: $v"

执行,

$ ./test.sh 
# Enter a value: 200
# The New Value Is: 400

很诧异吧,函数multiply2中变量v没有定义就可以使用,这是因为v是全局变量,在调用multiply2前定义了。这种方式很容易造成混乱,不建议过度使用。

函数内部使用的任何变量都可以被声明成局部变量,只要在变量声明的前面加上 local 关键字就可以了

#!/bin/bashfunction add5 {local temp=$[ $value + 5 ]result=$[ $temp * 2 ]
}temp=4
value=6add5
echo "The result is $result"
if [ $temp -gt $value ]
thenecho "temp is larger"
elseecho "temp is smaller"
fi

执行,

$ ./test.sh 
# The result is 22
# temp is smaller

上面例子中有两点,

  • result没有使用local修饰,因此是全局变量
  • local temp限定了其作用域仅在函数中,不会影响函数外temp的值

5)数组与函数

数组作为函数参数

将数组变量当作单个参数传递,它不会起作用。

#!/bin/bashfunction test_array {echo "The parameters are: $@"thisarray=$1echo "The received array is ${thisarray[*]}"
}myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
test_array $myarray

执行,

$ ./test.sh 
# The original array is: 1 2 3 4 5
# The parameters are: 1
# The received array is 1

可以看到通过$myarray指定传入的只是数组的第一个元素。要解决这个问题,必须将该数组变量的值分解成单个的值,然后将这些值作为函数参数使用。

#!/bin/bashfunction arraySum {local sum=0local newarraynewarray=($(echo "$@"))for value in ${newarray[*]}sum=$($sum + $value)doneecho $sum
}array=(1 2 3 4 5)
echo "The array is: ${array[*]}"
arg1=$(echo ${array[*]})
result=$(arraySum $arg1)
echo "The result is $result"

执行,

$ ./test.sh 
# The array is: 1 2 3 4 5
# The result is 15

使用$(echo $value)可以将echo的输出保存到变量中,这样可以将数组传入到函数中

数组作为函数的返回值

从函数中返回数组的操作也是使用echo语句,其操作为:

#!/bin/bashfunction multi2 {local origarraylocal newarraylocal eleslocal iorigarray=($(echo "$@"))newarray=($(echo "$@"))eles=$[ $# - 1 ]for (( i = 0; i <= $eles; i++ )){newarray[$i]=$[ ${origarray[$i]} * 2 ]}echo ${newarray[*]}
}array=(1 2 3 4 5)
echo "Array is: ${array[*]}"
arg1=$(echo ${array[*]})
result=($(multi2 $arg1))
echo "The new array is: ${result[*]}"

执行,

$ ./test.sh 
# Array is: 1 2 3 4 5
# The new array is: 2 4 6 8 10

注意,上面newarray=($(echo "$@"))newarray=$(echo "$@"),如果没有(),输出其实是一个整体,加上括号才是数组,不带括号,上面的脚本执行会报错

6)创建shell函数库

写一个脚本文件:

# compute文件function addem {echo $[ $1 + $2 ]
}
function multem {echo $[ $1 * $2 ]
}

在需要使用该库文件的地方,只需要在脚本开头

source /xxx/xx/compute

然后就可以使用定义在compute中的函数了。

source 命令有个快捷的别名,称作点操作符.,还可以写成:

. /xxx/xx/compute

函数的应用绝不仅限于创建自己的函数自娱自乐。在开源世界中,可以下载大量各式各样的函数,并将其用于自己的应用程序中。譬如GNU shtool shell脚本函数库其中提供了一些简单的shell脚本函数,可以用来完成日常的shell功能。



欢迎访问个人网络日志🌹🌹知行空间🌹🌹


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/612196.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

性格是如何形成的?能不能改变性格?

有一句话叫“性格决定命运”&#xff0c;广泛流传&#xff0c;也就是说 “命运”与“性格”是紧密相连的&#xff0c;可见“性格”对于一个人的重要性。 性格是怎么来的&#xff1f; 1、遗传基因 根据一些心理学家的最新研究&#xff0c;认为性格与人体内的基因有关系&#x…

不再恐惧指针,指针详解

什么是指针&#xff1f; 通俗来说指针就相当于地址&#xff0c;因为我们写入的代码每个变量的数据类型不同&#xff0c;字节大小不同&#xff0c;在计算机内存中所开辟存储的大小自然不同&#xff0c;且指针通常存储的是内存单元中最小单元的编号 比如&#xff1a;int*指针的…

【Scala】——面向对象

1 Scala 包 1.1 包风格 Scala 有两种包的管理风格。 第一种 Java 的包管理风格相同&#xff0c;每个源文件一个包&#xff08;包 名和源文件所在路径不要求必须一致&#xff09;&#xff0c;包名用“.”进行分隔以表示包的层级关系&#xff0c;如 com.atguigu.scala。另一种风…

遥感单通道图像保存为彩色图像

系列文章目录 第一章PIL单通道图像处理 文章目录 系列文章目录前言一、代码实现二、问题记录在这里插入图片描述 总结 前言 将单通道图像以彩色图像的形式进行保存主要使用了PIL库 一、代码实现 palette_data [***]&#xff1a;可以进行自定义设置 代码如下&#xff1a; fr…

UVa12304 2D Geometry 110 in 1!

题目链接 UVa12304 2D Geometry 110 in 1! 题意 这是一个拥有6&#xff08;二进制是110&#xff09;个子问题的2D几何问题集。 1 CircumscribedCircle x1 y1 x2 y2 x3 y3&#xff1a;求三角形(x1,y1)-(x2,y2)-(x3,y3)的外接圆。这3点保证不共线。答案应格式化成(x,y,r…

python实现对导入包中的全局变量进行修改

问题 在写程序中遇到这样一个问题&#xff0c;有一个base.py 文件&#xff0c;文件内容如下&#xff1a; #base.py文件 global x xbasedef print_x():print(x) 在另一个主程序test.py中&#xff0c;导入这个文件&#xff0c;并使用其中的print_x函数&#xff0c;但是我想修改…

服务器 配置git

参考了下面这篇文章&#xff0c;不对的地方做了改正 在服务器上git clone github项目的过程-CSDN博客 1. 下载解压 wget https://www.kernel.org/pub/software/scm/git/git-2.34.1.tar.gz tar -zxvf git-2.34.1.tar.gz 2. 安装 cd git-2.34.1/ ./configure make confi…

Geotools-PG空间库(Crud,属性查询,空间查询)

建立连接 经过测试&#xff0c;这套连接逻辑除了支持纯PG以外&#xff0c;也支持人大金仓&#xff0c;凡是套壳PG的都可以尝试一下。我这里的测试环境是Geosence创建的pg SDE&#xff0c;数据库选用的是人大金仓。 /*** 获取数据库连接资源** param connectConfig* return* {…

springboot私人健身与教练预约管理系统源码和论文

随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&#xf…

【rk3568】01-环境搭建

文章目录 1.开发板介绍1.1相关资源&#xff1a;1.2接口布局1.3屏幕1.4核心板引脚可复用资源 2.环境搭建2.1安装依赖包2.2git配置2.3安装sdk2.4sdk介绍2.5sdk编译 3.镜像介绍 1.开发板介绍 开发板&#xff1a;atk-rk3568开发板 eMMC&#xff1a;64G LPDDR4&#xff1a;4G 显示屏…

螺旋数字矩阵 - 华为OD统一考试

OD统一考试(C卷) 分值: 100分 题解: Java / Python / C++ 题目描述 疫情期间,小明隔离在家,百无聊赖,在纸上写数字玩。他发明了一种写法: 给出数字个数n和行数m (0 < n <= 999,0 < m <= 999),从左上角的1开始,按照顺时针螺旋向内写方式,依次写出2,3……

创建ROS模型与小机器人地图规划

1、打开自己的VM系统 2、安装小机器人的安装包&#xff0c;输入如下命令&#xff0c;回车输入密码(自己设的)&#xff1a; sudo apt install ros-noetic-turtlebot3-simulations ros-noetic-turtlebot3-slam ros-noetic-turtlebot3-navigation 提示我之前安装过了 3、用rosla…

Java 常见缓存详解以及解决方案

一. 演示Mybatis 一级缓存 首先我们准备一个接口 两个实现的方法&#xff0c; 当我们调用这个queryAll&#xff08;&#xff09;方法时我们需要调用selectAll&#xff08;&#xff09;方法来查询数据 调用此接口实现效果 这个时候我们就可以发现了问题&#xff0c;我们调用方法…

18张AI电脑动漫超清壁纸免费分享

18张AI电脑动漫壁纸&#xff0c;紫色系和暗黑系&#xff0c;都很不错&#xff0c;喜欢的朋友可以拿去 CSDN免积分下载

【LV12 DAY12-13 GPIO C 语言与寄存器封装】

GPIO 通用型输入输出&#xff0c;GPIO可以控制连接在其引脚实现信号的输入和输出 芯片的引脚和外部设备相连从而实现与外部硬件的通讯&#xff0c;控制&#xff0c;信号采集的功能。 控制CHG_COK引脚输出为高电平&#xff0c;LED亮&#xff0c;输出为低电平&#xff0c;LED熄灭…

Android 10.0 TvSettings系统设置wifi连接密码框点击Enter键失去焦点

1.前言 在10.0的box产品开发中,在TvSettings中,在wifi连接的时候,在用遥控器输入wifi密码框的时候,会发现在按遥控器Enter键的时候, 发现EditText焦点失去了,导致输入法消失了,为了解决这个问题就需要拦截Enter键保证正常输入wifi密码,接下来就来实现这个功能 如图: 2.…

CSS 弹幕按钮动画

<template><view class="content"><button class="btn-23"><text class="text">弹幕按钮</text><text class="marquee">弹幕按钮</text></button></view></template><…

win7添加access的odbc数据源

从控制面板打开odbc数据源&#xff1b;如果像下面没有access的驱动程序&#xff0c; 根据资料&#xff0c;打开C盘-Windows-SysWow64-odbcad32.exe&#xff0c;看一下就有了&#xff1b; 然后添加用户DSN&#xff0c;选中access的驱动程序&#xff0c; 自己输入一个数据源名&am…

@Autowired 和 @Resource 的区别是什么?

Java面试题目录 Autowired 和 Resource 的区别是什么&#xff1f; Autowired 是 Spring 提供的注解。默认的注入方式为byType&#xff08;根据类型进行匹配&#xff09;。 Resource 是 JDK 提供的注解。默认注入方式为 byName&#xff08;根据名称进行匹配&#xff09;。 当一…

【浅尝C++】引用

&#x1f388;归属专栏&#xff1a;浅尝C &#x1f697;个人主页&#xff1a;Jammingpro &#x1f41f;记录一句&#xff1a;大半夜写博客的感觉就是不一样&#xff01;&#xff01; 文章前言&#xff1a;本篇文章简要介绍C中的引用&#xff0c;每个介绍的技术点&#xff0c;在…