Search code examples
macosterminalapplescriptitunesdesktop-background

Can't delete directory via AppleScript


I'm writing a program that continuously sets the desktop background to the album art of the current song playing in iTunes, and to do so I am writing the artwork to a file with a random ID number. This means that the desktop will be changing to a different file every time.

Of course, I want to be able to delete all these files after they've been used, so am trying to use do shell script "rm ~rf " & folderName to delete the entire folder containing the images.

However every time I run my script or even type the full directory into Terminal, I get the error:

"rm: ~rf: No such file or directory rm: Macintosh: No such file or directory rm: HD:Users:BenClose:Desktop:iTunesWallpaper: No such file or directory"

Below is my entire program's code, I have no idea what's going wrong and where, so any help would be greatly appreciated, as I would like anyone who wants it to be able to use this program.

screenNum refers to which desktop is being changed.

hiddenFile refers to whether or not the files created will be hidden. "." if true and "" if false (A period added to the beginning of a file name will make it hidden).

Basically, what is happening is that the desktop background is being set to the album art 99 times, after which I would like to be able to delete all 99 files and let the process start again.

The error occurs at the very end of the script where it tries to delete the folder of images.

set screenNum to 2
set directoryName to "iTunesWallpaper"
set fileExt to "jpg"
set hiddenFile to ""
set repeatTrue to 1
set loopLimit to 99
set looped to 0
set folderName to ((path to desktop) as text) & hiddenFile & directoryName
repeat while repeatTrue is 1
    tell application "Finder"
        if (exists folderName) is not true then
            make new folder at (path to desktop) as text with properties {name:hiddenFile & directoryName}
        end if
    end tell
    set randID to screenNum
    set randLoop to 0
    repeat while randLoop is not 9
        set randNum to (random number from 0 to 9) as text
        set randID to randID & randNum
        set randLoop to randLoop + 1
    end repeat
    tell application "System Events"
        set fileName to {((path to desktop) as text) & hiddenFile & directoryName & ":" & randID & "." & fileExt}
        set changeDesktop to 0
        if process "iTunes" exists then
            tell application "iTunes"
                if (player state is not stopped) then
                    if exists artworks of current track then
                        set changeDesktop to 1
                        -- get the raw bytes of the artwork into a var
                        tell application "iTunes" to tell artwork 1 of current track
                            set srcBytes to raw data
                        end tell
                        -- write to file
                        set outFile to open for access file fileName with write permission
                        -- truncate the file
                        set eof outFile to 0
                        -- write the image bytes to the file
                        write srcBytes to outFile
                        close access outFile
                    end if
                end if
            end tell
            if changeDesktop = 1 then
                if exists desktop screenNum then
                    tell desktop screenNum
                        set picture to fileName
                    end tell
                end if
            end if
        end if
    end tell
    set looped to looped + 1
    if looped is loopLimit then
        do shell script "rm ~rf " & folderName
        set looped to 0
    end if
end repeat

Solution

  • The issue is that the shell expects a POSIX path (slash separated)

    do shell script "rm -rf " & quoted form of POSIX path of folderName
    

    Some other issues / notes to make the script more robust:

    • path to has a parameter as text. Use that instead of the coercion

      set folderName to (path to desktop as text) & hiddenFile & directoryName
      
    • In the Finder there is a property desktop and you should always check for a folder or file rather than a literal string

      tell application "Finder"
          if not (exists folder folderName) then
              make new folder at desktop with properties {name:hiddenFile & directoryName}
          end if
      end tell
      

      (Since the desktop folder is the root folder of the Finder you can even omit at desktop).

    • randID will be a list because screenNum is an integer but then you are adding strings, so coerce randID to text.

      set randID to screenNum as text
      
    • The while expression to create the random number is not needed. AppleScript can repeat a specific number of times.

      set randID to screenNum
      repeat 9 times
         set randNum to (random number from 0 to 9) as text
         set randID to randID & randNum
      end repeat
      
    • fileName is also a list which is not intended. Remove the curly braces.

      set fileName to (path to desktop as text) & hiddenFile & directoryName & ":" & randID & "." & fileExt
      
    • Using the write command you must catch potential errors because otherwise a file could be prevented from being closed. Adding try - on error blocks ensures that all files will be closed reliably.

      try
          -- write to file
          set outFile to open for access file fileName with write permission
          -- truncate the file
          set eof outFile to 0
          -- write the image bytes to the file
          write srcBytes to outFile
      
          close access outFile
      on error
              try
                  close access file fileName
              end try
      end try
      
    • Rather than asking System Events if a process is running you can ask the application itself.

      if application "iTunes" is running then
      
    • And last but not least avoid large nested application tell blocks (like the System Events one). Wrap only the affected terminology in an application tell block.