I would like to make a small script copying files from different directories example /pp/01 /pp/02/ etc... to another destination with the same directory design. But only those files within the directory with a size larger than 88MB but smaller than 93MB...

I would use a for loop and the find function. Are there more efficient ways? And how can I implement the find function exactly.

  • rsync has options --max-size and --min-size. find has the option -size which could be issued twice. – MattBianco Jun 5 '14 at 10:45
  • @MattBianco Wouldn't you like to add an answer using your rsync proposal? I think that would be the shortest code and probably a very efficient solution. – Dubu Jun 5 '14 at 13:50

I think this is what you are looking for:

$ find /file/location/ -type f -size +88M -size -93M \
    -exec cp {} /new/location/ \;`

This command will find only files that are larger that 88MB and smaller than 93MB. It will then copy each of the files to /new/location.

When it comes to keeping the directory structure it becomes a little harder. I would solve this problem like this:

$ cd /pp
$ find . -type f -size +88M -size -93M -exec cp \
    --parents {} /new/location/pp \;

This will make find return file paths that look like 01/myfile, 02/myfile on so on. The parent flag on cp makes it append a slash + the specified name of the source file.

Example: find finds a file that matches and outputs "02/myfile". cp moves this file to /new/location/pp/02/myfile, creating any directories that are needed.

  • I think that this command will not keep the directory structure, right? – Bernhard Jun 5 '14 at 11:05
  • You are correct. I am not 100% on what you mean but I will try to update my answer. – arnefm Jun 5 '14 at 11:06
  • 1
    Note that the M suffix assumes a GNU or FreeBSD find. It also means that files of size 92.1MiB won't be included (because 92.1 is rounded up (to 93) before comparing with 93, so excluded as not less than 93). – Stéphane Chazelas Jun 5 '14 at 12:01
  • 1
    The --parents assumes a GNU cp. – Stéphane Chazelas Jun 5 '14 at 12:01
  • 1
    Using find * instead of find . means that hidden files and dirs in the current directory (and in the current directory only) will be omitted, and that may cause the command to fail if there are files whose name starts with - or match find predicates. – Stéphane Chazelas Jun 5 '14 at 12:03

This command:

rsync -a --min-size 88m --max-size 93m pp /new_destination/

copies the structure from pp to /new_destination, but only files that are at least 88 MB and at most 93 MB in size.

Add more source directory trees before the final destination specifier if you like, such as:

rsync -a --min-size 88m --max-size 93m pp/01 pp/02 /target/

If you add a trailing slash to the source specification (pp/ as opposed to pp), rsync will not create that directory in the target.

In other words:pp in my first example, results in /new_destination/pp/01/..., whilst this:

rsync -a --min-size 88m --max-size 93m pp/ /new_destination/

instead results in /new_destination/01/..., /new_destination/02/....

The -a flag to rsync means "archive" which recurses directories, preserves metadata on the files, such as permissions and timestamps. (It is a convenience option that equals -rlptgoD which is a very popular combination of options).

  • This is the one really works – Zen Dec 5 '14 at 9:25

Assuming file and directory names don't contain newline characters, POSIXly:

cd /path/to/src/ &&
  find . -type f -size -"$((93 * 1024 * 1024))c" \
                 -size +"$((88 * 1024 * 1024))c" |
    pax -rw /path/to/dst/
  • I think you might be able to handle \newlines even if you did find ... -exec sh -c 'pax -rw "$@"' -- \{\} + I dunno if I've got that right, but I think it's close. I'm just looking over that pax spec for the first time and it specifically says that newlines can be handled by reading them in on the command line and that A pathname of a file to be copied or archived is an operand [that] shall be supported... I think you'd have to use -s to edit out the newline though before archiving or something... – mikeserv Jun 5 '14 at 23:48

To copy files with size in a range from "minimum" to "maximum", and re-create the directory structure, use something like this

cd /source/dir && \
   find . -type f -size "+$MINSIZE" -size "-$MAXSIZE" | cpio -pvdm /target/path

cpio options

  • -p "Pass-though" mode, each file listed is copied to the specified directory
  • -v "Verbose", can be omitted, or to make a dot for every file just to have a visual clue about the progress, use -V in stead.
  • -d "Create directories as needed"
  • -m "Preserve the Mode" (permissions, ownership)
  • 1
    I would recommend joining the cd and find commands into one line with && in case the cd fails for any reason: cd /source/path && find . -type f ... | cpio -p... /abs/target/path – MattBianco Sep 4 '17 at 12:12

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.