<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aayush Goswami</title>
    <description>The latest articles on DEV Community by Aayush Goswami (@aayushgoswami).</description>
    <link>https://dev.to/aayushgoswami</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3935352%2F17ce883c-a7d3-4afd-ac02-7f99164404da.jpeg</url>
      <title>DEV Community: Aayush Goswami</title>
      <link>https://dev.to/aayushgoswami</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aayushgoswami"/>
    <language>en</language>
    <item>
      <title>I Built a Zero-Dependency Python CLI to Batch Rename Files — Here's How It Works</title>
      <dc:creator>Aayush Goswami</dc:creator>
      <pubDate>Sat, 16 May 2026 21:33:35 +0000</pubDate>
      <link>https://dev.to/aayushgoswami/i-built-a-zero-dependency-python-cli-to-batch-rename-files-heres-how-it-works-2ado</link>
      <guid>https://dev.to/aayushgoswami/i-built-a-zero-dependency-python-cli-to-batch-rename-files-heres-how-it-works-2ado</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5mdpn22rfw8z459h2nfh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5mdpn22rfw8z459h2nfh.gif" alt="rnmtool demo" width="800" height="450"&gt;&lt;/a&gt;## The problem I was tired of ignoring&lt;/p&gt;

&lt;p&gt;It was a Saturday afternoon. I had a folder of 80 files that looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;01 Project Notes.txt
02 Sales Data 2024.csv
03 AppConfig.JSON
04 helper SCRIPT.py
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I needed them to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2025_01_project_notes.txt
2025_02_sales_data_2024.csv
2025_03_appconfig.json
2025_04_helper_script.py
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rename them manually&lt;/strong&gt; — 80 files × 30 seconds = 40 minutes of mind-numbing clicking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a one-off Python script&lt;/strong&gt; — 20 minutes to write, works once, forgotten forever&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a GUI bulk renamer&lt;/strong&gt; — install something, learn its interface, probably overkill&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these felt right. I wanted something I could type in any terminal, from any folder, in one line — and never think about again.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;rnmtool&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is rnmtool?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;rnmtool&lt;/code&gt; is a command-line file renaming utility written in Python. It lets you batch rename files using a combination of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Find &amp;amp; replace&lt;/strong&gt; (plain text or regex)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case conversion&lt;/strong&gt; (lower, upper, title)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefix / suffix&lt;/strong&gt; injection&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extension swapping&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Glob pattern filtering&lt;/strong&gt; (only affect &lt;code&gt;.txt&lt;/code&gt; files, for example)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recursive directory renaming&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And most importantly: a &lt;strong&gt;&lt;code&gt;--dry-run&lt;/code&gt; mode&lt;/strong&gt; that shows you exactly what will change before you commit to anything.&lt;/p&gt;

&lt;p&gt;Zero external dependencies. Pure Python stdlib. Works on Windows, macOS, and Linux.&lt;/p&gt;




&lt;h2&gt;
  
  
  Installing it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pipx &lt;span class="nb"&gt;install &lt;/span&gt;rnmtool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Don't have pipx? &lt;code&gt;pip install pipx&lt;/code&gt; first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After that, &lt;code&gt;rnmtool&lt;/code&gt; is available globally — from any folder, any terminal session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rnmtool &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Let's walk through real examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The golden rule: always dry-run first
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rnmtool my_folder &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--find&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;--replace&lt;/span&gt; &lt;span class="s2"&gt;"_"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[rnmtool] DRY RUN — no files will be changed.

  BEFORE                        AFTER
  ────────────────────────────  ────────────────────────────────
  01 Project Notes.txt          01_Project_Notes.txt          ✓
  02 Sales Data 2024.csv        02_Sales_Data_2024.csv        ✓
  03 AppConfig.JSON             03_AppConfig.JSON             ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only after you're satisfied, drop &lt;code&gt;--dry-run&lt;/code&gt; to apply.&lt;/p&gt;




&lt;h3&gt;
  
  
  Replace spaces with underscores
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rnmtool my_folder &lt;span class="nt"&gt;--find&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;--replace&lt;/span&gt; &lt;span class="s2"&gt;"_"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Convert all filenames to lowercase
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rnmtool my_folder &lt;span class="nt"&gt;--case&lt;/span&gt; lower
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;03 AppConfig.JSON   →   03 appconfig.json
04 helper SCRIPT.py →   04 helper script.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Add a date prefix to every file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rnmtool my_folder &lt;span class="nt"&gt;--prefix&lt;/span&gt; &lt;span class="s2"&gt;"2025_"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;01 Project Notes.txt  →  2025_01 Project Notes.txt
02 Sales Data.csv     →  2025_02 Sales Data.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Fix inconsistent file extensions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rnmtool my_folder &lt;span class="nt"&gt;--pattern&lt;/span&gt; &lt;span class="s2"&gt;"*.JSON"&lt;/span&gt; &lt;span class="nt"&gt;--ext&lt;/span&gt; .json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;03 AppConfig.JSON  →  03 AppConfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Strip leading numbers using regex
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rnmtool my_folder &lt;span class="nt"&gt;--regex&lt;/span&gt; &lt;span class="nt"&gt;--find&lt;/span&gt; &lt;span class="s2"&gt;"^&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="s2"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;01 Project Notes.txt   →  Project Notes.txt
02 Sales Data.csv      →  Sales Data.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Stack multiple transformations in one command
&lt;/h3&gt;

