Numeric file size after finder search results

Searching for specific files in finder the size always shows something like 2,4 Mb or GB etc.
selecting the get info for each file i get the actual numeric size. however if the files found are hundred it becomes impossible to get a proper list with numeric file values.
I need to get a tab separated list with name, dates (created, modified, opened, ecc), full numeric size, kind, extension.
How to achieve such result using Mojave Applescript?
I really need the full size numeric result, not only the 4 GB or 2,14Mb …
Thanks a lot

Browser: Google Chrome 98.0.4758.80
Operating System: macOS 10.14

No idea what works in the more recent versions of the OS but in general you can get most of those properties with something like this:

tell application "Finder"
	
	set fileList to selection as alias list
	set file1 to item 1 of fileList
	set fi to info for of file1
	
	set props to (name of fi) & tab & (size of fi) & tab & (creation date of fi)
	
end tell

The ‘size’ property will return the number of bytes in a file. If you comment out the ‘set props…’ line then you can see all of the properties that the ‘info for’ command returns. If you have a really large selection of files it could be sluggish. Using a repeat loop, you could generate your list for multiple files.

If there are any properties that you desire which aren’t returned by info for, then you might try using a shell script and the mdls command. Add the following line to after the ‘end tell’ statement:

do shell script "mdls " & (POSIX path of file1)

Note that if your file is located within Downloads, then you might get a restricted list of attributes due to quarantining rules.

FWIW, I think that there have been a handful of solutions posted on getting such information. It might be worth your while to try a search.

thank you very much, for your time and care.
However I am sure I didn’t write my question properly.

I have a folder with hundred of …txt files.
I searched before for those specific files in my mac and the Finder returned with the result as such:

filename/size -example 4,3MB/kind/ + the various dates

I then select them all and paste them in Bbedit.
From Bbedt I can import in Filemaker to compare them, delete the ones I don’t need and so on, open and read others, move trhem in nerw folders. All this using useful plug in in Filemaker.

For this reason I need for the size to be a regular number as oit appears in thew “get info” selecting one file at the time, so the comparison can be accurate, as name and dates are often misleading.

perhaps there is already a script which will choose one by one the files from the folder and transfer the getinfo data to another folder with a carriage return at the end of the new file.

I am no expert in Applescript but what i imagine should be something as follows

1-select folder
2-export the various infos as from the fionder search result
3-convert the size to a numeric readable number

I understand this isn’t at all an applescript, but i am no0t even a newbie and i hope these info would help to clarify m y request for help

sincere thanks again

rimi

this is what i get from the script you suggested:

tell application “Finder”

set fileList to selection as alias list
set file1 to item 1 of fileList
set fi to info for of file1

set props to (name of fi) & tab & (size of fi) & tab & (creation date of fi)

end tell

tell application “Finder”
get selection
→ {alias “Jade:”}
info for alias “Jade:”
→ error number -10004
end tell
tell current application
info for alias “Jade:”
→ {name:“Jade”, creation date:date “Thursday, 11 November 2021 at 18:34:00”, modification date:date “Monday, 15 November 2021 at 21:35:06”, size:missing value, folder:true, alias:false, package folder:false, visible:true, extension hidden:false, name extension:missing value, displayed name:“Jade”, default application:alias “Jade:System:Library:CoreServices:Finder.app:”, kind:“Volume”, folder window:{0, 0, 0, 0}, file type:“”, file creator:“”}
do shell script “mdls /”
→ “”
end tell
Result:
“”

Well, I began trying to explain this in detail but then my system crashed and I lost my post so you get the abbreviated version :stuck_out_tongue:

A volume is not (or at least, doesn’t seem to be) just another folder. FYI, when you run ‘info for’ against a volume, it seems to always return size:missing value. You can just ask for ‘size’ however.

tell application "Finder"
	set xy to selection
	--> {startup disk of application "Finder"}	
	set xy to selection as alias
	--> alias "Macint:"

	set fi to info for of xy
	set sz to size of xy
	--> 4.77264175104E+11
end tell

