Remove all directories with S(number)?

I’m stuck and after searching can’t find a solution. Hoping you all could help.

I am writing a script to delete user directories after the school year. All user directories (example below) start with an s and then have a a bunch of numbers after them. The user directories will very with each machine.

But as you see I also have directories that start with an s that I don’t want to be deleted (supervisor for example).

s97150
s97208
2014 s97594
s97754
s98273
s98751
s99715
supervisor

I wrote this to remove them"

if answer is equal to “Delete Student User Directories” then
do shell script “rm -rf /users/S0*” with administrator privileges
do shell script “rm -rf /users/S1*” with administrator privileges
do shell script “rm -rf /users/S2*” with administrator privileges
do shell script “rm -rf /users/S3*” with administrator privileges
do shell script “rm -rf /users/S4*” with administrator privileges
do shell script “rm -rf /users/S5*” with administrator privileges
do shell script “rm -rf /users/S6*” with administrator privileges
do shell script “rm -rf /users/S7*” with administrator privileges
do shell script “rm -rf /users/S8*” with administrator privileges
do shell script “rm -rf /users/S9*” with administrator privileges
tell application “Finder” to empty with security
end if

The problem is, on machines with not that many directories the script works great, but on some machines the directories are HUGE and my script times out before they are all moved to the trash.

What line of code can I use in my script to only move to the trash directories that only start with s and have a number after the s and ignore all other directories?

Thanks for any help you can provide.

Thanks!

Hi. This pattern should get directories only at the User folder level that end with s and 5 or more numbers. A shell find for directories can unintentionally capture packages and other undesirable objects, however, I think that this particular usage is focused enough to avoid that problem. The first code snippet is innocuous, but I advise that you test it carefully and proceed with caution before appending the dangerous deletion option.

do shell script "find -E " & (path to users folder)'s POSIX path's quoted form & " -maxdepth 1 -type d  -regex '.*//s([[:digit:]]{5,})' "

[format]… -regex ‘.*//s([[:digit:]]{5,})’ -delete" with administrator privileges[/format]

Here are two scripts.

I wrote the first one but guessed that it was not the best answer so I posted it to Shane STANLEY which returned - what a surprise - an enhanced version.

CAUTION I tested them upon standard folders with no problem of permissions.

script 1

(*
Tested with El Capitan
Delete every subfolders of the passed folder whose name starts with the letter "s" and a digit.

I guess that it's not the faster one but it works.
*)


