How do I rename the extension for a bunch of files?

BashRenameFile Rename

Bash Problem Overview


In a directory, I have a bunch of *.html files. I'd like to rename them all to *.txt

How can I do that? I use the bash shell.

Bash Solutions


Solution 1 - Bash

If using bash, there's no need for external commands like sed, basename, rename, expr, etc.

for file in *.html
do
  mv "$file" "${file%.html}.txt"
done

Solution 2 - Bash

For an better solution (with only bash functionality, as opposed to external calls), see one of the other answers.


The following would do and does not require the system to have the rename program (although you would most often have this on a system):

for file in *.html; do
    mv "$file" "$(basename "$file" .html).txt"
done

EDIT: As pointed out in the comments, this does not work for filenames with spaces in them without proper quoting (now added above). When working purely on your own files that you know do not have spaces in the filenames this will work but whenever you write something that may be reused at a later time, do not skip proper quoting.

Solution 3 - Bash

rename 's/\.html$/\.txt/' *.html

does exactly what you want.

Solution 4 - Bash

This worked for me on OSX from .txt to .txt_bak

find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \;

Solution 5 - Bash

You want to use rename :

rename -S <old_extension> <new_extension> <files>

rename -S .html .txt *.html

This does exactly what you want - it will change the extension from .html to .txt for all files matching *.html.

Note: Greg Hewgill correctly points out this is not a bash builtin; and is a separate Linux command. If you just need something on Linux this should work fine; if you need something more cross-platform then take a look at one of the other answers.

Solution 6 - Bash

On a Mac...

  1. Install rename if you haven't: brew install rename
  2. rename -S .html .txt *.html

Solution 7 - Bash

For Ubuntu Users :

rename 's/\.html$/\.txt/' *.html

Solution 8 - Bash

This is the slickest solution I've found that works on OSX and Linux, and it works nicely with git too!

find . -name "*.js" -exec bash -c 'mv "$1" "${1%.js}".tsx' - '{}' \;

and with git:

find . -name "*.js" -exec bash -c 'git mv "$1" "${1%.js}".tsx' - '{}' \;

Solution 9 - Bash

This question explicitly mentions Bash, but if you happen to have ZSH available it is pretty simple:

zmv '(*).*' '$1.txt'

If you get zsh: command not found: zmv then simply run:

autoload -U zmv

And then try again.

Thanks to this original article for the tip about zmv.

Solution 10 - Bash

Here is an example of the rename command:

rename -n ’s/\.htm$/\.html/’ *.htm

The -n means that it's a test run and will not actually change any files. It will show you a list of files that would be renamed if you removed the -n. In the case above, it will convert all files in the current directory from a file extension of .htm to .html.

If the output of the above test run looked ok then you could run the final version:

rename -v ’s/\.htm$/\.html/’ *.htm

The -v is optional, but it's a good idea to include it because it is the only record you will have of changes that were made by the rename command as shown in the sample output below:

$ rename -v 's/\.htm$/\.html/' *.htm
3.htm renamed as 3.html
4.htm renamed as 4.html
5.htm renamed as 5.html

The tricky part in the middle is a Perl substitution with regular expressions, highlighted below:

rename -v ’s/\.htm$/\.html/’ *.htm

Solution 11 - Bash

One line, no loops:

ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}

Example:

$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.json  ac8453e2-0d82-4d43-b80e-205edb754700.json
$ ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}
$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.txt  ac8453e2-0d82-4d43-b80e-205edb754700.txt

Solution 12 - Bash

The command mmv seems to do this task very efficiently on a huge number of files (tens of thousands in a second). For example, to rename all .xml files to .html files, use this:

mmv ";*.xml" "#1#2.html"

the ; will match the path, the * will match the filename, and these are referred to as #1 and #2 in the replacement name.

Answers based on exec or pipes were either too slow or failed on a very large number of files.

Solution 13 - Bash

Try this

rename .html .txt *.html 

usage:

rename [find] [replace_with] [criteria]

Solution 14 - Bash

