1

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?

  • 1
    So... you want to rename README to README.mp4? – Thomas Dickey Oct 2 '16 at 15:41
  • @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 '16 at 15:52
6

Something like this:

find . -type f  ! -name "*.*" -exec mv {} {}.mp4 \;
  • 3
    can also do it as find . -type f ! -name "*.*" -exec bash -c 'mv "$0" "$0".mp4' {} \; – Sundeep Oct 2 '16 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 '16 at 8:30
2

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.