-----------

由于Bash的易于编程等特点,是众多Shell中比较常用的一种。

Bash命令行参数

在使用wget的时候,我喜欢加上一个-c的参数,这样可以让wget启用断点续传功能。这里的-c就是一个命令行参数。

在写c语言的时候,我们使用字符串数组存储命令行参数,像我们所熟悉的argv[]。当然我们也需要命令行参数的个数,这存储在名为argc的整型变量中。argc和argv是约定俗成的名称,当然你可以使用自己的名称作为main函数的形参。

在编写Bash脚本的时候,也同样可以使用命令行参数。在Bash函数中也可以使用参数,特殊的是,Bash中的函数是没有参数列表的,例如

function foo

这样便完成了一个函数头的定义,但是没有任何的形参名称,这是由于Bash中特殊的参数传递方法所致。
这里需要说明的是,在Bash编程中命令行参数和函数的形参都采用统一的规则。

Bash的函数规则

在Bash中,所有变量在赋值是赋值号左侧直接写变量名。而在引用变量的值时,变量名的左侧需要加上$符号。写过PHP脚本可能对此深有印象,不过PHP是赋值和引用都要写。

Bash的参数是按照位置传递的,而且自动给出变量名称,例如$1就表示第一个参数,当然$2就是第二个参数,参数之间用空格区分。这样你可以顺序写到$n(n表示一个正整数),有几个参数都可以按照顺序引用。

$0表示当前运行命令的名称,这个其实是特殊的参数,但是往往很少用到。

如果你想得到参数的个数,它保存在一个特殊名称的变量里,叫做$#。

$*和$@表示所有的参数,具体区别和其他一些特殊参数请见这里

注:后面我们会用到一个$?参数,这表示上一条独立命令运行的结果。我们才c语言写程序的时候,常常以return 0作为程序正常退出的标志,这个0就被返回给Bash,而$?可以引用到上一个程序运行的结果。还记得Bash函数的参数和命令行参数是相同的吗?如果刚刚执行完一个Bash函数,$?里就保存着这个函数的运行结果,即return的值。

Bash的返回值

通常情况下Bash的函数是很少需要返回值的,但是有的时候需要,比如确定一个函数是否被成功执行,然后确定下一步的动作。这样的逻辑必须得到Bash函数的返回值,用以表示函数执行的状态。

在变写脚本时就遇到了这种需要,经过Google,获得两篇比较好的帖子:
英文:http://mail.linux.ie/pipermail/ilug/2008-March/097416.html (是一个邮件列表的邮件)
中文:http://blog.morebits.org/?p=83 (这里是一篇博文)

里面总结了5中Bash返回值的HACK方法:
1. 使用return返回(适用于数值)

myfun() {
 return $(( 5 + 1 )); 
}
 myfun
 RESULTS=$?
 echo $RESULTS

这里的$?保存着函数运行的结果。

2. 使用echo(用echo返回结果,同样适用于数值)

myfun() {
 echo $(( 5 + 1 ));
}
RESULTS=$(myfun)
echo $RESULTS

3. 近似全局变量的用法

myfun() {
 foo=$(( 5 + 1 )); 
}
myfun
RESULTS=$foo
echo $RESULTS

这里的$foo充当了全局变量的角色,将返回值从函数内带到函数外。

4. 使用地址传递参数

myfun() {
 eval $1="\$(( 5 + 1 ))"; 
}
myfun RESULTS
echo $RESULTS

这里使用了一个函数参数$1带出返回值,这个方法非常类似与C++中的引用和C中的参数传址。从一个侧面反应了Bash在参数传递的时候应该都是传递的内存地址。

5. 使用地址传递(适用于数值)

myfun() {
 let $1=5+1; 
}
myfun RESULTS
echo $RESULTS

当然,以上这些方法可以单独使用,也可以结合使用。比如可以将传址和使用echo的方法结合起来:
function myfunc()
 {
 local  __resultvar=$1
 local  myresult='some value' 
 if [[ "$__resultvar" ]]; then
 eval $__resultvar="'$myresult'" 
 else 
 echo "$myresult"
 fi 
}   
myfunc result 
echo $result 
result2=$(myfunc) 
echo $result2
这样使用可以提供最大的灵活性。