How to Batch Rename Files in a macOS Terminal?

BashMacosShellTerminalFile Rename

Bash Problem Overview


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:

Bash Solutions


Solution 1 - Bash

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 of bash 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, run man bash and search for Pattern 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 in bash - 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 - Bash

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 - Bash

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 - Bash

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 - Bash

you can install rename command by using brew. just do brew install rename and use it.

Solution 6 - Bash

Using mmv

mmv '*_*_*' '#1_#3' *.png

Solution 7 - Bash

try this

for i in *.png ; do mv "$i" "${i/remove_me*.png/.png}" ; done

Here is another way:

for file in Name*.png; do mv "$file" "01_$file"; done

Solution 8 - Bash

Since programmatically renaming files is risky (potentially destructive if you get it wrong), I would use a tool with a dry run mode built specifically for bulk renaming, e.g. renamer.

This command operates on all files in the current directory, use --dry-run until you're confident the output looks correct:

$ renamer --find "/(prefix_)(\w+_)(\w+)/" --replace "$1$3" -e name --dry-run *

Dry run

✔︎ prefix_1234_567.png → prefix_567.png
✔︎ prefix_abcd_efg.png → prefix_efg.png

Rename complete: 2 of 2 files renamed.

Plenty more renamer usage examples here.

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
QuestionkidnimView Question on Stackoverflow
Solution 1 - Bashmklement0View Answer on Stackoverflow
Solution 2 - BashDavid ThomasView Answer on Stackoverflow
Solution 3 - Bashl'L'lView Answer on Stackoverflow
Solution 4 - BashJanBView Answer on Stackoverflow
Solution 5 - BashNisim JosephView Answer on Stackoverflow
Solution 6 - BashαғsнιηView Answer on Stackoverflow
Solution 7 - BashThiagoView Answer on Stackoverflow
Solution 8 - BashLloydView Answer on Stackoverflow