Search folder, find and copy files to new folder corresponding file ending [duplicate]

I have manage to grab some data of a couple of hdd with photorec, but I can't figure out how the files are saved, and it not very convenient searching in those recup_dir.*. So my thought is to categorize by file endings. So all *.gif end up in /home/mike/photorec/12gb/sorted/gif or something like that. But I don't know how to search the root catalog, grab the file extension and move/cp to that folder (and if not present, create the folder).

This way I can just delete unnecessary folders/files like dll.

Lets say I have three folders:

~/photorec/80gb
~/photorec/120gb
~/photorec/100gb

Photorec creates a large amount of folder naming recup_dir.1, recup_dir.2 etc. like:

.
├── recup_dir.1
├── recup_dir.10
├── recup_dir.11
├── recup_dir.12
└── recup_dir.9
    ├── f21750248.jpg
    ├── f21750275.gif
    ├── f21750277.gif
    ├── f21750281.gif
    ├── f21750296.jpg

I want to cd 80gb, run a command or execute a bash script inside ~/photorec/80gb/ so that a new folder is created, sorted, and inside sorted I get all files from recup_dirs, sorted by the found files extensions.

.
├── recup_dir.1
├── recup_dir.10
├── recup_dir.11
├── recup_dir.12
├── sorted
    ├── gif
        ├── f21750275.gif
        ├── f21750277.gif
        ├── f21750281.gif
    ├── jpg
        ├── f21750248.jpg
        ├── f21750296.jpg

How can I achieve this?

Edit: This is not just photorec. It could be any folder ofc.


First, create some test files:

mkdir -p 80gb/recup_dir.{1,10,11,12,9}
touch 80gb/recup_dir.9/f00{1..3}.{jpg,png,gif}

This gives:

.
└── 80gb
    ├── recup_dir.1
    ├── recup_dir.10
    ├── recup_dir.11
    ├── recup_dir.12
    └── recup_dir.9
        ├── f001.gif
        ├── f001.jpg
        ├── f001.png
        ├── f002.gif
        ├── f002.jpg
        ├── f002.png
        ├── f003.gif
        ├── f003.jpg
        └── f003.png

Now:

find 80gb -type f -exec bash -c 'mkdir -p sorted/"${0##*.}"; mv "$0" sorted/"${0##*.}"' {} \;

$0 holds the current filename (the {} parameter to the scriptlet) and "${0##*.}" is the file's extension.

Result:

.
├── 80gb
│   ├── recup_dir.1
│   ├── recup_dir.10
│   ├── recup_dir.11
│   ├── recup_dir.12
│   └── recup_dir.9
└── sorted
    ├── gif
    │   ├── f001.gif
    │   ├── f002.gif
    │   └── f003.gif
    ├── jpg
    │   ├── f001.jpg
    │   ├── f002.jpg
    │   └── f003.jpg
    └── png
        ├── f001.png
        ├── f002.png
        └── f003.png

If you want the sorted directory below 80gb it might be easiest to do a cd 80gb first and then do find . … instead of find 80gb ….

Instead of mv you may first want to do cp instead in case anything goes wrong.

Caveat

The expression "${0##*.}" only works for files with an extension. For files without an extension it returns the complete filename (including the path) and the command will fail. If you expect files without extensions modify the command to:

find 80gb -type f -name "*.*" -exec … \;

so it catches only files with a dot in them.


Here’s a way which moves all files of one extension at once by using bash’s globstar option and looping over the different extensions:

shopt -s globstar
for i in $(find -type f -name "*.*" -printf '%p\n' | sed 's/.*\.//' | sort -u); do \
  mkdir -p sorted/"$i"; \
  mv **/*."$i" sorted/"$i"; \
done

The find | sed | sort command list creates a list of existing file extensions over which the for loop loops. For every extension, mkdir creates a directory under sorted/ and moves the matching files to it. **/ is the globstar pattern and matches (theoretically) infinite directories and subdirectories, see man bash/SHELL BUILTIN COMMANDS under shopt/globstar.

Example run

$ mkdir -p 80gb/recup_dir.{1,10,11,12,9}
$ touch 80gb/recup_dir.9/f00{1..3}.{jpg,png,gif}
$ tree
.
└── 80gb
    ├── recup_dir.1
    ├── recup_dir.10
    ├── recup_dir.11
    ├── recup_dir.12
    └── recup_dir.9
        ├── f001.gif
        ├── f001.jpg
        ├── f001.png
        ├── f002.gif
        ├── f002.jpg
        ├── f002.png
        ├── f003.gif
        ├── f003.jpg
        └── f003.png
$ shopt -s globstar; for i in $(find -type f -name "*.*" -printf '%p\n' | sed 's/.*\.//' | sort -u); do mkdir -p sorted/"$i"; mv **/*."$i" sorted/"$i"; done
$ tree
.
├── 80gb
│   ├── recup_dir.1
│   ├── recup_dir.10
│   ├── recup_dir.11
│   ├── recup_dir.12
│   └── recup_dir.9
└── sorted
    ├── gif
    │   ├── f001.gif
    │   ├── f002.gif
    │   └── f003.gif
    ├── jpg
    │   ├── f001.jpg
    │   ├── f002.jpg
    │   └── f003.jpg
    └── png
        ├── f001.png
        ├── f002.png
        └── f003.png