您的位置:首页 > 运维架构 > Shell

【CD唱片shell脚本实现】实现方法

2013-12-23 10:02 537 查看
程序首先会执行菜单选择程序,然后根据用户输入的命令,再去执行相应的函数。

# Here, we come to the main menu function, set_menu_choice.
# The contents of the menu vary dynamically, with extra options being added if a CD entry
# has been selected. Note that echo -e may not be portable to some shells.

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
}

# Now the application proper

clear
echo
echo
echo "Mini CD manager"
sleep 1

quit=n
while [ "$quit" != "y" ];
do
set_menu_choice
case "$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

几个重要函数的实现
1、count_cds函数
在标题文件和曲目文件中,每一项以一行存储,所以只要统计有多少行数就可以了。程序通过命令:
set $(wc -l $title_file)
num_titles=$1
实现。

2、 find_cd函数
find函数需要一个参数,如果这个参数是y,他会在你输入主键找到一个CD唱片后询问你是否要查看这张CD的曲目。不过这个参数是固定配置的,方便程序员修改程序吧,用户不能自己配置。
程序中用到了环境变量IFS,这里介绍一下。
IFS(Internal Field Separator),是内部字段分隔符。
例:



它会把IFS中设置的字符替换为空格(分隔符)。
CD成片程序中是这样用的:
IFS=","
read cdcatnum cdtitle cdtype cdac < $temp_file
IFS=" "
temp_file文件中是以“,”号分割的字符串。

3、 list_tracks函数
# 搜索含变量cdcatnum的内容到temp_file,^代表指向一行的开头。
grep "^${cdcatnum}," $tracks_file > $temp_file
if [ "$num_tracks" = "0" ]; then
echo no tracks found for $cdtitle
else {
echo
echo "$cdtitle :-"
echo
# 用","分隔符分割temp_file中的字符串,并输出从第二段开始后面的
cut -f 2- -d , $temp_file
echo

# 如果PAGER没有定义或者为空,则返回more,否则返回PAGER。 # PAGER这个变量包含了浏览文件内容的程序的路径(例如less或者more)。
} | ${PAGER:-more}
fi

4、add_record_tracks函数
while [ "$cdttitle" != "q" ]
if [ -n "$cdttitle" ] ; then
这个函数里用的最多的是字符串的匹配,要注意的是"["的右,"]"的左,"="的左右都要留空格。
以下是整数,字符串以及文件操作的匹配符:

比较操作
整数操作
字符串操作
相同
-eq
=或==
不同
-ne
!=
小于
-lt
\< (ASCII)
小于等于
-le
大于
-gt
\> (ASCII)
大于等于
-ge
-z (字符串为空)
-n (字符串不为空)
文件操作符
-e
-f
-s
-d
-r
-w
-x
说明
文件已经存在
文件是普通文件
文件大小不为零
文件是一个目录
文件对当前用户可以读取
文件对当前用户可以写入
文件对当前用户可以执行
5、shell脚本的默认变量
$# 传入脚本的命令行参数个数
$* 所有命令行参数值,在各个参数值之间留有空格(作为单个字符串)
$0 命令本身(shell文件名)
$1 第一个命令行参数
${10} 第10个命令行参数
$? 返回值
$$ 脚本的进程ID
$@ 所有位置参数(每个作为独立的字符串)

CD唱片的shell实现的源码(程序源码来自《linux程序设计(第四版)》一书)

