2

Let me give an example:

$ echo Hello > file1
$ echo Hello > file2
$ echo Hello > .file3
$ grep Hello * 2>/dev/null
file1:Hello
file2:Hello

Here you can see the grep ignored .file3 which is starting from .

Expected result:

$ grep Hello * 2>/dev/null
.file3:Hello
file1:Hello
file2:Hello

In case of ls, there is an argument -a to tell do not ignore entries starting with . but I can't find any feature for grep

So, Is there anyway to tell grep do not ignore entries starting with .? or why grep ignores them?

Pandya
  • 24,618

7 Answers7

13

* does not match leading period . in filename expansion. The rule was specified by POSIX.

With pattern matching, it works:

$ sh -c 'case . in *) echo 1;; esac'
1

POSIXly:

find . ! -name . -prune -type f -exec grep 'pattern' /dev/null {} +

This approach has advantage over using shell globbing. You will never get Argument list too long error when there're too many files.

cuonglm
  • 153,898
10

As others have stated, the * glob won't include hidden files (those whose name starts with a dot) by default. A simple way around that is to use two globs:

grep Hello * .*

On the down side, except with zsh, fish or shells based on the Forsyth shell (nowadays, pdksh and derivatives like mksh, posh or OpenBSD sh) that will cause grep to complain about searching through the directories . and ..:

$ grep Hello * .*
file1:Hello
file2:Hello
grep: .: Is a directory
grep: ..: Is a directory
.file3:Hello

