<?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: Stillwater Tools</title>
    <description>The latest articles on DEV Community by Stillwater Tools (@stillwatertools).</description>
    <link>https://dev.to/stillwatertools</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4223269%2Fe2a2cb00-a096-4f54-bddb-5c0bba8244ff.png</url>
      <title>DEV Community: Stillwater Tools</title>
      <link>https://dev.to/stillwatertools</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stillwatertools"/>
    <language>en</language>
    <item>
      <title>How to bulk rename files safely on Windows, macOS and Linux</title>
      <dc:creator>Stillwater Tools</dc:creator>
      <pubDate>Tue, 03 Nov 2026 01:07:53 +0000</pubDate>
      <link>https://dev.to/stillwatertools/how-to-bulk-rename-files-safely-on-windows-macos-and-linux-i96</link>
      <guid>https://dev.to/stillwatertools/how-to-bulk-rename-files-safely-on-windows-macos-and-linux-i96</guid>
      <description>&lt;p&gt;Renaming hundreds of files takes seconds. Undoing a bad rename can be impossible. Here is how to do it on Windows, macOS and Linux without losing anything, with the free built-in options first.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: this article was written with AI help (Claude), and every command below was run before publishing; the output shown is real. We make TidyBatch, a free command-line tool mentioned at the end, which has a paid Pro version (9 €).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The three rules
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Preview before you apply.&lt;/strong&gt; Every option below has a way to see the result first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never let a rename overwrite a file.&lt;/strong&gt; If two files end up with the same name, one of them can silently disappear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Have a way back.&lt;/strong&gt; A backup, a copy of the folder, or a tool with undo.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Windows
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;File Explorer.&lt;/strong&gt; Select the files, press F2, type a name and press Enter. Windows names them &lt;code&gt;Name (1)&lt;/code&gt;, &lt;code&gt;Name (2)&lt;/code&gt;, … Fine for quick numbering, but no preview and no patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PowerToys PowerRename&lt;/strong&gt; (free, from Microsoft). Install &lt;a href="https://learn.microsoft.com/en-us/windows/powertoys/powerrename" rel="noopener noreferrer"&gt;Microsoft PowerToys&lt;/a&gt;, select files, right-click, &lt;em&gt;Rename with PowerRename&lt;/em&gt;. Live preview, regular expressions, numbering and date variables. Ctrl+Z in Explorer undoes the batch right afterwards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PowerShell.&lt;/strong&gt; Add &lt;code&gt;-WhatIf&lt;/code&gt; to preview:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Preview: lowercase all .jpg names and replace spaces with underscores&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="nf"&gt;jpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rename-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NewName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-replace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-WhatIf&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Looks right? Run the same line without -WhatIf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="nf"&gt;jpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rename-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NewName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-replace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With two files, &lt;code&gt;Holiday Photo.JPG&lt;/code&gt; and &lt;code&gt;Beach Day.JPG&lt;/code&gt;, the &lt;code&gt;-WhatIf&lt;/code&gt; line prints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What if: Performing the operation "Rename File" on target "Item: …/Beach Day.JPG Destination: …/beach_day.jpg".
What if: Performing the operation "Rename File" on target "Item: …/Holiday Photo.JPG Destination: …/holiday_photo.jpg".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Rename-Item&lt;/code&gt; refuses to replace an existing file (&lt;code&gt;Rename-Item: The file '…/a_b.jpg' already exists.&lt;/code&gt;). Good, but in a long batch a few files fail halfway through, so read the red errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  macOS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Finder.&lt;/strong&gt; Select the files, right-click, &lt;em&gt;Rename…&lt;/em&gt;. &lt;em&gt;Replace Text&lt;/em&gt;, &lt;em&gt;Add Text&lt;/em&gt; or &lt;em&gt;Format&lt;/em&gt; with a counter, with an example of the result. &lt;em&gt;Edit → Undo&lt;/em&gt; straight away if it is wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal.&lt;/strong&gt; Use &lt;code&gt;mv -n&lt;/code&gt; (no-clobber) and print the commands before you run them:&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;# Preview (echo only), then remove "echo" to run&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;f &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.JPG&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo mv&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;%.JPG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.jpg"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; IMG_1.JPG IMG_1.jpg
&lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; Photo One.JPG Photo One.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Linux
&lt;/h2&gt;

