Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

TheNormsk

macrumors member
Original poster
Jun 23, 2015
81
36
Colorado
This may be an Apple script, a terminal script or something else? I've never scripted in MacOS before as all my programming has been in Windows (forgive me).

I am currently organizing a photo library (outside of Photos) of some 120,000+ photos with some 50,000+ duplicates in it. I'm using Photo Sweeper to help identify the duplicates but when it deletes it only removes the photo file (jpg, heic, raw etc). If the file has a sidecar (aae, xmp) it is left and orphaned. I will have 10s of thousands of orphaned sidecar files once I am done with this clean up.

I'm trying to find a script or a process that will allow me to find and deleted all .xmp and .aae sidecar files in a folder if there is no matching file name (one without a associated .xmp or .aae extension). The matching file may be a .jpg, .heic, .raw, .rw2, .png etc.

For the life of me, while I work in scripts all the time for work in Windows, on MacOS I can't figure out how to start with this. I'm thinking this may be an Apple script, or perhaps something UNIX related to run in terminal?

My Applescript knowledge is limited to 30 minutes of web browsing so far.. Some pointers in the right direction would really help me out. I'm thinking of a script along these lines..

AppleScript:
tell application "Finder"
    set search_folder to (choose folder)

    set sidecar_list to files in folder search_folder whose name extension is in ["xmp", "aac"]
    repeat with i from 1 to (count sidecar_list)
        
        set sidecar_name as name of item i of sidecar_list
        set photo_list to files in search_folder whose name is sidecar_name and name extension is not in ["xmp", "aac"]
        if (count photo_list)=0 then delete item i of sidecar_list       
        
    end repeat
end tell

Obviously this code won't work as it is just conceptual but any guidance or a better way to do this would be much appreciated.
 

casperes1996

macrumors 604
Jan 26, 2014
7,593
5,764
Horsens, Denmark
You say you work with scripts all the time in Windows; What languages do you script in Windows? There's a high likelihood you can just use something you already know for scripting macOS as well. Python, Ruby, JavaScript - Even Powershell (though with Unix commands rather than Windows commands as the underpinnings) all are available.

There are people on here who know AppleScript well but I never got into it.

I'd probably do something like this in bash, Python or Swift; But since you are looking at deleting things, I'd run it on a small test data sample set where you wouldn't mind losing all the files (you can create empty test files with the touch command) before using it on your full data set.

