1.11 函数和参数

和其他脚本语言一样,Bash同样支持函数。让我们看看它是如何定义和使用函数的。

1.11.1 实战演练

定义函数:

  1. function fname()
  2. {
  3. statements;
  4. }

或者

  1. fname()
  2. {
  3. statements;
  4. }

只需要使用函数名就可以调用某个函数:

  1. $ fname ; # 执行函数

参数可以传递给函数,并由脚本进行访问:

  1. fname arg1 arg2 ; # 传递参数

以下是函数fname的定义。在函数fname中,包含了各种访问函数参数的方法。

  1. fname()
  2. {
  3. echo $1, $2; # 访问参数1和参数2
  4. echo "$@"; # 以列表的方式一次性打印所有参数
  5. echo "$*"; # 类似于$@,但是参数被作为单个实体
  6. return 0; # 返回值
  7. }

类似地,参数可以传递给脚本并通过script:$0(脚本名)访问。

  • $1是第一个参数。

  • $2是第二个参数。

  • $n是第n个参数。

  • "$@" 被扩展成 "$1" "$2" "$3"等。

  • "$*" 被扩展成 "$1c$2c$3",其中c是IFS的第一个字符。

  • "$@" 用得最多。由于 "$*"将所有的参数当做单个字符串,因此它很少被使用。

1.11.2 补充内容

让我们再研究Bash函数的一些技巧。

  • 递归函数

在Bash中,函数同样支持递归(可以调用自身的函数)。例如,F() { echo $1; F hello; sleep 1; }

1.11 函数和参数 - 图1 Fork炸弹

  1. :(){ :|:& };:

这个递归函数能够调用自身,不断地生成新的进程,最终造成拒绝服务攻击。函数调用前的 & 将子进程放入后台。这段危险的代码会分支出大量的进程,因而被称为Fork炸弹。

上面这段代码要理解起来可不容易。请参阅维基百科http://en.wikipedia.org/wiki/Fork_bomb,那里列出了有关Fork炸弹的细节以及更详细的解释。

可以通过修改配置文件/etc/security/limits.conf来限制可生成的最大进程数来避开这枚炸弹。

  • 导出函数

函数也能像环境变量一样用export导出,如此一来,函数的作用域就可以扩展到子进程中,如下:

  1. export -f fname
  • 读取命令返回值(状态)

我们可以按照下面的方式获取命令或函数的返回值:

  1. cmd;
  2. echo $?;

$? 会给出命令cmd的返回值。

返回值被称为退出状态。它可用于分析命令执行成功与否。如果命令成功退出,那么退出状态为0,否则为非0。

我们可以按照下面的方法检测某个命令是否成功结束:

  1. #!/bin/bash
  2. #文件名: success_test.sh
  3. CMD="command" # command指代你要检测退出状态的目标命令
  4. status
  5. $CMD
  6. if [ $? -eq 0 ];
  7. then
  8. echo "$CMD executed successfully"
  9. else
  10. echo "$CMD terminated unsuccessfully"
  11. fi
  • 向命令传递参数

命令的参数能够以不同的格式进行传递。假设-p-v是可用选项,-k NO是另一个可以接受数字的选项,同时该命令还接受一个文件名作为参数,那么,它有如下几种执行方式:

  1. $ command -p -v -k 1 file

或者

  1. $ command -pv -k 1 file

或者

  1. $ command -vpk 1 file

或者

  1. $ command file -pvk 1