user3848196
user3848196

Reputation: 37

Sed function with arithmetic

i am doing up a program that if the user enter a number,(that number refer to item quantity being sold). The programme will then automatically update the available quantity and sold quantity and reflect back to user.

I would also like to know if there is a way to prevent user enter a integer that is bigger that the int store in "$avilable" variable

Thank you

The output will be as shown below.

Title : Star Wars VI – Return of the Jedi
Author : Darth Vader
No. of copies sold  : 3
Current book  info :    
Star Wars VI – Return of the Jedi, Darth Vader, $8.05,  30, 20 

New book info :     
Star Wars VI – Return of the Jedi, Darth Vader, $8.05,  27, 23 

Below is my code, however i am facing difficulty as it is not working.

 {
    echo -n "Title: "  
    read title
    echo -n "Author: "
    read author
    echo -n "No. of copies sold: "
    read numsold 
    if [[ ! $numsold|| $numsold = *[^0-9]* ]]; then
    echo "Please input a number." >&2
    fi
    newavilable=$((avilable - numsold)) 
    newsold=$((sold + numsold))
    sed "s/${sold}/${newsold}/g" BookDB.txt > BookDB1.txt
    mv -f BookDB1.txt BookDB.txt
    sed "s/${avilable}/${newavilable}/g" BookDB.txt > BookDB1.txt
    mv -f BookDB1.txt BookDB.txt
    echo $title:$author:$price:$avilable:$sold >> BookDB.txt
}

Upvotes: 2

Views: 410

Answers (1)

Qeole
Qeole

Reputation: 9124

I would proceed like this:

#!/bin/bash
info=""
# while $info is not set
while [[ -z "$info" ]] ; do
    # Get at title
    title=""
    while [[ -z "$title" ]] ; do
        echo -n "Title: "
        read title
    done

    # Get an author
    author=""
    while [[ -z "$author" ]] ; do
        echo -n "Author: "
        read author
    done

    # Check book is in DB
    info=$(grep "^${title}:${author}:" BookDB.txt)
    if [[ -z "$info" ]] ; then
        echo "Not in database."
    fi
done

# Extract number of books available/already sold
avilable="$(cut -d: -f4 <<< $info)"
sold="$(cut -d: -f5 <<< $info)"

# Get number of recently sold books
while [[ -z "$numsold" ]] ; do
    # We want a number…
    while [[ ! "$numsold" =~ ^[0-9]{1,}$ ]] ; do
        echo -n "No. of copies sold: "
        read numsold
    done
    newavilable=$((avilable - numsold))
    newsold=$((sold + numsold))
    # And we want it lower than $newavilable
    if [[ $newavilable -lt 0 ]] ; then
        echo "Too high"
        numsold=""
    fi
done

# Print old info
echo "Current book info:"
echo "$info"

# Currently prints desired new DB
echo "New book info:"
# Add '-i' option to sed to edit BookDB.txt in place instead of printing it
sed -e "s/^\(${title}:${author}:[0-9]\+\):${avilable}:${sold}$/\1:${newavilable}:${newsold}/" \
    BookDB.txt

In bash tests, don't forget to surround your variables with double quotes, or you'll have bad surprises when they are empty.


Edit: If your price is a float instead of an integer, you can extract it with:

price="$(cut -d: -f3 <<< $info)"

and replace final sed command by either

sed -e "s/^\(${title}:${author}:${price}\):${avilable}:${sold}$/\1:${newavilable}:${newsold}/" BookDB.txt
#               extracted value ^^^^^^^^

or

sed -e "s/^\(${title}:${author}:[0-9.]\+\):${avilable}:${sold}$/\1:${newavilable}:${newsold}/" BookDB.txt
#                       added a dot ^

As bash does not handle floats, use something like bc (or dc, or perl/python/…) to perform operations, e.g. something like:

totalprice=$(echo "$unitprice * $numsold" | bc)

Upvotes: 1

Related Questions