Help Learning AppleScript

Brand new member here. Just a little background on myself. Retired (as in bored) engineer by education and work history and I’m looking to learn new things. Have always had Apple Macintosh products, since my very first one, which came out in 1985, called the “FatMac.”

Decided that in order to prevent the brain cells dying, I needed to get back to learning stuff. Being a “Mac” person, what better way to do that than teaching myself AppleScript. Seemed to fit the bill. So, my first attempt has been to put together a script that will look at a folder, with thirteen subfolders, all with files that may change (just a bit) on a daily basis. It’s important that I know the status (content) of these folders. What I’d like to accomplish is to be able to print out a lists of these folders and subfolders, and the files within them. The list would need to have both the folders and the files within them printed in alphabetical order. Should be a snap, or so I thought.

Spent time here doing searches as well as on the Apple Support Community pages. No luck! I’ve come close, but nothing gives me the result I need. So, I’m looking for help.

You could post your existing script so we can see what you are doing

Homer712. Welcome to the forum.

Although it might appear otherwise, doing what you want with basic AppleScript is not the simple matter one might expect. I’ve included below a script that will do what you want, but it will be slow or even fail if your computer is old or the number of folders and files is large. However, it’s fairly straightforward in its operation and hopefully will be of help for learning purposes.

set theFolder to (choose folder)
set foldersAndFiles to getFoldersAndFiles(theFolder)
writeFile(foldersAndFiles)

on getFoldersAndFiles(theFolder)
	set foldersAndFiles to {theFolder as text}
	tell application "Finder"
		set theFiles to (name of every file in theFolder)
		if theFiles ≠ {} then set the end of foldersAndFiles to theFiles
		try
			set theFolders to (every folder of the entire contents of theFolder) as alias list
		on error
			set theFolders to {}
		end try
		repeat with aFolder in theFolders
			set contents of aFolder to aFolder as text
		end repeat
		set theFolders to sortFolders(theFolders) of me
		repeat with aFolder in theFolders
			set end of foldersAndFiles to linefeed & aFolder
			set theFiles to name of every file in folder aFolder
			if theFiles ≠ {} then set the end of foldersAndFiles to theFiles
		end repeat
	end tell
	set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
	set foldersAndFiles to foldersAndFiles as text
	set AppleScript's text item delimiters to ATID
	return foldersAndFiles
end getFoldersAndFiles

on writeFile(theText)
	set targetFile to (path to desktop as text) & "Folder Contents.txt"
	try
		set openedFile to (open for access file targetFile with write permission)
		set eof of openedFile to 0 -- delete this line to append data
		write theText to openedFile starting at eof
		close access openedFile
	on error errorMessage
		display alert "An error occurred while writing a file" message errorMessage as critical
		try
			close access file theFile
		end try
	end try
end writeFile

on sortFolders(a)
	repeat with i from (count a) to 2 by -1
		repeat with j from 1 to i - 1
			if item j of a > item (j + 1) of a then
				set {item j of a, item (j + 1) of a} to {item (j + 1) of a, item j of a}
			end if
		end repeat
	end repeat
	return a
end sortFolders

In my searches I found many example scripts that I tried making work, but the two that I worked with the most was one from this site (Getting All Files List of Directory and of it's SubDirectories) and one from the Apple Support Community (https://discussions.apple.com/thread/252097137). No matter what I changed, both would error out.

OMG, copied the script and it took maybe a couple of seconds to run, and there on the desktop was my list. First the folders listed in alphabetical order, then the individual folders with their contents listed in alphabetical order. I intend to pick up a good basic book on AppleScript (suggestions?) and see if I can get an understanding of your script and why it does what it does.

Thank you!

FYI, I am 54 years old and self taught at everything computer related. I started teaching myself how to write code with AppleScript about 6 years ago because I had a stroke, which severely affected the use of my fingers and hands. My thought process at the time was “wouldn’t it be cool if I could completely control my computer using only my voice”. I was already dabbling with Mac’s built in Dictation Commands but it had its limits. So I started writing little snippets of code and saving them and turning them into speakable commands.

Just like you, I started with small little projects. It was very confusing at first but with trial and error, I started to get better a little bit at a time. The better I got, the more fun it became. I did tons of reading in the forums and I downloaded some AppleScript books and soldiered on.

I’m going to give you some advice that I wish I had done from the very start when I started learning AppleScript. Learn Shell Scripting in Terminal.app! I hated it at first when I started but now I absolutely love it. I started using Terminal about a year and a half after I started learning AppleScript. That was my huge mistake.

That said, here is an AppleScript solution which does not use Finder at all.

activate
set chosenFolder to quoted form of POSIX path of ¬
	(choose folder with prompt "Choose A folder to list it's contents")

do shell script "find " & chosenFolder & ¬
	" -mindepth 1 |sort -f |tr -s '//' > ~/Desktop/Folder_Contents.txt"
2 Likes

I wish you well with the health issues, tough stuff.

As for the Shell Scripting in Terminal, that’s where I started. Simple stuff at first, then I discovered rsync (I’m a sucker for backup software) and started writing my own simple backup scripts. The more I learned, the more complex the scripts became. What I’ve ended up with is a routine that checks the backup against the source, syncs the two, archives any changed/deleted files into a separate dated folder and then goes back and clears out any changed/deleted archive that is over 90 days old.

After that I started doing small Apple Scripts just to see if I could do it. I tend to be obsessed with keeping things tidy. Every time I shut down the Mac I would first go the the menu bar and clear the “Recent Folders” and “Recent Files” menus. I now have an Apple Script that does that for me.

tell application "Finder" to activate
tell application "System Events" to tell application process "Finder"
	tell menu "Apple" of menu bar item "Apple" of menu bar 1
		click menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items"
	end tell
end tell

tell application "Finder" to activate
tell application "System Events" to tell application process "Finder"
	tell menu "Go" of menu bar item "Go" of menu bar 1
		click menu item "Clear Menu" of menu "Recent Folders" of menu item "Recent Folders"
	end tell
end tell

As for the speed of the script. Right now I’m on a 2020 M1 MacBook Pro, so the list appears on the desktop as soon as I run the script. I’ve also got a late 2014 Mac mini, but it’s an I7 processor with 16 GB of memory and the internal drive is an Apple SSD, so I don’t expect the speed of the script to suffer at all. Thanks again.

I’m now doing searches on how to change your “choose folder” to a specific folder in my Documents as the location of the folder never changes.

Homer712. To specify a specific folder in the script, delete existing line 1 below and insert new line 2 below.

set theFolder to (choose folder)
set theFolder to "Macintosh HD:Users:Robert:Records:" as alias -- change path to desired value

BTW, I previously wrote a script in ASObjC (post 4 here) which performs the exact same task as my Finder script but is 10 times faster. I posted the Finder script above because it’s more easily understood.

Here is a version of Peavine’s script using “System Events” rather than Finder

on run
	set foldersAndFiles to getfoldersAndFiles()
	writeFile(foldersAndFiles)
end run

on getfoldersAndFiles()
	local theFolder, theFolders, foldersAndFiles, theFiles, tid
	set theFolder to (choose folder)
	set foldersAndFiles to {theFolder as text}
	
	tell application "System Events"
		set theFiles to (name of every file in theFolder)
		if (count theFiles) = 0 then set the end of foldersAndFiles to theFiles
		
		try
			set theFolders to (path of every folder in theFolder) --as  list
		on error
			display alert "No folders were found in the selected folder"
			error number -128
		end try
		
		set theFolders to sortFolders(theFolders) of me -- disable to change folder sort
		
		repeat with aFolder in theFolders
			set end of foldersAndFiles to linefeed & aFolder
			set theFiles to name of every file in folder aFolder
			if theFiles ≠ {} then set the end of foldersAndFiles to theFiles
		end repeat
	end tell
	
	set {tid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
	set foldersAndFiles to foldersAndFiles as text
	set AppleScript's text item delimiters to tid
	return foldersAndFiles
end getfoldersAndFiles

on writeFile(theText)
	set targetFile to (path to desktop as text) & "Folder Contents.txt"
	try
		set openedFile to (open for access file targetFile with write permission)
	on error errorMessage
		display alert "An error occurred while writing a file" message errorMessage as critical
		return false
	end try
	set eof of openedFile to 0 -- delete this line to append data
	write theText to openedFile starting at eof
	close access openedFile
end writeFile

on sortFolders(a)
	repeat with i from (count a) to 2 by -1
		repeat with j from 1 to i - 1
			if item j of a > item (j + 1) of a then
				set {item j of a, item (j + 1) of a} to {item (j + 1) of a, item j of a}
			end if
		end repeat
	end repeat
	return a
end sortFolders
1 Like

Thank you for all the assistance, truly appreciated.

I ran into an issue today, resolved it, but have no idea why it was an issue, but hoping there’s an explanation I can understand.

I have a number of pretty simple AppleScripts that I was able to load into an Automator as an “application.” Tried that with Peavine’s script an it produced an error.

When you go to run an AppleScript via Automator the following comes up:

on run {input, parameters}

(* Your script goes here *)

return input

end run

The solution was to delete everything above, and just copy/paste to AppleScript as it is, and then it runs perfectly.

Also, I know I did it once already, but how do you insert a script into these replies?

Yes it was, thanks. And on the script you (sorry, robertfern) just posted, the folders are in alphabetical order, but the files within them are not.

Seem to be lost here. When I first started doing replies (by clicking on “reply” to the person’s post, my reply had their name attached to it. That is no longer happening.

Is it possible in AppleScript to change the output file to pdf rather than txt?

A script contains a top-level run handler (which can be explicit or implicit) and may contain additional explicit handlers. My script contains an implicit run handler (with the first two lines of the script) plus three explicit handlers named getFoldersAndFiles, writeFile, and sortFolders.

You cannot place the additional explicit handlers inside the run handler and that’s what you appear to have done. The simple solution is to delete all code provided by Automator and paste my script in its place.

A good explanation of handlers can be found here.

It can be done, but it’s cumbersome and is best avoided unless you have a really important reason for wanting the PDF.

I have none, it was just a thought.

On a side note, really, really regret not finding this site earlier. The wealth of information, and the willingness of the members to help folks along is really amazing. Thanks to all.

I got introduced to programming in 1982. After Fortran, I had to learn Pascal, Visual Basic, Assembler, Macro Assembler, AppleScript.

In my experience, the fastest and most efficient way to learn a programming language is to 1) buy a good book with lots of practical examples, 2) run those examples on a computer.

Other subtleties can be found on the forums, in the electronic documentation for the language. But this is the last step in improving knowledge. The first is a book. You should choose not a cheap, but a voluminous book.

Agree, any suggestions?

In the “read me” for the FileManagerLib is states “Once you have installed the file in ~/Library/Script Libraries.”

I am running Monterey 12.6.8 and can find no ~/Library/Script Libraries location. I have tried putting the file into other locations (anything with the word “script” in it) to no avail. Where does this file go, and do you copy it with the folder, or just the actual file? Thanks.

~ is short for your home directory, something like /Users/yourname/