转自:http://blog.csdn.net/taiyang1987912/article/details/39583179

一、简介

Linux Shell编
程中也会使用到函数,函数可以把大的命令集合分解成若干较小的任务,也避免重复编写相同的代码。在Shell中,所有的函数定义都是平行的,即不允许在函
数体内再定义其他的函数,但允许函数之间相互调用。函数又涉及到很多基本使用:函数参数调用、函数返回值、局部变量及全局变量、函数间的相互调用和函数递
归调用。

二、详解

1、函数的定义

(1)函数是一串命令的
集合,如果脚本中有重复代码时可以考虑使用函数,在shell中函数的返回值只能为退出状态0或1。应注意函数名在脚本中的唯一。可以在函数名前加上
fuction关键字也可省略。函数体中的命令集合必须含有至少一条命令(函数不允许空命令,与C不同)。

(2)脚本遇
到"hello(){"结构时,知道定义了一个名为hello的函数,而且它会记住hello代表的函数,并执行函数体中的命令,直到出现"}"字符结
束,当执行到单独的行hello时,shell就知道应该去执行刚才定义的函数,执行完毕返回继续执行其他的命令或函数。在shell中不需要申明就可直
接定义函数,但在调用函数前需对它进行定义。如下是shell脚本中循环调用函数的例子:

  1. #function2.sh
  2. #!/bin/bash
  3. output()
  4. {
  5. for(( num1 = 1; num1 <= 5; num1++ ))
  6. do
  7. echo -n "$num1 "
  8. done
  9. }
  10. let "num2=1"
  11. while [ "$num2" -le 5 ]
  12. do
  13. output
  14. echo ""
  15. let "num2=num2 + 1"
  16. done



(3)判断当前目录下存在多少个文件和子目录

  1. #显示当前目录下文件和目录数
  2. #function3.sh
  3. #!/bin/bash
  4. directory()
  5. {
  6. let "filenum = 0"
  7. let "dirnum = 0"
  8. ls
  9. echo ""                 #echo换行
  10. for file in $( ls )     #for循环判断当前子目录和文件
  11. do
  12. if [ -d $file ]     #判断为子目录
  13. then
  14. let "dirnum = dirnum + 1"
  15. else                #判断为文件
  16. let "filenum = filenum + 1"
  17. fi
  18. done
  19. echo "The number of directory is $dirnum"
  20. echo "The number of file is $filenum"
  21. }
  22. directory                  #在脚本中调用函数

2、向函数传递参数

shell中,向函数传递的参数仍然是以位置参数的方式来传递的,而不能传递数组等其他形式变量(与c不同)。利用函数参数的传递实现两数的四则运算。

  1. #用于实现两数加、减、乘和除四则运算
  2. #!/bin/bash
  3. count()
  4. {
  5. if [ $# -ne 3 ]             #3个参数,一个运算符两个数值
  6. then
  7. echo "The  number of arguments is not 3! "
  8. fi
  9. let "s = 0"
  10. case $2 in
  11. +)                          #加法
  12. let "s = $1 + $3"
  13. echo "$1 + $3 = $s";;
  14. -)                          #减法
  15. let "s = $1 - $3"
  16. echo "$1 - $3 = $s";;
  17. \*)                         #乘法
  18. let "s = $1 * $3"
  19. echo "$1 * $3 = $s";;
  20. \/)                        #除法-取余,浮点数运算使用bc
  21. let "s = $1 / $3"
  22. echo "$1 / $3 = $s";;
  23. *)                          #其他
  24. echo "What you input is wrong!";;
  25. esac
  26. }
  27. echo "Please type your word: ( e.g. 1 + 1 )"
  28. read a b c
  29. count $a $b $c

3、函数返回值

有时需要函数执行完成后返回特定的值来完成脚本的后续操作。函数通过return返回退出状态,0表示true无错误,非0表示false有错误(与C不同)。

  1. #根据用户输入显示星期
  2. #!/bin/bash
  3. show_week()
  4. {
  5. echo -n "What you input is: "
  6. echo "$1"
  7. case $1 in
  8. 0)
  9. echo "Today is Sunday. "
  10. return 0;;
  11. 1)
  12. echo "Today is Monday. "
  13. return 0;;
  14. 2)
  15. echo "Today is Tuesday. "
  16. return 0;;
  17. 3)
  18. echo "Today is Wednesday. "
  19. return 0;;
  20. 4)
  21. echo "Today is Thursday. "
  22. return 0;;
  23. 5)
  24. echo "Today is Friday. "
  25. return 0;;
  26. 6)
  27. echo "Today is Saturday. "
  28. return 0;;
  29. *)
  30. return 1;;
  31. esac
  32. }
  33. #if show_week "$1"          #返回0表示函数输入的命令行参数是正确的
  34. #也可以通过$?来获取函数执行的返回值
  35. show_week "$1"
  36. if [ $? -eq 0 ]
  37. then
  38. echo "What you input is right! "
  39. else
  40. echo "What you input is wrong! "
  41. fi
  42. exit 0

4、函数调用

shell脚本中可以同时放置多个函数,函数之间允许相互调用,而且允许一个函数调用多个函数。

  1. #用于显示一个不多于5位的正整数的位数,并按顺序显示各个数位的值
  2. #!/bin/bash
  3. count_of_int()
  4. {
  5. if [ $1 -gt 9999 ]
  6. then
  7. let "place=5"         #5位数
  8. elif [ $1 -gt 999 ]
  9. then
  10. let "place=4"
  11. elif [ $1 -gt 99 ]
  12. then
  13. let "place=3"
  14. elif [ $1 -gt 9 ]
  15. then
  16. let "place=2"
  17. else
  18. let "place=1"         #1位数
  19. fi
  20. echo "The place of the $1 is $place."      #整数的位数
  21. }
  22. num_of_int()
  23. {
  24. let "ten_thousand = $1/10000"           #整数的数位分解值
  25. let "thousand =$1/1000%10"
  26. let "hundred = $1/100%10"
  27. let "ten = $1%100/10"
  28. let "indiv = $1%10"
  29. if [ $ten_thousand -ne 0 ]
  30. then
  31. echo "$ten_thousand  $thousand  $hundred  $ten  $indiv"
  32. elif [ $thousand -ne 0 ]
  33. then
  34. echo "$thousand  $hundred  $ten  $indiv"
  35. elif [ $hundred -ne 0 ]
  36. then
  37. echo "$hundred  $ten  $indiv"
  38. elif [ $ten -ne 0 ]
  39. then
  40. echo "$ten  $indiv"
  41. else
  42. echo "$indiv"
  43. fi
  44. }
  45. show()
  46. {
  47. echo "Please input the number(1-99999): "
  48. read num
  49. count_of_int $num
  50. num_of_int $num
  51. }
  52. show

执行脚本,输入整数2014,该数是四位数,千位是2,百位是0,十位是1,个位是4。

5、函数中局部和全局变量

shell中,可以通过local关键字来申明局部变量,局部变量将局限在函数范围内。函数可调用函数外的全局变量,若一个局部变量和一个全局变量的名字相同,则在函数中局部变量会覆盖掉全局变量。

  1. #!/bin/bash
  2. text="global variable"
  3. use_local_var_fun()
  4. {
  5. local text="local variable"          #local声明为局部变量,否则会修改全局text的值
  6. echo "in function------"$text        #暂时覆盖掉全局变量的值
  7. }
  8. use_local_var_fun
  9. echo "Out of function------"$text        #text的值为开始定义的值
  10. exit 0

6、函数递归

(1)shell中执行递归函数可以直接或间接地反复调用其自身,每调用一层就进入新的一层,主调函数又是被调函数。

(2)使用局部变量进行递归实现阶乘运算,也可采用递推法实现。

  1. #阶乘运算,当n=0时 0!=1,当n>=1时n!=n*(n-1)!
  2. #!/bin/bash
  3. fact ()
  4. {
  5. local num=$1         #函数需将先前的局部值进行逐个还原,故设置成局部的变量
  6. echo $num
  7. if [ "$num" -eq 0 ]
  8. then
  9. factorial=1
  10. else
  11. let "decnum=num-1"
  12. fact $decnum
  13. let "factorial=$num * $?"
  14. fi
  15. return $factorial
  16. }
  17. fact $1
  18. echo "Factorial of $1 is $?"
  19. exit 0

