同步发表:http://blog.hacktons.cn/2017/12/13/shell-func-return/

背景

通过shell编程,写一些工具批处理的时候,经常需要自定义函数。更复杂点的情况下,可能有需要返回一个值。

由于在shell的世界中,并不像其他编程语言,它不支持我们所熟悉的方法返回。本文一起总结一下如何优雅的解决返回值问题?

测试程序

我们一般通过$?来获取上一个语句的输出。看一下下面得测试语句:

新建testReturn脚本

returnString(){
return $1
} returnString $1
result=$?
echo "result=$result"

现在我们有一个testReturn的脚本,里面有一个returnString的方法,我们希望它能够直接返回我们输入的参数。

当我们分别以hello,500,12作为输入参数时,他的执行和输出情况是一样的么?

./testReturn hello
./testReturn 500
./testReturn 12

在心中试着猜一下可能的情况,现在我们来揭晓答案:

程序输出情况

在执行hello的时候,并没有输出hello,而是报了一个return只接受数字类型的错误

aven-mac-pro-2:avenwu.github.io aven$ ./testReturn hello
./testReturn: line 23: return: hello: numeric argument required
result=255

在执行500的时候,页没有输出500,而是输出了244

aven-mac-pro-2:avenwu.github.io aven$ ./testReturn 500
result=244

执行12的时候,终于正确了,返回12

aven-mac-pro-2:avenwu.github.io aven$ ./testReturn 12
result=12

异常分析

现在我们分析一下returnString这个方法,为什么会有这么多种输出情况呢?

首先他的写法显然是不严谨的,但也不是完全错误,比如输入12他就正确返回了。

return本身是shell里面的buildin函数,笔者总结了下,他有以下几个特征:

  • return可以返回数字状态,常常用于返回0,1,标识一个函数执行后是否成功
  • 注意return不可以返回非数字类型
  • 同时数字类型也有可能发生溢出现象

全局变量

如果我们就是要返回一个字符串,怎么办呢?可以通过定义全局变量来进行赋值,类似于静态变量/成员变量的写法,我们让他的作用域穿透整个上下文。

result=""
returnString(){
result=$1
} returnString $1
echo "result=$result"

再看一下输出,得到了我们需要的结果:

aven-mac-pro-2:avenwu.github.io aven$ ./testReturn hello
result=hello
aven-mac-pro-2:avenwu.github.io aven$ ./testReturn 500
result=500
aven-mac-pro-2:avenwu.github.io aven$ ./testReturn 12
result=12

但是这样写,会污染全局变量,并且result这个变量很容易在内部和外部都被修改,导致内部修改失效。

eval

除了return,还有其他一些buildin的关键字,比如evallocal

默认在当前脚本定义的变量都是全局变量,在方法中则可以通过local来定义局部变量,这样可以避免全局变量污染.

同时结合eval赋值语句,来实现变量的修改

returnString(){
local __result=$2
eval $__result=$1
} returnString $1 result
echo "result=$result"

同样我们也得到了希望的结果

aven-mac-pro-2:avenwu.github.io aven$ ./testReturn hello
result=hello
aven-mac-pro-2:avenwu.github.io aven$ ./testReturn 500
result=500
aven-mac-pro-2:avenwu.github.io aven$ ./testReturn 12
result=12

echo

最后在介绍一种方法,通过echo输出,结合command substitution

这个command substitution也没有找到比较合适的翻译,姑且按字面意思翻译命令替换

如果你的方法内部只有一处echo输出,那么也可以利用她来进行值得返回,不过这个就有点局限性,一定要确保方法内只有一次输出,否则就会出现赋值内容过多。

returnString(){
local __result=$1
echo $__result
}
# 或者 result=`returnString $1`
result=$(returnString $1)
echo "result=$result"

同样可以得到预期结果

aven-mac-pro-2:avenwu.github.io aven$ ./testReturn hello
result=hello
aven-mac-pro-2:avenwu.github.io aven$ ./testReturn 500
result=500
aven-mac-pro-2:avenwu.github.io aven$ ./testReturn 12
result=12

越界问题

现在我们已经有几种办法可以返回字符串了,那么return返回数字有时候正确,有时候又不正确是为什么呢?

我们知道return原本就是用于返回执行状态的,比如0,1.那么我们在返回500的时候,实际上是数据溢出了。

根据测试,我们推断shell的内置return承接返回值用的是一个字节的大小,也就是8位,最多可以输出无符号0-255的整形,范围之外的数据全部溢出显示。因此在使用return的时候,务必留意数值大小。

