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.

Ipor Sircer
  • 14,546
  • 1
  • 27
  • 39
Franklin
  • 235

6 Answers6

5

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.)

muru
  • 72,889
  • I think this is the best way to solve the problem I was having since it specifically excludes the special cases. – Franklin Oct 18 '18 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.

  • 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 '19 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
jimmij
  • 47,140
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 ...

ilkkachu
  • 138,973
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.)

Kusalananda
  • 333,661