&lt;p&gt;This is where it gets powerful. The transformations apply in a fixed order:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;find/replace → case → prefix/suffix → extension&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rnmtool my_folder &lt;span class="nt"&gt;--find&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;--replace&lt;/span&gt; &lt;span class="s2"&gt;"_"&lt;/span&gt; &lt;span class="nt"&gt;--case&lt;/span&gt; lower &lt;span class="nt"&gt;--prefix&lt;/span&gt; &lt;span class="s2"&gt;"2025_"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;01 Project Notes.txt     →  2025_01_project_notes.txt
02 Sales Data 2024.csv   →  2025_02_sales_data_2024.csv
04 helper SCRIPT.py      →  2025_04_helper_script.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the exact transformation I needed on that Saturday — in one command.&lt;/p&gt;




&lt;h3&gt;
  
  
  Run from inside the target folder (no directory argument needed)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /path/to/my/messy/folder
rnmtool &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--case&lt;/span&gt; lower
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The directory argument defaults to &lt;code&gt;.&lt;/code&gt; (current folder). So you can &lt;code&gt;cd&lt;/code&gt; into any folder and just run &lt;code&gt;rnmtool&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How it compares to existing tools
&lt;/h2&gt;

&lt;p&gt;I know what you're thinking — tools like &lt;a href="https://github.com/ayoisaiah/f2" rel="noopener noreferrer"&gt;f2&lt;/a&gt; exist. And they're great. f2 is feature-rich and supports EXIF/ID3 metadata renaming, undo operations, and more.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;rnmtool&lt;/code&gt; is aimed at a different use case:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;rnmtool&lt;/th&gt;
&lt;th&gt;f2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pipx install rnmtool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Binary download&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies&lt;/td&gt;
&lt;td&gt;Zero (stdlib only)&lt;/td&gt;
&lt;td&gt;Go runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undo support&lt;/td&gt;
&lt;td&gt;❌ (dry-run instead)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metadata renaming (EXIF/ID3)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everyday file renaming&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;--dry-run&lt;/code&gt; preview&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you're already in a Python environment and want something you can install and forget — &lt;code&gt;rnmtool&lt;/code&gt; is for you. If you need EXIF/ID3-based renaming for media files, use f2.&lt;/p&gt;




&lt;h2&gt;
  
  
  How it's built
&lt;/h2&gt;

&lt;p&gt;The tool is ~200 lines of pure Python using only the standard library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;argparse&lt;/code&gt; — CLI interface&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pathlib&lt;/code&gt; — file system operations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;re&lt;/code&gt; — regex support&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;os&lt;/code&gt; — extension splitting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The src layout looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
└── rnmtool/
    ├── __init__.py
    └── __main__.py   ← everything lives here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core logic is split into three clean functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;collect_files&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;         &lt;span class="c1"&gt;# glob matching + recursive search
&lt;/span&gt;&lt;span class="nf"&gt;apply_transformations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# all rename logic in one pipeline
&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                   &lt;span class="c1"&gt;# orchestrates dry-run vs. real run
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transformation pipeline is intentional — by fixing the order (find/replace → case → prefix/suffix → extension), users get predictable, composable behavior without having to think about ordering themselves.&lt;/p&gt;




&lt;h2&gt;
  
  
  Included: a test folder to play with
&lt;/h2&gt;

&lt;p&gt;The repo ships with a &lt;code&gt;test_files/&lt;/code&gt; folder containing 12 dummy files of varied types — &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.csv&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;, &lt;code&gt;.py&lt;/code&gt;, &lt;code&gt;.md&lt;/code&gt;, &lt;code&gt;.html&lt;/code&gt;, &lt;code&gt;.XML&lt;/code&gt;, &lt;code&gt;.log&lt;/code&gt;, &lt;code&gt;.yaml&lt;/code&gt;, &lt;code&gt;.sql&lt;/code&gt;, &lt;code&gt;.bat&lt;/code&gt;, &lt;code&gt;.ini&lt;/code&gt; — specifically designed to let you safely experiment with every feature without touching real files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the repo and try it immediately&lt;/span&gt;
git clone https://github.com/AayushGoswami/rnmtool.git
&lt;span class="nb"&gt;cd &lt;/span&gt;rnmtool
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
rnmtool test_files &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--case&lt;/span&gt; lower
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install&lt;/span&gt;
pipx &lt;span class="nb"&gt;install &lt;/span&gt;rnmtool

&lt;span class="c"&gt;# Preview renaming every file in a folder&lt;/span&gt;
rnmtool /your/folder &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--find&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;--replace&lt;/span&gt; &lt;span class="s2"&gt;"_"&lt;/span&gt; &lt;span class="nt"&gt;--case&lt;/span&gt; lower

&lt;span class="c"&gt;# Apply when satisfied&lt;/span&gt;
rnmtool /your/folder &lt;span class="nt"&gt;--find&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;--replace&lt;/span&gt; &lt;span class="s2"&gt;"_"&lt;/span&gt; &lt;span class="nt"&gt;--case&lt;/span&gt; lower
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;strong&gt;&lt;a href="https://github.com/AayushGoswami/rnmtool" rel="noopener noreferrer"&gt;AayushGoswami/rnmtool&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
PyPI: &lt;strong&gt;&lt;a href="https://pypi.org/project/rnmtool" rel="noopener noreferrer"&gt;pypi.org/project/rnmtool&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;If you've ever spent more than 5 minutes manually renaming files, give it a try. And if you find a bug or have a feature idea, &lt;a href="https://github.com/AayushGoswami/rnmtool/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; — contributions are very welcome.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Python's standard library — zero dependencies required.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>cli</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
