Novell Home

HowTo: Create a Home Cooks Recipe Book using the Linux Shell and RunRev GUI Part 5

Novell Cool Solutions: Feature
By Stomfi

Digg This - Slashdot This

Posted: 5 Jul 2005
 

StomfiLearning to use Linux at Home and Work
Welcome to my ongoing series of HowTo articles designed to help Linux newbies get comfortable with Linux. Before trying any of these HowTos, take a few minutes to study the prerequisites so you can hit the ground running.
--Stomfi

This HowTo continues from Part One the creation of a home cook's recipe system using the shell and Runtime Revolution. Unlike MS Windows versions, it does not track nutritional information, as it is just for collecting favourite recipes, which you are going to eat because you like them. It does, however, attempt to give you a shopping list based on common package sizes, or where relevant a delicatessen quantity. It also has a space for a picture, which you can take to remind you what it should look like.

In this fourth part we finish developing the shopping list system. A shopping list is different from an ingredients list, which deals with cups and teaspoons, because its quantities are either in package sizes or piece quantities.

Special Offer for Cool Solutions Readers: Free Copy of Runtime Revolution

The good folks at Runtime Revolution have extended a special offer to Cool Solutions readers to make it easier for you to implement the great ideas in Stomfi's articles. They are offering it for free to Novell customers who know the secret code. See this page for details.

Actually, what we are doing here is quite mind boggling as we are taking a recipe ingredient name and quantity, like "1/2 CUP Chopped Parsley" and changing it to read "1 bunch Parsley" in the shopping list. This is all about matching patterns, and what you apply here will help you to create other reports from arbitrarily worded information, formatted as knowledge. This type of shell scripting can be used to create contents and indexes.

This is a view of the recipe card for Tasmanian Prawns with American Pecan Pesto including picture.

You can see I've added a button for a Shopping List to this card.

Create a new card and name it SHOP. Here it is with a shopping list for the Prawn recipe.

Here is the card script.

on openCard

global RECIPEIDX

#get the picture from the recipe card

put the filename of image "TPIC" of card "SHOWRECIPE" into PICFILE

set the filename of image "TPIC" to PICFILE

#fill the SHOPLIST field

put ($HOME & "/cookbook/bin/shoplist.sh" && RECIPEIDX) into GETLIST

replace return with empty in GETLIST

put the shell of GETLIST into field "SHOPLIST"

end openCard

Here is the Print button script.

on mouseUp

put ($HOME & "/cookbook/printlist.txt") into PRINTLIST

#Make sure the printlist file exists

put ("touch" && PRINTLIST) into TPRINT

put the shell of TPRINT into DUNTOUCH

open file PRINTLIST for write

write field "SHOPLIST" to file PRINTLIST

close file PRINTLIST

#Use lpr to print the file. If you have more than one printer, you can specify

#which one with "lpr -P PrinterName" Have a look at "man lpr"

put ("lpr" && PRINTLIST) into PRSHELL

put the shell of PRSHELL into DUNPR

end mouseUp

Finally, we look at the shell script that does all the work. It's probably the biggest script we have written. When developing this script I inserted lines at the end of control structures like after a "fi" or before a "done" which said:
read "DEBUG"

and ran the script with the command:

sh -x ./shoplist.sh 2

This lets you see the results without having to run the whole script, and see if what you think should happen is actually happening. You have to press the Enter key to get past the "read DEBUG" command.

Sometimes, before the "read" command, you can put an "echo $VariableName" or a "cat $FileName" to see the results.

This is the shoplist.sh shell script:

#!/bin/bash

#

#shoplist.sh index

#

#Set the ingredients files

INGFILE="$HOME/cookbook/book/mingreds.txt"

INGQ="$HOME/cookbook/ingquant.txt"

INGN="$HOME/cookbook/ingname.txt"

INGTEMP="$HOME/cookbook/ingtemp.txt"

INGNTEMP="$HOME/cookbook/ingntemp.txt"

INGNEW="$HOME/cookbook/ingnew.txt"

INGNEWALL="$HOME/cookbook/ingnewall.txt"

rm -f $INGNEWALL $INGNEW

touch $INGNEWALL $INGNEW

#

#Set the shopping packages file

PACKFILE="$HOME/cookbook/book/shoppkgs.txt"

#

#For each ingredient check to see if it is in the packages file

#If it is, check the ingredient quantity and calculate the packages

#What we need is some way of calculating how big each measure quantity is

#So we need another file which tells us this info

#

MCALC="$HOME/cookbook/book/mcalc.txt"

#

#And another format for the ingredients file which can tell us solid or liquid

#and a mandatory measurement field using ONLY for arbitrary quantities

#The format for this file is

#"INDEX#Quantity#Measure#Name#S or L"

#

#Get the ingredients for this recipe

awk -F"#" -v IDX="$1" '{if($1 == IDX) print $0 }' $INGFILE > $INGTEMP

#

#Replace Measurements with shopping quantity calculation in $INGTEMP

#Find out how many records there are

NUMRECS=`wc "$INGTEMP" | awk '{print $1}'`

#

for (( n = 1; n <= $NUMRECS; n++ ))

do

#Empty out temporary calc variable

NEWQ=""

CALCMT=""

#Fill in the needed values

#Quantity

CALCQ=`awk -F"#" -v NUMREC=$n '{if(NR == NUMREC) print $2}' "$INGTEMP"`

#Measure

CALCT=`awk -F"#" -v NUMREC=$n '{if(NR == NUMREC) print $3}' "$INGTEMP"`

#Name

CALCN=`awk -F"#" -v NUMREC=$n '{if(NR == NUMREC) print $4}' "$INGTEMP"`

SOLID=`awk -F"#" -v NUMREC=$n '{if(NR == NUMREC) print $5}' "$INGTEMP"`

CONLY=`echo "$CALCT" | grep "ONLY"`

if [ "${#CONLY}" -lt 1 ]

then

#Not an ONLY

#First got to find out if the shopping quantity is 1

#as this will be a bunch or bulb or something

#Look for name in packfile and print quantity

PQUANT=`grep "$CALCN" $PACKFILE | awk -F"#" '{print $4}'`

#Check that there is one

if [ ${#PQUANT} -gt 0 ]

then

SQUANT="$PQUANT"

else

#The match might be restricted by a words like "finely chopped"

# so do another search without the first words

#Find out if there are words to chop off

#

#This is a new way to create a test right inside the if statement

#without first creating a variable holder

if [ `echo "$CALCN" | wc -w` -gt 2 ]

then

#Cut off all words after the third with -f3-

SHORTN=`echo "$CALCN" | cut -d" " -f3- `

else

#Cut off all words after the second

SHORTN=`echo "$CALCN" | cut -d" " -f2- `

fi

PQUANT=`grep -F "$SHORTN" $PACKFILE | awk -F"#" '{print $4}'`

#Check that there is one. There always should be but mistake do happen.

if [ ${#PQUANT} -gt 0 ]

then

SQUANT="$PQUANT"

#Set name to short name so we can find it later in the script

CALCN="$SHORTN"

else

SQUANT=0

fi

fi

if [ "$SQUANT" -gt 1 ]

then

#This is a package sized quantity

CALCB=`grep "$CALCT" $MCALC | grep "#$SOLID#"`

#Quantity

CALCMS=`echo $CALCB | cut -d"#" -f3`

#Measure

CALCMT=`echo $CALCB | cut -d"#" -f4`

#Use bc to calculate decimals

SNEWQ=`echo "scale = 2; $CALCQ*$CALCMS" | bc -l`

#Make into a whole number if a decimal

#Look for a decimal dot. Have to escape the dot with \ as it means any character by itself

ISDEC=`echo $SNEWQ | grep '\.' `

if [ ${#ISDEC} -gt 0 ]

then

#Divide it into two parts

DECPART=`echo "$SNEWQ" | cut -d"." -f2`

INTPART=`echo "$SNEWQ" | cut -d"." -f1`

if [ $DECPART -gt 0 ]

then

let NEWQ=($INTPART + 1)

else

let NEWQ=$INTPART

fi

else

#Not a decimal

NEWQ=$SNEWQ

fi

#Which is larger

if [ $SQUANT -gt $NEWQ ]

then

#Order this much

THISQU=$SQUANT

else

#Order enough to satisfy recipe

THISQU=$NEWQ

fi

#create shopping line

#Name

CALCMN=`grep "$CALCN" $PACKFILE | cut -d"#" -f1`

awk -F"#" -v NEWSQ=$THISQU -v NUMREC=$n -v NEWM="$CALCMT" \

-v NEWN="$CALCMN" 'BEGIN{OFS = " "}; \

{if(NR == NUMREC) {$2 = NEWSQ; $3 = NEWM; $4=NEWN; \

print $2, $3, $4}}' $INGTEMP > $INGNEW

#Save each line

cat $INGNEW >> $INGNEWALL

else

if [ "$SQUANT" -eq 1 ]

then

#SQUANT is 1 so use the Pack

#Look for name in packfile and print quantity and measure

NEWINGR=`grep "$CALCN" $PACKFILE | awk -F"#" '{print $4 " " $3 " " $1}'`

if [ ${#NEWINGR} -gt 0 ]

then

#Got a package for this ingredient

awk -F"#" -v NUMREC=$n -v NNAME="$NEWINGR" 'BEGIN{OFS = " "};\

{if(NR == NUMREC) print NNAME}' $INGTEMP > $INGNEW

#Save each line

cat $INGNEW >> $INGNEWALL

fi

else

if [ "$SQUANT" -eq 0 ]

then

#

#Look for name in packfile and print quantity and measure

NEWINGR=`grep "$CALCN" $PACKFILE | awk -F"#" '{print $4 " " $3 " " $1}'`

if [ ${#NEWINGR} -gt 0 ]

then

#Got a package for this ingredient

awk -F"#" -v NUMREC=$n -v NNAME="$NEWINGR" 'BEGIN{OFS = " "};\

{if(NR == NUMREC) print NNAME}' $INGTEMP > $INGNEW

#Save each line

cat $INGNEW >> $INGNEWALL

else

#No Package size. This is actually an error in the Package file like a missing package name.

awk -F"#" -v NUMREC=$n 'BEGIN{OFS = " "};\

{if(NR == NUMREC) print $2, $3, $4}' $INGTEMP > $INGNEW

#Save each line

cat $INGNEW >> $INGNEWALL

fi

fi

fi

fi

else

#Is an ONLY so create quantity from recipe quantity

#Unless there is a pack

#Look for name in packfile and print quantity, measure and name

NEWINGR=`grep "$CALCN" $PACKFILE | awk -F"#" '{print $4 " " $3 " " $1}'`

if [ ${#NEWINGR} -gt 0 ]

then

#Got a package for this ingredient

awk -F"#" -v NUMREC=$n -v NNAME="$NEWINGR" 'BEGIN{OFS = " "};\

{if(NR == NUMREC) print NNAME}' $INGTEMP > $INGNEW

#Save each line

cat $INGNEW >> $INGNEWALL

else

#No Package size

awk -F"#" -v NUMREC=$n 'BEGIN{OFS = " "};\

{if(NR == NUMREC) print $2, $3, $4}' $INGTEMP > $INGNEW

#Save each line

cat $INGNEW >> $INGNEWALL

fi

fi

done

#Print out all the saved lines

cat $INGNEWALL

I hope you can follow this script. I've started to show you some more advanced shell techniques in this script.

Don't worry, I'm taking it real easy as I want you to learn without any pressure. As you notice I keep on explaining what the script is trying to do.

All that's left is to save the RunRev stack and create the standalone, then work out the measurement calculations file, and fill the application up with all your favourite recipes, especially the easy ones you can impress your partner with, or your parents, friends, pets, and visitors from across the galaxy.


Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com

© 2014 Novell