Shell 编程实验

Shell 编程实验

一、实验目的

了解 Shell 的作用和主要分类。
了解 Bash 的一般语法规则。
练习编写简单的 shell 程序。

二、实验内容

1.Shell 变量的定义及其使用。
2.位置参数和环境变量。
3.Shell 中的特殊字符。
4.条件判断结构与循环结构
5.函数的定义和使用

三、预备知识

1、LINUX 环境下常用命令和 VI 编辑器的操作。
2、了解 Shell 作用和主要分类等基础知识。

四、实验设备及工具

软件:PC 机操作系统 REDHAT ELAS4 环境

五、实验原理及说明

    Shell 是 Linux 系统中一个重要的层次,它是用户与系统交互作用的界面。在介绍 Linux命令时,Shell 都作为命令解释程序出现:它接收用户打入的命令,进行分析,创建子进程实现命令所规定的功能,等子进程终止工作后,发出提示符。这是 Shell 最常见的使用方式。Shell 除了作为命令解释程序以外,还是一种高级程序设计语言,它有变量,关键字,有各种控制语句,如 if, case, while, for 等语句,有自己的语法结构。利用 Shell 程序设计语言可以编写出功能很强、但代码简单的程序,特别是它把相关的 Linux 命令有机地组合在一起,可大大提高编程的效率,充分利用 Linux 系统的开放性能,设计出适合自己要求的命令。

六、实验步骤

1.语法练习

(1) Shell 变量
Shell 有两种变量:环境变量和临时变量。在 Shell 脚本中临时变量又分为两类:用户定
义的变量和位置参数。
� 用户定义的变量
用户定义的变量是最普遍的 Shell 变量,变量名是以字母或下化线打头的字母、数字和
下线符序列,并且大小写字母意义不同。变量名的长度不受限制。定义变量并赋值的一般形
式是: 变量名=字符串 例如,
MYFILE=/usr/meng/ff/m1.c
a. 定义并显示变量的值
在程序中使用变量的值时,要在变量名前面加上一个符号“$”
。这个符号告诉 Shell,
要读取该变量的值。
练习 1.1
1.1:
$ dir=/usr/mengqc/file1
$ echo $dir
/usr/mengqc/file1
$ echo dir
dir
$ today=Sunday
$ echo $today $Today
Sunday
$ str="Happy New Year ! "
$ echo "Wish You $str"
Wish You Happy New Year !
b.read 命令
作为交互式输入手段,可以利用 read 命令由标准输入(即键盘)上读取数据,然后赋
给指定的变量。其一般格式是:read 变量 1 [变量 2...]
练习 1.2
1.2:
$ read name -----输入 read 命令
mengqc -----输入 name 的值
$ echo "Your Name is $ name."
Your Name is mengqc -----显示输出的结果
$ read a b c -----read 命令有三个参数
crtvu cn edu -----输入三个字符串,中间以空格隔开
$ echo "Email : $a. $c. $b"
Email : crtvu.edu.cn -----显示输出结果

利用 read 命令可交互式的为变量两赋值。输入数据时,数据间以空格或制表符作为分隔符。

注意以下情况:

*若变量个数与给定数据个数相同,则依次对应赋值,如上面例子所示。
*若变量数少于数据个数,则从左至右依次给变量赋值,而最后一个变量取得所有余下
数据的值。
*若变量个数多余给定数据个数,则从左到右依次给变量赋值,后面的变量没有输入数
据与之对应时,其值就为空串。
� 位置参数
执行 Shell 脚本时可以使用参数。由出现命令行上的位置确定的参数称做位置参数。

sh 中总共有十个位置参数,其对应的名称依次是 $0,$1,$2,...$9。其中$0 始终表示命令名或
Shell 脚本名,对于一个命令行,必然有命令名,也就必定有$0;而其它位置参数依据实际
需求,可有可无。
练习 1.3 位置参数的作用。
a.在你的计算机上建立以下三个文件(设建立在目录/usr/username 之下,其中 username
表示你的主目录名)
:
文件 m1.c:
#include <stdio.h>
main( )
{
printf("Begin \n");
}
文件 m2.c:
# include < stdio.h >
main( )
{
printf("OK! \n");
}
文件 ex3:
# ex3: shell script to combine files and count lines
cat $1 $2 $3 $4 $5 $6 $7 $8 $9 | wc -l
# end
b.将 ex3 改为具有执行权限:
$ chmod +x ex3
c.利用 env 命令查看在环境变量 PATH 中是否包含你的当前工作目录
(即/usr/username)

