When constructing a pattern that matches a file name such as
/home/user/project/.git, how does one match the
. character "explicitly" -- that is, without the use of
shopt -s dotglob?
The manual at https://www.gnu.org/software/bash/manual/html_node/Filename-Expansion.html states:
When a pattern is used for filename expansion, the character ‘.’ at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set.
What, exactly, does it mean, to "be matched explicitly"?
And again, at http://www.tldp.org/LDP/abs/html/globbingref.html (in the
Notes section at the end), the same notion is addressed:
Filename expansion can match dotfiles, but only if the pattern explicitly includes the dot as a literal character.
The note provides the following examples:
~/[.]bashrc # Will not expand to ~/.bashrc ~/?bashrc # Neither will this. # Wild cards and metacharacters will NOT #+ expand to a dot in globbing. ~/.[b]ashrc # Will expand to ~/.bashrc ~/.ba?hrc # Likewise. ~/.bashr* # Likewise.
I fail to understand the inner workings of the last three examples, which will expand to include the "dotfile".
How, specifically, does placing the
b in brackets after the
. make this an "explicit" match in the example
~/.[b]ashrc? The subsequent examples are even more ambiguous to me. I simply fail to understand how manipulating the pattern in ways that seem completely unrelated to the
. character cause the pattern to produce a match.
With regard to why I would like to avoid using
shopt -s dotglob, the impetus for this question is rooted in the fact that I am writing these patterns for use in another program's configuration file. I want to exclude paths that contain, for example, "hidden
.git directories", and I'm not sure that I have the ability to specify
dotglob in any capacity.
In essence: What is the simplest means by which to match the
. character by "being explicit"? Placing the next character in brackets "makes it work", but I'd like to know why; I feel like I'm "shooting in the dark" with that approach.
Any explanation as to the underlying behavior in this regard is much appreciated.
EDIT TO ADD:
Initially, it didn't seem relevant, but because people seem to be interested in the specifics of my use-case, I'll explain further.
I'm using a Host-Based Intrusion Detection software called
Samhain. Samhain will "alert" whenever the filesystem is modified according to certain user-specified configuration parameters.
I don't want Samhain to alert when files within
.git directories (that are located within certain parent directories) are created/modified/deleted. In Samhain, this type of exclusion is performed by defining "ignore rules". The exact specification of these rules is explained at http://www.la-samhna.de/samhain/manual/filedef.html , in
4.2. File/directory specification.
Wildcard patterns ('*', '?', '[...]') as in shell globbing are supported for paths. The leading '/' is mandatory.
So, I am trying to write an "ignore rule" that will match the
.git directories in question, which will, in effect, cause Samhain to exclude them from its monitoring activities.
Initially, I tried this:
[IgnoreAll] dir = -1/home/user/project/*/*/.git
This didn't work; Samhain still alerted whenever files inside those
.git directories changed.
Upon finding the examples cited above, I tried this:
dir = -1/home/user/project/*/*/.[g]it
With this change, Samhain ignores the files, as desired.
In posting this question, I was simply trying to understand why that change has the intended effect.
I will say, I feel less stupid given that the very pattern I was trying to use at first does indeed match the
.git directories in question when I use "echo" test:
So, it wasn't so much that I was misunderstanding something fundamental with regard to pattern-matching, globbing, or file-name expansion in Bash; to the contrary, there seem to be nuances with regard to how Samhain, in particular, implements pattern-matching in this context.
I have no idea why this doesn't work when applied in the context of Samhain's configuration file (obviously). Maybe somebody will be able to explain, given this edit.