Getting Modification Date?

I have a script that gets a list of files& folders at a specific level of a directory structure.

I used to be able to use a construct like this:

		set current_file to item m of list_of_of_directories_as_text
		set current_modification_date to modification date of current_file

Worked under Tiger and AppleScript would not care if it was a File or Folder and would get the modification date without issue.

But Leopard seems to want “file” or “folder” stated explicitly before getting a modification date, so the above breaks. If I add the explicit for “file” it works until it hits a folder, and an explicit “folder” errors when it hits a file.

So how under Leopard to you get it not to care which it is and just get the darned date again? :stuck_out_tongue:

I’m finding this change in Leopard kinda annoying…I have alot of scripts that relied on implicit coersion (know a file is a file without saying so, or a folder a folder, or that both mixed together were okay). BAH.

Figures, after spending 30 minutes on it, I stumble on the answer 2 minutes after I post here…osmosis?

Turns out I have to use “item” and coerce the text to alias. Tiger let you skip the “item” and even the “alias” part, seems to require more explicit syntax now. BAH:

       set current_file to item m of list_of_of_directories_as_text
       set current_modification_date to modification date of item (current_file as alias)

Hey Kevin,

Try this.


set current_file to item m of list_of_of_directories_as_text as alias
set current_modification_date to modification date of (info for current_file)

Cheers,

Craig

Hi,

it depends on the context.

Within a Finder tell block you can get the properties of a file or folder, if the file / folder is an alias or (Finder) file specifier
Only the Finder can get the properties of an alias directly, it doesn’t work outside a Finder tell block


set theFile to "Path:To:TheFile"
tell application "Finder"
	set m to modification date of file theFile
	set m to modification date of alias theFile
end tell

outside any tell block you can get the properties of a file or folder with the Standard Addition info for,
in this case the file / folder must be an alias or file URL (not Finder file specifier!!)

set m to modification date of (info for theFile as alias)

I recommend to take care of the file classes in the scripts without mixing-up the classes too much.
If you work with files on a shared volume, use Finder file specifier with path strings.
On local volumes aliases are preferable

System Events can do it too. I usually prefer using system events instead of the Finder whenever possible because the Finder has a tendency to be busy some times doing other stuff, system events doesn’t usually have that problem.

set theFile to "Path:To:TheFile"

tell application "System Events"
	set m to modification date of file theFile
	set m to modification date of alias theFile
end tell

StefanK:

I’m using a Finder tell block, and I’m using the script on a remote volume. But I’m also using “as alias” coersion on file paths that are stored “as text” (they are being returned by the shell “find” command). Not using “as alias” for any other reason than it fixed my problem. Per some other advice I went through and stripped out all the “string” and “Unicode text” references in favor of “text” and where possible made “file” and “folder” explicit.

As much as I would usually not have a problem with explicit “file” and “folder” designators, in this instance I want “items”…whether it’s a file or folder isn’t the point, it’s the modification date of each “item” in a given directory regardless if it’s a file or folder.

Sounds like I shouldn’t use “as alias,” but what should I use to query the modification date for either file or folder?

Here’s a larger chunk of code that is working now:

--filter for files older than mark date
set files_to_mark to {}
repeat with m from 1 to (number of items in user_folders_filtered_contents)
	tell application "Finder"
		set current_file to item m of user_folders_filtered_contents
		set current_modification_date to modification date of item (current_file as alias)
		if current_modification_date < g_mark_date then
			set files_to_mark to files_to_mark & item m of user_folders_filtered_contents
		end if
	end tell
end repeat

user_folder_filtered_contents is a list of file paths returned by a shell “find” but has had invisibles removed as well as files and folders I wish to ignore. The paths are saved Apple style (colon delimiters) as text.

sorry, do you read my posts??
Third time:
I’D LIKE TO REPEAT, AVOIDING CLASS ALIAS ON SHARED VOLUMES IS STRONGLY RECOMMENDED

this syntax


