I have hundreds of files in various different subdirectories. Some of them have the correct file extension, but some of them don't. I want to rename all files that don't have a file extension and append a .mp4 extension to their file name. The other files should be left untouched. How can I automate this renaming operation using Bash? Or do I need a real scripting language like Perl or Python for this?
4 Answers
Something like this:
find . -type f ! -name "*.*" -exec mv {} {}.mp4 \;
-
3can also do it as
find . -type f ! -name "*.*" -exec bash -c 'mv "$0" "$0".mp4' {} \;
– SundeepOct 2, 2016 at 15:50 -
1The form from @Sundeep is better because it's actually specified in POSIX. Using multiple arguments containing
{}
may not work on all systems.– WildcardNov 8, 2016 at 8:30
Try this:
find -type f -not -name '*.mp4' -exec rename -n 's/$/.mp4/' {} +
This checks for all files in current directory and its sub-folders that do not end with .mp4
and renames them to add the extension
Assumes perl
based rename
command, -n
option is to show how the files will be renamed. Once you are okay with it, remove the option and run the command again
Example:
$ find -type f
./rand_numbers.txt
./tst
./abc/123
./abc/zyx.txt
$ find -type f -not -name '*.mp4' -exec rename -n 's/$/.mp4/' {} +
rename(./rand_numbers.txt, ./rand_numbers.txt.mp4)
rename(./tst, ./tst.mp4)
rename(./abc/123, ./abc/123.mp4)
rename(./abc/zyx.txt, ./abc/zyx.txt.mp4)
If you define file not having extension to mean file names without .
in their name, use:
$ find -type f -not -name '*.*' -exec rename -n 's/$/.mp4/' {} +
rename(./tst, ./tst.mp4)
rename(./abc/123, ./abc/123.mp4)
-
1Thanks for your answer. I guess the
find -type f -not -name '*.*' -exec rename -n 's/$/.mp4/' {} +
command does the job (I cannot assume that all other files have .mp4 that's why your first solution doesn't work for me). As I don't have the perl based rename command installed I've used the variant with the mv command instead.– ThoWeOct 2, 2016 at 15:47
globstar way:
#!/bin/bash
# Warning: globstar excludes hidden directories.
# Turn on recursive globbing (in this script) or exit if the option is not supported:
shopt -s globstar || exit
for f in **; do
if [ -f "$f" ]; then
case "${f##*/}" in
*.*) continue ;;
esac
mv "$f" "$f".mp4;
fi
done
perl way, adding _2 if target exists in order to avoid overwrite
#!/usr/bin/perl
use warnings;
use strict;
use File::Find;
find(\&rout, ".");
sub rout {
next if -d $_;
my $new_name = $_;
$new_name =~ s/^([^.]+)$/$1.mp4/;
chdir($File::Find::dir);
if(-e $new_name){
my $new_name2 = $_;
$new_name2 =~ s/^([^.]+)$/$1\_2.mp4/;
rename($_, $new_name2) or die $!;
} else {
$new_name =~ s/^([^.]+)$/$1.mp4/;
rename($_, $new_name) or die $!;
}
}
This will rename all files in current directory that DO NOT already have a file extension..
Example: your directory has files named: file1, file2, file3. They will be renamed to file1.mp4, file2.mp4, file3.mp4
for file in *; do
mv "$file" "${file}.mp4"
done
If there are files with a dot which must be excluded:
for file in *; do
[[ $file == *.* ]] && continue
mv "$file" "${file}.mp4"
done
Or with shopt -s extglob:
for file in +([^.]); do
mv "$file" "${file}.mp4"
done
README
toREADME.mp4
?