2

In a bash script I am working on I need to add a grep option to be accepted at the command line to only read words from a file that match a pattern. The user is prompted to enter books, authors, publishers, and publish years, and the list is stored in a file books in book1~author1~pub1~date1 format, with each set on a separate line. If "print" is passed at the command line (bookinfo print), the file "books" content is put in a book_print file in Book: book1 (\n) Author: author1 ect. format. What I am trying to do is add a grep option so that when a string is specified at the command line with the -f option, only lines in the "books" file that include that pattern are put in the "book_print" file. For example, if the command is "bookinfo -f "author2"", only lines in "books" that include author2 will be put in the book_print file. (bookinfo is the name of the script)

Here is what I have so far. I started the -f option code but don't know where to go from here.

#!/bin/bash
n=${1:-1}
#while getopts f name
#do
#       case $name in
#               f)dopt=1;;
#               *) echo "Invalid arg";;
#       esac
#done
if [[ $1 == "print" ]]
then
    printf "Booktitle: \t\t %s\n" `awk -F '~' '{print $1}' books` >> book_print
    printf "Author(s): \t\t %s\n" `awk -F '~' '{print $2}' books` >> book_print
    printf "Publisher: \t\t %s\n" `awk -F '~' '{print $3}' books`  >> book_print
    printf "Year of Publication: \t %s\n" `awk -F '~' '{print $4}' books` >> book_print
else
    for ((i = 1; i < n + 1; i++))
    do
        echo -n "Booktitle: " 
        read  b
        book=$b
        echo -n $book >> books
        echo -n "~" >> books
        echo -n "Author(s): "
        read a
        author=$a
        echo -n $author >> books
        echo -n "~" >> books
        echo -n "Publisher: "
        read  p
        publisher=$p
        echo -n $publisher >> books
        echo -n "~" >> books
        echo -n "Year of publication: "
        read y
        year=$y
        echo $year >> books
    done
fi

EDIT - I changed the while loop code to the following:

while getops ":f" opt;
do
    case $opt in
        f)
            grep "$OPTARG" books
            ;;
        *)
            echo "Invalid argument."
            ;;
     esac
done

My books file contains the lines A~B~C~D and E~F~G~H. When I run the command ./bookinfo -f "A", I am shown the entire books file rather than just the line that contains A.

2 Answers 2

2

Seems like you were headed in the right direction, here's what you need:

#!/bin/bash

while getopts "f:" opt;
do
  case $opt in
    f)
      echo "Found pattern: $OPTARG"
      ;;
    *)
      echo "Wrong arg"
      # Call the usage function here
  esac
done

You might want to read up on this getops tutorial for further understanding of how getops works.

Sign up to request clarification or add additional context in comments.

6 Comments

Any time I use getopts (which is a lot), I add a -h option to document what the valid options are.
@glennjackman Yes, that's good practice, just not what was asked in the question. :)
Thanks for your help, I changed my while loop and edited the OP with the change. My script is still not working as it should though and I think it may be a result of my grep command.
@tfreiner if you could add a few sample test cases of the book files and what the expected output would be for a specific call to your script, then I might be able to help more.
I figured it out. I was using grep $OPTARG when I should have been using grep $2. Thanks for your help!
|
1

Not an answer, but a quick rewrite to make your code a little tighter:

print() {
    # doing this in a single awk command is much more efficient
    # the default search pattern is "non-empty line"
    awk -F '~' -v pattern="${1:-.}" '
        $0 ~ pattern {
            printf "Booktitle: \t\t %s\n", $1
            printf "Author(s): \t\t %s\n", $2
            printf "Publisher: \t\t %s\n", $3
            printf "Year of Publication: \t %s\n", $4
        }
    ' books >> book_print
}

populate() {
    while true; do
        # use read -p to incorporate the prompt, 
        # and just use one variable per item
        read -p "Booktitle (blank to quit): " book
        [[ -z "$book" ]] && break
        reap -p "Author(s): " author
        read -p "Publisher: " publisher
        read -p "Year of publication: " year
        # critically important to quote the variables here:
        printf "%s~%s~%s~%s\n" "$book" "$author" "$publisher" "$year"
    done >> books
}

# magic getopts here to set the search pattern, say in $search variable,
# and a flag to indicate print versus populate

if [[ "$do_search" -eq 1 ]]; then
    print "$search"
else
    populate
done

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.