Measuring typing speed in terminal without a mistake
I think this is very nice, clean code. Let's make it better!

Consistency

Consistency helps a lot, making the code easier to understand.


Some functions are named camelCase, others snake_case. Stick to one pattern.
Some variables are named SHOUT_CASE, others snake_case. Stick to one pattern. The latter is recommended, because upper case variable names are commonly used for system variables like PATH and others.
The indentation is mostly 8 spaces, with few exceptions. Use the same everywhere.


Variable declaration

It's good to declare global constants at the top of the file where they are easy to see.
The same is not true for state variables that are implementation details,
such as current_lesson.
That variable would have been better to initialize right before you need it.

Iterating over arrays

Instead of a counting loop over the lesson array,
there is a more idiomatic approach:

for value in "${lesson[@]}"; do ...; done


I would also rename the array to plural lessons.

The return value of functions

There are some subtle points I don't like in this code:


function check_correct() {
        if [ "$user_input" == "$string_to_type" ]; then
                return;
        else
                echo "too many mistakes, try again!"
                false;
        fi
}



A return command without parameter will use the exit code of the last statement. In this case it's success. I would find it clearer if you used an explicit return 0 there.

The else branch ends with a false statement.
If this is the last statement in the function,
then the exit code of the function will be 1, as intended.
But this is not explicit enough.
The function doesn't return immediately on the false statement.
An explicit return 1 would be much better.

Like this:

function check_correct() {
        if [ "$user_input" == "$string_to_type" ]; then
                return 0
        else
                echo "too many mistakes, try again!"
                return 1
        fi
}


With my other suggestions further down, I recommend to write this function like this:

check_correct() {
        if ! [ "$user_input" = "$string_to_type" ]; then
                echo "too many mistakes, try again!" &gt;&amp;2
                return 1
        fi
}


Undocumented features

The == operator is not documented in man [.
For that reason I recommend using = instead of == in [ ... ].

Style

The recommended function declaration style is without the function keyword:

start() {


There are a bunch of redundant semicolons at end of lines that can be safely removed.

Instead of this:


wpm=$((sec / time_it_took))



You can write slightly simpler like this:

((wpm = sec / time_it_took))


This works too:

((wpm *= length_of_string / 5))


I don't remember the explanation, but instead of let count+=1, ((count+=1)) is recommended. An even better way to write is ((count++)).

Sharpening the saw


  I've been programming slightly better every year, but this year it has hardly changed.


Just keep doing it!