上篇我们学习了shell脚本编程中常用的一些工具,从本篇开始,我们可以尝试编写自己的脚本了。我们依次来讨论以下几个主题:
 
创建脚本文件
变量
内部整数算术运算
 
一、创建脚本文件
创建并执行
shell程序可以直接从终端上键入,如:
$who | wc –l
$
或者,也可以先把程序键入一个文件,然后由shell来执行这个文件。所要做的事情只有以下几步:
1  创建文件
2  将程序内容依次键入文件中
3  赋予该文件可以被执行的权限
下面演示创建一个shell脚本的完整过程,脚本的名字叫做nu,用于统计系统已登陆用户数。
$vi nu
who | wc –l
退出vi并保存。
$chmod +x nu
shell脚本nu就创建好了,接下来的任务就是,执行这个脚本。
$./nu
4
$
结果表明,目前有4个用户登陆到系统上。
再写一个看起来稍微复杂一点点的脚本stats。这次我们打算完成的任务是,输出当前时间、已登陆用户数、当前工作目录。
$cat stats
date
who | wc –l
pwd
$chmod +x stats
$./stats
Mon Sep 28 14:04:47 EDT 2009
4
/root/testdir
$
从上面两个脚本,我们可以得到几个结论:只要把命令一条接一条写进脚本,执行时shell就按照顺序挨个执行他们,并输出结果;执行命令的时候只要输入脚本带路径的文件名就可以了(./stats是一个相对路径)。
注释
如果没有注释,那么shell脚本是不完整的,尽管注释对脚本的执行没有影响。维护一个没有任何注释的脚本,是件很痛苦的事。哪怕脚本是维护者自己写的,一段时间以后,也不能保证能完全理解以前写的脚本。
每当shell在看到特殊字符#后,就会将其后直到行尾的内容视为注释,直接将他们忽略。如果某行以#开头,那么shell将整行视为注释内容。下面有一些例子:
$cat stats
# Here is a entire commentary line
Date
 
who | wc –l    # count the number of users
 
pwd
 
# End of script
$
额外的空行几乎不占用什么程序空间,然而可以大大增加程序的可读性,shell只是将他们忽略掉。
 
二、变量
与所有的变成语言一样,shell也允许把值存在变量中。Shell变量名以字母或下划线字
符开始,后面跟0或若干个字母、数字或下划线字符。把值存入变量(俗称赋值)的格式为:
variable=value
例如,要把数值1赋值给shell变量count,只要写
count=1
要把值/home/steve/bin赋给shell变量my_bin,只要写
my_bin=/home/steve/bin
这里有几个关键点:
1、等号的任何一边不能加空格;
2Shell没有任何数据类型的概念,shell默认将所有赋给变量的值当作字符处理。此外,shell可以根据上下文判断是字符还是数字。
显示变量的值
可以用echo命令显示变量的值:
$echo $count
1
$echo $my_bin
/home/steve/bin
$
也可以一次显示多个变量:
$echo $count $my_bin
1 /home/steve/bin
$
键入echo $count时,shell$count替换为count所存入的值,然后执行echo命令;键入echo $count $my_bin时,sehll先替换$count$my_bin的值,然后执行echo命令。
变量值可以用于命令行的任何地方,如:
$ls $my_bin
mon
nu
$
就是命令也能存在变量中:
$command=wc
$option=-l
$file=names
$$command $option $file
4 names
$
因为sehll在确定要执行的程序名及其参数之前进行替换,扫描命令行
$command $option $file
并转换成
wc –l names
然后再执行wc,并传递两个参数-lnames
空值
$echo :$nosuch:
: :
$
可以看到,shell没有把$nosuch替换成任何值,因为我们并没有给变量nosuch赋过值。如果一个变量没有值,我们就说它含有空值,这是变量还没有赋值时的默认状态。当shell进行变量替换时,任何空值都被完全从命令行中被清除,不留一点痕迹。
文件名替换和变量
如果键入
x=*
执行命令echo $x 会出现什么结果呢?我们来试试吧:
$ls
1.bak  2.bak  3.bak  urfile
$x=*
$echo $x
1.bak  2.bak  3.bak  urfile
$
替换的顺序是这样的:
x=*将符号*存入变量x中,这一步并不将文件名清单替换出来
echo $x$x替换成变量x的值,也就是*,得到echo *
echo *shell看到了*,所以先把*替换为当前目录文件名列表,再执行echo
${variable}结构
当我们键入
echo $count1
时,shell会认为我们要显示变量count1的值,还是显示变量count的值后面跟1呢?答案是显示变量count1的值。那么如果我们想要显示count的值后面跟1,应该怎么做呢?${}结构可以帮我们这个忙。看下面的例子:
$count=1
$count1=a
$echo $count1
a
$echo ${count}1
11
$
事实上,$count也可以写成${count},只不过这时的{}不是必须的。一般情况,当你引用某个变量时,其后还紧跟其他字符,这时应该用{}把变量保护起来。
 
三、内部整数算术运算
Shell有自己的执行算术运算的机制,称为算术扩展。算术扩展的格式是:
$((expression))
其中expression是由变量和运算符构成的算术表达式。下面的例子中,变量a开始是没有值的:
$echo $a
 
$echo $((a=a+1))
1
$echo $a
1
$
表达式还可以用括号来改变优先级,就像小学数学中学的那样:
echo $((i=(i+10)*j))
$a=$((a * 5))
$echo $a
5
$
有两点是需要我们注意的:1expression中的变量替换不需要再用$引用了,因为(())外面已经有$2expression中的空格是任选的,但是赋值放到小括号外的话,就不能有空格了。
expression中还可以使用不等式:
result=$(( i >= 0 && i <= 100))
如果表达式的值为真,就给result1,否则给result0
$i=$(( 100 * 200 / 10 ))
$j=$(( i < 1000 ))
$echo $i $j
2000 0
$
 
本篇就介绍到这里了,关于引用、命令替换的内容将在下一篇中介绍。