grep is the name of a common filesystem utility on many Unix or unix like systems.
Folklore says that the name represents a command that developers in the old days used to issue within their editor or other similar program:
g/re/p
which was a global {regular expression} print command.
Grep reads through one or more input streams (stdin or files), searching for a string of text which represents some for of a regular expression, and, depending on options provided, may produce the matching lines of input.
RS wrote this tiny, and feature-poor, emulation for use on PocketPC (but it should run elsewhere too):
proc grep {re args} { set files [eval glob -types f $args] foreach file $files { set fp [open $file] while {[gets $fp line] >= 0} { if [regexp -- $re $line] { if {[llength $files] > 1} {puts -nonewline $file:} puts $line } } close $fp } } # Test: catch {console show} puts "Result:\n[grep "require" "*.tcl"]"
Here's another version - I wrote this out of desperation because the real grep -f ate up all my memory, and then busted, under Cygwin (remove the leading blank in the # line for an executable script):
#!/usr/bin/env tclsh proc main argv { set usage {usage: grep-f.tcl refile ?file...? > outdata} if {[llength $argv] < 1} {puts $usage; exit} set fp [open [lindex $argv 0]] set REset [split [string trim [read $fp]] \n] close $fp if {[llength $argv] == 1} { grep-f $REset stdin } else { foreach file [lrange $argv 1 end] { set fp [open $file] grep-f $REset $fp close $fp } } } proc grep-f {REset fp} { while {[gets $fp line] >= 0} { foreach RE $REset { if {[regexp $RE $line]} { puts $line break } } } } main $argv
JM we can change the target-file selection to use wild cards (instead of listing each file) if we take some code from RS above:
#!/usr/bin/env tclsh proc main argv { set usage {usage: grep-f.tcl refile ?file...? > outdata} if {[llength $argv] < 1} {puts $usage; exit} set fp [open [lindex $argv 0]] set REset [split [string trim [read $fp]] \n] close $fp if {[llength $argv] == 1} { grep-f $REset stdin } else { set files [eval glob -types f [lindex $argv 1]] foreach file $files { puts "============" set fp [open $file] grep-f $REset $fp close $fp } } } proc grep-f {REset fp} { while {[gets $fp line] >= 0} { foreach RE $REset { if {[regexp $RE $line]} { puts $line break } } } } main $argv
(this was moved here from Example Scripts Everybody Should Have
DKF: Grep does an awful lot of different things, and implementing a full version of it is probably a worthy topic for a Wiki page to itself. Here's something to get you started...
proc grep {pattern args} { if {[llength $args] == 0} { # read from stdin set lnum 0 while {[gets stdin line] >= 0} { incr lnum if {[regexp $pattern $line]} { puts "${lnum}:${line}" } } } else { foreach filename $args { set file [open $filename r] set lnum 0 while {[gets $file line] >= 0} { incr lnum if {[regexp $pattern $line]} { puts "${filename}:${lnum}:${line}" } } close $file } } }
FP: This slightly modified code is now included in Tcllib
package require tcllib set listOfMatches [fileutil::grep $_pattern] ;# (stdin input) set listOfMatches [fileutil::grep $_pattern $_fileList]
RS: Hmm.. I see duplication above... how about factoring that out, and make two little ones?
proc grep {pattern args} { if {[llength $args] == 0} { grep0 "" $pattern stdin } else { foreach filename $args { set file [open $filename r] grep0 ${filename}: $pattern $file close $file } } } proc grep0 {prefix pattern handle} { set lnum 0 while {[gets $handle line] >= 0} { incr lnum if {[regexp $pattern $line]} { puts "$prefix${lnum}:${line}" } } }
DKF: Adjusted to print the filename too; that's usually useful with grep...
ph: Small and simple.
proc grep {re {f stdin}} { for {set i 0} {[gets $f line] >= 0} {incr i} { if {[regexp $re $line]} { puts "$i:$line" } } }