use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on deleteSomeFolders:folderPath
	set theURL to current application's class "NSURL"'s fileURLWithPath:folderPath
	set fileManager to current application's NSFileManager's defaultManager()
	set keysToRequest to {current application's NSURLIsPackageKey, current application's NSURLIsDirectoryKey}
	set theOptions to (current application's NSDirectoryEnumerationSkipsPackageDescendants as integer) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
	set theEnumerator to fileManager's enumeratorAtURL:theURL includingPropertiesForKeys:keysToRequest options:theOptions errorHandler:(missing value)
	set theArray to theEnumerator's allObjects()
	repeat with i from 1 to count of theArray
		set aURL to item i of theArray
		set {theResult, isDirectory} to (aURL's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
		if isDirectory as boolean then
			set {theResult, isPackage} to (aURL's getResourceValue:(reference) forKey:(current application's NSURLIsPackageKey) |error|:(missing value))
			if isPackage as boolean then
				-- it's a package
			else
				-- It's a folder, check if its name starts with "s" and a digit
				set folderName to aURL's lastPathComponent()
				set maybe to (its replaceThis:"(s[1-9])" inString:folderName usingThis:"")
				set maybe to (current application's NSString's stringWithString:maybe)
				if (folderName's |length|()) = (maybe's |length|()) + 2 then
					-- folderName starts with "s" and a digit, must delete this folder
					set theResult to (fileManager's removeItemAtURL:aURL |error|:(missing value))
				end if
			end if
		end if
	end repeat
end deleteSomeFolders:

on replaceThis:thePattern inString:theString usingThis:theTemplate
	set theNSString to current application's NSString's stringWithString:theString
	set theOptions to (current application's NSRegularExpressionDotMatchesLineSeparators as integer) + (current application's NSRegularExpressionAnchorsMatchLines as integer)
	set theRegEx to current application's NSRegularExpression's regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
	set theResult to theRegEx's stringByReplacingMatchesInString:theNSString options:0 range:{location:0, |length|:theNSString's |length|()} withTemplate:theTemplate
	return theResult as text
end replaceThis:inString:usingThis:

#=====

set thePath to POSIX path of ((path to desktop as text) & "Tester")
its deleteSomeFolders:thePath

script 2 due to Shane STANLEY

(*
tested with El Capitan
Delete every subfolders of the passed folder whose name starts with the letter "s" and a digit.

Code enhanced by Shane STANLEY.
*)


use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on deleteSomeFolders:folderPath
	set theURL to current application's class "NSURL"'s fileURLWithPath:folderPath
	set fileManager to current application's NSFileManager's defaultManager()
	set keysToRequest to {current application's NSURLIsPackageKey, current application's NSURLIsDirectoryKey}
	set theOptions to (current application's NSDirectoryEnumerationSkipsPackageDescendants as integer) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
	set theEnumerator to fileManager's enumeratorAtURL:theURL includingPropertiesForKeys:keysToRequest options:theOptions errorHandler:(missing value)
	set theArray to theEnumerator's allObjects()
	set thePredicate to current application's NSPredicate's predicateWithFormat:"lastPathComponent MATCHES %@" argumentArray:{"^s[0-9].+"}
	set theArray to theArray's filteredArrayUsingPredicate:thePredicate
	repeat with i from 1 to count of theArray
		set aURL to item i of theArray
		set {theResult, isDirectory} to (aURL's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
		if isDirectory as boolean then
			set {theResult, isPackage} to (aURL's getResourceValue:(reference) forKey:(current application's NSURLIsPackageKey) |error|:(missing value))
			if isPackage as boolean then
				-- it's a package
			else
				-- It's a folder
				set theResult to (fileManager's removeItemAtURL:aURL |error|:(missing value))
			end if
		end if
	end repeat
end deleteSomeFolders:

#=====

set thePath to POSIX path of ((path to desktop as text) & "Tester")
its deleteSomeFolders:thePath

Here is an edited copy of the events log in Shane’s ASObjC Explorer 4.
You will see how it treat the different cases when asked to delete a folder.
[format] { (NSArray)
1 {(NSURL) file:///Users/ user account/Desktop/tester/dossier sans titre/s6dossier sans titre/,
2 (NSURL) file:///Users/ user account/Desktop/tester/dossier sans titre/s6dossier sans titre/s3dossier sans titre/,
3 (NSURL) file:///Users/ user account/Desktop/tester/dossier sans titre/s6dossier sans titre/s3dossier sans titre/s8dossier sans titre/,
4 (NSURL) file:///Users/ user account/Desktop/tester/dossier sans titre/s9dossier sans titre/,
5 (NSURL) file:///Users/ user account/Desktop/tester/s1dossier sans titre - copie/}

16:38:16,457 [22] repeat with i from 1 to count of theArray
16:38:16,457 [23] set aURL to item 1 of theArray
→ 1 (NSURL) file:///Users/ user account/Desktop/tester/dossier sans titre/s6dossier sans titre/
16:38:16,460 [31] set theResult to (fileManager’s removeItemAtURL:aURL |error|:(missing value))
→ true – successful removal
16:38:16,461 [23] set aURL to item 2 of theArray
→ 2 (NSURL) file:///Users/ user account/Desktop/tester/dossier sans titre/s6dossier sans titre/s3dossier sans titre/
16:38:16,463 [31] set theResult to (fileManager’s removeItemAtURL:aURL |error|:(missing value))
→ false – removal failed, the folder was removed with item 1
16:38:16,464 [23] set aURL to item 3 of theArray
→ 3 (NSURL) file:///Users/ user account/Desktop/tester/dossier sans titre/s6dossier sans titre/s3dossier sans titre/s8dossier sans titre/
16:38:16,467 [31] set theResult to (fileManager’s removeItemAtURL:aURL |error|:(missing value))
→ false – removal failed, the folder was removed with item 1
16:38:16,467 [23] set aURL to item 4 of theArray
→ 4 (NSURL) file:///Users/ user account/Desktop/tester/dossier sans titre/s9dossier sans titre/
16:38:16,470 [31] set theResult to (fileManager’s removeItemAtURL:aURL |error|:(missing value))
→ true – successful removal
16:38:16,472 [23] set aURL to item 5 of theArray
→ 5 (NSURL) file:///Users/ user account/Desktop/tester/s1dossier sans titre - copie/
16:38:16,475 [31] set theResult to (fileManager’s removeItemAtURL:aURL |error|:(missing value))
→ true – successful removal[/format]

As I wrote at the beginning of both scripts, I tested them under El Capitan.
I’m not sure that they work under Yosemite but I left the instruction :
use AppleScript version “2.4”
so that you may test them under Yosemite as is.
Using the instruction : use AppleScript version “2.5” would require El Capitan

Yvan KOENIG running El Capitan 10.11.5 in French (VALLAURIS, France) vendredi 10 juin 2016 17:17:43