当前位置: 首页 > news >正文

shell脚本之函数的引入

内容预知

 1.shell函数的基本知识

1.1 shell函数的个人理解 

 1.2 定义函数的格式

 

 1.3 查看函数与删除函数(Linux命名行环境中)

1.4 函数的返回值 

1.4.1 return 返回值  

1.4.2 echo返回值的用法 

 2.函数的参数传入与变量范围

 2.1 函数传参规则

2.2 函数中变量的范围 

 测试一

测试二

 2.2.2 用local重新规定函数变量的范围

 测试一

 测试二

 3.实战演练,使用函数写脚本

 3.1 菱形打印(函数版本)

 3.2 十进制IP转化二进制(函数版)

 4. 递归函数

4.1 递归函数进行阶乘运算 

4.2 使用递归函数来读取文件 

 5.函数库的引用

第一步:搭建函数库 

第二步:编写脚本进行调用

 第三步:结果测试

 总结


 1.shell函数的基本知识

1.1 shell函数的个人理解 

 在shell脚本中,存在着大量的命令操作,其中有很多编写的代码的重复性很高,让代码出现了大量的冗余和繁琐,不易维护和解读。于是引入了函数的方法,我们可以将shell中的函数看作是一个方法,只需要调用它并且进行传参,就可以得出结果,并且还能够多次利用,减少重复代码带来的不便。

 

shell函数的作用:

1.避免代码重复,减少代码的冗余

2.模块化处理,随调随用,增强代码的可读性和维护性 

 

 1.2 定义函数的格式

 

 格式一:

function  函数名 {

  命令操作(指令代码)

}

 

 

格式二:

函数名  (){

  命令操作(指令代码)

}

 

 

=================main==============================

定义好函数和编写好内容后,就可以开辟一块main(主方法区),在此范围进行函数的调用 

 

 1.3 查看函数与删除函数(Linux命名行环境中)

 

 查看函数  :   declare  -F

 

 删除函数: unset 函数名

 

 

1.4 函数的返回值 

 

1.4.1 return 返回值  

 1)是函数结束的标识,并且后面跟着的数值(就是返回的状态码,默认情况下的$?是0,而经过return改变后,就会变为return后面跟着的数值)

2)return的返回值范围在1-255之间,超过该范围后会被256取余,取余的结果作为返回码

#!/bin/bash


function test {

echo "这是一个关于return返回值的验证实验"

return 257

}

##################main######################
test
echo $?

 返回值的结果:

 

1.4.2 echo返回值的用法 

 echo对于linux来讲就是一个万能输出的工具,当return 不能满足我们我们对返回值的需求时,可以强迫echo来充当返回值输出工具

#!/bin/bash

function test2 {
echo "这是echo返回值的验证实验:"
read  -p  "请任意输入一个数字:"  num
echo $[$num+1]

}

result=$(test2)
echo $result

 

 

返回值输出结果:

 

 2.函数的参数传入与变量范围

 2.1 函数传参规则

 

脚本函数传参测试:


#!/bin/bash

function test3 {

echo "函数获得第一个参数值:"   $1
echo "函数获得第二个参数值:"   $2
}



############main###################
test3 $2  $1

输出结果:

 

将结果代入代码中再次分析:

函数传参的结论:

 当脚本里位置变量获取到外部传参数值后,函数此时根据脚本获取参数的位置顺序(来决定函数里位置变量获取数值的顺序)图中因为脚本的$2在$1前面,所以函数中的$1获取的是脚本中$2的值

 

2.2 函数中变量的范围 

 

2.2.1 函数变量的默认范围

 测试一

#!/bin/bash

function test4 {
i=1
echo  "输出的函数变量的值为"  $i
}


############main##############
i=2
test4

 

 

 输出结果:

测试二

#!/bin/bash

function test4 {
echo  "输出的函数变量的值为"  $i
i=1
}


############main##############
i=2
test4 

 输出结果:

 

结论:对比测试一和测试可知 函数中的变量默认的情况下为shell脚本环境中的全局变量,影响函数内外的结果,最后输出的函数结果依据获取变量的先后顺序来决定的

 

 2.2.2 用local重新规定函数变量的范围

 测试一

#!/bin/bash

function test4 {
   i=1
}


############main##############
i=2
test4
echo "输出的变量值为" $i 
                      

 输出结果:

 

 

 测试二


