Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

The command

    ls .*

when run gives as output the following :

  • All the files in the current directory starting with a . (hidden files)
  • All the files in the hidden directories present in the current directory
  • All the files in the current directory
  • All the files in the parent directory

Why does the command

    ls *.

not display :

  • All the files in the current directory
  • All the files in the parent directory

Reason I am thinking so is : The regular expression *. should match both . and .. So ls should be run on both and thus the output which I am expecting should be displayed

share|improve this question
add comment

2 Answers

up vote 4 down vote accepted

It's because * doesn't match files starting with a . by default. Consider the following directory:

$ ls -la 
total 8404
drwxrwxrwx   2 terdon terdon 8105984 Dec 31 13:14 .
drwxr-xr-x 153 terdon terdon  491520 Dec 30 22:32 ..
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 .dotfile
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 file1
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 file2
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 file3.

Let's see what each of the globs you used expands to:

$ echo .*
. .. .dotfile

$ echo *.
file3.

$ echo *
file1 file2 file3.

As you can see, the * does not include files or directories starting with . so both ./ and ../ are ignored. The same thing happens with your ls example. In bash, you can change this with the dotglob parameter:

$ shopt -s dotglob
$ echo .*
. .. .dotfile

Other shells behave differently, for example csh:

% echo .*
. .. .dotfile
share|improve this answer
    
Great explanation –  X Tian Dec 31 '13 at 11:45
add comment

The rule for filename expansion have a special case for . as the first character in a filename: it must be explicitly matched (i.e. the pattern must contain a starting ., or . after a /). Otherwise these files are not candidates.

This is why your first version does pick up filenames that start with ., but the second doesn't. * doesn't match . as the first character of a filename.

POSIX Shell Command Language describes it as:

If a filename begins with a period ( '.' ), the period shall be explicitly matched by using a period as the first character of the pattern or immediately following a slash character. The leading period shall not be matched by:

  • The asterisk or question-mark special characters
  • A bracket expression containing a non-matching list, such as "[!a]", a range expression, such as "[%-0]", or a character class expression, such as "[[:punct:]]"

It is unspecified whether an explicit period in a bracket expression matching list, such as "[.abc]", can match a leading period in a filename.

Your shell might have options to change this behavior. Bash has this for instance (Filename expansion):

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. When matching a file name, the slash character must always be matched explicitly. In other cases, the ‘.’ character is not treated specially.


Note that these are not regular expressions. .* as a regex would match anything at all (including nothing). *. would be ill-formed.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.