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.