7

I would like to have a regex that will rename my files. Microsoft Windows has changed my files' names and I want to remove the parenthetical datetime substring from the filenames.

Here are some sample filenames:

icon-culture (2015_09_04 06_58_44 UTC).png
icon-disk (2015_09_04 06_58_44 UTC).png
icon-download (2015_09_04 06_58_44 UTC).png
icon-drop (2015_09_04 06_58_44 UTC).png
icon-file (2015_09_04 06_58_44 UTC).png
icon-film (2015_09_04 06_58_44 UTC).png
icon-flag (2015_09_04 06_58_44 UTC).png
icon-folder (2015_09_04 06_58_44 UTC).png
icon-garbage (2015_09_04 06_58_44 UTC).png
icon-graph (2015_09_04 06_58_44 UTC).png
icon-heart (2015_09_04 06_58_44 UTC).png
icon-help (2015_09_04 06_58_44 UTC).png
icon-lock (2015_09_04 06_58_44 UTC).png
icon-map (2015_09_04 06_58_44 UTC).png
icon-media (2015_09_04 06_58_44 UTC).png
icon-money (2015_09_04 06_58_44 UTC).png
icon-monitor (2015_09_04 06_58_44 UTC).png
icon-notes (2015_09_04 06_58_44 UTC).png
icon-openmail (2015_09_04 06_58_44 UTC).png
icon-phone (2015_09_04 06_58_44 UTC).png
icon-photo (2015_09_04 06_58_44 UTC).png

My desired filenames after renaming are:

icon-culture.png
icon-disk.png
icon-download.png
icon-drop.png
icon-file.png
icon-film.png
icon-flag.png
icon-folder.png
icon-garbage.png
icon-graph.png
icon-heart.png
icon-help.png
icon-lock.png
icon-map.png
icon-media.png
icon-money.png
icon-monitor.png
icon-notes.png
icon-openmail.png
icon-phone.png
icon-photo.png

The tutorials that I found didn't do well for me because there are some special characters and numbers.

5
  • I've edited muru. @Serg, I want to change these names like that: icon-monitor (date).png to icon-monitor.png and icon-notes (date).png to icon-notes.png
    – user513724
    Mar 12, 2016 at 9:28
  • Have a look on this: tips.webdesign10.com/… Mar 12, 2016 at 9:29
  • I've looked up but there is no any example with "complicated strings" and other characters like "(". But I've learned some tricks and my problem has solved. Thank you.
    – user513724
    Mar 12, 2016 at 9:44
  • Possible duplicate of How to easily rename files using command line? Mar 14, 2016 at 7:38
  • I already looked up this but I just want to special argument for my problem. Because tutorials didn't do well for me.
    – user513724
    Mar 14, 2016 at 10:07

5 Answers 5

14

You can use the rename command:

$ rename -n 's/ \(.*?\)//' *.png
icon-culture (2015_09_04 06_58_44 UTC).png renamed as icon-culture.png
icon-disk (2015_09_04 06_58_44 UTC).png renamed as icon-disk.png
icon-download (2015_09_04 06_58_44 UTC).png renamed as icon-download.png
icon-drop (2015_09_04 06_58_44 UTC).png renamed as icon-drop.png
icon-file (2015_09_04 06_58_44 UTC).png renamed as icon-file.png
icon-film (2015_09_04 06_58_44 UTC).png renamed as icon-film.png
icon-flag (2015_09_04 06_58_44 UTC).png renamed as icon-flag.png
icon-folder (2015_09_04 06_58_44 UTC).png renamed as icon-folder.png
icon-garbage (2015_09_04 06_58_44 UTC).png renamed as icon-garbage.png
icon-graph (2015_09_04 06_58_44 UTC).png renamed as icon-graph.png
icon-heart (2015_09_04 06_58_44 UTC).png renamed as icon-heart.png
icon-help (2015_09_04 06_58_44 UTC).png renamed as icon-help.png
icon-lock (2015_09_04 06_58_44 UTC).png renamed as icon-lock.png
icon-map (2015_09_04 06_58_44 UTC).png renamed as icon-map.png
icon-media (2015_09_04 06_58_44 UTC).png renamed as icon-media.png
icon-money (2015_09_04 06_58_44 UTC).png renamed as icon-money.png
icon-monitor (2015_09_04 06_58_44 UTC).png renamed as icon-monitor.png
icon-notes (2015_09_04 06_58_44 UTC).png renamed as icon-notes.png
icon-openmail (2015_09_04 06_58_44 UTC).png renamed as icon-openmail.png
icon-phone (2015_09_04 06_58_44 UTC).png renamed as icon-phone.png
icon-photo (2015_09_04 06_58_44 UTC).png renamed as icon-photo.png

