4

The basic question is:

How can I pass a filename to the Spotlight search module in Automator?

The essential problem:

I have hundreds of broken aliases scattered throughout a particular directory on my HD. The original files DO STILL EXIST, but for some reason the aliases have lost their connection. I would like to replace them all with symlinks, so that they can be backed up by Rsync.

Here is a scaled-down example of a folder with broken aliases in it:

enter image description here

Now here is an example of a sub-directory that contains both the originals of some of the broken aliases, as well as additional copies of the SAME alias, that still point to another location for their originals:

enter image description here

And lastly, here is an image of a directory that contains the master files to some of the aliases that were located in both of the previous 2 locations:

enter image description here

So what I need to do is:

  1. Identify all aliases in a user-defined directory
  2. Use the filenames of those aliases to locate their original files, in a second user-defined directory (recursively and ensuring not to identify a second alias as an original)
  3. remove the alias
  4. create a symlink to the original file, in the former location of the alias

I'm using Automator wherever I can, and Applescript wherever I must. Prior to the response that prompted these edits, my workflow did the following:

  1. Prompt for the location to look for original files
  2. Prompt for location to look for aliases
  3. Get POSIX paths to all aliases
  4. Get text filenames of all the aliases

Now, it gets a bit further but with some problems:

  1. I had an alias titled "3dfx & ambience.rfl" (changed already in the screenshots to "3dfx and ambience.rfl"). The applescript provided would fail on that file due to the ampersand.
  2. After fixing #1, the script ran and did indeed remove broken aliases and replace them with symlinks. But the symlinks pointed to the parent folder that contained the originals, not the originals themselves. So I ended up with 2 symlinks, "Luftrum 1 - Thor Ambient.rfl" and "Luftrum 2 - Thor Ambient II.rfl", that in reality pointed to the "Luftrum" folder shown in my third screenshot above.

Hopefully this will be enough detail to ultimately arrive at a working solution. I can tell it's very close.

  • I have been playing with Spotlight to edit my answer, and have some thoughts on this... If you do get Spotlight working through Automator, how will you know that the result isn't the dead alias or another file with the same simple name? It would be great to have the tool that you describe, but seems risky to implement it in this manner. May be good motivation to learn shell or python! – beroe Sep 8 '13 at 9:53
  • I have left an answer for you. Which the script works. But It would be easier for us to show you the actual passing the list into an action if you show us how your lists are formed/formatted. And how you are actually are getting them. i.e the end result and how you got there – markhunte Sep 8 '13 at 13:10
  • @beroe - It's pretty easy in automator to filter a folder's contents first, down to only aliases. markhunte - Very much appreciate your response! I hope my edited question now helps you to see what I'm trying to do. – Jonathan van Clute Sep 8 '13 at 19:06
  • Hi I have Updated the answer. – markhunte Sep 8 '13 at 23:16
2
+50

If you simply want to pass a file name to the Spotlight action

The pass the file name from an action to a set variable Action

  • set the Spotlight Action to ignore the any above action. Done by right clicking on it's title bar and using the menu.

enter image description here

  • drag and drop the variable token into the search text field.

enter image description here


THIS IS AN UPDATE

Using Automator actions and Applescript to store properties for later retrieval:

The idea here is the first action writes out a applescript file to the documents folder.

The script will be used to store information we get along the way and then retrieve it later on in the final Applescript action.

We do this because we need to pass the final script multiple bits of information. Which we cannot do with the normal variables in Automator.

The Actions.

enter image description here

  1. Run Applescript: Write out a a storage script to the documents folder

The script.

set script_text to MakeScript()
my RunMaker(script_text)

on RunMaker(script_text)
    set file_path to (path to documents folder as Unicode text) & "MyProperties.scpt"
    set file_path to POSIX path of file_path as string
    store script script_text in file_path with replacing
end RunMaker


on MakeScript()

    script
        property theBrokenAliasFolderPath : ""
        property broken_alias_file_Paths : {}

        property theOriginalFolderPath : ""
        property Original_file_Paths : {}


        property SearchfileNames : {}

    end script
end MakeScript

2, Ask for Finder Items: This is for the Broken Alias folder.

  • Set to Ignore Input
  • set your start at: at your broken alias folder.
  • set your Type to: Folder

3,Run Applescript:

  • Writes out broken alias folder path to a property in the storage script file.
  • pass the path on to the next action

( The write outs are done by the Action Applescript loading the storage file script. This will be a version of sorts. It will then change properties in its version and re-write the file out again replacing the old one)

--WRITE OUT BROKEN ALIAS FOLDER PATH


