4

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?

2
  • 1
    So... you want to rename README to README.mp4? Oct 2, 2016 at 15:41
  • 1
    @ThomasDickey Believe me when I say that all of the files that have no file extensions in those folders are MP4 video files. No README. But I understand your concern.
    – ThoWe
    Oct 2, 2016 at 15:52

4 Answers 4

13

Something like this:

find . -type f  ! -name "*.*" -exec mv {} {}.mp4 \;
2
  • 3
    can also do it as find . -type f ! -name "*.*" -exec bash -c 'mv "$0" "$0".mp4' {} \;
    – Sundeep
    Oct 2, 2016 at 15:50
  • 1
    The form from @Sundeep is better because it's actually specified in POSIX. Using multiple arguments containing {} may not work on all systems.
    – Wildcard
    Nov 8, 2016 at 8:30
4

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)
1
  • 1
    Thanks 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.
    – ThoWe
    Oct 2, 2016 at 15:47
0

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 $!;
    }
}
0

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .