How to Batch Rename Files in a macOS Terminal?
Solution 1
In your specific case you can use the following bash
command (bash
is the default shell on macOS):
for f in *.png; do echo mv "$f" "${f/_*_/_}"; done
Note: If there's a chance that your filenames start with -
, place --
before them[1]:
mv -- "$f" "${f/_*_/_}"
Note: echo
is prepended to mv
so as to perform a dry run. Remove it to perform actual renaming.
You can run it from the command line or use it in a script.
-
"${f/_*_/_}"
is an application ofbash
parameter expansion: the (first) substring matching pattern_*_
is replaced with literal_
, effectively cutting the middle token from the name. - Note that
_*_
is a pattern (a wildcard expression, as also used for globbing), not a regular expression (to learn about patterns, runman bash
and search forPattern Matching
).
If you find yourself batch-renaming files frequently, consider installing a specialized tool such as the Perl-based rename
utility.
On macOS you can install it using popular package manager Homebrew as follows:
brew install rename
Here's the equivalent of the command at the top using rename
:
rename -n -e 's/_.*_/_/' *.png
Again, this command performs a dry run; remove -n
to perform actual renaming.
- Similar to the
bash
solution,s/.../.../
performs text substitution, but - unlike inbash
- true regular expressions are used.
[1] The purpose of special argument --
, which is supported by most utilities, is to signal that subsequent arguments should be treated as operands (values), even if they look like options due to starting with -
, as Jacob C. notes.
Solution 2
To rename files, you can use the rename
utility:
brew install rename
For example, to change a search string in all filenames in current directory:
rename -nvs searchword replaceword *
Remove the 'n' parameter to apply the changes.
More info: man rename
Solution 3
You could use sed:
ls * | sed -e 'p;s@_.*_@_@g' | xargs -n2 mv
result:
prefix_567.png prefix_efg.png
*to do a dry-run first, replace mv
at the end with echo
Explanation:
- e: optional for only 1 sed command.
- p: to print the input to sed, in this case it will be the original file name before any renaming
- @: is a replacement of / character to make sed more readable. That is, instead of using sed s/search/replace/g, use s@search@replace@g
- _.* : the underscore is an escape character to refer to the actual '.' character zero or more times (as opposed to ANY character in regex)
- -n2: indicates that there are 2 outputs that need to be passed on to mv as parameters. for each input from ls, this sed command will generate 2 output, which will then supplied to mv.
Solution 4
I had a batch of files that looked like this: be90-01.png and needed to change the dash to underscore. I used this, which worked well:
for f in *; do mv "$f" "`echo $f | tr '-' '_'`"; done
Solution 5
you can install rename
command by using brew
. just do brew install rename
and use it.
kidnim
Updated on May 08, 2021Comments
-
kidnim about 3 years
I have a folder with a series of files named:
prefix_1234_567.png prefix_abcd_efg.png
I'd like to batch remove one underscore and the middle content so the output would be:
prefix_567.png prefix_efg.png
Relevant but not completely explanatory:
-
Grady Player about 10 yearslook at NSString and NSMutableString's range and substring methods
-
Encryptic about 10 yearsHave you considered non-terminal solutions to this? An Automator workflow can perform these types of operations with ease. You could create an automator workflow to rename all of the files and replace the text with
_*_
with a blank. -
kidnim about 10 yearsi thought automator couldn't do wildcards
-
-
mklement0 about 10 yearsClever, if somewhat arcane solution. Making this more general, so as to also support filenames with embedded spaces, gets even more arcane:
ls * | xargs -I % bash -c 'echo mv "%" "$(sed 's@_.*_@_@' <<<"%")"'
(removeecho
to actually rename). -
kidnim about 10 yearsgreat answer, worked perfectly. i also appreciate that you went back and edited it to explain it more and provide a more elegant solution if i repeat this. again, much thanks, very helpful
-
l'L'l almost 9 years
OS X
versions ofGNU bash
(x86_64-apple-darwin) doesn't include the rename utility. -
David Thomas almost 9 yearsThanks, yes it needs to be installed via
brew install rename
-
Steve Robbins over 8 yearsAn example using matched replacements (
.*
->$1
), e.g. RenameFoo bar S01E01 biz baz.ext
toS01E01.ext
:rename -n -e 's/.*(S[0-9]{2}E[0-9]{2}).*(\.[a-z]{2,4})/$1$2/' *
-
Sander W. van der Laan about 8 yearsThis tip is awesome! I typed
rename -vs GLYCOPHORIN GLYCC *
and now it's automatically renaming 450+ files. And super fast too. -
Ben Duffin almost 8 yearsExcellent! Love the "show what would be changed" part BEFORe it actually renames things!
-
Bryan almost 8 yearsYou can use a regex as well. rename 's/123/onetwothree/g' *
-
S.M.Mousavi about 7 yearsIf you like to replace any matched string use
S
parameter instead ofs
. If you like to use regex note: 1-regex is Perl-style 2-remove 's' parameter as this (rename -nv 's/ /_/g' *
). -
buckaroo1177125 over 6 yearsGiven this was OS X, the correct installation procedure is
brew install mmv
. -
James Wright about 6 yearsLove the idea of using
echo
for dry runs. Thanks for the tip! -
Chris Redford about 4 yearsHighly recommend just doing the
brew install rename
-
norbDEV almost 4 yearsrecoursive rename: rename -vs searchword replaceword */