如果没有包含在其中,则利用以下语句改变 PATH 的值:
$ PATH=$PATH:/usr/username
d.执行脚本 ex3:
$ ./ex3 m1.c m2.c
10
练习 1.4 利用位置参数给定变量赋值。
a.建立脚本 ex5,如下所示:
n1=$1
n2=$2
n3=$3
cat $n1 $n2 $n3 | wc -l
b.将 ex5 改为具有执行权限:
$ chmod +x ex5
c.执行脚本 ex5:
$ ./ex5 m1.c m2.c
10
(2) Shell 中的特殊字符
� 通配符
通常的通配符有三种:
* 星号,它匹配任意字符的 0 次或多次出现。但注意,文件名前面的圆点(.)和路径
名中的斜线(/)必须显示匹配。
? 问号,它匹配任意一个字符。
[] 一对方括号,其中有一个字符组。其作用是匹配该字符组所限定的任意一个字符。
应该注意:字符 * 和 ?在一对方括号外面是通配符,若出现在其内部,它们就失去通
配符的能力了。
! 叹号,若它紧跟在一对方括号的左方括号[之后,则表示不在一对方括号中所列出的
字符。
� 引号
在 Shell 中引号分为三种:单引号、双引号、和倒引号。
� 双引号
由双引号括起来的字符,除$、倒引号和反斜线(\)仍保留其功能外,其余字符通常作
为普通字符对待。
练习 1.5
a.建立以下文件 ex8:
echo "current directory is`pwd`"
echo "home directory is $ HOME"
echo "file" * . ?
echo " directory ' $ HOME ' "
b.执行 ex8:
$sh ex8
� 单引号
由单引号括起来的字符都作为普通字符出现。
� 倒引号
练习 1.6
1.6:
$ today=`date`
$echo Today is $today
Today is Thu May 04 10 :56 :20 CST 2000
$
又:
$ users=`who | wc -l`
$ echo The number of users is $ users
The number of users is 5
� 反斜线
转义字符,若想在字符串中使用反斜线本身,则必须采用(\\)的形式,其中第一个反
斜线作为转义字符,而把第二个反斜线变为普通字符。
(3) 条件判断与循环结构
� if 语句
练习 1.7
a.建立脚本 ex9:
echo "The current directory is `pwd`"
if test - f " $1"
then echo " $1 is an ordinary file."
else echo " $ 1 is not anordinary file."
fi
b.执行 ex9:
$sh ex9 ex1
The current directory is /usr/mengqc
ex1 is not anordinary file.

if 语句的 else 部分还可以是 else-if 结构。 (wj14)
if test -f " $1"
then cat $1
else if test -d $1"
then ( cd $1 ;cat * )
else echo "$1 is neither a file nor a directory."
fi
fi
如上例改写成为:
if test -f " $1"
then cat $1
elif test -d " $1"
then ( cd $1 ; cat * )
else echo " $1 is neither afile nor adirectory."
fi
� 测试语句:
有两种常用形式:一种是用 test 命令,如上所示。另一种是用一对方括号将测试条件括
起来。两种形式完全等价。例如,测试位置参数$1 是否是已存在的普通文件,可写成:test
-f " $1",也完全可写成:[ -f $ l ]
在格式上应注意,如果在 test 语句中使用 shell 变量,为表示完整、避免造成歧异起见
最好用双引号将变量括起来。利用一对方括号表示条件测试时,在左方括号[之后、右方括
号]之前各应有空格。
练习 1.8
a.建立脚本文件 ex10
echo "Enter your filename"
read filenane
if [ -f "$filename"]
then cat $filename
else if [ -d "$filename"]
then cd $filename
ls -l *
else echo "$filename:bad filename"
fi
fi
b.执行 ex10
$sh ex10
� while 语句
练习 1.9
a.建立脚本 ex11:
while [ $1 ]
do
if [ -f $1 ]
then echo "display : $1"
cat $1
else echo " $1 is not a file name."
fi
shift
done
b.执行 ex11
练习 1.10
a.建立脚本 ex12:
echo"ley in file->\c"
read filename
echo"key in data:"
while [\n $x]
do
read x
echo $x>>$filename
done
cat $ filename
b.执行 ex12,并分析结果。
� for 语句
练习 1.11
for day in Monday Wednesday Friday Sunday
do
echo $ day
done
例如: (wj20)
for file in m*.c
do
cat $ file | more
done
练习 1.12
a.建立脚本 ex13:
# display files under a given directory
# $1-the nameof the diectory
# $2-the of files
dir=$1;shift
if [ - d $ dir ]
then
cd $dir
for name
do
if [ -f $name ]
then cat $name
echo "End of $ {dir} / $name"
else echo "Invalid file name: $ {dir} / $name"
fi
done
else echo "Bad directory name : $dir"
fi
$
b.执行 ex13,并分析运行结果。
(4) 函数的定义与调用
同其他高级语言一样,shell 也提供了函数功能。
其定义格式如下:
funcname()
{
command
...
command;
}
#分号
定义函数之后,可以在 shell 中对此函数进行调用
如下所示:
iscontinue()
{
while true
do
echo -n "Continue?(Y/N)"
read ANSWER
case $ANSWER in
[Yy])
return 0;;
[Nn])
return 1;;
*) echo "Answer Y or N";;
esac
done
}
这样可以在 shell 编程中调用 iscontinue 确定是否继续执行:
if iscontinue
then
continue
else
break
fi

2.综合实验一:清除/var/log 下的 log 文件

练习 2.1 cleanlog.sh 版本 1

