函数介绍
  定义:把一段独立功能的的代码当做一个整体,并为之一个名字,命名的代码段,此即为函数;
  功能:函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程。
  注意:定义函数的代码段不会自动执行,在调用时执行;所谓函数调用,就在代码中给定函数名称即可;函数名出现的任何位置,在代码执行时,都会被自动替换为函数代码;

函数和shell程序比较相似,区别在于:
  Shell程序在子Shell中运行,而函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改;
  它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。

函数语法和使用
  语法:函数由两部分组成函数名和函数体。
  语法一:
  function f_name {
  ...函数体...
 }
  语法二:
 f_name() {
  ...函数体...
  }

函数的定义和使用:
  可在交互式环境下定义函数
  可将函数放在脚本文件中作为它的一部分(自己定义自己用)
  可放在只包含函数的单独文件中
  函数调用:函数只有被调用才会执行
  调用方法:在代码中给定函数名称,函数名出现的地方,会被自动替换为函数代码
  函数的生命周期:被调用时创建,返回时终止

函数的两种返回值
  函数的执行结果返回值:使用echo或printf命令进行输出;函数体中调用命令的输出结果
  函数的退出状态码:其状态返回结果为函数中执行的最后一条命令的状态结果
  自定义退出状态码:return
  return [0-255] :从函数中返回,用最后状态命令决定返回值
    0:成功,无错误返回
    1-255:失败,有错误返回

示例:给定一个用户名,显示其用户名,id和默认的shell
#!/bin/bash
#
userinfo() {
  if id $username &> /dev/null; then
    getent passwd $username| cut -d: -f1,3,7
  else
    echo "No such user"
fi
}

[ $# -lt 1 ] && echo "At least one username." && exit 2

username=$1
userinfo

username=$2
userinfo

示例:以函数的方式改写服务框架脚本
#!/bin/bash
#
#chkconfig: - 50 50
#description: test service scipt
#

prong=$(basename $0)
lockfile=/var/lock/subsys/$prong

start() {
  if [ -f $lockfile ];then
    echo "$prong is running yet."
  else
    touch $lockfile
    [ $? -eq 0 ] && echo "start $prong finished."
  fi
}
stop() {
  if [ -f $lockfile ];then
    rm -f $lockfile
    [ $? -eq 0 ] && echo "stop $prong finished."
  else
    echo "$prong is not running."
  fi
}
status() {
  if [ -f $lockfile ];then
    echo "$prong is running"
  else
    echo "$prong is stopped"
  fi
}

usage() {
  echo "Usage: $prong {start|stop|restart|status}"
}

case $1 in
start)
  start
  ;;
stop)
  stop
  ;;
restart)
  stop
  start
  ;;
status)
  status
  ;;
*)
  usage
  exit 1
esac

函数定义及用法详述
  函数可以定义在三个场景:交互环境下、脚本中 、单独的函数文件
  1、交互环境下定义和使用函数:
  示例:键入函数名,注意左大括号和函数体之间需要有空格。这里要注意优先级,如果函数名和定义的别名、内部命令外部命令同名,优先级为:别名>函数>内部命令>外部命令;以该方法定义的函数将一直保留到用户从系统退出,或执行了unset命令:
[root@centos7 function]# fun() { who; hostname ;}
[root@centos7 function]# fun
root pts/0 2017-03-02 09:39 (192.168.1.101)
centos7

2、在脚本文件中定义和使用函数
  方法:函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用;调用函数仅使用其函数名即可。
  注意:在脚本中的函数在外面是用不了的,因为不在同一个shell中,运行脚本是开了一个子shell,而在外面是父shell。
示例:
#!/bin/bash
#

fun1() {
  echo "this is fun1"
}

echo "fun1 before"
fun1
echo "fun1 after"

# 执行结果如下:
[root@centos7 function]# bash test1.sh
fun1 before
this is fun1 # 函数只有在被调用才会执行
fun1 after