When I open Get Info on my startup disk, it doesn’t display a size immediately. And when it does, it continues to change slowly for a while, presumably becoming incrementally more accurate as it has more time to weigh things. Likewise, when I get the size using a script, the result isn’t final. If I wait a bit and run the script again, I get a different size. This doesn’t really happen for regular folders. I assume that it’s related to stuff like metadata and symbolic links but I don’t really know.

I ran the script and it returned the following:
[format]–> 4.77396119552E+11[/format]

After typing another sentence, I ran it again and it returned this:
[format]–> 4.77396586496E+11[/format]

Just so you’re aware, applescript won’t display integers with values of 2^29 or higher, as is. It displays those using scientific notation. That means 536870911 is the highest integer that gets displayed this way. So, if you want to use these in a table, you need to mess around with them a bit:

tell application "Finder"
	set xy to selection as alias

	set sz to size of xy as text
	--> "4.77263044608E+11"
	
	character 1 of sz & (characters 3 thru 13 of sz)
	--> "477263044608"
end tell

On the subject of handling multiple selected folders, this should actually work. As implied above, I would be suspicious about using it on multiple volumes.

tell application "Finder"
	
	set folSel to selection as alias list
	set nmList to {}
	set szeList to {}
	set sziList to {}
	
	repeat with ef in folSel
		set end of szeList to size of ef
		-- convert sizes to integer/text
		if size of ef is greater than 2 ^ 29 then
			set sze to size of ef as text
			tell me to set end of sziList to character 1 of sze & (characters 3 thru ((offset of "E" in sze) - 1) of sze)
		else
			set end of sziList to size of ef
		end if
		set end of nmList to name of ef
	end repeat
	
	-- combine properties into tab-separated values
	set tsv to ""
	repeat with xx from 1 to count of nmList
		set tsv to tsv & item xx of nmList & tab & item xx of sziList & linefeed
	end repeat
end tell
tsv

FWIW, I tested Finder, System Events, and the info-for command, and they did not return date opened or added. If you need those, mdls would seem best, although the time returned appears not to be localized.

Hi.

Here’s a fairly fast effort which lists the properties of a selected folder’s files, using System Events to get the properties and vanilla AppleScript to collate the results. The final, tab-separated text is opened in a BBEdit document. Unfortunately, it’s not possible to get last-opened dates using either the Finder or System Events, so they’re not included here. It is possible to get last-accessed dates and added-to-directory dates by using ASObjC, or possibly a shell script, instead.

main()

