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

      2Shell编程没什么多说的,记录个代码,本章最后的那个简单的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 
-"Press return \c"
  read x
  
return 0
}

get_confirm() {
  echo 
-"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 
-"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 
-"Track $cdtrack, track title? \c"
      read tmp
      cdttitle
=${tmp%%,*}
      
if [ "$tmp" != "$cdttitle" ]; then
        echo 
"Sorry, no commas allowed"
        
continue
      fi
      
if [ -"$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 
-"Enter catalog name \c"
  read tmp
  cdcatnum
=${tmp%%,*}

  echo 
-"Enter title \c"
  read tmp
  cdtitle
=${tmp%%,*}

  echo 
-"Enter type \c"
  read tmp
  cdtype
=${tmp%%,*}

  echo 
-"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 
-"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 [ -"$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 
-"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 [ -"$cdcatnum" ]; then
    echo 
"You must select a CD first"
    find_cd n
  fi
  
if [ -"$cdcatnum" ]; then
    echo 
"Current tracks are :-"
    list_tracks
    echo
    echo 
"This will re-enter the tracks for $cdtitle"
    get_confirm 
&& {
      grep 
-"^${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 
-"^$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 [ -"$cdcatnum" ]; then
    echo You must select a CD first
    find_cd n
  fi
  
if [ -"$cdcatnum" ]; then
    echo 
"You are about to delete $cdtitle"
    get_confirm 
&& {
      grep 
-"^${cdcatnum}," $title_file > $temp_file
      mv $temp_file $title_file
      grep 
-"^${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 
-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

posted on 2008-11-24 16:05  Phinecos(洞庭散人)  阅读(883)  评论(0编辑  收藏  举报

导航