len
len

Reputation: 807

Copy all files with a certain extension from all subdirectories and preserving structure of subdirectories

How can I copy specific files from all directories and subdirectories to a new directory while preserving the original subdirectorie structure?

This answer:

find . -name \*.xls -exec cp {} newDir \;

solves to copy all xls files from all subdirectories in the same directory newDir. That is not what I want.

If an xls file is in: /s1/s2/ then it sould be copied to newDir/s1/s2.

copies all files from all folders and subfolders to a new folder, but the original file structure is lost. Everything is copied to a same new folder on top of each other.

Upvotes: 2

Views: 1356

Answers (3)

len
len

Reputation: 807

Thanks for the solutions.

Meanwhile I found also:

find . -name '*.xls' | cpio -pdm newDir

Upvotes: 0

user1934428
user1934428

Reputation: 22247

This should do:

# Ensure that newDir exists and is empty. Omit this step if you
# don't want it.
[[ -d newDir ]] && rm -r newDir && mkdir newDir

# Copy the xls files.
rsync -a --include='**/*.xls'  --include='*/' --exclude='*' . newDir

The trick here is the combination of include and exclude. By default, rsync copies everything below its source directory (. in your case). We change this by excluding everything, but also including the xls files.

In your example, newDir is itself a subdirectory of your working directory and hence part of the directory tree searched for copying. I would rethink this decision.

NOTE: This would not only also copy directories whrere the name ends in .xls, bur also recreated the whole directory structure of your source tree (even if there are no xls files in it), and populate it only with xls files.

Upvotes: 2

Renaud Pacalet
Renaud Pacalet

Reputation: 29230

You can try:

find . -type f -name '*.xls' -exec sh -c \
'd="newDir/${1%/*}"; mkdir -p "$d" && cp "$1" "$d"' sh {} \;

This applies the d="newDir/${1%/*}"; mkdir -p "$d" && cp "$1" "$d" shell script to all xls files, that is, first create the target directory and copy the file at destination.

If you have a lot of files and performance issues you can try to optimize a bit with:

find . -type f -name '*.xls' -exec sh -c \
'for f in "$@"; do d="newDir/${f%/*}"; mkdir -p "$d" && cp "$f" "$d"; done' sh {} +

This second version processes the files by batches and thus spawns less shells.

Upvotes: 1

Related Questions