Changing file extensions for all files in a directory on OS X
Asked Answered
C

12

89

I have a directory full of files with one extension (.txt in this case) that I want to automatically convert to another extension (.md).

Is there an easy terminal one-liner I can use to convert all of the files in this directory to a different file extension?

Or do I need to write a script with a regular expression?

Coady answered 15/2, 2013 at 1:55 Comment(0)
V
152

You could use something like this:

for old in *.txt; do mv $old `basename $old .txt`.md; done

Make a copy first!

Vivienne answered 15/2, 2013 at 2:11 Comment(8)
On Mavericks, this does not work for me, giving this output: usage: mv [-f | -i | -n] [-v] source target mv [-f | -i | -n] [-v] source ... directoryKeshiakesia
just tried it on Mavericks, and it works fine. This assumes you are using bash, the default shell.Vivienne
Works fine on Mavericks, if you run into permission issues just insert sudo before the whole line, or enter a su.Interment
This does not work for filenames with spaces in them without proper quoting.Dinorahdinosaur
$old should be enclosed in double quotes here, lest much havoc could be wreaked. Edit: The whole `basename ...` too.Intricate
With all the ways to get this wrong, I highly recommend the simple interactive Finder solution that Vicky posted instead.Enteron
Any way of making it recursive?Lynnette
@AlexandreCastro for old in **/*.txt; do mv $old "`dirname $old`/`basename $old .txt`.md"; doneCoumarin
S
83

Alternatively, you could install the ren (rename) utility

brew install ren

ren '*.txt' '#1.md'

If you want to rename files with prefix or suffix in file names

ren 'prefix_*.txt' 'prefix_#1.md'
Symbolism answered 13/2, 2015 at 7:24 Comment(3)
This is the best suggestion for command-line renaming of files. Thanks!Johanna
If you want to rename files with prefix or suffix in file names, you can use ren 'prefix_*.txt' 'prefix_#1.md'Inelastic
@Scorn #16935627Symbolism
S
49

Terminal is not necessary for this... Just highlight all of the files you want to rename. Right click and select "Rename ## items" and just type ".txt" into to the "Find:" box and ".md" into the "Replace with:" box.

Simoniac answered 29/1, 2015 at 2:49 Comment(7)
Yeah. This was great. In terminal: open . and then do this! Much easier.Pe
Whoa!! Never knew about this!Bloodthirsty
Nice find, but when renaming file extensions you typically have a lot of files to process. This method, on El Capitan, prompts you for each file asking if you really want to rename it.Carlottacarlovingian
I've just tried on El Capitan, and it didn't prompt me for anything. Just renamed with no questions....Chickie
Wow, that was slick. I would recommend this over the terminal solution.Raddled
Finder > Preferences > Advanced > Show warning before changing extensions.Scorn
On Big Sur it will warn you but you can check the "apply to all files" box and it works.Ivoryivorywhite
V
11

The preferred Unix way to do this (yes, OS X is based on Unix) is:

ls | sed 's/^\(.*\)\.txt$/mv "\1.txt" "\1.md"/' | sh

Why looping with for if ls by design loops through the whole list of filenames? You've got pipes, use them. You can create/modify not only output using commands, but also commands (right, that is commands created by a command, which is what Brian Kernighan, one of the inventors of Unix, liked most on Unix), so let's take a look what the ls and the sed produces by removing the pipe to sh:

$ ls | sed 's/^\(.*\)\.txt$/mv "\1.txt" "\1.md"/'
mv "firstfile.txt" "firstfile.md"
mv "second file.txt" "second file.md"
$

As you can see, it is not only an one-liner, but a complete script, which furthermore works by creating another script as output. So let's just feed the script produced by the one-liner script to sh, which is the script interpreter of OS X. Of course it works even for filenames with spaces in it.

BTW: Every time you type something in Terminal you create a script, even if it is only a single command with one word like ls or date etc. Everything running in a Unix shell is always a script/program, which is just some ASCII-based stream (in this case an instruction stream opposed to a data stream).

To see the actual commands being executed by sh, just add an -x option after sh, which turns on debugging output in the shell, so you will see every mv command being executed with the actual arguments passed by the sed editor script (yeah, another script inside the script :-) ).

However, if you like complexity, you can even use awk and if you like to install other programs to just do basic work, there is ren. I know even people who would prefer to write a 50-lines or so perl script for this simple every-day task.

Maybe it's easier in finder to rename files, but if connected remotely to a Mac (e.g. via ssh), using finder is not possible at all. That's why cmd line still is very useful.

Verlie answered 18/4, 2016 at 22:31 Comment(1)
This works nicely - to do it recursively, change 'ls' to 'find . -name "*.txt"'Pastern
K
11

You do not need a terminal for this one; here is a sample demonstration in MacOS Big Sur.

  • Select all the files, right-click and select "rename..." enter image description here

  • Add the existing file extension in "Find" and the extension you want to replace with "Replace with". enter image description here

And done!

Karlsruhe answered 5/4, 2021 at 5:49 Comment(0)
S
4

Based on the selected and most accurate answer above, here's a bash function for reusability:

function change_all_extensions() {
    for old in *."$1"; do mv $old `basename $old ."$1"`."$2"; done
}

Usage:

$ change_all_extensions txt md

(I couldn't figure out how to get clean code formatting in a comment on that answer.)

Snowball answered 14/8, 2015 at 23:49 Comment(0)
D
4

No need to write a script for it just hit this command

find ./ -name "*.txt" | xargs -I '{}' basename '{}' | sed 's/\.txt//' | xargs -I '{}' mv '{}.txt'  '{}.md'
Despotism answered 29/8, 2016 at 4:1 Comment(0)
C
1

I had a similar problem where files were named .gifx.gif at the end and this worked in OS X to remove the last .gif:

for old in *.gifx.gif; do
    mv $(echo "$old") $(echo "$old" | sed 's/x.gif//');
done
Camion answered 14/1, 2017 at 14:17 Comment(1)
This will modify a few more files than you intend if they have x?gif anywhere in the name (for example, maxsgift.gitx.git). This is best: sed s/\.gif$//'.Buffum
A
0
    cd $YOUR_DIR
    ls *.txt > abc
    mkdir target // say i want to move it to another directory target in this case
    while read line
    do 
    file=$(echo $line |awk -F. '{ print $1 }')
    cp $line target/$file.md  // depends if u want  to move(mv) or copy(cp)
    done < abc
Alitaalitha answered 21/2, 2013 at 8:57 Comment(0)
B
0

list=ls for file in $list do newf=echo $file|cut -f1 -d'.' echo "The newf is $newf" mv $file $newf.jpg done

Basque answered 15/12, 2020 at 23:30 Comment(0)
A
0

If you're using the zsh shell

autoload -U zmv
zmv '(**/)(*).txt' '$1$2.md'
Anglian answered 21/8, 2023 at 14:25 Comment(0)
T
0

Not sure if this was a mistake in the original accepted answer, but the original answer ADDS the .md file extension, it does not REPLACE the file extension. Also, the original answer would not work for filename with spaces in them. This worked for me:

for old in *.txt; do mv "$old" "`echo "${old%.*}"`.md"; done
Tower answered 7/6 at 15:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.