kwatz
kwatz

Reputation: 67

How to find all files in subdirectories that match pattern and replace pattern

I am attempting to move some video files of mine into new subdirectories while also renaming them on my Unraid system. The files all follow a similar naming convention:

featurette name-featurette.mkv

I would like to move these files from their current directory to a subdirectory and rename them like this:

featurettes/featurette name.mkv 

I am able to create the directories and relocate the files using find and execdir:

find . -type f -name *-featurette.mkv -maxdepth 2 -execdir mkdir ./featurettes/ \;
find . -type f -name *-featurette.mkv -maxdepth 2 -execdir mv {} ./featurettes/ \;

I am struggling with the renaming piece. I've tried the rename command but am unable to get it to work within the featurettes directory, let alone from two directories above, which is where I'd like to execute the command. I've tried the following command within the featurettes directory:

rename \-featurette.mkv .mkv *

However I get the error:

invalid option -- 'f'

I thought by escaping the dash I could avoid that issue, but it doesn't appear to work. Any advice on how to remove this pattern from all files within subdirectories matching it would be very much appreciated.

Upvotes: 2

Views: 2222

Answers (3)

Léa Gris
Léa Gris

Reputation: 19585

find . \
  -maxdepth 2 \
  -type f \
  -name '*-featurette.mkv' \
  -execdir sh -c '
echo mkdir -p ./featurettes/
echo mv -- "$@" ./featurettes/
' _ {} \+

Issue with your implementations I fixed or improved:

  • -maxdepth 2 must precede -type f
  • -name '*-featurette.mkv' must have the pattern quoted to prevent the shell to expand globb it.
  • -execdir is best used with an inline shell, so it can also process multiple arguments from the same directory

Also keep in mind that while running a command with -execdir, find will cd to that directory. It means that mv -- "$@" ./featurettes/' will move files into the ./featurettes/' directory relative to were -execdir has just cd.

Version which also rename files while moving:

( has no echo dry-run protection, so use only if you are sure it does what you want )

#!/usr/bin/env sh

find . \
  -maxdepth 2 \
  -depth \
  -name '*-featurette.mkv' \
  -type f \
  -execdir sh -c '
mkdir -p featurettes
for arg
do
  basename=${arg##*/}
  mv -- "$basename" "./featurettes/${basename%-featurette.mkv}.mkv"
done
' _ {} +

Upvotes: 1

thanasisp
thanasisp

Reputation: 5975

From man rename you see this command gets options and 3 positional parameters:

SYNOPSIS rename [options] expression replacement file...

So in your case the first parameter is being interpreted as an option. You may use this syntax:

rename -- '-featurette' '' *-featurette.mkv

to rename the files. -- indicates that any options are over and what follows are only positional parameters.


Totally, to copy the files with one mv process and rename them:

mkdir -p target/dir
find . -maxdepth 2 -type f -name "*-featurette.mkv" -exec mv -t target/dir {} +
cd target/dir && rename -- '-featurette' '' *-featurette.mkv

If you want to rename many files located into different subdirectories, you can use this syntax:

find . -name "*-featurette.mkv" -print0 | xargs -r0 rename -- '-featurette' ''  

Upvotes: 4

VDR
VDR

Reputation: 2853

You can use Bash's shell parameter expansion feature to get the part of the file name, for example:

$> filename=name-featurette.mkv
$> echo ${filename%-*} #To print first part before '-'
name
$> echo ${filename##*.} #To get the extension
mkv
$> echo ${filename#*-} #To print the part after '-' with extension
featurette.mkv

With this and slightly modifying your find command, you should be able to move+rename your files:

find . -type f -name '*-featurette.mkv' -maxdepth 2 -execdir sh -c 'f="{}"; mv -- "$f" ./featurettes/"${f%-*}.mkv"' \;

In fact you should be able to combine both the find command into one to create_dir, move and rename file.

find . -type f -name '*-featurette.mkv' -maxdepth 2 -execdir sh -c 'f="{}"; mkdir ./featurettes; mv -- "$f" ./featurettes/"${f%-*}.mkv"' \;

Upvotes: 0

Related Questions