set _desktop to path to desktop as text --> "MacHD:Users:Kevin:Desktop:" (it's silly, but it's only an example)
tell application "Finder"
	set current_file to item 1 of folder _desktop --> for example document file "myFile" of folder Desktop." (Finder file specifier)
	set current_modification_date to modification date of current_file -- no more specification or alias coercion needed
end tell

StefanK:

Wrong side of the bed much? No idea why you’re so pissed…I asked precisely because I want to know how. You seem upset because I simply restated the premise (so shoot me?) I’m guessing you’re misunderstanding what I want because your answers seem mixed (your example is local, not server, for example). So maybe you gave the right answer but wrong explanation?

Come on dude, have you known me to ignore you…jeebus you’ve been very helpful in the past…chill or don’t help if it bugs you so much. :stuck_out_tongue:

So let me back-up and try again, so maybe either a) I’ll get the answer I need, or b) you’ll give me the explanation that is going over my head.

I have a routine that used the shell “find” command to find the first-level contents of a given directory x-levels down in the directory structure and returns the item list. So, if the serverdirectory contains…

File01.jpg
File02.ai
Folder01
File03.psd
Folder02
Folder03

The list is something like…

{“Server:Directory:Subdirectory:UserFolder:File01.jpg”, “Server:Directory:Subdirectory:UserFolder:File02.ai”, “Server:Directory:Subdirectory:UserFolder:Folder01”, “Server:Directory:Subdirectory:UserFolder:File03.psd”, “Server:Directory:Subdirectory:UserFolder:Folder02”, “Server:Directory:Subdirectory:UserFolder:Folder03”}

…formatted “as text”

You said aliases are bad mojo, that’s fine. So is your example…

tell application "Finder"
   set current_file to item 1 of folder _desktop --> for example document file "myFile" of folder Desktop." (Finder file specifier)
   set current_modification_date to modification date of current_file -- no more specification or alias coercion needed
end tell

…which is great for a specific instance, but what if I’ve pre-collected for each folder as a bulk rather than parsing a folder at a time?

In other words, I have 10 folders with contents similar to above, so instead of doing them one at a time and jumping back and forth in the directories (since the “levels down” varies from place to place on my server), I collect all the files I wish to examine all at once, with their complete path from top-down, not in relation to some upper directory.

In other words my “items” has ceased to be directly generated by the Finder, but instead aggregated into the “items” in the aforementioned list.

Is that more clear and help with why I seem confused at your help.

I’m trying to do the right thing here…ask questions and learn…

Here’s the entire script, working, but apparently needing help to get rid of the “as alias” evils. ;-p
(DIamond Design is a Mac OS X Server mounted on my desktop…and please note the StefanK assistance throughout!)

Peace man…I’d buy you an Earle Grey to relax your nerves, but virtual tea tastes aweful. :stuck_out_tongue:

--
--Transfer Folder Marker & Cleaner
--by Kevin Quosig, 2007
--
--Marks and deletes old files in the Diamond Design Transfer File folder.
--

--
-- DECLARE PROPERTIES
--
-- debugging/logging on?
property g_debug : true

--basic file path and names
property g_home_folder_path : path to home folder
property g_log_file_name : "LOG--Overnight Automation.txt"
property g_transfer_files_location : "Diamond Design:Transfer Files"

