Hello. This is under construction
Here is one that seeks to do it all, files and folders, with some kind of syntax to it, it doesn’t handle searching of files by uti’s nor by default apps, or more esoteric searches, like by image sizes.
Should you make such a specialized fileList, don’t hesitate to upload it.
# © McUsr and put in public Domain, you may not post this stand alone elsewhere, nor put it in a publically
# accessible repository
# Please refer to this link: http://macscripter.net/edit.php?id=157655
-- fileList
-- =======
-- Example call:
---------------
-- set the flist to fileList({sTerm:".*", spath:theFolder, sType:"both", sPred:"re", sExt:{""}, sDepth:2,
-- sWithInvisibles:true})
-- Properties of R the parameter for filelist of type record:
-- ==========================================================
-- sTerm: type string: MANDATORY
--------------------------------
-- The searchterm you are looking for, an empty search term will be interpreted as "*" (all files).
-- When it comes to specifying search terms the new type of regexp are allowed, so you can use
-- terms like "expenses second quarter 200\(4|5|6\).*" or "expenses second quarter [[.201.]]\(0|1|2\).*"
-- See man grep under the -E option and much better man re_format(7).
-- NOTE! To specify any with those kind of regexp you'll have to specify '.*' where you otherwise would have
-- specified '*'
-- sPath: type string: MANDATORY
-- The searchterm is a posix path or hfs path (hierchial file sysem path) to a directory that must exist,
-- it can end with "/" or ":" or not.
-- sType: type string
---------------------
-- What to search for: "file","folder" or "both". Optional, "file" is the default value.
-- sDepth: type integer
-----------------------
-- The depth of the search. Optional; defaults to 1.
-- 1 specifies that the search is just to be performed in the given directory,
-- just a positive number gives the number of levels to search, or the levels up that number.
-- ( sed 'd' for større nivåer )
-- (-1) is the full subtree below the given directory, all levels.
-- sPred: type string
---------------------
-- The search predicate, specifies how the handler will interpret and use the searchTerm.
-- Optional; defaults to "regexp".
-- If there are no extension given, then the searchterm will specify the full pattern to search
-- for. Legal values:
-- "starts with": Matches files/folders that starts with the search term.
-- "ends with": Matches files/folders that ends with the search term, it is not smart in the
-- sense that it will not match up to an extension, if none are given, if this is
-- what you want, then you'd specify an sExt of "". This is not default, as
-- some like the mother, other prefers the daughter! Example:
-- if your specify ends with, and the filename is hackerne.ws and you search for ws,
-- without an extension, then you will miss this file.
-- "Contains": Matches files/folders that contains the searchterm somewhere (see Ends with.)
-- "Exact": Exact match.
-- "Regexp": The whole regexp is solely provided by the user, either with or without sExt,
-- but considering it if it is there. if you want all files, then don't specify
-- the sExt, set sPred to "regexp" and sTerm to "" or "*"
-- sExt: type list
------------------
-- The search extension, specifies which extension the file/folder list will be filtered against.
-- It works in conjunction with sTerm, it takes a list of file extensions, *spelled fully out*.
-- Example: {"xls","xlsm","xlsx","xlsb"} is a valid list of extensions{"xls[bmx]"} is discouraged
-- but it works.
-- Optional parameter, default value {"*"} which means that any extension is allowed, but you must
-- specify and extension of {""} to make sure that nothing will be interpreted as extensions though.
-- An empty extension is not allowed when more than one extension is given.
-- sWithInvisibles: type boolean
-------------------------
-- If invisible files are to be included or not. Optional, defaults to not include invisible files.
-- Returns a file list:
-- ====================
-- The file list will be returned in the format the search directory was given, posix path, or hfs.
to fileList(R)
# preliminary checks of MANDATORY parameters
local searchTerm, pathtype, tids, searchPath, hfsPattern, homePosixPath, DeepPath, searchType, searchPredicate, searchExtensions, searchWithInvisibles, searchDepth, findResult
script common
on initialParameterCheck()
set tids to AppleScript's text item delimiters
try
set searchTerm to sTerm of R
on error
error "fileList: Mandatory parameter \"sTerm\" missing!"
end try
try
set searchPath to spath of R
on error
error "fileList: Mandatory parameter \"sPath\" missing!"
end try
end initialParameterCheck
on determinePathType()
# We "fix" the given path to the folder we are using for our exploration!
if ":" is in searchPath then
# We figure out what kind of path it is. Eventually converting it to posix.
set pathtype to "hfs"
if text -1 of searchPath is not ":" then set searchPath to searchPath & ":"
set hfsPattern to searchPath # save for later!
set AppleScript's text item delimiters to ":"
set searchPath to text items of searchPath
set AppleScript's text item delimiters to "/"
set searchPath to "/" & text items 2 thru -1 of searchPath as text
set AppleScript's text item delimiters to tids
else if "/" is in searchPath or "~" is in searchPath then
set pathtype to "posix"
if text -1 of searchPath is not "/" then set searchPath to searchPath & "/"
else
error "fileList: The parameter \"sPath\" is invalid"
end if
end determinePathType
on tildeExpand()
# we perform tilde expansion:
if "~" is in searchPath then
set AppleScript's text item delimiters to "~"
set searchPath to text items of searchPath
set AppleScript's text item delimiters to homePosixPath
set searchPath to searchPath as text
set AppleScript's text item delimiters to tids
end if
end tildeExpand
on assertSearchPath()
# It is time to check if the path to the searchfolder indeed exists!
# when you use this handler interactively then you'd use something like this:
# choose folder. (posix path of theFolder as text for instance) **TODO documentation.
try
local probe
set probe to POSIX file searchPath as alias
on error
error "fileList: the \"sPath\" does not exist!"
end try
end assertSearchPath
on determineifPathIsDeep()
if ((length of searchPath) - 1) ≤ length of homePosixPath then
set DeepPath to true
else
set DeepPath to false
end if
end determineifPathIsDeep
on setDefaultValuesForMissingParameters()
set R to R & {sType:"file", sDepth:1, sPred:"regexp", sExt:{"*"}, sWithInvisibles:false}
end setDefaultValuesForMissingParameters
on setAndCheckParameterValues()
set {searchType, searchPredicate, searchExtensions, searchWithInvisibles} to {sType of R, sPred of R, sExt of R, sWithInvisibles of R}
# Prelimnary tests of user supplied parameters to the handler:
if searchType is not in {"file", "folder", "both"} then error "fileList: typo in \"sType\"!"
if searchPredicate is not in {"contains", "begins", "begins with", "ends", "ends with", "exact", "re", "regexp"} then error "fileList: typo in \"sPred\"!"
if searchTerm = "" then set searchTerm to "*" # so we have something TODO maybe remove! Isn't common to both cases.
if ("^" is in searchTerm or "$" is in searchTerm or "." is in searchTerm) and (searchPredicate is not "regexp" and searchPredicate is not "re") then error "fileList: illegal characters in \"sTerm\"!"
if class of searchExtensions is not list then error "fileList: \"sExt\" must be a list!"
set searchDepth to sDepth of R as number
end setAndCheckParameterValues
end script
common's initialParameterCheck()
common's determinePathType()
set homePosixPath to text 1 thru -2 of POSIX path of (path to home folder)
common's tildeExpand() # if we were given a posix path, error otherwise. hvis det startet med tilde men brukernavn etter?
common's assertSearchPath()
# if the path is deep then we'd better use Find than mdfind!
# But we don't know if we can substitute Unix find for mdfind
# before we have seen the Depth parameter, depth > 3 ==> mdfind.
common's determineifPathIsDeep()
# Now that we have the essentials, we have to look over our options
# and set defaults where parameters are amiss for starters!
common's setDefaultValuesForMissingParameters()
# All necessary parameters are now set, to default values if not specifed, it is time
# to analyze the query and "compile" the query.
common's setAndCheckParameterValues()
# we also analyze the search with regards to depth, and chooses the "right tool" for the job of creating
# the filelist.
if searchDepth ≤ 3 and DeepPath = true then # We leverage upon Unix find for finding the files.
# The finder commandline consists of several parts. (In order of appearance in the "compiled" commandline:)
# head: the find command , and maybe -E for enhanced regexp, dependent on suffix
# searchPath: No dependencies
# wayToSearch: By name, or regexp, dependent on both sPredicate and sExt(ension(s))
# baseNamePart: dependant on subclauses invisibles, and sExt
# findSearchExt: No depencies
# searchPattern: Depenent on baseNamePart and findSearchExt
# fileType dependant on searchType
# redirection of stderr
# we'll also throw an error and show an error message if the pattern or something wasn't valid.
local fileType
if searchType = "file" then
set fileType to " -type f"
else if searchType = "folder" then
set fileType to " -type d"
else # "both"
set fileType to " -type f -o -type d"
end if
# compile the Base name.
local invisibleClause
if searchWithInvisibles is true then
set invisibleClause to "'^\\.\\{0,1\\}" # testes!
else
set invisibleClause to "'^"
end if
local baseName, usesRegexp
if searchWithInvisibles = true then
set usesRegexp to true
else
set usesRegexp to false
end if
if searchPredicate is "contains" then
set usesRegexp to true
if searchTerm is not "*" then
set baseName to invisibleClause & ".*" & searchTerm & ".*"
else
set baseName to invisibleClause & ".*"
end if
else if searchPredicate is "begins with" or searchPredicate is "begins" then
set usesRegexp to true
if searchTerm is not "*" then
set baseName to invisibleClause & searchTerm & ".*"
else
set baseName to invisibleClause & ".*"
end if
else if searchPredicate is "ends with" or searchPredicate is "ends" then
set usesRegexp to true
if searchTerm is not "*" then
set baseName to invisibleClause & ".*" & searchTerm
else
set baseName to invisibleClause & ".*"
end if
else if searchPredicate is "exact" then
if searchTerm does not contain "*" then
set baseName to invisibleClause & searchTerm
else
error "listFiles: * is not a valid specifier for an exact filename!"
end if
else if searchPredicate is "regexp" or searchPredicate is "re" then
set usesRegexp to true
if text 1 of searchTerm is "'" then set searchTerm to text 2 thru -1 of searchTerm
if text -1 of searchTerm is "'" then set searchTerm to text 1 thru -2 of searchTerm
if text 1 of searchTerm is "^" then set searchTerm to text 2 thru -1 of searchTerm
if text -1 of searchTerm is "$" then set searchTerm to text 1 thru -2 of searchTerm
# precautions.
set baseName to invisibleClause & searchTerm
end if
# todo: check out hvordan går med quotes og name some name specifier.
# todo: checks for file-ext here, up front. since we should really know this before we
local singleExt, noExt, searchPattern
set {noExt, searchPattern} to {false, ""}
if length of searchExtensions > 1 then
local firstExt
set {singleExt, firstExt, usesRegexp} to {false, false, true}
repeat with thisExt in searchExtensions
if "." is in contents of thisExt then
error "fileList: literal dots are not allowed in the \"sExt\"'s!"
else if contents of thisExt = "" then
error "fileList: empty extension in the \"sExt\" is not allowed when more than one!"
else
if firstExt = true then
set firstExt to false
set searchPattern to searchPattern & baseName & "\\." & thisExt
else
set searchPattern to searchPattern & "|" & baseName & "\\." & thisExt
end if
end if
# todo : here do we compile the searchExt
end repeat
else
set singleExt to true
# just one ext
set theExt to item 1 of searchExtensions
if theExt is not "" then
if "." is in theExt then error "fileList: literal dots are not allowed in the \"sExt\"'s!"
set searchPattern to baseName & "\\." & thisExt
else
set noExt to true
set searchPattern to baseName
end if
end if
set searchPattern to searchPattern & "'"
# Assembling the command line:
# We have to take the extensions into account here, We'll also have to change the
# simple names if we have to create from shell globs into regexps, and if there is
# more than one, then we'll have to turn on -E for extended regexp's
if (usesRegexp = true and singleExt = false) then
set headOfCommand to "find -E "
else
set headOfCommand to "find "
# no need for enhanced regexp
end if
if searchPredicate = "exact" and singleExt = true then
set wayToSearch to "-name "
else
set wayToSearch to " -iregex "
end if
# -maxdepth...
local depthParameter
set depthParameter to " -maxdepth " & searchDepth
set findResult to (do shell script headOfCommand & (quoted form of searchPath) & wayToSearch & searchPattern & depthParameter & fileType & " 2>/dev/null | sed -n 's_//\\._/_p'")
# END OF UNIX FIND VERSION
else
# we generate the parameters for the content type for the query
local contentType
if searchType = "file" then
set contentType to " && ( kMDItemContentTypeTree == \"public.item\" && kMDItemContentType != \"public.folder\" )"
else if searchType = "folder" then
set contentType to " && ( kMDItemContentType == \"public.folder\" || kMDItemFSSize == 0 )"
else # "both"
set contentType to ""
end if
# The prevalent parameter down the road for generating the searchTerm is the searchExtension.
local singleExt, holdPattern
# precautions to only perform searches that may work.
local holdPattern
if searchPredicate is "contains" then
if searchTerm is not "*" then
set searchTerm to "\"*" & searchTerm & "*"
else
set searchTerm to "\"" & searchTerm
end if
else if searchPredicate is "begins with" or searchPredicate is "begins" then
if searchTerm is not "*" then
set searchTerm to "\"" & searchTerm & "*"
else
set searchTerm to "\"" & searchTerm
end if
else if searchPredicate is "ends with" or searchPredicate is "ends" then
if searchTerm is not "*" then
set searchTerm to "\"*" & searchTerm
else
set searchTerm to "\"" & searchTerm
end if
else if searchPredicate is "exact" then
set searchTerm to "\"" & searchTerm
else if searchPredicate is "regexp" or searchPredicate is "re" then
set holdPattern to searchTerm
set searchTerm to "\"*"
end if
# Invisibles. måten vi gjør dette på er at vi hvis vi har med invisibles, så legger vi dette til patternet.
# på en slik måte at vi får med begge deler.
local itemNameSpec, singleExt # is where the string is stored to be fed to mdfind for the name pattern.
if length of searchExtensions > 1 then
set singleExt to false
set itemNameSpec to " '( "
repeat with thisExt in searchExtensions
if "." is in contents of thisExt then
error "fileList: literal dots are not allowed in the \"sExt\"'s!"
else if contents of thisExt = "" then
error "fileList: empty extension in the \"sExt\" is not allowed when more than one!"
else
set itemNameSpec to itemNameSpec & "kMDItemFSName == " & searchTerm & "." & thisExt & "\" || "
end if
end repeat
set itemNameSpec to text 1 thru -4 of itemNameSpec & " ) "
else
set singleExt to true
# just one ext
set theExt to item 1 of searchExtensions
if theExt is not "" then
if "." is in theExt then error "fileList: literal dots are not allowed in the \"sExt\"'s!"
set itemNameSpec to "'kMDItemFSName == " & searchTerm & "." & theExt & "\" "
else
set itemNameSpec to "'kMDItemFSName == " & searchTerm & "\" "
end if
end if
# adds kdmiItem for invisible, so that invisible is included!
local invisibleClause
if searchWithInvisibles is true then
set invisbleClause to " && ( kMDItemFSInvisible == '1' || kMDItemFSInvisible == '0' )'"
else
set invisibleClause to "'"
end if
# We are now done setting up the the different parts of the search we will feed mdfind with.
local mdfindParameter, mdfindResult
set mdfindParameter to itemNameSpec & contentType & invisbleClause
# try
set mdfindResult to (do shell script "mdfind -onlyin " & (quoted form of searchPath) & " " & mdfindParameter without altering line endings)
# end try
if mdfindResult = "" then return null # No match !
# it is time for post processing in the cases that we sent with a reg exp.
local hugeResult, temporaryFile, fref # if we get a really big result, we better store the result to disk, and work with it from a file.
set bufferLen to length of mdfindResult
set maxBufferLen to ((do shell script "getconf ARG_MAX") as number) - 10000
if bufferLen > maxBufferLen then # 252144 Bytes, my fairly small free argspace - 1000 by getconf ARG_MAX
set hugeResult to true
try
set temporaryFile to (do shell script "export TMPFILE=`mktemp /tmp/fileList.XXXXXX` && touch $TMPFILE && echo $TMPFILE")
on error
error "listFiles: I cant make a temporry file, quitting!"
end try
try
set fref to (open for access POSIX file temporaryFile with write permission)
on error e number n
error "listFiles: I can't seem to open the temporary file : \"" & temporaryFile & "\" " & e & " " & n
end try
try
write mdfindResult as «class utf8» to fref starting at 0
on error e number n
error "listFiles: I can't seem to write to the temporary file : \"" & temporaryFile & "\" " & e & " " & n
end try
try
close access fref
on error
close access fref
end try
else
set hugeResult to false
end if
if searchPredicate is "regexp" or searchPredicate is "re" then
if hugeResult is true then
# it is really bes to work "infile" from now on, and it may even blow up in our face when we are done!
try
do shell script "sed -n -i '' '/" & holdPattern & "/p' " & temporaryFile
# set mdfindResult to (do shell script "sed -n '/" & holdPattern & "/p' " & temporaryFile without altering line endings)
on error e number n
error "fileList: malformed regexp: " & e & " " & n
end try
else
try
set mdfindResult to (do shell script "sed -n '/" & holdPattern & "/p'<<<" & quoted form of mdfindResult without altering line endings)
on error e number n
error "fileList: malformed regexp: " & e & " " & n
end try
end if
end if
# posprocessing for mdfind unless the depth is -1, we must process it.
if searchDepth is not -1 then
# we'll have to escape the slashes in thefile name to make it work with sed.
set AppleScript's text item delimiters to "/"
set picketFence to text items of searchPath
set AppleScript's text item delimiters to "\\/"
set picketFence to picketFence as text
set AppleScript's text item delimiters to tids
#if we are searching for folders or both we'll first of all have to increase the depth, or adjust the patterns. [/]* could help on the end
# won't get a hit on that when searches files anyways.
if searchDepth is 1 then
# huge result
if hugeResult is true then
set mdfindResult to (do shell script "sed '/" & picketFence & "[^/]*[/][^/]*[/]*/ d' " & temporaryFile without altering line endings)
else
set mdfindResult to (do shell script "sed '/" & picketFence & "[^/]*[/][^/]*[/]*/ d' <<<" & quoted form of mdfindResult without altering line endings)
end if
else
set dirStr to "[^/]*[/]"
# build the string for sed
repeat (searchDepth - 1) times
set dirStr to dirStr & "[^/]*[/]"
end repeat
set dirStr to dirStr & "[^/]*[/]*/ d'"
if hugeResult is true then
set mdfindResult to (do shell script "sed '/" & picketFence & dirStr & " " & temporaryFile without altering line endings)
else
set mdfindResult to (do shell script "sed '/" & picketFence & dirStr & " <<<" & quoted form of mdfindResult without altering line endings)
end if
end if
# this effectively removes any files or folders that are deeper in the tree structure than the specified level, keeping any others.
else if searchDepth < -1 then
error "fileList: illegal value for searchDepth, only -1 (for all levels) are allowed as a negative argument!"
end if
set findResult to mdfindResult
end if
# finally we must do some adjustments if we had hfspath's given initially.
if pathtype = "hfs" then
set AppleScript's text item delimiters to searchPath
set findResult to text items of findResult
set AppleScript's text item delimiters to hfsPattern
set findResult to findResult as text
set AppleScript's text item delimiters to tids
set findResult to (do shell script "tr [/] [:] <<<" & quoted form of findResult without altering line endings)
set findResult to (do shell script "sed '/^$/ d' <<<" & quoted form of findResult)
end if
return paragraphs of findResult
end fileList