on main()
	tell application "Finder"
		set theFolder to item 1 of (get selection)
		if (theFolder's class is not folder) then error "The selected item isn't a folder"
	end tell
	
	set theFolder to theFolder as alias
	
	script o
		property fileNames : missing value
		property creationDates : missing value
		property modDates : missing value
		property sizes : missing value
		property kinds : missing value
		property extns : missing value
		property output : {}
	end script
	
	-- Get the details of the folder's files en masse. The result is individual, parallel lists of names, creation dates, etc.
	tell application "System Events" -- Faster than the Finder.
		set {o's fileNames, o's creationDates, o's modDates, o's sizes, o's kinds, o's extns} to ¬
			{name, creation date, modification date, size, kind, name extension} of theFolder's files
	end tell
	
	set astid to AppleScript's text item delimiters
	-- Create each line of the text output from the corresponding details in each list.
	set AppleScript's text item delimiters to tab
	repeat with i from 1 to (count o's fileNames)
		set end of o's output to {get item i of o's fileNames, dateToText(item i of o's creationDates), dateToText(item i of o's modDates), ¬
			numberToText(item i of o's sizes), get item i of o's kinds, get item i of o's extns} as text
	end repeat
	-- Unite the lines into one text with linefeeds.
	set AppleScript's text item delimiters to linefeed
	set o's output to o's output as text
	set AppleScript's text item delimiters to astid
	
	tell application "BBEdit"
		activate
		make new text window with properties {text:o's output}
	end tell
end main

-- Derive a "YYYY-MM-DD hh:mm:ss" string from an AppleScript date.
on dateToText(theDate)
	set {year:y, month:m, day:d, hours:hr, minutes:min, seconds:sec} to theDate
	tell (100000000 + y * 10000 + m * 100 + d) as text to set datePart to text 2 thru 5 & ("-" & text 6 thru 7) & ("-" & text 8 thru 9)
	tell (1000000 + hr * 10000 + min * 100 + sec) as text to set timePart to text 2 thru 3 & (":" & text 4 thru 5) & (":" & text 6 thru 7)
	return datePart & (space & timePart)
end dateToText

-- Derive a straight numeric string (just digits) from an AppleScript whole number value.
on numberToText(n)
	set txt to ""
	repeat until (n < 100000000)
		set txt to text 2 thru -1 of ((100000000 + n mod 100000000) as integer as text) & txt
		set n to n div 100000000
	end repeat
	return (n as integer as text) & txt
end numberToText

Perhaps this:

set aFilePath to POSIX path of (choose file)
set dateAdded to (do shell script "mdls -name kMDItemDateAdded -raw " & quoted form of aFilePath)
set dateLastUsed to (do shell script "mdls -name kMDItemLastUsedDate -raw " & quoted form of aFilePath)

dateAdded --> "2022-02-01 20:25:02 +0000"
dateLastUsed --> "2022-02-09 14:55:12 +0000"

Hi peavine.

Unless there’s a way to make mdls handle hundreds of files in a single shell script, I’m guessing it could take quite a while.

Here’s an ASObjC offering which handles my test folder of 6592 files in about seven and a half seconds.

use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use scripting additions

main()

on main()
	tell application "Finder"
		set theFolder to item 1 of (get selection)
		if (theFolder's class is not folder) then error "The selected item isn't a folder"
	end tell
	
	set |⌘| to current application
	set folderURL to |⌘|'s class "NSURL"'s fileURLWithPath:(POSIX path of (theFolder as alias))
	set fileManager to |⌘|'s class "NSFileManager"'s defaultManager()
	-- The required property keys. The first two are the isDirectory and isPackage keys.
	-- The rest are in the order the values will appear in the final text.
	set propKeys to |⌘|'s class "NSArray"'s arrayWithArray:({¬
		|⌘|'s NSURLIsDirectoryKey, |⌘|'s NSURLIsPackageKey, |⌘|'s NSURLLocalizedNameKey, ¬
		|⌘|'s NSURLCreationDateKey, |⌘|'s NSURLContentModificationDateKey, |⌘|'s NSURLAddedToDirectoryDateKey, |⌘|'s NSURLContentAccessDateKey, ¬
		|⌘|'s NSURLFileSizeKey, |⌘|'s NSURLLocalizedTypeDescriptionKey})
	-- Get the URL of every visible file in the folder.
	set folderContents to fileManager's contentsOfDirectoryAtURL:(folderURL) includingPropertiesForKeys:({}) options:(|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	
	-- Script object to speed up the filling of the output list.
	script o
		-- Initialise the output with a tab-separated header row.
		property output : {"Name	Creation date	Modification date	Date added	Date last accessed	Size	Kind	Extension"}
	end script
	
	-- Set AppleScript's TIDs to a tab and work through the URLs.
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to tab
	repeat with thisURL in folderContents
		-- Get the properties fetched with this URL.
		set props to (thisURL's resourceValuesForKeys:(propKeys) |error|:(missing value))
		-- Get their values in the required order.
		set propValues to (props's objectsForKeys:(propKeys) notFoundMarker:("(not found)"))
		-- If the isDirectory and isPackage keys are the same, the item's either a file or a package.
		if (((item 1 of propValues) as boolean) = ((item 2 of propValues) as boolean)) then
			-- The remaining properties' descriptions are probably good enough here. Get them as a list of text.
			set propList to ((propValues's valueForKey:("description")) as list)'s items 3 thru end
			-- Append the URL's pathExtension.
			set end of propList to thisURL's pathExtension() as text
			-- Coerce the list to text (with the tab delimiter) and append the result to the output.
			set end of o's output to propList as text
		end if
	end repeat
	-- Unite the output into a single text with linefeeds.
	set AppleScript's text item delimiters to linefeed
	set o's output to o's output as text
	set AppleScript's text item delimiters to astid
	
	-- Open the text in a new BBEdit document.
	tell application "BBEdit"
		activate
		make new text window with properties {text:o's output}
	end tell
end main

Nigel. I tested your script, which worked great. I thought ASObjC would be the best solution but I didn’t know where to start.

Just as an aside, mdls does appear to work with multiple files–at least in my testing. It’s reasonably quick, although the volume containing the files has to be indexed. A partial example, the output of which needs to be parsed (I’m not sure how best to do that),

set theFiles to (choose file with multiple selections allowed)

repeat with aFile in theFiles
	set contents of aFile to (quoted form of POSIX path of aFile) & space
end repeat
set theFiles to theFiles as text

set fileData to (do shell script "mdls -name kMDItemDisplayName -name kMDItemPhysicalSize -name kMDItemContentCreationDate -name kMDItemContentModificationDate -name kMDItemDateAdded -name kMDItemLastUsedDate " & theFiles) -- output has to be parsed

Edit: February 14, 2022. The mdls utility also appears to work with wildcards if that’s preferred. For example,

set theFolder to POSIX path of (choose folder)
set theFiles to (quoted form of theFolder) & "*.pdf"

set fileData to do shell script "mdls -name kMDItemDisplayName -name kMDItemLogicalSize -name kMDItemContentCreationDate -name kMDItemContentModificationDate -name kMDItemDateAdded -name kMDItemLastUsedDate " & theFiles

Hi peavine.

That works well, although there seems to be an upper limit on the number of files any one mdls command is prepared to accept. (There’s also an upper limit on the number of characters in a ‘do shell script’ text, but I think it’s an mdls limit I’ve been seeing.)

Here’s an attempt to develop your code into a script similar to the ASObjC one above.

  1. It can’t handle my 6952-file folder because of the mdls limit. But it can handle a folder containing 2219 files, which sounds as if it would be adequate for danwan’s needs.
  2. It’s not as fast as the ASObjC — not the way I’ve written it, anyway. :wink:
  3. I’ve changed “kMDItemPhysicalSize” to “kMDItemLogicalSize” to match the output from the ASObjC script. “kMDItemLogicalSize” is equivalent to ‘size’ in the Finder and System Events and to “NSURLFileSizeKey” in Foundation. It’s the number of bytes in the file itself. “kMDItemPhysicalSize” is the amount of storage required to contain the file on disk. It’s the file size rounded up to the nearest multiple of the disk’s block size.
  4. “kMDItemLastUsedDate” doesn’t appear to be equivalent to my “NSURLContentAccessDateKey” either, but I can’t identify anything that is! Since I’ve no idea what danwan would want for this (if anything), I’ve left it as in your code.
  5. I’ve just realised that I’ve assumed the display names include the extensions! I’ll see if I can come up with something more reliable. (Edit: Done.)
main()

on main()
	tell application "Finder"
		set theFolder to item 1 of (get selection)
		if (theFolder's class is not folder) then error "The selected item isn't a folder"
	end tell
	
	set theFolder to theFolder as alias
	
	tell application "System Events" to set thePaths to POSIX path of theFolder's files
	
	script o
		property thePaths : missing value
		property fileData : missing value
		property output : {"Name	Creation date	Modification date	Date added	Date last accessed	Size	Kind	Extension"}
	end script
	tell application "System Events" to set o's thePaths to POSIX path of theFolder's files
	
	repeat with i from 1 to (count o's thePaths)
		set item i of o's thePaths to quoted form of item i of o's thePaths
	end repeat
	
	set astid to AppleScript's text item delimiters
	-- Use the quoted paths (silently coerced to text and separated by spaces) in an mdls shell script to get the required data.
	set AppleScript's text item delimiters to space
	set o's fileData to paragraphs of (do shell script "mdls -name kMDItemDisplayName -name kMDItemLogicalSize -name kMDItemContentCreationDate -name kMDItemContentModificationDate -name kMDItemDateAdded -name kMDItemLastUsedDate -name kMDItemKind " & o's thePaths)
	
	set rowTemplate to {missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value} -- 8 slots.
	repeat with i from 1 to (count o's fileData) by 7
		set AppleScript's text item delimiters to "= "
		repeat with j from i to (i + 6)
			set thisEntry to item j of o's fileData
			if (thisEntry begins with "kMDItemDisplayName") then
				set fileName to text 2 thru -2 of text item 2 of thisEntry -- Strip quotes.
				set item 1 of rowTemplate to fileName -- Display name.
				set AppleScript's text item delimiters to "."
				set item 8 of rowTemplate to text 1 thru -2 of text item -1 of item (i div 7 + 1) of o's thePaths -- Extension.  :)
				set AppleScript's text item delimiters to "= "
			else if (thisEntry begins with "kMDItemLogicalSize") then
				set item 6 of rowTemplate to text item 2 of thisEntry
			else if (thisEntry begins with "kMDItemContentCreationDate") then
				set item 2 of rowTemplate to text item 2 of thisEntry
			else if (thisEntry begins with "kMDItemContentModificationDate") then
				set item 3 of rowTemplate to text item 2 of thisEntry
			else if (thisEntry begins with "kMDItemDateAdded") then
				set item 4 of rowTemplate to text item 2 of thisEntry
			else if (thisEntry begins with "kMDItemLastUsedDate") then
				set item 5 of rowTemplate to text item 2 of thisEntry
			else -- kMDItemKind
				set item 7 of rowTemplate to text 2 thru -2 of text item 2 of thisEntry
			end if
		end repeat
		-- Coerce the list to a tab-delimited text and append the result to the output.
		set AppleScript's text item delimiters to tab
		set end of o's output to rowTemplate as text
	end repeat
	-- Unite the output into a single text with linefeeds.
	set AppleScript's text item delimiters to linefeed
	set o's output to o's output as text
	set AppleScript's text item delimiters to astid
	
	-- Open the text in a new BBEdit document.
	tell application "BBEdit"
		activate
		make new text window with properties {text:o's output}
	end tell
end main

Nigel. I tested your script, which implements mdls, and it worked great. For me, your ASObjC script is the one to use, but it’s good that the OP has an mdls solution. I’ve never used mdls much, and I learned a lot from this thread.

I noticed this morning that my ASObjC script didn’t include a header for “Kind” and the mdls one didn’t cater for “Kind” at all. Both scripts now corrected.

The OP appears to have what he wants, and I thought I might post on a related but marginally different topic.

It seems a useful thing to be able to get two or three bits of mdls data for a series of files, much as is done above, and to create a list of lists with each sublist containing the data for one file. ASObjC is probably the best way to do this, but I decided to stick with mdls for this project.

A few thoughts:

  • I used the mdls raw option for speed and brevity. The values returned by mdls are not in the order expected but are returned in a reliable order in my testing. If that’s not the case, the script will throw an error and the use of the raw option would need to be abandoned.

  • I wanted to convert all dates to a date object reflecting the user’s locale, the goal being that the date/time returned by the script is the same date/time shown by Finder.

  • With 100 test files, the script took 160 milliseconds to run.

  • If the number of files being processed is very large, this script should be edited to use a script object.

use framework "Foundation"
use scripting additions

on main()
	set theFiles to (choose file with multiple selections allowed)
	set ATID to AppleScript's text item delimiters
	
	repeat with aFile in theFiles
		set contents of aFile to (quoted form of POSIX path of aFile) & space
	end repeat
	
	set rawFileData to (do shell script "mdls -raw -name kMDItemFSName -name kMDItemDateAdded " & theFiles)
	set AppleScript's text item delimiters to {character id 0}
	set rawFileData to text items of rawFileData
	
	set fileData to {}
	set AppleScript's text item delimiters to {space}
	repeat with i from 1 to (count rawFileData) by 2 -- change to reflect data item count
		set theDate to getLocalDate(text 1 thru text item 2 of item i of rawFileData)
		set end of fileData to {text item (i + 1) of rawFileData, theDate}
	end repeat
	
	set AppleScript's text item delimiters to ATID
	return fileData
end main

on getLocalDate(dateString)
	set theFormatter to current application's NSDateFormatter's new()
	theFormatter's setDateFormat:"yyyy-MM-dd' 'HH:mm:ss"
	set theDate to (theFormatter's dateFromString:dateString)
	set theTimeZone to current application's NSTimeZone's localTimeZone()
	set secondsToGmt to (theTimeZone's secondsFromGMTForDate:theDate)
	return ((theDate as date) + (secondsToGmt))
end getLocalDate

set theFileData to main()

Given that ‘time to GMT’ is not ‘time to UTC’, would your ‘getLocalDate’ be universal?

Mockman. Thanks for looking at my script.

My knowledge of dates is extremely poor, and, unfortunately, I don’t know the answer to your question. In an earlier version of my script (see handler below), I used the “time to GMT” command, which the documentation indicates does use Universal Time.

An issue that may not be dealt with in my script is Daylight Savings time, and apparently neither the “time to GMT” command nor the secondsFromGMTForDate method consider that. This is of some importance for me because my State does not observe Daylight Savings Time but other states in my time zone do. There is a daylightSavingTimeOffset method, and perhaps I need to incorporate that in my handler.

Anyways, you asked a simple question and, as mentioned above, I don’t know the answer.

My earlier handler:

on getLocalDate(dateString)
	set theFormatter to current application's NSDateFormatter's new()
	theFormatter's setDateFormat:"yyyy-MM-dd' 'HH:mm:ss"
	set theDate to (theFormatter's dateFromString:dateString) as date
	set theDate to theDate + (((time to GMT) div 3600) * hours)
end getLocalDate

peavine, you’re making things unnecessarily complex for your self by stripping out the time zone info in the first place.

set fileData to {}
repeat with i from 1 to (count rawFileData) by 2 -- change to reflect data item count
	set theDate to getLocalDate(item i of rawFileData)
	set end of fileData to {text item (i + 1) of rawFileData, theDate}
end repeat
set AppleScript's text item delimiters to ATID

on getLocalDate(dateString)
	set theFormatter to current application's NSDateFormatter's new()
	theFormatter's setDateFormat:"yyyy-MM-dd' 'HH:mm:ss Z"
	set theDate to (theFormatter's dateFromString:dateString)
	return theDate as date
end getLocalDate

If the computer clock’s correctly set for its location, time to GMT returns the difference between the computer’s local time and GMT/UTC at the moment the function’s executed, which isn’t necessarily relevant to a date being considered. Since the result’s positive for time zones that are ahead of GMT and negative for those behind, I’ve always felt it should have been called time from GMT. :slight_smile:

Shane. Thanks for the suggestion, which works great. At first I was confused by the handler, because I didn’t understand the purpose of the capital letter Z, but a little Google research explained that. My modified script is:

use framework "Foundation"
use scripting additions

on main()
	set theFiles to (choose file with multiple selections allowed)
	set ATID to AppleScript's text item delimiters
	
	repeat with aFile in theFiles
		set contents of aFile to (quoted form of POSIX path of aFile) & space
	end repeat
	
	set rawFileData to (do shell script "mdls -raw -name kMDItemFSName -name kMDItemDateAdded " & theFiles)
	set AppleScript's text item delimiters to {character id 0}
	set rawFileData to text items of rawFileData
	
	set fileData to {}
	repeat with i from 1 to (count rawFileData) by 2 -- change to reflect data item count
		set theDate to getLocalDate(item i of rawFileData)
		set end of fileData to {item (i + 1) of rawFileData, theDate} -- also corrected
	end repeat
	
	set AppleScript's text item delimiters to ATID
	return fileData
end main

on getLocalDate(dateString)
	set theFormatter to current application's NSDateFormatter's new()
	theFormatter's setDateFormat:"yyyy-MM-dd' 'HH:mm:ss Z"
	set theDate to (theFormatter's dateFromString:dateString)
	if theDate = missing value then return "No Date"
	return theDate as date
end getLocalDate

set theFileData to main()

Nigel. The time to GMT command is one of many date issues that had me confused. Based on Shane’s statement in the following thread, it was my impression that time to GMT took into account daylight savings time:

https://macscripter.net/viewtopic.php?id=41117

However, based on an example in the AppleScript Language Guide under the heading “time to GMT”, I concluded that was not the case:

https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_cmds.html#//apple_ref/doc/uid/TP40000983-CH216-DontLinkElementID_827

So, it was my understanding that time to GMT would always be the same for a particular time zone regardless of daylight savings time. I now understand that I misread the example and your point makes absolute sense. Thanks for the information.