PDA

View Full Version : Applescript search for empty folders




xstophe
Jul 2, 2008, 04:33 AM
Who can help me.

I need a script, applescript or automator task, or even a project in xcode. Doens't matter, just need something working.

What I want to do is the following:

- I need to define a map (either local or server)
- the program has to find empty subfolders on this server.
- program has to make a log file of the empty folders, and give a coloured label to the empty folder.

I tried with automator, but I can't find to do a search on empty folders.

Hope someone can help me.

Thnx
C.



tedsmith3rd
Jul 2, 2008, 01:27 PM
Sweet Jesus! This tiny applescript was painful to write. Anyway let me know if you have questions.


-- Give this directory as a unix path
set mySearchDirectory to "~/Desktop"

-- This should be a unix path too
set myReportFile to "~/Desktop/EmptyDirs.txt"

-- I think 1 is red... google finder label index for a list somewhere
set myLabelColorNumber to 1


tell application "Finder"
-- Let the shell expand these user vars
set mySearchDirectory to (do shell script "echo " & mySearchDirectory)
set myReportFile to (do shell script "echo " & myReportFile)

-- Init some things
set reportText to "Empty Folders:"
set newline to ASCII character 10

-- Start the find process to search mySearchDirectory for empty directories
set emptyDirs to do shell script "find " & quoted form of mySearchDirectory & " -type d -empty -print0"

repeat with thisDir in my findSplit(emptyDirs)
-- Label each returned directory
set label index of item thisDir to myLabelColorNumber

-- Add this directory to our report text, I'm using posix path, but you can just use thisDir if you want
set reportText to reportText & newline & (POSIX path of thisDir as string)
end repeat

-- To get a posix path the file has to exist
do shell script "touch " & quoted form of myReportFile
set myReport to (get POSIX file myReportFile as string)
try
set fh to open for access file myReport with write permission
set eof fh to 0
write reportText to fh starting at 0 as string
close access fh
on error
close access fh
display dialog "Couldn't open output file"
end try
end tell

to findSplit(input)
set retVal to {}
set origDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to ASCII character 0

repeat with thisItem in every text item in input
try
copy thisItem as POSIX file to the end of retVal
end try
end repeat

set AppleScript's text item delimiters to origDelimiters

return retVal
end findSplit

xstophe
Jul 3, 2008, 12:35 AM
thnx man,

I tried it, like you gave it and it worked, found empty folders around my desktop.

Only thing it didn't do, I changed the mySearchDirectory to ~/Desktop/test, because in this folder I wanted it to search, but it just returns an empty textfile.

What am I doing wrong?

greetz
C.

xstophe
Jul 3, 2008, 12:46 AM
ok I tried something different, placed a fresh empty map in de subdirectory and it worked.

First I tried it with al list of directories, and I manually deleted the files from 1 of the folders.
For me this is empty.

Probably there are some hidden system files still hanging around in a folder this way? Like the .xxxxx files, with a dot in front of them.

Is there a way, that the script could ignore these? If there are still some hidden files in the folder, it should be considered empty.

Hope I am clear, english is not my native language ;).

thnx

You should receive a medal for your work ;).

tedsmith3rd
Jul 6, 2008, 10:41 PM
Probably there are some hidden system files still hanging around in a folder this way? Like the .xxxxx files, with a dot in front of them. Is there a way, that the script could ignore these? If there are still some hidden files in the folder, it should be considered empty.


This gets a little trickier. The problem is that the BSD "find" command which I was leveraging doesn't support that type of logic. We're going to have to do a lot more on the applescript level, which could slow things down a lot. It might be worth it to change programming languages at this point. Let me think about it and I'll post another attempt today or tomorrow.

xstophe
Jul 7, 2008, 12:21 AM
sure take your time, I'm glad your helping me.

I also have xcode installed on the system, so if you like some other language like C++, I could code it in that.

Thnx for all the work.

tedsmith3rd
Jul 8, 2008, 11:17 PM
Sorry, I forgot to post this yesterday.

Here's a python script that does what you want. Using a text editor (in text mode) save this to a file, called for example "find-empty.py". Then from terminal, enable it to run with this command
chmod +x find-empty.py

Then you can run it on one or more directories for example
./find-empty.py ~/Desktop

This will write a report called "Empty Folders Report.txt" to the root of the directory you are scanning (in this case it will show up on your Desktop), and set the finder label of any empty subfolders to orange. It will ignore any files whose names begin with a dot when deciding if a folder is empty.

