Showing All Hidden (dot) Files in the Current Directory
You want to see only hidden (dot) files in a directory to edit a file you
forget the name of or remove obsolete files. ls -a
shows all
files, including normally hidden ones, but that is often too noisy, and
ls -a
.* doesn’t do what you think it
will.
Use ls-d
along with whatever other criteria you have.
ls -d .* ls -d .b* ls -d .[!.]*
Or construct your wildcard in such a way that . and .. don’t match.
$ grep -l 'PATH' ~/.[!.]* /home/jp/.bash_history /home/jp/.bash_profile
Due to the way the shell handles file wildcards, the sequence .* does not behave as you might expect or desire. The
way filename expansion or
globbing works is that any string containing the
characters *, ?, or [ is treated as a pattern, and replaced by
an alphabetically sorted list of file names matching the pattern. *
matches any string, including the null string, while ? matches any
single character. Characters enclosed in [] specify a list or range of characters, any
of which will match. There are also various extended pattern-matching operators that we’re not going
to cover here (see “Pattern-Matching Characters” and “extglob Extended
Pattern-Matching Operators” in Appendix A). So
*.txt
means any file ending in .txt, while
*txt
means any file ending in
txt
(no dot). f?o
would match foo
or fao
but not fooo
. So you’d think that .* would match any
file beginning with a dot.
The problem is that .* is expanded to include . and .., which are then both displayed. Instead of getting just the dot files in the current directory, you get those files, plus all the files and directories in the current directory (.), all the files and directories in the parent directory (..), and the names and contents of any subdirectories in the current directory that start with a dot. This is very confusing, to say the least.
You can experiment with the same ls command
with -d
and without, then try
echo
.*. The echo
trick simply shows you what the shell expanded your .* to. Try echo.[!.]*
also.
.[!.]* is a filename expansion pattern where [] denotes a list of characters to match, but the leading ! negates the list. So we are looking for a dot, followed by any character that is not a dot, followed by any number of any characters. You may also use ^ to negate a character class, but ! is specified in the POSIX standard and thus is more portable.
Warning
.[!.]* will miss a file named ..foo. You
could add something like .??* to match anything starting with a
dot that is also at least three characters long. But
ls -d
.[!.]* .??* will then display
anything that matches both patterns twice. Or you can use .??* alone,
but that will miss files like .a. Which you use
depends on your needs and environment; there is no good
one-size-fits-all solution.
$ touch ..foo .a .normal_dot_file normal_file $ ls -a . .. ..foo .a .normal_dot_file normal_file $ ls -d .??* ..foo .normal_dot_file $ ls -d .[!.]* .a .normal_dot_file $ ls -d .[!.]* .??* | sort -u ..foo .a .normal_dot_file
You can use echo
* as an
emergency substitute for ls if the
ls command is corrupt or not available for some
reason. This works because * is expanded by the shell to everything in
the current directory, which results in a list similar to what you’d
get with ls
.
http://www.gnu.org/software/coreutils/faq/#ls-_002da-_002a-does-not-list-dot-files
Section 2.11 in http://www.faqs.org/faqs/unix-faq/faq/part2
“Pattern Matching Characters” in Appendix A
“extglob Extended Pattern-Matching Operators” in Appendix A
Get bash Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.