After someone else's website crawl, I ended up with thousands of files missing the .html extension, across a wide tree of subdirectories.

To rename them all in one shot, except the files already having a .html extension (most of them had none at all), this worked for me:

cd wwwroot
find . -xtype f \! -iname *.html   -exec mv -iv "{}"  "{}.html"  \;  # batch rename files to append .html suffix IF MISSING

In the OP's case I might modify that slightly, to only rename *.txt files, like so:

find . -xtype f  -iname *.txt   -exec filename="{}"  mv -iv ${filename%.*}.{txt,html}  \; 

Broken down (hammertime!):

-iname *.txt

  • Means consider ONLY files already ending in .txt

mv -iv "{}.{txt,html}"

  • When find passes a {} as the filename, ${filename%.*} extracts its basename without any extension to form the parameters to mv. bash takes the {txt,html} to rewrite it as two parameters so the final command runs as: mv -iv "filename.txt" "filename.html"

Fix needed though: dealing with spaces in filenames

Solution 15 - Bash

This is a good way to modify multiple extensions at once:

for fname in *.{mp4,avi}
do
   mv -v "$fname" "${fname%.???}.mkv"
done

Note: be careful at the extension size to be the same (the ???)

Solution 16 - Bash

A bit late to the party. You could do it with xargs:

ls *.html | xargs -I {} sh -c 'mv $1 `basename $1 .html`.txt' - {}

Or if all your files are in some folder