小结

通过shell命令可以很方便的写出一些小脚本,但是如果遇到逻辑复杂,建议通过其他更合适的预览来实现,比如Python,Golang之类。

Shell中处理方法返回值问题的更多相关文章

  1. SpringMVC中 controller方法返回值

    1)ModelAndView @RequestMapping(value="/itemEdit") public ModelAndView itemEdit(){ //创建模型视图 ...

  2. java中的方法返回值使用泛型,实现灵活的返回值类型

    痛点:      使用Mybatis框架的时候,想封装一个底层JDBC控制器,用于提供和Mybatis交互的增删改查接口(公用的接口),但由于公用的查询方法可能是用户自定义的任意一个和表对应的java ...

  3. C#中部分方法返回值类型为什么只能是void?

    这个问题答案选至<C#入门经典> 如果方法具有返回类型,那就可以作为表达式的一部分: x=Manipulate(y,z); 如果没有给部分方法提供实现代码,编译器就会在使用该方法的所有地方 ...

  4. Spring MVC中 controller方法返回值

    1.返回ModelAndView 定义ModelAndView对象并返回,对象中可添加model数据.指定view 2.返回String 1.表示返回逻辑视图名 model对象通过 model.add ...

  5. Android onTouchEvent事件中onTouch方法返回值介绍

    1.若return false说明没有成功执行onTouch事件,在执行完onTouch里面的代码之后,onTouch事件并没有结束.因此某些组件如Gallery会自动执行它所在view里onTouc ...

  6. 060、Java中定义有返回值有参数的方法

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  7. C# 方法返回值的个数

    方法返回值类型总的来说分为值类型,引用类型,Void 有些方法显示的标出返回值 public int Add(int a,int b) { return a+b; } 有些方法隐式的返回返回值,我们可 ...

  8. 使用Result代替ResultSet作为方法返回值

    在开发过程中,我们不能将ResultSet对象作为方法的返回值,因为Connection连接一旦关闭,在此连接上的会话和在会话上的结果集也将会自动关闭,而Result对象则不会发生这种现象,所以在查询 ...

  9. SpringMVC第五篇【方法返回值、数据回显、idea下配置虚拟目录、文件上传】

    Controller方法返回值 Controller方法的返回值其实就几种类型,我们来总结一下-. void String ModelAndView redirect重定向 forward转发 数据回 ...

随机推荐

  1. java多线程开发容易犯的错误

    昨天在社区上看到有人讨论多线程使用,多线程遇到一些问题以及一些使用技巧记录一下.为什么要使用多线程, 不能是为了用而用,和设计模式一样用的合理,会让程序更易于理解,用的不合理反而会让程序变得更难理解. ...

  2. code forces 436 C. Bus

    C. Bus time limit per test 2 seconds memory limit per test 256 megabytes input standard input output ...

  3. H - Pair: normal and paranormal URAL - 2019

    If you find yourself in Nevada at an abandoned nuclear range during Halloween time, you’ll become a  ...

  4. The Worm Turns

    The Worm Turns Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...

  5. Equations

    Equations Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  6. keepalived中的脑裂

    在高可用(HA)系统中,当联系2个节点的“心跳线”断开时,本来为一整体.动作协调的HA系统,就分裂成为2个独立的个体.由于相互失去了联系,都以为是对方出了故障.两个节点上的HA软件像“裂脑人”一样,争 ...

  7. Appium python自动化测试系列之日志的收集(十二)

    ​13.1 日志的定义 13.1.1 日志的定义 听到日志这个东西可能有的人莫名其妙,第一次接触就会觉得我们为什么要收集日志,即使要收集日志那么我们需要收集哪些日志,日志的作用是什么等等. 其实日志无 ...

  8. android版火狐调试器

    Remotely debugging Firefox for Android 使用火狐开发工具可以在桌面上进行远程代码的调试(FF26以上) 具体使用参考: https://developer.moz ...

  9. Wordpress上传文件 “无法建立目录wp-content/uploads/2018/25。有没有上级目录的写权限?”

    可能的原因有两个: wp-content/uploads 文件夹权限所限制 解决方法:修改wp-content/uploads 文件夹权限,可以借助ftp等工具: wp_options表中upload ...

  10. 北京Python筛选过程中应注意什么

    计算机初级爱好者普遍喜欢Python,因为Python干净利索,简单直接.它编写代码的速度非常的快,而且非常注重代码的可读性,非常适合多人参与的项目.很多人选择了培训,那么北京Python培训筛选过程 ...