copy source files to multiple new filenames in new folders from csv

Hi,

Firstly I’m very new to applescript, please be gentle! This is in fact my first script attempt. I am testing this in script editor now but plan to put it into a Automator app. Thank you in advance for any help you can give.

I have a script I’m managed to put together from googling and this sites information and have got over most of the initial hurdles but I’m getting script error "Can’t get every paragraph of alias "Macintosh HD:Users:me:Desktop:AUTOMATOR:testfilecopy:CSVFile.csv" when I run and cannot find out why. This is just on a small test csv for now. I have a large csv that this script will eventually be used on.

The purpose is to have a small selection of source files that I need to create many duplicates from, each with a unique filename; for testing purposes. the files copies will be put into multiple new folders (for each respective test). The source list is a 3 column CSV file with sourcefilename, newfilname and newfoldername. the actual source files will be in same base folder as csv file.

Here’s my current script attempt:

set theFile to (choose file with prompt "Select the CSV file!")
set theFolderRoot to choose folder with prompt "Choose the root output folder"

set theCSVdata to paragraphs of theFile

set TID to AppleScript's text item delimiters
set AppleScript's text item delimiters to ","

repeat with row in theCSVdata
	
	set {sourcefilename, targetfilename, targetfoldername} to text items of row
	
	set targetfolderpath to theFolderRoot & targetfoldername
	tell application "Finder"
		set theFileCopy to duplicate sourcefilename to folder targetfolderpath
	end tell
	tell application "System Events"
		set name of file theFileCopy to targetfilename
	end tell
end repeat

and here is the CSV contents:

sourcefilename,targetfilename,targetfoldername
test file 1.mxf,A.mxf,folder 1
test file 2.mxf,B.mxf,folder 1
test file 3.mxf,C.mxf,folder 2

Thanks,
Mark.

Model: MBPro Retina
AppleScript: AppleScript 2.4
Browser: Chrome Version 52.0.2743.116 (64-bit)
Operating System: Mac OS X (10.10)

Hey Mark,

There’s no such thing as paragraphs of theFile.

You have to read the file, before you can work with its text.


-------------------------------------------------------------------------------------------
set inputFileAlias to alias ((path to downloads folder as text) & "test.csv")
set theText to read inputFileAlias as «class utf8»
set theRows to paragraphs of theText

# Filter out any blank lines.
repeat with theRow in theRows
	if contents of theRow = "" then
		set contents of theRow to 0
	end if
end repeat
set theRows to text of theRows
-------------------------------------------------------------------------------------------

But that’s not how I’d do it. I’d use the Satimage.osax to make it simpler.


-------------------------------------------------------------------------------------------
# REQUIRES the Satimage.osax AppleScript Extension “ http://tinyurl.com/dc3soh
-------------------------------------------------------------------------------------------

set inputFileAlias to alias ((path to downloads folder as text) & "test.csv")
# Find paragraphs that start with a non-space character - return as list.
set theRows to fnd("^\\S.+", inputFileAlias, true, true) of me
# Split each row (list item) using "," as the delimiter.
set theRows to fnd("[^,]+", theRows, true, true) of me

repeat with theRow in theRows
	set {a, b, c} to theRow
	# Etcetera
end repeat

-------------------------------------------------------------------------------------------
--» HANDLERS
-------------------------------------------------------------------------------------------
on fnd(_find, _data, _all, strRslt)
	try
		find text _find in _data all occurrences _all string result strRslt with regexp without case sensitive
	on error
		return false
	end try
end fnd
-------------------------------------------------------------------------------------------


Chris


{ MacBookPro6,1 · 2.66 GHz Intel Core i7 · 8GB RAM · OSX 10.11.6 }
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

Thanks Chris.

I’ve tried your first option (as that seemed easier for a complete beginner). Now I get an error “Finder got an error: Handler can’t handle objects of this class.” number -10010

which appears to be on “duplicate sourcefilename to folder targetfolderpath”

here is the current code:

set theFile to (choose file with prompt "Select the CSV file!")
set theFolderRoot to choose folder with prompt "Choose the root output folder"

