In the Bourne-Again Shell(bash) ... utilizing arrays and parameter expansion:
for f in *.mp4
do
IFS='. ' read -r -a a <<< "$f"
f1="${a[-4]} ${a[-3]} ${a[@]::${#a[@]}-4}.${a[-1]}"
echo mv -nv -- "$f" "$f1"
done
Notice: echo is added for a safe dry-run ... Remove it when satisfied with the output for the actual renaming to happen.
Demonstration:
$ for f in *.mp4
do
IFS='. ' read -r -a a <<< "$f"
f1="${a[-4]} ${a[-3]} ${a[@]::${#a[@]}-4}.${a[-1]}"
mv -nv -- "$f" "$f1"
done
renamed 'How to Structure Concrete Lesson 2 [code_412].mp4' -> 'Lesson 2 How to Structure Concrete.mp4'
renamed 'The Ultimate Fallacy Lesson 1 [code*123].mp4' -> 'Lesson 1 The Ultimate Fallacy.mp4'
How it works:
The for f in *.mp4 ... will assign each one of the filenames(none-hidden i.e. don't start with a dot.) with the extension .mp4 in the current working directory to the variable f one filename at a time in each loop run.
Then, that filename in the variable f is split into parts(words) around the dot . and the space characters by setting the Internal Field Separator to those characters with IFS='. ' while reading it as a Here String into an indexed array elements withe read -r -a.
Taking the filename The Ultimate Fallacy Lesson 1 [code*123].mp4 as an example, after:
IFS='. ' read -r -a a <<< "$f"
the array a will look like this:
$ declare -p a
declare -a a=([0]="The" [1]="Ultimate" [2]="Fallacy" [3]="Lesson" [4]="1" [5]="[code*123]" [6]="mp4")
... and its elements can be called by index from left to right(first to last) like:
$ echo "${a[0]} ${a[1]}"
The Ultimate
... or from right to left(last to first) like:
$ echo "${a[-1]} ${a[-2]}"
mp4 [code*123]
... or by range with ${a[@]:start_index:length}(if start_index is omitted, then 0 is assumed) like:
$ echo "${a[@]:0:2}"
The Ultimate
$
$ echo "${a[@]::2}"
The Ultimate
... ranges relative to the length of the array ${#a[@]} can also be called with e.g.:
$ echo "${a[@]::${#a[@]}-4}"
The Ultimate Fallacy
... Therefor the variable assignment to f1:
f1="${a[-4]} ${a[-3]} ${a[@]::${#a[@]}-4}.${a[-1]}"
... will look like this:
$ declare -p f1
declare -- f1="Lesson 1 The Ultimate Fallacy.mp4"
Notice for the Z Shell(zsh) users:
You can do the same utilizing extended glob patterns with the builtin shell function zmv with something like this:
% autoload zmv
%
% zmv -n -- '(* *) (* * )(\[*\])(.mp4)' '$2$1$4'
mv -- 'How to Structure Concrete Lesson 2 [code_412].mp4' 'Lesson 2 How to Structure Concrete.mp4'
mv -- 'The Ultimate Fallacy Lesson 1 [code*123].mp4' 'Lesson 1 The Ultimate Fallacy.mp4'
The -n option is for a safe dry-run ... When satisfied with the output, substitute it with -v(for verbosity) so the actual renaming will happen.