在一个最简单的例子中,一个 shell 脚本其实就是将一堆系统命令列在一个文件中。好
处就是把所有命令都放在一个脚本中,不用每次都敲它们.这样的话,对于特定的应用来说,
这个脚本就很容易被修改或定制。
在这次练习中,我们编写一个最简单的脚本,其内容是用两条命令清除/var/log/message
和/var/log/wtmp 中的内容。
cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Logs cleaned up."

练习 2.2 cleanlog.sh 版本 2

下面按照 Shell 编程的一些规则进行改良:
在第一行添加一个 Bash 脚本的正确的开头部分,指定解释器为 bash。
使用变量指定/var/log 目录,在后面使用这个变量。
最后用 exit 退出。
使用注释说明各部分的用法。
#!/bin/bash
# 一个 Bash 脚本的正确的开头部分.
# Cleanup, 版本 2
# 当然要使用 root 身份来运行.
# 在此处插入代码,来打印错误消息,并且在不是 root 身份的时候退出.
LOG_DIR=/var/log
# 如果使用变量,当然比把代码写死的好.
cd $LOG_DIR
cat /dev/null > messages
cat /dev/null > wtmp
echo "Logs cleaned up."
exit # 这个命令是一种正确并且合适的退出脚本的方法.

练习 2.3 cleanlog.sh 版本 3

现在,让我们来编写有真正意义的脚本:
添加权限有关语句,判断执行脚本的是否根用户,如果不是则输出出错信息,退出。
添加语句,判断是否有命令行参数,如果有,假设是 n,在后面的清除 log 的时候保留
最后的 n 行;如果没有,设 n=50。
你可以不断地找到新的方法来完善这个脚本,并提高效率。
#!/bin/bash
###############################################################
# 说明:删除 logfile 的脚本
###############################################################
LOG_DIR=/var/log
ROOT_UID=0
# $UID 为 0 的用户才具有根用户的权限
LINES=50
# 默认的保存行数
E_XCD=66
# 不能修改目录,与下面的 E_NOTROOT 相似,用于本脚本退出返回
E_NOTROOT=67
# 非根用户
# 一定要使用根用户来运行
if [ "$UID" -ne "$ROOT_UID" ]
then
echo "Must be root to run this script."
exit $E_NOTROOT
fi
if [ -n "$1" ] # 测试是否有命令行参数(非空).
then
lines=$1
else
lines=$LINES # 如果不在命令行中指定,使用默认
fi
#
#
#
#
#
#
#
#
#
#
可以使用下边的更好方法来检测命令行参数.
其使用了 case 结构
E_WRONGARGS=65
# Non-numerical argument (bad arg format)
case "$1" in
""
) lines=50;;
*[!0-9]*) echo "Usage: `basename $0` file-to-cleanup"; exit $E_WRONGARGS;;
*
) lines=$1;;
esac
#
cd $LOG_DIR
if [ `pwd` != "$LOG_DIR" ]
# 也可以用
if [ "$PWD" != "$LOG_DIR" ]
# 查看是否在 /var/log 目录中
then
echo "Can't change to $LOG_DIR."
exit $E_XCD
fi # 在处理 log file 之前,再确认一遍当前目录是否正确.
# 更有效率的做法是:
#
# cd /var/log || {
#
echo "Cannot change to necessary directory." >&2
#
exit $E_XCD;
#}
tail -$lines messages > mesg.temp # 保存 log file 消息的最后部分.
mv mesg.temp messages
# 变为新的 log 目录.
cat /dev/null > wtmp
echo "Logs cleaned up."
exit 0
# 退出之前返回 0,表示成功.

3.综合实验二:找出死链接文件

执行流程:
1.判断是否有命令行参数,如果没有,那么就使用当前目录,否则就使用传递进来的
参数作为目录来搜索。
2.建立函数 linkchk,用来检查传进来的目录或文件是否是链接和是否链接到不存在的
路径,即死链接。
如果是死链,打印出它们的路径。
如果传进来的目录有子目录,
那么把子目录也发送到 linkchk 函数中处理,也就是递归目
录。
3.对每个从脚本传递进来的参数,都调用 linkchk 函数去处理,如果有参数不是目录,
那就打印出错误消息和使用信息。
4.Exit 退出。
#!/bin/bash
# broken-link.sh
# Written by Lee bigelow <[email protected]>
# Modified and commented by oyxin
# Used with permission.
# 说明:用来找出死链接文件并且输出它们的路径
###############################################################
# 如果没对这个脚本传递参数,那么就使用当前目录.
# 否则就使用传递进来的参数作为目录来搜索.
[ $# -eq 0 ] && directorys=`pwd` || directorys=$@
linkchk () {
for element in $1/*; do
[ -h "$element" -a ! -e "$element" ] && echo \"$element\"
[ -d "$element" ] && linkchk $element
# '-h'是测试链接,'-d'是测试目录.
done
}
for directory in $directorys; do
if [ -d $directory ]
then linkchk $directory
else
echo "$directory is not a directory"
echo "Usage: $0 dir1 dir2 ..."
fi
done
exit 0

你可能感兴趣的:(shell,设计,语言,编程实验)