set theText to read theFile as «class utf8»
set theRows to paragraphs of theText

set TID to AppleScript's text item delimiters
set AppleScript's text item delimiters to ","

# Filter out any blank lines.
repeat with theRow in theRows
	if contents of theRow = "" then
		set contents of theRow to 0
	end if
end repeat
set theRows to text of theRows

repeat with row in theRows
	
	set {sourcefilename, targetfilename, targetfoldername} to text items of row
	
	set targetfolderpath to theFolderRoot & targetfoldername
	tell application "Finder"
		set theFileCopy to duplicate sourcefilename to folder targetfolderpath
	end tell
	tell application "System Events"
		set name of file theFileCopy to targetfilename
	end tell
end repeat

This is my first script, and I got here from taking bits of other examples and trying to fit them together to complete the purpose I need.

Is it that I need a add the full path to the source file (sourcefilename = exactly that, just the source filename) or is this taking the path that we started the CSV file in as the root for the source files?

You are trying to move a string, not a file

[format] set theFileCopy to duplicate sourcefilename to folder targetfolderpath[/format]

replace it by :[format] set theFileCopy to duplicate (file sourcefilename of (the Folder containing this file) to folder targetfolderpath[/format]

I add that it woul be a good idea to insert the instruction below at the very end of your posted script.
[format]set AppleScript’s text item delimiters to TID[/format]

Yvan KOENIG running El Capitan 10.11.6 in French (VALLAURIS, France) jeudi 25 aout 2016 13:41:12

This example makes use of the AppleScript Toolbox osax (see my signature). The script assumes that the CSV file is located in the same folder as the files you want to duplicate (if not, replace the set sourceFolder. line with a choose folder command).

set theFile to (choose file with prompt "Select the CSV file!")
set theFolderRoot to choose folder with prompt "Choose the root output folder"

-- the following 4 commands require AppleScript Toolbox scripting addition
-- split the CSV file contents by linefeed and returns
set theRows to AST find regex "[^" & return & linefeed & "]+" in file theFile
-- split the lines by komma
set theData to AST find regex "[^,]+" in string theRows

-- get source folder based on basename of csv file
set sourceFolder to AST find regex ".*:" in string theFile as string

-- get a list of all file names in the source folder
set existingFiles to AST list folder sourceFolder

repeat with theRow in theData
	repeat 1 times -- to simulate break later
		-- check to see if CSV row is not empty or incomplete
		if (count of theRow) < 3 then exit repeat --break
		-- set fields to variables
		set {sourceFileName, targetFileName, targetFolderName} to contents of theRow
		-- check if the file exists before trying to duplicate
		if sourceFileName is not in existingFiles then exit repeat --break
		tell application "Finder"
			set sourceFile to file ((sourceFolder as string) & sourceFileName)
			set targetFolder to folder ((theFolderRoot as string) & targetFolderName & ":")
		end tell
		tell application "System Events"
			set copiedFile to duplicate sourceFile to targetFolder
			set name of copiedFile to targetFileName
		end tell
	end repeat
end repeat

Hey Mark

I’ve commented this to highlight the errors and to ask about needed information.

Read through it and provide the requested info, and we’ll move forward from there.

-Chris


set theFile to (choose file with prompt "Select the CSV file!")
set theFolderRoot to choose folder with prompt "Choose the root output folder"

set theFolderRoot to theFolderRoot as text --» Change from alias to string!

set theText to read theFile as «class utf8»
set theRows to paragraphs of theText

set TID to AppleScript's text item delimiters
set AppleScript's text item delimiters to ","

# Filter out any blank lines.
repeat with theRow in theRows
	if contents of theRow = "" then
		set contents of theRow to 0
	end if
end repeat
set theRows to text of theRows

repeat with row in theRows
	
	set {sourcefilename, targetfilename, targetfoldername} to text items of row
	
	set targetfolderpath to theFolderRoot & targetfoldername --» Invalid
	
	# You cannot create intermediate folders with the duplicate command.
	# Although there are ways to do it with the shell and with ASObjC.
	
	tell application "Finder"
		set theFileCopy to duplicate sourcefilename to targetfolderpath --» Invalid
		
		# You cannot duplicate a FILE-NAME to a location.
		# You have to provide a valid object-specifier.
		# Where is the folder containing your source-files?
		
		# Don't use System Events “ you're [i]already[/i] using the Finder “ stick with it.
		set name of theFileCopy to targetfilename
		
	end tell
	
end repeat

An tell block is only syntax for better readability to targeting multiple commands, each command is send individually to the targeted application using AppleEvents. There is nothing to stick with like in a session or something, other than personal preferences there is actually nothing wrong with it. I agree that it looks better but that is also my personal preference.

Recent experience push me to say that, although I hate Finder, when we are using it for some reasons - here to duplicate - it’s a good idea to stick on it if we want to extract filenames.

Here is why.
Assume that a file’s path is : path to desktop as text)&" a/slash.txt"
Yes I dislike slash in filenames but I am trying to help somebody with numerous filenames of this kind.

