shell cd,shell脚本cd
一个简单的程序。
要求
假设我们有一个扩展的CD收藏。为了使我们的生活更简单,我们设计并实现了一个光盘管理程序。用我们学过的Linux编程知识实现一个电子目录似乎是一个非常好的想法。
我们希望,至少在最初,我们的程序可以存储基本的CD信息,比如标签、音乐类型或艺术家。我们还希望保存一些跟踪信息。
我们希望我们可以搜索每一个CD项目,但我们不会搜索跟踪细节。
为了使我们的程序完整,我们希望输入、更新和删除任何信息。
设计
上面提到的三个需求——更新、搜索和显示数据——表明我们应该实现一个简单的菜单程序。我们要存储的所有内容都是文本,这里假设我们的CD收藏不是很大。我们不需要一个完整的数据库,我们只需要一些简单的文本。将信息存储在文本文件中可以使我们的程序保持简单。此外,如果我们的需求发生变化,处理文本文件总是比处理其他类型的文件容易得多。不得已,我们可以手动使用文本编辑器来输入和删除数据,我们需要编写一个程序来完成这项工作。
我们必须为我们的数据存储做出一个重要的设计决策:单个文件够吗?如果有,应该是什么格式?我们希望每张CD只存储一次大部分数据信息。当然,跟踪信息除外。所有CD都有不止一个跟踪信息。
我们是否应该对我们想要存储的每张CD设置一个数量限制?这似乎是一个武断的、不必要的限制,所以我们立刻拒绝了这个想法。
如果我们允许灵活的跟踪号码,我们有以下三种选择:
使用单个文件,一行存储CD的标题信息,n行存储CD的跟踪信息。
将CD的所有信息放在一行中,并允许该行继续,直到没有要存储的跟踪信息。
将标题信息与跟踪信息分开,并将其存储在不同的文件中。
只有第三个选项允许我们灵活地修改文件格式。如果我们想要将数据库转换成相关的格式,我们可以做出这样的选择,所以这里我们将选择第三个选项。
下一个决定是我们希望在文件中存储什么:
最初,对于每个CD标题,我们将选择存储:
1张CD目录标签
2标题
类型3
作曲家或艺术家
对于曲目内容,我们将简单地存储:
1个音轨标签
2轨道名称
为了合并这两个文件,我们必须将轨道信息与CD的其他信息相关联。为此,我们将使用CD目录号。因为这对于每张CD都是唯一的,所以它只会在标题文件和曲目文件中出现一次。
让我们看一个简单头文件的例子:
标题类型作曲家
CD123酷萨克斯爵士Bix
CD234古典小提琴古典巴赫
CD345点击99弹出各种
它们对应的轨迹信息如下:
音轨标签标题
一些爵士乐
CD123 2更多爵士乐
CD345 1头晕
D小调CD234 1奏鸣曲
这两个文件由目录域组合而成。这里我们要记住,在轨道文件中,标题文件中的每个实体都会有多行对应。
我们需要做的最后一件事是如何区分这些实体。在关系数据库中,通常使用具有一定宽度的域,但这并不总是合适的。另一种常见的方法是逗号,这是我们在这里使用的方法。
在下一节中,为了避免混淆,我们将使用以下一些函数:
get_return()
get_confirm()
设置菜单选择()
插入标题()
insert_track()
添加记录轨道()
添加记录()
find_cd()
update_cd()
count_cds()
移除记录()
list_tracks()
激光唱片节目
1在我们的示例程序中,第一行总是保证该程序将作为Shell脚本执行,后面是一些版权信息:
#!/bin/sh
#用于管理激光唱片收藏的非常简单的壳脚本示例。
#版权所有(C) 1996-2003年Wrox出版社。
#这个程序是自由软件;您可以重新发布和/或修改它
#根据由发布的角马通用公共许可证条款
#自由软件基金会;许可证的第2版,或(在您的
#选项)任何更高版本。
#分发此程序是希望它有用,但是
#无任何担保;甚至没有暗示的保证
#适销性或对特定用途的适用性。参见GNU通用
#公共许可证了解更多详细信息。
#您应该已经收到了一份角马通用公共许可证
#用这个程序;如果没有,请写信给自由软件基金会。
美国马萨诸塞州剑桥市麻省大道675号,邮编02139。
2我们要做的第一件事就是保证我们在整个脚本中使用的全局变量已经进行设置。我们要设置标题文件,一个轨迹文件以及一个临时文件。我们同时要跟踪拷贝操作,这样如果用户中断了脚本,我们可以保证删除临时文件. menu_choice=" "
current_cd=" "
title_file="title.cdb "
tracks_file="tracks.cdb "
临时文件=/tmp/cdb .$$
陷阱" rm -f $temp_file "退出
3现在我们要定义我们需要的一些函数,这样脚本从顶行开始执行,在我们试着第一次调用这些函数时可以找到这些函数的定义。为了避免在一些重写一些相同的代码,最初的两个函数是简单的实用程序。
get_return() {
回声-e "按回车键/c "
阅读x
返回0
}
get_confirm() {
"你确定吗?/c "
虽然是真的
做
阅读x
案例" $x "在
是是是是)
返回0;
不,不,不)
回声
回显"已取消"
返回1;
*)回显"请输入是或否";
环境系统应用中心环境系统应用程序中心
完成的
}
四现在我们来定义主要的菜单函数,设置菜单选择。菜单的内容可以动态的变化,如果一个激光唱片实体被选择可以增加一些其他的选项。
set_menu_choice() {
清楚的
回声”选项:-"
回声
回声a)添加新光盘"
回显" f)查找光盘"
回声c)清点目录中的激光唱片和曲目
if [ "$cdcatnum "!="" ];然后
回声“l”列出$cdtitle上的曲目
echo " r) Remove $cdtitle "
echo " u)更新$cdtitle的曲目信息"
船方不负担装货费用
echo“q)退出"
回声
回声-e "请输入选项,然后按返回/c "
阅读菜单选择
返回
}
5现在是两个非常短小的函数,插入标题和插入_轨道,这样可以增加数据库文件。虽然一些讨厌这样的内容,但是他们却可以使得其他的函数看起来更为简洁。
紧随着他们的是一个较大的函数定义,添加记录跟踪,在这其中使用前面的两个函数。这个函数使用模式匹配从而保证用户没有输入逗号(因为我们要使用逗号作为区域分隔符),并且当输入了轨迹信息后使用算村运算来增加轨迹数。
insert_title() {
echo $* $title_file
返回
}
insert_track() {
echo $* $tracks_file
返回
}
add_record_tracks() {
回显"输入此激光唱片的曲目信息"
回声"当没有更多的轨道进入问"
cdtrack=1
cdttitle=" "
while [ "$cdttitle "!="q" ]
做
echo -e "Track $cdtrack,曲目标题?/c "
读取终端监督程式(Terminal Monitor Program的缩写)
cdttitle=${tmp%%,*}
if [ "$tmp "!=" $ CDT title "];然后
回显"对不起,不允许使用逗号"
继续
船方不负担装货费用
if[-n " $ CDT title "];然后
if [ "$cdttitle "!=" q "];然后
insert_track $cdcatnum,$cdtrack,$cdttitle
船方不负担装货费用
其他
cdtrack=$((cdtrack-1))
船方不负担装货费用
cdtrack=$((cdtrack 1))
完成的
}
6条添加记录函数允许将一个主激光唱片的信息实体作为一个新的激光唱片
add_records() {
#提示输入初始信息
回声-e "输入目录名/c "
读取终端监督程式(Terminal Monitor Program的缩写)
cdcatnum=${tmp%%,*}
回声-e "输入标题/c "
读取终端监督程式(Terminal Monitor Program的缩写)
cdtitle=${tmp%%,*}
回声-e "输入类型/c "
读取终端监督程式(Terminal Monitor Program的缩写)
cdtype=${tmp%%,*}
回声-e "输入艺术家/作曲家/c "
读取终端监督程式(Terminal Monitor Program的缩写)
cdac=${tmp%%,*}
#检查他们是否想要输入信息
回声即将添加新条目
echo " $ cdcatnum $ CD title $ CD type $ cdac "
#如果确认,则将其附加到标题文件中
如果得到_确认然后
insert_title $cdcatnum,$cdtitle,$cdtype,$cdac
添加_记录_曲目
其他
移除_记录
船方不负担装货费用
返回
}
七查找光盘函数使用可做文件内的字符串查找命令在激光唱片标题文件中查找指定的目录名字的文本。我们需要知道查找到多少次字符串,但是可做文件内的字符串查找命令只会在他匹配了零次或是多次时才返回一个值。因为这样的情况,我们在一个文件中存储这些输出,其中每一个行匹配一个,然后我们可以计算这个文件中的行数。
字数统计命令wc,在他的输出中使用空格来分隔行数,字数以及文件中的字符数。我们使用$(wc -l $temp_file)命令来从这个命令的输出中得到第一个参数来设置找到线条变量。如果我们希望得到其他的后面的参数,我们可以使用设置命令来设置命令输出的壳参数变量。
我们将可安装文件系统设置为逗号,这样我们就可以使用逗号来进行分隔了。另一个办法就是使用切口命令。
find_cd() {
if[" $ 1 "=" n "];然后
asklist=n
其他
asklist=y
船方不负担装货费用
cdcatnum=" "
回声-e "输入要在激光唱片标题中搜索的字符串/c "
读取搜索字符串
if[" $ search str "=" "];然后
返回0
船方不负担装货费用
grep " $ search str " $ title _ file $ temp _ file
set $(wc -l $temp_file)
linesfound=$l
案例" $linesfound "位于
0)回显"抱歉,未找到任何内容"
获取_返回
返回0
;
1) ;
2)回声”对不起,不是唯一的。"
回声”发现以下内容"
cat $temp_file
获取_返回
返回0
环境系统应用中心环境系统应用程序中心
IFS=","
读取cdcatnum CD标题CD类型cdac $ temp _ file
IFS=" "
if[-z " $ cdcatnum "];然后
回声”对不起,无法从$temp_file中提取目录字段"
获取_返回
返回0
船方不负担装货费用
回声
回显目录号:$cdcatnum
回显标题:$cdtitle
回显类型:$cdtype
回声艺术家/作曲家:cdac
回声
获取_返回
if[" $ asklist "=" y "];然后
回声-e "查看此激光唱片的曲目?/c "
阅读x
if[" $ x "=" y "];然后
回声
列表_曲目
回声
船方不负担装货费用
船方不负担装货费用
返回一
}
8更新_光盘可以允许我们重新输入一个激光唱片的信息。在这里我们要注意的就是我们要查找(使用可做文件内的字符串查找命令)以$cdcatnum开头(^)并且后跟逗号的行,而且我们需要将$cdcatnum用{}作来一个整体,这样我们就可以在他与目录标号之间没有空格的情况下查找逗号。如果获取_确认函数返回值为真,则这个函数同时还会使用{}括起多条语句来执行。
update_cd() {
if[-z " $ cdcatnum "];然后
回显"您必须先选择一张光盘"
查找cd n
船方不负担装货费用
if[-n " $ cdcatnum "];然后
回声”当前曲目有:-"
列表_曲目
回声
回声”这将为$cdtitle重新输入曲目"
get_confirm {
grep-v"^${cdcatnum}",$tracks_file临时文件
mv $temp_file $tracks_file
回声
添加_记录_曲目
}
船方不负担装货费用
返回
}
9计数_光盘将会返回我们数据库内容的一个快速计数。
count_cds() {
set $(wc -l $title_file)
num_titles=$l
set $(wc -l $tracks_file)
数量_曲目=$l
回声找到了$num_titles张CD,总共有$num_tracks首曲目
获取_返回
返回
}
10删除记录将断开数据库文件与实体之间的联系,使用grep -v命令来移除所有匹配的字符串。在这里我们要注意的是我们必须使用临时文件。
如果我们试着使用下面的命令:
grep -v "^$cdcatnum" $title_file
在可做文件内的字符串查找命令有机会执行之前$title_file已经使用输出重定向设置为一个空文件,所以可做文件内的字符串查找命令将会读取一个空文件。
移除记录(){
if[-z " $ cdcatnum "];然后
回声您必须首先选择一张激光唱片
查找cd n
船方不负担装货费用
if[-n " $ cdcatnum "];然后
回显"您即将删除$cdtitle "
get_confirm {
grep-v"^${cdcatnum}",$title_file临时文件
mv $temp_file $title_file
grep-v"^${cdcatnum}",$tracks_file临时文件
mv $temp_file $tracks_file
cdcatnum=" "
回显条目已删除
}
获取_返回
船方不负担装货费用
返回
}
11 list_tracks现在使用grep命令解压我们需要的行,截取我们需要的部分并提供标记输出。如果我们考虑在C代码中重新实现这些20多行的奇代码需要多少行代码,那么我们就会意识到Shell有多强大。
list_tracks() {
if[" $ cdcatnum "=" "];然后
echo尚未选择CD
返回
其他
grep“^${cdcatnum}”,$tracks_file $temp_file
num_tracks=$(wc -l $temp_file)
if[" $ num _ tracks "=" 0 "];然后
回显未找到$cdtitle的曲目
否则{
回声
echo "$cdtitle :-"
回声
截f 2- -d,$temp_file
回声
} $ {传呼机:-更多}
船方不负担装货费用
船方不负担装货费用
获取_返回
返回
}
现在所有的功能都已经定义好了,我们可以进入我们的主要部分了。前几行可以简单地将文件读入一个已知的状态,然后我们调用菜单函数set_menu_choice,并在输出中反映出来。
当选择quit时,我们删除这个临时文件,输出信息,并成功返回条件。
rm -f $temp_file
如果[!-f $ title _ file];然后
触摸title _ file
船方不负担装货费用
如果[!-f $ tracks _ file];然后
触摸tracks _ file
船方不负担装货费用
#现在应用程序本身
清楚的
回声
回声
echo“迷你CD管理器”
睡眠1
退出=n
而[" $戒"!=" y "];
做
设置菜单选择
案例“$menu_choice”在
a)添加记录;
r)删除记录;
f)find _ CD y;
u)update _ CD;
c)count _ CDs;
l)列表_轨道;
b)
回声
更多$title_file
回声
get _ return;
q Q)退出=y;
*)回显“对不起,选择不被识别”;
environmental systems applications center 环境系统应用程序中心
完成的
#收拾好离开
rm -f $temp_file
回显“完成”
出口0
就这样,我们完成了我们简单却实用的程序~ ~