BUT there is probably a better way to run this script. You said you have 10.5 and the developer tools installed. Open /Developer/Applications/Utilities/MacPython 2.5. Drag and drop this script onto "Build Applet.app". This will create "find-empty.app"

If you want to scan a folder or disk, just drag it's icon onto this new app file and it will create your report and label your folders as above without requiring you to use the terminal. There is no progress bar or anything, but you can see if it is having problems with "Console.app". Hope this helps.


#!/usr/bin/python

import sys
import os
import tempfile
import subprocess
import time

########################################
#### Subroutines #######################
########################################

# callback for filter below
def isNonTrivial(fileName):
# If the fileName starts with a dot, it doesn't count
if fileName[0:1] == '.':
return False
else:
return True

# function which sets the finder label for OS X files
def finderLabelFiles(files, labelNum):
# Write the list of files to label to a temp file
(tmpFH, tmpPath) = tempfile.mkstemp('.txt')
os.write(tmpFH, "\n".join(files))
os.close(tmpFH)

# Open a pipe to and from the applescript interpreter
asInterpreter = subprocess.Popen(
"/usr/bin/osascript",
shell=True,
stdin=subprocess.PIPE,
stdout=sys.stdout)

# The script we'll send it
script = [
'tell application "Finder"',
'set fileList to (POSIX file "%s")' % (tmpPath),
'set labelColor to %i' % (labelNum),
'try',
'set fh to open for access fileList',
'repeat with thisFile in (read fh using delimiter (ASCII character 10))',
'set label index of item (thisFile as POSIX file) to labelColor',
'end repeat',
'close access fh',
'on error',
'try',
'close access fh',
'end try',
'end try',
'end tell'
]

asInterpreter.stdin.write("\n".join(script))
asInterpreter.stdin.close()
asInterpreter.wait()
os.unlink(tmpPath)

########################################
#### Main ##############################
########################################

# Sanity-Check Arguments
if (not (len(sys.argv) > 1 and map(os.path.isdir, sys.argv[1:]).count(False) < 1)):
print "Usage: %s directory_to_search [...]" % (sys.argv[0])
exit()

# For each directory specified on the command line
for searchDirectory in sys.argv[1:]:
# Init
emptyDirs = []
reportFile = os.path.join(searchDirectory, "Empty Folders Report.txt")

# Main Loop: os.walk returns this tuple for each subdir
for thisPath, thisPathDirs, thisPathFiles in os.walk(searchDirectory):
# Does this directory have subdirectories?
if len(thisPathDirs) == 0:
# Does this directory have files?
if len(thisPathFiles) == 0:
emptyDirs.append(thisPath)
else:
# Are the files all trivial?
filteredFiles = filter(isNonTrivial, thisPathFiles)
if len(filteredFiles) == 0:
emptyDirs.append(thisPath)

# Were there actually were any empty directories?
if len(emptyDirs) > 0:
# Write our report
try:
report = open(reportFile, 'w')
report.write("# Empty Folders in %s on %s:\n" % ( searchDirectory, time.asctime() ) )
report.write("\n".join(emptyDirs))
report.close()
except:
print "Couldn't write report for %s (%s)" % (searchDirectory, reportFile)
raise

# Set the finder labels for the empty dirs
finderLabelFiles(emptyDirs, 1)
else:
print 'No empty directories were found in "%s"' % (searchDirectory)

exit()

xstophe
Jul 10, 2008, 11:05 AM
you are great !

it worked like a charm on 10.5.

I did it with MacPython like you said.

Now I can just drag the folder on it and there we have it !

You like this kind of questions? If you do I have another challenge you could try out, something similar..


The case:

I have folders (on a server), which are the following structure.

0xxxxxxx/0xxxxxxx.jpg or 0xxxxxxx/0xxxxxxx.swf
where the folder name is the same as the file in it with a zero in front of it.

I have to get a log, and label it like the empty folders app (if you could do a drag on the app thing for this would be great), of the files that don't match the folder name.

example

02134578/02134578.jpg is a good one
02134578/02134578.swf is a good one
02134578/02134579.jpg is a bad one (this has to log and label)
02134578/2134578.jpg is also a bad one (this has to log and label)
02134578/02134579.swf is also a bad one (this has to log and label)

etc...

Is this something simple to do? Like the python app you made for the empty folders problem?