In bash you can loop over all the files in a directory with
for filename in /Data/*; do
loopInHere
done

the variable "filename" will contain the names of all the files in the Data folder at the root inside of the loop.

So for example

for file1 in /dir/*.xmp in
for file2 in /dir/*.jpg in
if [[ ${file1%.*} == ${file2%.*}
rm file1
fi
done
done

should remove all of the amp files that have a matching .jpg; Though not only .jpg. But I have not tested this, so I will reiterate, don't run it on your actual data to begin with; It could delete things you don't want gone. Make test data like
touch file1.xmp
touch file2.jpg
touch file2.xmp
touch file 1.png

or whatever and run it on that input first to validate correct behaviour. Once rm is run, the data isn't easily recoverable.
 
  • Like
Reactions: TheNormsk

casperes1996

macrumors 604
Jan 26, 2014
7,593
5,764
Horsens, Denmark
I beautifully indented those lines of bash... I guess I need to think more about using code blocks in the future cause apparently text blocks lose indentation
 

casperes1996

macrumors 604
Jan 26, 2014
7,593
5,764
Horsens, Denmark
Also I should mention that you should probably have a look at the Automator app. It's very very good GUI-based scripting. You can record actions that you want saved for automation, or use simple building blocks like "select files", "copy", "connect to network volume", "paste to directory" or whatever and create automation easily with a GUI app - Default program on all Macs. Macs are very good about automation with a lot of extensible places, like Folder Actions, Services, etc.
 
  • Like
Reactions: TheNormsk

TheNormsk

macrumors member
Original poster
Jun 23, 2015
81
36
Colorado
You say you work with scripts all the time in Windows; What languages do you script in Windows? There's a high likelihood you can just use something you already know for scripting macOS as well. Python, Ruby, JavaScript - Even Powershell (though with Unix commands rather than Windows commands as the underpinnings) all are available.

There are people on here who know AppleScript well but I never got into it.

I'd probably do something like this in bash, Python or Swift; But since you are looking at deleting things, I'd run it on a small test data sample set where you wouldn't mind losing all the files (you can create empty test files with the touch command) before using it on your full data set.

In bash you can loop over all the files in a directory with
for filename in /Data/*; do
loopInHere
done

the variable "filename" will contain the names of all the files in the Data folder at the root inside of the loop.

So for example

for file1 in /dir/*.xmp in
for file2 in /dir/*.jpg in
if [[ ${file1%.*} == ${file2%.*}
rm file1
fi
done
done

should remove all of the amp files that have a matching .jpg; Though not only .jpg. But I have not tested this, so I will reiterate, don't run it on your actual data to begin with; It could delete things you don't want gone. Make test data like
touch file1.xmp
touch file2.jpg
touch file2.xmp
touch file 1.png

or whatever and run it on that input first to validate correct behaviour. Once rm is run, the data isn't easily recoverable.
Most of my work is in CMD (yeah, old school I know) with some powershell but mostly database languages (PLSQL, TSQL...) I used to do UNIZ but that was 20 years ago and I've forgotten most of it. I never got into the modern languages. I'm a bit of a dinosaur these days.
 

casperes1996

macrumors 604
Jan 26, 2014
7,593
5,764
Horsens, Denmark
Most of my work is in CMD (yeah, old school I know) with some powershell but mostly database languages (PLSQL, TSQL...) I used to do UNIZ but that was 20 years ago and I've forgotten most of it. I never got into the modern languages. I'm a bit of a dinosaur these days.

Hehe, Python and bash are from the 80's :p. Though Python just took quite a while to really get popular. Bash has been a popular shell for a long time though, since it was the GNU project's answer to the classic Unix shell. But Bash may also not be in your list of modern languages.

But yeah if you know Powershell's syntax and such better you can get PowerShell for macOS, though I would say that PowerShell is a bit of an abomination and I'd recommend learning a standard shell language like zsh, bash, csh or something instead; Perhaps using the Automator app for a GUI that'll let you automate things and maybe giving Python a go if you find it fun. :)
 

TheNormsk

macrumors member
Original poster
Jun 23, 2015
81
36
Colorado
I'm part way there using Applescrpt.

So far I have this:
AppleScript:
set this_folder to (choose folder with prompt "Pick the folder containing the sidecar files to process:") as string

tell application "System Events"
    set these_files to every file of folder this_folder whose name does not start with ¬
        "." and (file type is "AAE" or ¬
        file type is "XMP" or ¬
        name extension is "xmp" or ¬
        name extension is "aae")
    set check_files to every file of folder this_folder whose name does not start with ¬
        "." and not (file type is "AAE" or ¬
        file type is "XMP" or ¬
        name extension is "xmp" or ¬
        name extension is "aae")
end tell

log
log "this_file list ****************************"
repeat with i from 1 to the count of these_files
    set this_file to (item i of these_files as alias)
end repeat

log
log "check_file list **************************"
repeat with i from 1 to the count of check_files
    set check_file to (item i of check_files as alias)
end repeat

log
log "main program ******************************"
repeat with i from 1 to the count of these_files
    log "********************************************************************"
    set this_file to (item i of these_files as alias)
    log this_file
    tell application "Finder"
        set this_folder to folder of this_file as string
        set this_name to name of this_file as string
        set this_extension to name extension of this_file as string
        set this_name to text 1 thru -((count this_extension) + 2) of this_name -- just the name part
        set this_extension to "." & this_extension
        log this_name
        set check_file to this_folder & this_name & ".jpg"
        log check_file
        if exists check_file then
            log "Exists"
        else
            log "Not exists"
            (*
                delete file this_file
            *)
        end if
    end tell
    
end repeat

It includes some lines just to help me track what is going on using Events. The output is:
Code:
tell application "Script Editor"
    choose folder with prompt "Pick the folder containing the sidecar files to process:"
end tell
tell application "System Events"
    get every file of folder "Macintosh HD:Users:kerry:Desktop:Testing:" whose name does not start with "." and (file type = "AAE" or file type = "XMP" or name extension = "xmp" or name extension = "aae")
    get every file of folder "Macintosh HD:Users:kerry:Desktop:Testing:" whose name does not start with "." and not (file type = "AAE" or file type = "XMP" or name extension = "xmp" or name extension = "aae")
end tell
(**)
(*this_file list *****************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
end tell
(**)
(*check_file list ***************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file1.jpg"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file2.heic"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file5.mov"
end tell
(**)
(*main program *******************************)
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file5.aae*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
    (*file5*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file5.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file5.jpg"
    (*Not exists*)
end tell
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file4.aae*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
    (*file4*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file4.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file4.jpg"
    (*Not exists*)
end tell
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
    (*file2*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file2.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file2.jpg"
    (*Not exists*)
end tell
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
    (*file3*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file3.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file3.jpg"
    (*Not exists*)
end tell
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
    (*file1*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file1.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file1.jpg"
    (*Exists*)
end tell

Basically these_files (and this_file) are the items I am testing for. check_files (and check_file) would be the list I want to check against.

I can extract out the folder and name of this_file so it does not have the extension and I can test it using a modified extension (.jpg) to see if it exists and this works. But, what I need to do now, is ideally see is the modified this_file exists in the check_files list (excluding the extension).

I'm thinking there may be two ways to do this:
1) Convert both file lists into corresponding test lists (these_files_text and check_files_text) without extensions and then iteration through each item of these_files_text to see if it is in check_files_text, or
2) set check_files when iterating through these_files and additionally filter on name (somehow). If check_files has count > 0 then file exists - ie it is matched.

Any other options or code that i am missing here?
 

casperes1996

macrumors 604
Jan 26, 2014
7,593
5,764
Horsens, Denmark
I'm part way there using Applescrpt.

So far I have this:
AppleScript:
set this_folder to (choose folder with prompt "Pick the folder containing the sidecar files to process:") as string

tell application "System Events"
    set these_files to every file of folder this_folder whose name does not start with ¬
        "." and (file type is "AAE" or ¬
        file type is "XMP" or ¬
        name extension is "xmp" or ¬
        name extension is "aae")
    set check_files to every file of folder this_folder whose name does not start with ¬
        "." and not (file type is "AAE" or ¬
        file type is "XMP" or ¬
        name extension is "xmp" or ¬
        name extension is "aae")
end tell

log
log "this_file list ****************************"
repeat with i from 1 to the count of these_files
    set this_file to (item i of these_files as alias)
end repeat

log
log "check_file list **************************"
repeat with i from 1 to the count of check_files
    set check_file to (item i of check_files as alias)
end repeat

log
log "main program ******************************"
repeat with i from 1 to the count of these_files
    log "********************************************************************"
    set this_file to (item i of these_files as alias)
    log this_file
    tell application "Finder"
        set this_folder to folder of this_file as string
        set this_name to name of this_file as string
        set this_extension to name extension of this_file as string
        set this_name to text 1 thru -((count this_extension) + 2) of this_name -- just the name part
        set this_extension to "." & this_extension
        log this_name
        set check_file to this_folder & this_name & ".jpg"
        log check_file
        if exists check_file then
            log "Exists"
        else
            log "Not exists"
            (*
                delete file this_file
            *)
        end if
    end tell
 
end repeat

It includes some lines just to help me track what is going on using Events. The output is:
Code:
tell application "Script Editor"
    choose folder with prompt "Pick the folder containing the sidecar files to process:"
end tell
tell application "System Events"
    get every file of folder "Macintosh HD:Users:kerry:Desktop:Testing:" whose name does not start with "." and (file type = "AAE" or file type = "XMP" or name extension = "xmp" or name extension = "aae")
    get every file of folder "Macintosh HD:Users:kerry:Desktop:Testing:" whose name does not start with "." and not (file type = "AAE" or file type = "XMP" or name extension = "xmp" or name extension = "aae")
end tell
(**)
(*this_file list *****************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
end tell
(**)
(*check_file list ***************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file1.jpg"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file2.heic"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file5.mov"
end tell
(**)
(*main program *******************************)
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file5.aae*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file5.aae"
    (*file5*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file5.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file5.jpg"
    (*Not exists*)
end tell
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file4.aae*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file4.aae"
    (*file4*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file4.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file4.jpg"
    (*Not exists*)
end tell
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file2.xmp"
    (*file2*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file2.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file2.jpg"
    (*Not exists*)
end tell
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file3.xmp"
    (*file3*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file3.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file3.jpg"
    (*Not exists*)
end tell
(**********************************************************************)
tell application "System Events"
    get file "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
end tell
(*alias Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp*)
tell application "Finder"
    get folder of alias "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
    get name of alias "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
    get name extension of alias "Macintosh HD:Users:kerry:Desktop:Testing:file1.xmp"
    (*file1*)
    (*Macintosh HD:Users:kerry:Desktop:Testing:file1.jpg*)
    exists "Macintosh HD:Users:kerry:Desktop:Testing:file1.jpg"
    (*Exists*)
end tell

Basically these_files (and this_file) are the items I am testing for. check_files (and check_file) would be the list I want to check against.

I can extract out the folder and name of this_file so it does not have the extension and I can test it using a modified extension (.jpg) to see if it exists and this works. But, what I need to do now, is ideally see is the modified this_file exists in the check_files list (excluding the extension).

I'm thinking there may be two ways to do this:
1) Convert both file lists into corresponding test lists (these_files_text and check_files_text) without extensions and then iteration through each item of these_files_text to see if it is in check_files_text, or
2) set check_files when iterating through these_files and additionally filter on name (somehow). If check_files has count > 0 then file exists - ie it is matched.

Any other options or code that i am missing here?

Hey again - As mentioned, Apple Script isn't my forte so someone else might be able to help with that; But I wrote and tested a small bash script that seems to do what you want. The way it's written it operates on the folder it's executed from.

Here's some test output:
1604089114953.png
And the script itself

Code:
#!/bin/bash





seen=()





        for file1 in *.xmp


        do


                for file2 in *.jpg


                do


                        if [[ ${file1%.*} == ${file2%.*} ]]; then


                                seen+=$file1


                        fi


                done


                if [[ ! " ${seen[@]} " =~ " ${file1} " ]]; then


                        printf "executing rm on: %s \n " $file1


                        printf "array of seen holds %s\n" $seen


                        rm $file1


                fi


        done

As screenshot:
1604089176074.png
 
Last edited:

TheNormsk

macrumors member
Original poster
Jun 23, 2015
81
36
Colorado
That was very useful and sent me down a rabbit hole looking into Bash instead.

I took your code but the comparisons were not quite what I was looking for but with some working and lots of googling I have a working script. May not be the best coded bash script but it appears to work!

The key for me is FIND. This finds the files I am looking for (though I am not using it at the moment)
Code:
find . -name '*.aae' -o -name '*.xmp'

and this finds what I am comparing to
Code:
find . ! '(' -name '*.aae' -o -name '*.xmp' -o -name '.' ')'

I would use the first find in a FOR loop but everything I read tells me not to and to use this syntax instead.
Code:
find find . -name '*.aae' -o -name '*.xmp' -exec echo {} \;

But I can't figure out how to replace the process (echo in this example) with a subroutine that runs from this.

But this is my code. I adjusted the second find to look for the file (stripped of it's extension) from the for loop to see if the find returns results. If it does not, then it is an orphaned sidecar and I can delete it.

Code:
#!/bin/bash
for files in {*.aae,*.xmp}
do
  filename=${files%.*}
  printf "Processing file: %s as %s \n" $files $filename
  lines=$(find $filename.* ! '(' -name '*.aae' -o -name '*.xmp' -o -name '.' ')' | wc -l)
  printf "Found %s match(es)" $lines
  if [ $lines -eq 0 ]
  then
    Printf "Deleting %s\n" $files
    rm $files
  fi
done

This is the file list before running the script. The red boxes are the files I would want to remove.
Screen Shot 2020-10-30 at 4.54.31 PM.png


and after the run
Screen Shot 2020-10-30 at 4.56.34 PM.png
 

TheNormsk

macrumors member
Original poster
Jun 23, 2015
81
36
Colorado
Arh! so close. I just ran it on (a copy) of one of my photo libraries and the file search is not not quite right. Files with - in them get the - truncated out for example.

The end result still looks okay but there is messiness in the execution output. I still need to do more work....
 

casperes1996

macrumors 604
Jan 26, 2014
7,593
5,764
Horsens, Denmark
I think my brain is slightly toast at the moment; Has everything been solved like it seems per your last picture or do you have any questions/unresolved issues left? :)

But yeah, AppleScript can interact with running GUI applications in ways you can't really with a bash script, but for things like deleting files and basic operations a bash script can do you well; And it's not limited to Apple; It will run on any Unix platform
 

casperes1996

macrumors 604
Jan 26, 2014
7,593
5,764
Horsens, Denmark
One quick little thing I can say is that if you want extra info on any one command; Like find or whatever, you can run "man <command-name>"; Like "man find" in a Terminal and you'll get the "man-page", i.e. the manual for that command
 

TheNormsk

macrumors member
Original poster
Jun 23, 2015
81
36
Colorado
The prior code was incorrectly parse whitespace and this updated code fixes that:

Bash:
#!/bin/bash
while read sidecarFile
do   
    Printf "Source: %s\n" "$sidecarFile"
    fileName=${sidecarFile%.*}
    
    lines=$(find "$fileName".* ! '(' -type f -iname '*.aae' -o -iname '*.xmp' -o -iname '.' ')' | wc -l)   
    if [ $lines -eq 0 ]
    then
        Printf "  --  no match found  ******** DELETED ********\n"
        rm "$sidecarFile"

    else
        Printf "  --  matched\n"
    fi
done < <(find "$PWD" -type f -iname '*.aae' -o -iname '*.xmp' | sort -z)

This one now correctly handles whitespace and is case insensitive.
 

Mark FX

macrumors regular
Nov 18, 2011
159
17
West Sussex, UK
As "casperes1996" has pointed out, a bash script is defiantly the correct way to go,
simply for the speed when dealing with hundreds or even thousands of files.
As Applescript woud be very slow handling that many files in comparison.
But this AppleScript below would get you started if you did decide to try the AppleScript route.

AppleScript:
try
    set imageFolder to choose folder with prompt "Select a Folder with sidecar image files to process" default location (path to desktop folder)
on error
    -- User Canceled Selecting an Image Folder
    return
end try

tell application id "com.apple.finder"
    set oldTextitemDelimiter to AppleScript's text item delimiters -- Save old text item delimiters
    set AppleScript's text item delimiters to "." -- Used to seperate file extension from file name
    set masterImageFiles to every file in imageFolder whose name extension is in ["jpg", "JPG", "jpeg", "JPEG"] -- Add the Image File Extensions
    if (count of masterImageFiles) > 0 then -- Check if master image files exist in the folder
        set masterImageFileNames to {} as list -- List used to hold the names minus ext of master image files
        repeat with masterImageFile in masterImageFiles -- Loop through master image files
            set masterImageFileName to displayed name of masterImageFile as text -- Master image file display name
            set masterImageFileNameMinusExt to first item of (every text item of masterImageFileName) as text -- Master image name minus ext
            set end of masterImageFileNames to masterImageFileNameMinusExt
        end repeat
    end if
    set sidecarImageFiles to every file in imageFolder whose name extension is in ["aae", "AAE", "xmp", "XMP"] -- Sidecare Image File Extensions
    if (count of sidecarImageFiles) > 0 then -- Check if sidecar image files exist in the folder
        repeat with sidecarImageFile in sidecarImageFiles -- Loop through sidecar image files
            set sidecarImageFileName to displayed name of sidecarImageFile as text -- Sidecar image file display name
            set sidecarImageFileNameMinusExt to first item of (every text item of sidecarImageFileName) as text -- Sidecar image name minus ext
            if masterImageFileNames does not contain sidecarImageFileNameMinusExt then -- Check if Master image file exists
                with timeout of 10 seconds -- Allow Finder 10 seconds to perform image file deleteion
                    try
                        delete sidecarImageFile -- Delete sidecar image file
                    on error
                        -- Error occured while trying to delete sidecar image file
                        exit repeat
                    end try
                end timeout
            end if
        end repeat
    end if
    set AppleScript's text item delimiters to oldTextitemDelimiter -- Reset to old text item delimiters
    if (count of (every file in the trash)) > 0 then -- Check the trash folder for deleted image files
        empty the trash -- Empty trash folder of deleted image files
    end if
end tell

The above script will only work on image files that don't have a period "." in the filename,
other than the period separating the file extension, so if your filenames might have a "." in the
name. then don't use the above script as it stands, as it would need to be modified.

The other issue with using the "Finder" application to process the files, is that any deleted files,
would end up in the "Trash" folder, so I've incorporated an empty the trash command that could be removed.
The script could be changed to use "System Events" instead of "Finder", that way no deleted files would end up in the Trash folder.

You would have to add all of the likely image file extensions into the "masterImageFiles" list.
Obviously I would recommend testing the script on a test folder, before unleashing it on your important folders.
And of course it will be very slow in comparison to any bash script, probably 10 times slower.

Regards Mark
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.