If you ask the file name to Finder, you will get “a/slash.txt
if you ask to “System Events” you will get “a:slash.txt

Of course if you have to build instructions using the names you will get some surprises.

set theFile to (path to desktop as text) & "a/slash.txt"
tell application "Finder"
	set nameByFinder to name of file theFile
end tell
tell application "System Events"
	set nameBySysEvents to name of disk item theFile
end tell
{nameByFinder, nameBySysEvents}
--> {"a/slash.txt", "a:slash.txt"}

I beg your pardon DJ, but although I’m not sure that Nigel was aware of that, given this behavior I feel that its advice was a good one.
Caution is required too if POSIX paths are used.

Yvan KOENIG running El Capitan 10.11.6 in French (VALLAURIS, France) vendredi 26 aout 2016 15:52:24

Both commands return the names correctly on my machine. VFS (BSD/Cocoa) names are converted back to virtual HFS names for AppleScript in System Events on my machine. Can you tell me on which OS the example code goes wrong?

Edit: For the record “ I’m using Mavericks and will test your code later on El Capitan (not behind a machine right now).

The used system El Capitan 10.11.6 appears in my signature :rolleyes:

When I run the script posted in my late message the window opened by cmd + alt + L (I don’t know its English name) display :
[format]tell current application
path to desktop as text
→ “SSD 500:Users:yvankoenig:Desktop:”
end tell
tell application “Finder”
get name of file “SSD 500:Users:yvankoenig:Desktop:a/slash.txt”
→ “a/slash.txt”
end tell
tell application “System Events”
get name of disk item “SSD 500:Users:yvankoenig:Desktop:a/slash.txt”
→ “a:slash.txt”
end tell
Résultat :
{“a/slash.txt”, “a:slash.txt”}[/format]

Yvan KOENIG running El Capitan 10.11.6 in French (VALLAURIS, France) vendredi 26 aout 2016 16:57:42

So System Events has the behavior of AppleScriptObjC now? which is new to me. Are some parts of System Events rewritten in Cocoa now?

I stand corrected only because of a complete different reason. It is to avoid a bug in System Events in newer systems that I mainly use not because “You’re already using Finder”.

Hey DJ,

I disagree.

The Finder can rename a file.

Since the Finder is already being used to duplicate the file (returning a Finder-ref) it is inefficient to then switch to another application to rename said file.

-Chris

FWIW, I’m pretty sure it’s been written in Cocoa for a long time, if not always. This looks like a bug, pure and simple. I hope Yvan is reporting it.

That was my point, there is no such thing as switching to application. The tell blocks in AppleScript is just a friendly way for the coder to target multiple commands instead of using tell to for each line. AppleEvent behave pretty much like an RPC which means each event opens a connection to the target, makes a request, read the returned data en close the connection before returning the data and continuing the script. So even inside a single tell application block each AppleEvent is send individually to target application, it is not the tell that opens a connection.

On my machine it still contains a mix of deprecated code and Cocoa looking at the Mach-O executable. So some of its code require to be re-written in Cocoa instead of using the API’s on BSD Level at some point. That’s why I asked.

For the record, the change in System Events happened somewhere between 10.9.5 and 10.10.5.