If I am bothering you with this, just say it ;), you helped me already a great deal. So this is something of a bonus ;). So if you like to do it, be my guest otherwise thnx for the great empty folders app !!! I appriciate it !

tedsmith3rd
Jul 10, 2008, 12:12 PM
"Bonus" :rolleyes:

Anyway, that's not too difficult to do. Most of the work done on the last script can be ported to this one. Use it the same as above.


#!/usr/bin/python

import sys
import os
import tempfile
import subprocess
import time

########################################
#### Subroutines #######################
########################################


# function which sets the finder label for OS X files
def finderLabelFiles(files, labelNum):
# Write the list of files to label to a temp file
(tmpFH, tmpPath) = tempfile.mkstemp('.txt')
os.write(tmpFH, "\n".join(files))
os.close(tmpFH)

# Open a pipe to and from the applescript interpreter
asInterpreter = subprocess.Popen(
"/usr/bin/osascript",
shell=True,
stdin=subprocess.PIPE,
stdout=sys.stdout)

# The script we'll send it
script = [
'tell application "Finder"',
'set fileList to (POSIX file "%s")' % (tmpPath),
'set labelColor to %i' % (labelNum),
'try',
'set fh to open for access fileList',
'repeat with thisFile in (read fh using delimiter (ASCII character 10))',
'set label index of item (thisFile as POSIX file) to labelColor',
'end repeat',
'close access fh',
'on error',
'try',
'close access fh',
'end try',
'end try',
'end tell'
]

asInterpreter.stdin.write("\n".join(script))
asInterpreter.stdin.close()
asInterpreter.wait()
os.unlink(tmpPath)

########################################
#### Main ##############################
########################################

# Sanity-Check Arguments
if (not (len(sys.argv) > 1 and map(os.path.isdir, sys.argv[1:]).count(False) < 1)):
print "Usage: %s directory_to_search [...]" % (sys.argv[0])
exit()

# For each directory specified on the command line
for searchDirectory in sys.argv[1:]:
# Init
badFiles = []
reportFile = os.path.join(searchDirectory, "Bad Files Report.txt")

# Main Loop: os.walk returns this tuple for each subdir
for thisPath, thisPathDirs, thisPathFiles in os.walk(searchDirectory):
# The parent folder of '/some/path/on/your/computer" is "computer"
parentFolder = os.path.split(thisPath)[1]

# Does this directory have any files?
for thisFile in thisPathFiles:
# Ignore files beginning with a dot
if thisFile[0:1] == '.': continue

# The base name of "123.jpg" is "123"
thisFileBaseName = os.path.splitext(thisFile)[0]

# Do the comparison
if parentFolder != thisFileBaseName:
badFiles.append(os.path.join(thisPath, thisFile))


# Were there actually were any bad files?
if len(badFiles) > 0:
# Write our report
try:
report = open(reportFile, 'w')
report.write("# Bad files in %s on %s:\n" % ( searchDirectory, time.asctime() ) )
report.write("\n".join(badFiles))
report.close()
except:
print "Couldn't write report for %s (%s)" % (searchDirectory, reportFile)
raise

# Set the finder labels for the empty dirs
finderLabelFiles(badFiles, 2)
else:
print 'No bad files were found in "%s"' % (searchDirectory)

exit()

xstophe
Jul 11, 2008, 02:59 AM
great thnx works like a charm !

the bad files are labelled now, can I change something so that the dirs of the bad files are labelled? it's easier on the eye If I got a complete list to view. The dirs will stand out.

tedsmith3rd
Jul 11, 2008, 10:29 AM
can I change something so that the dirs of the bad files are labelled? it's easier on the eye If I got a complete list to view. The dirs will stand out.

I made a couple of small adjustments so that it labels the folders as well as the files. (See attached) If you don't want the files labeled, remove or comment-out line 83 which reads "badItems.append(os.path.join(thisPath, thisFile))"

123668

xstophe
Jul 12, 2008, 03:36 PM
perfect !!

thx a lot for your work, I hope sometime I can help you back with something !!

hope to stay on contact with you, maybe I have some new challenges for you in the future ;)

nostar
Jul 25, 2010, 02:20 PM
I tried tedsmith3rd post entitled "Progress", but it doesn't seem to report anything. Is there a programming change since he built that app for 10.5? I know nothing about Python, I'm just trying to get rid of some empty folders on an external drive formatted in HFS+ attached to my Airport Extreme.