1

There are too many files [*] in a certain folder. I'd like to move some of them into a sub-folder. How can I:

  • move first 3000 files or folders into another folder, or
  • move files older than 3 months into another folder?

Thanks

  • http://www.google.com/search?hl=&q=Errno%3A%3AEMLINK)+“Too+many+links&

4 Answers 4

1

By far the easiest way is to use zsh. To move the first 3000 files in the current directory into /other/directory:

mv *([1,3000]) /other/directory

If you've created a few subdirectories that you want to exclude from that command:

setopt extended_glob
mv *([1,3000])~(exclude-me|exclude-me-too) /other/directory

To move files older than 3 months (the first m is for “modification time”, and the second m means months; fractional parts are ignored, so +2 means ≥3):

mv *(mm+2) /other/directory

If you'd rather use complicated commands than start a different shell, these are still reasonable one-liners with GNU find:

find -mindepth 1 -maxdepth 1 -print0 | head -n 3000 | xargs -0 -i mv {} /other/directory
find -mindepth 1 -maxdepth 1 -mtime +91 -print0 | xargs -0 -i mv {} /other/directory
1

The find command should be of help with some minor scripting over it.

Some references,

  1. A Unix/Linux "find" Command Tutorial
  2. Linux find command examples
  3. Command Line Interface Ninja Howto

Figure out how you want to re-distribute the files and directories to write your command line or short-script based on these examples.

1

A script like this should work to move the first NUMBER_OF_FILES files to SUBDIRECTORY:

NUMBER_OF_FILES=3000  
SUBDIRECTORY=target_folder_name  
NUM=0

find . -type f -maxdepth 1 | sort > /tmp/$$  
exec 4</tmp/$$  
while read FILENAME <&4  
do  
NUM=`expr $NUM + 1`  
if [ $NUM -le $NUMBER_OF_FILES ]  
then  
mv $FILENAME $SUBDIRECTORY  
fi  
done  
rm /tmp/$$ 

Something like this for modified 90 days ago or more:

NUMBER_OF_DAYS=90  
SUBDIRECTORY=target_folder_name  

find . -type f -maxdepth 1 -mtime +$NUMBER_OF_DAYS | sort > /tmp/$$  
exec 4</tmp/$$  
while read FILENAME <&4  
do  
mv $FILENAME $SUBDIRECTORY  
done  
rm /tmp/$$
5
  • The temporary file and extra file descriptor are unnecessary if you just pipe the find into the while read. Also, variables containing filenames should be quoted and code within loops and if statements should be indented (I code-formatted your code for you). Oct 12, 2010 at 15:17
  • Also, hardcoded parameters are bad. Oct 12, 2010 at 15:40
  • And so are tempfiles. Oct 12, 2010 at 15:41
  • And the sort is superfluous. Oct 12, 2010 at 15:42
  • Thanks for the feedback on the script. In this case, the output of find could be piped to the while. However, I've been burned with this when using some shells that spawn a sub-shell when piping commands together, causing any changes to variables within the loop to be lost when it exits. For instance, if a count of files was desired, and a counter variable incremented within the loop using the piping technique, that variable would revert to its original value after the loop ends, and lose the count value. The tempfile technique above avoids that.
    – E Brown
    Nov 18, 2010 at 16:03
1

How I would modify Dennis Williamson's answer:

find . -maxdepth 1 -type f -mtime +30 | rsync -nav --remove-source-files --files-from=- . archive/.

for testing, and

find . -maxdepth 1 -type f -mtime +30 | rsync  -av --remove-source-files --files-from=- . archive/.

for the real thing.

The use of rsync instead of mv is just because rsync supports specifying its source files on standard input. But an added benefit is that rsync has lots of options for detailed control, e.g. dealing with symlinks.

You must log in to answer this question.

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