The Computer Oracle

Rename a group of files with one command

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Track title: CC O Beethoven - Piano Sonata No 3 in C

--

Chapters
00:00 Rename A Group Of Files With One Command
00:19 Accepted Answer Score 51
01:21 Answer 2 Score 12
02:01 Answer 3 Score 12
02:32 Answer 4 Score 7
03:13 Answer 5 Score 4
03:28 Thank you

--

Full question
https://superuser.com/questions/8716/ren...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#unix #bash

#avk47



ACCEPTED ANSWER

Score 51


Or, you could use pure bash... (except for mv, that is..)

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

and avoid the nasty basename stuff. ;)

Bash has an extensive set of variable expansion options. The one used here, '%', removes the smallest matching suffix from the value of the variable. The pattern is a glob pattern, so ${file%.*} would also work. The '%%' operator removes the largest matching suffix, and is interchangeable in the example above, as the pattern is fixed, ${file%%.*}.html would turn a.b.htm into a.html though.

See the variable substition section of the bash manpage for more neat tricks. There's a lot that can be done within bash directly.




ANSWER 2

Score 12


rename(1) is a Perl utility that does exactly what you want. In this case:

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

or if you are using sub directories as well

(requires Bash 4.0 and the globstar setting: shopt -s globstar)

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




ANSWER 3

Score 12


There shouldn't be spaces, newlines or other whitespace in the filenames, but this version of freiheit's answer handles those. It also uses $() instead of backticks for readability along with other benefits.

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

Even better - for the special case of just adding on to the end:

for file in *.htm
do
    mv "$file" "${file}l"
done



ANSWER 4

Score 7


for file in *.htm; do
  mv $file `basename "$file" .htm`.html
done

Try it with an echo in front of the mv first time around.

The problem with your original is that "mv *.htm *.html" has the *s handled by the shell, so the mv command simply sees a list of all the .htm and .html files in the current directory. In other words, something like "mv foo.htm bar.htm stuff.htm six.htm file.htm". mv only knows how to handle more than 2 arguments if the last one is a directory.




ANSWER 5

Score 4


Yet another pure bash example using string replace.

for file in *.htm; do mv $file ${file/htm/html}; done

Extra - this replaces all the occurrences of a string

for file in *.htm; do mv $file ${file//htm/html}; done