0

I have a directory structure that follows this kind of pattern:

- Dir 01 (Disc 1) \
  - Dir 01 (Disc 1).iso
- Dir 01 (Disc 2) \
  - Dir 01 (Disc 2).iso
- Dir 01 (Disc 3) \
  - Dir 01 (Disc 3).iso

- Dir 02 (Disc 1) \
  - Dir 02 (Disc 1).iso
- Dir 02 (Disc 2) \
  - Dir 02 (Disc 2).iso
 
- Dir 02 (Disc 1) (A) \
  - Dir 02 (Disc 1) (A).iso
- Dir 02 (Disc 2) (A) \
  - Dir 02 (Disc 2) (A).iso

My goal is to end up with this structure:

- Dir 01 \
  - Dir 01 (Disc 1).iso
  - Dir 01 (Disc 2).iso
  - Dir 01 (Disc 3).iso

- Dir 02 \
  - Dir 02 (Disc 1).iso
  - Dir 02 (Disc 2).iso

- Dir 02 (A) \
  - Dir 02 (Disc 1) (A).iso
  - Dir 02 (Disc 2) (A).iso

I know there has to be a way to loop through these directories, match the file names and move everything into place, but I can't wrap my head around how to script it. Any pointers would be greatly appreciated.

2 Answers 2

0
Given that you specified the desired tree structure, I am adhering to it, but I cannot stress how critical it is to try to avoid spaces in directory and file names at all cost. If you do not require the spacing, and can also work with '_' in their place, let me know and I will provide an updated tree structure.

Initial tree:

tree
.
├── Dir 01 (Disc 1)
│   └── Dir 01 (Disc 1).iso
├── Dir 01 (Disc 2)
│   └── Dir 01 (Disc 2).iso
├── Dir 01 (Disc 3)
│   └── Dir 01 (Disc 3).iso
├── Dir 02 (Disc 1)
│   └── Dir 02 (Disc 1).iso
├── Dir 02 (Disc 1) (A)
│   └── Dir 02 (Disc 1) (A).iso
├── Dir 02 (Disc 2)
│   └── Dir 02 (Disc 2).iso
└── Dir 02 (Disc 2) (A)
    └── Dir 02 (Disc 2) (A).iso

8 directories, 7 files

Command to restructure it - you can leave the comments, but ensure you copy-paste it as one command.


find . -type f -iname '*iso' -exec bash -c '
    var="$1" ;                                                   # found filename variable
    bad_dir=$(dirname "$var" | grep -i "disc");                  # old directory name variable
    good_dir=$(echo "$bad_dir" | cut -d" " -f1,2,5- ) ;          # Only acts on dirnames with "disc"
     
    if [[ -n $good_dir ]] ; then                           
       mkdir -p "$good_dir" ;                                    # creates new proper dir  
       mv "$var" "$good_dir" ;                                   # mv file to new dir
       rmdir "$bad_dir"                                          # removes old bad dir
    fi 
' bash {} \;                 

Testing new directory tree structure:

tree .
.
├── Dir 01
│   ├── Dir 01 (Disc 1).iso
│   ├── Dir 01 (Disc 2).iso
│   └── Dir 01 (Disc 3).iso
├── Dir 02
│   ├── Dir 02 (Disc 1).iso
│   └── Dir 02 (Disc 2).iso
└── Dir 02 (A)
    ├── Dir 02 (Disc 1) (A).iso
    └── Dir 02 (Disc 2) (A).iso

4 directories, 7 files

Note:I added a check to ensure that re-runing the command wont destroy the current structure. Additionally, the above should work even for more complicated file and directory names, for instance:

├── Dir 01 (Disc 3) (A) (B) (C)
    └── Dir 01 (Disc 3) (A) (B) (C).iso
├── Dir 02 (Disc 1) (A) (B)
    └── Dir 02 (Disc 1) (A) (B).iso

will be restructured into:

├── Dir 01 (A) (B) (C)
│   └── Dir 01 (Disc 3) (A) (B) (C).iso
└── Dir 02 (A) (B)
    └── Dir 02 (Disc 1) (A) (B).iso
1
  • Thank you so much! I found that the piped cut command for setting the good_dir wasn't working for the various directory naming schemes, but I was able to fix it with a variable substitution: good_dir="${bad_dir% (Disc*)}" Commented Jan 29, 2023 at 7:42
0

With zsh:

autoload -U zmv
mkmv() { mkdir -p -- $2:h && mv -- "$@"; }
zmv -P mkmv -n '(*) [(]Disc <->[)](*)/(*.iso)' '$1$2/$3'

(where -n is for dry-run to show what would happen).

That gives:

mkmv 'Dir 01 (Disc 1)/Dir 01 (Disc 1).iso' 'Dir 01/Dir 01 (Disc 1).iso'
mkmv 'Dir 01 (Disc 2)/Dir 01 (Disc 2).iso' 'Dir 01/Dir 01 (Disc 2).iso'
mkmv 'Dir 01 (Disc 3)/Dir 01 (Disc 3).iso' 'Dir 01/Dir 01 (Disc 3).iso'
mkmv 'Dir 02 (Disc 1) (A)/Dir 02 (Disc 1) (A).iso' 'Dir 02 (A)/Dir 02 (Disc 1) (A).iso'
mkmv 'Dir 02 (Disc 1)/Dir 02 (Disc 1).iso' 'Dir 02/Dir 02 (Disc 1).iso'
mkmv 'Dir 02 (Disc 2) (A)/Dir 02 (Disc 2) (A).iso' 'Dir 02 (A)/Dir 02 (Disc 2) (A).iso'
mkmv 'Dir 02 (Disc 2)/Dir 02 (Disc 2).iso' 'Dir 02/Dir 02 (Disc 2).iso'

Where mkmv has been defined earlier as a function that moves files after having created the parent directory of the target.

You must log in to answer this question.

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