Bash – For each subfolder, sort files by name and rename them to sequential padded numbers (regardless of extension)

bashfilenamesrenamesort

I have the following directory structure:

.
├── event-a
│   ├── album-a
│   │   ├── a.jpg
│   │   └── x.png
│   └── album-b
│       ├── a.jpg
│       ├── x.png
│       └── y.gif
└── event-b
    ├── album-x
    │   ├── a.jpg
    │   └── x.png
    └── album-y
        ├── a.jpg
        ├── x.png
        └── y.gif

For each second-level subfolder (named album-foo in the example), I want to sort the files by name and rename them to sequential padded numbers, regardless of their extension. The folders may contain JPG, PNG or GIF images, and any file extensions should be preserved.

So, in this case, I’d like to get this result:

.
├── event-a
│   ├── album-a
│   │   ├── 01.jpg
│   │   └── 02.png
│   └── album-b
│       ├── 01.jpg
│       ├── 02.png
│       └── 03.gif
└── event-b
    ├── album-x
    │   ├── 01.jpg
    │   └── 02.png
    └── album-y
        ├── 01.jpg
        ├── 02.png
        └── 03.gif

The rename utility may be used if that makes anything easier.

The main problem is figuring out the number each file should get. Do I need to use a nested for loop to iterate over the event-x and album-x subfolders, then for each inner loop, keep track of the number myself, or is there some clever solution that I’m missing?

Best Answer

for dir in */*; do           # loop over the directories
    (                        # run in a subshell ...
        cd "$dir"            # ... so we don't have to cd back
        files=(*)            # store the filenames in a zero-indexed array

        for index in "${!files[@]}"; do
            file=${files[$index]}
            ext=${file##*.}
            newname=$(printf "%02d.%s" $((index+1)) "$ext")
            mv "$file" "$newname"
        done
    )
done

Suppose you have a file with no extension. In that case it will have the same name except with leading numbers (e.g. my_file => 05.my_file)

All non-hidden directory entries will be renamed, including directories.

Related Question