Rename File if Name Exists in Target Folder

Related to How to Rename a Dynamic File Automatically Without Prompting User Input?

I frequently file documents using this:

image

This fails when there is a file with the same name in the target folder, leaving the file where it is. Unlike the referenced macro, there may be a few or many files in the target folder.

Current workaround is with the file still selected, use:

To append a random 3-digit number to the end of the file name and before the extension. Then, re-running the move macro works.

It seems in some instances, the Finder adds 'copy' 'copy copy' etc. to make a file name unique and sometimes prompts for replace or keep both. I'm unclear what triggers the variants.

Can the simple move macro register the failure, append a unique number and rerun successfully without prompting for input, so the move happens regardless of the contents of the target folder?

Why do you want a unique number rather than something potentially useful, like a timestamp? If you do just want to append a number, do you want it simple -- MyFile-1.txt -- or padded -- MyFile-001.txt, and if the latter what's your maximum number of duplicates? When you chose, consider whether sort-by-name order will be important in the future.

Just throwing things out there. Here's a macro that will move any Finder-selected files to a folder that you chose via a prompt, adding a padded, incrementing, unique number if there's a clash:

Move File with Rename if Exists.kmmacros (5.1 KB)

Image

1 Like

Here's another version that uses the fact that an as-yet "undeclared" Local variable resolves to an empty string when used in a token. This one dispenses with the "Try/Catch" and just tests for a file's existence using an incrementing suffix:

Move File with Rename if Exists 2.kmmacros (4.4 KB)

Image

These do the job of resolving duplicate names. Thank you!

Now, I have two different kinds of questions.

When I have the bandwidth, I like to keep inching forward toward some useful level of understanding.

Depending on how interested you are in putting on a teaching hat, I'd like to glean some understanding of how this works. Here's my understanding (for error checking), stumbling points, and questions.



Second, instead of starting with Prompt for Folder:
image

which I see sets a variable used later 'Local__DestinationFolder' which likely determines the structure of the entire macro, can we start with a location like and then sort out duplicate naming?

image

Thank you in advance for any part of this you care to respond to.

I'll try!

You're bang on with the "For Each". But I'd add that the Local__fileToMove variable is what "holds" each item and lets you refer to it in the loop -- and in the case of Finder selections that's the path to the item. So if you selected 1.jpg, 2.jpg, and 3.jpg on your Desktop, in loop 1 Local__fileToMove would be /Users/bernsh/Desktop/1.jpg, on loop 2 ``/Users/bernsh/Desktop/2.jpg`, etc.

Second box: An item's path is the complete reference to the item, starting at the "root" level of the file system and ending with the item's name -- you can see this if you right-click a file or folder in the Finder, hold down the Option key, select "Copy... as Pathname" and then paste into TextEdit or similar. And that's what we have in Local__fileToMove so yes, to get the bits we want later we use the "Split Path" action -- note that the "Extension is:" value does not include the period! (Using the explicit %Variable% form is good practice, for the reasons you state, and while it's more verbose I find it makes it easier to spot what is or isn't a variable.)

Third box: Yep. Also, i is traditional for this sort of counter -- I've always assumed that's because it's used to iterate through an array, a series of numbers, or similar.

Fourth box: Only way I know to make the box expand is to make the window bigger! But what you can do is copy all the text and paste it into either a "Display Dialog" action or even into TextEdit etc, edit it there, and paste it back into the action.

Local__destinationFolder is the path to the folder we chose in the first action of the macro, "Prompt for Folder". We're back to talking paths, as above, and we're joining bits of text together to make a full path to test.

Say you choose "Test Folder" on your Desktop as your destination, the file to move is picture.jpg, your destination already has file of that name and this is our first loop so i = 1. Putting each bit on its own line to make it clearer:

%Variable%Local__destinationFolder%    /Users/berhsh/Desktop/Test Folder
/                                      /
%Variable%Local__basename%             picture
%CalculateFormat%Local__i%-000%        -001
.                                      .
%Variable%Local__extension%            jpg

...and because we are just joining together ("concatenating") those bits of text we get

/Users/berhsh/Desktop/Test Folder/picture-001.jpg

So yes, the order is significant!

Fifth box: Hopefully the above has explained that we add the / and . because the path we get from the prompt and the extension we get from "Split Path" don't include those characters, so we have to add them back in when we build the path.

%CalculateFormat% is a tricksy step -- well spotted! You'd normally use it for things like "give me the result of 4 / 3 to one decimal place":

%CalculateFormat% 4 / 3 % .#%

...which returns 1.3. And the "calculation" of any number is simply itself. So what we're doing here is "calculate Local__i and format the answer with as many leading 0s as are needed to make it three digits long, then prepend a -". So when Local__i is 1 we get -001, when it's 11 we get -011, and so on.

Sixth box: I think you're answering your own question here! The "While" loop keeps repeating until the condition is no longer met -- in this case, until there isn't already a file with the path we are creating. If there is a file the loop continues, 1 is added to Local__i, and we're back to testing the new file path.

It's an inelegant, brute force, approach -- keep trying file names with an ever-increasing suffix until you find one that doesn't conflict.

Seventh (I think!) box: Another tricksy concept. On the first "While" test of every run of this macro, the variable Local__suffix does not exist. Except it looks like we've already used it -- we tested our path with %Variable%Local__destinationFolder%/%Variable%Local__basename%%Variable%Local__suffix%.%Variable%Local__extension%. WTF!

Some languages would throw an error at this point because we've asked for the value of Local__suffix but there is no Local__suffix at that point. KM is much more forgiving and returns an empty string instead. So on the first test, before we've set Local__suffix to a value, we are checking for a file named "picture and <an empty string> and . and jpg" -- picture.jpg. If that exists then we enter the "While" loop, increment Local__i, and set Local__suffix to -001 so the next test is for "picture and -001 and . and jpg" -- picture-001.jpg. And so on, until there is no file match and we can do the copy.

Do notice the difference between the two versions of the macro. In the first we try and move the file, and if that fails we start testing suffixes. In the second we test names until there's no clash then move the file.

You can certainly "hard-code" your destination folder so the macro always puts files in the same place. It's still better practice to use a variable though, setting the path at the beginning of the macro -- if you ever want to change the destination it's easier to edit that one field and let the variable do the work than it is to go through every action looking for the path you want to change.

Or you could go one step better and make your macro work with either a default or chosen destination! For example, give it two triggers -- maybe ⌃M and ⌃⌥M -- and start with (pseudocode):

if %TriggerValue% contains ⌥ then
   set destinationFolder to "Prompt for Folder"
else
   set destinationFolder to "/Users/bernsh/Desktop/Destination"
end if

...so that triggering the macro with ⌃M will use your default location while ⌃⌥M will let you choose.

And I've probably blathered enough. Hopefully that's explained a few bits, and not made things even worse!

Just quickly read through. Thrilling on two counts:

  1. I was able to ask the question clearly enough to get an answer I was looking for.
  2. That you were willing to give the time, attention, and effort.

Thank you!

This was a mistake I make. No blather and certainly not worse (it wasn't actually bad to begin as I was asking for understanding). If anything happened, it was that I wasn't clear enough to set you up to answer with certainty. That's the shortcoming of my poor questioning. I'll get better as my understanding develops.

I need to re-read slowly until I get through with a clear understanding. I didn't want to wait to acknowledge your generosity, effort, and care. I appreciate you greatly!

Well, only a year later (it seems I'm getting quicker at this :wink:).

I've tried this a few times, and it fails after the first rename. For example, the destination folder has four folders in it named Untitled Folder, Untitled Folder 1, Untitled Folder 2, and Untitled Folder 3.

Moving a folder named Untitled Folder into this folder renames the moved folder to the same name with a period at the end like this: "Untitled Folder." (w/o the quotes, of course)

This is unexpected as it looks like it should be Untitled Folder 1.

Moving another folder titled Untitled Folder simply does nothing, so something is amiss.

Before fixing this (if you go to) I have a variation to this sequence.

I'm now using a simpler filing scheme with just a few "bucket" folders to put most unfiled items into awaiting a final filing (if I live long enough). I therefore do not need the Prompt for Folder first action and just need a rename if the same name exists at the destination.

I'm using this to specify the location:
Keyboard Maestro Export

Seems this idea was discussed here: "Create Unique File" Action in Keyboard Maestro v10.0.1