HiveBrain v1.2.0
Get Started
← Back to all entries
patternbashMinor

Bash script to rename subfolder to include name of parent folder

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
scriptincludeparentsubfoldernamefolderbashrename

Problem

Here's the current structure of my directory.

.
├── Show 1
│   ├── Season 1
│   └── Season 2
├── Show 2
   ├── Season 1
    └── Season 2


I want to rename the Season folders to include the name of the Show. The desired structure looks like this :

.
├── Show 1
│   ├── Show 1 - Season 1
│   └── Show 1 - Season 2
├── Show 2
   ├── Show 2 - Season 1
    └── Show 2 - Season 2


Here's the script I wrote :

# Parse through all show folders.
for show in /Users/sanjeetsuhag/Desktop/* ; do
# Check if it is a folder.
if [ -d "$show" ]; then
# Parse through all season folders.
for season in $show/* ; do
# Check if it is a folder.
if [ -d "$season" ]; then
mv $season "$show/$(basename "$show") - $(basename "$season")"
fi
done
fi
done


This is my first time scripting in Bash. Is there any thing I could improve ?

Solution

You should always double-quote variables that are used as filesystem paths.
This is the same script but with variables correctly double-quoted:

# Parse through all show folders.
for show in /Users/sanjeetsuhag/Desktop/*; do
    # Check if it is a folder.
    if [ -d "$show" ]; then
        # Parse through all season folders.
        for season in "$show"/*; do
            # Check if it is a folder.
            if [ -d "$season" ]; then               
                mv "$season" "$show/$(basename "$show") - $(basename "$season")" 
            fi      
        done
    fi
done


If you change the globs to end with /,
they will match only directories,
and so you can skip the directory checks:

for show in /Users/sanjeetsuhag/Desktop/*/; do
    for season in "$show"/*/; do
        mv "$season" "$show/$(basename "$show") - $(basename "$season")" 
    done
done


You could further optimize this by using pattern substitution instead of basename:

for show in /Users/sanjeetsuhag/Desktop/*/; do
    for season in "$show"/*/; do
        show=${show%/}
        season=${season%/}
        mv "$season" "$show/${show##*/} - ${season##*/}"
    done
done


The ${show%/} is to shave off the trailing /,
and the ${show##*/} is to delete everything until the last /.

Finally, instead of hardcoding the base path /Users/sanjeetsuhag/Desktop,
the script would be more reusable if you make that a command line parameter of the script.

Code Snippets

# Parse through all show folders.
for show in /Users/sanjeetsuhag/Desktop/*; do
    # Check if it is a folder.
    if [ -d "$show" ]; then
        # Parse through all season folders.
        for season in "$show"/*; do
            # Check if it is a folder.
            if [ -d "$season" ]; then               
                mv "$season" "$show/$(basename "$show") - $(basename "$season")" 
            fi      
        done
    fi
done
for show in /Users/sanjeetsuhag/Desktop/*/; do
    for season in "$show"/*/; do
        mv "$season" "$show/$(basename "$show") - $(basename "$season")" 
    done
done
for show in /Users/sanjeetsuhag/Desktop/*/; do
    for season in "$show"/*/; do
        show=${show%/}
        season=${season%/}
        mv "$season" "$show/${show##*/} - ${season##*/}"
    done
done

Context

StackExchange Code Review Q#151399, answer score: 3

Revisions (0)

No revisions yet.