on run {input, parameters}

    set file_path to (path to documents folder as Unicode text) & "MyProperties.scpt" as alias

    set script_text to load script file_path

    set theBrokenAliasFolderPath of script_text to (POSIX path of (item 1 of input))


    my RunMaker(script_text)

    return input
end run



on RunMaker(script_text)
    set file_path to (path to documents folder as Unicode text) & "MyProperties.scpt"
    set file_path to POSIX path of file_path as string
    store script script_text in file_path with replacing
end RunMaker

4,Get Folder contents:

  • The action receives the "broken alias folder path" and gets all the contents of the folder.

5, Filter Finder Items:

  • Filter the items so they only contain alias files.

All: Kind : is : other : alias

  • Pass the list to the next Action

6, Run Applescript:

Writes out broken alias PATHS to a property in the storage script file.

on run {input, parameters}

    set file_path to (path to documents folder as Unicode text) & "MyProperties.scpt" as alias

    set script_text to load script file_path

    set broken_alias_file_Paths of script_text to input


    my RunMaker(script_text)

    return input
end run
on RunMaker(script_text)
    set file_path to (path to documents folder as Unicode text) & "MyProperties.scpt"
    set file_path to POSIX path of file_path as string
    store script script_text in file_path with replacing
end RunMaker

7, Ask for Finder Items: This is for the Original files folder.

  • Set to Ignore Input
  • set your start at: at your Original files folder.
  • set your Type to: Folder

8,Run Applescript:

Writes out the Original files folder to a property in the storage script file.

 on run {input, parameters}

        set file_path to (path to documents folder as Unicode text) & "MyProperties.scpt" as alias

        set script_text to load script file_path

        set theOriginalFolderPath of script_text to (POSIX path of (item 1 of input))


        my RunMaker(script_text)

        return input
    end run



    on RunMaker(script_text)
        set file_path to (path to documents folder as Unicode text) & "MyProperties.scpt"
        set file_path to POSIX path of file_path as string
        store script script_text in file_path with replacing
    end RunMaker

9, Run Applescript:

This retrieves the information from the storage script. This will take the list of paths of the dead alias files.

  • Try and Find a matching file in the Original files folder. It will look at all matches but ignore aliases.

  • Remove the old Alias file (checking it is a alias file first)

  • Create a symlink in the folder the old alias was in from the matching file found.

  • Only alias files should be deleted. If no matching file is found then the alias file will not be deleted. Nor will a symlink be created.

.

set file_path to (path to documents folder as Unicode text) & "MyProperties.scpt" as alias

            set theScript to load script file_path


            --choose a search folder
            set searchPath to quoted form of theOriginalFolderPath of theScript
            set folderPath to quoted form of theBrokenAliasFolderPath of theScript
            set input to broken_alias_file_Paths of theScript


            repeat with i from 1 to count of items of input

                set this_item to item i of input

                set aliasPath to this_item

                #Get the the file name
                set theFileName to "\\\"" & (do shell script "basename " & quoted form of (POSIX path of (this_item))) & "\\\"" as string
                log theFileName

                #search the searchPath for a matching file with the same name.
                #NOTE: this will find all files with he same name. So We use last paragraph to get what should be the first one it finds.
                set theOrigFilePath to paragraphs of (do shell script "mdfind -onlyin " & searchPath & " kMDItemFSName == \"" & theFileName & "\"")


                if theOrigFilePath is not quoted form of "" then

                    repeat with i from 1 to count of items in theOrigFilePath

                        set this_item to item i of theOrigFilePath
                        log this_item
                        tell application "Finder"

                            #make sure we are pointing to an alais that will be deleted and not another symlink file. Otherwise the original file will be deleted.

                            set theKind to kind of ((POSIX file this_item) as alias)

                            if theKind is not equal to "Alias" then
                                set this_item to quoted form of (item i of theOrigFilePath)
                                my symLink(aliasPath, this_item)
                            end if


                        end tell


                    end repeat



                end if

            end repeat


            on symLink(aliasPath, aOrigFilePath)

                #move to trash the old alias file

                set theOldAlias to aliasPath
                tell application "Finder"

                    #make sure we are pointing to an alais that will be deleted and not another symlink file. Otherwise the original file will be deleted.

                    set theKind to kind of theOldAlias
                    set theNewFilePath to (POSIX path of (aliasPath)) as string
                    if theKind is equal to "Alias" then
                        delete theOldAlias

                        log "ln -s  " & aOrigFilePath & space & (quoted form of theNewFilePath)
                        #create the symlink
                        do shell script "ln -s  " & aOrigFilePath & space & (quoted form of theNewFilePath)
                    end if
                end tell
            end symLink

