33

I want to carry out some action (say chown) on all the hidden files in a directory.

I know that this .* is not a good idea because it will also find the current . and parent .. directories (I know that rm will fail to operate on . and .. but other commands, including chown and chmod, will happily take effect)

But all my hidden files have different names!

How should I glob for all hidden files while excluding . and .. ?

Zanna
  • 70,465

4 Answers4

33

In Bash, set the GLOBIGNORE variable as follows:

GLOBIGNORE=".:.."

to hide the . and .. directories. This also sets the dotglob option so that the glob * character now matches both hidden and non-hidden files. Setting the GLOBIGNORE variable as shown above only affects the current terminal session and top-level processes unless you export it and and add it to your ~/.bashrc file as export GLOBIGNORE=".:..".

You can also do:

shopt -s dotglob

Source: Gilles' answer here :)

Rinzwind
  • 299,756
  • 3
    IMO this is better than the accepted answer. Easier to remember, infinitely more intuitive, and able to be stuffed into .bashrc to make it permanent if one so wishes (I know I almost never want * to mean "non-dotfiles only"). – jcgoble3 Sep 27 '21 at 04:30
22

You can use the following extglob pattern:

.@(!(.|))
  • . matches a literal . at first

  • @() is a extglob pattern, will match one of the patterns inside, as we have only one pattern inside it, it will pick that

  • !(.|) is another extglob pattern (nested), which matches any file with no or one .; As we have matched . at start already, this whole pattern will match all files starting with . except . and ...

extglob is enabled on interactive sessions of bash by default in Ubuntu. If not, enable it first:

shopt -s extglob

Example:

$ echo .@(!(.|))
.bar .foo .spam
heemayl
  • 91,753
  • 1
    This is clearly an awesome thing I need to learn about! Thank you for teaching – Zanna Sep 26 '16 at 10:38
  • @Zanna Glad i could help :) – heemayl Sep 26 '16 at 10:39
  • 2
    What is the purpose of the @()? Simple .!(.|) seems to work identically. – Kyle Strand Sep 26 '16 at 16:49
  • 1
    I know that this is old, but I have the same question as @KyleStrand. In my tests, !(.|) works the same. Is there any purpose behind @() in this context? – Paddy Landau Apr 02 '17 at 07:26
  • Is the bang character a negation? It is not mentioned, and reading your explanation, I get the impression, that the pattern matches dot and doubledot, but you clearly describe files which match a starting dot, except just those two. – user unknown May 14 '19 at 21:21
  • 1
    @userunknown, right, !() means to not match any of the pipe-separated alternatives inside of it, so basically this is saying: match a dot, but do not let the second character match a dot or an empty string. As pointed out above, the @() which means to pick only one of the pipe-separated alternatives, does not have a purpose since there are no alternatives. My golden source for glob information is this primer from node-glob (See https://github.com/isaacs/node-glob#glob-primer) which is equivalent to enabling dotglob in the shell – Miguel Sánchez Villafán Jan 29 '23 at 14:47
10

You can use a find command here. For example something like

find -type f -name ".*" -exec chmod 775 {} \;

This will find hidden files and change permissions


Edit to include the comment by @gerrit:

find -type f -maxdepth 1 -name ".*" -exec chmod 775 {} \;

This will limit the search top the current directory instead of searching recursively.

Wayne_Yux
  • 4,873
3

In case anyone need an alternative that doesn't require environment variables or shell options enabled like dotglob or extglobyou can use the following:

.[!.]*

it works because it matches at least two characters, the second of which must not be a dot (.)

I came to this question because I was looking for a way to match dotfiles and non-dotfiles, for which you could use:

{.[!.]*,*}

which matches either of the two options.

I needed a glob that didn't require environment variables nor shell options; and the reason is that I needed a glob that worked in VSCode's findFiles API, which supports globs (See https://code.visualstudio.com/api/references/vscode-api#3906), but doesn't offer room for shell options nor dotglob or extglob equivalents. It is nice that these tools decided to use the *NIX way for doing globs.