shell程序设计
一、shell脚本的编写与执行
- 建立shell脚本
建立shell脚本的步骤同建立普通文本文件的方式相同,如:vi sh01.sh
- 执行shell脚本的方式
执行shell脚本的常用方式基本上有两种:
(1)以脚本名作为参数。其一般形式是:
$ bash 脚本名 [参数]
或sh 脚本名[参数]
(2)将shell脚本的权限设置为可执行,然后在提示符下直接执行它。
$ chmod u+x ex
$ PATH=$PATH:.
$ ex 或者 $ ./ex
二、shell变量
-
shell变量类型
局部变量:只存在于创建它的shell中
环境变量:由子shell继承 -
shell变量使用
用$
字符来解析变量,例如:echo $A
变量赋值:A=apple
变量命名:由字母数字字符和下划线组成的任意字符串,但是不能以数字开头,区分大小写。一般为大写
取消变量:unset A
-
环境变量
无论何时一个进程启动另一个进程时,子进程都会继承环境变量;
环境变量的创建:创建一个shell变量,然后用export将其转化为环境变量。
Bash环境变量实例如下:
-
列出变量
set命令:没有参数,列出shell变量和与shell有关的环境变量;
env命令:没有参数,列出已经被导出成为环境变量的变量。 -
预先定义的特殊变量
⑴$#
——除脚本名外,命令行上参数的个数。
⑵$?
——上一条前台命令执行后的返回值(也称“退出码”等)。
⑶$$
——当前进程的进程号。
⑷$!
——上一个后台命令对应的进程号。
⑸$*
——表示在命令行上实际给出的所有实参。
⑹$@
——它与$*
基本功能相同。 -
常用环境变量
(1)HOME:用户主目录的全路径名。如/home/myname
(2)LOGNAME:即用户注册名
(3)PWD:当前工作目录的路径。
(4)PATH:shell查找命令的路径(目录)列表,各个目录用冒号(:)隔开。用户可以设置它:$ PATH=$PATH:$PWD
(5)PS1:shell的主提示符。$ PS1="$LOGNAME> "
(6)SHELL:当前使用的shell。通常,它的值是/bin/bash。
(7)TERM:终端类型。
(8)MAIL:系统信箱的路径。
三、程序控制结构
3.1 分支
3.1.1 if语句
-
一般格式为:
if 测试条件 then 命令1 else 命令2 fi
-
if语句中,else部分可以缺省。例如:
if test -f "$1" then echo "$1 is an ordinary file . " fi
-
if 语句的else部分还可以是else-if结构,例如:
if test - f "$1" then pr $1 elif test - d "$1" then ( cd $1 ; pr * ) else echo "$1 is neither a file nor a directory ." fi
-
条件测试
条件测试有三种常用形式:
①用test命令,如:test -f " $1 "
;
②用一对方括号将测试条件括起来,如:[ -f “$1” ]
(左括号后和右括号前都有空格),和第一种等价;
③用[[条件表达式]]
的形式; -
有关文件方面的测试
参数 说明 -e 文件名 如果文件存在则为真 -r 文件名 如果文件存在且可读则为真 -w 文件名 如果文件存在且可写则为真 -x 文件名 如果文件存在且可执行则为真 -s 文件名 如果文件存在且至少有一个字符则为真 -d 文件名 如果文件存在且为目录则为真 -f 文件名 如果文件存在且为普通文件则为真 -c 文件名 如果文件存在且为字符型特殊文件则为真 -b 文件名 如果文件存在且为块特殊文件则为真 -
有关字符串方面的测试
参数 说明 = 等于为真 != 不等于为真 -z 字符串 字符串长度为零则为真 -n 字符串 字符串长度不为零则为真 -
有关数值方面的测试
参数 说明 -eq 等于为真 -ne 不等与为真 -gt 大于为真 -ge 大于等于为真 -lt 小于为真 -le 小于等于为真 -
逻辑运算符
⑴ ! 表示逻辑非(NOT)。
例如,[ ! -r “$1” ]
或! test -r "$1"
⑵ -a 表示逻辑与(AND)。
例如:[ -f "$myfile" –a -r "$myfile" ]
⑶ -o 表示逻辑或(OR)。
例如:[ "$a" -ge 0 -o "$b" -le 100 ]
-
举例:
(1)判断数是否合法(1-10)
(2)查找某文件是否存在(以参数形式),若存在,则将其权限设置为用户主可读可改,其他人无任何权限。否则则返回无此文件的信息。
(3)条件表达式应用
(4)编写脚本文件leapyear.sh,脚本功能为:判断给定的某一年是否是闰年。
3.1.2 case语句
-
一般格式:
case 字符串 in 模式字符串1) command1 command2 command3 ;; 模式字符串2) command1 command2 command3 ;; ... 模式字符串n) command1 command2 command3 ;; esac
-
举例
3.2 循环
3.2.1 while语句
-
一般形式是:
while 测试条件 do 命令表 done
-
例如:
3.2.2 until语句
-
一般形式是:
until 测试条件 do 命令表 done
当测试条件为假时,才进入循环体,直至测试条件为真时终止循环。
-
例如:
如果第二个位置不为空,就将文件1复制给文件2,然后将位置参数左移两个位置。重复上述过程,直至没有第二个位置参数为止。退出until循环后,测试第一个位置参数,如果不为空,则显示参数不正确。
3.2.3 for语句
-
一般格式是:
for 变量 in 值表 do 命令表 done
例如:
for day in Monday Wednesday Friday Sunday do echo $day done
-
值表可以是文件正则表达式,其一般格式为:
for 变量 in 文件正则表达式 do 命令表 done
例如:
for file in m *.c do cat $file | pr done
-
值表还可以是全部位置参数,此时for语句的书写格式一般是:
for 变量 in $* do 命令表 done
或者
for 变量 do 命令表 done
-
算术表达式方式, 其一般格式是:
for ((e1;e2;e3)) do 命令表 done
例如:打印给定行数的*号。第一行打印1个,第二行打印2个,等等。行
数由用户在命令行上输入。
-
例子:
(1)用循环实 现对每一个用户输入的文件名参数(个 数不限)判断其是否存在,若存在,则将其权限设置为用户主可读可改,其他人无任何权限。否则则返回无此文件的信息。
方法一:
方法二:
3.3 其他命令
3.3.1 break命令
可以使脚本从循环体中退出。
语法格式是:break [ n ]
,n表示要跳n层循环,默认值为1;
3.3.2 continue命令
跳过循环体中在它之后的语句,回到本层循环的开头,进行下一次循环。其语法格式是:continue [ n ]
,n表示从最内层的循环向外跳到第n层,默认值为1;
3.3.3 exit命令
立即退出正在执行的shell脚本,并设定退出值,。其语法格式是:exit [ n ]
,n为退出值。
3.4 shell函数
定义格式为:
[function] 函数名( )
{
命令表
}
函数应先定义,后使用。
3.4 其他命令
-
read命令:从键盘上读取数据,然后赋给指定的变量。
一般格式:read [-u fd] [-n nchars] [-p ''提示''][name1 name2…]
-n 后跟一个数字,定义输入文本的长度;
-u 后面跟fd,从文件描述符中读入,该文件描述符可以是exec新开启的;
变量个数M与输入数据N个数之间的关系:
M=N$ read x y z Today is Monday $ echo $z $x $y Monday Today is
M<N
$ read n1 n2 n3 First Second Third 1234 abcd $ echo $n3 Third 1234 abcd $ echo $n2 $n1 Second First
M>N
$ read n1 n2 n3 1 2 $ echo $n3 $ echo $n1 $n2 1 2
-
echo命令:显示其后的变量值或者直接显示它后面的字符串。
一般格式:echo [-neE] [arg…]
$ echo -e "Enter the file name ->\c" Enter the file name ->$ ▌ $ echo -n "Enter the file name ->" Enter the file name ->$ ▌
echo –e 含有转义字符;
echo –n 光标不换行输出,同\c; -
let命令:执行整数算术运算的命令
一般格式为:let arg …
其中,arg是单独的使用C语言语法的算术表达式。如let "j=i*6+2"
let 命令的替代表示形式是:((算术表达式))
如((j=i*6+2))
其运算符及其优先级和结合性基本上与C语言的相同。
提供了方幂运算符**
,其优先级比*
、/
高一级。
当表达式中有shell的特殊字符时,必须用双引号将其括起来。例如,let “val=a|b”
。
只有使用$((算术表达式))
形式才能返回表达式的值,例如 :$ echo "((12*9))" ((12*9)) $ echo "$((12*9))" 108
-
双引号:由双引号括起来的字符(除$、倒引号` 和转义字符\外)均作为普通字符对待。
$ cat exam9 echo "current directory is `pwd`" #倒引号表示命令替换 echo "home directory is $HOME" #以HOME的值代替$HOME echo "file*.?" #其中的字符都作为普通字符出现 echo "directory '$HOME' " #单引号仍作为普通字符出现 $ exam9 current directory is /home/cauc/scripts home directory is /home/cauc file*.? directory '/home/cauc'
-
单引号:由单引号括起来的所有字符都作为普通字符出现。例如:
$ str='echo "directory is $HOME"' $ echo $str echo "directory is $HOME"
-
倒引号:用倒引号括起来的字符串被shell解释为命令行。
可以将一个命令的执行结果赋给变量,即命令替换。
一般形式是:变量名=`命令表`
例如:dir=`pwd`
另一种形式是:变量名=$(命令表)
例如:dir=$(pwd) -
注释:shell程序中以“#”开头的正文行表示注释。
#! /bin/bash
说明该脚本是用Bourne Again shell编写的,应该调用相应的解释程序予以执行 -
管道线:执行时,前一个命令的输出正好是下一个命令的输入。
$ ls -l $HOME | wc –l $ ls | grep m?.c | wc –l
-
后台命令
-
位置参数:这种变量不能用赋值语句直接赋值,只能通过命令行上对应位置的实参
传值。
• $0始终表示命令名或shell脚本名。 -
shift命令
• 用shift命令移动位置参数
命令行: ex7 A B C D E F
原位置参数: $0 $1 $2 $3 $4 $5 $6
移位后位置参数: $0 $1 $2 $3 $4 $5
【例4.9】 使用shift命令移动位置参数。
• $ cat exam3
#!/bin/bash
3.5 命令执行操作符
-
顺序执行:各条命令之间以分号
;
隔开,从左到右依次执行。
例如:$ pwd ; who | wc -l ; cd /home/bin
-
逻辑与
一般形式:命令1 && 命令2
先执行命令1,如果成功,才执行命令2;否则,不执行命令2。
例如:$ cp ex1 ex10 && rm ex1
-
逻辑或
• 一般形式:命令1 || 命令2
先执行命令1,如果不成功,则执行命令2;否则,不执行命令2。
例如:$ cat abc || pwd
练习:
编写脚本文件sum.sh,脚本功能为:计算从1加到100的和并返回结果。
编写脚本文件Fibonacci.sh,脚本功能为:求费波纳奇数列的前10项及总和。