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.
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.
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.
ren *.a *.b
–
Mcdavid $()
instead of legacy backtick syntax. Improves readability, and makes syntax much less ambiguous when you have characters that would need to be backslash-escaped to be literal inside the command substitution with the latter. –
Cressler 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
"${file%.*}.txt"
, but this could be dangerous for files w/o an extension at all. –
Classicism $
inside the curly braces! –
Potage mv file{1,2}
works leading to this answer. Googling "linux batch rename" would have led me here directly... –
Nonviolence --
"operator": mv -- "$file" "${file%.html}.txt" That operator prevents file names that start with a '-' from being parsed by mv as arguments. –
Tew 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.
ren *.a *.b
–
Mcdavid $()
instead of legacy backtick syntax. Improves readability, and makes syntax much less ambiguous when you have characters that would need to be backslash-escaped to be literal inside the command substitution with the latter. –
Cressler rename 's/\.html$/\.txt/' *.html
does exactly what you want.
rename 's/jpg/png/' *.jpg
, this is easier to remember and type. It may cause error if there is a filename contains jpg, so I will check it first before typing. –
Cornel This worked for me on OSX from .txt to .txt_bak
find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \;
.txt
to .txt_bak
you just have to concatenate _bak
;) –
Dissertation .scss
to .sass
(after in-place conversion…): find . -name '*.scss' -exec sh -c 'mv "$0" "${0%.scss}.sass"' {} \;
–
Tartuffery 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.
rename
program is not related to bash
and is also not available on all platforms. I've only seen it on Linux. –
Omen rename -S .html .text *.html
where -S
stands for --subst-all
–
Mancuso rename -s .html .txt *.html
–
Cavour rename
tools with different options and different syntax, even if you have exactly the same base Linux (or FreeBSD etc) system as somebody else. What works depends on which rename
you have, if you have one at all. This is all nonstandard, so YMMV. –
Middlebreaker On a Mac...
brew install rename
rename -S .html .txt *.html
For Ubuntu Users :
rename 's/\.html$/\.txt/' *.html
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' - '{}' \;
xargs
you can simply add -P 10
and it will fork you command with up to 10 concurrent processes. Really good for handling large directories. Use of ls -1
was just an example of how to feed xargs
- you could use it with find too –
Jahdiel 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.
zmv '(*).html' '$1.txt'
to use the specific file extensions from the original question. –
Sacred 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"' _ {} \;
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
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
ls
or xargs
; for f in ./*; do mv "$f" "${f%.*}.swift; done
–
Middlebreaker 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.
Try this
rename .html .txt *.html
usage:
rename [find] [replace_with] [criteria]
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
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 ???)
Rename file extensions for all files under current directory and sub directories without any other packages (only use shell script):
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
Run it by ./rename.sh .old .new
.
Eg. ./rename.sh .html .txt
&
to your mv
, but then you could have 100s or 1000s of spawned processes. Using xargs
you can assure yourself that -P 20
will allow a max of 20 forked processes. –
Jahdiel for file in $(find ...)
is inherently broken for file names which contain whitespace or shell metacharacters. See mywiki.wooledge.org/BashFAQ/020 –
Middlebreaker 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' - {}
ls
. This command is ridiculous: it uselessly uses a glob with ls
, instead of directly using the glob. This will break with filenames containing spaces, quotes and (due to the lack of quotes) glob characters. –
Netsuke 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}"' {} \;
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
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
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.
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.
Nice & simple!
find . -iname *.html -exec mv {} "$(basename {} .html).text" \;
"$(basename {} .html).text"
gets expanded by the shell to {}.text
before find
runs; this is broken. –
Middlebreaker 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://mcmap.net/q/73358/-how-do-i-rename-the-extension-for-a-bunch-of-files
."$1"
should have quotes around it in both places). –
Middlebreaker 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
ls
in scripts and quote your variables. –
Middlebreaker I wrote this code in my .bashrc
alias find-ext='read -p "Path (dot for current): " p_path; read -p "Ext (no punctuation): " p_ext1; find $p_path -type f -name "*."$p_ext1'
alias rename-ext='read -p "Path (dot for current): " p_path; read -p "Ext (no punctuation): " p_ext1; read -p "Change by ext. (no punctuation): " 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:
The commands would behave like this:
~$ find-text
Path (dot for current): example-files/
Ext (no punctuation): txt
example-files/file1.txt
example-files/file2.txt
~$ rename-text
Path (dot for current): ./example-files
Ext (no punctuation): txt
Change by ext. (no punctuation): mp3
Found files:
./example-files/file1.txt
./example-files/file1.txt
Changed Files:
./example-files/file1.mp3
./example-files/file1.mp3
~$
© 2022 - 2024 — McMap. All rights reserved.