Linux操作系统实验五 shell编程基础(四)

简介: Linux操作系统实验五 shell编程基础(四)

任务描述

本关任务:学习掌握什么是 shell 函数的返回值。

相关知识

bash shell 会把函数当作一个小型脚本,运行结束时,会返回一个退出状态码。有 3 种不同的方法来为函数生成退出状态码。

默认退出状态码

默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码。在函数执行结束后,可以用标准变量$?来确定函数的退出状态码。 【实例1】已知 test1.sh 脚本内容如下:

  1. #!/bin/bash
  2. func1() {
  3. echo "trying to display a non-existent file"
  4. ls -l badfile
  5. }
  6. echo "testing the function: "
  7. func1
  8. echo "The exit status is: $?"

运行脚本 bash test1.sh 执行结果如下:

  1. testing the function:
  2. trying to display a non-existent file
  3. ls: cannot access badfile: No such file or directory
  4. The exit status is: 2

函数的退出状态码是 2,这是因为函数中的最后一条命令没有成功运行。但你无法知道函数中其他命令中是否成功运行。带着这个疑问再看下面的例子:

【实例2】已知 test2.sh 脚本内容如下:

  1. #!/bin/bash
  2. func1() {
  3. ls -l badfile
  4. echo "trying to display a non-existent file"

  5. }
  6. echo "testing the function: "
  7. func1
  8. echo "The exit status is: $?"

运行脚本 bash test1.sh 执行结果如下:

  1. testing the function:
  2. ls: cannot access badfile: No such file or directory
  3. trying to display a non-existent file
  4. The exit status is: 0

这次,由于函数最后一条语句 echo 运行成功,该函数的退出状态码就是 0,尽管其中有一条命令并没有正常运行。由此可见,使用函数的默认退出状态码,来判断函数是否正常运行是很危险的。幸运的是,有几种办法可以解决这个问题。

return 命令

bash shell 使用 return 命令退出函数,并返回特定的退出状态码。return 命令允许指定一个整数值来定义函数的退出状态码,从而提供了一种简单的途径来设定函数退出状态码。 【实例3】已知 test3.sh 脚本的内容如下:

  1. #!/bin/bash
  2. func1() {
  3. ls -l badfile
  4. echo "trying to display a non-existent file"
  5. return 20
  6. }
  7. echo "testing the function: "
  8. func1
  9. echo "The exit status is: $?"

执行bash test.sh显示如下:

  1. testing the function:
  2. ls: cannot access badfile: No such file or directory
  3. trying to display a non-existent file
  4. The exit status is: 20

这一次变量$?返回的结果是 20,而按照默认的返回 $? 应该是 0,因为函数的最后一条命令正确执行。

任务描述

本关任务:掌握函数传递参数的方法以及如何处理变量。

相关知识

向函数传递参数

我们在 shell 变量那个实训,介绍过了一些特殊变量 $0$1$# 等。在 shell 中,函数可以使用标准的参数环境变量来表示命令行上传给函数的参数。例如,函数名会在$0变量中定义,函数命令行上的任何参数都会通过$1$2等定义。也可以用特殊变量$#,来判断传给函数的参数数目。请参考实例 1:

