1

I'm very new to AppleScript and to this community so I hope this explanation makes since.

I have an AppleScript the reads in a tab delimited file with 20+ fields and several hundred records. The purpose of the script is to match each filename contained in the text file with a file in an input folder and move those files to one of eight output folders based on another field in the text file.

My problem is the filenames in the text file have .jpg extensions and the files in the input folder have been processed so they contain .png as the extension. How can I change the script so it either ignores the extension when matching the files or the input list is converted to .png when AppleScript creates a list.

Here's the current script. I've had a lot of help creating this.

(*
gsbr.applescript
    
Process a tab-separated-values (.tsv) file of 23 columns and several hundred records to identify
"SP1" in the GSBR column, and add its associated filename for background replacement to a list.
That list then attempts to match filenames in a selected folder with the same name, and duplicate those
files to an outfolder for subsequent background replacement.
The script repeats this process looking for values "SP2" - "SP8"  using the same input folder but placing each SPx in a different output folder
*)

use framework "Foundation"
use AppleScript version "2.4" # Yosemite or later
use scripting additions

property NSString : a reference to current application's NSString
property NSCharacterSet : a reference to current application's NSCharacterSet
property NSArray : a reference to current application's NSArray
property istext : {"public.text", "public.plain-text"}
property adesktop : (path to desktop) as alias
property delim : tab

set moveList to {}
set rowItems to {}
set matchList1 to {}
set matchList2 to {}
set matchList3 to {}
set matchList4 to {}
set matchList5 to {}
set matchList6 to {}
set matchList7 to {}
set matchList8 to {}
set gsbr1List to NSArray's array()'s mutableCopy()
set gsbr2List to NSArray's array()'s mutableCopy()
set gsbr3List to NSArray's array()'s mutableCopy()
set gsbr4List to NSArray's array()'s mutableCopy()
set gsbr5List to NSArray's array()'s mutableCopy()
set gsbr6List to NSArray's array()'s mutableCopy()
set gsbr7List to NSArray's array()'s mutableCopy()
set gsbr8List to NSArray's array()'s mutableCopy()

-- by default, the invisibles is true, and other clauses are false by default
set myList to (choose file with prompt "Select file containing list:" of type istext default location adesktop without invisibles)
set inFolder to (choose folder with prompt "Select copy-from folder: " default location adesktop)

set theJobFolder to (choose folder with prompt "Select the Job folder" default location (path to desktop))
set jobName to name of (info for theJobFolder)



