Need Help with AppleScript

I have a Tab delimited .txt file with 23 columns and several hundred records. FileName is one of the 23 fields.  I also have a folder of .jpg files that match the filenames in the txt file.


I need to read input .txt file and If the StudentID field is not blank, rename the associated .jpg file with the StudentID.jpg and move it to a Processed output folder.


if StudentID field is blank rename the associated .jpg file in the input folder with Grade_LastName_FirstName.jpg and move the file to the “Errors” output folder. The last thing is to produce two txt files as explained in # 3 and 4 below. These new txt files will be reference files to go with each output folder.  The output folders and txt files can be created on the desktop.


Inputs:

1) Operator selected Folder containing .jpg files - default location desktop

2) Operator selected Tab delimited .txt file with 23 columns - first record is header with field names


Input File has the following fields:


SequenceNumber

FirstName

LastName

StudentID

Teacher

Grade

HomeRoom

Custom1

Custom2

Custom3

Custom4

P1

Q1

P2

Q2

P3

Q3

P4

Q4

Retouch

Spray

FileName

GSBR


Outputs to be created by AppleScript - Script will move renamed files to these two folders:

1) Folder named with name of input folder & “_” & “Processed”  i.e.   If input folder is named Branford, output folder would be Branford_Proceessed 


2) Folder named with name of input folder & “_” & “Errors”  i.e., If input folder is named Branford output folder would be Branford_Errors


3) Tab delimited .txt file with fields FirstName LastName StudentID Grade FileName from the input file for each record that has a StudentID. File should be named with name of input Folder & “_” & “Processed”  i.e.   If input Folder is named Branford, output file would be Branford_Processed.txt


4) Tab delimited .txt file with fields FirstName LastName StudentID Grade FileName from the input file for each record that did not contain a StudentID. File should be named with name of input Folder & “_” & “Errors”  i.e.   If input Folder is named Branford, output file would be Branford_Errors.txt


Any help will be soooo much appreciated.


Posted on Jan 7, 2023 11:07 AM

Reply

Similar questions

46 replies

Jan 11, 2023 6:41 PM in response to JB001

Here's an update that adds #3 and #4 in your question.

Just save this this file as RenameAndMove.py on your desktop, and if you're not comfortable in Terminal, then just create a 1 line AppleScript, (edit for your desktop path) with:

do shell script "/usr/bin/python3 /Users/Tony/Desktop/RenameAndMove.py"


And then copy this into TextEdit, and save as a plain text file as: RenameAndMove.py

#!/usr/bin/python3

import os
import csv

InputDir = "/Users/Tony/Desktop/InputDir"
ErrorDir = "/Users/Tony/Desktop/ErrorDir"
ProcessedDir = "/Users/Tony/Desktop/ProcessedDir"
with open('/Users/Tony/Desktop/data.csv') as csvfile:
	reader = csv.DictReader(csvfile, delimiter = '\t')
	f1 = open('/Users/Tony/Desktop/Errors.txt', 'w')
	f2 = open('/Users/Tony/Desktop/Processed.txt', 'w')
	f1writer = csv.writer(f1)
	f2writer = csv.writer(f2)
	header = ['FirstName', 'LastName', 'StudentID', 'Grade', 'FileName']
	f1writer.writerow(header)
	f2writer.writerow(header)
	for row in reader:
		if not row['StudentID']:
			newFileName = row['Grade'] + '_' + row['LastName'] + '_' + row['FirstName']
			oldFileNamePath = os.path.join(InputDir, row['FileName'])
			newFileNamePath = os.path.join(ErrorDir, newFileName)
			os.rename(oldFileNamePath, newFileNamePath)
			newrow = [row['FirstName'],row['LastName'],row['StudentID'],row['Grade'],newFileName + ".jpg"]
			f1writer.writerow(newrow)
		elif row['StudentID']:
			newFileName = row['StudentID'] + ".jpg"
			oldFileNamePath = os.path.join(InputDir, row['FileName'])
			newFileNamePath = os.path.join(ProcessedDir, newFileName)
			os.rename(oldFileNamePath, newFileNamePath)
			newrow = [row['FirstName'],row['LastName'],row['StudentID'],row['Grade'],newFileName + ".jpg"]
			f2writer.writerow(newrow)
	f1.close()
	f2.close()



Didn't follow your naming convention of: "1) Folder named with name of input folder & “_” & “Processed”  i.e.   If input folder is named Branford, output folder would be Branford_Proceessed  and 2) Folder named with name of input folder & “_” & “Errors”  i.e., If input folder is named Branford output folder would be Branford_Errors", but that should be easy for you to edit in the python script

Jan 10, 2023 12:27 PM in response to JB001

I did look at your code (nice work), but without any sample data I wasn't able to test, but if you've got everything working but the renaming of the file, I would think that it could be done with the following after changing file01.jpg and file02.jpg and desktop to your variables:


tell application "Finder" to set name of file "file01.jpg" of desktop to "file02.jpg"



(you should already be in a: tell application "Finder" to block, so you can delete that in your code)

Jan 11, 2023 5:44 PM in response to JB001

OK, so after banging my head against the wall with AppleScript (I hate AppleScript 😄),

I decided to go the easier route with python (you can call this python script in AppleScript with:

do shell script "/usr/bin/python3 /Users/Tony/Desktop/RenameAndMove.py"

..changing the path of the py script.


I handled the first part of your question, and did not do "The last thing is to produce two txt files as explained in # 3 and 4 below. "


You will see that python is much more concise (..and change the Directory paths to yours):



#!/usr/bin/python3

import os
import csv

InputDir = "/Users/Tony/Desktop/InputDir"
ErrorDir = "/Users/Tony/Desktop/ErrorDir"
ProcessedDir = "/Users/Tony/Desktop/ProcessedDir"
with open('/Users/Tony/Desktop/data.csv') as csvfile:
	reader = csv.DictReader(csvfile, delimiter = '\t')
	for row in reader:
		if not row['StudentID']:
			newFileName = row['Grade'] + '_' + row['LastName'] + '_' + row['FirstName']
			oldFileNamePath = os.path.join(InputDir, row['FileName'])
			newFileNamePath = os.path.join(ErrorDir, newFileName)
			os.rename(oldFileNamePath, newFileNamePath)
		else:
			newFileName = row['StudentID'] + ".jpg"
			oldFileNamePath = os.path.join(InputDir, row['FileName'])
			newFileNamePath = os.path.join(ProcessedDir, newFileName)
			os.rename(oldFileNamePath, newFileNamePath)



I didn't follow your naming convention of: "1) Folder named with name of input folder & “_” & “Processed”  i.e.   If input folder is named Branford, output folder would be Branford_Proceessed  and 2) Folder named with name of input folder & “_” & “Errors”  i.e., If input folder is named Branford output folder would be Branford_Errors", but that should be easy to edit in the python script. I'll look into items #3 and #4



Jan 12, 2023 3:33 AM in response to Tony T1

New day -- fresh (large) pot of coffee. And many thanks.

I edited the code to change Tony to John and saved as .py

I ran it with the a line do shell script AppleScript and got the following error


error "Traceback (most recent call last):

  File \"/Users/John/Desktop/RenameAndMove.py\", line 9, in <module>

    with open('/Users/John/Desktop/data.csv') as csvfile:

FileNotFoundError: [Errno 2] No such file or directory: '/Users/John/Desktop/data.csv'" number 1


This is my first encounter with python. It looks to me like the input file is hardcoded and is looking for a .csv file. The input file is a tab delimited .txt file so that might have caused the error.


This will be run about 90 times over a few week period each year. The input file will have a different name each time. That is also the reason for naming the output file with the input file_errors, etc. Need to be able to know what school the output is for and don't want to overwrite files.

What changes would need to be made to either have the operator select the input file as the first step in an AppleScript or to have them select the file using Automator?

Jan 12, 2023 7:22 AM in response to JB001

To have the operator select the input file as the first step, we just need to add arguments to the script.


Better to first run from Terminal for you to test this (Are you the only user of the script?)

Should be possible to add this to AppleScript, Automator or Shortcuts, but let's get the script to work for you first.


Copy this script into TextEdit and save as a plain text file named RenameAndMove.py (or any name you want)

Then:

  1. Open Terminal.
  2. Enter "chmod u+x", a space, then 'drag' the script into the Terminal Window and press return

(the script is now executable)

3. Drag the python script into the Terminal Window, drag the csv file into the Terminal Window,

and then drag the Input Folder into the Terminal Window and press return


And, as always, test the python script on copies of your data and files

(This worked for me using the data you provided)



#!/usr/bin/python3

import sys
import os
import csv

if ((len(sys.argv) != 3)):
	exit("usage: " + os.path.basename(sys.argv[0]) + " file_containing_list" + " copy_from_folder" )

file_containing_list = sys.argv[1]
copy_from_folder = sys.argv[2]

ErrorDir = copy_from_folder + "_errors"
if not os.path.exists(ErrorDir):
	os.mkdir(ErrorDir)
ProcessedDir =  copy_from_folder + "_processed"
if not os.path.exists(ProcessedDir):
	os.mkdir(ProcessedDir)
errors_txt = os.path.dirname(copy_from_folder) + "/Errors.txt"
processed_txt = os.path.dirname(copy_from_folder)  + "/Processed.txt"

with open(file_containing_list) as csvfile:
	reader = csv.DictReader(csvfile, delimiter = '\t')
	f1 = open(errors_txt, 'w')
	f2 = open(processed_txt, 'w')
	f1writer = csv.writer(f1)
	f2writer = csv.writer(f2)
	header = ['FirstName', 'LastName', 'StudentID', 'Grade', 'FileName']
	f1writer.writerow(header)
	f2writer.writerow(header)
	for row in reader:
		if not row['StudentID']:
			newFileName = row['Grade'] + '_' + row['LastName'] + '_' + row['FirstName']
			oldFileNamePath = os.path.join(copy_from_folder, row['FileName'])
			newFileNamePath = os.path.join(ErrorDir, newFileName)
			if os.path.exists(oldFileNamePath):
				os.rename(oldFileNamePath, newFileNamePath)
				newrow = [row['FirstName'],row['LastName'],row['StudentID'],row['Grade'],newFileName + ".jpg"]
				f1writer.writerow(newrow)
		elif row['StudentID']:
			newFileName = row['StudentID'] + ".jpg"
			oldFileNamePath = os.path.join(copy_from_folder, row['FileName'])
			newFileNamePath = os.path.join(ProcessedDir, newFileName)
			if os.path.exists(oldFileNamePath):
				os.rename(oldFileNamePath, newFileNamePath)
				newrow = [row['FirstName'],row['LastName'],row['StudentID'],row['Grade'],newFileName + ".jpg"]
				f2writer.writerow(newrow)
	f1.close()
	f2.close()


Jan 12, 2023 9:02 AM in response to JB001

JB001 wrote:
Yes, let's get it working for me first. Then we really need to get it to work with either AppleScript or automator.


So, to make it easier, lets run the python script into Automator (easier than AppleScript).

You'll still need to have a copy of the python script you saved on your Desktop (or any Folder you choose)


Open Automator, and select: New Document->Application

This screenshot will show the 3 actions needed (Note my highlights)

Save, then just click the Automator App to Run


The Run Shell Script Action is:

/usr/bin/python3 /Users/Tony/Desktop/RenameAndMove.py "$1" "$2"



Jan 10, 2023 5:48 AM in response to JB001

I've noticed this question has been getting views but no replies.

This may get you started.


Picking your input data folder:

set myFolder to (choose folder with prompt "Please pick just one folder" default location (path to desktop) without multiple selections allowed)

--> Returns an alias to the folder which allows the variable to be used as-is with the "choose file" command


Choosing your data file:

set sourceFile to (choose file with prompt "Please select just one text file" of type "zip" default location myFolder without multiple selections allowed)


I would use the read command to access your text file then parse each record individually in a separate handler.


I am self-taught so feel comfortable saying there is probably a better way to do this but these suggestions may get the ball rolling.


Hope this helps.

Jan 10, 2023 5:56 AM in response to bob264

Thanks @bob264


After lots of failures I have something that is closer to working but could really use some help.

Problem 1 - The current script gets and error when trying to move the files. The first output folder is created and then the move statement generates an error "Finder got an error: Can’t make folder \"ISAAC_errors\" of folder \"Desktop\" of folder \"John\" of folder \"Users\" of startup disk into type integer." number -1700 from folder "ISAAC_errors" of folder "Desktop" of folder "John" of folder "Users" of startup disk to integer


Problem 2 - I need to rename the files that are moved and can not figure out how to do that. Files moved to the error folder need to be named with the Grade_lastName_firstName.jpg Files moved to the Processed folder need to be named with the StudentId.jpg

Here's my humble attempt at doing all this - I am a real novice at this and am working from examples mostly.


Jan 10, 2023 9:05 AM in response to JB001

The first thing I'd try is to enclose the Name property text in parentheses, "{name:( {name:(jobName & "_errors" as string)}) to force your script to resolve that into a string before it tries to assign it to the name.

This command is seeing something it doesn't recognize and this might be the only issue.

If this works then do the same with your "Processed" files.


I'm not at all conversant in Objective-C so can't help much there.


Renaming files should be as quick as "set the name of file myFile to Grade & "_" & lastName & "_" & firstName & ".jpg"


Hope this helps. B



Jan 10, 2023 11:43 AM in response to bob264

I figured the syntax error out it just needs to be {name:jobName & "_errors"}) as string

Now everything works except the rename.

I have the following code and don't understand where or how to put the rename statement you suggested.


-- Move and rename error files
	set outFolder1 to (make new folder at adesktop with properties {name:jobName & "_errors"}) as string
	set matchList to (every item in folder inFolder whose name is in errorList) as alias list
	repeat with anItem in matchList
		move ((inFolder & anItem's name) as text) to folder outFolder1
	end repeat
	


Jan 10, 2023 11:46 AM in response to JB001

Try this:

-- Move and rename error files
	set outFolder1 to (make new folder at adesktop with properties {name:jobName & "_errors"}) as string
	set matchList to (every item in folder inFolder whose name is in errorList) as alias list
	repeat with anItem in matchList
		move ((inFolder & anItem's name) as file) to folder outFolder1
	end repeat

Jan 10, 2023 12:53 PM in response to Tony T1

So this would be done after the move statement or would it be run against the output folder as a final process?

I know the code in this would lead someone to believe I know what I'm doing but that is a very large exaggeration. This is a lot of copy and past from all the help I have received from this community in the past. I'm trying to learn but still need a lot more help.


j

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

Need Help with AppleScript

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.