3、使用函数文件定义函数
  可以将经常使用的函数存入函数文件,然后将函数文件载入shell。文件名可任意选取,但最好与相关任务有某种联系。例如:functions.main
  一旦函数文件载入(source或.)shell,就可以在命令行或脚本中调用函数。可以使用set命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数。若要改动函数,首先用unset命令从shell中删除函数。改动完毕后,再重新载入此文件

  函数文件载入shell的格式:
    . /PATH/TO/SOMEFILE或者source /PATH/TO/SOMEFILE

  查看是否载入:
    用source或 . 载入shell后,可使用set命令检查函数是否已载入。set命令将在shell中显示所有的载入函数
    
  删除shell函数:
    现在对函数做一些改动。首先删除函数,使其对shell不可用。使用unset命令完成此功能。
    命令格式为:unset function_name

  在脚本中载入函数:在脚本中使用函数,只要source FILES或者. FILE(存放函数的文件),就可以载入到当前shell当中,调用函数了。
 注意:
  1、Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改;
  2、当函数载入到当前环境中或脚本中时,当前环境或者脚本中定义的变量会和函数中定义的变量起冲突,这是因为,我们在当前环境中或者脚本中定义的为本地变量,函数载入当前shell之后,其实就是当前shell的一部分,所以定义的本地变量对其也有效。为了避免这种冲突,函数要使用局部变量。

示例:
1、首先创建一个函数文件,此函数文件中可以存放多个函数;
[root@centos7 function]# cat funs
#!/bin/bash
#

fun1() {
  echo "This is fun1"
}

fun2() {
  echo "This is fun2"
}
2、在当前shell中要想调用此函数,要使用 source 或者 . 加载到当前shell 中方可
# 直接调用,bash(相当于开了一个子shell)都不行
[root@centos7 ~]# fun1
-bash: fun1: 未找到命令

[root@centos7 ~]# bash fun1 # 相当于
bash: fun1: 没有那个文件或目录

# source 加载到当前shell
[root@centos7 ~]# source /root/bin/function/funs
[root@centos7 ~]# fun1
This is fun1
[root@centos7 ~]# fun2
This is fun2

# 删除shell函数,再执行就没有了
[root@centos7 ~]# unset fun1
[root@centos7 ~]# fun1
-bash: fun1: 未找到命令
[root@centos7 ~]# fun2
This is fun2
[root@centos7 ~]# unset fun2
[root@centos7 ~]# fun2
-bash: fun2: 未找到命令
3、在脚本中使用函数,只要source FILES或者. FILE(存放函数的文件),就可以载入到当前shell当中,调用函数了。
[root@centos7 function]# cat test2.sh
#!/bin/bash
#
source /root/bin/function/funs
fun1
echo "taotao"
fun2

# 执行结果如下:
[root@centos7 function]# fun1
-bash: fun1: 未找到命令 # 在当前shell中不能使用,因为脚本为子shell,当前环境为父shell
[root@centos7 function]# fun2
-bash: fun2: 未找到命令

[root@centos7 function]# bash test2.sh
This is fun1
taotao # 调用函数成功
This is fun2

函数参数:
  函数可以接受参数:
    传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如"testfunc arg1 arg2 ..."
    在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*, $#等特殊变量

示例1:
1、添加10个用户,(添加用户的功能使用函数实现),用户名作为参数传递给函数
[root@centos7 function]# cat useradd.sh
#!/bin/bash
#
addusers () {
  if id $1 &> /dev/null; then
    return 5
  else
    useradd $1
    retval=$? # 表示函数的状态返回值,这里如果添加成功则为0
    return $retval #
  fi
}

for i in {1..10};do
  addusers ${1}${i} # $1 为脚本传递的参数变量,$i 为循环体中i的变量
  renum=$? # 这里的状态返回值取决于函数中 return 的值,为0,表示添加成功,为5表示用户存在
  if [[ "$renum" -eq 5 ]];then
    echo "user ${1}${i} exits."
  elif [[ "$renum" -eq 0 ]];then
    echo "Add user ${1}${i} successd."
  else
    echo "Unknow Error."
  fi