#!/bin/bash

function test4 {
  local i=1
}


############main##############
i=2
test4
echo "输出的变量值为" $i 

 

 

输出结果:

 

 延申:

 

输出结果:

 

 测试结论: 用local定义的函数变量为局部变量,它只会影响到自己所在函数的内的与该变量相关的结果,不影响外界或则其他函数中的变量(即使是同名也不影响)

 3.实战演练,使用函数写脚本

 3.1 菱形打印(函数版本)

使用函数的方式打印一个菱形,并且能够通过标准输入的方式来控制该菱形的大小

#!/bin/bash

#用来打印菱形上半部分的函数
shang (){
i=1
NUM=$1
while [ $i -le $NUM ]
do
  a=$NUM
  while [ $a  -ge  $i ]
  do
  echo -n  ' '
  let a--
  done
  b=1
  while [ $b -le  $i ]
  do
  echo -n '*'
  let b++
  done
  c=2
  while [ $c -le  $i   ]
  do
  echo -n '*'
  let c++
  done
echo ""
let i++
done
}
#用来打印菱形下半部分的函数
xia (){
let d=$1-1
while [ $d -ge 1  ]
do
 e=$1
 while [ $e -ge $d ]
 do
 echo -n ' '
 let e--
 done
 f=$[(2*d)-1]
 g=1
 while [ $g -le $f ]  
 do
 echo -n '*'
 let g++
 done
let d--
echo ""
done
}

######################main#####################
read -p  "请输入一个数字来控制函数的大小(数字越大菱形越大):"    num

shang $num

xia   $num

 

 测试结果:

 3.2 十进制IP转化二进制(函数版)

使用函数的方式,将标准输入获得十进制IP地址转化为二进制的IP地址 

 

#!/bin/bash

#定义一个用于十进制转化成二进制的函数
function bin {
SUM=''
NUM=$1
for i in {1..8}
do
   SUM=$[NUM%2]$SUM
   let NUM/=2
done
echo $SUM
}

