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.
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
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.
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"
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
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.
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.
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.
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.