Find and replace in text files using AppleScript

22,238

Solution 1

Here an version that doesn't need text edit. It will read the file in utf-8 encoding, update it's contents and store that back into the file as utf-8 encoded text. The reason I use an try block around writing the file is that there will be an error if another application has the file open with read permission at the same time. The considering case block can be wrapped around the set ti to every text item of theContent if you want the search and replace case sensitive. There is no need for this to be active when you replace the string, only for finding it.

set stringToFind to "replace that"
set stringToReplace to "with this"
set theFile to choose file
set theContent to read theFile as «class utf8»
set {oldTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, stringToFind}
set ti to every text item of theContent
set AppleScript's text item delimiters to stringToReplace
set newContent to ti as string
set AppleScript's text item delimiters to oldTID
try
    set fd to open for access theFile with write permission
    set eof of fd to 0
    write newContent to fd as «class utf8»
    close access fd
on error
    close access theFile
end try

Solution 2

Well, yes, as @dj_bazzie_wazzie points out, you really don't need a text editor for this, you can use the terminal and do something like:

perl -pi -e 's/old text/new text/g' /path/to/theFile.plist

which of course you can use in AppleScript with the powerful do shell script command:

do shell script "perl -pi -e 's/" & search_string & "/" & replacement_text & "/g' " & quoted form of (POSIX path of file_path)

--assuming file_path is a variable with Mac-style (colon-separated) file path.

Solution 3

Modified from http://discussions.apple.com/message/20542594#20542594, the handler below does what you want. I made a few changes and added your variables. A few notes: (1) the 'my' before the handler call makes sure it is seen as the script's handler and not something TextEdit should interpret 'internally' (because it is in a tell block); (2) 'considering case' makes the handler case sensitive, which I assume you want; (3) You might consider something like TextWrangler, which has robust and feature-rich AppleScript support, and includes text replacement in its AS dictionary, as does Smile, a fantastic Script Editor (which can work with text, and formats plist files nicely).

tell application "TextEdit"
    set workingWin to open this_document
    set this_text to the text of the workingWin
    set the text of the workingWin to (my replaceText(this_text, search_string, replacement_text))
    close workingWin saving yes
end tell

to replaceText(someText, oldItem, newItem)
    (*
         replace all occurances of oldItem with newItem
              parameters -     someText [text]: the text containing the item(s) to change
                        oldItem [text, list of text]: the item to be replaced
                        newItem [text]: the item to replace with
              returns [text]:     the text with the item(s) replaced
         *)
    considering case
        set {tempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, oldItem}
        try
            set {itemList, AppleScript's text item delimiters} to {text items of someText, newItem}
            set {someText, AppleScript's text item delimiters} to {itemList as text, tempTID}
        on error errorMessage number errorNumber -- oops
            set AppleScript's text item delimiters to tempTID
            error errorMessage number errorNumber -- pass it on
        end try
    end considering
    return someText
end replaceText
Share:
22,238
mash3d3d
Author by

mash3d3d

Updated on September 24, 2020

Comments

  • mash3d3d
    mash3d3d over 3 years

    I am trying to write an applescript which will run via a launch agent. What the script needs to do is edit a user preference plist file so that default save locations are specific to that user. I am aware that this can be done by just setting "~/documents" as the location in the template plist. But Premier Pro for example also needs to write scratch files to a local drive. For simplicity I would like each user to have these put in a locations based on their username. This script will only need to run if the local profile has just been created from a template at first log on.

    I have started by using some sample code found on this site and just making a simple test below. This test should edit a txt file and replace one word with another. This script is currently not working. When tested it opens up test.txt in TextEdit but does nothing more. No errors are displayed either.

    Thank you in advance

    John.

    replaceText("replace this", "replace with this", "/Volumes/USB_Drive/test.txt")
    
    
    on replaceText(search_string, replacement_text, this_document)
    tell application "TextEdit"
        open this_document
        set AppleScript's text item delimiters to the search_string
        set this_text to the text of the front document as list
        set AppleScript's text item delimiters to the replacement_text
        set the text of the front document to (this_text as string)
        close this_document saving yes
    end tell
    end replaceText