• Welcome to Overclockers Forums! Join us to reply in threads, receive reduced ads, and to customize your site experience!

[tutorial] writing a quiz program in bash

Overclockers is supported by our readers. When you click a link to make a purchase, we may earn a commission. Learn More.

Stratus_ss

Overclockix Snake Charming Senior, Alt OS Content
Joined
Jan 24, 2006
Location
South Dakota
HowTo: [tutorial] writing a quiz program in bash

I have been sort of grappling with this issue for the past several years, whats the best way to re-write a quiz program that I had written in VB4 back in the day.

Today I would like to show a simple bash program and explain what each section does, albeit briefly. I know there are a lot of websites out there that deal with this subject so the aim here is actually to help you learn a bit instead of just posting the code.

Brief overview
Step 1: Decide what type of quiz you want to write. Do you want a multiple choice? Fill in the blank? True and false? All of these things make a difference in the way you code.

Step 2: Decide on a language. Do you want a graphical user interface (GUI)? are you fine running it in the terminal? How about dialoge boxes? All of these effect the scripting.

Step 3: Setup your question and answer files. Spacing and the characters you use make a difference (using - instead of / or _ for example)

Step 4: Start coding!

Step 5: Debug and test

Step 6: Your done, pass it on!

Putting the steps into practice

Steps 1 & 2

In this case I decided that I was going to use BASH, it will be a fill in the blank and I wrote 2 variants, CLI only and dialogue boxes.

In order to accomplish my goal of quizzing my vocabulary in another language, I set out to make myself fill in the blanks. This is because I am aiming to use this program as a review of words I have already gone over a few times.

Step 3

My questions and answers were placed in the same flat file. It took the format of WORD - TRANSLATION... So

to think about - pensare a

The reason that the format of the file is important to establish is because your program has to have this information to properly parse the "answer" from the "question". If you use an inconsistent format then your program will get confused and throw out erroneous results.

Now that we have our format lets start the coding!

Step 4: Bash, bash and bash some more...

The best way to understand scripting is by seeing it in action, the second best way is to make good comments as you go along!

Code:
#!/bin/bash
#written by stratus_ss
#this grabs italian words from an english -> italian translation
#it then randomizes them and prompts the user for an answer
#the answer is then compared to the actual answer

The very first line is important, its not mandatory but it is important. It's called the shebang line and it indicates the path which the program should use to execute the code, in this case bash.

If it were a perl script it might be something like #!/usr/bin/perl. At any rate I just wanted to draw this to your attention in the interest of best practices.

In order to make your code clean, programmers use variables in order to store commands or values, what have you. Some languages require you to initialize the variable and then set a value later (by initialize I mean set its value to null or 0). Bash however does not require this as seen in the next code snippets

Code:
#Have zenity pop up and ask how many questions should be looped
number_of_questions=$(zenity --text "how many questions do you want to do?" --entry)

#set the default number of loops to 0
loop=0
#set the default number of correct answers to 0
correct=0

Here I have a few variables: number_of_questions, loop and correct. The first variable tells Zenity to pop up and as the user how many questions they want to go through. This will be explained in a minute.

Loop is initialized to 0. The reason behind this is that every time the program asks a question it will check the number of questions against the loop variable. (more on this in just a minute)

Finally here the correct variable holds the number of questions that a person answers correctly. By default this is set to none.

Code:
until [ $loop = $number_of_questions ]

This line of code tells the program to run until the number of loops matches the number of questions the user wants to be quizzed on. Now there are many ways one could tackle this but that is beyond the scope of this tutorial. Suffice it to say this was just one solution to keep the program running for the desired amount of time.

Code:
do 
	sentence=`cat /home/stratus/Mail/italian |shuf -n1`
	word=`echo $sentence |gawk -F " - " '{print $2 }'`

This may look daunting but its not too bad. The do clause is tied to the "until loop" from the line above. It just says do this until loop=number_of_questions.

Sentence is a new variable I introduce inside the loop because it does not need to exist outside of the loop. Why you ask? because it is constantly being over written and therefore it does not need to have a permanent value.

