0PT1MU5 PR1ME
0PT1MU5 PR1ME

Reputation: 45

How to copy all files from a directory and its subdirectories to another dir?

I have a /dir1, the structure is:

./aaa.txt
./bbb.jpg
./subdir1/cccc.doc
./subdir1/eeee.txt
./subdir2/dddd.xls
./subdir2/ffff.jpg

I want to copy all .txt and .jpg in /dir1 and its subdirectories to /dir2.

By using cp -r /dir1/* /dir2, it copies all files and its structure to /dir2.

By using cp -r /dir1/*.jpg /dir2 and cp -r /dir1/*.txt /dir2, it doesn't copy the .jpg and .txt files in the subdirectories.

By using

for FILE in `find`
do
  cp -f $FILE /dir1/
done

it can copy all files in dir and subdirectories to the destination, but I cannot filter the file type.

Is there another way that can achieve what I want?

Upvotes: 2

Views: 5535

Answers (2)

Benjamin W.
Benjamin W.

Reputation: 52536

With the globstar1 and extglob shell options:

shopt -s globstar extglob
cp dir1/**/*.@(txt|jpg) dir2

The **/ expression matches zero or more directories or subdirectories, so you get files from the whole subtree of dir1; @(txt|jpg) is an extended pattern that matches either txt or jpg.

For the somewhat unlikely case that there are no .jpg and .txt files in any of dir1, but a file called *.@(txt|jpg) in a subdirectory of dir1 called **, you may also want to set the failglob shell option so the command is not executed if the glob doesn't match anything – instead of copying the unlikely file.


1 globstar was added in Bash 4.0 and is thus not available for the Bash that comes standard with Mac OS (3.2).

Upvotes: 1

heemayl
heemayl

Reputation: 42147

You can use find to get the desired source files, and then use cp within the -exec predicate of find to copy the files to the desired destination. With GNU cp:

find /dir1/ -type f \( -name '*.txt' -o -name '*.jpg' \) -exec cp -t /dir2/ {} + 

POSIX-ly:

find /dir1/ -type f \( -name '*.txt' -o -name '*.jpg' \) -exec cp {} /dir2/ \; 

Upvotes: 5

Related Questions