#!/usr/bin/env bash add_question() { question="|" until [[ ${#question} -eq 0 ]]; do read -p "Enter the question. (leave blank to end): " question if [[ ${#question} -eq 0 ]]; then continue fi while [[ $question == *"|"* ]]; do echo "Question cannot contain '|'. Please try again." read -p "Enter the question (without '|' character): " question done question="${question^}" answers=() read -p "Enter the answer (or press Enter to proceed to correct answer): " answer while [[ -n $answer ]]; do answers+=("$answer") if [[ "${answer^^}" =~ ^(T(R(U(E)?)?)?|F(A(L(S(E)?)?)?)?)$ ]]; then break fi read -p "Next answer? (press Enter to proceed): " answer done if [[ ${#answers[@]} -gt 1 ]]; then choices=() for ((i=1; i<=${#answers[@]}; i++)); do letter=$(printf "%s" $((i)) | tr '1-9' 'A-J') choices+=("${letter}: ${answers[$((i-1))]}") done choicesStr="${choices[0]}" for ((i=1; i<${#choices[@]}; i++)); do choicesStr+="|${choices[$i]}" done echo "Enter the correct choice:" read -p "${choicesStr//|/$'\n'}: " correct correct="${correct^}" while [[ ! $correct =~ ^[A-${letter}]$ ]]; do echo "Invalid choice. Please try again." read -p "Enter the correct choice (${choicesStr}): " correct done correctChoice="${correct:0:1}" elif [[ ${#answers[@]} -eq 1 ]]; then choice=${answers[0]} if [[ "${choice^^}" =~ ^[T][R][U][E]?$ ]]; then correctChoice="T" elif [[ "$choice" =~ ^[F][A][L][S][E]?$ ]]; then correctChoice="F" else echo "Invalid choice. Assuming 'T' (True) as the correct answer." correctChoice="T" fi else echo "No answers provided. Skipping the question." return fi question="${question}|${correctChoice:0:1}|${choicesStr}" question="${question%|}" echo "${question}" >> "$0" echo "Question added successfully!" done exit 0 } shuffle_choices() { if [[ ${#answers[@]} -lt 2 ]]; then return fi local letter=({A..Z}) local length="${#answers[@]}" local newAnswer local shuffledChoices mapfile -t shuffledChoices < <(shuf -e "${answers[@]#*: }") for i in "${!answers[@]}" ; do if [[ "${answers[$i]:0:1}" == "${answer}" ]]; then newAnswer="${answers[$i]}" fi done for i in "${!shuffledChoices[@]}" ; do shuffledChoices[$i]="${letter[$i]}: ${shuffledChoices[$i]}" if [[ "${shuffledChoices[$i]#*:}" == "${newAnswer#*:}" ]]; then answer="${letter[$i]}" fi done answers=("${shuffledChoices[@]}") } if [[ $# -gt 1 ]]; then echo "Only 1 argument supported, -a or --question." exit 0 fi if [[ $# -eq 1 ]]; then if [[ "${1}" == "-a" ]] || [[ "${1}" == "--add-question" ]]; then add_question else echo "Only 1 argument supported, -a or --question." exit 0 fi fi startPosition="$(grep -n '^exit 0$' "${0}")" startPosition="${startPosition%%:*}" ((startPosition++)) mapfile -t data < <(tail -n +${startPosition} "$0" | grep -v "^#" | grep -v "^$" | shuf) right=0 wrong=0 echo "Total questions: ${#data[@]}" if [[ ${#data[@]} -eq 0 ]]; then echo "To add questions use the -a or --add-questions flag." fi for i in "${data[@]}" ; do question="${i%%|*}" i="${i#*|}" answer="${i%%|*}" answer="${answer^}" i="${i#*|}" unset answers while [[ ${#i} -gt 1 ]]; do answers+=("${i%%|*}") i="${i#*|}" if [[ "${i%%|*}" == "${i}" ]]; then answers+=("${i}") break fi done shuffle_choices echo echo "${question}" for i in "${answers[@]}" ; do echo "${i}" done read -r choice choice="${choice:0:1}" choice="${choice^}" if [[ "${choice}" == "${answer}" ]]; then echo "Correct!" ((right++)) else echo -n "Wrong, the answer is: " for i in "${answers[@]}" ; do if [[ "${answer}" == "${i:0:1}" ]]; then echo "$i" fi done ((wrong++)) fi if [[ "${answer}" == "F" ]] || [[ "${answer}" == "T" ]]; then answer="${answer/F/False}" answer="${answer/T/True}" echo "${answer}" fi read -rp "Press enter to continue" done # Results echo echo "Out of ${#data[@]} questions, you got ${right} correct." if [[ ${#wrong} -gt 0 ]]; then echo "You missed ${wrong} questions." fi if command -v bc &> /dev/null ; then grade=$(echo "scale=2; $right * 100 / ${#data[@]}" | bc) echo "On a 100 based grading scale, this gives you a score of $grade." fi exit 0