Find and move directories based on file type and date
Do not -exec mv
the directory which is currently being examined by find
. It seems that find
gets confused when you do that.
Workaround: first find the directories, then move them.
cd "/mnt/user/New Movies/"
find -type f \( -name "*.avi" -or -name ".*mkv" \) -mtime +180 \
-printf "%h\0" | xargs -0 mv -t /mnt/user/Movies
Explanation:
-
-printf
prints the match according to the format string. -
%h
prints the path part of the match. This corresponds to the"${0%/*}"
in your command. -
\0
separates the items using the null character. This is just precaution in case the filenames contain newlines. -
xargs
collects the input from the pipe and then executes its arguments with the input appended. -
-0
tells xargs to expect the input to be null separated instead of newline separated. -
mv -t <target>
allowsmv
to be called with all the source arguments appended at the end.
Note that this is still not absolutely safe. Some freak scheduler timing in combination with pipe buffers might still cause the mv
to be executed before find
moved out of the directory. To prevent even that you can do it like this:
cd "/mnt/user/New Movies/"
find -type f \( -name "*.avi" -or -name ".*mkv" \) -mtime +180 \
-printf "%h\0" > dirstomove
xargs -0 mv -t /mnt/user/Movies < dirstomove
Background explanation:
I asume what happens with your find
is following:
-
find
traverses the directory/mnt/user/New Movies/
. While there it takes note of the available directories in its cache. -
find
traverses into one of the subdirectories using the system callchdir(subdirname)
. - Inside
find
finds a movie file which passes the filters. -
find
executesmv
with the given parameters. -
mv
moves the directory to/mnt/user/Movies
. -
find
goes back to parent directory using the system callchdir(..)
, which now points to/mnt/user/Movies
instead of/mnt/user/New Movies/
-
find
is confused because it does not find the directories it noted earlier and throws up a lot of errors.
This assumption is based on the answer to this question: find -exec mv stops after first exec. I do not know why find
just stops working in that case and throws up errors in your case. Different versions of find
might be the explanation.
Related videos on Youtube
Sudesh Gama
Updated on September 18, 2022Comments
-
Sudesh Gama over 1 year
I have a directory "New Movies" containing 200+ subdirectories "Movie Name (year)". The subdirectories "Movie Name (year)" contains a single video file (avi/mkv) and several related jpg/xml files.
I need to move all directories containing a video file that is at least 180 days old to another directory.
For example:
New Movies/Movie A (year) would contain movie.mkv, folder.jpg & movie.xml and I want to move them to a subdirectory of the same name elsewhere with all files present and intact.
After looking elsewhere on this site I have tried:
cd "/mnt/user/New Movies/" find -type f \( -name "*.avi" -or -name ".*mkv" \) -mtime +180 -exec sh -c 'mv "${0%/*}" /mnt/user/Movies' {} \;
The command successfully moves the first subdirectory and all files to their new home, however every single operation after this one returns the error
find: './Movie B (year)': No such file or directory find: './Movie C (year)': No such file or directory
and so on through all directories contained under "New Movies" whether they were due to be moved or not.