!/bin/bash
非常简单的示例shell脚本,用于管理CD集合
这个程序是自由软件;您可以重新分配它并/或修改它。
我们还捕获了Ctrl-C,因此如果用户中断脚本,我们的临时文件将被删除。
menu_choice=””
current_cd=””
title_file=”title.cdb”//标题文件
tracks_file=”tracks.cdb”//跟踪文件
temp_file=/tmp/cdb.
trap ‘rm -f $temp_file’ EXIT
//表示的是脚本接收到EXIT的信号时, trap执行删除临时文件的操作
现在我们定义我们的函数,以便从顶部执行的脚本可以找到。
//得到返回值
get_return() {
// 其中 \c的作用是,把\c后面的字符串停止输出
echo -e “Press return \c”//任意键继续
read x
return 0
}
//询问是否确认
//返回正确为0,错误为1
//与C语言和c++语言不同
get_confirm() {
echo -e “Are you sure? \c”
while true
do
read x
case “$x” in
y | yes | Y | Yes | YES )
return 0;;
n | no | N | No | NO )
echo
echo “Cancelled”
return 1;;
*) echo “Please enter yes or no” ;;
esac
done
}
在这里,我们来到主菜单函数set_menu_choice。
菜单的内容是动态变化的,如果一个CD条目添加了额外的选项。
被选中。注意,echo -e可能无法移植到某些shell中。
set_menu_choice() {
clear//先清屏
echo "Options :-"
echo
echo " a) Add new CD"
echo " f) Find CD"
echo " c) Count the CDs and tracks in the catalog"
if [ "$cdcatnum" != "" ]; then
echo " l) List tracks on $cdtitle"
echo " r) Remove $cdtitle"
echo " u) Update track information for $cdtitle"
fi
echo " q) Quit"
echo
echo -e "Please enter choice then press return \c"
read menu_choice
return
}
还有两个非常短的函数,insert_title和insert_track用于添加到数据库文件。
尽管有些人讨厌这样的一行程序,但它们有助于使其他功能更清晰。
它们后面是使用它们的较大的add_record_track函数。
这个函数使用模式匹配来确保不输入逗号(因为我们使用逗号)。
作为一个字段分隔符),以及算术运算来增加当前的曲目数量。
insert_title() {
echo
∗>>
title_file//给予它额外的参数
return
}
insert_track() {
echo
∗>>
tracks_file//给予它额外的参数
return
}
add_record_tracks() {
echo “Enter track information for this CD”
echo “When no more tracks enter q”
cdtrack=1
cdttitle=””
while [ “$cdttitle” != “q” ]
do
echo -e "Track $cdtrack, track title? \c"
read tmp
cdttitle=${tmp%%,*}
//从tmp中拿出第一个参数
//若是拿出最后一位参数为:${tmp%,*}
if [ "$tmp" != "$cdttitle" ]; then
echo "Sorry, no commas allowed"
continue//这个是继续的意思,回到while重新执行
fi
if [ -n "$cdttitle" ] ; then//判断cdttitle是否为空
if [ "$cdttitle" != "q" ]; then
insert_track $cdcatnum,$cdtrack,$cdttitle
fi
else
cdtrack=$((cdtrack-1))
fi
cdtrack=$((cdtrack+1))
done
}
add_records函数允许新CD的主CD信息进入
add_records() {
# 提示初始信息。
echo -e “Enter catalog name \c”
read tmp
cdcatnum=${tmp%%,*}
echo -e “Enter title \c”
read tmp
cdtitle=${tmp%%,*}
echo -e “Enter type \c”
read tmp
cdtype=${tmp%%,*}
echo -e “Enter artist/composer \c”
read tmp
cdac=${tmp%%,*}
# 检查他们是否想输入信息。
echo About to add new entry
echo “
cdcatnum
cdtitle
cdtype
cdac”
#如果确认,则追加到标题文件。
if get_confirm ; then
insert_title
cdcatnum,
cdtitle,
cdtype,
cdac
add_record_tracks
else
remove_records
fi
return
}
find_cd函数在CD标题文件中搜索目录名文本,使用。
grep命令。我们需要知道字符串被找到的次数,但是grep只返回。
一个值告诉我们它是否匹配0次或多次。为了解决这个问题,我们储存了。
一个文件中的输出,每个匹配有一行,然后计算文件中的行数。
单词count命令,wc,在其输出中有空格,分隔行数,
文件中的单词和字符。我们使用 (wc−l temp_file)符号来提取。
来自输出的第一个参数设置linesfound变量。如果我们想要另一个,
后面的参数我们将使用set命令来设置shell的参数变量。
命令输出。
我们将IFS(内部字段分隔符)改为a(逗号),这样我们就可以将其分离。
用逗号分隔的字段。另一个命令被删除。
find_cd() {
if [ "$1" = "n" ]; then
asklist=n
else
asklist=y
fi
cdcatnum=""
echo -e "Enter a string to search for in the CD titles \c"
read searchstr
if [ "$searchstr" = "" ]; then
return 0
fi
grep "$searchstr" $title_file > $temp_file
set $(wc -l $temp_file)//使用其中的某个数据域
inlinesfound=$1
case "$linesfound"
0) echo "Sorry, nothing found"
get_return
return 0
;;
1) ;;
2) echo "Sorry, not unique."
echo "Found the following"
cat $temp_file
get_return
return 0
esac
IFS=”,”
read cdcatnum cdtitle cdtype cdac < $temp_file
IFS=” “
if [ -z “$cdcatnum” ]; then
//判断cdcatnum是否为空(本身为0)
echo “Sorry, could not extract catalog field from $temp_file”
get_return
return 0
fi
echo
echo Catalog number: $cdcatnum
echo Title: $cdtitle
echo Type: $cdtype
echo Artist/Composer: $cdac
echo
get_return
if [ "$asklist" = "y" ]; then
echo -e "View tracks for this CD? \c"
read x
if [ "$x" = "y" ]; then
echo
list_tracks
echo
fi
fi
return 1
}
update_cd允许我们重新输入CD的信息。注意我们搜索(grep)
行开始(^)美元cdcatnum后跟一个,,,我们需要包装
在{}中扩展$cdcatnum,我们可以搜索一个没有空格的。
号码和目录号。这个函数还使用{}来包含多个语句。
如果get_confirm返回true,将执行该操作。
update_cd() {
if [ -z "$cdcatnum" ]; then
echo "You must select a CD first"
find_cd n
fi
if [ -n "$cdcatnum" ]; then
echo "Current tracks are :-"
list_tracks
echo
echo "This will re-enter the tracks for $cdtitle"
get_confirm && {// 语句块,当get_confirm返回true时才会执行
grep -v "^${cdcatnum}," $tracks_file > $temp_file//^表示的行首
mv $temp_file $tracks_file
echo
add_record_tracks
}
fi
return
}
count_cds为我们提供了数据库内容的快速计数。
count_cds() {
set $(wc -l $title_file)
num_titles=$1
set $(wc -l $tracks_file)
num_tracks=$1
echo found $num_titles CDs, with a total of $num_tracks tracks
get_return
return
}
remove_records从数据库文件中删除条目,使用grep -v删除所有文件。
匹配字符串。注意,我们必须使用一个临时文件。
如果我们想这样做,
grep - v“^ $ # cdcatnum ” > title_file美元
$title_file将在grep之前由>输出重定向设置为空。
有执行的机会,所以grep会从一个空文件中读取。
remove_records() {
if [ -z "$cdcatnum" ]; then
echo You must select a CD first
find_cd n
fi
if [ -n "$cdcatnum" ]; then
echo "You are about to delete $cdtitle"
get_confirm && {
grep -v "^${cdcatnum}," $title_file > $temp_file
mv $temp_file $title_file
grep -v "^${cdcatnum}," $tracks_file > $temp_file
mv $temp_file $tracks_file
cdcatnum=""
echo Entry removed
}
get_return
fi
return
}
List_tracks再次使用grep来提取我们想要的行,剪切来访问字段。
我们想要,然后更多的提供一个分页的输出。如果你考虑有多少行。
要重新实现这20多行代码,你会很感激的。
这是一个多么强大的工具。
list_tracks() {
if [ "$cdcatnum" = "" ]; then
echo no CD selected yet
return
else
grep "^${cdcatnum}," $tracks_file > $temp_file
num_tracks=$(wc -l $temp_file)
if [ "$num_tracks" = "0" ]; then
echo no tracks found for $cdtitle
else {
echo
echo "$cdtitle :-"
echo
cut -f 2- -d , $temp_file
echo
} | ${PAGER:-more}
fi
fi
get_return
return
}
现在已经定义了所有的函数,我们可以进入主例程。
开头的几行简单地将文件放入已知状态,然后我们调用菜单。
函数,set_menu_choice,并对输出进行操作。
当选择退出时,我们删除临时文件,写入消息并退出。
rm -f
tempfileif[!−f
title_file ]; then
touch
titlefilefiif[!−f
tracks_file ]; then
touch $tracks_file
fi
应用
clear
echo
echo
echo “Mini CD manager”
sleep 1
quit=n
while [ “
quit”!=“y”];dosetmenuchoicecase“
menu_choice” in
a) add_records;;
r) remove_records;;
f) find_cd y;;
u) update_cd;;
c) count_cds;;
l) list_tracks;;
b)
echo
more $title_file
echo
get_return;;
q | Q ) quit=y;;
*) echo “Sorry, choice not recognized”;;
esac
done
Tidy up and leave
rm -f $temp_file
echo “Finished”
exit 0