Test first.. use at your own risk and all that..

  • Holy shiatzu! This sounds like exactly what I need. I will test it ASAP! I didn't know you could drag & drop a variable like that - very cool! Unfortunately I believe that will only work for single values, not lists. But your applescript seems like the answer. It still uses some shell scripting which I was hoping to avoid, but I've accepted that there's probably no other way. Thanks, will let you know if this solves the problem for me! – Jonathan van Clute Sep 8 '13 at 16:49
  • Close but no cigar. It moved 2 broken aliases to the trash, but the originals of both were located inside a folder called "Luftrum". The script made 2 symlinks of that folder, renamed each to the names of the dead aliases, and put them in the correct place. So I now have 2 differently-named but otherwise identical aliases to a folder, that contains items other than just the actual dead alias items. I'll try troubleshooting this myself but you may be able to do it more quickly and if you can edit your answer, I'd appreciate it! – Jonathan van Clute Sep 8 '13 at 17:25
  • Additional observation, it dies on filenames that contain ampersands. Looks like they need to be escaped, but I'm not sure of the syntax to accomplish that. – Jonathan van Clute Sep 8 '13 at 17:35
  • Uh oh... another serious issue is that I have multiple aliases in some cases. So the script is assuming that the first matching filename found, is the original when it may not be. Should also check to see that it's not an alias. I'm going to try and fix this myself but in case I fail, would be amazing if you could make this adjustment as well. =) – Jonathan van Clute Sep 8 '13 at 17:37
  • Hi. I do not get your first two issues when I run tests. The first issue if I am understanding you correctly sounds like the script is finding the original files but file names are not being passed to the symlink code. Also testing on a i.e on a folder named "a folder with & ya" works for me. Applescript can have issues with some languages and their text encoding when it comes to files and folders. I suspect this is the case. But you really need to show an example of how your alias and files are organised and how your list is structured. And save us working from your worded description.. – markhunte Sep 8 '13 at 18:26
2

Usually "broken alias" refers to an alias where the original file no longer exists. I have used this script to find aliases like that:

set l to {}
tell application "Finder"
    try
        alias files of entire contents of (POSIX file "/Users/username" as alias)
        result as list
    on error
        return
    end try
    repeat with f in result
        try
            original item of contents of f
        on error
            --move contents of f to trash
            set end of l to POSIX path of (f as text)
        end try
    end repeat
end tell
set text item delimiters to linefeed
l as text

If the script finds the aliases you want to replace symlinks, save the relevant lines of the output to a text file. Then try running a shell script like this:

cat /tmp/aliases.txt | while IFS= read -r f; do
  original=$(find ~/directory/with/original/files -name "${f##*/}" | head -n1)
  echo "$f:$original"
  # rm "$f"; ln -s "$original" "$f"
done
  • Unfortunately(?), not so in my case. The original files DO exist. I don't know why the aliases broke. Looking at Get Info, I see they all point to THEMSELVES as the original. Also in your code (and I'm not much of an AppleScripter so forgive me), it seems to start by creating an alias of everything in an entire directory. Why is that? I'm not clear on what that would do to help. I currently iterate through all aliases in a dir and try to get the original contents and if it fails, then I know I have a broken alias. So finding them is easy, it's finding their original file that I'm stuck on. – Jonathan van Clute Sep 3 '13 at 15:01
  • alias files of entire contents of (POSIX file "/Users/username" as alias) just gets a list of all alias files under /Users/username. You could also try to extract the original paths from the resource forks with something like cat example.txt\ alias/..namedfork/rsrc | strings. – Lri Sep 4 '13 at 9:05
  • I already have all the alias files, and all their paths. Automator gave me that easily, that's not the problem. The problem is that I can't perform a search on the filenames, in order to locate the original files elsewhere on my drive. They do exist, and are located somewhere below a specific directory, but could be in any of hundreds of other subdirectories. – Jonathan van Clute Sep 4 '13 at 16:36
0

You could use mdfind which is the command-line version of Spotlight in a shell subscript in Automator. You can pass variables to and from this script/command via stdin and stdout.

EDIT if you don't want to try using any shell commands:

Did you try setting a value of a variable in Automator, then right-click on the Spotlight input box and choose "New Variable..." from the bottom of the pop-up list?

spotlight screenshot...

  • Thanks but without a lot more detail, that's over my head. I'm really looking to avoid having to drop outside of automator to shell scripting. At most I'd prefer to stick with basic applescript but even that would be a last resort. I just want to pass a variable in as the input to the spotlight module. – Jonathan van Clute Sep 7 '13 at 16:51
  • I only just noticed the edit to this comment. I can't use a variable in this way because the input is a list of items, and automator does not handle lists in the above fashion. You have to resort to AppleScript or shell scripting. =( – Jonathan van Clute Sep 9 '13 at 0:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .