I am trying to create a log of when my computer turns off and on. To do this I am writing a script to run at start up that will write to a text file however it is telling me that I don't have permission to write to the file.
Using print statements I have determined that the try block terminates after the first line.
writeTextToFile(getTimeInHoursAndMinutes(), "Users/labspecialist/Desktop/system_log")
on writeTextToFile(theText, theFile)
try
-- Convert the file to a string
set theFile to theFile as string
-- Open the file for writing
set theOpenedFile to (open for access file theFile with write permission)
-- Write the new content to the file
write theText to theOpenedFile starting at eof
-- Close the file
close access theOpenedFile
-- Return a boolean indicating that writing was successful
return true
-- Handle a write error
on error
-- Close the file
try
close access file theFile
end try
-- Return a boolean indicating that writing failed
return false
end try
end writeTextToFile
on getTimeInHoursAndMinutes()
-- Get the "hour"
set timeStr to time string of (current date)
set Pos to offset of ":" in timeStr
set theHour to characters 1 thru (Pos - 1) of timeStr as string
set timeStr to characters (Pos + 1) through end of timeStr as string
-- Get the "minute"
set Pos to offset of ":" in timeStr
set theMin to characters 1 thru (Pos - 1) of timeStr as string
set timeStr to characters (Pos + 1) through end of timeStr as string
--Get "AM or PM"
set Pos to offset of " " in timeStr
set theSfx to characters (Pos + 1) through end of timeStr as string
return (theHour & ":" & theMin & " " & theSfx) as string
end getTimeInHoursAndMinutes
I expect when I run this to get an output of true and for my file to contain a new line of the current time. However it currently returns false with nothing written to the file.
The problem is that your script is using a file specifier in the open for access line, where it should use a POSIX file specifier (because you're feeding the command a POSIX path). It should look like this:
writeTextToFile(getTimeInHoursAndMinutes(), "/Users/labspecialist/Desktop/system_log")
on writeTextToFile(theText, theFile)
try
-- Convert the file to a string
set theFile to theFile as string
-- Open the file for writing
set theOpenedFile to (open for access POSIX file theFile with write permission)
-- Write the new content to the file
write theText to theOpenedFile starting at eof
-- Close the file
close access theOpenedFile
-- Return a boolean indicating that writing was successful
return true
-- Handle a write error
on error errstr
display dialog errstr
-- Close the file
try
close access file theFile
end try
-- Return a boolean indicating that writing failed
return false
end try
end writeTextToFile
P.s. And yes, you really should use that opening slash in the file path, though it seems to work regardless...
Related
Thanks everyone for your help so far. And apologies I asked this in the 'answer' section of a previous question which I now understand I shouldn't have done ..... so I have started a new question here.
SO, I wanted to write a script to save the attachments in emails as they arrive - with a different folder for each email sender. I got a lot of help from people on this site.
It sort of works ..... for new incoming emails it works perfectly, but when I run it against my old emails in my mailbox it saves some attachments and not others.
I thought the problem was an error on finding a duplicate (which I thought would be unlikely as I have added the time stamp to the filename along with the data stamp of the email.) So I added the delFile delete process to check for a file of the same name and if it finds it to delete it.
When I execute the script it processes a few more attachments than before but not all by any means..... and interestingly nothing get put in the trash bin.
I am now stumped!! As a newcomer to AppleScript I don't know how to debug or handle errors yet.
Can anyone help please?
use scripting additions
using terms from application "Mail"
on perform mail action with messages messageList for rule aRule
set destinationPath to (POSIX file "/volumes/Data/Dropbox/WORK ITEMS/Email Attachments/") as string
tell application "Mail"
repeat with aMessage in messageList
repeat with anAttachment in mail attachments of aMessage
set senderName to (extract name from sender of aMessage)
set {year:y, month:m, day:d, hours:h, minutes:min} to date received of aMessage
set timeStamp to (d & "/" & (m as integer) & "/" & y & " " & h & "." & min) as string
set attachmentName to timeStamp & " - " & name of anAttachment
set doSave to true
set originalName to name of anAttachment
if originalName contains "jpg" then
set doSave to false
else if originalName contains "jpeg" then
set doSave to false
else if originalName contains "gif" then
set doSave to false
else if originalName contains "png" then
set doSave to false
else if originalName contains "html" then
set doSave to false
else if originalName contains "ics" then
set doSave to false
end if
if doSave is true then
tell application "System Events"
if not (exists folder (destinationPath & senderName)) then
make new folder at end of alias destinationPath with properties {name:senderName}
end if
end tell
end if
if doSave is true then
set delFile to destinationPath & senderName & ":" & attachmentName
tell application "System Events" to if (exists file delFile) then delete file delFile
end if
if doSave is true then save anAttachment in file (destinationPath & senderName & ":" & attachmentName) with replacing
end repeat
end repeat
end tell
end perform mail action with messages
end using terms from
Thanks
I'm not sure I can help with the precise reason for your script's failure, but I might be able to help you see where it's failing.
First of all, I would substitute a list of file extensions that you wish to exclude for the long if...else if block. Something like:
set ignore list to {".jpg", ".jpeg", ".gif", ".png", ".html", ".ics"} at the top of the script, with set fileExtension to rich text (offset of "." in originalName) thru end of originalName in the loop.
You can then test:
if fileExtension is not in ignoreList then
and wrap this around the saving code (you don't need to do the same test several times).
I think your delete file block is redundant, because it should be doing the same as the following save...with replacing (if the file's already there). (You may want to delete the file if it exists, in which case remove the with replacing later on.)
To start debugging, first of all remove the code up top that works with incoming messages and replace it with set messageList to selection. Try inserting some display dialog <varname> in places where you're not sure what's happening. For example, you know what anAttachment is but are you certain what destinationPath & senderName & ":" & attachmentName are?
Finally, note that I have NOT run this on YOUR data, so be sure to do a back-up. It shouldn't destroy anything, but better safe than sorry!
Please come back with any questions. Good luck!
EDIT:
I have added a function at the top (the on getExtension(fileName) block. This is called by the line set fileExtension to my getExtension(originalName)
This is to refine extension getting by reversing the name string, so that only the first '.' is found. Once got the extension is reversed.
Another crucial part is that this contains try ... on error ... end try. This is how AppleScript does error handling. If there is no '/' an error is thrown. This is caught by on error which returns 'skip'. (At this point this is not used in the main program, but could be used to funnel all the output to a catchall folder.)
The final change is that I have wrapped the saving part in If originalName does not contain "/" then ... end if. This is to catch those files that contain a '/' and to 'jump over' them without doing anything.
I have NOT needed to add a delay, so try without one to start with. It might have been a red herring!
set ignoreList to {".jpg", ".jpeg", ".gif", ".png", ".html", ".ics"}
set destinationPath to (POSIX file "/volumes/Data/Dropbox/WORK ITEMS/Email Attachments/") as string
on getExtension(fileName)
try
set fileName to (reverse of every character of fileName) as string
set extension to text 1 thru (offset of "." in fileName) of fileName
set extension to (reverse of every character of extension) as string
return extension
on error
return "skip"
end try
end getExtension
tell application "Mail"
set messageList to selection
repeat with aMessage in messageList
repeat with anAttachment in mail attachments of aMessage
set senderName to (extract name from sender of aMessage)
set {year:y, month:m, day:d, hours:h, minutes:min} to date received of aMessage
set timeStamp to (d & "/" & (m as integer) & "/" & y & " " & h & "." & min) as string
set attachmentName to timeStamp & " - " & name of anAttachment
set originalName to name of anAttachment
if originalName does not contain "/" then
set fileExtension to my getExtension(originalName)
if fileExtension is not in ignoreList then
tell application "System Events"
if not (exists folder (destinationPath & senderName)) then
make new folder at end of alias destinationPath with properties {name:senderName}
end if
end tell
save anAttachment in file (destinationPath & senderName & ":" & attachmentName) with replacing
end if
end if
end repeat
end repeat
end tell
For calling from a mail rule:
use scripting additions
set ignoreList to {".jpg", ".jpeg", ".gif", ".png", ".html", ".ics"}
set destinationPath to (POSIX file "/Users/bernardharte/test/") as string
on getExtension(fileName)
try
set fileName to (reverse of every character of fileName) as string
set extension to text 1 thru (offset of "." in fileName) of fileName
set extension to (reverse of every character of extension) as string
return extension
on error
return "skip"
end try
end getExtension
using terms from application "Mail"
on perform mail action with messages messageList for rule aRule
tell application "Mail"
repeat with aMessage in messageList
repeat with anAttachment in mail attachments of aMessage
set senderName to (extract name from sender of aMessage)
set {year:y, month:m, day:d, hours:h, minutes:min} to date received of aMessage
set timeStamp to (d & "/" & (m as integer) & "/" & y & " " & h & "." & min) as string
set attachmentName to timeStamp & " - " & name of anAttachment
set originalName to name of anAttachment
if originalName does not contain "/" then
set fileExtension to my getExtension(originalName)
if fileExtension is not in ignoreList then
tell application "System Events"
if not (exists folder (destinationPath & senderName)) then
make new folder at end of alias destinationPath with properties {name:senderName}
end if
end tell
save anAttachment in file (destinationPath & senderName & ":" & attachmentName) with replacing
end if
end if
end repeat
end repeat
end tell
end perform mail action with messages
end using terms from
I have a variable that contains {"THIS", "THAT"} that I am trying to write to a csv so that the csv formats as THIS,THAT. Current it just spits out as THISTHAT.
I think I need to repeat though the variable but I am not sure...
the code is as follows (check the ---> for the important bits):
tell application "Adobe InDesign CC 2014"
delete unused swatches of document 1
set _NotUSED to {"None", "Paper", "Black", "Registration", "Keyline", "ImageLabel", "C=0 M=0 Y=0 K=37", "C=0 M=100 Y=100 K=0", "Map this to white ->", "Dieline", "C=0 M=100 Y=0 K=0"} as string
try
---> Get the variables
set _UpDatedList to get (name of swatches of document 1 whose name is not in _NotUSED)
on error
display alert {"Your document has no spot colours"}
end try
end tell
set filePath to (path to desktop as text) & "Pantones.csv"
---> Set the theString to the variables
set theString to _UpDatedList as string
set theResult to writeTo(filePath, theString, text, false)
if not theResult then display dialog "There was an error writing the data!"
on writeTo(targetFile, theData)
try
set openFile to open for access file targetFile with write permission
---> write the variables to csv
write theData to openFile
close access openFile
return true
on error
try
close access file targetFile
end try
return false
end try
end writeTo
Try this, the easiest way to convert a list to CSV is to use text item delimiters.
The main problem is the coercion to string in the 3rd line. Delete as string.
tell application "Adobe InDesign CC 2014"
delete unused swatches of document 1
set _NotUSED to {"None", "Paper", "Black", "Registration", "Keyline", "ImageLabel", "C=0 M=0 Y=0 K=37", "C=0 M=100 Y=100 K=0", "Map this to white ->", "Dieline", "C=0 M=100 Y=0 K=0"}
try
set _UpDatedList to (get name of swatches of document 1 whose name is not in _NotUSED)
on error
display alert "Your document has no spot colours" buttons {"Cancel"}
return -- abort the script
end try
end tell
set filePath to (path to desktop as text) & "Pantones.csv"
set {TID, text item delimiters} to {text item delimiters, ","}
set csvString to _UpDatedList as text
set text item delimiters to TID
set theResult to writeTo(filePath, csvString)
if not theResult then display dialog "There was an error writing the data!"
on writeTo(targetFile, theData)
try
set openFile to open for access file targetFile with write permission
write theData to openFile
close access openFile
return true
on error
try
close access file targetFile
end try
return false
end try
end writeTo
Here is another option. Just modify your WriteTo handler as shown below to tell it to add a comma after every item in the list, except the last item.
-- Define theString and the target file
set theString to {"This", "That"}
set theFile to (path to desktop as text) & "Pantones.csv"
-- Execute the write handler
set theResult to writeTo (theFile, theString)
on writeTo(targetFile, theData)
set openFile to open for access file targetFile with write permission
set theCount to the count of items in theData
set n to 0
--write to the target file & add a comma after every item except the last
repeat theCount times
set n to n + 1
if n is not theCount then write item n of theData & "," to openFile as string
if n is theCount then write item n of theData to openFile as string
end repeat
close access openFile
end writeTo
In this example, the end result will be your file "Pantones.csv" with the following text:
This,That
Say I have a file sometext.txt . I want the contents of this txt file to show up in the notification which I will trigger using displaynotification in applescript.
In other words I want to be able to:
display notification "File's content" with title "Title".
How can I do it? Assume that sometext.txt and the applescript file are in the same directory.
GOAL
To fire a notification with text from a file that resides in the
same folder as this script.
NOTE
Before execution, save the script because when the script is unsaved, the composed path points to the „~/Library/Autosave Information/„ folder (the place where unsaved scripts are) or even to "/Applications/Utilities/" (where Script-Editor is).
USAGE
The script beeps (when 'errBeep' is true) if something was not
100% ok and displays the status in a notification.
when the text file isn't found the script asks for automatic creation.
if the text file is empty you get notified and it opens the file.
if the length of the text is greater as in allowedCharactersCount (default 65), some action can be performed before firing the notification.
(* *** please customize the appropriate parts *** *)
-- ---------------------------------
-- BEEP when error
-- ---------------------------------
set errBeep to true
--set errBeep to false
-- ---------------------------------
-- file name &
-- number of allowed characters:
-- ---------------------------------
set fileName to "messages.txt"
set allowedCharactersCount to 65
-- ---------------------------------
-- Notification title:
-- ---------------------------------
set notificationTitle to "From: " & fileName
-- ---------------------------------
-- END CUSTOMIZING
-- ---------------------------------
-- ---------------------------------
-- compose file path
-- ---------------------------------
set filePath to my composeFilePath(fileName)
if filePath is "" then
if errBeep then beep
return
end if
-- ---------------------------------
-- check file existence ?
-- ---------------------------------
set filePathExists to my fileExists(filePath)
if not filePathExists then
-- ------------------------------------
-- The file isn't there, ask the user if it should be created (and opened):
-- ------------------------------------
if errBeep then beep
set message to "File " & quoted form of fileName & " at " & return & return & quoted form of filePath & return & return & "is missing."
display dialog message buttons {"Create & Open", "Cancel"} cancel button 2 default button 2 giving up after 20 with title "Where is " & quoted form of fileName & "?" with icon 2
if button returned of the result starts with "Create" then
my readFromFile(filePath) -- this creates the file
tell application "Finder" to open item filePath -- open for edit
end if
return -- we did what we could
end if
-- ---------------------------------------
-- Found the file, now read it:
-- ---------------------------------------
set textFromFile to my readFromFile(filePath)
if textFromFile is not "" then
-- ---------------------------------------------------------
-- Found content, we are ready to fire our notification
-- ---------------------------------------------------------
-- -----------------------------------
-- • but first check length •
-- -----------------------------------
set countCharactersInTextFromFile to count characters in textFromFile -- count includes the "return" characters
if (countCharactersInTextFromFile) is greater than allowedCharactersCount then
-- -----------------------------------
-- • Length is NOT OK
-- More characters as allowed. What to do ? Here, we just beep & change the message and title
-- -----------------------------------
if errBeep then beep
set notificationTitle to "ERROR: " & ((countCharactersInTextFromFile - allowedCharactersCount) as text) & " characters overflow"
set notificationText to (countCharactersInTextFromFile as text) & " characters in textFromFile," & return & (allowedCharactersCount as text) & " characters are allowed."
else
-- -----------------------------------
-- • Length is OK •
-- -----------------------------------
set notificationText to textFromFile
end if
-- ---------------------------------------------------------
-- Fire the notification
-- ---------------------------------------------------------
display notification notificationText with title notificationTitle
-- ---------------------------------------------------------
else
-- ---------------------------------------------------------
-- File is empty! Replace following lines with appropriate action:
-- ---------------------------------------------------------
if errBeep then beep
display notification "*** NO TEXT IN THIS FILE ***" with title "ERROR: EMPTY FILE"
tell application "Finder" to open item filePath -- open for edit
end if
-- ---------------------------------------------------------
-- Sub Routines
-- ---------------------------------------------------------
-- ---------------------------------
-- file existence ?
-- ---------------------------------
on fileExists(filePath)
set filePathExists to false
tell application "Finder"
try
set filePathExists to item filePath exists
end try
end tell
return filePathExists
end fileExists
-- ---------------------------------
-- composeFilePath(fileName)
-- ---------------------------------
on composeFilePath(fileName)
if fileName is "" then return ""
set pathToMe to path to me -- this is the full path to this script
-- get the folder this script is in:
set thisScriptsFolder to ""
tell application "Finder"
try
set thisScriptsFolder to (get container of pathToMe) as text
end try
end tell
if thisScriptsFolder is "" then
return ""
end if
return thisScriptsFolder & fileName -- full path
end composeFilePath
-- ---------------------------------------------------------
-- readFromFile(sourceFile)
-- ---------------------------------------------------------
on readFromFile(sourceFile)
try
set the sourceFile to the sourceFile as string
set the open_sourceFile to open for access file sourceFile
set fileData to read the open_sourceFile
close access the open_sourceFile
return fileData
on error the error_message number the error_number
try
close access file sourceFile
end try
-- display dialog "Error: " & the error_number & ". " & the error_message buttons {"Cancel"} default button 1
return ""
end try
end readFromFile
Here the short version:
set fileName to "messages.txt"
set filePath to my composeFilePath(fileName)
display notification my readFromFile(filePath) with title "From: " & fileName
on readFromFile(sourceFile)
try
set the sourceFile to the sourceFile as string
set the open_sourceFile to open for access file sourceFile
set fileData to read the open_sourceFile
close access the open_sourceFile
return fileData
on error the error_message number the error_number
try
close access file sourceFile
end try
return ""
end try
end readFromFile
on composeFilePath(fileName)
if fileName is "" then return ""
set pathToMe to path to me -- this is the full path to this script
-- get the folder this script is in:
set thisScriptsFolder to ""
tell application "Finder"
try
set thisScriptsFolder to (get container of pathToMe) as text
end try
end tell
if thisScriptsFolder is "" then
return ""
end if
return thisScriptsFolder & fileName -- full path
end composeFilePath
Assuming the contents of the file isn't more than say 20 characters.
Set theContents to read "/posix/path/to/your/file" as «class utf8»
display notification theContents with title "Title"
I want to cook up an Applescript that adds some characters to the beginning and end of each line of text, like this:
Before script execution:
<div>Something</div>
<div>Something</div>
<div>Something</div>
After script execution:
'<div>Something</div>' +
'<div>Something</div>' +
'<div>Something</div>'
How would you go about scripting something like this? Any hints or ideas is highly appreciated :)
Something like this?
set theFile to (choose file) as string
try
set fd to open for access file theFile
set fileContents to read fd as string
close access fd
on error
close access file theFile
return false
end try
set AppleScript's text item delimiters to "' +" & linefeed & "'"
set newFileContents to "'" & (every paragraph of fileContents) & "'" as string
set AppleScript's text item delimiters to ""
try
set fd to open for access file theFile with write permission
set eof of fd to 0
write newFileContents to fd as string
close access fd
on error
close access file theFile
return false
end try
return true
I am trying to get applescript to read todays ical events and write them to a file. The code is as follows:
set out to ""
tell application "iCal"
set todaysDate to current date
set time of todaysDate to 0
set tomorrowsDate to todaysDate + (1 * days)
repeat with c in (every calendar)
set theEvents to (every event of c whose start date ≥ todaysDate and start date < tomorrowsDate)
repeat with current_event in theEvents
set out to out & summary of current_event & "
"
end repeat
end repeat
end tell
set the_file to (((path to documents folder) as string) & "DesktopImage:ical.txt")
try
open for access the_file with write permission
set eof of the_file to 0
write out to the_file
close access the_file
on error
try
close access the_file
end try
end try
return out
The ical items are getting returned correctly and the file ical.txt is created correctly in the folder Documents/DesktopImage, but the file is blank.
Even if I substitute
write out to the_file
with
write "Test string" to the_file
it still comes up blank
any ideas?
Ty
To fix something, you first need to find out what's wrong. You can get the error message when your error handler is invoked, then display it:
on error msg
display dialog "Error accessing " & (the_file as string) & ": " & msg
Once you do this, you quickly see the problem: the_file is a string, not a file, so all the file operations will fail. Define the_file as:
set the_file to alias (((path to documents folder) as string) & "DesktopImage:ical.txt")