I'm trying to understand linux, its command-line and this quote:
You can run into problems with globs because
.*
matches.
and..
(the
current and parent directories). You may wish to use a pattern such as
.[^.]*
or.??*
to get all dot files except the current and parent
directories.
When exactly (in what command) would you use .[^.]*
or .??*
?
Best Answer
That's to work around a bug/misfeature in shells other than
zsh
,fish
and the descendants of the Forsyth shell (includingpdksh
and derivatives), whereby the.*
globs includes.
and..
(on systems (most, unfortunately) wherereaddir()
returns them)With those shells,
for instance would recursively remove rwx permissions to the current and parent directory instead of just the hidden files and directories in the current directory. A work around had to be added to
rm
for that as too many people tripped onrm -rf .*
.It's also (probably more often) used to pass all files (hidden or not) as arguments to a command (
cmd .[!.]* ..?* *
), for which you'll find other workarounds depending on the shell.It's particularly bad for commands that do things recursively or act on directories like
ls .*
,chown -R .*
,find .*
,grep -r blah .*
but it's still annoying for most other commands and I can't think of any commands for which you'd want to have those.
and..
included in the list of files passed to them.The
.[^.]*
glob (.[!.]*
in Bourne/POSIX shells) excludes.
(as it matches on filenames with at least two characters) and..
(as the second character is.
which doesn't match[^.]
), but also excludes files like..foo
, for which you need the second glob..?*
.Those
.
and..
are tools for directory traversal, it's a mistake that they should be listed like ordinary files. POSIX requires them to be understood in path components (like inopen(".")
,stat("foo/../bar")
) but not necessarily be implemented as directory entries nor included inreaddir()
.Still, most systems still do implement those like in the early Unices as hard links, and those that don't will still fake entries for them in the output of
getdents()
/readdir()
.With
bash
, an alternative is to turn thedotglob
option on and use:(though beware that if there's no non-hidden file, it could change the permissions of the
[.]*
file unless you had thefailglob
option on to mimic the behaviour ofzsh
/fish
).As a history note, filename starting with
.
being hidden files were born from a coding mistake from someone trying to skip.
and..
in the first place. It's ironical that when trying to do things with hidden files we would run into the same problem.