s/ \(.*?\)// is a simple, if broad, expression, matching a space followed by parentheses-enclosed stuff. You can pick more precise expressions like:

  • s/ \(.*?\)\.png$/.png/ - like the previous, but matching only if followed by .png and the end of the filename, or
  • s/ \(\d{4}(_\d\d){2} \d\d(_\d\d){2} UTC\)\.png/.png/ - matching the date pattern shown in these files, and followed .png.

The -n option is for testing the command. Run without it if you're satisfied with the results.

5
  • There's another very similar rename command shipped by ubuntu: prename. The exact same args should work for it, too, but the implementation is different. Mar 12, 2016 at 21:34
  • @PeterCordes that is the rename I'm using here (aka perl-rename). The other rename (from util-linux) isn't the default, so I don't mention it unless necessary.
    – muru
    Mar 12, 2016 at 21:36
  • 2
    On my Ubuntu 15.10: /usr/bin/prename is from the perl package. /usr/bin/rename is a symlink, through /etc/alternatives/rename, to /usr/bin/file-rename from the rename package. That package's description says it's "intended to replace the version currently supplied by the perl package", so I guess it's the better choice. Mar 12, 2016 at 21:58
  • @PeterCordes Hmm. Guess I should start using new releases more often.
    – muru
    Mar 12, 2016 at 21:59
  • I always use and recommend the current Ubuntu release, not the LTS. Nobody wants to run into old bugs that are fixed in the current versions of things, and writing bug reports against old versions is usually a lot less useful. Mar 12, 2016 at 22:03
4

Using bash parameter expansion:

for file in *.png; do mv -i "$file" "${file%% *}".png; done

${file%% *} will discard the unwanted portion of the filename starting from space. Then the extension .png is added after the filename while mv-ing.

0
3

You could try the following python code snippet

import os
import glob
files = glob.glob('*')
for file in files:
    var1 = file.find(' (')
    var2 = file.find(')')+1
    filename = file[:var1] +  file[var2:]
    os.rename(file, filename)
  • glob finds all files which satisfy the regex argument
  • You iterate through the list and modify the name of the file
  • rename changes the name of the file
0
2

Using bash and parameter expansion, run the following code from the same directory where you have the files.

for file in *.png ; do NAME="${file%%\ \(*}"; EXT="${file##*.}" ; mv "$file" "$NAME"."$EXT"   ; done  

Sample run

$> ls                                                                                                                             
icon-culture (2015_09_04 06_58_44 UTC).png  icon-disk (2015_09_04 06_58_44 UTC).png
$> for file in *.png ; do NAME="${file%%\ \(*}"; EXT="${file##*.}" ; mv "$file" "$NAME"."$EXT"   ; done                               
$> ls
icon-culture.png  icon-disk.png
0
0

Assuming all of the files in the directory need to receive the same treatment (IOW, this is a string extraction task and not a string validation task), here is alternative to @muru's solution that mixes some wisedom that I drew from @CandyGumdrop's comprehensive Stackoverflow answer with my understanding of regular expression optimization:

prename 's/ [^.]*//' *

The pattern relies on the consistent substring structure that begins with the only space character in the filename, then greedily consumes all characters that are not a literal dot. Upon matching these characters, the replacement string is a zero-width string (IOW, replace with nothing). If you ever want to insert any characters in place of the matched substring, those characters would be written between the two consecutive forward slashes.

The * at the end of the command says to include all files in the directory. This may be useful if your file types may differ in the future.

One metric for measuring regex pattern efficiency is the number of steps that the regex engine has to take. https://regex101.com does a great job of spelling out pattern logic and presenting the step count.

https://regex101.com/r/JeB581/1/ shows that it takes 64 steps to make the 21 replacements on your provided battery of filenames.

https://regex101.com/r/JeB581/2/ shows that @muru's pattern will require 588 steps to perform the same 21 replacements.

It is entirely possible that there is no reason to quibble over performance, say, if your file count is relatively small. I merely want to point out how to optimize the pattern by taking advantage of greedy quantifiers (*?) versus lazy quantifiers (.*) if/when it is beneficial. The other way to state the pattern difference is that I am sacrificing string validation strength for faster matching.

You must log in to answer this question.