How to batch rename files in a directory from a list of names in a text file

Learn how to batch rename files in a directory from a list of names in a text file with practical examples, diagrams, and best practices. Covers shell, powershell, batch-file development techniques...

Batch Rename Files from a List: A Comprehensive Guide

Illustration of files being renamed from a list, showing old names transforming into new names.

Learn how to efficiently rename multiple files in a directory using a list of new names provided in a text file, covering both Linux/macOS (Bash) and Windows (PowerShell).

Renaming a large number of files manually can be a tedious and error-prone task. Whether you're organizing photos, standardizing document names, or processing data, automating the renaming process is a significant time-saver. This article will guide you through batch renaming files in a directory using a list of new names from a text file, providing solutions for both Linux/macOS (Bash) and Windows (PowerShell) environments.

Understanding the Core Concept

The fundamental idea behind this process is to establish a one-to-one mapping between existing files in a directory and a list of desired new names. This mapping is typically achieved by reading both the current filenames and the new names in a specific order (e.g., alphabetical, creation date, or a custom order). The new names are usually provided in a simple text file, with one new name per line. The script then iterates through these lists, applying the new name to the corresponding old file.

flowchart TD
    A[Start] --> B{Prepare Old Files List}
    B --> C[Prepare New Names List (Text File)]
    C --> D{Read Old File and New Name Pair}
    D -- For each pair --> E[Rename Old File to New Name]
    E --> D
    D -- No more pairs --> F[End]

Workflow for batch renaming files from a list.

Prerequisites and Setup

Before you begin, ensure you have the following:

  1. A directory with files to be renamed: For example, file1.txt, file2.txt, image.jpg.

  2. A text file containing the new names: Each new name should be on a separate line, in the exact order you want them applied to the old files. For instance, if your old files are sorted alphabetically and you want to rename them in that order, your new names list should also be in that corresponding order.

    Example new_names.txt:

    document_a.txt
    document_b.txt
    photo_c.jpg
    
  3. Backup your files: Always create a backup of your original files before performing any batch operations. This prevents accidental data loss if something goes wrong.

Batch Renaming in Linux/macOS (Bash)

In a Unix-like environment, you can use a combination of ls, read, and mv commands within a Bash script. The key is to ensure that the order of files read from the directory matches the order of names in your new_names.txt file. A common approach is to sort both lists alphabetically.

#!/bin/bash

# Directory containing the files to rename
TARGET_DIR="./my_files"
# Text file with new names, one per line
NEW_NAMES_FILE="./new_names.txt"

# Check if the directory exists
if [ ! -d "$TARGET_DIR" ]; then
    echo "Error: Directory '$TARGET_DIR' not found."
    exit 1
fi

# Check if the new names file exists
if [ ! -f "$NEW_NAMES_FILE" ]; then
    echo "Error: New names file '$NEW_NAMES_FILE' not found."
    exit 1
fi