【实例1】已知脚本 test.sh 的内容如下:

  1. function addem {
  2. if [ $# -eq 0 ] || [ $# -gt 2 ]   # 判断传递给函数的参数个数
  3.     then
  4.     echo -1
  5. elif [ $# -eq 1 ]
  6.     then
  7.     echo $[ $1 + $1 ]
  8. else
  9.     echo $[ $1 + $2 ]
  10. fi
  11. }

  12. echo -n "Adding 10 and 15: "
  13. value=$(addem 10 15)
  14. echo $value

  15. echo -n "Let's try adding just one number: "
  16. value=$(addem 10)
  17. echo $value

  18. echo -n "Now trying adding no numbers: "
  19. value=$(addem)
  20. echo $value

  21. echo -n "Finally, try adding three numbers: "
  22. value=$(addem 10 15 20)
  23. echo $value

输出结果如下:

  1. Adding 10 and 15: 25
  2. Let's try adding just one number: 20
  3. Now trying adding no numbers: -1
  4. Finally, try adding three numbers: -1

这段脚本的意思是:脚本中的 addem 函数首先会检查脚本传给它的参数数目。如果没有任何参数,或者参数多于两个,addem 会返回值 -1;如果只有一个参数,addem 会将参数与自身相加;如果有两个参数,addem 会将它们进行相加。

注意:由于函数使用特殊参数环境变量作为自己的参数值,因此它无法直接获取脚本在命令行中的参数值。下面的【实例2】将会运行失败。

【实例2】:已知 test2.sh 的内容如下:

  1. function badfunc1 {
  2.     echo $[ $1 * $2 ]
  3. }

  4. badfunc1

我在命令行执行 bash test2.sh 10 3,发现脚本报错:

  1. [root@pre-host-work02 opt]# bash a.sh 1 10
  2. a.sh: line 3: *  : syntax error: operand expected (error token is "*  ")

尽管函数 badfunc1 也使用了 $1 和 $2 变量,但它们和脚本主体中的 $1 和 $2 变量并不相同。要在函数中使用这些值,必须在调用函数时手动将它们传过去。我们把脚本改动如下:

  1. function badfunc1 {
  2.     echo $[ $1 * $2 ]
  3. }

  4. badfunc1 $1 $2    

通过将$1$2变量传给函数,它们就能跟其他变量一样供函数使用了,我在命令行执行 bash test2.sh 10 3,结果符合预期:

  1. [root@pre-host-work02 opt]# bash a.sh 10 3
  2. 30
函数中处理变量

函数使用两种类型的变量:

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

全局变量是在 shell 脚本中任何地方都有效的变量。如果你在脚本的主体部分定义了一个全局变量,那么可以在函数内读取它的值。类似地,如果你在函数内定义了一个全局变量,可以在脚本的主体部分读取它的值。 默认情况下,你在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内正常访问,请看【实例3】。

【实列3】查看 test3.sh 内容,执行cat test3.sh 得到如下内容:

  1. #!/bin/bash

  2. function dbl {

  3. value=$[ $value * 2 ]
  4. }

  5. value=450

  6. dbl
  7. echo "The new value is: $value"

执行脚本输出结果如下:

  1. The new value is: 900

$value变量在函数外定义并被赋值。当 dbl 函数被调用时,该变量及其值在函数中都依然有效。如果变量在函数内被赋予了新值,那么在脚本中引用该变量时,新值也依然有效。但这其实很危险,尤其是如果你想在不同的 shell 脚本中使用函数的话。它要求你清清楚楚地知道函数中具体使用了哪些变量,包括那些用来计算非返回值的变量。请看【实例4】。

【实例4】:

  1. #!/bin/bash

  2. function func1 {
  3.     temp=$[ $value + 5 ]
  4.     result=$[ $temp * 2 ]
  5. }

  6. temp=4
  7. value=6
  8. func1               # 这个时候全局变量temp=6+5及为11,result=22

  9. echo "The result is $result"
  10. if [ $temp -gt $value ]
  11. then
  12. echo "temp is larger"
  13. else
  14. echo "temp is smaller"
  15. fi

执行脚本输出结果如下:

  1. The result is 22
  2. temp is larger
局部变量

无需在函数中使用全局变量,函数内部使用的任何变量都可以被声明成局部变量。要实现这一点,只要在变量声明的前面加上 local 关键字就可以了,比如local temp。或者也可以在变量赋值语句中使用 local 关键字:local temp=$[ $value + 5 ]。 local 关键字保证了变量只局限在该函数中。如果脚本中在该函数之外有同样名字的变量,那么 shell 将会保持这两个变量的值是分离的。现在你就能很轻松地将函数变量和脚本变量隔离开了,只共享需要共享的变量。

【实例5】:

  1. #!/bin/bash
  2. # demonstrating the local keyword
  3. function func1 {
  4.     local temp=$[ $value + 5 ]
  5.     result=$[ $temp * 2 ]
  6. }

  7. temp=4                    
  8. value=6    
  9. func1         #这个时候全局部变量temp=6+5,但是全局变量temp=4.

  10. echo "The result is $result"
  11. if [ $temp -gt $value ]
  12. then
  13. echo "temp is larger"
  14. else
  15. echo "temp is smaller"
  16. fi

执行脚本输出结果如下:

  1. The result is 22
  2. temp is smaller

现在,在 func1 函数中使用 $temp 变量时,并不会影响在脚本主体中赋给$temp变量的值。请重点分析【实例4】和【实例5】中的不同。

编程要求

本关不进行考核,希望大家能够真正的理解:

  • 向函数传递变量的方法;
  • 在函数中使用局部变量和全局变量的区别。 这两点非常重要,希望大家能够在命令行中自行练习本关【实例】中代码,能够充分的理解掌握这两点内容。

任务描述

本关任务:掌握文件包含方法的使用。

相关知识

文件包含方法

在 C,C++,PHP 中都是用 include 来包含文件,Go 和 Java 使用 import 来包含(导入)包,而在 shell 中,很简单,只需要一个点.,然后跟着文件路径及文件名,或者使用source关键字也可以,注意文件路径可以使用绝对路径和相对路径。请看实例 1。

【实例1】已知在同一目录下,有 test1.sh 和 test2.sh 两个脚本,test1.sh 内容如下:

  1. #!/bin/bash
  2. url="www.educoder.net"

同一目录下的 test2.sh 内容如下:

  1. #!/bin/bash
  2. . ./test1.sh   # 第一个.是包含符号,第二个. 表示当前目录下。
  3.               # 这是采用相对路径包含的学法,记得中间要空格。

  4. echo "编程平台地址是:$url"

在命令行执行bash test2.sh,大家想想看这个时候输出的是什么? 输出的结果如下:

  1. 编程平台地址是:www.educoder.net

注意:

  • 变量的定义也要考虑局部变量和全局变量;
  • 如实例1 所示 test1.sh 并不需要赋予执行权限;
  • 注意包含文件的路径。

【实例2】同一目录下 test1.sh、test2.sh、test3.sh 内容如下:

  1. [root@pre-host-work02 opt]# cat test1.sh

  2. #!/bin/bash

  3. test(){

  4.    url='www.educoder.net'

  5. }

  6. [root@pre-host-work02 opt]# cat test2.sh
  7. #!/bin/bash

  8. hello(){

  9.    echo "i am from test3.sh"

  10. }
  11. [root@pre-host-work02 opt]# cat test3.sh
  12. #!/bin/bash
  13.               ##包含多个文件时,一行智能写一个文件,分开写。
  14. . ./test1.sh   ##包含test1.sh  ./test1.sh表示当前目录下
  15. . ./test2.sh   ##包含test2.sh  ./test2.sh表示当前目录下

  16. echo "编程平台:$url"
  17. hello

在命令行执行bash test3.sh ,输出结果如下:

  1. [root@pre-host-work02 opt]# bash test3.sh
  2. 编程平台:
  3. i am from test3.sh
  • 因为在 test1.sh 中 url 变量定义在函数内,即为局部变量,所以包含过来之后不能被调用;
  • test2.sh 中定义了函数 hello,在 test3.sh 通过. 的方式包含进来,通过函数名 hello 的调用,调用了 test2.sh 中的 hello()函数,输出“i am from test3.sh” 。

编程要求

本关任务包含了三个脚本文件,它们分别是 step4/t1.shstep4/t2.shstep4/main.sh,点击右侧“代码文件”即可查看,如下图所示:

  • 根据要求补全 step4/t1.sh 代码。
  • 根据要求补全 step4/main.sh 代码。

相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
目录
相关文章
|
10天前
|
安全 Linux 数据安全/隐私保护
Vanilla OS:下一代安全 Linux 发行版
【10月更文挑战第30天】
27 0
Vanilla OS:下一代安全 Linux 发行版
|
13天前
|
人工智能 安全 Linux
|
1月前
|
Web App开发 网络协议 Linux
linux命令总结(centos):shell常用命令汇总,平时用不到,用到就懵逼忘了,于是专门写了这篇论文,【便持续更新】
这篇文章是关于Linux命令的总结,涵盖了从基础操作到网络配置等多个方面的命令及其使用方法。
61 1
linux命令总结(centos):shell常用命令汇总,平时用不到,用到就懵逼忘了,于是专门写了这篇论文,【便持续更新】
|
17天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
1月前
|
Unix 物联网 大数据
操作系统的演化与比较:从Unix到Linux
本文将探讨操作系统的历史发展,重点关注Unix和Linux两个主要的操作系统分支。通过分析它们的起源、设计哲学、技术特点以及在现代计算中的影响,我们可以更好地理解操作系统在计算机科学中的核心地位及其未来发展趋势。
|
1月前
|
Shell
Shell编程(下)
Shell编程(下)
88 1
|
1月前
|
Shell Linux Windows
Shell编程(上)
Shell编程(上)
39 1
|
1月前
|
算法 调度 UED
探索操作系统中的多线程编程
【8月更文挑战第78天】在数字世界的复杂迷宫中,操作系统扮演着至关重要的角色。本文旨在揭开操作系统中多线程编程的神秘面纱,引导读者理解其概念、实现及应用。通过深入浅出的方式,我们将探讨如何在程序设计中运用多线程,以及这一技术如何优化软件性能和提升用户体验。文章将结合具体代码示例,展示多线程在实际应用中的魔力。无论你是编程新手还是资深开发者,这篇文章都将为你提供新的视角和思考路径。
|
1月前
|
存储 Shell Linux
【Linux】shell基础,shell脚本
Shell脚本是Linux系统管理和自动化任务的重要工具,掌握其基础及进阶用法能显著提升工作效率。从简单的命令序列到复杂的逻辑控制和功能封装,Shell脚本展现了强大的灵活性和实用性。不断实践和探索,将使您更加熟练地运用Shell脚本解决各种实际问题
23 0
|
3月前
|
编解码 安全 Linux
基于arm64架构国产操作系统|Linux下的RTMP|RTSP低延时直播播放器开发探究
这段内容讲述了国产操作系统背景下,大牛直播SDK针对国产操作系统与Linux平台发布的RTMP/RTSP直播播放SDK。此SDK支持arm64架构,基于X协议输出视频,采用PulseAudio和Alsa Lib处理音频,具备实时静音、快照、缓冲时间设定等功能,并支持H.265编码格式。此外,提供了示例代码展示如何实现多实例播放器的创建与管理,包括窗口布局调整、事件监听、视频分辨率变化和实时快照回调等关键功能。这一技术实现有助于提高直播服务的稳定性和响应速度,适应国产操作系统在各行业中的应用需求。
108 3