Reputation: 24535
I have a directory oridir
with structure as follows:
.
├── DIRA
│ ├── DIRA1
│ │ └── file2.txt
│ └── DIRA2
│ ├── file1.xls
│ └── file1.txt
└── DIRB
├── DIRB1
│ └── file1.txt
└── DIRB2
└── file2.xls
I have to copy files which have extension .xls
while maintaining the directory structure. So I need to have following directory and files in a newdir
folder:
.
├── DIRA
│ └── DIRA2
│ └── file1.xls
└── DIRB
└── DIRB2
└── file2.xls
I tried following command but it copies all files and folders:
cp -r oridir newdir
Finding required files can be done as follows:
$ find oridir | grep xls$
oridir/DIRB/DIRB2/file2.xls
oridir/DIRA/DIRA2/file1.xls
Also as follows:
$ find oridir -type f -iname *.xls
./oridir/DIRB/DIRB2/file2.xls
./oridir/DIRA/DIRA2/file1.xls
But how to create these folders and copy files. How can I achieve this selected creation of directories and copying files with `bash' in Linux?
Edit: There are space also in some file and directory names.
Upvotes: 1
Views: 699
Reputation: 2456
See Yuji's excellent answer first, but I think tar
is also a good option here:
cd oridir; find . -name "*.xls" | xargs tar c | (cd ../newdir; tar x)
You may need to adjust oridir
and/or ../newdir
depending on the precise paths of your directories.
Possible improvement: Here is a version that may be better in that it will handle files (and paths) with spaces (or other strange characters) in their names, and that uses tar
's own options instead of xargs
and cd
:
cd oridir; find . -print0 -name "*.xls" | tar -c --null -T- | tar -C ../newdir -x
Explanation:
The -print0
and the --null
cause the respective commands to separate filenames by the null (ASCII 0) character only.
-T-
causes tar
to read filenames from standard input.
-C
causes tar
to cd
before extracting.
Upvotes: 1
Reputation: 525
If a destination dir is "dest".
foo.sh
#!/bin/bash
dest=./dest
find . -type f -name "*.xls" | while read f
do
d=$(dirname "${f}")
d="${dest}/${d}"
mkdir -p "${d}"
cp "${f}" "${d}"
done
Make dirs and files.
$ mkdir -p DIRA/DIRA1
$ mkdir -p DIRA/DIRA2
$ mkdir -p DIRB/DIRB1
$ mkdir -p DIRB/DIRB2
$ touch DIRA/DIRA1/file2.txt
$ touch DIRA/DIRA2/file1.xls
$ touch DIRA/DIRA2/file1.txt
$ touch DIRB/DIRB1/file1.txt
$ touch DIRB/DIRB1/file2.xls
A result is
$ find dest
dest
dest/DIRB
dest/DIRB/DIRB1
dest/DIRB/DIRB1/file2.xls
dest/DIRA
dest/DIRA/DIRA2
dest/DIRA/DIRA2/file1.xls
Upvotes: 1
Reputation: 10064
cp's --parents
flag makes use full source file name under DIRECTORY
For example, if recursive glob **
is enabled (shopt -s globstar
):
cp --parents origin/**/*.xls target
If recursive glob is not enabled, you have to add a wildcard for each level on directory hierarchy:
cp --parents origin/*/*/*.xls target
Upvotes: 3