Recursively Find last modified file

This should list 10 files of your documents folder sorted by modification date. However, it does not seem to produce the correct results. Any ideas?

set folderPath to POSIX path of (path to documents folder)
if folderPath ends with "/" then set folderPath to text 1 thru -2 of folderPath

set latestFile to paragraphs of (do shell script "find " & quoted form of folderPath & " \\! -name \".*\" -type f -print0 | xargs -0 ls -t | head -n 10")

For Example:

Hello.

The way I reckon, you’ll ever have to sort afterwords, since you are getting an item at a time via find, or do it another way, I chose the different path.

Getting a long listing of the folder sorted by modifcation date, grepping away directories, getting 10 last entries with head, coalescing spaces with tr, before I cut the filenames with cut, using a space as field delimiter.

ls -ltc |grep -v "^d" |head -10 |tr -s ' ' |cut -d ' ' -f9

If you want to make this recursively, you’ll of course just add the -R parameter to the ls command.

That still does not seem to include the correct last modified files

There are folder within the documents folder that contain newer files than those listed in the output.

I have only tested it for a directory, and that seems to work for me.

Maybe you’ll have to sort the result if you get a recursive listing?

Here I sort the listing afterwards by the year, month and day

 ls -Rltc |egrep -v "(^d|^$|^[[:alpha:]])" |tr -s ' ' |sort -k7 -k5M -k6 |head −10

I hope this works.

Test it on your documents folder and tell me if it works there.

The above seems to work for me. :slight_smile:

Edit, actually, this doesn’t work that good, because not all files are having a year. Those files on the other hand are having a time stamp.

I can’t follow this right now, but will be back later with something, involving find, and accessed within the last days.

If you use find like that, then tr -s to compact the spaces, the sort command should work all right. :slight_smile:

Hello.

This does the trick for me, but I set a limit for the last days the files must be modified within, so if you set -mtime 30d and haven’t modifed 10 files since the last 30 days, then you’ll obviously get back less than 10 files.

It should work in january too. :slight_smile:

 find . -mtime -10 -type f -exec ls -ltc {} \; |head -11 |grep -v DS_Store |tr -s ' ' | cut -d ' ' -f9

You’ll have to sort the output of the find command.

Hello.

Ok, this doesn’t do spaces in filenames, and should work correctly, with regards to sorting by dates descending. The name is the last field of the filename, I have taken height that you may have up to 5 spaces in the filenames by cutting the 9’th to the 15’th field.

find . -mtime -10 -type f -exec ls -ltc {} \; |grep -v DS_Store |tr -s ' ' |sort -t ' ' -k6rM -k7rn -k8rn |head -10 |cut -d ' ' -f 9-15

Edited

As I wrote several times, I’m not at ease with terminal so I tried to answer using ASObjC Runner.


set target to (path to documents folder as text) & "tempo:"
tell application "ASObjC Runner"
	set longList to enumerate folder target modified before {false, (current date) - 90 * days} with recursion
	
	set pathsAndDates to {}
	repeat with aFile in longList
		set end of pathsAndDates to (about file aFile include only {"POSIX path", "modification date"})
	end repeat
	set begOfList to rearrange records pathsAndDates by keys "modification date" without ascending orders
end tell

if count begOfList > 10 then set begOfList to items 1 thru 10 of begOfList

Here I got :

