第2章Shell编程没什么多说的,记录个代码,本章最后的那个简单的CD管理程序
#
!/
bin
/
sh
# Very simple example shell script for managing a CD collection.
# Copyright (C) 1996 - 99 Wrox Press.
# This program is free software; you can redistribute it and / or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
# This program is distributed in the hopes that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.
# 675 Mass Ave, Cambridge, MA 02139 , USA.
# The first thing to do is to ensure that some global variables that we ' ll be using
# throughout the script are set up. We set the title and track files and a temporary file.
# We also trap Ctrl - C, so our temporary file is removed if the user interrupts the script.
menu_choice = ""
current_cd = ""
title_file = " title.cdb "
tracks_file = " tracks.cdb "
temp_file =/ tmp / cdb.$$
trap ' rm -f $temp_file ' EXIT
# Now we define our functions, so that the script, executing from the top line, can find
# all the function definitions before we attempt to call any of them for the first time.
# To avoid rewriting the same code in several places, the first two functions are simple
# utilities.
get_return() {
echo - e " Press return /c "
read x
return 0
}
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
}
# 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
}
# Two more very short functions, insert_title and insert_track for adding to the database files.
# Though some people hate one - liners like these, they help make other functions clearer
# They are followed by the larger add_record_track function that uses them.
# This function uses pattern matching to ensure no commas are entered (since we ' re using commas
# as a field separator), and also arithmetic operations to increment the current track number
# as tracks are entered.
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 %% , * }
if [ " $tmp " != " $cdttitle " ]; then
echo " Sorry, no commas allowed "
continue
fi
if [ - n " $cdttitle " ] ; then
if [ " $cdttitle " != " q " ]; then
insert_track $cdcatnum,$cdtrack,$cdttitle
fi
else
cdtrack = $((cdtrack - 1 ))
fi
cdtrack = $((cdtrack + 1 ))
done
}
# The add_records function allows entry of the main CD information for a new CD.
add_records() {
# Prompt for the initial information
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 %% , * }
# Check that they want to enter the information
echo About to add new entry
echo " $cdcatnum $cdtitle $cdtype $cdac "
# If confirmed then append it to the titles file
if get_confirm ; then
insert_title $cdcatnum,$cdtitle,$cdtype,$cdac
add_record_tracks
else
remove_records
fi
return
}
# The find_cd function searches for the catalog name text in the CD title file, using the
# grep command. We need to know how many times the string was found, but grep only returns
# a value telling us if it matched zero times or many. To get around this , we store the
# output in a file, which will have one line per match, then count the lines in the file.
# The word count command, wc, has whitespace in its output, separating the number of lines,
# words and characters in the file. We use the $(wc - l $temp_file) notation to extract the
# first parameter from the output to set the linesfound variable. If we wanted another,
# later parameter we would use the set command to set the shell ' s parameter variables to
# the command output.
# We change the IFS (Internal Field Separator) to a , (comma), so we can separate the
# comma - delimited fields. An alternative command is cut.
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)
linesfound = $ 1
case " $linesfound " in
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
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 allows us to re - enter information for a CD. Notice that we search (grep)
# for lines that start ( ^ ) with the $cdcatnum followed by a ,, and that we need to wrap
# the expansion of $cdcatnum in {} so we can search for a , with no whitespace between
# it and the catalogue number. This function also uses {} to enclose multiple statements
# to be executed if get_confirm returns 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 && {
grep - v " ^${cdcatnum}, " $tracks_file > $temp_file
mv $temp_file $tracks_file
echo
add_record_tracks
}
fi
return
}
# count_cds gives us a quick count of the contents of our database.
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 strips entries from the database files, using grep - v to remove all
# matching strings. Notice we must use a temporary file.
# If we tried to do this ,
# grep - v " ^$cdcatnum " > $title_file
# the $title_file would be set to empty by the > output redirection before the grep
# had chance to execute, so grep would read from an empty file.
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 again uses grep to extract the lines we want, cut to access the fields
# we want and then more to provide a paginated output. If you consider how many lines
# of C code it would take to re - implement these 20 - odd lines of code, you ' ll appreciate
# how powerful a tool the shell can be.
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
}
# Now all the functions have been defined, we can enter the main routine.
# The first few lines simply get the files into a known state, then we call the menu
# function, set_menu_choice, and act on the output.
# When quit is selected, we delete the temporary file, write a message and exit
# with a successful completion condition.
rm - f $temp_file
if [ ! - f $title_file ]; then
touch $title_file
fi
if [ ! - f $tracks_file ]; then
touch $tracks_file
fi
# 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
# Very simple example shell script for managing a CD collection.
# Copyright (C) 1996 - 99 Wrox Press.
# This program is free software; you can redistribute it and / or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
# This program is distributed in the hopes that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.
# 675 Mass Ave, Cambridge, MA 02139 , USA.
# The first thing to do is to ensure that some global variables that we ' ll be using
# throughout the script are set up. We set the title and track files and a temporary file.
# We also trap Ctrl - C, so our temporary file is removed if the user interrupts the script.
menu_choice = ""
current_cd = ""
title_file = " title.cdb "
tracks_file = " tracks.cdb "
temp_file =/ tmp / cdb.$$
trap ' rm -f $temp_file ' EXIT
# Now we define our functions, so that the script, executing from the top line, can find
# all the function definitions before we attempt to call any of them for the first time.
# To avoid rewriting the same code in several places, the first two functions are simple
# utilities.
get_return() {
echo - e " Press return /c "
read x
return 0
}
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
}
# 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
}
# Two more very short functions, insert_title and insert_track for adding to the database files.
# Though some people hate one - liners like these, they help make other functions clearer
# They are followed by the larger add_record_track function that uses them.
# This function uses pattern matching to ensure no commas are entered (since we ' re using commas
# as a field separator), and also arithmetic operations to increment the current track number
# as tracks are entered.
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 %% , * }
if [ " $tmp " != " $cdttitle " ]; then
echo " Sorry, no commas allowed "
continue
fi
if [ - n " $cdttitle " ] ; then
if [ " $cdttitle " != " q " ]; then
insert_track $cdcatnum,$cdtrack,$cdttitle
fi
else
cdtrack = $((cdtrack - 1 ))
fi
cdtrack = $((cdtrack + 1 ))
done
}
# The add_records function allows entry of the main CD information for a new CD.
add_records() {
# Prompt for the initial information
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 %% , * }
# Check that they want to enter the information
echo About to add new entry
echo " $cdcatnum $cdtitle $cdtype $cdac "
# If confirmed then append it to the titles file
if get_confirm ; then
insert_title $cdcatnum,$cdtitle,$cdtype,$cdac
add_record_tracks
else
remove_records
fi
return
}
# The find_cd function searches for the catalog name text in the CD title file, using the
# grep command. We need to know how many times the string was found, but grep only returns
# a value telling us if it matched zero times or many. To get around this , we store the
# output in a file, which will have one line per match, then count the lines in the file.
# The word count command, wc, has whitespace in its output, separating the number of lines,
# words and characters in the file. We use the $(wc - l $temp_file) notation to extract the
# first parameter from the output to set the linesfound variable. If we wanted another,
# later parameter we would use the set command to set the shell ' s parameter variables to
# the command output.
# We change the IFS (Internal Field Separator) to a , (comma), so we can separate the
# comma - delimited fields. An alternative command is cut.
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)
linesfound = $ 1
case " $linesfound " in
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
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 allows us to re - enter information for a CD. Notice that we search (grep)
# for lines that start ( ^ ) with the $cdcatnum followed by a ,, and that we need to wrap
# the expansion of $cdcatnum in {} so we can search for a , with no whitespace between
# it and the catalogue number. This function also uses {} to enclose multiple statements
# to be executed if get_confirm returns 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 && {
grep - v " ^${cdcatnum}, " $tracks_file > $temp_file
mv $temp_file $tracks_file
echo
add_record_tracks
}
fi
return
}
# count_cds gives us a quick count of the contents of our database.
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 strips entries from the database files, using grep - v to remove all
# matching strings. Notice we must use a temporary file.
# If we tried to do this ,
# grep - v " ^$cdcatnum " > $title_file
# the $title_file would be set to empty by the > output redirection before the grep
# had chance to execute, so grep would read from an empty file.
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 again uses grep to extract the lines we want, cut to access the fields
# we want and then more to provide a paginated output. If you consider how many lines
# of C code it would take to re - implement these 20 - odd lines of code, you ' ll appreciate
# how powerful a tool the shell can be.
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
}
# Now all the functions have been defined, we can enter the main routine.
# The first few lines simply get the files into a known state, then we call the menu
# function, set_menu_choice, and act on the output.
# When quit is selected, we delete the temporary file, write a message and exit
# with a successful completion condition.
rm - f $temp_file
if [ ! - f $title_file ]; then
touch $title_file
fi
if [ ! - f $tracks_file ]; then
touch $tracks_file
fi
# 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