Hi. I’m trying to write a simple script that opens a text file from a specific folder in TextWrangler, runs a replace changing all “|” into tabs, saves and closes the file and then moves on to the next file in the folder.
When I run my script I get the following error message:
The problem seems to be centered around the replace function. (If I run the same script, telling it only to open the files in TextWrangler and nothing more, it works just fine.)
Here is my code. If anyone out there can find my error and point me in the right direction, I’d be very grateful.
Thanks,
Shannon
set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
set aFiles to files in aFolder
end tell
repeat with CurrentFile in aFiles
tell application "TextWrangler"
open CurrentFile
replace "|" using " " searching in text 1 of text document CurrentFile options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
save CurrentFile
close CurrentFile
end tell
end repeat
When usung a repeat with a in b
a is pointer to item 1 of b
so converting to a string fixes the problem
set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
set aFiles to files in aFolder
end tell
repeat with CurrentFile in aFiles
set CurrentFile to CurrentFile as string
tell application "TextWrangler"
open CurrentFile
tell document 1
replace "|" using " " searching in text 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
save
close
end tell
end tell
end repeat
It’s also the case that the list returned by the Finder contains Finder references, which TextWrangler doesn’t understand. It’s actually that that’s cured by coercing each reference to string (or preferably to Unicode text or alias). Getting the Finder to return aFiles as an alias list would achieve the same thing.
To make Mr. G’s last point clearer with an example, this construction is quite common:
set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
try
set aFiles to files in aFolder as alias list -- this form errors if there is only one file in the chosen folder
on error
set aFiles to files in aFolder as alias as list -- this form works with one file
end try
end tell
--> a list of aliases to the files at the top level of the chosen folder
If the chosen folder might contain folders and you want the files in them too:
set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
try
set aFiles to files in entire contents of aFolder as alias list
on error
set aFiles to files in entire contents of aFolder as alias as list
end try
end tell
--> a list of aliases to every file at any depth within the chosen folder.
I don’t like and don’t use the alias list construction, unless it’s sure, that the list contains more than one item.
If not, I perfer the “on-the-fly” coercion
...
repeat with CurrentFile in aFiles
tell application "TextWrangler"
open (CurrentFile as alias)
tell document 1
replace "|" using " " searching in text 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
save
close
end tell
end tell
end repeat
...
I prefer the “alias list construction” above when I don’t know what might be in a chosen folder and then I know for every time I use an item from that list that it’s an alias. Your construction avoids having to know what’s in the folder chosen because it coerces the file or files found individually. I would guess that would take longer to do than constructing an alias list does (requiring as it does only one Apple Event call instead of one per repeat), but in this case (or for small numbers of files) that doesn’t matter. A matter of philosophy, I guess - if I can do things outside of subsequent repeat loops, I always do.
An alternative, if the application opening the files understands Unicode text paths (as TextWrangler does), is to mass coerce the references to Unicode text, which compares very favourably for speed:
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to return as Unicode text
tell application "Finder" to set aFiles to paragraphs of (files of aFolder as Unicode text)
set AppleScript's text item delimiters to astid
Besides having the Finder coerce the references en masse, more speed can be obtained by having TextWrangler open, resave, and close the documents en masse, so that the repeat loop only has to cycle through documents already in memory.
In TextWrangler 2.1.2, documents have a ‘contents’ property, not multiple ‘text’ elements “ although you wouldn’t know so from the dictionary. The dictionary also doesn’t say that windows contain documents. (Maybe it depends on the window settings in TextWrangler’s “Documents” preferences.) Anyway, this works very quickly for me:
set aFolder to choose folder with prompt "Choose a folder:"
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to return as Unicode text
tell application "Finder" to set aFiles to paragraphs of (files of aFolder as Unicode text)
set AppleScript's text item delimiters to astid
tell application "TextWrangler"
activate
open aFiles opening in new_window
tell front window
repeat with i from 1 to (count documents)
replace "|" using " " searching in contents of document i options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
end repeat
save documents
close documents
end tell
end tell
My 2 cents. Your list doesn’t allow for no files. I do it this way
set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
set ThenCount to (count of files in entire contents of aFolder)
if ThenCount = 0 then
set TheFileList to {}
else if ThenCount = 1 then
set TheFileList to files in entire contents of aFolder as alias as list
else
set TheFileList to files in entire contents of aFolder as alias list
end if
end tell
Interesting! There’s a bug or an inconsistency here. If the ‘entire contents’ doesn’t contain the required elements, it errors instead of returning an empty list.
set aFolder to choose folder with prompt "Choose a folder with no files:"
tell application "Finder" to get files of aFolder -- as alias list
--> {}
tell application "Finder" to get files of entire contents of aFolder -- as alias list
--> Error.
So something like this is required to get around two bugs - ugh (It’s coercing a null result to alias that fails)
set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
try
-- try for more than one
set aFiles to files in entire contents of aFolder as alias list
on error
-- oops, try for one or fewer
try
set aFiles to files in entire contents of aFolder as alias as list
on error
-- oops, there aren't any
set aFiles to {}
end try
end try
end tell