I want to write a script in AppleScript that will output all numbers from 0000 to 9999 in turn to an application (here it is System Preferences) using the keystroke command. I have this so far that will do one number:
tell application "System Preferences" to activate
delay 0.5
tell application "System Events"
keystroke (1234)
end tell
But I would have to manually make 9998 more of these, which is obviously undoable.
I also have text file that has all of the numbers from 0000 to 9999 in a format like:
0000 0001 0002 0003 0004 0005
etc, and also a text file formatted like
0001
0002
0003
0004
0005
etc.
How could I import each of these numbers in turn to the keystroke command in the script I wrote above, so that it would go through all of those numbers in the same script? Maybe in a repeating script?
I would also want to output a terminal command after each keystroke command, but I think I could manage that.
Any help would be appreciated!
You have several questions there, but they all involve using the repeat statement:
tell application "Whatever" to activate -- this is where the keystrokes will go
delay 0.5
# repeat from startingValue to endingValue
set prefix to "0000" -- for leading zeros
repeat with aValue from 0 to 1000
tell application "System Events"
keystroke text -4 thru -1 of (prefix & aValue)
end tell
end repeat
# repeat with words in some text (punctuation, etc are skipped)
set test to read "/path/to/words/file.txt" -- POSIX path
repeat with aWord in (words of test)
tell application "System Events"
keystroke aWord
end tell
end repeat
# repeat with paragraphs in some text (handles different line endings)
set test to read "disk:path:to:paragraphs:file.txt" -- HFS path
repeat with aParagraph in (paragraphs of test)
if aParagraph is not in {"", return} then -- no empty paragraphs
tell application "System Events"
keystroke aParagraph
end tell
end if
end repeat
See the AppleScript Language Guide for language features and syntax.
Assuming you saved following valid Terminal commands as plain text, in the .txt file, and Terminal prompt is already active,
echo 'Hello, one'
echo 'Hello, two'
echo 'Hello, three'
you can execute commands number 2 and 3 using following simple script:
set {startNumber, endNumber} to {2, 3}
set texfFile to choose file of type "public.text"
set theParagraphs to read texfFile
tell application "Terminal" to activate -- required
tell application "System Events"
repeat with i from startNumber to endNumber
keystroke (paragraph i of theParagraphs) & return
end repeat
end tell
Generally, it is better to not use GUI scripting at all:
set {startNumber, endNumber} to {2, 3}
set texfFile to choose file of type "public.text"
set theParagraphs to read texfFile
tell application "Terminal"
activate
repeat with aNumber from startNumber to endNumber
do script (paragraph aNumber of theParagraphs) in window 1
end repeat
end tell
Related
I was looking for a script that would batch convert all *.numbers files in a given folder to *.csv files.
I found the following on GitHub and added an additional line as suggested in the comments suggestion. When I run the script, Numbers launches and opens the test file from the folder specified - but the file is not exported. Numbers just stays open and terminal errors out with:
/Users/Shared/Untitled.scpt: execution error: Numbers got an error: Invalid key form. (-10002)
The script (located in /Users/Shared) has the following permissions:
-rwxr-xr-x
#!/usr/bin/osascript
on run argv
set theFilePath to POSIX file (item 1 of argv)
set theFolder to theFilePath as alias
tell application "Finder" to set theDocs to theFolder's items
-- Avoid export privilege problem
set privilegeFile to (theFolder as text) & ".permission"
close access (open for access privilegeFile)
repeat with aDoc in theDocs
set docName to aDoc's name as text
if docName ends with ".numbers" then
set exportName to (theFolder as text) & docName
set exportName to exportName's text 1 thru -9
set exportName to (exportName & "csv")
tell application "Numbers"
open aDoc
delay 5 -- may need to adjust this higher
tell front document
export to file exportName as CSV
close
end tell
end tell
end if
end repeat
end run
Any suggestions?
Here is what I did and works for me in macOS High Sierra:
In Terminal:
touch numb2csv; open -e numb2csv; chmod +x numb2csv
• This creates an empty ASCII Text file named numb2csv.
• Opens, by default, numb2csv in TextEdit.
• Makes the numb2csv file executable.
Copy and paste the example AppleScript code, shown further below, into the opened numb2csv file.
Save and close the numb2csv file.
In Terminal executed the numb2csv executable file, e.g.:
./numb2csv "$HOME/Documents"
This created a CSV file of the same name as each Numbers document in my Documents folder, not traversing any nested folders.
Example AppleScript code:
#!/usr/bin/osascript
on run argv
set theFilePath to POSIX file (item 1 of argv)
set theFolder to theFilePath as alias
tell application "System Events" to set theDocs to theFolder's items whose name extension = "numbers"
repeat with aDoc in theDocs
set docName to aDoc's name as text
set exportName to (theFolder as text) & docName
set exportName to exportName's text 1 thru -8
set exportName to (exportName & "csv")
tell application "Numbers"
launch
open aDoc
repeat until exists document 1
delay 3
end repeat
tell front document
export to file exportName as CSV
close
end tell
end tell
end repeat
tell application "Numbers" to quit
end run
NOTE: As coded, this will overwrite an existing CSV file of the same name as each Numbers file processed, if they already exist. Additional coding required if wanting to not overwrite existing files
If you receive the Script Error:
Numbers got an error: The document “name” could not be exported as “name”. You don’t have permission.
It is my experience that the Numbers document was not fully opened prior to being exported and that increasing the value of the delay command resolves this issue. This is of course assuming that one actually has write permissions in the folder the target Numbers documents exists.
Or one can introduce an error handler within the tell front document block which, if my theory is right about the target document not being fully loaded before the export, will give additional time, e.g.:
Change:
tell front document
export to file exportName as CSV
close
end tell
To:
tell front document
try
export to file exportName as CSV
close
on error
delay 3
export to file exportName as CSV
close
end try
end tell
Note: The primary example AppleScript code is just that and does not contain any error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. See included example directly above.
I was looking for that, unfortunately, that doesn’t work anymore.
This line
tell application "System Events" to set theDocs to theFolder's items whose name extension = "numbers"
Gets the following error:
execution error: Can’t make file "file.numbers" of application "System Events" into the expected type. (-1700)
macOs Big Sur Versio 11.01
automator version 2.10
Numbers version 10.3.5
Inspired by this thread and those articles Exporting Numbers Documents and Get full directory contents with AppleScript
The following code works:
#!/usr/bin/osascript
log "Start"
property exportFileExtension : "csv"
tell application "Finder"
activate
set sourceFolder to choose folder with prompt "Please select directory."
set fileList to name of every file of sourceFolder
end tell
set the defaultDestinationFolder to sourceFolder
repeat with documentName in fileList
log "documentName: " & documentName
set fullPath to (sourceFolder as text) & documentName
log "fullPath: " & fullPath
if documentName ends with ".numbers" then
set documentName to text 1 thru -9 of documentName
tell application "Finder"
set newExportItemName to documentName & "." & exportFileExtension
set incrementIndex to 1
repeat until not (exists document file newExportItemName of defaultDestinationFolder)
set newExportItemName to ¬
documentName & "-" & (incrementIndex as string) & "." & exportFileExtension
set incrementIndex to incrementIndex + 1
end repeat
end tell
set the targetFileHFSPath to ¬
(defaultDestinationFolder as string) & newExportItemName
tell application "Numbers"
launch
open fullPath
with timeout of 1200 seconds
export front document to file targetFileHFSPath as CSV
end timeout
close
end tell
end if
end repeat
user3439894's answer works with a few change:
exists document 1 => number of documents > 0
I have a bunch of files in a folder named something like this:
123456_this_is_a_fun_test_v01.mov
685954_this_more_is_a_fun_test_v01_clean.mov
They all have a 6 digit number in the beginning and a version number somewhere. What i need to do is remove the version number and move the first 6 digits til the end, before the extension name, like this:
this_is_a_fun_test_123456.mov
this_more_is_a_fun_test_clean_685954.mov
Been trying some stuff out in automator and some simple Applescripting, but without any luck. My scripting skills are not good, I'm only at "Hobby" level. Anyone got some advice?
tell application "Finder"
--grab the selected files and put them into a variable
set F to selection
end tell
-- This will be the character used to rejoin pieces
-- of the filename after breaking them apart
set the text item delimiters to "_"
repeat with g in F -- Loop through the file list
-- Get the filename
tell application "System Events" to get name of g
-- Eliminate the version number component of the filename
set r to do shell script ¬
"echo " & quoted form of result & ¬
" | egrep -o '[^_\\.]+'" & ¬
" | egrep -iv 'v\\d+'"
-- Assemble the other components in the new order
get {paragraphs 2 thru -2, paragraph 1} of r
get (result as text) & ".mov"
-- Rename the file to the new name
tell application "System Events" to set name of g to result
end repeat
I've added comments to this AppleScript, which explain what each part of the script does. As it stands, it's designed to run from inside Script Editor, but it could easily be tweaked to be part of an Automator workflow.
Copy-n-paste the script into Script Editor. Replace /Path/To/Folder with the path to the folder in which your .mov files are located (keep the quotes). Use the full path, i.e. /Users/CK/Movies and not ~/Movies. Press Cmd+K to compile the script, and check for pre-run syntax errors, and the like. When the fonts change and the script looks all pretty-printed, then hit Cmd+R to execute it.
tell application "System Events" to get the files in folder ¬
"/Path/To/Folder" whose name extension is "mov"
set F to the result -- The list of .mov files that need renaming
-- This will be the character used to rejoin pieces
-- of the filename after breaking them apart
set the text item delimiters to "_"
repeat with g in F -- Loop through the file list
-- Get the filename
tell application "System Events" to get name of g
-- Eliminate the version number component of the filename
set r to do shell script ¬
"echo " & quoted form of result & ¬
" | egrep -o '[^_\\.]+'" & ¬
" | egrep -iv 'v\\d+'"
-- Assemble the other components in the new order
get {paragraphs 2 thru -2, paragraph 1} of r
get (result as text) & ".mov"
-- Rename the file to the new name
tell application "System Events" to set name of g to result
end repeat
With a bit of google Fu and a lot of looking at your code i got it to work on selected files. Thanks for the help
tell application "Finder"
set F to selection
end tell
set the text item delimiters to "_"
repeat with g in F -- Loop through the file list
-- Get the filename
tell application "Finder" to get name of g
-- Eliminate the version number component of the filename
set r to do shell script ¬
"echo " & quoted form of result & ¬
" | egrep -o '[^_\\.]+'" & ¬
" | egrep -iv 'v\\d+'"
-- Assemble the other components in the new order
get {paragraphs 2 thru -2, paragraph 1} of r
get (result as text) & ".mov"
-- Rename the file to the new name
tell application "Finder" to set name of g to result
end repeat
tell application "System Events"
activate
display dialog "Selected files have been renamed!"
end tell
I am using the below script for few months. It ask the user to select from the list and copy paste the text in MS Word and run some VB Macro and save the file as Text file.
tell application "Finder"
if not (exists folder "Test" of desktop) then make new folder at desktop with properties {name:"Test"}
end tell
set desktopTestFolder to (path to desktop folder as text) & "Test:"
set mychoice to (choose from list {"PS List", "AA Table", "PS Legend", "PO Chart", "MD"} with prompt "Please select which sound you like best" default items "None" OK button name {"Play"} cancel button name {"Cancel"})
if mychoice is false then error number -128 -- user canceled
tell application "Microsoft Word"
set theContent to content of text object of selection
copy object text object of selection
set newDoc to make new document
delay 2
tell application "System Events"
tell process "Microsoft Word"
keystroke "v" using command down
end tell
end tell
run VB macro macro name "Normal.NewMacros.Clean"
run VB macro macro name "Normal.Module9.bold"
save as newDoc file format format Unicode text file name (desktopTestFolder & mychoice & ".txt")
close document 1 saving no
end tell
But when I try it to put in an handler it not works. What I have tried is:
tell application "Finder"
if not (exists folder "Test" of desktop) then make new folder at desktop with properties {name:"Test"}
end tell
set desktopTestFolder to (path to desktop folder as text) & "Test:"
set mychoice to (choose from list {"PS List", "AA Table", "PS Legend", "PO Chart", "MD"} with prompt "Please select which sound you like best" default items "None" OK button name {"Play"} cancel button name {"Cancel"})
if mychoice is false then error number -128 -- user canceled
set mychoice to mychoice as text
if mychoice is equal to "PS List" then
handler1()
else
handler2()
end if
on handler1()
tell application "Microsoft Word"
set theContent to content of text object of selection
copy object text object of selection
set newDoc to make new document
delay 2
tell application "System Events"
tell process "Microsoft Word"
keystroke "v" using command down
end tell
end tell
run VB macro macro name "Normal.NewMacros.EDCleanup1"
run VB macro macro name "Normal.Module9.bold"
save as newDoc file format format Unicode text file name (desktopTestFolder & mychoice & ".txt")
close document 1 saving no
end tell
end handler1
on handler2()
tell application "Microsoft Word"
run VB macro macro name "Normal.NewMacros.EDCleanup1"
run VB macro macro name "Normal.Module9.bold"
save as newDoc file format format Unicode text file name (desktopTestFolder & mychoice & ".txt")
close document 1 saving no
end tell
end handler2
Please let me know, Where I am wrong?
Thanks
Josh
You didn't say what result you get when you say "it not works". Do you get an error? Do you get nothing? Do you get the same result when you select "PS List" versus the others?
The error I see is that you never bring Microsoft Word to the front. This is necessary for when you're using UI scripting and the keystroke command. Add 'activate' to your Word tell blocks.
tell application "Microsoft Word"
activate
set theContent to content of text object of selection
…
Also, yes, your variable desktopTestFolder loses scope. You can make the variable a global property by placing this at the front of your script:
property desktopTestFolder: ""
I'm trying to read an html file into a variable in AppleScript, I have the following code.
tell application "Finder"
set theItems to every file of folder folderName
repeat with theFile in theItems
open for access theFile
set fileContents to (read theFile)
end repeat
end tell
Now I get an error like:
Finder got an error: Can’t make document file "index.html" of folder
[...] of startup disk into type «class fsrf».
What am I doing wrong? I followed this example. Are HTML files not recognized as text?
You have to convert the Finder file objects to aliases or text.
read can be used without separate open or close commands. It reads files as MacRoman without as «class utf8» though. (as Unicode text is UTF-16.)
tell application "Finder" to files of folder "HD:Users:lauri:Sites" as alias list
repeat with f in result
read f as «class utf8»
end repeat
Try:
tell application "Finder" to set theItems to every file of folder folderName
repeat with theFile in theItems
set aFile to POSIX path of (theFile as text)
set fileContents to do shell script "cat " & quoted form of aFile
end repeat
Starting from your original code, this should do it:
set folderPath to choose folder
set someData to ""
tell application "Finder"
set theItems to every file of folder folderPath as list
repeat with theFile in theItems
set theFilePath to theFile as text
if characters -5 thru -1 of theFilePath as string is ".html" then
set theFileHandle to (open for access file theFilePath)
set fileContents to (read theFileHandle)
-- for testing, call some function
set someData to someData & return & processHtml(fileContents) of me
close access theFileHandle
end if
end repeat
-- do something with someData here
return someData
end tell
on processHtml(theData)
-- do something with theData here
return theData
end processHtml
As Lauri wrote, you can add "as «class utf8»" to read the file as UTF8. You could also use "as Unicode text" for UTF16. Personally, I like this, because it is vanilla AppleScript and doesn't need shell scripting.
Using open for access is really doing it the hard way.
If you want to read an HTML file with AppleScript, then the best way to do that is to use AppleScript to tell an HTML editor to read the HTML file for you. That is the fundamental way that AppleScript works. That’s why “tell” is the most important command. That’s why you can accomplish your goal of reading an HTML file into a variable in just 3 lines:
tell application "BBEdit"
open (choose file)
set theHTMLSource to the text of document 1
close document 1
end tell
The following script expands on the above to read an arbitrary number of HTML files from a chosen folder. It works with BBEdit 9, and should also work with BBEdit’s free version, which is called “TextWrangler” and is available in Mac App Store. Or you can fairly easily adapt this script for use with HyperEdit or TextEdit or whatever AppleScript-aware HTML/text editor you prefer to use.
tell application "Finder"
set theFolder to (choose folder)
set theFiles to every file of folder theFolder
set theHTMLSourceList to {}
repeat with theFile in theFiles
if the kind of theFile is equal to "HTML document" then
set theName to the name of theFile
tell application "BBEdit"
open file (theFile as text)
set theSource to the text of document 1
copy {theName, theSource} to the end of theHTMLSourceList
close document 1
end tell
end if
end repeat
end tell
When the above script is finished, the variable “theHTMLSourceList” is populated with the names and source code of the entire folder of HTML documents, like so:
{{name of file 1, source of file 1}, {name of file 2, source of file 2}, {name of file 3, source of file 3}}
… and so on up to an arbitrary number of files. But of course you can have the script return the HTML source to you in whatever way you like. The key point is that an AppleScript-aware HTML editor can both read HTML and set AppleScript variables, so you don’t have to write (and debug and maintain) your own HTML reader in tiny AppleScript.
The deal is this:
I use http://www.clipmenu.com/ ClipMenu to have 20 states of the clipboard, because i need to copy each line of some txt file separated. So i open the txt file, and i go through every line hitting command+shift+→ then command+c then ↑ and so on until i reach the top and i have all the lines copied and stored in the history of ClipMenu.
My question is, is there a way to make a service or script that copies every single line in an automated way? i think i could make a script that repeat those keystrokes until it reaches the top of the txt file but i have no idea how to make it so.
Thanks a lot.
I do not know how to do this using Automator, but using mono [MonoMac] it is very simple:
using (System.IO.FileStream file = new System.IO.FileStream("path", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)) {
using (System.IO.StreamReader reader = new System.IO.StreamReader(file)) {
while (!reader.EndOfStream) {
String line = reader.ReadLine ();
System.Windows.Forms.Clipboard.SetText(line);
}
}
}
Try:
set fileText to read (choose file) as «class utf8»
set filePara to paragraphs of fileText
repeat with aPara in filePara
set aPara to contents of aPara
if aPara ≠ "" then set the clipboard to aPara
end repeat
ClipMenu seems to ignore "transient" clipboards, so you also need a delay between the copy actions:
read POSIX file "/Users/username/Documents/test.txt" as «class utf8»
repeat with p in reverse of paragraphs of result
if contents of p is not "" then set the clipboard to contents of p
delay 1
end repeat
Or using UI scripting:
delay 1
tell application "TextEdit"
activate
set n to number of paragraphs of document 1
end tell
tell application "System Events"
key code {125, 123} using command down
repeat n times
key code 124 using {shift down, command down}
keystroke "c" using command down
key code 126
delay 1
end repeat
end tell
The key codes are listed in Events.h.