Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

Use an 'rmdir' function that's smart about .DS_Store files UNIX
Ever wish that 'rmdir' was smart enough that it would delete a directory if it was empty except for a .DS_Store file?

I wrote a zsh function which will replace rmdir and do exactly that. It is also available as a bash script, which you can rename to rmdir and drop in your $PATH.

The code is thoroughly documented for anyone who wants to see how it works, but the executive summary is this:
  1. Take a bunch of arguments
  2. Check to see if those arguments translate to directories
  3. If they do, check to see if the directory is emptied by /bin/rmdir
  4. If /bin/rmdir fails, check to see if the only file in the folder is .DS_Store
  5. If yes, delete the file and re-run /bin/rmdir on the folder
  6. If no, just report the directory is not empty
[robg adds: I've duplicated both files here on Mac OS X Hints, in case the source ever goes away: zsh function | bash script. I have not tested these myself.]
    •    
  • Currently 1.76 / 5
  You rated: 2 / 5 (21 votes cast)
 
[8,685 views]  

Use an 'rmdir' function that's smart about .DS_Store files | 10 comments | Create New Account
Click here to return to the 'Use an 'rmdir' function that's smart about .DS_Store files' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: lar3ry on Dec 22, '09 09:34:30AM

This looks like an excellent use for Perl rather than shell programming, as Perl has all the necessary functions within it so that you don't need to invoke the overhead of a fork for the rmdir, find, temp file, etc.

Unfortunately, debugged Perl script is about 100 lines long.

Interesting idea, though. Thanks!



[ Reply to This | # ]
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: luomat on Dec 22, '09 10:25:20AM

Go ahead and convert this to perl and tell me what you plan to do with the spare cycles that you save.

This is a tiny little script you're going to run, what, once per day? Maybe, MAYBE, on a really heavy day, you'd run it 20 times.

Actually, let me do it for you:

# date;time rmdir.sh test;date
Tue Dec 22 13:23:41 EST 2009
rmdir: removed test
rmdir.sh test 0.00s user 0.02s system 11% cpu 0.217 total
Tue Dec 22 13:23:42 EST 2009



[ Reply to This | # ]
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: dsouth on Dec 22, '09 10:00:35AM

Your script is not handling the tempfile securely. You need to do better checking to insure that the rm -f $TMPFILE is effective and/or use mktemp to generate a filename that is guaranteed to be unique. As written it's trivial to exploit the script to overwrite any file owned by the user running it.

Alternately, just use `rm -rf` to delete directories rather than rmdir.



[ Reply to This | # ]
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: luomat on Dec 22, '09 10:28:23AM

Yes, I'm aware it's not "secure". However, for the vast, vast majority of Mac users, this will simply never be an issue because they are the only person using the computer.

> Alternately, just use `rm -rf` to delete directories rather than rmdir.

Sure, if you want to completely ignore the fact that the main benefit of 'rmdir' is that it will protect you from accidentally deleting a directory which isn't empty.



[ Reply to This | # ]
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: dsouth on Dec 22, '09 11:23:15AM

Wasn't meant as a negative critique -- you wrote the script well. A one-line change to use mktemp rather than hard-coding the tmpfile path fixes the issue for MacOS users that frequent computer labs, have siblings, and are otherwise in shared environments.

Using mktemp also makes the script re-entrant so that more than one instance could be running at the same time without stepping on each other (important if you're doing scripted cleanups).



[ Reply to This | # ]
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: luomat on Dec 22, '09 10:32:08AM

If you want to make this more secure, change:

TMPFILE=/tmp/rmdir.$USER.$$

to

TMPFILE=$HOME/.Trash/rmdir.$USER.$$

which will put the temp file in your own trash folder.

This will reduce the chance that anyone will exploit it from 0.00000002% to 0.00000001%



[ Reply to This | # ]
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: Anonymous on Dec 29, '09 12:46:21PM

Fix the behavior and it's fixed for all time.

I work in a place where scripts of this quality were probably used as the basis of something far more complex, with resulting "inexplicable" breakage. Nothing to do with exploits.



[ Reply to This | # ]
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: jkreileder on Dec 22, '09 03:13:25PM

Note that this script fails miserably with filenames with spaces, filenames with newlines, and filenames starting with a '-'. In contrast to rmdir(1) proper quoting and using '--' don't help.



[ Reply to This | # ]
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: geert2705 on Dec 23, '09 04:09:02AM

And there is also the excellent & speedy JollysFastVNC



[ Reply to This | # ]
Use an 'rmdir' function that's smart about .DS_Store files
Authored by: eengstrom on Nov 17, '13 08:29:20PM
Why are you all making it so hard. How about this:
rmdir() { for d in "${@}"; do [ 0 -eq $(ls "$d" | grep -v DS_Store | wc -l) ] && env rm -f "$d"/.DS_Store; done; env rmdir "${@}"; }

[ Reply to This | # ]