COPY FILES LETTERS AT A TIME ( And find out their size )
############################################################

Lets say your in a folder and you want to copy out every movie that begins with the letters B thru I.

Look at the difference between this and this:

find . -iname "[BCDEFGHI]*" -print0
find . -iname "[BCDEFGHI]*"

Print0 helps with files with spaces (gotta have it for Windows files or any files/folders with spaces)
Print0 is put on the find command, and you MUST do a -0 on the xargs command to catch the print0.

Before running any copy or rsync or move command, setup the xargs with an echo to insure you have the right files selected (you dont want to touch data you didnt want to touch)
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I % echo "this file is: %"
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I{} echo "this file is: {}"

NOTE: where % or {} is thats where the file name is. Xargs runs the mentioned command so echo in the above case (and rsync in the final case) once per file, where % or {} is it will substitute in the filename. With -I you define what character or characters you will use to define for filename substitution. So in the top command its -I % so for for every time I want to use the the filename in the command xargs is going to run, then I have to type %.

Then write out your command but put an echo before it to make sure each command looks right (notice I put the double qoutes around the file name, but that is not needed because of the -print0 and -0)
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I % echo rsync -avh --progress % /targetlocation/
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I {} echo rsync -avh --progress {} /targetlocation/
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I % echo rsync -avh --progress \"%\" /targetlocation/
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I {} echo rsync -avh --progress \"{}\" /targetlocation/

So which one is correct? Well without the quotes because we have print0 and 0 take care of the spaces.

find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I % echo rsync -avh --progress % /targetlocation/
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I {} echo rsync -avh --progress {} /targetlocation/

Well because -print0 and -0 takes care of spaces we dont need to cover the filename in quotes.
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I % rsync -avh --progress % /targetlocation/

However before copying lets make sure that the destination can hold all of that space. The destination can hold 3.7 TB, so lets make sure our selection satisfies that. If our selection only yields 2TB, lets select more letters. If it yields close to 3.7TB then we are good, and if we are over then lets select less letters.

CHECK SIZES BEFORE COPY
##########################

The destination can hold 3.7 TB, so lets make sure our selection satisfies that. If our selection only yields 2TB, lets select more letters. If it yields close to 3.7TB then we are good, and if we are over then lets select less letters.

To calculate the size: we look up each file with find, then we push each filename one by one to du. we have to du every file (make du spit out kilobytes). DU spits out 2 columns of data for each file (first column is size, and second is filename), then with awk we add up each 1st column which gives us the size in eithe kilobytes (if we used -k in du) or megabytes (if we used -m in du - i used this one because the total wasnt a scientific notation number - i didnt want any "e" - ten to the power of whatever stuff). Finally after awk adds everything up, I have it simply print x.

Here is an example with -k (kilobytes) notice the scientific notation:
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I {} du -k {} | awk '{x=x+$1}END{print SIZE x}';
2.24729e+09

With -m we get megabytes - easier to read - we only get 2.2 TB:
find . -iname "[BCDEFGHI]*" -print0 | xargs -0 -I {} du -m {} | awk '{x=x+$1}END{print x}';
2194927

Lets select more letters:
find . -iname "[BCDEFGHIK]*" -print0 | xargs -0 -I {} du -m {} | awk '{x=x+$1}END{print x}';
2324695

Even more:
find . -iname "[BCDEFGHIKL]*" -print0 | xargs -0 -I {} du -m {} | awk '{x=x+$1}END{print x}';
2649330

Even more:
find . -iname "[BCDEFGHIKLM]*" -print0 | xargs -0 -I {} du -m {} | awk '{x=x+$1}END{print x}';
2969636

Even more:
find . -iname "[BCDEFGHIKLMNOPQ]*" -print0 | xargs -0 -I {} du -m {} | awk '{x=x+$1}END{print x}';
3403337

Even more letters and we have too much (we went over 3.7 TB):
find . -iname "[BCDEFGHIKLMNOPQR]*" -print0 | xargs -0 -I {} du -m {} | awk '{x=x+$1}END{print x}';
3756753

There we go thats the good spot. So lets copy all that over.
find . -iname "[BCDEFGHIKLMNOPQ]*" -print0 | xargs -0 -I {} du -m {} | awk '{x=x+$1}END{print x}';
3403337

Our target is a USB mounted to /USB and we have a folder there called Movies:

Remember putting quotes on filename is not necessary - so we dont do this:
find . -iname "[BCDEFGHIKLMNOPQ]*" -print0 | xargs -0 -I {} echo rsync -avh --progress \"{}\" /USB/Movies/
find . -iname "[BCDEFGHIKLMNOPQ]*" -print0 | xargs -0 -I {} rsync -avh --progress \"{}\" /USB/Movies/

Here is the final copy command:
find . -iname "[BCDEFGHIKLMNOPQ]*" -print0 | xargs -0 -I {} rsync -avh --progress {} /USB/Movies/
find . -iname "[BCDEFGHIKLMNOPQ]*" -print0 | xargs -0 -I % rsync -avh --progress % /USB/Movies/

 

Leave a Reply

Your email address will not be published. Required fields are marked *