2

I have a directory tree that looks like this (simplified, in truth there are hundreds of folders):

.
├── a
│   └── b
│       └── a.h5
├── b
│   ├── b
│   │   └── e.h5
│   └── c
│       ├── a.h5
│       └── b.h5
├── c
│   └── b
│       └── a.h5
├── d
│   ├── a.h5
│   └── e.h5
└── e
    └── e.h5

Basically, some .h5 files are at depth 1 (ex. d/a.h5, e/e.h5) and some files are are depth 2 (ex. b/b/e.h5, b/c/b.h5, ...)

I would like to move up only the files at depth 2, so that they all lie at depth one, as in:

.
├── a
│   └── a.h5
├── b
│   ├── e.h5
│   ├── a.h5
│   └── b.h5
├── c
│   └── a.h5
├── d
│   ├── a.h5
│   └── e.h5
└── e
    └── e.h5

I know that */*/*.h5 matches the files i'm interested in (tested via ls */*/*.h5), but I tried mv */*/*.h5 */*.h5 and it made a mess.

Duplicate files would ideally be handled by renaming, but also prompting is okay. How should I procede?

P.S: I've seen:

But they both apply to single directories.

3

Going from your directory structure:

$ tree
.
├── a
│   └── b
│       └── a.h5
├── b
│   ├── b
│   │   └── e.h5
│   └── c
│       ├── a.h5
│       └── b.h5
├── c
│   └── b
│       └── a.h5
├── d
│   ├── a.h5
│   └── e.h5
└── e
    └── e.h5

12 directories, 8 files

Use this for loop:

$ for f in */*/*.h5; do mv -v -- "$f" "${f%/*}/../"; done
»a/b/a.h5“ -> »a/b/../a.h5“
»b/b/e.h5“ -> »b/b/../e.h5“
»b/c/a.h5“ -> »b/c/../a.h5“
»b/c/b.h5“ -> »b/c/../b.h5“
»c/b/a.h5“ -> »c/b/../a.h5“

The result:

$ tree
.
├── a
│   ├── a.h5
│   └── b
├── b
│   ├── a.h5
│   ├── b
│   ├── b.h5
│   ├── c
│   └── e.h5
├── c
│   ├── a.h5
│   └── b
├── d
│   ├── a.h5
│   └── e.h5
└── e
    └── e.h5

12 directories, 8 files

Explanation:

for f in */*/*.h5; do mv -v -- "$f" "${f%/*}/../"; done
  • for f in */*/*.h5 loops trough all the desired files
    • mv -v -- moves them, verbosely. -- prevents filenames with dashes to be interpreted as arguments.
    • "$f" the original filename
    • ${f%/*}/../ the name of the directory containing the file, ../ added. That path is interpreted as "one directory up".
3

This should be a start:

find . -mindepth 3 -maxdepth 3 -type f -execdir mv -i -v {} .. \;

the mv -i asks to overwrite existing files. -execdir changes to the directory of the file before doing the command.

1

try

 for x in */*/*.h5
 do
    mv "$x" "$(dirname $(dirname $x))"
 done

if you have no strange characters in your directory names.

Or, alternatively:

ls */*/*.h5 | awk -F/ '{print "mv \"%s\"  \"%s/%s\" \n",$0,$1,$3 ;}' | bash

you can remove | bash to get a preview.

  • Your for loop can deal with any file name, why did you add the extremely fragile awk/ls one? – terdon Oct 27 '15 at 13:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.