【CD唱片shell腳本實現】實現方法

    程序首先會執行菜單選擇程序,然後根據用戶輸入的命令,再去執行相應的函數。

# 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章