1- import sys
21import argparse
3- import re
42from collections import deque
3+ import fnmatch
4+ import os
5+ import re
6+ import sys
57
68
79def find (patterns , line ):
@@ -188,6 +190,15 @@ def make_parser():
188190 grp .add_argument ('-C' , '--context' ,
189191 type = int , default = 0 , metavar = 'NUM' ,
190192 help = 'Print NUM lines of output context.' )
193+
194+ grp = parser .add_argument_group ('File and Directory Selection' )
195+ grp .add_argument ('-r' , '--recursive' ,
196+ action = 'store_true' ,
197+ help = 'Read all files under each directory, recursively.' )
198+ grp .add_argument ('--include' ,
199+ action = 'append' ,
200+ metavar = 'GLOB' ,
201+ help = 'Search only files whose base name matches GLOB (using wildcard matching).' )
191202 return parser
192203
193204def parse_args ():
@@ -229,13 +240,35 @@ def compile_patterns(opts):
229240 flags = re .IGNORECASE if opts .ignore_case else 0
230241 return [re .compile (pat , flags ) for pat in patterns ]
231242
243+ def filter_file (opts , filename ):
244+ return not opts .include or any (fnmatch .fnmatch (filename , pat )
245+ for pat in opts .include )
246+
247+ def iter_files (opts ):
248+ for arg in opts .files or ['-' ]:
249+ if arg == '-' :
250+ yield None
251+ elif os .path .isfile (arg ):
252+ if filter_file (opts , os .path .basename (arg )):
253+ yield arg
254+ elif os .path .isdir (arg ):
255+ if not opts .recursive :
256+ print (f'error: { arg !r} is a directory' , file = sys .stderr )
257+ continue
258+ for dirpath , dirnames , filenames in os .walk (arg ):
259+ for filename in filenames :
260+ if filter_file (opts , filename ):
261+ yield os .path .join (dirpath , filename )
262+ else :
263+ print (f'error: { arg !r} has unsupported type' , file = sys .stderr )
264+
232265def main ():
233266 opts = parse_args ()
234267 patterns = compile_patterns (opts )
235268
236269 found = False
237- for filename in opts . files or [ '-' ] :
238- if filename == '-' :
270+ for filename in iter_files ( opts ) :
271+ if filename is None :
239272 found |= grep (opts , patterns , sys .stdin , opts .label )
240273 else :
241274 with open (filename , encoding = sys .stdin .encoding ,
@@ -252,6 +285,6 @@ def main():
252285 except SystemExit :
253286 raise
254287 except BaseException as e :
255- print (f'error: { e !r} ' )
288+ print (f'error: { e !r} ' , file = sys . stderr )
256289 sys .exit (2 )
257290 sys .exit (0 if found else 1 )
0 commit comments