# Get a sorted list of current files (adjust pattern if needed, e.g., *.txt)
OLD_FILES=($(ls -1v "$TARGET_DIR"/*))

# Read new names into an array
mapfile -t NEW_NAMES < "$NEW_NAMES_FILE"

# Check if the number of old files matches the number of new names
if [ ${#OLD_FILES[@]} -ne ${#NEW_NAMES[@]} ]; then
    echo "Error: Number of old files (${#OLD_FILES[@]}) does not match number of new names (${#NEW_NAMES[@]})."
    exit 1
fi

# Loop through and rename files
for i in "${!OLD_FILES[@]}"; do
    OLD_PATH="${OLD_FILES[$i]}"
    NEW_NAME="${NEW_NAMES[$i]}"
    NEW_PATH="$TARGET_DIR/$NEW_NAME"

    echo "Renaming \"$OLD_PATH\" to \"$NEW_PATH\""
    mv "$OLD_PATH" "$NEW_PATH"
done

echo "Batch renaming complete."

Bash script for batch renaming files.

Batch Renaming in Windows (PowerShell)

PowerShell offers powerful cmdlets for file system manipulation. We'll use Get-ChildItem to list files, Get-Content to read the new names, and Rename-Item to perform the renaming. Similar to Bash, ensuring the order of files and new names is crucial.

# Directory containing the files to rename
$targetDir = ".\my_files"
# Text file with new names, one per line
$newNamesFile = ".\new_names.txt"

# Check if the directory exists
if (-not (Test-Path $targetDir -PathType Container)) {
    Write-Error "Error: Directory '$targetDir' not found."
    exit
}

# Check if the new names file exists
if (-not (Test-Path $newNamesFile -PathType Leaf)) {
    Write-Error "Error: New names file '$newNamesFile' not found."
    exit
}

# Get a sorted list of current files (adjust filter if needed, e.g., *.txt)
$oldFiles = Get-ChildItem -Path $targetDir | Sort-Object Name

# Read new names into an array
$newNames = Get-Content -Path $newNamesFile

# Check if the number of old files matches the number of new names
if ($oldFiles.Count -ne $newNames.Count) {
    Write-Error "Error: Number of old files ($($oldFiles.Count)) does not match number of new names ($($newNames.Count))."
    exit
}

# Loop through and rename files
for ($i = 0; $i -lt $oldFiles.Count; $i++) {
    $oldFile = $oldFiles[$i]
    $newName = $newNames[$i]
    $newPath = Join-Path -Path $targetDir -ChildPath $newName

    Write-Host "Renaming '$($oldFile.FullName)' to '$newPath'"
    Rename-Item -Path $oldFile.FullName -NewName $newName -Force
}

Write-Host "Batch renaming complete."

PowerShell script for batch renaming files.

Advanced Considerations and Best Practices

While the provided scripts cover the basic scenario, real-world situations can be more complex. Consider these points:

  • File Extensions: The scripts assume the new names in new_names.txt include the desired file extension. If you only provide base names, you'll need to extract the original extension and append it.
  • Error Handling: The scripts include basic checks for directory and file existence, and matching counts. You might want to add more robust error handling, such as checking for duplicate new names or invalid characters.
  • Simulating Renames (Dry Run): Before executing the mv or Rename-Item commands, it's a good practice to perform a "dry run" where you only print what would be renamed without actually doing it. This helps verify your logic.
  • Handling Subdirectories: The current scripts only process files directly within the TARGET_DIR. To include subdirectories, you would need to modify the ls or Get-ChildItem commands (e.g., Get-ChildItem -Recurse). However, this complicates the mapping with a flat new_names.txt file.
  • Non-matching Counts: If the number of old files doesn't match the number of new names, the scripts will exit with an error. You might want to implement logic to handle this, such as skipping extra new names or leaving unmatched old files as they are.

Bash Dry Run

#!/bin/bash

... (same setup as before) ...

Loop through and print what would be renamed (DRY RUN)

for i in "${!OLD_FILES[@]}"; do OLD_PATH="${OLD_FILES[$i]}" NEW_NAME="${NEW_NAMES[$i]}" NEW_PATH="$TARGET_DIR/$NEW_NAME"

echo "DRY RUN: Would rename \"$OLD_PATH\" to \"$NEW_PATH\""
# mv "$OLD_PATH" "$NEW_PATH" # Commented out for dry run

done

echo "Dry run complete. No files were actually renamed."

PowerShell Dry Run

... (same setup as before) ...

Loop through and print what would be renamed (DRY RUN)

for ($i = 0; $i -lt $oldFiles.Count; $i++) { $oldFile = $oldFiles[$i] $newName = $newNames[$i] $newPath = Join-Path -Path $targetDir -ChildPath $newName

Write-Host "DRY RUN: Would rename '$($oldFile.FullName)' to '$newPath'"
# Rename-Item -Path $oldFile.FullName -NewName $newName -Force # Commented out for dry run

}

Write-Host "Dry run complete. No files were actually renamed."