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

《Beginning Linux Programming》读书笔记(二)

2008-11-24 16:42 417 查看
第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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: