AppleScript: If a file does not exist - applescript

I need some way to determine if a particular file exists. If it exists do one script if not then do another script. Here was my logic in applescript:
If exists "File:Path:To:theFile"
tell application "Finder"
open "File:Path:To:the:script"
end tell
else
tell application "Finder"
open "File:Path:To:the:Anotherscript"
end tell
end if
The only problem is that sometimes when i use the above logic the script fails saying can't find the file. I need a full proof, never fails way to see if a file exists. I'm open to using the terminal, or applescript. I'm sure someone has run into this before but I have looked all over the web for an answer but could not find one.

In your original code you're giving the exists function a string, rather than a file, even though it's the path to a file. You have to explicitly give it a file, or it treats it the same as if you had tried to do
exists "god"
or
exists "tooth fairy"
The exists command won't know what you're talking about. You could use
return exists alias "the:path:to:a:file"
but aliases don't work unless the file actually exists, so a non-existent file will create an error. You could of course catch the error and do something with it, but it's simpler to just give the exists function a file object. File objects belong to the Finder application, so:
return exists file "the:path:to:a:file" of application "Finder"

I use the following to see if an item in the Finder exists:
on FinderItemExists(thePath)
try
set thePath to thePath as alias
on error
return false
end try
return true
end FinderItemExists
I think what you're missing is conversion of the path to an alias.

This sounds like a good place for a try...on error block. I believe the following should do what you want:
tell application "Finder"
try
open "File:Path:To:the:script"
on error
open "File:Path:To:the:Anotherscript"
end try
end tell

Related

Where is 'missing value' coming from in this repeat block?

I am creating a text file and looping through every Safari window, every tab, and pasting each link into the .txt file. However I am getting an extra missing value written to the .txt file. I know I can explicitly check for missing values but I don't understand where is the "empty" window/value?
on run {input, parameters}
(* create text file to hold links *)
tell application "Finder" to make file at desktop with properties {name:"links_0"}
set classicPath to (((path to desktop folder) as string) & "links_0")
(* get links of all windows *)
tell application "Safari"
repeat with this_window in windows
set the_URLs to ""
repeat with this_tab in tabs of this_window
set the_URLs to the_URLs & URL of this_tab & return
end repeat
do shell script "echo " & quoted form of the_URLs & " >> " & POSIX path of (classicPath)
do shell script "echo >> " & POSIX path of (classicPath)
end repeat
end tell
return input
end run
sample output (2 windows, each with 2 tabs):
https://discussions.apple.com/thread/64896
https://discussions.apple.com/thread/22543
https://discussions.apple.com/thread/25140
https://discussions.apple.com/thread/22546
missing value
An easier way to do this would be:
set my text item delimiters to linefeed
set fp to POSIX path of (path to desktop folder) & "links_0.txt"
close access (open for access fp) -- Create the file if it doesn't exist
# set eof of fp to 0 -- Erase any existing contents in the file
tell application id "com.apple.Safari" to tell every tab of every window ¬
to tell (the URL as text) & linefeed to continue write it to fp ¬
starting at eof
This currently appends URLs to the end of the file. To overwrite the file, uncomment this line:
# set eof of fp to 0
by removing the hash symbol.
Note: There's potential for confusion having read the comment left by #user3439894, where he states:
"It also shows code missing from CJK's answer in which a file should be closed after being written to. It also wraps relevant code in a try statement so if there is an error it attempts to close the file."
I would take what you read at the provided link with a pinch of salt. Sadly, a lot of the AppleScript documentation from Apple contains code that is poorly written and is part of the reason a lot of bad AppleScript persists so pervasively on the internet. Some of the documentation provided by Apple is also flat out wrong, which makes it very difficult for people to learn from and to know whose advice to take.
The code I have provided above, I assure you, is very much complete. Read on for a pretty boring explanation that I wish I didn't have to give, but now have to:
You'll see a lot of people do this:
set fh to open for access filepath with write permission
write somedata to fh
close access fh
It's not wrong, per se, but it's a pretty draconian way of using these read/write commands, which persists among many simply because they've always done it that way, and only seen it done that way. It's cumbersome and completely unnecessary1.
#user3439894 alluded to a try statement, which would, indeed, be needed for this method. open for access opens a file handle that was necessary in order to write out to a file. However, if an error in the script occurs during the write process, then the file handle is left dangling because the script terminates before being able to close access to the file. The way around this would be to use a try statement whose purpose was to catch an error, and ensure the close access command still gets executed:
try
set fh to open for access filepath with write permission
write somedata to fh
close access fh
on error
close access fh
end try
open for access and close access are redundant. There's no need to use them, and in fact, their use is only creating a potential problem that then needs a workaround in order to solve.
write--and read--are safe and advisable to use on their own, and they don't need a try block to catch potential errors. So why do the two commands I just called redundant appear in my script at all ?
close access (open for access fp)
One nifty side effect of the open for access command is that it will create a file at the specified path if one doesn't already exist. This is really useful because it negates the need to call out to System Events or (shudder) Finder to do this for you. It also has seems to have a wider scope for creating files at locations that other AppleScript applications don't have permission to access if they're sandboxed, etc.
Once open for access has created the file--or opened one that already exists--it returns a reference to the file handle. Then close access is used to immediately destroy file handle, because we don't actually have any use for it, but also don't want it left open. There's also no need for a try block: any error that could possibly arise would do so during the creation of the file handle, which would mean that the file handle won't be created, and so cannot be left open.
1The way the data gets written out now is fundamentally different to how it was written out when these commands were first introduced, and previously, write would not be able to access a file without first explicitly opening a file handle to it and declaring the need for writing permissions. Now, everything gets handled within the write command itself, including clean up.

The excel file was converted to a Numbers file by AppleScript

First, I ran the script code in the script editor, and found that there was an error. The Numbers did not understand the save command, The script command was as follows:
tell application "Numbers"
set thisDocument to open alias "Macintosh HD:Users:admin:numbers-FATP.xls"
tell thisDocument
save thisDocument in file "Macintosh HD:Users:admin:NumbersTest.numbers"
end tell
close thisDocument
end tell
And the specific error information was as follows:
error "“Numbers” encountered an error:“remove id \"C76B3CB0-D007-46C4-BEB0-9C65D0E65767\"” do not understand “save” information." number -1708 from remove id "C76B3CB0-D007-46C4-BEB0-9C65D0E65767"
The point is, sometimes can execute the script code, sometimes can't perform, and it is puzzling, I try to change the computer version and version Numbers, but did not solve the problem, this is why, look forward to your reply, best regards!
I refer to this website: https://iworkautomation.com/numbers/document-save.html

Moving a File with AppleScript

Today is my first day of even knowing AppleScript exists so I apologize if this is a stupid question. I've searched and can't find the answer on how to simply move a file with AppleScript
All I need to do is move a file from ~/Downloads/blank.potx to ~/Library/Application Support/Office/User Templates/My Templates
This is what I have in AppleScript right now:
tell application "Finder"
move "~/Downloads/blank.potx" to "~/Library/Application Support/Microsoft/Office/User Templates/My Templates/blank.potx"
end tell
When I run this it gives me an error:
error "Finder got an error: AppleEvent handler failed." number -10000
Again, first day using AppleScript and I'm lost. Any help you can provide would be awesome.
If there's a better way to do this please let me know as well.
Thanks!
Search is your friend. You can easily find the syntax on stack overflow. Such as here:
tell application "Finder"
move POSIX file "/Users/xx/Documents/img.jpg" to POSIX file "/Users/xx/Documents/State" with replacing
end tell
If you're gonna use Posix file paths, you need to indicate so, and you need to name the string as a file.

AppleScript error when trying to copy home folder to shared drive

So, i'm working on a script that copies the home folder to a mounted shared drive folder. But i'm getting the following error:
"Handler can't handle objects of this class number -10010"
This is the code I came up with following the example of other code i've seen on here. I'm guessing that it is the way i'm telling finder to duplicate.
set vserver to ("/Volumes/sharedfolder")
set source to ("/Users/user")
tell application "Finder"
duplicate source to vserver
end tell
How else can I write this?
I've also tried running a boolean test to see if Finder saw the shared folder or my home folder and it retured false. (but only one false when it should have returned two)
tell application "Finder"
setaBoolean1 to get (exists vserver)
setaBoolean1 to get (exists source)
end tell
set vserver to ("/Volumes/sharedfolder")
The line above sets the variable vserver to a string object consisting of "/Volumes/sharedfolder". Likewise, the set source to "/Users/user" line sets source to a string object containing "/Users/user". Note that strings are not what the Finder is expecting when you're telling it to duplicate items.
The tell app Finder line is basically trying to tell the Finder to duplicate one string into another string, which it doesn't know how to do (hence the Handler can't handle objects of this class message).
What you need to do is to, instead of creating strings, create some sort of file system reference to those folders, so that the Finder knows how to deal with them.
There are numerous ways to do this, but the method I found that works (which uses the same POSIX style path format) is the following:
set vserver to POSIX file "/Volumes/sharedfolder"
set source to POSIX file "/Users/user"
tell application "Finder"
duplicate source to vserver
end tell

Can I put shared applescript code in a separate file and load it in various scripts?

I'm starting to poke around with Applescript and am looking at writing a few scripts for managing windows. A common task they will all need is to get the current screen size.
I've created a screen_size subroutine that seems to work, and I want to be able to share that with all my scripts. However, I can't figure out a way to put that in a separate file that I can load in my other scripts. I tried creating a separate screen_size.scpt file and use load script "screen_size.scpt", but I get an error about "can't make "screen_size.scpt" into a type file".
There has to be a way to do this, but I haven't been able to find anything online about how to do it.
EDIT:
The POSIX stuff suggested isn't working for me. I'm able to create the file object, but it refuses to convert to an alias, saying it can't find the file (looks like the POSIX file stays relative instead of expanding fully).
I found a suggestion online to use Finder, and have gotten the following working to get an alias:
tell application "Finder"
set _myPath to container of (path to me) as text
end tell
set _loadPath to (_myPath & "screen_size.scpt")
set _loadAlias to alias _loadPath
However, the next line fails with a syntax error, claiming that _loadAlias isn't a variable:
property _ScreenSize : load script _loadAlias
Every variation of this I've tried (doing the alias in the load call, etc) fails, always claiming the variable doesn't exist, even though I know it's being set and working as I can display it. What's going on? Why is it claiming a variable doesn't exist when it obviously does?
AppleScript is doing some really weird things when saving and I haven't figured out what's going on, but I ended up getting something to work.
Here's what I have:
on load_script(_scriptName)
tell application "Finder"
set _myPath to container of (path to me) as text
end tell
set _loadPath to (_myPath & _scriptName)
load script (alias _loadPath)
end load_script
set _ScreenSize to load_script("screen_size.scpt")
set _bounds to _ScreenSize's screen_size()
-- ...
The other answers were saying to set _ScreenSize as a property, but that would cause a syntax error which prevented me from ever saving the file. When I did it just using set it worked.
I wasn't ever able to get the POSIX path stuff suggested to work, but poking Finder for the path worked fine.
In order to execute an action from another script, you'll have to create an handler in the script you're going to load (in your answer you already did this with "screen_size()".
In your case this script will be "screen_size.scpt".
So "screen_size.scpt" will have to look something like this:
on screen_size()
--your actions
return [yourvalue] --the value you want to pass to the other script
end screen_size()
The script you'll load it from will have to look like this:
tell application "Finder"
set _myPath to (container of (path to me) as text & "screen_size.scpt") as alias
end tell
set _ScreenSizeScript to load script _myPath
set _bounds to _ScreenSizeScript's screen_size()
If it doesn't work, or you don't understand me completely, feel free to ask (:
Yes there is a way to do this. Load the file into a property and access it that way
property _ScreenSize : load script (alias "pathtoscript")
_ScreenSize's doStuff()
and for relative paths try this:
set p to "./screen_size.scpt"
set a to POSIX file p
so perhaps this will work:
set p to "./screen_size.scpt"
set a to POSIX file p
property _ScreenSize : load script (alias a)
_ScreenSize's doStuff()
I have people using my libraries on a daily basis, so I first ensure the library is here before calling it.
Let's say I have a library "Lib.Excel.app" (save as non-editable application with Satimage's Smile).
At the beginning of a script that makes use of it, I "load" the library by using this code :
set commonCodeFile to (path to library folder as string) & "Scripts:CommonLibraries:Lib.Excel.app"
tell application "Finder"
if not (exists (file commonCodeFile)) then error ("\"Lib.Excel\"
" & "
should be found in folder
" & "
scroll > CommonLibraries")
end tell
global cc -- make it short and easy to write :)
set cc to load script alias ccFile
Then when I have to use a function from the lib, I just call it like this :
set {what, a} to cc's veryNiceFunction()
Yes you can. You need the full path to the script however.
I believe you can still use "path to me" to get the path to the app executing the current script, and you can then modify that path to point to your sub-folder containing the scripts.
I used this technique to get around AppleScripts (former) 32k text size limits years ago for some really large/complex IRC scripting.
I think I still have all those old scripts in my G4, which is under the desk in my office at work. Sadly it's behind a Enet switch and I can't VNC into it otherwise I'd have tons of sample code to post.
You CAN load the script in a variable, but you have to declare it first.
property _ScreenSize : missing value
tell application "Finder" to set _myPath to container of (path to me) as text
set _loadPath to (_myPath & "screen_size.scpt")
set _loadAlias to alias _loadPath
set _ScreenSize to (load script _loadAlias)

Resources