Search & Replace in File Name?

I have some files that end in "(3)", "(5)," and other numbers.

How would I get KM to replace any string like that in file names? I'm having a hard time figuring it out with For-Each.

Hey Pariah,

You're not giving enough detail about your task...

  • What are you working with?
    • Files in a selection?
    • Files in a given folder?
    • Files in the open Finder window?

At the most basic level you're:

  • Iterating through a list of file paths.
  • Using the Split Path action to grab the name OR working with the full path.
  • Using the Search and Replace action with a regular expression to replace the string you desire.

If that's not enough of a hint then be sure to post more details.

-Chris

1 Like

My apologies. I'm working with files in a given folder. The folder path is stored in a variable (it changes weekly with each show).

These file names will always end with numbers surrounded by parentheses?

Or will there be file extensions?

Can you provide 4-5 real example names for testing?

They won't always end with any particular string. Some of the files are numbered because the library contains multiple files with the same filename. They're songs, but they aren't always actually duplicates. Here's an example of a recent few I worked with:

Cinderella - Somebody Save Me.wav
Crashing Wayward - Breathe.wav
Def Leppard - Women (5).wav
Disturbed - Down With the Sickness.wav
Extreme - Play With Me.wav
Five Finger Death Punch - Times Like These (3).wav
Hurricane - I'm on to You.wav
In This Moment - Big Bad Wolf.wav
Iron Maiden - Can I Play With Madness (4).wav
Jackyl - Dirty Little Mind.wav
KISS - Love Gun.wav
L.A. Guns - Never Enough.wav
Lita Ford - Kiss Me Deadly (3).wav
Lynch Mob - River Of Love.wav
Mike Tramp - CRY FOR FREEDOM.wav

Once I have the file names in a TXT file for the reporting playlist, I use KM to easily remove those numbers. I'm just not sure how to do it to the actual filenames in advance to save me some work in the reporting playlist and in other aspects of producing a show with these music files.

So you actually want to delete those parts rather than replace?

What do you want to do when you have both "My Song.wav" and "My Song (1).wav"?

Correct. I want to delete them from the filenames.

Alert with an error, I suppose. It shouldn't happen.

Using Swift, you could take the characters up to the first (.

Remove bracketed numbers from string.kmmacros (2.0 KB)

Output:

That should be easy -- regex search for \s\(\d+\) (using \s because it's more obvious than a space character), replacing with nothing.

"Fail with error" is the default for the "Move or Rename a File" file action. So you could use the action's result to either throw an alert up (which will require you to interact) or log and continue then pop a dialog at the end showing failures.

So, in pseudocode:

for eachFile in the folder
   get the filename-with-extension of eachFile to tempVariable
   search tempVariable for '\s\(\d+\)', replacing with ''
   try
      rename eachFile to tempVariable -- because if you don't put a full path in the "to" field it renames in place
   catch
      throw alert or log eachFile
   end
end
display "Done", with or without failure log

Have a go, and see how you get on.

Thank you @Nige_S,

I think I'm doing something wrong because it isn't running.

For Each.kmactions (1.6 KB)

Hey Pariah,

Please don't post actions in lieu of a full and complete test macro. The actions you posted don't reveal where you've gone wrong.

Take a look at the appended macro.

  • Make sure to change the local_TargetFolder variable to the correct path on your system.
  • Note that the macro can also use the Front Finder Window FinderInsertionLocation by toggling the enabled target location actions.
  • The macro reports any failures.

-Chris


Sanitize Music File Names in a Given Folder v1.01.kmmacros (25 KB)

Macro Image

1 Like

That IS the whole macro I tried. It was a one-action macro.

Thank you for the macro. That did what I needed.

No, that's not the whole macro. It may be the contents of the macro, but those are not one and the same.

Posting complete, testable macros is very important. Finicky little details hide in macros that are not deducible via images and/or prose and/or actions alone, and those details are often key to solving a given problem.

Actions do not show a full macro, its trigger(s) or lack thereof, or the parent macro group – and all these things can contribute why a macro fails to work.

2 Likes

Chris's version is more featured, but here's one that's based on the action you posted so you can compare them and see where you were going wrong. My first guess is that, if your screenshot is the entire macro, you were doing everything right, but you forgot to include the "rename the file" step -- you're just changing the variable and then moving on to the next file name.

Rename Files.kmmacros (4.0 KB)

Image

That "If" at the end isn't necessary at the moment -- if the file name doesn't get changed the "Move" action could be set to fail silently rather than throw a notification. But we're planning ahead for the "log the errors" version, where we only want the rename-to-an-existing-name files to error.

1 Like

@iampariah, if any of @ccstone or @Nige_S have solved your problem, please mark one of those as solution.

FWIW, another possible solution using Haskell could be:

Expand disclosure triangle to see "haskell" source
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}

module Parsing where

import Control.Applicative
import Control.Monad (replicateM, void)
import Data.Aeson
import Data.Bifunctor
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as LB
import Data.Map.Strict (Map, fromList, mapWithKey, restrictKeys, (!))
import Data.Set (fromList)
import Data.Text (justifyRight, pack, unpack, strip)
import Data.Text.Encoding (decodeUtf8)
import System.Directory
import System.FilePath
import Control.Monad

interact'' :: (String -> IO ()) -> IO ()
interact'' f =
  LB.getContents
    >>= LB.readFile . unpack . decodeUtf8 . LB.toStrict
    >>= pure . (eitherDecode :: LB.ByteString -> Either String String)
    >>= either putStrLn f

folderPath = "/Users/detach/Downloads/Folder"

removeSuffixFromFileName :: FilePath -> String
removeSuffixFromFileName =
  uncurry (<>)
    . first removeSuffix
    . splitExtension
  where
    removeSuffix :: String -> String
    removeSuffix = unpack . strip . pack . takeWhile (/= '(')

main :: IO ()
main = interact'' $
  (listDirectory 
    >=> mapM_ ((renameFile . (folderPath </>)) <*> (folderPath </>) . removeSuffixFromFileName) 
  )

Download Macro(s): Remove suffixes from filenames in a given directory.kmmacros (5.8 KB)

Macro-Image

Macro-Notes
  • Macros are always disabled when imported into the Keyboard Maestro Editor.
    • The user must ensure the macro is enabled.
    • The user must also ensure the macro's parent macro-group is enabled.
System Information
  • macOS 13.1
  • Keyboard Maestro v10.2