You can either just ignore those errors (they're not important in this context) or you can use a simple loop and check that the target is a regular file (after symlink resolution):

$ for file in .* *; do [ -f "$file" ] && grep -H -- Hello "$file"; done 
.file3:Hello
file1:Hello
file2:Hello
terdon
  • 242,166
  • From man grep: -d ACTION \n If an input file is a directory, use ACTION to process it. By default, ACTION is read... if ACTION is skip, silently skip directories.... – Centimane Sep 15 '17 at 16:51
9

For globs to include hidden files except . and ..:

  • zsh:

    grep Hello ./*(D)
    

    (you also need ./ for file names starting with -). Or:

    (set -o dotglob; grep Hello ./*)
    

    Another advantage of zsh globs is that you can specify that you only want regular files (with the . glob qualifier):

    grep Hello ./*(D.)
    
  • ksh93:

    (FIGNORE='.?(.)'; grep Hello ./*)
    
  • bash:

    (shopt -s dotglob; grep Hello ./*)
    
  • tcsh:

    (set globdot; grep Hello ./*)
    
  • fish:

    grep Hello {.,}*
    
  • Forsyth shell and derivatives (pdksh, OpenBSD sh, posh, mksh...) and fish:

    grep Hello ./.* ./*
    
  • rc, es:

    grep Hello ./.[~.]* ./..?* ./*
    
  • Bourne shell, ksh88 and Almquist shell derivatives:

    grep Hello ./.[!.]* ./..?* ./*
    
  • csh:

    grep Hello ./.[^.]* ./..?* ./*
    

With zsh, (t)csh and fish, that won't run the command if the glob(s) don't match any file. In other shells, the globs that are not matched will be passed as-is to grep, and grep will complain that the corresponding file doesn't exist.

7

grep doesn't ignore anything. *, by default, does not match files with a leading .. If you have GNU grep, it is easier to use its recursive option, instead of relying on shell wildcards:

grep Hello . -r
muru
  • 72,889
6

Others have correctly said that * will not match files starting with dot. Various solutions have been given in many answers, most of which have some loop-hole or the other (such as including . & .. ; or excluding files starting with multiple Dots ; or including Sub-Directories ; or involving a very long command-line) all of which provide some new points to this question.

My simple solution (for bash users) is to use shopt -s dotglob which informs bash to include Dot Files in * glob.
For POSIX compatibility or usage of other shells, I hope the other answers are useful.
Highlights of shopt -s dotglob Solution : It will not include . and .. ; It will not include Sub-Directories in a recursive way ; It is very short ; It can be put in .bashrc file.

Prem
  • 3,342
  • 2
    Problem with this answer: it will work only in bash. – techraf Feb 20 '16 at 10:37
  • 1
    @techraf , I was waiting for somebody to point that out ! & I even included the word "bash" rather than "shell", to indicate that this for bash on linux. There will be no solution which works in all shells (csh tcsh zsh ksh ash . . .) on all OS platforms. – Prem Feb 20 '16 at 11:30
  • 1
    @Prem: There's one, see my answer – cuonglm Feb 20 '16 at 13:14
  • @cuonglm , Well , it is a solution within the parameters of the question , +1 , but I would qualify that as almost a shell script (written on a single line) which could be done similarly via Perl. – Prem Feb 20 '16 at 13:24
  • @Prem: Of course, but Perl is not a standard tools, which you can not rely to work in all platforms. – cuonglm Feb 20 '16 at 13:27
  • @cuonglm , my comment about Perl was not assuming that it is standard ; I mentioned it merely as a comparison to shell scripting way of "getting all files and forwarding everything except . & .." ; Not every system is POSIX compatible. More-over , in your case , exit status will not be from "grep", but from "find". Not taking anything away from your answer ( which I already upvoted , along with many other answers here ) but simply listing some potential issues , which might have a bearing in individual cases. – Prem Feb 20 '16 at 16:13
3

The expansion of * is done by the shell running the command.
By default shells omit dot files (hidden files).

The simplest and most portable solution (not zsh) would be to use:

$ grep Hello * .[!.]* 

The second glob .[!.]* is equivalent to .[^.]* and is needed for some shells (use the ^ form for zsh,csh and tcsh, or .[~.]* for rc/es).
It makes the dot files appear on the list for grep.

If there is the need to process file names other than .. starting with 2 dots, add a third glob Reference page from UNIX FAQ:

$ grep Hello * .[!.]* ..?*

If you want to see what is going on, do:

echo grep Hello * .[!.]* ..?*

And test why this doesn't quite work: echo grep Hello * .*


ksh | bash

In ksh or bash with extglob active (on by default in interactive use for bash):

grep Hello .!(.|) *

Or only for bash, just use dotglob:

shopt -s dotglob; grep Hello *

zsh

grep Hello *(D.)
  • .[!.]* won't work with csh/tcsh either (where you need .[^.]*, ! conflicts with history expansion, bash has a special case here that disables history expansion for this case), or rc/es where you need .[~.]* (^ is a special concatenation operator in rc). The reason it's [!.] in the Bourne shell is because ^ was a piping operator there like | for backward compatibility with the Thomson shell. fish globs have no bracket expressions, but .* will never include . nor .. like in all sensible shells... – Stéphane Chazelas Feb 21 '16 at 20:25
  • @StéphaneChazelas Both comments are correct, incorporated them (in part). The description in your second comment is too extense for me to be able to incorporate all the details: Please do not erase it, I believe it adds quite a lot to my attempt at an answer, thanks. –  Feb 21 '16 at 20:47
2

Try this

$ grep Hello `ls -A` 2>/dev/null
.file3:Hello
file1:Hello
file2:Hello

EDIT:

Above code will not produce results having space in file name, as suggested by techraf. To solve this issue, try following code:

$ echo Hello > .file 4
$ find . -print0 | xargs -0 grep Hello 2>/dev/null
    .file3:Hello
    .file 4:Hello
    file1:Hello
    file2:Hello

Here find . will search in subdirectories also. To limit the search for current directory, use the parameter -maxdepth=1

From man page of find

-print0

      True; print the full file name on the standard  output,  followed
      by  a  null  character  (instead  of  the  newline character that
      ‘-print’ uses).  This allows file names that contain newlines  or
      other  types  of  white space to be correctly interpreted by pro-
      grams that process the find output.  This option  corresponds  to
      the ‘-0’ option of xargs.

And from man page of xargs

-0

Input items are terminated by a null character instead of by whitespace, and the quotes and backslash are not special (every charac‐ ter is taken literally). Disables the end of file string, which is treated like any other argument. Useful when input items might contain white space, quote marks, or backslashes. The GNU find -print0 option produces input suitable for this mode.

SHW
  • 14,786
  • 14
  • 66
  • 101