"Find" CLI to list all visible files on a disc

Hi all. I’m having trouble quoting this command line into a “do shell script” form to simply list every visible file on an external disk, writing one path per line into a text file, but suppressing any line that begins with a period. Can someone help? Thanks!

This is my latest try, which doesn’t work:

find /Volumes/External HD -not -path '*/\.*' -type f \( ! -iname ".*" \) > ~/Desktop/allfiles-External HD.txt

When I made sure that a command works in Terminal.app I use quoted form of for each path etc.

To see what will be executed by do shell script I use a variable:

set theShellScript to "find " & quoted form of "/Volumes/External HD" & ...

When this variable matches the command that already worked in Terminal.app do:

do shell script theShellScript

Once the command works in AppleScript you could get rid of the variable.

Thanks. Yes, the command works in Terminal, but in an AppleScript it requires a "do shell script " & the CLI command itself, which requires some kind of escaping of characters such as those found in the “‘/.’ -type f ( ! -iname “.*” )” part of the command string.

Do you know how I can properly escape this whole command:

`
find /Volumes/External HD -not -path ‘/.’ -type f ( ! -iname “.*” ) > ~/Desktop/allfiles-External HD.txt.

`

Thanks!

Try This…

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

set cc to "find " & quoted form of "/Volumes/Crucial SSD" & "  -not -path '*/\\.*' -type f \\( ! -iname \".*\" \\) > " & "~/Desktop/allfiles-External\\ HD.txt 2>&1"
do shell script cc

For some reason you cant use 'quoted form of ’ on file output portion of the string. you have to doubele escape the spaces. (i.e. “~/Desktop/allfiles-External\\ HD.txt”)

1 Like

Not sure but I think this is because of the tilde. The tilde can’t be expanded if we provide a path in straight quotes (which is what quoted form of does) as every string in straight quotes is seen as a literal without any change applied.

2 Likes

Thanks, Robert. The first 3 lines of the text file are:

find: /Volumes/Macintosh HD/.DocumentRevisions-V100: Permission denied
find: /Volumes/Macintosh HD/.TemporaryItems: Permission denied
find: /Volumes/Macintosh HD/.Trashes: Permission denied

but otherwise gives me all the full paths of visible files, as requested. Thanks!

BTW, you can also use my program “Find Any File” (shareware, i.e. you can try it out before buy). You can then use the rule “Path doesn’t contain /.” to find all files that do not start with a “.”.

You can wait for the results window to appear, then Save to a file, which will contain all the found paths. Or you add a rule “Pass results to …” (hold down option key to see that rule) where you can either send it directly to a file or to an application, e.g. a script of yours.

Note that that FAF is not scriptable in case you rely on that (I wanted to add AppleScript support for years, but it’s a lot of work).

1 Like

Hi Tempel. I actually own Find Any File because it’s indispensable for finding anything anywhere, but have never explored this functionality. I just tried it on my startup disk. It worked but I couldn’t get it to output one full path per line. Thanks though!

1 Like

Can you elaborate, please? I’m currently working on the next beta and might fix any issues right away.

What worked? I guess you mean the search.

But then using “Pass results to file” didn’t work?

Here’s an example that worked for me:

Screen Shot 2024-02-14 at 00.13.07

And if I make an app with the following AppleScript code

on open of theFiles
	display dialog "got " & (count of theFiles) & " items"
end open

And then change the Find rule into “Pass results to test.app”, then the app will show that it got 100 items.

The OP wants to use the find command, and Robert has supplied that. FWIW, the following is an ASObjC solution. It returns regular files and skips hidden files, packages, and package contents, although it’s easily modified to include these.

use framework "Foundation"
use scripting additions

set theVolume to "/Volumes/Backup 1/" -- set to desired value
set textFile to POSIX path of (path to desktop) & "allfiles-External HD.txt"
writeFiles(theVolume, textFile)

on writeFiles(theVolume, textFile)
	set theVolume to current application's |NSURL|'s fileURLWithPath:theVolume
	set fileManager to current application's NSFileManager's defaultManager()
	set fileKey to current application's NSURLIsRegularFileKey
	set theFiles to (fileManager's enumeratorAtURL:theVolume includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects()'s mutableCopy()
	repeat with i from theFiles's |count|() to 1 by -1
		set {theResult, aRegularFile} to ((theFiles's objectAtIndex:(i - 1))'s getResourceValue:(reference) forKey:fileKey |error|:(missing value))
		if aRegularFile as boolean is false then (theFiles's removeObjectAtIndex:(i - 1))
	end repeat
	set theString to (theFiles's valueForKey:"path")'s componentsJoinedByString:linefeed
	theString's writeToFile:textFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeFiles
1 Like

Hi Tempel: Basically, the find and the Pass Results worked. However, I couldn’t manage to filter things like folder lines and package contents. An Ends With could be useful in addition to the Begins With, but I don’t think it can currently give me the one normal visible file per line output I was seeking. Thanks!

Peavine, your script outputs exactly what I was looking for: one normal visible full file path per line. It’s fast too, taking just a few seconds for around 600,000 files. I’m going to use it to populate Filemaker databases.
Note: I must have googled and tried dozens of scripts, but they all failed or I couldn’t construct the output criteria correctly. I eventually had almost given up and I used my Livecode license to make a little stack, which worked fine. But I think it’s essential to have this script in my repertoire, even if I don’t understand ASObjC! So thanks thanks thanks!

2 Likes

Peavine, I’ve tried your script and is does in fact work perfectly, with one small issue. The output text file does not list in alphabetical order. Any chance that feature can be added?

I see you got your task resolved with Peavine’s help, but I’d still like to make sure that FAF can handle special searches like yours, too.
Would you be willing to help me improve FAF in this regard (I’d like to understand better what didn’t work and make sure you didn’t miss an option that would’ve solved it)? Then please contact me here with a PM.
Thanks!

Sure. Here is an example of the desired output:

/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConBol.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConBolIt.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConBoo.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConBooIt.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConDem.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConDemIt.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConExB.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConExBIt.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConLig.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConLigIt.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConMed.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConMedIt.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConReg.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConRegIt.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConThi.otf
/Volumes/2GB_230515/Fonts/fonts-id/Cabrito-ConThiIt.otf

It’s very very simple. :slight_smile: An Ends With would be useful for folder elimination, and suppression of package items somehow. Thanks!

There’s a “Name ends with” rule you can add. Or the newer “Extension is” rule. And there’s also “Kind is not Directory”, or the hidden (“expert”, see manual) rule “Is Folder No”.
Then there’s the rule “Package Items are not shown”, though that may indeed not have the desired effect when saving the results to a file (meaning that they’ll end up in the file regardless because this option is only filtering them out in the results window, even though they’re still part of the “found” set - that’s something I could fix, indeed).
Give these rules a try if you have the time and let me know if that gives you better results.

Offtopic: if you like to make paragraphs you need to use double linefeeds, I think :slight_smile:

Homer712. I’ve modified my script to sort the output text in alphabetical order. I’ve also changed some variable names, since this and my previous script work with both volumes and folders. The sort selector used works in the same fashion as the Finder (it is case insensitive and numbers are sorted numerically instead of lexically). This is easily changed.

use framework "Foundation"
use scripting additions

set theFolder to "/Users/Robert/Documents/" -- set to desired value
set textFile to POSIX path of (path to desktop) & "All Files.txt"
writeFiles(theFolder, textFile)

on writeFiles(theFolder, textFile)
	set fileManager to current application's NSFileManager's defaultManager()
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set fileKey to current application's NSURLIsRegularFileKey
	set theFiles to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects()'s mutableCopy()
	repeat with i from theFiles's |count|() to 1 by -1
		set {theResult, aRegularFile} to ((theFiles's objectAtIndex:(i - 1))'s getResourceValue:(reference) forKey:fileKey |error|:(missing value))
		if aRegularFile as boolean is false then (theFiles's removeObjectAtIndex:(i - 1))
	end repeat
	set sortedFiles to (theFiles's valueForKey:"path")'s sortedArrayUsingSelector:"localizedStandardCompare:"
	set theString to sortedFiles's componentsJoinedByString:linefeed
	theString's writeToFile:textFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeFiles

Not only does the script work perfectly, it is incredibly fast. The file seems to pop up on the desktop just as soon as the run arrow is clicked. Thank you, I can see many uses for this kind of script. Now, I’m not asking (because I’d like to see if I can figure it out myself), but I’m going to try to have the output be a PDF. I asked you once in another thread and I’ll look at that one where you went from TXT to PDF.

After three cups of coffee I have a working txt to pdf conversion. Not very polished, but it works.

use framework "Foundation"
use scripting additions

set theFolder to "/Users/homer/Documents/" -- set to desired value
set textFile to POSIX path of (path to desktop) & "All Files.txt"
writeFiles(theFolder, textFile)

on writeFiles(theFolder, textFile)
	set fileManager to current application's NSFileManager's defaultManager()
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set fileKey to current application's NSURLIsRegularFileKey
	set theFiles to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects()'s mutableCopy()
	repeat with i from theFiles's |count|() to 1 by -1
		set {theResult, aRegularFile} to ((theFiles's objectAtIndex:(i - 1))'s getResourceValue:(reference) forKey:fileKey |error|:(missing value))
		if aRegularFile as boolean is false then (theFiles's removeObjectAtIndex:(i - 1))
	end repeat
	set sortedFiles to (theFiles's valueForKey:"path")'s sortedArrayUsingSelector:"localizedStandardCompare:"
	set theString to sortedFiles's componentsJoinedByString:linefeed
	theString's writeToFile:textFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeFiles

tell application "TextEdit"
	activate
	open "/Users/homer/Desktop/All Files.txt/"
	tell (windows whose id is not (get id of front window) and visible is true)
		set miniaturized to true
	end tell
	set bounds of front window to {279, 111, 1180, 719}
	
	tell application "System Events"
		click menu item "Export as PDF…" of menu 1 of menu bar item "File" of menu bar 1 of application process "TextEdit"
	end tell
end tell