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.
Emacs Lisp: Run Elisp Script in Shell
To process thousands of files, read only, use
(defun my-process-file (fPath) "Process the file at path FPATH …" (with-temp-buffer fPath (insert-file-contents fPath) ;; process it … ) )
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 ) (with-temp-buffer (insert-file-contents fPath) ;; process text … ;; set fileChanged-p to true/false (when fileChanged-p (write-region 1 (point-max) fPath) ) ) ) )
If you always need to change every file, use
Note: you should not use
write-file, because they have many side-effects and is slow.
See: Emacs Lisp Text Processing: find-file vs with-temp-buffer.
Emacs Lisp: Read File Content as String or List of Lines
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")
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))) ) )
Emacs Lisp: Get Script Name at Run Time, Call by Relative Path
Call a shell command, wait for it to finish before continuing, use
; 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-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")
In the following, “my-process-file” is a function that takes a file full path as input.
The “find-lisp-find-files” will generate a list of full paths, using a regex on file name.
mapc will apply the function to elements in a list.
; idiom for traversing a directory (require 'find-lisp) (mapc 'my-process-file (find-lisp-find-files "~/web/emacs/" "\\.html$"))
To get arguments passed from the command line, use the built-in variable argv. See: Getting Command Line Arguments.
Emacs Lisp: Functions for Processing Lines
Emacs Lisp: print, princ, prin1, format, message
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.)