147

Does anyone have a solution to remove those pesky ._ and .DS_Store files that one gets after moving files from a Mac to A Linux Server?

specify a start directory and let it go? like /var/www/html/ down...

codeforester
  • 39,467
  • 16
  • 112
  • 140
JT.
  • 1,491
  • 2
  • 10
  • 6
  • Although it's not a duplicate IMO, you should take a look at this: http://stackoverflow.com/questions/1280429/delete-all-files-but-keep-all-directories-in-a-bash-script – Grundlefleck Jan 06 '10 at 22:36
  • Although not what you are asking. I would argue this is a better solution: http://unix.stackexchange.com/questions/9665/create-tar-archive-of-a-directory-except-for-hidden-files – Viktor Jun 25 '14 at 10:38

12 Answers12

176

change to the directory, and use:

find . -name ".DS_Store" -print0 | xargs -0 rm -rf
find . -name "._*" -print0 | xargs -0 rm -rf

Not tested, try them without the xargs first!

You could replace the period after find, with the directory, instead of changing to the directory first.

find /dir/here ...
X-Istence
  • 16,324
  • 6
  • 57
  • 74
  • 2
    I know his question didn't ask for it, but I can never remember: does your example handle filenames with spaces? – Grundlefleck Jan 06 '10 at 22:41
  • 4
    Yes, that is what the print0 and the -0 to xargs is for. Normally it wouldn't handle spaces correctly, however with print0 it will print the filename with a null character at the end of the line, which xarg with -0 will then use to pass the full path to xargs without a chance of having the whitespace being used a second or third parameter to the rm command which could be really bad! – X-Istence Jan 06 '10 at 22:47
  • @X-Istence - This wont recursively traverse sub-directories though right? – JT. Jan 06 '10 at 22:52
  • @X-Istence - What do you think about running this starting at /var/www/html and directories below it in a CRON say every hour? This box is a webserver, but files are uploaded frequently. – JT. Jan 06 '10 at 22:53
  • 7
    @X: newer findutils supports a `-delete` action, which could shorten this. @JT: This searches recursively under `.`. Depends on how many files and subdirectories there are... can't you just just forbid those from being uploaded? – ephemient Jan 06 '10 at 23:25
  • @JT: It will recurse. `man find`. Using this in a cron would be possible, rather see if your FTPD supports upload scripts, which will check what is uploaded and remove files like ._ and .DS_Store. @ephemient: Yes, newer find will, however last time I used find it was not available. Also, I do believe there is a performance penalty to have find run the delete, as searching a directory and removing files at the same time can cause slowdowns (UFS has issues with this from experience) – X-Istence Jan 07 '10 at 00:39
  • 1
    Using the `-r` (recursive) flag is not recommended in this case since you don't want to delete any directories.. – Daniel Zohar Jul 04 '13 at 14:49
  • +1 for "try them without the xargs first!" :) did what I needed flawlessly. – Hayri Uğur Koltuk Jan 09 '14 at 09:48
  • `.DS_Store` is not a directory, so there's no need for the `-r` flag on that line. I'm not sure why you'd want `-f` either, since you'll only get file paths passed to `rm` that actually exist, so you don't need to suppress error messages. – iconoclast Jul 09 '14 at 15:33
  • 1
    @iconoclast: Possibly because some [moron](http://superuser.com/questions/384769/alias-rm-rm-i-considered-harmful) put `alias rm="rm -i"` into `.bashrc` (or `/etc/bashrc`). Yes, I've used systems that had that "feature" set up by default. – Ilmari Karonen Nov 25 '14 at 07:45
  • 2
    @IlmariKaronen: good point. Wouldn't `command rm` be a better (that is, more direct) solution? (By "direct" I mean it deals specifically with the problem at hand and nothing else, and therefore is less likely to have any unwanted side-effects, and is also going to be more self-explanatory to anyone who has to maintain the code later.) – iconoclast Nov 25 '14 at 19:55
93
find /var/www/html \( -name '.DS_Store' -or -name '._*' \) -delete
devnull69
  • 16,402
  • 8
  • 50
  • 61
OneOfOne
  • 95,033
  • 20
  • 184
  • 185
92

Newer findutils supports -delete, so:

find . -name ".DS_Store" -delete

Add -print to also get a list of deletions.

Command will work for you if you have an up-to-date POSIX system, I believe. At least it works for me on OS X 10.8 and works for others who've tested it on macOS 10.12 (Mojave).

Credit to @ephemient in a comment on @X-Istence's post (thought it was helpful enough to warrant its own answer).

vhs
  • 9,316
  • 3
  • 66
  • 70
rattray
  • 5,174
  • 1
  • 33
  • 27
  • 1
    Works back in OSX 10.6 as well. – hoss Dec 12 '13 at 14:40
  • 5
    Cleanest and simplest solution, +1! – limist Feb 19 '14 at 10:20
  • 7
    @OneOfOne: as my comment says, I got this from @ ephemient. As a beginner to bash, I found your (perhaps more correct) solution far less readable and usable. They may be functionally identical but I find this syntax provides more clarity. – rattray Mar 06 '14 at 18:30
  • 1
    The '.' isn't necessary because `find` recurses into the current working directory by default. – Tom Russell Sep 08 '16 at 17:35
  • *In newer versions of the program, the directory may be omitted, and it will imply the current working directory* ([wikipedia](https://en.wikipedia.org/wiki/Find)). You still need `.` on macOS 10.12 (Sierra). – Dem Pilafian Oct 16 '16 at 05:40
  • Worked like a charm! Indeed the cleanest and simplest solution. – Muhammad Arsalan Hassan May 04 '21 at 09:14
19

Simple command:

rm `find ./ -name '.DS_Store'` -rf
rm `find ./ -name '._'` -rf

Good luck!

KimKha
  • 4,370
  • 1
  • 37
  • 45
  • 1
    This works great. BUT a word of caution, I just used this `rm -i `find ./ -name '*py'` -rf`, which did NOT prompt me to delete files. you will need to take it on the end (i.e. `-rfi`). Thank god for my backup script. – ryanjdillon Apr 24 '13 at 19:11
  • 1
    If there are too many files this breaks with the error: `-bash: /bin/rm: Argument list too long` – Viktor Jun 25 '14 at 10:46
12
cd /var/www/html && find . -name '.DS_Store' -print0 | xargs -0 rm
cd /var/www/html && find . -name '._*' -print0 | xargs -0 rm
mopoke
  • 10,555
  • 1
  • 31
  • 31
6

You could switch to zsh instead of bash. This lets you use ** to match files anywhere in a directory tree:

$ rm /var/www/html/**/_* /var/www/html/**/.DS_Store

You can also combine them like this:

$ rm /var/www/html/**/(_*|.DS_Store)

Zsh has lots of other features that bash lacks, but that one alone is worth making the switch for. It is available in most (probably all) linux distros, as well as cygwin and OS X.

You can find more information on the zsh site.

Dave Kirby
  • 25,806
  • 5
  • 67
  • 84
  • 1
    A possible problem: since you don't use xargs, you might run into the command-line argument length restriction. Also, Bash 4 supports `**` too :-) (though not by default, `shopt -s globstar` needs to be set) – ephemient Jan 06 '10 at 23:26
4
find . -name "FILE-TO-FIND"-exec rm -rf {} \;
Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • Using exec for each file found is not fast. It is faster to have find print them out and then use xargs to invoke rm once. – X-Istence Jan 06 '10 at 22:38
  • 3
    However, if you have a `find` that supports it, `+` is xargs-like: `find . -name "FILE-TO-FIND" -exec rm -rf {} +` - (also, you're missing a space before `-exec`) – Dennis Williamson Jan 07 '10 at 02:38
  • 3
    we never had xargs in my day. And we had to walk to school, uphill both ways ....... – Martin Beckett Jul 07 '12 at 01:02
3

Example to delete "Thumbs.db" recursively;

find . -iname "Thumbs.db" -print0 | xargs -0 rm -rf

Validate by:

find . -iname "Thumbs.db"

This should now, not display any of the entries with "Thumbs.db", inside the current path.

parasrish
  • 3,864
  • 26
  • 32
  • Please be sure your answer prints a list of what's being deleted and explain why someone might want to use `xargs` and `print0` instead of `exec` (there are reasons). – vhs Mar 21 '19 at 09:01
3

It is better to see what is removing by adding -print to this answer

find /var/www/html \( -name '.DS_Store' -or -name '._*' \) -delete -print
Community
  • 1
  • 1
Ahmad Yoosofan
  • 961
  • 12
  • 21
2

if you have Bash 4.0++

#!/bin/bash
shopt -s globstar
for file in /var/www/html/**/.DS_Store /var/www/html/**/._ 
do
 echo rm "$file"
done
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
1

A few things to note:

'-delete' is not recursive. So if .TemporaryItems (folder) has files in it, the command fails.

There are a lot of these pesky files created by macs: .DS_Store ._.DS_Store .TemporaryItems .apdisk

This one command addresses all of them. Saves from running find over and over again for multiple matches.

find /home/foo \( -name '.DS_Store' -or -name '._.DS_Store' -or -name '._*' -or -name '.TemporaryItems' -or -name '.apdisk' \) -exec rm -rf {} \;
0

This also works:

sudo rm -rf 2018-03-*

here your deleting files with names of the format 2018-03-(something else)

keep it simple

pranavhd
  • 25
  • 7
  • You don't explain when someone might want to prefix a command with `sudo` nor do you provide any information how `rm` works in the context of your answer. – vhs Mar 21 '19 at 08:56