{{name:" ebay", modification date:date “dimanche 3 février 2013 18:42:34”, POSIX path:“/Users/yvankoenig/Documents/tempo/ ebay”}, {name:" 2011-11-17-ebay 1.png", modification date:date “dimanche 3 février 2013 18:42:07”, POSIX path:“/Users/yvankoenig/Documents/tempo/ ebay/ 2011-11-17-ebay 1.png”}, {name:“pour Luther.pdf”, modification date:date “samedi 19 janvier 2013 16:15:52”, POSIX path:“/Users/yvankoenig/Documents/tempo/ ebay/pour Luther.pdf”}, {name:" pour Seed", modification date:date “vendredi 25 janvier 2013 12:16:26”, POSIX path:“/Users/yvankoenig/Documents/tempo/ pour Seed”}, {name:“2013-01-09T12.23.02.png”, modification date:date “mercredi 9 janvier 2013 12:23:14”, POSIX path:“/Users/yvankoenig/Documents/tempo/ pour Seed/2013-01-09T12.23.02.png”}, {name:“2013-01-25-iMac.spx”, modification date:date “vendredi 25 janvier 2013 11:37:32”, POSIX path:“/Users/yvankoenig/Documents/tempo/ pour Seed/2013-01-25-iMac.spx”}, {name:“2013-01-25T11.22.35.png”, modification date:date “vendredi 25 janvier 2013 11:22:46”, POSIX path:“/Users/yvankoenig/Documents/tempo/ pour Seed/2013-01-25T11.22.35.png”}, {name:“2013-01-25T11.23.45.png”, modification date:date “vendredi 25 janvier 2013 11:23:52”, POSIX path:“/Users/yvankoenig/Documents/tempo/ pour Seed/2013-01-25T11.23.45.png”}, {name:“2013-01-25T11.24.19.png”, modification date:date “vendredi 25 janvier 2013 11:24:25”, POSIX path:“/Users/yvankoenig/Documents/tempo/ pour Seed/2013-01-25T11.24.19.png”}, {name:“2013-01-25T11.24.30.png”, modification date:date “vendredi 25 janvier 2013 11:24:37”, POSIX path:“/Users/yvankoenig/Documents/tempo/ pour Seed/2013-01-25T11.24.30.png”}}

I let you extracting what is relevant for you from the begOfList value.

Yvan KOENIG (VALLAURIS, France) samedi 30 mars 2013 17:31:35

Thanks Yvan,

For some reason the recursion in that is producing the same results as my original script, which is incorrect.

I finally got it…


set folderPath to POSIX path of (path to documents folder)
if folderPath ends with "/" and folderPath is not "/" then set folderPath to text 1 thru -2 of folderPath

set lastModPath to paragraphs of (do shell script "find " & quoted form of folderPath & " -type f -flags nohidden -exec stat -f \"%Sm - %N\" -t \"%Y-%m-%d %H:%M:%S\" {} + | sort -r | grep -om10 '/.*' ;")

You’re right.

It appears that the instruction using rearrange records doesn’t achieve what it’s supposed to do.

I sent the script to Shane Stanley because I don’t understand what is wrong in the script.

Yvan KOENIG (VALLAURIS, France) samedi 30 mars 2013 21:53:37

Hello.

Here is my take, I don’t work on the Documents folder as that would be too much, but seeing the last modified files in the projects folder can be useful. :slight_smile:

set pxpth to POSIX path of ((path to documents folder as text) & "Projects" as alias)

do shell script "cd " & pxpth & "; (echo '
10 last files modfied within last week in Project folder.

' ; find . -mtime -7d -type f -flags nohidden -exec /usr/bin/stat -f '%Sm - %N' -t '%Y-%m-%d %H:%M:%S' {} \\; | sort -r |head -10 |cut -d ' ' -f 4 | sed  's_^\\._'$PWD'_g' ) |open -f"

Yvan,

Here’s the working script:

set target to (path to documents folder as text) & "tempo:"
tell application "ASObjC Runner"
	set longList to enumerate folder target modified before {false, (current date) - 90 * days} with recursion
	set pathsAndDates to (about file longList include only {"POSIX path", "modification date"})
	set begOfList to rearrange records pathsAndDates by keys {"«asmo»"} without ascending orders -- asmo = modification date
	set fileList to value for label "«posx»" in records begOfList -- posx = POSIX path
	if length of fileList > 10 then set fileList to items 1 thru 10 of fileList
end tell

The problems is that AS records are not real records, in that they store values where the label is an AS term differently to values where the label is a variable, and getting at the former is tricky. The workaround is to use the four-letter codes, as above.

If anyone is interested, this command was for a service I wrote to reveal the latest file. You can map it to a Keyboard Shortcut to quickly reveal files on your Desktop, Downloads etc. I have wrapped it in the proper handlers for ThisService http://wafflesoftware.net/thisservice/.

Enjoy!


property findRecursive : true

on run
	process()
end run

on process()
	try
		set currentFolder to findFolder()
		revealRecent(currentFolder, findRecursive)
	on error errMsg number errNum
		tell application "SystemUIServer"
			activate
			display alert errMsg & return & return & "Error number" & errNum buttons "Cancel" cancel button "Cancel"
		end tell
	end try
end process

---------------------- Handlers ----------------------
on findFolder()
	tell application "Finder"
		set mySelection to (get selection)
		if mySelection ≠ {} then
			set mySelection to first item of mySelection
			if mySelection's class = alias file then set mySelection to original item of mySelection
			if mySelection's class = folder then
				set currentFolder to mySelection
			else if mySelection's class = document file then
				set currentFolder to parent of mySelection
			end if
		else
			try
				set currentFolder to target of front Finder window
			on error
				set currentFolder to desktop
			end try
		end if
	end tell
	return (currentFolder as text)
end findFolder

on revealRecent(folderPath, recursive)
	set folderPath to POSIX path of folderPath
	set findOption to space
	if not recursive then set findOption to " -maxdepth 1 "
	if folderPath ends with "/" and folderPath is not "/" then set folderPath to text 1 thru -2 of folderPath
	try
		set latestFile to (do shell script "find " & quoted form of folderPath & findOption & "-type f -flags nohidden \\! -name \".*\" -exec stat -f \"%Sm - %N\" -t \"%Y-%m-%d %H:%M:%S\" {} + | sort -r | grep -om1 '/.*' ;")
	on error -- If there are no files within the folder
		set latestFile to (do shell script "find " & quoted form of folderPath & findOption & "-flags nohidden \\! -name \".*\" -exec stat -f \"%Sm - %N\" -t \"%Y-%m-%d %H:%M:%S\" {} + | sort -r | grep -om1 '/.*' ;")
	end try
	
	tell application "Finder"
		reveal (POSIX file latestFile) as alias
		activate
	end tell
end revealRecent

That is a nice both idea and implementation

I’d expand the number of entries with files in BBEdit to 100. The I leverage upon the command-L shortcut in BBEdit to select a line, and command-D to open the path specified in a file. I don’t think this is perfect, should the file be binary, but at least it should work equally well with TextWrangler:

[applescriptset pxpth to POSIX path of ((path to documents folder as text) & “Projects” as alias)

do shell script "cd " & pxpth & "; (echo ’
100 last files modfied within last week in Project folder.

’ ; find . -mtime -7d -type f -flags nohidden -exec /usr/bin/stat -f ‘%Sm - %N’ -t ‘%Y-%m-%d %H:%M:%S’ {} \; | sort -r |head -100 |cut -d ’ ’ -f 4 | sed ‘s_^\._’$PWD’_g’ ) |open -a "BBEdit" -f "



[b]Edit[/b]
With the TextEdit version, I could selected a file with cursor keys in the Document, activate Quicksilver and use  [b]commmand-G[/b] for getting selection, then I could type some keystrokes for a command. I think my version of BBEdit is too old for this to work. But it doesn't work with the latest version of TextWrangler neither. :|



[b]Edit++[/b]
Selecting a line in TextEdit is as easy as [b]ctrl+A[/b] and then [b]ctrl+shift+e[/b], (and I couldn't make that service take a shortcut key anyway, as there wasn't any marked text for the service to begin with I guess.

This is a service, that takes marked text from TextEdit, which I have installed on [b]command-D[/b]


on run {input, parameters}

do shell script "open " & quoted form of (input as text)

end run



This is just another approach to [b][color=#004080]adyazdone's[/color][/b] functionality.

same result without any coercion

set pxpth to POSIX path of (path to documents folder) & "Projects"

Hopefully it sticks, this time. :wink: Less typing is often better.

Edit

I can’t make that work on Snow Leopard, in Script Debugger 4.5.7. So I have to use it as it stands.

Thanks for posting the answer here so that everybody may read your explanation.

Reading your code I learnt a complementary info.

if count fileList > 10
compiles but fail at execution. I’m the culprit because I typed the instruction directly in the message and forgot the needed parenthesis.
if (count fileList) > 10
works flawlessly.
I don’t remember who but somedy told me, here or in applescript-users@lists.apple.com, that there was no need to write
if count of fileList
but using this syntax if fine because
if count of fileList > 10
compiles automatically as
if (count of fileList) > 10
which is executed flawlessly.

Your wording :
if length of fileList > 10
compiles and works flawlessly.

Yvan KOENIG (VALLAURIS, France) dimanche 31 mars 2013 10:43:07

PS :
As everybody may check, the posted code is fair enough which doesn’t return the .DS Store files.