0

This is easier to explain with an example. Imagine I have a directory structure as follows:

pics/cats/png/01.png
pics/cats/png/02.png
pics/cats/jpg/01.jpg
pics/cats/jpg/02.jpg
pics/dogs/png/01.png
pics/dogs/png/02.png
pics/dogs/jpg/01.jpg
pics/dogs/jpg/02.jpg

I would like to rsync the "pics" directory to a destination, but on the destination I would like the following result, assuming the filter string for my leaf directories is "png":

pics/cats/png/01.png
pics/cats/png/02.png
pics/dogs/png/01.png
pics/dogs/png/02.png

In addition, I would like to accomplish the following result as well: (as the png dirs are no longer necessary)

pics/cats/01.png
pics/cats/02.png
pics/dogs/01.png
pics/dogs/02.png

It might be important to note that any directory might have the string "png" in it, but I only want to "filter" on the leaf directories, ie, directories that do not contain another directory.

It might be important to note also that I want to keep the contents of the "png" directories, even if they contain non-png files. Ie:

pics/cats/png/01.png
pics/cats/png/02.txt
pics/cats/jpg/01.jpg
pics/cats/jpg/02.jpg
pics/dogs/png/01.txt
pics/dogs/png/02.png
pics/dogs/jpg/01.jpg
pics/dogs/jpg/02.jpg

Becomes:

pics/cats/png/01.png
pics/cats/png/02.txt
pics/dogs/png/01.txt
pics/dogs/png/02.png

Or:

pics/cats/01.png
pics/cats/02.txt
pics/dogs/01.txt
pics/dogs/02.png

Last item to note: The directory structure might be "n" deep. Ie:

pics/cats/house/tabby/png/01.png
pics/cats/house/tabby/png/02.txt
pics/cats/house/tabby/jpg/01.jpg
pics/cats/house/tabby/jpg/02.jpg

Becomes:

pics/cats/house/tabby/png/01.png
pics/cats/house/tabby/png/02.txt

Or:

pics/cats/house/tabby/01.png
pics/cats/house/tabby/02.txt

If no easy way exists I'm sure I can just write a bash script to do it, but this seems like a use case that while not common, I'm sure crops up every now and then, and perhaps there is a name and flag for this operation.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
cat pants
  • 435

1 Answers1

1

You can get all the leaf nodes, filter them with grep and save the result to a file.

Then you run rsync with the --files-from option.

That is just the basics. You could filter directly in awk and/or pipe directly to to xargs for example. I'm not trying to be concise or performant, but to show the steps involved.

If you are at the root of the hierarchy:

$ find . -type d | sort | awk '$0 !~ last "/" {print last} {last=$0} END {print last}' | grep '/png$' > /tmp/dirs_rsync.txt

$ rsync -av --files-from=/tmp/dirs_rsync.txt . /your/destination/folder