Search code examples
linuxbashdebianpattern-matching

Rename multiple files by prefix taken from folder names, bash


I have a sequence of folders containing mp4 files (one mp4 in one folder). Folders are numbered sequentially like this example:

.. ..
18. Lesson 18 - Sketching a design to cut out
19. Lesson 19 - How to create a sweep
.. ..

the .mp4 files inside these folders are named, respectively:

.. ..
1. Sketching a design to cut out.mp4
1. Creating a sweep.mp4
.. ...

So all .mp4 file names start with "1." regardless of the folder name. I want to rename all mp4 files with an ascending prefix taken from the folder number, i.e.

18. Sketching a design to cut out.mp4
19. Creating a sweep.mp4
.. ..

for this I want to use the following bash script:

for f in *.mp4; do mv "$f" "$(echo "$f" | sed s/1./MYNUMBER/)"; done

How to specify a sequential prefix taken from folder names instead of 'MYNUMBER'? Folder names and filenames both include whitespace. Possibly, there is another way though.


Solution

  • Using Perl's rename (usable in any OS):

    Hierarchy:

    tree
    .
    ├── 18. Lesson 18 - Sketching a design to cut out
    │   └── 1. Sketching a design to cut out.mp4
    └── 19. Lesson 19 - How to create a sweep
        └── 1. Creating a sweep.mp4
    
    2 directories, 2 files
    

    Code:

    rename -n 's@\./(\d+\.)[^/]+/\d+\.\s*(.*)@$1 $2@' ./*/*.mp4
    rmdir *
    ls -1
    

    Output:

    '18. Sketching a design to cut out.mp4'
    '19. Creating a sweep.mp4'
    

    The regular expression matches as follows:

    Node Explanation
    ( group and capture to \1:
    \d+ digits (0-9) (1 or more times (matching the most amount possible))
    \. .
    ) end of \1
    [^/]+ any character except: / (1 or more times (matching the most amount possible))
    / /
    \d+ digits (0-9) (1 or more times (matching the most amount possible))
    \. .
    \s* whitespace (\n, \r, \t, \f, and " ") (0 or more times (matching the most amount possible))
    ( group and capture to \2:
    .* any character except \n (0 or more times (matching the most amount possible))
    ) end of \2