How to Write grep in Emacs Lisp

Master emacs+lisp, benefit for life. Testimonials. Thank you for support.
, , …,

This page shows you how to write a emacs lisp script to search files, similar to unix grep.

Problem Description

I want to write a elisp script that reports files in a dir that contain a string n times. The script is expected to search thru 5 thousand files.

Solution

Here's a very simple version. It reports number of matches.

;; -*- coding: utf-8 -*-
;; 2010-03-27
;; print file names of files that have n occurrences of a string, of a given dir

;; input dir
(setq inputDir "~/web/" )

;; add a ending slash if not there. In elisp, dir path should end with a slash
(when (not (string= "/" (substring inputDir -1) ))
  (setq inputDir (concat inputDir "/") )
  )

(defun my-process-file (fPath)
  "Process the file at FPATH …"
  (let (myBuffer p1 p2 (ii 0) searchStr)
    (when
        (and (not (string-match "/xx" fPath)) ) ; exclude some dir

      (with-temp-buffer
        (insert-file-contents fPath nil nil nil t)

        (setq searchStr "somesearchstring" ) ; search string here

        (goto-char 1)
        (while (search-forward searchStr nil t)
          (setq ii (1+ ii))
          )

        ;; report if the occurrence is not n times
        (if (not (= ii 0))
            (princ (format "this many: %d %s\n" ii fPath))
          )))))

;; traverse the dir

(require 'find-lisp)

(let (outputBuffer)
  (setq outputBuffer "*my occur output*" )
  (with-output-to-temp-buffer outputBuffer
    (mapc 'my-process-file (find-lisp-find-files inputDir "\\.html$"))
    (princ "Done deal!")
    )
  )

The code is pretty simple. At the bottom, the code visits every file in a dir. For each file, it calls (my-process-file fPath). The “my-process-file” function creates a temp buffer, inserts the file content in it, then do search inside the temp buffer. We do this because it's faster.

(with temp buffer, emacs doesn't do syntax-coloring (which is very slow), disables undo, or any other thing emacs normally do when opening a file for interactive edit.)

To run the file, you can call eval-buffer or load-file. 〔☛ Emacs: How to Evaluate Emacs Lisp Code〕 〔☛ Emacs Lisp: Execute/Compile Current File

The elisp idioms used in this script are explained at: Text Processing with Emacs Lisp Batch Style.

On 5k files, the script takes 20 seconds on a average year 2011 computer.

Why can't i just call the unix grep command?

See: Problems of Calling Unix grep in Emacs.

Note

For the full version of this command, see the package xah_file_util.el at http://code.google.com/p/ergoemacs/source/browse/packages/xah_file_util.el

For applications of this script, with slight variations, see:

For simple example of writing grep/sed/awk in Python and Perl, see:

Like what you read?
Buy Xah Emacs Tutorial
or share some
blog comments powered by Disqus