Subject: bug#38792: man grep

From: Stephane Chazelas <[email-masked]>
Date: Mon, 30 Dec 2019 08:52:26 +0000

2019-12-29 18:59:22 -0800, Paul Eggert:
[...]
> > It should be
> > 
> > grep -n -- 'f.*\.c$' *g*.h /dev/null
> 
> Thanks, done in the attached patch.
[...]

There were a few other instances. The patch below attempts to
fix those (includes your patch).

I've also replaced find|xargs to the standard and more portable
(and simpler/faster...) find -exec + (GNU find used not to
support that but that was eventually fixed over 10 years ago).

I've replaced the POSIX+XSI ps -e with POSIX ps -A (for BSD
compatibility).

I've moved the grep -H and grep -- FAQ entries to the front so
they are explained before being used.

diff --git a/doc/grep.in.1 b/doc/grep.in.1
index a382966..a91b2a6 100644
--- a/doc/grep.in.1
+++ b/doc/grep.in.1
@@ -1333,13 +1333,18 @@ The following example outputs the location and contents of any line
 containing \*(lqf\*(rq and ending in \*(lq.c\*(rq,
 within all files in the current directory whose names
 contain \*(lqg\*(rq and end in \*(lq.h\*(rq.
-The command also searches the empty file /dev/null,
-so that file names are displayed
+The
+.B \-n
+option outputs line numbers, the
+.B \-\-
+argument treats expansions of \*(lq*g*.h\*(rq starting with \*(lq\-\*(rq
+as file names not options,
+and the empty file /dev/null causes file names to be output
 even if only one file name happens to be of the form \*(lq*g*.h\*(rq.
 .PP
 .in +2n
 .EX
-$ \fBgrep\fP \-n 'f.*\e.c$' *g*.h /dev/null
+$ \fBgrep\fP \-n \-\- 'f.*\e.c$' *g*.h /dev/null
 argmatch.h:1:/* definitions and prototypes for argmatch.c
 .EE
 .in
diff --git a/doc/grep.texi b/doc/grep.texi
index 873b53c..de7d028 100644
--- a/doc/grep.texi
+++ b/doc/grep.texi
@@ -1585,12 +1585,13 @@ showing the location and contents of any line
 containing @samp{f} and ending in @samp{.c},
 within all files in the current directory whose names
 contain @samp{g} and end in @samp{.h}.
-The command also searches the empty file @file{/dev/null},
-so that file names are displayed
+The @option{-n} option outputs line numbers, the @option{--} argument
+treats any later arguments starting with @samp{-} as file names not
+options, and the empty file @file{/dev/null} causes file names to be output
 even if only one file name happens to be of the form @samp{*g*.h}.
 
 @example
-$ @kbd{grep -n 'f.*\.c$' *g*.h /dev/null}
+$ @kbd{grep -n -- 'f.*\.c$' *g*.h /dev/null}
 argmatch.h:1:/* definitions and prototypes for argmatch.c
 @end example
 
@@ -1608,11 +1609,78 @@ Here are some common questions and answers about @command{grep} usage.
 
 @enumerate
 
+@item
+How do I force @command{grep} to print the name of the file?
+
+Append @file{/dev/null}:
+
+@example
+grep 'eli' /etc/passwd /dev/null
+@end example
+
+gets you:
+
+@example
+/etc/passwd:eli:x:2098:1000:Eli Smith:/home/eli:/bin/bash
+@end example
+
+Alternatively, use @option{-H}, which is a GNU extension:
+
+@example
+grep -H 'eli' /etc/passwd
+@end example
+
+Using that trick is generally wanted when using @command{find}, shell
+globbing or other forms of expansions or more generally when we don't
+know in advance what file are being searched in and want that
+information to be returned. Without it
+
+@example
+grep -- pattern *.txt
+@end example
+
+could output the matched lines without indication of which file they
+were found in if there was only one non-hidden @samp{.txt} file in the
+current directory.
+
+@item
+What if a pattern or filename has a leading @samp{-}?
+
+@example
+grep -H -- '--cut here--' *
+@end example
+
+@noindent
+searches for all lines matching @samp{--cut here--}.
+
+@samp{--} marks the end of options. None of the arguments after
+@samp{--} are treated as options even if they start with
+@samp{-}.
+
+Alternatively, one can use @option{-e} to specify the pattern:
+
+@example
+grep -H -e '--cut here--' -- *
+@end example
+
+But @samp{--} is still needed to guard against filenames that
+start with @samp{-}.
+
+Another approach would be to use:
+
+@example
+grep -H -e '--cut here--' ./*
+@end example
+
+Which also guards against a file called @samp{-} (which
+@command{grep} would otherwise interpret as meaning standard
+input).
+
 @item
 How can I list just the names of matching files?
 
 @example
-grep -l 'main' *.c
+grep -l -- 'main' *.c
 @end example
 
 @noindent
@@ -1630,45 +1698,33 @@ grep -r 'hello' /home/gigi
 searches for @samp{hello} in all files
 under the @file{/home/gigi} directory.
 For more control over which files are searched,
-use @command{find}, @command{grep}, and @command{xargs}.
+use @command{find} in combination with @command{grep}.
 For example, the following command searches only C files:
 
 @example
-find /home/gigi -name '*.c' -print0 | xargs -0r grep -H 'hello'
+find /home/gigi -name '*.c' -exec grep -H 'hello' '@{@}' +
 @end example
 
 This differs from the command:
 
 @example
-grep -H 'hello' *.c
+grep -H -- 'hello' *.c
 @end example
 
-which merely looks for @samp{hello} in all files in the current
-directory whose names end in @samp{.c}.
+which merely looks for @samp{hello} in all (non-hidden) files in
+the current directory whose names end in @samp{.c}.
 The @samp{find ...} command line above is more similar to the command:
 
 @example
-grep -rH --include='*.c' 'hello' /home/gigi
+grep -r --include='*.c' 'hello' /home/gigi
 @end example
 
-@item
-What if a pattern has a leading @samp{-}?
-
-@example
-grep -e '--cut here--' *
-@end example
-
-@noindent
-searches for all lines matching @samp{--cut here--}.
-Without @option{-e},
-@command{grep} would attempt to parse @samp{--cut here--} as a list of
-options.
 
 @item
 Suppose I want to search for a whole word, not a part of a word?
 
 @example
-grep -w 'hello' *
+grep -H -w -- 'hello' *
 @end example
 
 @noindent
@@ -1679,7 +1735,7 @@ For more control, use @samp{\<} and
 For example:
 
 @example
-grep 'hello\>' *
+grep -H -- 'hello\>' *
 @end example
 
 @noindent
@@ -1690,38 +1746,17 @@ searches only for words ending in @samp{hello}, so it matches the word
 How do I output context around the matching lines?
 
 @example
-grep -C 2 'hello' *
+grep -H -C 2 -- 'hello' *
 @end example
 
 @noindent
 prints two lines of context around each matching line.
 
-@item
-How do I force @command{grep} to print the name of the file?
-
-Append @file{/dev/null}:
-
-@example
-grep 'eli' /etc/passwd /dev/null
-@end example
-
-gets you:
-
-@example
-/etc/passwd:eli:x:2098:1000:Eli Smith:/home/eli:/bin/bash
-@end example
-
-Alternatively, use @option{-H}, which is a GNU extension:
-
-@example
-grep -H 'eli' /etc/passwd
-@end example
-
 @item
 Why do people use strange regular expressions on @command{ps} output?
 
 @example
-ps -ef | grep '[c]ron'
+ps -Af | grep '[c]ron'
 @end example
 
 If the pattern had been written without the square brackets, it would
@@ -1788,6 +1823,9 @@ Use the special file name @samp{-}:
 cat /etc/passwd | grep 'alain' - /etc/motd
 @end example
 
+To match in a file called @samp{-} in the current directory, use
+@samp{./-}.
+
 @item
 @cindex palindromes
 How to express palindromes in a regular expression?
diff --git a/gnulib b/gnulib
--- a/gnulib
+++ b/gnulib
@@ -1 +1 @@
-Subproject commit 575b0ecbad2f34d5777f9562eebc2d0c815bfc5c
+Subproject commit 575b0ecbad2f34d5777f9562eebc2d0c815bfc5c-dirty