- Use builtin 'command -v' rather than external 'which'.
- The clean_filename() function just removed the initial ./ from a file
name; do this with a parameter substitution instead. This gets rid of the
need to fork subshells for command substitutions, so is much faster.
- Where convenient, replace 'echo ... | sed ...' with fast parameter
substitutions.
* Iterating through 'ls' output using 'for' is very brittle; it relies on word splitting and globbing can also mess it up. It's best to use globs directly, but if using 'ls' cannot be avoided, e.g. if you need to sort by date, at least we can use 'IFS= read -r $i' to read from a here-document filled with the 'ls' output, which leaves everything in file names intact except newlines.
* Other minor cleanups.
- Fix lots of problems with convoluted and broken quoting techniques.
- Group code blocks for redirection into a file rather than doing a separate additive redirect for each command.
- Replace strings using bash parameter substitution rather than piping 'echo' through 'sed', resulting in a faster script.
Another minor code cleanup. Within [[ ... ]] and (( ... )) (but not [ ... ]) there is a different shell parsing context in which field splitting (a.k.a. word splitting) and pathname expansion (a.k.a. filename globbing) don't apply, so consistently use '[[' (and '((' for arithmetics) instead of '[' and remove unnecessary quotes.
Since '[[ x == y]]' does 'case'-like glob pattern matching on 'y', the quotes to the right of '==' need to be kept for variables or glob characters, except if a glob pattern is wanted.
Substitutions (variables, command substitutions, etc.) directly assigned to a scalar variable don't need to be quoted, as field splitting and globbing don't apply in that context. Removing superfluous quotes makes the code look a bit cleaner.