Copying multiplies files into multiplies directories

Hello !

I have a file structure like this:

1_0/file1.tiff
1_1/file2.tiff
1_2/file3.tiff
1_3/file4.tiff
1_4/file5.tiff
1_5/file6.tiff
1_6/file7.tiff
2_0/file8.tiff
2_1/file9.tiff
2_2/file10.tiff
2_3/file11.tiff
etc.

There is only one file in one directory.
I'd like to have files from each folder starting from 1_ moved into folder 1, 2_ into 2 etc.
The final structure of directory would look like:
1/file1.tiff
1/file2.tiff
1/file3.tiff
1/file4.tiff
1/file5.tiff
1/file6.tiff
1/file7.tiff
2/file8.tiff
2/file9.tiff
2/file10.tiff
2/file11.tiff
etc.

I've tried with bash scripting, but without any success

Thank you in advance

No usability warranty

#! /bin/bash

# range of directories to look into, change as needed
for d in {1,2}_{1..6} 
do
    dst=$(echo "$d" | cut -d"_" -f1) # name of destination directory
    [ -d "$dst" ] || mkdir "$dst"    # create new directory if it does not exist
    cp "$d"/* "$dst"  2> /dev/null   # copy content to new directory
done

Just a visual example

1 Like

Thank You Aia !
This is quite nice.

Although, the problem is that the numeration of directories may be not contiguous:

$ ls | sort
33_0
33_1
33_2
33_3
33_4
33_5
33_6
39_0
39_1
39_2
39_3
39_4
39_5
39_6
41_0
41_1
41_2
41_3
41_4
41_5
41_6

Then obviously it creates additional empty folders.
I modified for loop like:

for d in {33..41}_{0..6} 

It would be great that it looks for the directories that actually exists, without typing them into the script manually, each time.

I want also to move the files, and delete source directories, which i suppose will be like:

#! /bin/bash

# range of directories to look into, change as needed
for d in {33..43}_{0..6} 
do
    dst=$(echo "$d" | cut -d"_" -f1) # name of destination directory
    [ -d "$dst" ] || mkdir "$dst"    # create new directory if it does not exist
    mv "$d"/* "$dst"  2> /dev/null   # copy content to new directory
    rm -R "$d"
done

Or maybe it will be easier to delete additional empty folders by:

find -depth -type d -empty -exec rmdir {} \;

?

Untested:

for dir in $(echo *_* | sed -e 's^_.*^^')
do
mkdir -p ${dir}
mv ${dir}_*/* ${dir}
done

BUG: directories whose names end in _ could pose a problem. I don't check for files with the same name either.

Hope this helps.

Andrew

Thank You Andrew.
Unfortunately, your script copies only one directory set (0...6) and then stops

$ ls -R
.:
11    11_1  11_3  11_5  17_0  17_2  17_4  17_6
11_0  11_2  11_4  11_6  17_1  17_3  17_5  sortBack2

./11:
ZN_000204_sRGB_g2.tiff  ZN_234121_sRGB_g2.tiff  ZN_235652_sRGB_g2.tiff
ZN_233105_sRGB_g2.tiff  ZN_234630_sRGB_g2.tiff
ZN_233613_sRGB_g2.tiff  ZN_235140_sRGB_g2.tiff

./11_0:

./11_1:

./11_2:

./11_3:

./11_4:

./11_5:

./11_6:

./17_0:
ZN_032122_sRGB_g2.tiff

./17_1:
ZN_032714_sRGB_g2.tiff

./17_2:
ZN_033307_sRGB_g2.tiff

./17_3:
ZN_033901_sRGB_g2.tiff

./17_4:
ZN_034455_sRGB_g2.tiff

./17_5:
ZN_035051_sRGB_g2.tiff

./17_6:
ZN_035648_sRGB_g2.tiff

If you can guarantee that every directory in . are part of the range, then you could

#! /bin/bash

# range of directories to look into, change as needed
for d in *                               # list everything under current directory
do
    if test -d "$d"; then                # if it's a directory
        dst=${d%%_*}                     # name of destination directory
        [ -d "$dst" ] || mkdir "$dst"    # create new directory if it does not exist
        cp "$d"/* "$dst"  2> /dev/null   # copy content to new directory
    fi
done

Yes, this is exactly what I was looking for!
Thank you one more time.

# range of directories to look into, change as needed
for d in *                               # list everything under current directory
do
    if test -d "$d"; then                # if it's a directory
        dst=${d%%_*}                     # name of destination directory
        [ -d "$dst" ] || mkdir "$dst"    # create new directory if it does not exist
        mv "$d"/* "$dst"  2> /dev/null   # move content to new directory
        rm -R "$d"                             # delete the source directory
    fi
done

Okay, I see where I went wrong - problem with posting without testing! If we use

ls -d1 *_* | sed -e 's^_.*^^' | uniq

instead of

echo *_* | sed -e 's^_.*^^'

it will pick up all the directories. But you have a solution that works now.

Andrew

:slight_smile:
I will have 2 versions, just in case...
Thanks !