0

I have a directory l

── 10020
│   ├── live
│   │   ├── 211231.jpg
│   │   ├── 211231_BB.txt
│   │   ├── 448378.jpg
│   │   ├── 448378_BB.txt
│   │   ├── 460830.jpg
│   │   └── 460830_BB.txt
│   └── spoof
│       ├── 035383.jpg
│       ├── 035383_BB.txt
│       ├── 057847.jpg
│       ├── 057847_BB.txt
│       ├── 080343.jpg
│       ├── 080343_BB.txt
├── 10021
│   ├── live
│   │   ├── 013031.jpg
│   │   ├── 013031_BB.txt
│   │   ├── 025895.jpg
│   │   ├── 025895_BB.txt
│   └── spoof
│       ├── 006434.jpg
│       ├── 006434_BB.txt
│       ├── 021470.jpg
│       ├── 021470_BB.txt
│       ├── 027017.jpg
│       ├── 027017_BB.txt
├── 10022
│   ├── live
│   │   ├── 125401.jpg
│   │   ├── 125401_BB.txt
│   │   ├── 196573.jpg
│   │   └── 196573_BB.txt
│   └── spoof
│       ├── 013054.jpg
│       ├── 013054_BB.txt
│       ├── 015386.jpg
│       ├── 015386_BB.txt
│       ├── 016760.jpg
│       ├── 016760_BB.txt
│       ├── 020204.jpg
│       ├── 020204_BB.txt
├── 10023
│   ├── live
│   │   ├── 000240.jpg
│   │   ├── 000240_BB.txt
│   │   ├── 030384.jpg
│   │   ├── 030384_BB.txt
│   │   ├── 034898.jpg
│   │   ├── 034898_BB.txt
│   └── spoof
│       ├── 022241.jpg
│       ├── 022241_BB.txt
│       ├── 023855.jpg
│       ├── 023855_BB.txt
│       ├── 030252.jpg
│       ├── 030252_BB.txt
│       └── 475104_BB.txt
 [it goes on, as you guys suggested I put up the real directory rather than a simplified version]

I want to cp or mv all */live/*.jpg and */live/*.png into another directory like dir how can I achieve this?

Things I tried:

rsync -av ~/train/*/*.jpg dir
find ~train/ -type f -name '*/live/*.jpg' -exec cp '{}' dir ';'
rsync -a --include '*.jpg' --exclude 'live/*' ~/train/ dir
8
  • for find, use the -path or -ipath filter. Commented Jan 10, 2021 at 13:36
  • The first arg of find does not match the dir as stated in the question. Commented Jan 10, 2021 at 13:39
  • Do you want to keep the source path at the destination? If not, what's wrong with cp */real/*.jpeg */real/*.png dir/? Commented Jan 10, 2021 at 13:43
  • @roaima cp: cannot stat '*/real/*.jpeg': No such file or directory cp: cannot stat '*/real/*.png': No such file or directory
    – Moe
    Commented Jan 10, 2021 at 14:14
  • 1
    @roaima into a single directory
    – Moe
    Commented Jan 10, 2021 at 14:45

4 Answers 4

1

find -path '/media/data/woreom/dataset/CelebA_Spoof/Data/train /*/real/*.jpg' -type f -exec cp '{}' /media/data/woreom/dataset/dataset/real/ ';' does nothing.

This is because you asked to find /media/data/woreom/datase… in your current working directory.

You need to specify where to search, as first argument. So change to (I think this should do it.)

find /media/data/woreom/dataset/CelebA_Spoof/Data/train \
    -path '/*/real/*.jpg' -type f \
    -exec echo cp '{}' /media/data/woreom/dataset/dataset/real/ ';'

I added the word echo for testing, remove when it is working porperly.

1
  • this still does nothing :))
    – Moe
    Commented Jan 10, 2021 at 14:07
0

As I saw, in this case, there isn't any subdirectory with the name of real, so if you share your real directory name, maybe you have a little problem with your keywords. by the way, you can use "find" with structure @Kusalananda or using a for loop to cp your files and directories

0

This should work, assuming you adapt it to your directory structure and I understand you correctly.

user@user:~$ tree

├── dir
└── foo
    ├── 10021
    │   └── live
    │       ├── a.jpg
    │       ├── b.jpg
    │       ├── c.jpg
    │       └── d.jpg
    ├── 10022
    │   └── live
    │       ├── e.jpg
    │       └── f.jpg
    └── 10023
        └── live
            ├── g.jpg
            ├── h.jpg
            ├── i.jpg
            └── j.jpg

Now, placed into you home directory:

cp */live/*.{jpg,png} ~/dir/
0

You can let the shell do the heavy lifting with globbing wildcards

shopt -s nullglob
cp */live/*.jpg */live/*.png dir/

The first command tells the bash shell not to fail to expand patterns that don't exist but instead to strip them out as non-matches. (For example from your question, here are no png files in the 10020/live/ directory; normally that would mean the command would end up seeing the literal 10020/live/*.png which would fail to match as there is no png file with an asterisk as its name.)

If you don't run bash you can redirect the stderr output of the cp command to null (cp ... 2>/dev/null) so that you don't see the error messages generated by the invalid failure to expand patterns such as 10020/live/*.png, but you'll also redirect other error messages too so this should be a last step option.

If you really want a clean solution you could copy the files one by one, but it's less efficient and generally harder to read

for file in */live/*.jpg */live/*.png
do
    [ -f "$file" ] && cp "$file" dir/
done

You don't really need a trailing slash on dir/ but I tend to write it that way to make it crystal clear I'm intending dir to be a directory. (In the extreme event that you end up copying only one file when dir doesn't exist, using dir/ rather than just dir will safely fail by triggering an error instead of silently renaming the file to be dir.)

In both cases you can prefix echo to the cp command to see the command that would be executed without actually changing anyway (i.e. use echo cp … instead of just cp …)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .