Emacs Lisp Idioms for Text Processing in Batch Style
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)
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
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:
- How to Write grep in Emacs Lisp
- Emacs Lisp: Generate Web Links Report
- Emacs Lisp: Create Sitemap
- Emacs Lisp: Batch Transform HTML to HTML5 “figure” Tag
- Emacs Lisp: Batch Script to Validate Matching Brackets
( Thanks to Rubén Berenguel for a correction.) ( thx to Phil Hudson for a tip.)
or, buy something from my keyboard store.