-- read the text file into a list of the images to duplicate
-- all 23 fields in a row are string list items
set moveList to (read myList as text using delimiter linefeed) -- text is utf-8 by default
-- extract just the header fields
set headerList to ((NSString's stringWithString:(item 1 of moveList))'s componentsSeparatedByString:delim)
-- and then the rows of data
set dataList to rest of moveList




-- get column number representing header fields of interest
-- assumption: Header fields are not already double-quoted
-- we add 1 because Objective-C arrays are zero-based
set gsbr1 to (headerList's indexOfObject:"GSBR") + 1
set gsbr2 to (headerList's indexOfObject:"GSBR") + 1
set gsbr3 to (headerList's indexOfObject:"GSBR") + 1
set gsbr4 to (headerList's indexOfObject:"GSBR") + 1
set gsbr5 to (headerList's indexOfObject:"GSBR") + 1
set gsbr6 to (headerList's indexOfObject:"GSBR") + 1
set gsbr7 to (headerList's indexOfObject:"GSBR") + 1
set gsbr8 to (headerList's indexOfObject:"GSBR") + 1
set fname to (headerList's indexOfObject:"FileName") + 1



-- process data rows
repeat with arow in dataList
    -- convert the row as text to individual list items so we can find gsbr1 and filename content
    set rowItems to my txt_to_list(arow, delim)
    -- retrieve gsbr1 code if present in the row items
    set rcode to (item gsbr1 of rowItems) as text
    -- and if found, then add the associated filename to the gsbr1List array
    if my to_uppercase(rcode) = "SP1" then
        (gsbr1List's addObject:((item fname of rowItems) as text))
    end if
    if my to_uppercase(rcode) = "SP2" then
        (gsbr2List's addObject:((item fname of rowItems) as text))
    end if
    if my to_uppercase(rcode) = "SP3" then
        (gsbr3List's addObject:((item fname of rowItems) as text))
    end if
    if my to_uppercase(rcode) = "SP4" then
        (gsbr4List's addObject:((item fname of rowItems) as text))
    end if
    if my to_uppercase(rcode) = "SP5" then
        (gsbr5List's addObject:((item fname of rowItems) as text))
    end if
    if my to_uppercase(rcode) = "SP6" then
        (gsbr6List's addObject:((item fname of rowItems) as text))
    end if
    if my to_uppercase(rcode) = "SP7" then
        (gsbr7List's addObject:((item fname of rowItems) as text))
    end if
    if my to_uppercase(rcode) = "SP8" then
        (gsbr8List's addObject:((item fname of rowItems) as text))
    end if
    
end repeat


-- convert the NSMutableArray back to an AppleScript list
set gsbr1List to gsbr1List as list
set gsbr2List to gsbr2List as list
set gsbr3List to gsbr3List as list
set gsbr4List to gsbr4List as list
set gsbr5List to gsbr5List as list
set gsbr6List to gsbr6List as list
set gsbr7List to gsbr7List as list
set gsbr8List to gsbr8List as list


(*
    Check to see if there are any items in each GSBR list. It there are, then create a subfolder inside
    the job folder and move the matching files from the list into that subfolder
*)


tell application "Finder"
    activate
    set matchList1 to (every item in folder inFolder whose name is in gsbr1List) as alias list
    if matchList1 ≠ {} then -- we have at least one matching file, so create the folder
        set outFolder1 to (make new folder at theJobFolder with properties {name:jobName & "_SP1"})
        -- and iterate through the file to move them
        repeat with anItem in matchList1
            set moved_file to (move anItem to outFolder1)
        end repeat
    end if
    
    set matchList2 to (every item in folder inFolder whose name is in gsbr2List) as alias list
    if matchList2 ≠ {} then -- we have at least one matching file, so create the folder
        set outFolder2 to (make new folder at theJobFolder with properties {name:jobName & "_SP2"})
        -- and iterate through the file to move them
        repeat with anItem in matchList2
            set moved_file to (move anItem to outFolder2)
        end repeat
    end if
    
    set matchList3 to (every item in folder inFolder whose name is in gsbr3List) as alias list
    if matchList3 ≠ {} then -- we have at least one matching file, so create the folder
        set outFolder3 to (make new folder at theJobFolder with properties {name:jobName & "_SP3"})
        -- and iterate through the file to move them
        repeat with anItem in matchList3
            set moved_file to (move anItem to outFolder3)
        end repeat
    end if
    
    
    set matchList4 to (every item in folder inFolder whose name is in gsbr4List) as alias list
    if matchList4 ≠ {} then -- we have at least one matching file, so create the folder
        set outFolder4 to (make new folder at theJobFolder with properties {name:jobName & "_SP4"})
        -- and iterate through the file to move them
        repeat with anItem in matchList4
            set moved_file to (move anItem to outFolder4)
        end repeat
    end if
    
    set matchList5 to (every item in folder inFolder whose name is in gsbr5List) as alias list
    if matchList5 ≠ {} then -- we have at least one matching file, so create the folder
        set outFolder5 to (make new folder at theJobFolder with properties {name:jobName & "_SP5"})
        -- and iterate through the file to move them
        repeat with anItem in matchList5
            set moved_file to (move anItem to outFolder5)
        end repeat
    end if
    
    
    set matchList6 to (every item in folder inFolder whose name is in gsbr6List) as alias list
    if matchList6 ≠ {} then -- we have at least one matching file, so create the folder
        set outFolder6 to (make new folder at theJobFolder with properties {name:jobName & "_SP6"})
        -- and iterate through the file to move them
        repeat with anItem in matchList6
            set moved_file to (move anItem to outFolder6)
        end repeat
    end if
    
    
    set matchList7 to (every item in folder inFolder whose name is in gsbr7List) as alias list
    if matchList7 ≠ {} then -- we have at least one matching file, so create the folder
        set outFolder7 to (make new folder at theJobFolder with properties {name:jobName & "_SP7"})
        -- and iterate through the file to move them
        repeat with anItem in matchList7
            set moved_file to (move anItem to outFolder7)
        end repeat
    end if
    
    
    set matchList8 to (every item in folder inFolder whose name is in gsbr8List) as alias list
    if matchList8 ≠ {} then -- we have at least one matching file, so create the folder
        set outFolder8 to (make new folder at theJobFolder with properties {name:jobName & "_SP8"})
        -- and iterate through the file to move them
        repeat with anItem in matchList8
            set moved_file to (move anItem to outFolder8)
        end repeat
    end if
    
    
end tell




-- cleanup
repeat with alist in {moveList, rowItems, matchList1, matchList2, matchList3, matchList4, matchList5, matchList6, matchList7, matchList8, gsbr1List, gsbr2List, gsbr3List, gsbr4List, gsbr5List, gsbr6List, gsbr7List, gsbr8List, headerList, dataList}
    set alist to {}
end repeat

display dialog "Script is done, check your Outfolders for results."
return

on txt_to_list(astr, delim)
    -- split the text row to its individual list items based on TSV delimiter (tab)
    return ((NSString's stringWithString:astr)'s componentsSeparatedByString:delim) as list
end txt_to_list

on to_uppercase(astr)
    -- force to uppercase and remove surrounding whitespace if present
    set nows to NSCharacterSet's whitespaceCharacterSet
    return ((NSString's stringWithString:astr)'s localizedUppercaseString()'s stringByTrimmingCharactersInSet:nows) as text
end to_uppercase

Here's a sample test input TSV file: SequenceNumber FirstName LastName StudentID Teacher Grade HomeRoom Custom1 Custom2 Custom3 Custom4 P1 Q1 P2 Q2 P3 Q3 P4 Q4 Retouch Spray FileName GSBR
1 Faxxxxxxxxx Laxxxxxxxxx 14 My Teacher 11 AAAAAAAAAA A 1 IMG_3002.jpg SP3 2 Fbxxxxxxxxx Lbxxxxxxxxx 42 My Teacher 9 AAAAAAAAAA A 1 F 1 IMG_1018.jpg SP1 3 Fcxxxxxxxxx Lcxxxxxxxxx 15 Staff AAAAAAAAAA zz JBS_7611.jpg
4 Fdxxxxxxxxx Ldxxxxxxxxx 1 My Teacher 12 AAAAAAAAAA NB IMG_1025.jpg SP1 5 Fexxxxxxxxx Lexxxxxxxxx 16 My Teacher 11 AAAAAAAAAA B 1 R JBS_5002.jpg SP5 6 Ffxxxxxxxxx Lfxxxxxxxxx 2 My Teacher 12 AAAAAAAAAA C 1 IMG_3003.jpg SP3 7 Fgxxxxxxxxx Lgxxxxxxxxx 17 Staff AAAAAAAAAA zz JBS_7612.jpg
8 Fhxxxxxxxxx Lhxxxxxxxxx 3 My Teacher 12 AAAAAAAAAA B 1 R IMG_2550.jpg SP2 9 Fixxxxxxxxx Lixxxxxxxxx 4 My Teacher 12 AAAAAAAAAA A 1 G 2 JBS_7613.jpg SP7

The folder with images to be moved has the same file names except with an extension of .png

10
  • This sounds like a problem which could be easily solved with a shell script, but maybe we don't know all the details yet. Maybe you can just pre-process the TSV file to replace jpg with png?
    – nohillside
    Sep 28, 2022 at 13:58
  • 2
    Anyway, not sure anyboy is interested to read through a lot of lines of uncommented code to find the place where the filename is read from the TSV. Can you point out the relevant part?
    – nohillside
    Sep 28, 2022 at 13:59
  • You identified a big part of my problem. I don't know AppleScript very well yet which is why I posted the entire script -- sorry. I believe the section that might need to be changed is the -- process data rows section of code. It is creating several gsbr lists with the filename from the TSV file. I don't know if the extension can be changed at that point so the gsbr lists contain filenames with .png vs .jpg.
    – JBS
    Sep 28, 2022 at 14:28
  • Are the two names (source file and target folder) in the same colums in each row? Do I need to care what is in the other columns when processing the file?
    – nohillside
    Sep 28, 2022 at 14:47
  • Yes, they are in the same column in each row. And the rest of the columns are not needed for this script
    – JBS
    Sep 28, 2022 at 14:54

1 Answer 1

0

Since the file name extensions are known, they can just be replaced when getting the name from the row. In your script that is spread out and duplicated across several lines, so I cleaned it up a bit:

use AppleScript version "2.4" # Yosemite or later
use framework "Foundation"
use scripting additions

property NSString : a reference to current application's NSString
property NSCharacterSet : a reference to current application's NSCharacterSet

global dataList, gsbrLists, indexes

on run
   initialize(true)
   process() -- do the stuff
   tell me to activate
   display dialog "Script is done, check your Outfolders for results."
   initialize(false) -- clear globals
end run

on initialize(flag) -- initialize or clear global variables
   set dataList to {} -- the rows
   set gsbrLists to {{}, {}, {}, {}, {}, {}, {}, {}} -- SP1-SP8
   set indexes to {} -- column indexes
   if flag is not true then return
   
   set myList to (choose file with prompt "Select the file containing the data list:" of type {"public.text", "public.plain-text"} default location (path to desktop))
   -- read the text file into a list of the images to duplicate
   set moveList to paragraphs of (read myList) -- text is utf-8 by default
   -- extract  column numbers of the desired header fields - note that Objective-C arrays are zero-based
   set headerList to ((NSString's stringWithString:(item 1 of moveList))'s componentsSeparatedByString:tab)
   set end of indexes to (headerList's indexOfObject:"GSBR") + 1
   set end of indexes to (headerList's indexOfObject:"FileName") + 1
   -- and then the rows of data
   set dataList to rest of moveList
end initialize

to process() -- process data rows
   set inFolder to (choose folder with prompt "Select the folder to copy from: " default location (path to desktop))
   set jobFolder to (choose folder with prompt "Select the Job folder:" default location (path to desktop))
   tell application "Finder" to set jobName to name of jobFolder
   repeat with aRow in dataList
      -- convert the row as text to individual list items so we can find gsbr and filename content
      set rowItems to ((NSString's stringWithString:aRow)'s componentsSeparatedByString:tab) as list
      if rowItems is not {""} then -- skip empty lines
         set fileName to (text 1 thru -5 of (item (last item of indexes) of rowItems)) & ".png" -- replace .jpg extension
         -- retrieve gsbr code if present in the row items
         set rowCode to upcaseAndTrim(item (first item of indexes) of rowItems)
         if rowCode is not "" then -- if found, add the filename to the associated gsbrLists list
            if rowCode = "SP1" then set end of (first item of gsbrLists) to fileName
            if rowCode = "SP2" then set end of (second item of gsbrLists) to fileName
            if rowCode = "SP3" then set end of (third item of gsbrLists) to fileName
            if rowCode = "SP4" then set end of (fourth item of gsbrLists) to fileName
            if rowCode = "SP5" then set end of (fifth item of gsbrLists) to fileName
            if rowCode = "SP6" then set end of (sixth item of gsbrLists) to fileName
            if rowCode = "SP7" then set end of (seventh item of gsbrLists) to fileName
            if rowCode = "SP8" then set end of (eighth item of gsbrLists) to fileName
         end if
      end if
   end repeat
   
   tell application "Finder" -- move matching files
      activate
      repeat with indx from 1 to (count gsbrLists)
         set matches to (every item of inFolder whose name is in (item indx of gsbrLists)) as alias list
         if matches ≠ {} then -- we have at least one matching file, so create the folder
            try -- check if folder already exists
               set outFolder to ((jobFolder as text) & jobName & "_SP" & indx) as alias
            on error errmess -- nope
               log errmess
               set outFolder to (make new folder at jobFolder with properties {name:jobName & "_SP" & indx})
            end try
            move matches to outFolder -- and move 'em
         end if
      end repeat
   end tell
end process

to upcaseAndTrim(theString) -- convert to uppercase and trim whitespace
   return ((NSString's stringWithString:theString)'s localizedUppercaseString()'s stringByTrimmingCharactersInSet:(NSCharacterSet's whitespaceCharacterSet)) as text
end upcaseAndTrim

I used lists instead of a lot of different variables, which removed a bunch of the duplication and (hopefully) made it a little simpler. I performed some tests, but you might want to use a smaller test set before turning it loose on production files.

1
  • Wow! Thank you so much. This works perfectly.
    – JBS
    Sep 29, 2022 at 2:00

You must log in to answer this question.

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