每日一SHELL (9) 函数和参数

定义函数
function fname()
{
    statements;
}

或者:

fname()
{
    statements;
}
调用函数

不带参数:

$ fname ;

带参数:

$ fname arg1 arg2 ;
读取参数
fname()
{
    echo $1, $2; # 输出访问的参数1 和参数2
    echo "$@"; # 以列表形式一次打印所有参数
    echo "$*"; # 类似于 $@,但是参数被作为单个实体

类似,在脚本里面也可以用同样的方法读取参数。

  • $0 是脚本名,也就是调用语句的第一个单词
  • $1 是第一个参数
  • $2 是第二个参数
  • $n 是第 n 个参数
  • $@ 被扩展成 $1 $2
  • $* 被扩展成 $1c$2c$3 其中 c 是环境变量 IFS 的第一个字符
  • $@ 要比 $* 常用,因为 $* 将所有参数当做单个字符串,因此很少用。
读取命令返回值
$ cmd;
$ echo $?;

$? 会给出上一个命令(cmd)的返回值

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

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

#!/bin/bash
# Filename: success_test.sh

CMD="$@"
$CMD
if [ $? -eq 0 ];
then
    echo "$CMD executed successfully"
else
    echo "$CMD terminated unsuccessfully"
fi
递归
Fib()
{
    if [ $1 -lt 1 ]; then echo "Fib($1)=0"; return 0;
    elif [ $1 -lt 3 ]; then echo "Fib($1)=1"; return 1;
    else
        local a b ans;
        Fib $(( $1 - 1 )); a=$?;
        Fib $(( $1 - 2 )); b=$?;
        ans=$(( a + b ))
        echo "Fib($1)=$ans"
        return $ans;
    fi
}

注意,这里的所有变量都是全局的,因此需要用 local 关键字进行局部变量的声明;

不过,一般而言返回值不是用于逻辑计算,输出才是,所以像上面这个函数,这样写更为合理:

Fib() {
    [ $1 -lt 1 ] && echo 0 || [ $1 -lt 3 ] && echo 1 || echo $(( $(Fib $(( $1 - 1))) + $(Fib $(( $1 - 2))) ))
}

$ Fib 2
1
$ Fib 15
610

上面这个才是斐波那契数列的笨拙递归解,下面再来写一个最大公约数:

Gcd() {
    [ $2 -eq 0 ] && echo $1 || Gcd $2 $(( $1 % $2 ))
}

$ Gcd 3 5
1
$ Gcd 12 16
4
$ Gcd 352 624
16
fork 炸弹

:(){ :|:& };:

http://en.wikipedia.org/wiki/Fork_bomb

导出函数

函数能够像环境变量一样用 export 导出,这样可以让函数的作用与扩展到子进程。

export -f name
向命令传递参数

例如我们一般调用命令的参数,有些是仅仅是可用选项,有些是带有的参数,可能会有如下方式:

  • command -p -v -k 1 file
  • command -pv -k 1 file
  • command -vpk 1 file
  • command file -pvk 1

上面的调用方式是等价的,但是如何在 command 中获取参数值,本书没有提及。

这个议题本书一笔带过,参考另文:https://www.huangwenchao.com.cn/?p=2721&preview=true


【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2015/12/bash-shell-9.html【每日一SHELL (9) 函数和参数】

发表评论

电子邮件地址不会被公开。 必填项已用*标注