5

rm -rf .* will only not end horribly because rm refuses to delete . and ...

How do I exclude these special directories from a glob pattern?

This is not solved by dotglob since I want to match only files beginning with a dot not all files.

6
  • 1
    History: unix.stackexchange.com/a/90075/117549
    – Jeff Schaller
    Oct 18, 2018 at 9:30
  • 1
    @JeffSchaller, doesn't that one ask for all files, which is easily accomplished with dotglob? Here, they just want those starting with a dot.
    – ilkkachu
    Oct 18, 2018 at 9:38
  • 1
    Stéphane’s answer in it: unix.stackexchange.com/a/264571/117549
    – Jeff Schaller
    Oct 18, 2018 at 9:42
  • Good catch @JeffSchaller but I suggest we repost the solution here so it will be found more easily. Would you do the honors?
    – Franklin
    Oct 18, 2018 at 9:54
  • 1
    The “duplicate” feature is exactly to put good solutions in one place...
    – Jeff Schaller
    Oct 18, 2018 at 9:55

6 Answers 6

4

With bash, setting the GLOBIGNORE special variable is some non-empty value is enough to make it ignore . and .. when expanding globs. From the Bash docs:

The GLOBIGNORE shell variable may be used to restrict the set of filenames matching a pattern. If GLOBIGNORE is set, each matching filename that also matches one of the patterns in GLOBIGNORE is removed from the list of matches. If the nocaseglob option is set, the matching against the patterns in GLOBIGNORE is performed without regard to case. The filenames . and .. are always ignored when GLOBIGNORE is set and not null. However, setting GLOBIGNORE to a non-null value has the effect of enabling the dotglob shell option, so all other filenames beginning with a ‘.’ will match.

If we set it to .:.., both . and .. will be ignored. Since setting it to anything non-null will also get this behaviour, we might as well set it to just .

So:

GLOBIGNORE=.
rm -rf .*

(From my earlier answer on Ask Ubuntu.)

1
  • I think this is the best way to solve the problem I was having since it specifically excludes the special cases.
    – Franklin
    Oct 18, 2018 at 10:54
4

This should do it:

rm -rf .[^.] .??*  

This command can catch all cases.

.[^.] will catch any two character entries. .??* will only match 3+ character filenames.

3

@Goro has, I think, the simplest totally correct answer. However, I find it's a pain to type. I would suggest instead

ls .??*

It's absolutely true that this will miss files like .a, but those are so extraordinarily rare that in practice I don't think it matters, especially for interactive usage.

1
  • This is genius! :). It's just what I wanted, short, simple and it works! None of my dot files have just a single character after the dot (all of them have longer names) so this works for me. Thank you!
    – OMA
    Oct 15, 2019 at 12:09
1

You need to exclude single and double dots:

rm -rf {..?,.[!.]}*
  • ..?* matches everything with two dots followed by anything
  • .[!.]* matches everything with single dot not followed by another dot
1

With extglob:

$ shopt -s extglob
$ touch ... .a .bbb ..c foo
$ echo .!(.|)
... .a .bbb ..c

!(.|) matches anything but a dot or empty, so .!(.|) matches anything starting with a dot, except . and ...

1

With find, it's a bit more to type but you can be more explicit, which makes it easier to understand:

find . -maxdepth 1 -name '.*' ! -name . ! -name .. -exec rm -rf {} +

This calls rm -rf with all names in the current directory (only) that starts with a dot and which is not . nor ... I'm not using -delete here as that predicate may not delete non-empty directories.

If you want to match only regular files in the current directory, it becomes even easier:

find . -maxdepth 1 -type f -name '.*' -delete

Here, we don't need to exclude . or .. as they are automatically excluded by -type f.

Change -type f to ! -type d to make it delete any non-directory (i.e. symbolic links etc.)

Not the answer you're looking for? Browse other questions tagged or ask your own question.