1 #!/bin/bash
2
3 # Very simple example shell script for managing a CD collection.
4 # Copyright (C) 1996-2007 Wiley Publishing Inc.
5
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the
8 # Free Software Foundation; either version 2 of the License, or (at your
9 # option) any later version.
10
11 # This program is distributed in the hopes that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 # Public License for more details.
15
16 # You should have received a copy of the GNU General Public License along
17 # with this program; if not, write to the Free Software Foundation, Inc.
18 # 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 # The first thing to do is to ensure that some global variables that we'll be using
21 # throughout the script are set up. We set the title and track files and a temporary file.
22 # We also trap Ctrl-C, so our temporary file is removed if the user interrupts the script.
23
24 menu_choice=""
25 current_cd=""
26 title_file="title.cdb"
27 tracks_file="tracks.cdb"
28 temp_file=/tmp/cdb.$$
29 trap 'rm -f $temp_file' EXIT
30
31 # Now we define our functions, so that the script, executing from the top line, can find
32 # all the function definitions before we attempt to call any of them for the first time.
33 # To avoid rewriting the same code in several places, the first two functions are simple
34 # utilities.
35
36 get_return() {
37   echo -e "Press return \c"
38   read x
39   return 0
40 }
41
42 get_confirm() {
43   echo -e "Are you sure? \c"
44   while true
45   do
46     read x
47     case "$x" in
48       y | yes | Y | Yes | YES )
49         return 0;;
50       n | no  | N | No  | NO )
51         echo
52         echo "Cancelled"
53         return 1;;
54       *) echo "Please enter yes or no" ;;
55     esac
56   done
57 }
58
59 # Here, we come to the main menu function, set_menu_choice.
60 # The contents of the menu vary dynamically, with extra options being added if a CD entry
61 # has been selected. Note that echo -e may not be portable to some shells.
62
63 set_menu_choice() {
64   clear
65   echo "Options :-"
66   echo
67   echo "   a) Add new CD"
68   echo "   f) Find CD"
69   echo "   c) Count the CDs and tracks in the catalog"
70   if [ "$cdcatnum" != "" ]; then
71     echo "   l) List tracks on $cdtitle"
72     echo "   r) Remove $cdtitle"
73     echo "   u) Update track information for $cdtitle"
74   fi
75   echo "   q) Quit"
76   echo
77   echo -e "Please enter choice then press return \c"
78   read menu_choice
79   return
80 }
81
82 # Two more very short functions, insert_title and insert_track for adding to the database files.
83 # Though some people hate one-liners like these, they help make other functions clearer
84 # They are followed by the larger add_record_track function that uses them.
85 # This function uses pattern matching to ensure no commas are entered (since we're using commas
86 # as a field separator), and also arithmetic operations to increment the current track number
87 # as tracks are entered.
88
89 insert_title() {
90   echo $* >> $title_file
91   return
92 }
93
94 insert_track() {
95   echo $* >> $tracks_file
96   return
97 }
98
99 add_record_tracks() {
100   echo "Enter track information for this CD"
101   echo "When no more tracks enter q"
102   cdtrack=1
103   cdttitle=""
104   while [ "$cdttitle" != "q" ]
105   do
106       echo -e "Track $cdtrack, track title? \c"
107       read tmp
108       cdttitle=${tmp%%,*}
109       if [ "$tmp" != "$cdttitle" ]; then
110         echo "Sorry, no commas allowed"
111         continue
112       fi
113       if [ -n "$cdttitle" ] ; then
114         if [ "$cdttitle" != "q" ]; then
115           insert_track $cdcatnum,$cdtrack,$cdttitle
116         fi
117       else
118         cdtrack=$((cdtrack-1))
119       fi
120     cdtrack=$((cdtrack+1))
121   done
122 }
123
124 # The add_records function allows entry of the main CD information for a new CD.
125
126 add_records() {
127   # Prompt for the initial information
128
129   echo -e "Enter catalog name \c"
130   read tmp
131   cdcatnum=${tmp%%,*}
132
133   echo -e "Enter title \c"
134   read tmp
135   cdtitle=${tmp%%,*}
136
137   echo -e "Enter type \c"
138   read tmp
139   cdtype=${tmp%%,*}
140
141   echo -e "Enter artist/composer \c"
142   read tmp
143   cdac=${tmp%%,*}
144
145   # Check that they want to enter the information
146
147   echo About to add new entry
148   echo "$cdcatnum $cdtitle $cdtype $cdac"
149
150   # If confirmed then append it to the titles file
151
152   if get_confirm ; then
153     insert_title $cdcatnum,$cdtitle,$cdtype,$cdac
154     add_record_tracks
155   else
156     remove_records
157   fi
158
159   return
160 }
161
162 # The find_cd function searches for the catalog name text in the CD title file, using the
163 # grep command. We need to know how many times the string was found, but grep only returns
164 # a value telling us if it matched zero times or many. To get around this, we store the
165 # output in a file, which will have one line per match, then count the lines in the file.
166 # The word count command, wc, has whitespace in its output, separating the number of lines,
167 # words and characters in the file. We use the $(wc -l $temp_file) notation to extract the
168 # first parameter from the output to set the linesfound variable. If we wanted another,
169 # later parameter we would use the set command to set the shell's parameter variables to
170 # the command output.
171 # We change the IFS (Internal Field Separator) to a , (comma), so we can separate the
172 # comma-delimited fields. An alternative command is cut.
173
174 find_cd() {
175   if [ "$1" = "n" ]; then
176     asklist=n
177   else
178     asklist=y
179   fi
180   cdcatnum=""
181   echo -e "Enter a string to search for in the CD titles \c"
182   read searchstr
183   if [ "$searchstr" = "" ]; then
184     return 0
185   fi
186
187   grep "$searchstr" $title_file > $temp_file
188
189   set $(wc -l $temp_file)
190   linesfound=$1
191
192   case "$linesfound" in
193   0)    echo "Sorry, nothing found"
194         get_return
195         return 0
196         ;;
197   1)    ;;
198   2)    echo "Sorry, not unique."
199         echo "Found the following"
200         cat $temp_file
201         get_return
202         return 0
203   esac
204
205   IFS=","
206   read cdcatnum cdtitle cdtype cdac < $temp_file
207   IFS=" "
208
209   if [ -z "$cdcatnum" ]; then
210     echo "Sorry, could not extract catalog field from $temp_file"
211     get_return
212     return 0
213   fi
214
215   echo
216   echo Catalog number: $cdcatnum
217   echo Title: $cdtitle
218   echo Type: $cdtype
219   echo Artist/Composer: $cdac
220   echo
221   get_return
222
223   if [ "$asklist" = "y" ]; then
224     echo -e "View tracks for this CD? \c"
225       read x
226     if [ "$x" = "y" ]; then
227       echo
228       list_tracks
229       echo
230     fi
231   fi
232   return 1
233 }
234
235 # update_cd allows us to re-enter information for a CD. Notice that we search (grep)
236 # for lines that start (^) with the $cdcatnum followed by a ,, and that we need to wrap
237 # the expansion of $cdcatnum in {} so we can search for a , with no whitespace between
238 # it and the catalogue number. This function also uses {} to enclose multiple statements
239 # to be executed if get_confirm returns true.
240
241 update_cd() {
242   if [ -z "$cdcatnum" ]; then
243     echo "You must select a CD first"
244     find_cd n
245   fi
246   if [ -n "$cdcatnum" ]; then
247     echo "Current tracks are :-"
248     list_tracks
249     echo
250     echo "This will re-enter the tracks for $cdtitle"
251     get_confirm && {
252       grep -v "^${cdcatnum}," $tracks_file > $temp_file
253       mv $temp_file $tracks_file
254       echo
255       add_record_tracks
256     }
257   fi
258   return
259 }
260
261 # count_cds gives us a quick count of the contents of our database.
262
263 count_cds() {
264   set $(wc -l $title_file)
265   num_titles=$1
266   set $(wc -l $tracks_file)
267   num_tracks=$1
268   echo found $num_titles CDs, with a total of $num_tracks tracks
269   get_return
270   return
271 }
272
273 # remove_records strips entries from the database files, using grep -v to remove all
274 # matching strings. Notice we must use a temporary file.
275 # If we tried to do this,
276 # grep -v "^$cdcatnum" > $title_file
277 # the $title_file would be set to empty by the > output redirection before the grep
278 # had chance to execute, so grep would read from an empty file.
279
280 remove_records() {
281   if [ -z "$cdcatnum" ]; then
282     echo You must select a CD first
283     find_cd n
284   fi
285   if [ -n "$cdcatnum" ]; then
286     echo "You are about to delete $cdtitle"
287     get_confirm && {
288       grep -v "^${cdcatnum}," $title_file > $temp_file
289       mv $temp_file $title_file
290       grep -v "^${cdcatnum}," $tracks_file > $temp_file
291       mv $temp_file $tracks_file
292       cdcatnum=""
293       echo Entry removed
294     }
295     get_return
296   fi
297   return
298 }
299
300 # List_tracks again uses grep to extract the lines we want, cut to access the fields
301 # we want and then more to provide a paginated output. If you consider how many lines
302 # of C code it would take to re-implement these 20-odd lines of code, you'll appreciate
303 # how powerful a tool the shell can be.
304
305 list_tracks() {
306   if [ "$cdcatnum" = "" ]; then
307     echo no CD selected yet
308     return
309   else
310     grep "^${cdcatnum}," $tracks_file > $temp_file
311     num_tracks=$(wc -l $temp_file)
312     if [ "$num_tracks" = "0" ]; then
313       echo no tracks found for $cdtitle
314     else {
315       echo
316       echo "$cdtitle :-"
317       echo
318       cut -f 2- -d , $temp_file
319       echo
320     } | ${PAGER:-more}
321     fi
322   fi
323   get_return
324   return
325 }
326
327 # Now all the functions have been defined, we can enter the main routine.
328 # The first few lines simply get the files into a known state, then we call the menu
329 # function, set_menu_choice, and act on the output.
330 # When quit is selected, we delete the temporary file, write a message and exit
331 # with a successful completion condition.
332
333 rm -f $temp_file
334 if [ ! -f $title_file ]; then
335   touch $title_file
336 fi
337 if [ ! -f $tracks_file ]; then
338   touch $tracks_file
339 fi
340
341 # Now the application proper
342
343 clear
344 echo
345 echo
346 echo "Mini CD manager"
347 sleep 1
348
349 quit=n
350 while [ "$quit" != "y" ];
351 do
352   set_menu_choice
353   case "$menu_choice" in
354     a) add_records;;
355     r) remove_records;;
356     f) find_cd y;;
357     u) update_cd;;
358     c) count_cds;;
359     l) list_tracks;;
360     b)
361       echo
362       more $title_file
363       echo
364       get_return;;
365     q | Q ) quit=y;;
366     *) echo "Sorry, choice not recognized";;
367   esac
368 done
369
370 # Tidy up and leave
371
372 rm -f $temp_file
373 echo "Finished"
374
375 exit 0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: