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 and Directory 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 and Directory Manipulation

Commonly used functions to manipulate files and directorys.

(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: Open File in External App.

(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.)

Like it? Buy Xah Emacs Tutorial. Thanks.

or, buy something from Best Keyboard for Emacs