(3)递归实现汉诺塔的问题(不使用局部变量的递归)

  1. #汉诺塔算法
  2. #!/bin/bash
  3. move=0
  4. dohanoi()
  5. {
  6. if [ $1 -eq 0 ]
  7. then
  8. echo ""
  9. else
  10. dohanoi "$(($1-1))" $2 $4 $3
  11. echo "move $2 ----> $3"
  12. let "move=move+1"
  13. dohanoi "$(($1-1))" $4 $3 $2
  14. fi
  15. if [ $# -eq 1 ]
  16. then
  17. if [ "$(( $1 > 1 ))" -eq 1 ]
  18. then
  19. dohanoi $1 A C B
  20. echo "Total moves  = $move"
  21. else
  22. echo "The number of disk which you input is illegal! "
  23. fi
  24. fi
  25. }
  26. echo "Please input the num of disk:"
  27. read num
  28. dohanoi $num 'A' 'B' 'C'

三、总结

(1)函数间的相会调用增加了shell编程的灵活性和代码的可重用性,对脚本语言来说很是实用。

(2)函数的递归调用应进一步理解,阶乘和汉诺塔的实现可逐步分析。

(3)通过函数可以封装自己的函数库,减少以后开发的难度并使用代码的可重复性

shell浅谈之十函数的更多相关文章

  1. shell浅谈之九子shell与进程处理

    转自:http://blog.csdn.net/taiyang1987912/article/details/39529291 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] ...

  2. 浅谈 es6 箭头函数, reduce函数介绍

    今天来谈一下箭头函数, es6的新特性 首先我们来看下箭头函数长什么样子, let result = (param1, param2) => param1+param2; 上述代码 按照以前书写 ...

  3. 浅谈js回调函数

    回调函数原理: 我现在出发,到了通知你”这是一个异步的流程,“我出发”这个过程中(函数执行),“你”可以去做任何事,“到了”(函数执行完毕)“通知你”(回调)进行之后的流程 例子 1.基本方法 ? 1 ...

  4. 浅谈JSON.stringify 函数与toJosn函数和Json.parse函数

    JSON.stringify 函数 (JavaScript) 语法:JSON.stringify(value [, replacer] [, space]) 将 JavaScript 值转换为 Jav ...

  5. 浅谈JavaScript eval() 函数

    用js的人都应该知道eval()函数吧,虽然该函数用的极少,但它却功能强大,那么问题来了,为什么不常用呢?原因很简单,因为eval()函数是动态的执行其中的字符串,里面有可能是脚本,那么这样的话就有可 ...

  6. 浅谈C++虚函数

    很长时间都没写过博客了,主要是还没有养成思考总结的习惯,今天来一发. 我是重度拖延症患者,本来这篇总结应该是早就应该写下来的. 一.虚函数表 C++虚函数的机制想必大家都清楚了.不清楚的同学请参看各种 ...

  7. Qt浅谈之四十九俄罗斯方块(代码来自网络)

    一.简介 从网上下载了一个Qt实现的俄罗斯方块单机版的源码,觉得非常有意思,故以博客形式记录下来,以便慢慢来研究.在centos6.6下编译运行(注意程序运行需要读取pro目录的配置文件,若把编译目录 ...

  8. Qt浅谈之四十五QSplitter实现自由伸缩滑动窗口

    一.简介 最近看到一篇Qt实现伸缩滑动的窗口的文章,但其代码不完整.便在此重新书写了完整的代码,并开源出来.窗口的中央有滑动条可以动态改变子窗口的大小,隐藏的按钮可以快速伸缩子窗口.其效果图如下: 二 ...

  9. 浅谈JavaScript匿名函数与闭包

    一. 匿名函数   //普通函数定义: //单独的匿名函数是无法运行的.就算运行了,也无法调用,因为没有名称. 如: function(){             alert('123');    ...

随机推荐

  1. 【Swift】 应用内显示 AppStore 某个应用的详情

    前言 应用内跳转到 AppStore 的文章很多,一般都是用 SKStoreProductViewController 来实现的,不知道有没有在意一个问题:打开很慢!!怎么忍?! 声明 欢迎转载,但请 ...

  2. 【原】Github系列之三:开源iOS下 渐变颜色的进度条WGradientProgress

    概述 今天我们来实现一个iOS平台上的进度条(progress bar or progress view).这种进度条比APPLE自带的更加漂亮,更加有“B格”.它拥有渐变的颜色,而且这种颜色是动态移 ...

  3. 敏捷开发与jira之流程

    敏捷流程在Jira中的运用

  4. Session 失效原因

    转载http://blog.csdn.net/LLorJJ999/article/details/4107464 昨天去GTSC面试,有面试官问我关于Session丢失之后怎么查的问题,说老实话,开发 ...

  5. C语言的泛型编程

    1 问题引入 首先引入一个问题,实现一个泛型的swap函数,分别使用C++和C实现. 2 C++的泛型 C++有良好的泛型编程机制,所以我很快就写出了C++版的泛型swap函数. template&l ...

  6. SLF4j:Log facade abstract

    内 容: 应用中使用slf4j的工作流程 简单示例 ILoggerFactory实例化过程 由ILoggerFactory创建Logger实例 slf4j 适配器实现 自定义适配器 slf4j 如何选 ...

  7. MYSQL复制

    今天我们聊聊复制,复制对于mysql的重要性不言而喻,mysql集群的负载均衡,读写分离和高可用都是基于复制实现.下文主要从4个方面展开,mysql的异步复制,半同步复制和并行复制,最后会简单聊下第三 ...

  8. asp.net signalR 专题—— 第三篇 如何从外部线程访问 PersistentConnection

    在前面的两篇文章中,我们讲到的都是如何将消息从server推向client,又或者是client再推向server,貌似这样的逻辑没什么异常,但是放在真实 的环境中,你会很快发现有一个新需求,如何根据 ...

  9. Mysql时间类型处理

    关于Mysql中时间的处理 最近在读<人类简史>,读第二遍.只有晚上睡觉之前读一点点,有时候觉得一天可以抽出一个专门的时间来看书了,效率应该能高不少. 另外分享个网址可以随心创作 这里有一 ...

  10. Linux 服务器模型小结

    当我们用socket进行编程的时候,细节上都是选择一个AF_LOCAL,AF_INET再根据相应的类型填充地址,其实根据通信需求,有几种简单的服务模型可供选用,掌握了这些框架再结合socket高度的抽 ...