Repeat until file name does not exist.

Hi All,

I have a script that creates another script. When it names the new script I want it to add a number to the end if the name it wants to use already exists so the previous file stays. Lets say the script is going to name the new file My Script.app but that file is already there. I need the script to add a number to the end and test again to see if that file exists ( My Script-1.app ) and if so keep repeating until the name it wants to use does not exist then continue. My first thought was to use a repeat until statement something like this.

set appendIncr to "0"
	set file_path to (path to desktop as Unicode text) & "Create Process-" & processName & ".app"
	set file_path to POSIX path of file_path as string
	if exists file_path then
		repeat until not exists file_path
			set appendIncr to (appendIncr + 1)
			set file_path to (path to desktop as Unicode text) & "Create Process-" & processName & appendIncr & ".app"
			set file_path to POSIX path of file_path as string
		end repeat
	end if
	do shell script "echo " & quoted form of script_text & "|osacompile  -o \"" & file_path & "\""

So I’m thinking it would repeat adding 1 to appendIncr on each repeat until the name is unique. What is the proper syntax to achieve this? This sample is actually a snippet from a handler in a larger script so some variables don’t exist.

Thanks,
Mark

mtorrance,

I just had this same issue here is the thread

http://bbs.applescript.net/viewtopic.php?id=20874

mm

Hi Mark,

I use this universal handler to check the file name

on checkFileName(fDir, fName, separator) -- fDir can be alias or path string
	set fDir to fDir as Unicode text
	try
		set f to (fDir & fName) as alias
		set {name:Nm, name extension:Ex} to info for f
		if Ex is missing value then set Ex to ""
		if Ex is not "" then set Nm to text 1 thru ((count Nm) - (count Ex) - 1) of Nm
		set idx to 0
		repeat
			set idx to idx + 1
			set checkName to (fDir & Nm & separator & (idx as string) & "." & Ex)
			try
				checkName as alias
			on error
				return checkName
			end try
		end repeat
	on error
		return (fDir & fName)
	end try
end checkFileName

Hi StefanK,

It seems this would work great but I’m having trouble working it into my script.


on RunMaker(script_text, bugcheck)
	set file_path to (path to desktop as Unicode text) & "Create Process-" & processName & ".app"
	set file_path to POSIX path of file_path as string
	
	set fDir to path to desktop as string
	set fName to ("Create Process-" & processName & ".app" as string)
	set separator to "-"
	my checkFileName(fDir, fName, separator)
	do shell script "echo " & quoted form of script_text & "|osacompile  -o \"" & file_path & "\""
	if bugcheck then say "saved"
	
	--Copy Icon to new bundle
	set newIconPath to ((path to me) as string)
	set newIconPath to (POSIX path of newIconPath) & "Contents/Resources/Appleticon/applet.icns" as string
	set iconDestination to (file_path & "/Contents/Resources/" as string)
	do shell script "cp " & "\"" & newIconPath & "\"" & " " & "\"" & iconDestination & "\""
	
	
end RunMaker

on checkFileName(fDir, fName, separator) -- fDir can be alias or path string
	set fDir to fDir as Unicode text
	try
		set f to (fDir & fName) as alias
		set {name:Nm, name extension:Ex} to info for f
		if Ex is missing value then set Ex to ""
		if Ex is not "" then set Nm to text 1 thru ((count Nm) - (count Ex) - 1) of Nm
		set idx to 0
		repeat
			set idx to idx + 1
			set checkName to (fDir & Nm & separator & (idx as string) & "." & Ex)
			try
				checkName as alias
			on error
				return checkName
			end try
		end repeat
	on error
		set filepath to (fDir & fName as Unicode text)
		set file_path to POSIX path of file_path
		--return (fDir & fName)
	end try
end checkFileName

Where am I going wrong? Working with handlers is fairly new territory to me.

Thanks,
Mark

Hi,

If you use a naming convention where the files are sorted you can use a filter reference form to get the file. Suppose your files are named:

a.ext
file_000.ext
file_001.ext

file_010.ext
z.ext

Here, there are other files in the same folder with different names. Your filter reference form would look like this:

tell app “Finder”
set last_file to last file of somefolder whose name begins with “file_”
end tell

Since the listing of files whose name begins with “file_” is sorted, it will return the one with the highest index.

gl,

Hi Mark,

a handler has a few special rules, one of them is, which is very important,
that local variables are only recognized by the handler, which they are declared in
Only properties and global variables are valid everywhere in the script.
Also your processName variable should be a property or a global!

You can pass parameters through the parentheses and the result is either
the result of the last executed line or the argument of the explicit return command.

Try this:

on RunMaker(script_text, bugcheck)
	set fName to "Create Process-" & processName & ".app"
	set file_path to POSIX path of checkFileName(path to desktop, fName, "-")
	do shell script "echo " & quoted form of script_text & "|osacompile  -o " & quoted form of file_path
	if bugcheck then say "saved"
	
	--Copy Icon to new bundle
	set newIconPath to ((path to me) as Unicode text)
	set newIconPath to (POSIX path of newIconPath) & "Contents/Resources/Appleticon/applet.icns"
	set iconDestination to file_path & "/Contents/Resources/"
	do shell script "cp " & "\"" & newIconPath & "\"" & " " & "\"" & iconDestination & "\""
end RunMaker

on checkFileName(fDir, fName, separator) -- fDir can be alias or path string
	set fDir to fDir as Unicode text
	try
		set f to (fDir & fName) as alias
		set {name:Nm, name extension:Ex} to info for f
		if Ex is missing value then set Ex to ""
		if Ex is not "" then set Nm to text 1 thru ((count Nm) - (count Ex) - 1) of Nm
		set idx to 0
		repeat
			set idx to idx + 1
			set checkName to (fDir & Nm & separator & (idx as string) & "." & Ex)
			try
				checkName as alias
			on error
				return checkName
			end try
		end repeat
	on error
		return (fDir & fName)
	end try
end checkFileName

StefanK,

Awesome as usual!:lol:

I did already have processName declared as a property in the top of the larger script. Thanks for the explanation.

MT

Hi StefanK,

In my “on run” section of my script I was setting the comments of the resulting file. However if the file is renamed by the checkFileName handler can I get the values of fDir & fName into that part of the script. I declared fDir and fName as property’s at the top of my script and then try to set the comment like


set commentText to ("Quality:" & processQuality & ", Format:" & processFormat & ", Scaling:" & processScale & ", Resolution:" & processRes as string)
	set new_file to (fDir & fName as Unicode text)
	set new_file to new_file as alias
	tell application "Finder"
		set comment of file new_file to commentText
	end tell

It worked before using the checkFileName handler and the error shows it’s looking for the file name before the handler renamed it. Since the handler explicitly returns fDir and fName and since I declared them as properties I was thinking I could get the new name to set the comments to. Where am I going wrong?

Thanks,
MT

Hi Mark,

the problem is, if the file already exists, the handler returns checkName, not fName
change the repeat block to this:


...
repeat
	set idx to idx + 1
	set fName to (Nm & separator & (idx as string) & "." & Ex)
	try
		(fDir & fName) as alias
	on error
		return (fDir & fName)
	end try
end repeat
...

Stefan,

The handler renames the file like it should but I still don’t get the updated filename in the property fName in the “on run” portion of the script.

I’m working this from a application bundle so if you could at your convenience look at the main.scpt in this bundle.

http://www.bwstudios.biz/downloads/C1PROProcessCreator.zip

I commented “–Stefan Look Here” at the start of the section in question. Everything works except the file won’t get comments if the handler renamed it from what the user input in the first dialog processName. Just run the app once hitting return for each dialog then do it a second time to get the handler to rename the file. Get info on both files and you’ll see that one gets the comments and the other did not.

Many Thanks,
MT

Hi Mark,

sorry, but I get a couple of errors in your script, which is not your fault,
because my (international) number format settings expect a comma as decimal point instead of a dot.
And then I get an error: No user interaction allowed.

But as far as I can see, the property “fName” should be set properly.
I don’t understand why it doesn’t.

A few notes:
¢ the keyword my in front of a handler call is only necessary if the handler is called within a tell block.

¢ Take care of your coercions, for example

set Pathz to ((path to me) & "Contents:Resources:Scripts:main.scpt" as string)

works, but better is:

set Pathz to (((path to me) as Unicode text) & "Contents:Resources:Scripts:main.scpt")

¢ instead of your yes/no lists I would use yes/no buttons

Edit: I know, what the problem is:
we use the same variable name (fName) as a property and as a parameter variable of a handler.
The handler takes it as a local variable and ignores the property.
Using a different name solves the problem:

on checkFileName(fDir, fN, separator) -- fDir can be alias or path string
    set fDir to fDir as Unicode text
    try
        set f to (fDir & fN) as alias
        set {name:Nm, name extension:Ex} to info for f
        if Ex is missing value then set Ex to ""
        if Ex is not "" then set Nm to text 1 thru ((count Nm) - (count Ex) - 1) of Nm
        set idx to 0
        repeat
            set idx to idx + 1
            set fName to (Nm & separator & (idx as string) & "." & Ex)
            try
                (fDir & fName) as alias
            on error
                return (fDir & fName)
            end try
        end repeat
    on error
        return (fDir & fN)
    end try
end checkFileName