#定义一个用分割IP的函数
SPT (){
   IP=$1
   for i in {1..4}
   do
   num=${IP%%.*}
   IP=${IP#*.}
   #使用bin函数进行转化
   BIN=$(bin $num)
   echo -n $BIN.
   done
}

####################main##################
read -p "请输入一个十进制的IP地址:"   SIP
RES=$(SPT $SIP)
echo  "输出的二进制IP为:"   ${RES%.*}

 

 输出结果:

 4. 递归函数

4.1 递归函数进行阶乘运算 

#!/bin/bash
   fact() {
    if [ $1 -eq 1 ];then
    echo 1
    else
    local temp=$[$1 -1]
    local result=$(fact $temp)
    echo $[$1 * $result]                        
    fi
   }
########## main ##########

   read -p "请输入一个要阶乘的数值:" n

   result=$(fact $n)

   echo $result

 

 

 

 递归函数进行阶乘的实际过程(以$1=5为例子):

#fact 5  $1=5     temp=4     result=$(fact 4)    echo  5 * $(fact 4)  ​

 #fact 4  $1=4     temp=3     result=$(fact 3)    echo 5 * 4*$(fact 3)  ​  

#fact 3  $1=3     temp=2     result=$(fact 2)    echo 5 * 4 * 3*$(fact 2)  ​

 #fact 2  $1=2     temp=1      result=$(fact 1)   echo 5 * 4 * 3 * 2*$(fact 1)​  

#fact 1              $1=1                                  

 

输出结果:

 

 

4.2 使用递归函数来读取文件 

 需求:想要读取/var/log  目录下所有的文件和子目录,并且进行区分输出

 

在没有函数前,我们会选择用循环的方式来写脚本(但是缺点也显而易见)

但是递归读取,就能很好的实现该需求 

 

#!/bin/bash

function list_dir {
for f in `ls $1`
do
if [ -d "$1/$f" ];then
     echo "目录:$2$f"
list_dir "$1/$f" " $2"
else
  echo "文件:$2$f"
fi
done
}

########## main ##########
list_dir "/var/log" ""

          

 输出结果:

 

另外:只要就将第一个位置变量传进的参数改为一个标准输入的变量,就可以查找任意目录下的文件和子目录了

 5.函数库的引用

 如果我们能拥有,或者编写过很多有价值的函数(能够具体实现某一功能的那种函数),我们在想运用的时候希望能够跨文件调用,这些在Linux中shell脚本也能实现,只要进行函数库文件的搭建,后期就能在编写脚本时进行直接调用

 

 函数库所存文件为普通文件即可,但是函数的格式一定要规范,有能传参的设置。

后面进行调用时可以通过  “.”和“source”来进行跨文件调用

第一步:搭建函数库 

 

 

[root@localhost xunhuan6]#vim myfunction



#加法函数
jiafa(){

echo $[$1+$2]

}
#减法函数
jianfa(){

echo $[$1-$2]
}
#乘法函数
chengfa(){
echo $[$1*$2]
}
#除法函数
chufa(){
if [ $2 -ne 0  ];then
echo $[$1/$2]
else
echo "除数不能为0"
fi
}
#阶乘函数
jiecheng(){
 if [ $1 -eq 1 ];then
    echo 1
    else
    local temp=$[$1 -1]
    local result=$(fact $temp)
    echo $[$1 * $result]
    fi
}

 

 

第二步:编写脚本进行调用


#!/bin/bash

#调用函数库
source /xunhuan6/myfunction
#获取输入的两个变量
read -p "请输入第一个正整数:" a
read -p "请输入第二个正整数:" b

#调用函数库中的方法,将值赋予变量
r1=$(jiafa $a $b)
r2=$(jianfa $a $b)
r3=$(chengfa $a $b)
r4=$(chufa $a $b)
r5=$(jiecheng $a)


#输出变量
echo "加法的运算结果为:" $r1
echo "减法的运算结果为:" $r2
echo "乘法的运算结果为:" $r3
echo "除法的运算结果为:" $r4
echo "阶乘的运算结果为:" $r5

 

 

 

 第三步:结果测试

 

 总结

 1.注意函数中的传参和函数外通过位置变量的传参是不同的(函数传参是根据脚本变量的位置决定)

2.注意局部函数变量和全局函数变量的差异

3.接收位置位置变量值,建议赋予新定义的变量,增强代码的可读性

4.理解递归函数,是对函数进行更深层次的利用和挖掘,尤其是递归运用的方面

5.搭建函数库要注意在文件中也要保持函数该有的脚本格式,另外调用时先声明调用的文件,用source或者“.”

相关文章:

  • JDK的下载与安装详细教程
  • 刷题记录(NC231128 Steadily Growing Steam,NC21467 [NOIP2018]货币系统,NC235950 多重背包)
  • 详解红黑树【C++实现】
  • Flask的一些简单代码
  • 链路追踪 - SkyWalking
  • 基于NFS共享存储实现KVM虚拟主机动态迁移
  • MySQL之常用存储引擎
  • 动手学习深度学习 02:预备知识
  • dockerkubernets篇(二十六)
  • 9.synchronized的三把锁
  • 为什么开发人员正在成为供应链攻击中的最薄弱环节
  • MySQL之事务、锁
  • 项目第二天
  • Windows与网络基础-10-windows用户管理
  • 计算机网络笔记(王道考研) 第三章:数据链路层
  • JS 中的深拷贝与浅拷贝
  • python3.6+scrapy+mysql 爬虫实战
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • 【mysql】环境安装、服务启动、密码设置
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • CentOS从零开始部署Nodejs项目
  • learning koa2.x
  • mac修复ab及siege安装
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • oldjun 检测网站的经验
  • select2 取值 遍历 设置默认值
  • Vue2 SSR 的优化之旅
  • 大整数乘法-表格法
  • 给新手的新浪微博 SDK 集成教程【一】
  • 官方解决所有 npm 全局安装权限问题
  • 如何解决微信端直接跳WAP端
  • 与 ConTeXt MkIV 官方文档的接驳
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 大数据全解:定义、价值及挑战
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • (+4)2.2UML建模图
  • (14)Hive调优——合并小文件
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (第27天)Oracle 数据泵转换分区表
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (转)Unity3DUnity3D在android下调试
  • (转)母版页和相对路径
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .net core 连接数据库,通过数据库生成Modell
  • .net core开源商城系统源码,支持可视化布局小程序
  • .Net Core与存储过程(一)
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证
  • .sh 的运行
  • /etc/shadow字段详解
  • @Autowired注解的实现原理
  • [ C++ ] 继承
  • [hdu 1247]Hat’s Words [Trie 图]