Emacs Lisp Idioms for Text Processing in Batch Style

By Xah Lee. Date: . Last updated: .

This page shows common programing patterns of emacs lisp for batch text processing. Typically the type of tasks one would do in unix shell tools or Perl. For example, find/replace on a list of given files or dir, process (small sized) log files, compile a bunch of files, generating a report.

If you don't know elisp, see: Emacs Lisp Basics.

Run Emacs Lisp Script in Shell

Emacs Lisp: Run Elisp Script in Shell

Read / Write to File

Read-Only Text Processing

To process thousands of files, read only, use with-temp-buffer.

(defun my-process-file (fPath)
  "Process the file at path FPATH …"
  (with-temp-buffer
    (insert-file-contents fPath)
    ;; process it …
    ))

Modify Files

If you want to write to file ONLY when you actually changed the file, you can create flag variable and call write-region, like this:

(defun my-process-file (fPath)
  "Process the file at path FPATH …"
  (let ((fileChanged-p nil))
    (with-temp-buffer
      (insert-file-contents fPath)

      ;; process text
      ;; set fileChanged-p to t or nil

      (when fileChanged-p (write-region 1 (point-max) fPath)))))

If you always need to change every file, use with-temp-file.

Note: you should not use find-file or write-file, because they have many side-effects and is slow. See: Emacs Lisp Text Processing: find-file vs with-temp-buffer.

Read File Content as String or List of Lines

Emacs Lisp: Read File Content as String or List of Lines

File & Dir Manipulation

Filename Manipulation

Commonly used functions to manipulate file names.

(file-name-directory f)      ; get dir path
(file-name-nondirectory f)   ; get file name

(file-name-extension f)      ; get suffix
(file-name-sans-extension f) ; remove suffix

(file-relative-name f )      ; get relative path
(expand-file-name f )        ; get full path

default-directory       ; get the current dir (this is a variable)

(info "(elisp) File Names")

File & Dir Manipulation

Commonly used functions to manipulate files & dirs.

(file-exists-p FILENAME)

(rename-file FILE NEWNAME &optional OK-IF-ALREADY-EXISTS)

(copy-file FILE NEWNAME &optional OK-IF-ALREADY-EXISTS KEEP-TIME PRESERVE-UID-GID)

(delete-file FILE)

(set-file-modes FILE MODE)
;; get list of file names
(directory-files DIR &optional FULL MATCH NOSORT)

;; create a dir. Non existent paren dirs will be created
(make-directory DIR &optional PARENTS)

;; copy/delete whole dir
(delete-directory DIRECTORY &optional RECURSIVE) ; RECURSIVE option new in emacs 23.2
(copy-directory DIR NEWNAME &optional KEEP-TIME PARENTS) ; new in emacs 23.2

(info "(elisp) Files")

Example: make backup file.

(defun make-backup ()
  "Make a backup copy of current buffer's file.
Create a backup of current buffer's file.
The new file name is the old file name with trailing “~”, in the same dir.
If such a file already exist, append more “~”.
If the current buffer is not associated with a file, its a error."
  (interactive)
  (let (fName backupName)
    (setq fName (buffer-file-name))
    (setq backupName (concat fName "~"))

    (while (file-exists-p backupName)
      (setq backupName (concat backupName "~")))

    (copy-file fName backupName t)
    (message (concat "Backup saved as: " (file-name-nondirectory backupName)))))

Find the Current Elisp Script's File Name Programmatically

Emacs Lisp: Get Script Name at Run Time, Call by Relative Path

Call Shell Command

Call a shell command, wait for it to finish before continuing, use shell-command or shell-command-to-string.

; idiom for calling a shell command
(shell-command "cp /somepath/myfile.txt  /somepath")

; idiom for calling a shell command and get its output
(shell-command-to-string "ls")

Call a shell command, but don't wait for it to finish before continuing, use start-process or start-process-shell-command. Here a example:

;; open files in Linux desktop
(mapc
 (lambda (fPath)
   (let ((process-connection-type nil))
     (start-process "" nil "xdg-open" fPath)) )
 myFileList)

For detail, see: Emacs Dired: Opening Files in External Apps.

(info "(elisp) Asynchronous Processes")

Traverse Directory

Emacs Lisp: Traverse Directory

Get Command Line Arguments

To get arguments passed from the command line, use the built-in variable argv.

Emacs Lisp: Get Command Line Arguments

Process Lines

Emacs Lisp: Functions to Process Lines

Print, Princ, Prin1, Format, Message

Emacs Lisp: print, princ, prin1, format, message

Practical Examples

For some practical examples of batch style text processing, see:

( Thanks to Rubén Berenguel for a correction.) ( thx to Phil Hudson for a tip.)

or, buy something from my keyboard store.