done

函数变量:
  变量的作用域:
  环境变量:当前shell和子shell有效
  本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数
  局部变量:作用域是函数的生命周期;函数结束时变量被自动销毁

在函数中定义局部变量的方法:
  local NAME=VALUE

注意:
  函数中也可调用本地变量,如果函数中定义的变量名称和本地变量相同,函数调用之后会覆盖本地变量的值;为了避免和本地变量相冲突,使之互不干扰,所以在函数中使用的变量要使用局部变量

示例:
1、在函数中定义的本地变量和脚本中定义的本地变量名相同,但值不同的执行结果;
[root@centos7 function]# cat test.sh
#!/bin/bash
#

setname() {
  name=jerry
  echo "Function:$name"
}

name=tom
echo "Fun before:$name"
setname
echo "Fun after:$name"

#执行结果,可以发现 函数中定义的变量覆盖了脚本中定义的变量,
[root@centos7 function]# bash test.sh
Fun before:tom # 脚本执行前为本地变量
Function:jerry # 调用函数,函数也会调用本地变量,并再次给其赋值
Fun after:jerry # 脚本中定义的变量被函数中定义的变量覆盖

2、在函数中定义局部变量,和脚本中定义本地变量但值不同的结果:
[root@centos7 function]# cat test.sh
#!/bin/bash
#

setname() {
  local name=jerry
  echo "Function:$name"
}

name=tom
echo "Fun before:$name"
setname
echo "Fun after:$name"

#执行结果如下:
[root@centos7 function]# bash test.sh
Fun before:tom
Function:jerry
Fun after:tom
结论:
  如果函数中有局部变量,如果其名称同本地变量,使用局部变量。否则,函数执行之后会把当前shell中定义的相同的变量覆盖。
  定义的局部变量只是在函数内部使用,互不干扰;如果不加local就是本地变量了。
函数递归:

函数递归:
  函数直接或间接调用自身
  递归实例(阶乘):
  阶乘是所有小于及等于该数的正整数的积,0的阶乘为1,自然数n的阶乘写作n!。
  阶乘亦可以递归方式定义:
    n! = n(n-1)! = n(n-1)(n-2)! = n(n-1)(n-2)(n-3)...1
    0! = 1
    
示例1:给定一个正整数,求其阶乘:
[root@centos7 function]# cat jiecheng.sh
#!/bin/bash
#

fab() {
  if [ $1 -eq 0 -o $1 -eq 1 ];then
    echo 1
  else
    echo $[$1*$(fab $[$1-1])]
  fi
}

fab $1

#执行结果如下:
[root@centos7 function]# bash jiecheng.sh 2
2
[root@centos7 function]# bash jiecheng.sh 5
120
[root@centos7 function]# bash jiecheng.sh 3
6