--Mac OS names to be ignored
property g_exclusions_macosx : {"Temporary Items", "Trash", ".DS_Store", "TheFindByContentFolder", "TheVolumeSettingsFolder", "z_CS Separation Transition", "Icon
"}

--folder names not to be scanned
property g_exclusions_folders : g_exclusions_macosx & {"_VACATION REQUESTS", "WB"}

--folder names of users whose contents should never be deleted automatically
property g_exclusions_users : g_exclusions_macosx & {"SKU LISTS", "WB", "AR", "BW", "JR", "KQ", "Cost Tracking DB"}

--file marking threshold 
property g_mark_days : 7 --files older than this number of days will be marked
set g_mark_date to ((current date) - (g_mark_days * days))

--file deletion threshold 
property g_delete_days : 14 --files older than this number of days will be deleted
set g_delete_date to ((current date) - (g_delete_days * days))

--transfer folder size for additional reminders
property g_threshold_size : 300 as integer --size in megabytes


--
-- UTILITY HANDLERS
--

--Log Entry Generation
--
-- with help from StephanK of MacScripter
-- http://bbs.applescript.net/viewtopic.php?pid=76607#p76607
--
on logMe(log_string, indent_level)
	if g_debug is true then --allows turning the debugger on and off so my logMe's can be left in final version
		set log_target to ("Data: Automation:Logs:" & g_log_file_name) as text
		try
			set log_file_ref to open for access file log_target with write permission
			repeat indent_level times
				write tab to log_file_ref starting at eof
			end repeat
			write ((log_string as text) & return) to log_file_ref starting at eof
			close access log_file_ref
			return true
		on error
			try
				close access file log_target
			end try
			return false
		end try
	end if
end logMe


-- Date stamp generator
--
-- with help from StefanK of MacScripter
-- http://bbs.applescript.net/viewtopic.php?id=20420
--
on dateStamp()
	
	-- Load date components from system
	tell (current date)
		set dayStamp to day
		set monthStamp to (its month as integer)
		set yearStamp to year
	end tell
	
	--coerce components to two-digit form
	set dayStamp to (text -2 thru -1 of ("0" & dayStamp as text))
	set monthStamp to (text -2 thru -1 of ("0" & monthStamp as text))
	set yearStamp to (text 3 thru 4 of (yearStamp as text))
	
	--Assemble datestamp
	return yearStamp & monthStamp & dayStamp as text
	
end dateStamp


-- Get a file/folder list of all items at a certain level inside a given folder
--
-- with help from chrys of MacScripter
-- http://bbs.applescript.net/viewtopic.php?pid=91191#p91191
--
on listGetter(folder_to_scan, scan_level, folder_exceptions)
	--exceptions formatted for shell find
	copy folder_exceptions to folder_exceptions
	repeat with fe_ref in folder_exceptions
		set contents of fe_ref to quoted form of contents of fe_ref
	end repeat
	set ASTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to " -or -name "
	set exclude_code to text 6 thru -1 of ("" & ({""} & folder_exceptions))
	set AppleScript's text item delimiters to ASTID
	--do shell find with exceptions
	do shell script "/usr/bin/find " & (quoted form of POSIX path of folder_to_scan) & " ! \\( \\( " & exclude_code & " \\) -prune \\) -maxdepth " & scan_level & " -mindepth " & scan_level & " -print0 ; true" without altering line endings
	set find0 to result
	set {ASTID, text item delimiters} to {text item delimiters, {ASCII character 0}}
	try
		set POSIX_pathnames to text items 1 through -2 of find0 -- Drop the last text item because it is always empty (find -print0 always prints a trailing null).
		set text item delimiters to ASTID
	on error m number n from o partial result r to t
		set text item delimiters to ASTID
		error m number n from o partial result r to t
	end try
	script speedHack
		property Mac_pathnames : {}
	end script
	repeat with P_pn in POSIX_pathnames
		set end of speedHack's Mac_pathnames to (POSIX file (contents of P_pn)) as text
	end repeat
	speedHack's Mac_pathnames
end listGetter


--get user folders that aren't empty
--
on nonEmptyFolders(directory_to_filter)
	set filtered_folder_list to {}
	
	repeat with e from 1 to (number of items in directory_to_filter)
		tell application "Finder"
			set folder_to_check to (item e of directory_to_filter) as alias
			set item_contents to (number of items in folder folder_to_check)
			if number of items in folder folder_to_check > 0 then
				set filtered_folder_list to filtered_folder_list & folder_to_check
			end if
		end tell
	end repeat
	
	return filtered_folder_list
end nonEmptyFolders

--
-- MAIN SCRIPT
--

my logMe("Transfer Folder Cleaner and Logger Begin--" & (current date), 1)

--COLLECT DATA

--get transfer folder categories (include empties)
set category_folders to {}
set category_folders to listGetter(g_transfer_files_location, 1, g_exclusions_folders)

--get user folders (include empties)
set user_folders to {}
repeat with j from 1 to (number of items in category_folders)
	set user_folders to user_folders & listGetter(item j of category_folders, 1, g_exclusions_users)
end repeat

--get user folders that aren't empty
set user_folders_filtered to {}
set user_folders_filtered to nonEmptyFolders(user_folders)

--get user folder contents (skip empties)
set user_folders_filtered_contents to {}
repeat with k from 1 to (number of items in user_folders_filtered)
	set user_folders_filtered_contents to user_folders_filtered_contents & listGetter(item k of user_folders_filtered, 1, g_exclusions_macosx)
end repeat

--filter for files older than mark date
set files_to_mark to {}
repeat with m from 1 to (number of items in user_folders_filtered_contents)
	tell application "Finder"
		set current_file to item m of user_folders_filtered_contents
		set current_modification_date to modification date of item (current_file as alias)
		if current_modification_date < g_mark_date then
			set files_to_mark to files_to_mark & item m of user_folders_filtered_contents
		end if
	end tell
end repeat

--filter for files older than delete date
set files_to_delete to {}
repeat with d from 1 to (number of items in user_folders_filtered_contents)
	tell application "Finder"
		set current_file to item m of user_folders_filtered_contents
		set current_delete_date to modification date of item (current_file as alias)
		if current_delete_date < g_delete_date then
			set files_to_delete to files_to_delete & item d of user_folders_filtered_contents
		end if
	end tell
end repeat

--MARK OLD FILES
repeat with currently_coloring in files_to_mark
	tell application "Finder"
		set label index of item (currently_coloring as alias) to "2"
	end tell
end repeat

my logMe("Items over " & g_mark_days & " days: " & (number of items in files_to_mark), 2)

--DELETE OLDEST FILES
(*
repeat with currently_deleting in files_to_delete
	tell application "Finder"
		delete file currently_deleting
	end tell
end repeat
*)

my logMe("Items over " & g_delete_days & " days: " & (number of items in files_to_delete), 2)

--get user folders that aren't empty (updated)
set user_folders_filtered to {}
set user_folders_filtered to nonEmptyFolders(user_folders)


my logMe("Transfer Folder Cleaner and Logger End--" & (current date), 1)

My example is quite independent from local or shared, because the Finder treats both the same way in this case

You probably want to process only the files, not the folders, so the easiest way is to filter all folders already in the shell find line.
Try to insert -type f right before the print0, of course separated by a space character

then use this syntax for example

 tell application "Finder"
       set current_file to file (item m of user_folders_filtered_contents)
       set current_delete_date to modification date of current_file
       .
   end tell

or, without the -type f flag, if you want to process the folders, too


tell application "Finder"
	try
		set current_file to file (item m of user_folders_filtered_contents) -- throws an error, if it's no file
	on error
		set current_file to folder (item m of user_folders_filtered_contents)
	end try
	set current_modification_date to modification date of current_file
     .
   end tell

Yes, do need to process the folders. Bummer have to go through all those hoops, much simple before. :wink:

Thank you for your patience. :stuck_out_tongue:

So on a side note…why is Apple pushing folks away from the “as alias” for servers? I mean, instead of having the dichotomy, why don’t they get rid of “as alias” for both instances (local vs. remote) like they did “as string” and “as Unicode text” (which became “as text”…I understand why, but still…)?

I just think all these new rules go against the spirit of AppleScript, which is that AppleScript itself has some intelligence and doesn’t need such “literalness.” Kinda turning into a much more formal language these days. :stuck_out_tongue:

This isn’t actually a new rule. Already in Tiger using aliases as pointers to files and folders on a shared volume didn’t work reliably at all.

The AppleScript alias class works similar to a Finder alias.
As mentioned above, the alias points to a file or folder “object”. It doesn’t matter, if the object will be moved or renamed.
The Finder uses just an ID, not the real path or name. For this purpose the file system uses a database.

A local volume can be scanned very fast to update the database, the same way as Spotlight updates its index.
On a shared volume, which will be mounted dynamically, updating the database is not possible in the same speed.

Therefore it’s more reliable, to use real paths as file specifiers.

I hope this explains the problem, which is not a Leopard specific problem

You can use just the term “item” to reference either a string path to a file or folder with the Finder… without coercing it to an alias. The following works in Leopard. I didn’t check it in Tiger but I think it’s the same… maybe.

set theFolder to path to preferences folder as text
set theFile to theFolder & "com.apple.dashboard.plist"

tell application "Finder"
	set current_modification_date to modification date of item theFolder
	set current_modification_date to modification date of item theFile
end tell

This didn’t work the first time I tried it (before asking the question here), but that was before I switched all the “Unicode text” and “string” coersions to “text” and now it seems to work, short and sweet and with the “try” of StefanK’s code.

BUT, since I don’t want to start a row again accidentally , and I do want to do this “right”…I’d like StefanK’s feedback on the use of “item”.

I want to clean-up this script as much as possible since it is going to be the starting point for a similar script I need to write ASAP.

Thanks again profusely for the help.

Oh, and to StefanK…nice to know it wasn’t Leopard that caused it specifically…but some reason Leopard made the fracture apparent. Did Leopard change the way it accessed servers? Is it possible the change from “scpt” format to “scptd” format (which I had to do to get my scripts to play nicely with Leopard) affected the issue?

Always more to learn…

OK, since I’m not such an expert then look it up in the Finder’s dictionary yourself. The term “item” is a real term.

Lots of grumpy people here today…yeesh. Didn’t mean to imply you were “wrong” or anything, and I know it’s a real term, but so is “as alias” and apparently it’s bad mojo. StefanK seemed to have near-vehemently strong feelings on the matter, and it never hurts to have a second opinion, right?

That’s all. Jeebus, everybody wake-up on the wrong side of the ADSL line this morning? :stuck_out_tongue:

If there was ever a case for legalizing marijuana it’s you two today. :cool:

I have no experience using scptd, but what’s the advantage, unless you want to store data into the bundle?

Right, I haven’t thought of that. It’s indeed the easiest solution

My scripts stopped working with cron and Leopard in general when just using scpt, though in retrospect, it may have been just these pathing issues and the scripts just weren’t giving errors…hmmmm…gonna have to look at that again.

In any case a few folks told me scrptd was preferred for scripts…same as the “don’t us ‘as alias’” kinda advice. “Best practice” as we call it in the corporate world. Whether or not that is 100% true, no idea…I tend to take any relative concensus here seriously. :wink:

Thanks for the confirmation. :slight_smile:

Appreciate yours and regulus’ help as well. Hope y’all are having a better day today. :smiley:

I guess, the errors come rather from slutty code :wink:

BTW: cron is “deprecated” in Leopard, because it’s a child process of launchd.
It’s recommended to use launchd anyway

I’ve never heard about this. Maybe you mix it up with the save as application option.
Unlike application, which created a carbon application depending on the processor type,
application bundle creates a cocoa UB application, which is compatible with PPC and Intel.

Hey, beg pardon, posted it often enough for advice and no one corrected me. I plead ignorance compounded by “it worked”…which is kinda the spirit of AppleScript. If I wanted to be a codemonkey I’d learn C and Perl (okay, so I would like to learn those, just not enough time in the day…) :stuck_out_tongue:

Knew you’d bring that up, you never can resist. :stuck_out_tongue: I simply find cron (managed by CronniX) alot easier to use to manage multiple scheduled tasks. So far, no similar functionality is available for launchd (where I can look at and manage entire calendar of scripts rather than one-at-a-time)…folks here have pointed me at UIs for launchd and none of them do what CronniX does for me.

When Apple gets rid of cron altogether or it stops working, or a better UI for launchd comes around, then I’ll switch. :stuck_out_tongue:

Point taken, I may have, as saving scripts as applications works better with cron…may very well be the case, thanks for catching that.

Have you looked at Lingon

I hear good things about it.

Cheers,

Craig