ls folder/*.html | xargs -I {} sh -c 'mv $1 folder/`basename $1 .html`.txt' - {}

Solution 17 - Bash

Rename file extensions for all files under current directory and sub directories without any other packages (only use shell script):

  1. Create a shell script rename.sh under current directory with the following code:

     #!/bin/bash
    
     for file in $(find . -name "*$1"); do
       mv "$file" "${file%$1}$2"
     done
    
  2. Run it by ./rename.sh .old .new.

Eg. ./rename.sh .html .txt

Solution 18 - Bash

If you prefer PERL, there is a short PERL script (originally written by Larry Wall, the creator of PERL) that will do exactly what you want here: tips.webdesign10.com/files/rename.pl.txt.

For your example the following should do the trick:

rename.pl 's/html/txt/' *.html

Solution 19 - Bash

Nice & simple!

find . -iname *.html  -exec mv {} "$(basename {} .html).text"  \;

Solution 20 - Bash

Similarly to what was suggested before, this is how I did it:

find . -name '*OldText*' -exec sh -c 'mv "$0" "${0/OldText/NewText}"' {} \;

I first validated with

find . -name '*OldText*' -exec sh -c 'echo mv "$0" "${0/OldText/NewText}"' {} \;

Solution 21 - Bash

Here is what i used to rename .edge files to .blade.php

for file in *.edge; do     mv "$file" "$(basename "$file" .edge).blade.php"; done

Works like charm.

Solution 22 - Bash

You can also make a function in Bash, add it to .bashrc or something and then use it wherever you want.

change-ext() {
    for file in *.$1; do mv "$file" "$(basename "$file" .$1).$2"; done
}

Usage:

change-ext css scss

Source of code in function: https://stackoverflow.com/a/1224786/6732111

Solution 23 - Bash

The easiest way is to use rename.ul it is present in most of the Linux distro

rename.ul -o -v [oldFileExtension] [newFileExtension] [expression to search for file to be applied with]

rename.ul -o -v .oldext .newext *.oldext

Options:

-o: don't overwrite preexisting .newext

-v: verbose

-n: dry run

Solution 24 - Bash

Unfortunately it's not trivial to do portably. You probably need a bit of expr magic.

for file in *.html; do echo mv -- "$file" "$(expr "$file" : '\(.*\)\.html').txt"; done

Remove the echo once you're happy it does what you want.

Edit: basename is probably a little more readable for this particular case, although expr is more flexible in general.

Solution 25 - Bash

Here is a solution, using AWK. Make sure the files are present in the working directory. Else, cd to the directory where the html files are located and then execute the below command:

for i in $(ls | grep .html); do j=$(echo $i | grep -oh "^\w*." | awk '{print $1"txt"}'); mv $i $j; done

Solution 26 - Bash

I wrote this code in my .bashrc

alias find-ext='read -p "Path (dot for current): " p_path; read -p "Ext (unpunctured): " p_ext1; find $p_path -type f -name "*."$p_ext1'
alias rename-ext='read -p "Path (dot for current): " p_path; read -p "Ext (unpunctured): " p_ext1; read -p "Change by ext. (unpunctured): " p_ext2; echo -en "\nFound files:\n"; find $p_path -type f -name "*.$p_ext1"; find $p_path -type f -name "*.$p_ext1" -exec sh -c '\''mv "$1" "${1%.'\''$p_ext1'\''}.'\''$p_ext2'\''" '\'' _ {} \;; echo -en "\nChanged Files:\n"; find $p_path -type f -name "*.$p_ext2";'

In a folder like "/home/<user>/example-files" having this structure:

  • /home/<user>/example-files:
    • file1.txt
    • file2.txt
    • file3.pdf
    • file4.csv

The commands would behave like this:

~$ find-text
Path (dot for current): example-files/
Ext (unpunctured): txt

example-files/file1.txt
example-files/file2.txt


~$ rename-text
Path (dot for current): ./example-files
Ext (unpunctured): txt
Change by ext. (unpunctured): mp3

Found files:
./example-files/file1.txt
./example-files/file1.txt

Changed Files:
./example-files/file1.mp3
./example-files/file1.mp3
~$

Solution 27 - Bash

You could use a tool designed for renaming files in bulk, e.g. renamer.

To rename all file extensions in the current folder:

$ renamer --find ".html" --replace ".txt" --dry-run * 

Many more usage examples here.

Solution 28 - Bash

In Linux or window git bash or window's wsl, try below command to change every file's extension in current directory or sub-directories or even their sub-directories with just one line of code

find . -depth -name "*.html" -exec sh -c 'mv "$1" "${1%.html}.txt"' _ {} \;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionbmw0128View Question on Stackoverflow
Solution 1 - Bashghostdog74View Answer on Stackoverflow
Solution 2 - BashMikael AunoView Answer on Stackoverflow
Solution 3 - BashAmberView Answer on Stackoverflow
Solution 4 - BashSteven LizarazoView Answer on Stackoverflow
Solution 5 - BashDaveRView Answer on Stackoverflow
Solution 6 - BashizilottiView Answer on Stackoverflow
Solution 7 - BashBheru Lal LoharView Answer on Stackoverflow
Solution 8 - BashbdombroView Answer on Stackoverflow
Solution 9 - BashMichael LeonardView Answer on Stackoverflow
Solution 10 - BashA.AView Answer on Stackoverflow
Solution 11 - BashChristian BongiornoView Answer on Stackoverflow
Solution 12 - BashRoko MijicView Answer on Stackoverflow
Solution 13 - BashP SreedharView Answer on Stackoverflow
Solution 14 - BashMarcosView Answer on Stackoverflow
Solution 15 - BashNick De GreekView Answer on Stackoverflow
Solution 16 - BashespView Answer on Stackoverflow
Solution 17 - BashNeo LiuView Answer on Stackoverflow
Solution 18 - BashdudusanView Answer on Stackoverflow
Solution 19 - BashDeanoView Answer on Stackoverflow
Solution 20 - BashCarl BoschView Answer on Stackoverflow
Solution 21 - BashNixon KosgeiView Answer on Stackoverflow
Solution 22 - BashJ KluseczkaView Answer on Stackoverflow
Solution 23 - BashCreatorGhostView Answer on Stackoverflow
Solution 24 - BashCB BaileyView Answer on Stackoverflow
Solution 25 - BashRohithView Answer on Stackoverflow
Solution 26 - BashPyetroView Answer on Stackoverflow
Solution 27 - BashLloydView Answer on Stackoverflow
Solution 28 - BashHaratView Answer on Stackoverflow