Ubuntu kernel update and removal automation script
The only thing I know now is grep -P and everything seems like a nail if you have a hammer.


I hope that's an exaggeration. Otherwise, I don't know how you will understand a review ;-)

Use more here-strings

The script uses here-strings in only one place,
when there are more places where it would be good to use.
For example, instead of this:


LATEST_KERNEL=$(echo "$AVAILABLE_KERNELS" | grep -oPz 'Available Kernels.*?\n=+\n\Kv.+?(?=\s.*?\n)')



This would be better, and eliminate an unnecessary echo call:

LATEST_KERNEL=$(grep -oPz 'Available Kernels.*?\n=+\n\Kv.+?(?=\s.*?\n)' &lt;&lt;&lt; "$AVAILABLE_KERNELS")


Eliminate unnecessary condition

The inner if here can be eliminated:


if ! containsElement "$INSTALLED_KERNEL" "${FALLBACK_KERNELS[@]}"
then
    if ! echo "$INSTALLED_KERNEL" | grep -q "$LATEST_KERNEL"
    then
        echo "${INSTALLED_KERNEL} is not fallback, nor latest. Removing it..."
        ukuu --remove "$INSTALLED_KERNEL"
    fi
fi



You could add "$INSTALLED_KERNEL" to the parameter list of the call to containsElement. Not only the code will be simpler, but it will also eliminate a grep call. (And the echo with the grep, which should have been a here-string anyway, as explained earlier.)

Understand the flags of commands

This call looks strange: grep -oPzq ....
Because of the -q.
Thanks to the -q, the command will produce no output.
Which makes the -o flag unnecessary.
I suggest to review in man grep all the flags you're using,
understand what they do,
and consistently eliminate unnecessary flags.

Naming variables

I and e are too short, they don't help understanding their purpose, and therefore the code.

All capital letters are traditionally used for system variables.
For all local variables in shell scripts,
it's better to use lowercase names to avoid any confusion.

Appending to an array

This statement appends a value to the INSTALLED_KERNELS array:


INSTALLED_KERNELS=( "${INSTALLED_KERNELS[@]}" "$I" )



A simpler way to achieve the same:

INSTALLED_KERNELS+=("$I")


Declare important global variables and constants at the top

Some of the variables are crucial for the behavior of the script,
for example FALLBACK_KERNELS.
What if later you want to change the fallback kernels?
You have to read through the script to find the declaration in the middle.
It would be a lot easier if this was declared at the top,
so you would not need to re-read and re-understand what's going on just to make a simple change.