The code that "sentence=..." looks a bit challenging if you dont understand what it is doing. The first section issues the cat command. This command with display the contents of a file. The path directly behind the cat tells it which file to display. In this case, its in my home folder in a folder called Mail, the file is called italian.

The last little bit is important here the
Code:
 |shuf -n 1
tells bash to shuffle the first result. I.e. grab a random line from within the file. if " -n " was to have a different number, it would spit out several lines. For example if it was " -n 3" it would shuffle the first 3 results. In the case of a quiz game we don't want it to display more then one question at a time, thus we us -n 1.

The last part of this section tells bash to echo the sentence variable. This variable is holding the first shuffled result from code above it.
The part that may be confusing is the
Code:
 |gawk -F " - " '{ print $2 }'

The | symbol takes the output from the previous command and forwards it to the next command as input. In this case the program gawk is getting its input from the variable sentence. The -F " - " section tells gawk that to divide the input into columns whenever there is a <space> - <space>. This way it knows which section of text we want it to grab. The final part '{ print $2 }' does exactly that. It tells gawk to print the second column.

Next we grab the user's answer with the following
Code:
# get the user's answer from zenity input box
user_answer=$(zenity --text "Translate the following word to english: $word" --entry)

#the actual answer is in the first column of the variable sentence
	act_answer=`echo $sentence |gawk -F " - " '{print $1}'`

It puts the $word variable directly into the question so the user can see which word to translate.

The actual answer's code is almost exactly the same as the question except its printing the first column instead of the second. Remember that it is important to know the format of your files before copying my code verbatim.

Code:
if [ "$user_answer" = "$act_answer" ]; then
			zenity --title=Correct --warning --text "Correct! "$word" is "$user_answer" in english!"
			((correct +=1))

The above code is conceptually simple, if the users answer is the same as the actual answer, then display the congratulation text and add +1 to the correct variable.

The correct variable keeps score of how many questions the user answers correctly to be computed later. Other then that, this code has been seen previously in the program and really requires little further explanation.

Code:
	else
			zenity --warning --title=Incorrect --text "Sorry the correct answer is "$act_answer""
		fi
((loop +=1))
done

zenity --warning --title=Score --text "You got $correct out of $loop correct"

This is the final bit of code for zenity version of this quiz program. In summation, it produces the dialogue box if the users answer does not equal the actual answer, closes the if statement, adds +1 to the loop variable and then closes the until loop. Finally it displays the total score for the number of loops. Every time the loop executes, the total number of questions is increased by 1.

The final code block looks like this
Code:
#!/bin/bash
#written by stratus_ss
#this grabs italian words from an english -> italian translation
#it then randomizes them and prompts the user for an answer
#the answer is then compared to the actual answer

number_of_questions=$(zenity --text "how many questions do you want to do?" --entry)
loop=0
correct=0
wrong=0
until [ $loop = $number_of_questions ]
do 
	sentence=`cat /home/stratus/Mail/italian |shuf -n1`
	word=`echo $sentence |gawk -F " - " '{print $2 }'`

	user_answer=$(zenity --text "Translate the following word to english: $word" --entry)
	act_answer=`echo $sentence |gawk -F " - " '{print $1}'`
		if [ "$user_answer" = "$act_answer" ]; then
			zenity --title=Correct --warning --text "Correct! "$word" is "$user_answer" in english!"
			((correct +=1))
		else
			zenity --warning --title=Incorrect --text "Sorry the correct answer is "$act_answer""
		fi
((loop +=1))
done

zenity --warning --title=Score --text "You got $correct out of $loop correct"

The last thing you will need to do is
Code:
 sudo chmod +x quiz_zenity.sh
to make quiz_zenity.sh executable. You can now run it from the command line or double click on it and test your program!
 
Last edited:
Hopefully this has been useful to you. I have tried to be thorough in my explanations without insulting your intelligence. If you have questions or comments please feel free to post them
 
Back