Linux Shell脚本编程-函数的更多相关文章

  1. Linux shell脚本编程(三)

    Linux shell脚本编程 流程控制: 循环语句:for,while,until while循环: while CONDITION; do 循环体 done 进入条件:当CONDITION为“真” ...

  2. Linux shell脚本编程(一)

    Linux shell脚本编程: 守护进程,服务进程:启动?开机时自动启动: 交互式进程:shell应用程序 广义:GUI,CLI GUI: CLI: 词法分析:命令,选项,参数 内建命令: 外部命令 ...

  3. Linux shell脚本编程(二)

    Linux shell脚本编程(二) 练习:求100以内所有偶数之和; 使用至少三种方法实现; 示例1: #!/bin/bash # declare -i sum=0 #声明一个变量求和,初始值为0 ...

  4. Linux Shell脚本编程--Linux特殊符号大全

    Linux Shell脚本编程--Linux特殊符号大全 linux_shell 特殊符号的介绍 2011

  5. Linux Shell脚本编程while语句

    Linux Shell脚本编程while语句案例 1,每隔3秒,打印一次系统负载 #!/bin/bash while truedo    uptime    sleep 3done 2,把监控结果保存 ...

  6. Linux Shell脚本编程-基础1

    概述:  shell脚本在Linux系统管理员的运维工作中非常重要.shell脚本能够帮助我们很方便的管理服务器,因为我们可以指定一个任务计划,定时的去执行某一个脚本以满足我们的需求.本篇将从编程基础 ...

  7. 【学习】Linux Shell脚本编程

    1.脚本的组成和执行 Linux shell脚本的结构并不复杂,其主要由变量.内部命令以及shell的语法结构和一些函数.其他命令行的程序等组成,以下是一个简单的shell脚本. #!/bin/bas ...

  8. Linux shell脚本编程基础之练习篇

    shell脚本编程基础之练习篇. 1.编写一个脚本使我们在写一个脚本时自动生成”#!/bin/bash”这一行和注释信息. #!/bin/bash ] then echo "请输入一个参数& ...

  9. [linux] shell脚本编程-xunsearch安装脚本学习

    安装脚本setup.sh #!/bin/sh # FULL fast install/upgrade script # See help message via `--help' # $Id$ # s ...

随机推荐

  1. 51nod 1179 最大的最大公约数 (打表计数法)

    题目: 考虑清楚就简单了,我们把每个数的因子计数. 两个数的公约数就是计数超过2的数,然后找到最大的那个就好了. 计算每个数的素因子,记得sqrt(),不然会超时. 打表计数法时间复杂度O(n*sqr ...

  2. jquery.gritter 提示

    首先引入css和js文件 <link rel="stylesheet" href="<%=basePath%>assets/css/jquery.gri ...

  3. jQuery学习(八)——使用JQ插件validation进行表单校验

    1.官网下载:http://bassistance.de/jquery-plugins/jquery-plugin-validation/ 目录结构: 2.引入jquery库和validation插件 ...

  4. hiho1041 - 树,遍历

    题目链接 给一棵树,给一个序列,问能不能按这个序列遍历这棵树,满足每条边最多经过两次. -------------------------------------------------------- ...

  5. QT笔记 -- (2) 文件相关操作、中文路径乱码

    1.显示文件对话框,选择一个目录,显示选中目录中的所有图片的代码如下 主要class: QFileDialog QStringList QFileInfoList QDir void open(){ ...

  6. php 添加redis扩展

    我主要是按照http://blog.163.com/fan_xy_qingyuan/blog/static/1889877482014111111283265/ 这篇博客来的,但是这篇博客里只有php ...

  7. iOS开发者中心重置设备列表

    苹果开发者账号允许的测试设备为100台,如果你注册了,这台机器就算是一个名额,禁用也算一个名额,仍被计入机器总数,每年可以重置一次,那我们怎么重置机器数量呢? 我们需要给苹果发送申请: https:/ ...

  8. Hadoop-2.4.1 ubuntu集群安装配置教程

    一.环境 系统: Ubuntu 14.04 32bit Hadoop版本: Hadoop 2.4.1 (stable) JDK版本: 1.7 集群数量:3台 注意事项:我们从Apache官方网站下载的 ...

  9. BZOJ 2246 [SDOI2011]迷宫探险 (记忆化搜索)

    题目大意:太长了,略 bzoj luogu 并没有想到三进制状压 题解: 3进制状压陷阱的状态,0表示这种陷阱的状态未知,1已知危险,2已知不危险 然后预处理出在当前状态下,每种陷阱有害的概率,设为$ ...

  10. Solr全文检索引擎配置及使用方法

    介绍 Solr是一款开源的全文检索引擎,基于lucene.拥有完善的可配置功能界面.具有丰富的查询语言,可扩展,可优化. 下载安装 进入solr官网下载包(这里我使用的版本是8.0) http://w ...