&lt;p&gt;There are two different &lt;code&gt;rename&lt;/code&gt; commands (Perl and util-linux) with different syntax. Run &lt;code&gt;rename --version&lt;/code&gt; to see which you have. The util-linux one only prints the plan with &lt;code&gt;-v&lt;/code&gt;:&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;# Perl rename (Debian/Ubuntu "rename" package): spaces -&amp;gt; underscores&lt;/span&gt;
rename &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'s/ /_/g'&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="c"&gt;# rename(My Trip 2.jpg, My_Trip_2.jpg)&lt;/span&gt;
&lt;span class="c"&gt;# rename(Photo One.jpg, Photo_One.jpg)&lt;/span&gt;

&lt;span class="c"&gt;# util-linux rename (Arch, Fedora…): replace the first "IMG_" with "photo_"&lt;/span&gt;
rename &lt;span class="nt"&gt;-nv&lt;/span&gt; IMG_ photo_ &lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="c"&gt;# `IMG_1.JPG' -&amp;gt; `photo_1.JPG'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The trap: chains silently overwrite files
&lt;/h2&gt;

&lt;p&gt;Say you renumber &lt;code&gt;1.txt, 2.txt, 3.txt&lt;/code&gt; to &lt;code&gt;2.txt, 3.txt, 4.txt&lt;/code&gt;. A simple loop renames &lt;code&gt;1.txt → 2.txt&lt;/code&gt; first. On Linux and macOS a plain &lt;code&gt;mv&lt;/code&gt; or Python's &lt;code&gt;os.rename&lt;/code&gt; &lt;strong&gt;overwrites the original 2.txt without warning&lt;/strong&gt;. On Windows it fails instead, leaving the folder half renamed.&lt;/p&gt;

&lt;p&gt;The fix is two phases: move every file to a temporary name, then to its final name. Or rename into a new, empty folder. A related trap: on Windows and macOS &lt;code&gt;Photo.JPG&lt;/code&gt; and &lt;code&gt;photo.jpg&lt;/code&gt; are the &lt;em&gt;same&lt;/em&gt; file, so collision checks must ignore case.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tool that does this for you
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tidybatch.github.io/?utm_source=devto&amp;amp;utm_campaign=tidybatch" rel="noopener noreferrer"&gt;TidyBatch&lt;/a&gt; is a free, open-source command-line tool (we made it) built around these rules. It previews by default, renames in two phases, checks collisions without case, and keeps a journal so you can undo with one command, even after an interrupted run. Install it with &lt;code&gt;pipx install tidybatch&lt;/code&gt;, or try it without installing with &lt;code&gt;uvx tidybatch&lt;/code&gt;. On a folder with three files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tidybatch rename Downloads --slug --lower
  Café Menu.txt          -&amp;gt;  cafe_menu.txt
  Holiday Photo 1.JPG    -&amp;gt;  holiday_photo_1.jpg
  Report Final (v2).PDF  -&amp;gt;  report_final_v2.pdf

3 file(s) would change.
Dry run: nothing was changed. Add --apply to do it.

$ tidybatch rename Downloads --slug --lower --apply
  Café Menu.txt          -&amp;gt;  cafe_menu.txt
  Holiday Photo 1.JPG    -&amp;gt;  holiday_photo_1.jpg
  Report Final (v2).PDF  -&amp;gt;  report_final_v2.pdf

3 file(s) will change.
Done. To revert: tidybatch undo "Downloads"   (journal: journal-20261103-010602-321629.json)

$ tidybatch undo Downloads
Restored 3 file(s), skipped 0. Journal: journal-20261103-010602-321629.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It runs locally and needs no account. &lt;code&gt;rename&lt;/code&gt; and &lt;code&gt;undo&lt;/code&gt; are free; the paid Pro (9 €) adds &lt;code&gt;organize&lt;/code&gt; and &lt;code&gt;dedupe&lt;/code&gt;. More guides: &lt;a href="https://tidybatch.github.io/guides/?utm_source=devto&amp;amp;utm_campaign=tidybatch" rel="noopener noreferrer"&gt;tidybatch.github.io/guides&lt;/a&gt;. Code: &lt;a href="https://github.com/tidybatch/tidybatch" rel="noopener noreferrer"&gt;github.com/tidybatch/tidybatch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you only use Windows and like clicking, PowerRename is excellent and free. TidyBatch is for when you want the same command on every OS, in scripts, with an undo that survives closing the window.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>cli</category>
      <category>linux</category>
      <category>windows</category>
    </item>
  </channel>
</rss>
