AppleScript: How to write to text file in specific location (signaled by specific character)?

I have a .txt file saved on my computer. I want my Automator application to add a bit of text to the .txt file (the text will be entered by the user). I already know how to append text or prepend text in AppleScript. However, I want the text to be inserted into a specific location.

For example, this is the contents of my .txt file entitled My Fruit Log.txt. This is what the .txt file looks like before the text is written to the file:

You can see where exactly I want the text to be saved in the file in this image:

Is what I want to do clear? I want the text to be written on the line directly above the first blank line found in the file. Note: It is not necessarily the second line from the top where I want the text to be written. Depending on what text has already been written to the file, the text might be saved on a lower line. For example:

The location where I want the text to be written must be at least the second line from the top, but it may also be as further down as the seventh line from the top. So, the most reliable way to articulate where I want to write the text is "on the line before the first instance of a blank line in the document."

Can this be accomplished in AppleScript?


Solution 1:

Here's a shell script:

sed -i '' -e ':a' -e 'N' -e '$!ba' -e 's/\n\n/\
Write the new line you wish inserted in your file here\
\
/' ~/Desktop/file.txt

You can wrap this in a ‘do shell script’ if you really want AppleScript, but for an Automator script, you can use a Run Shell Script action and just use the shell script.


Here's an AppleScript wrapper for the script, where the TextToWrite variable and the Target_Filepath variable have been defined elsewhere per your comments:

set addline to "sed -i '' -e ':a' -e 'N' -e '$!ba' -e 's/\\n\\n/\\
" & TextToWrite & "\\
\\
/' \"" & Target_Filepath & "\""
do shell script addline

Solution 2:

If I understand your question correctly, you what to write some new text content to the text file directly above the first blank line and if that's correct then here's an example of one way it can be done.

Note that sometimes the AppleScript do shell script command can get complex when having to escape certain instances of special charters, ordinary charters and or if multiple command lines are involved, etc.

So in the following example I'm going to limit the do shell script command to something as simple as I can that doesn't require lots of escaping while allowing for a variable filename and will return the byte count up to the first blank line in the file, as I believe this is the insertion point you're requesting for where the new text is to be written.

I will then use the byte count as the offset point as the reference point to where the new text would be written to the target text file. I'll do this by reading into variables from the start of the file up the offset and reading from the offset to the end of the file, then concatenate the three variables to one variable to write to the target file from the beginning of the file. Thus overwriting the old content with the combination of new and old content.


AppleScript code:

set filePathName to POSIX path of (path to desktop as string) & "My Fruit Log.txt"

try
    set offsetCount to (do shell script "grep -b -m1 '^$' \"" & filePathName & "\" | cut -f1 -d:")
end try
if offsetCount is equal to "0" or offsetCount is equal to "" then
    display dialog "The contents of the target file does not conform to the necessary requirements for processing and or may contain consecutive 0D Carriage Return Characters, instead of the 0A Line Feed Characters expected by default in macOS." buttons {"OK"} default button 1
    return
end if

set newContent to "I ate a strawberry at 1 am."

try
    set referenceNumber to open for access filePathName with write permission

    set oldContentUpToFirstBlankLine to read referenceNumber from 1 to offsetCount
    set oldContentFromFirstBlankLine to read referenceNumber from offsetCount to eof

    set allContent to oldContentUpToFirstBlankLine & newContent & oldContentFromFirstBlankLine

    write allContent to referenceNumber starting at 0
    close access referenceNumber

on error eStr number eNum
    display dialog eStr & " number " & eNum buttons {"OK"} default button 1 with title "File I/O Error..." with icon caution
    try
        close access referenceNumber
    end try
    return
end try

Terminal output of "My Fruit Log.txt" before running AppleScript code:

$ cat "$HOME/Desktop/My Fruit Log.txt"
2016_11_09 -

2016_11_08 -
I ate a banana at 8 am.
I ate a kiwi at 11 am.
I ate a mango at 6 pm.

2016_11_07 -
I ate a pear at 6 am.
I ate a tangerine at 4 pm.
I ate a peach at 8 pm.
$ 

Terminal output of "My Fruit Log.txt" after running AppleScript code:

$ cat "$HOME/Desktop/My Fruit Log.txt"
2016_11_09 -
I ate a strawberry at 1 am.

2016_11_08 -
I ate a banana at 8 am.
I ate a kiwi at 11 am.
I ate a mango at 6 pm.

2016_11_07 -
I ate a pear at 6 am.
I ate a tangerine at 4 pm.
I ate a peach at 8 pm.
$ 

So as you can see, this inserts the new text content above the first blank line in the file.

Below we see the Event Log of the AppleScript Editor when the above AppleScrip code is run:

tell current application
    path to desktop as string
        --> "Macintosh HD:Users:me:Desktop:"
    do shell script "grep -b -m1 '^$' \"/Users/me/Desktop/My Fruit Log.txt\" | cut -f1 -d:"
        --> "13"
    open for access "/Users/me/Desktop/My Fruit Log.txt" with write permission
        --> 172
    read 172 from 1 to "13"
        --> "2016_11_09 -
"
    read 172 from "13" to eof
        --> "

2016_11_08 -
I ate a banana at 8 am.
I ate a kiwi at 11 am.
I ate a mango at 6 pm.

2016_11_07 -
I ate a pear at 6 am.
I ate a tangerine at 4 pm.
I ate a peach at 8 pm.
"
    write "2016_11_09 -
I ate a strawberry at 1 am.

2016_11_08 -
I ate a banana at 8 am.
I ate a kiwi at 11 am.
I ate a mango at 6 pm.

2016_11_07 -
I ate a pear at 6 am.
I ate a tangerine at 4 pm.
I ate a peach at 8 pm.
" to 172 starting at 0
    close access 172
end tell