Elisp: Writing Elisp Script
This page shows common programing solutions of emacs lisp for batch text processing. Typically the type of tasks one would do in unix shell tools or Python, Ruby . 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.
Run Emacs Lisp Script in Shell
Read / Write to File
Read-Only Text Processing
To process thousands of files, read only, use
(defun my-process-file (fPath) "Process the file at path FPATH …" (with-temp-buffer (insert-file-contents fPath) ;; process it … ))
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.
If you want to change every file you opened, use
(defun my-process-file (fPath) "Process the file at path FPATH …" (with-temp-file fPath (insert-file-contents fPath) ;; process text code here ))
If you want to write to file ONLY when you actually changed the file, you can create flag variable and Alt+x
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)))))
Read File Content as String or List of Lines
File and Directory 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 and Directory Manipulation
Commonly used functions to manipulate files and directories.
(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 (buffer-file-name)) backupName ) (if (null fname) (message "current buffer is not a file.") (progn (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
Call Shell Command
Call a shell command, wait for it to finish before continuing, use
; call a shell command (shell-command "cp /somepath/myfile.txt /somepath") ; call 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's a example:
;; open files in Linux desktop (mapc (lambda (x) (let ((process-connection-type nil)) (start-process "" nil "xdg-open" x)) ) filePathList)
For detail, see: Emacs: Open File in External App.
Get Command Line Arguments
To get arguments passed from the command line, use the built-in variable argv.
Print, Princ, Prin1, Format, Message
For some practical examples of batch style text processing, see:
- How to Write grep in Emacs Lisp
- Elisp: Generate Web Links Report
- Elisp: Create Sitemap
- Elisp: Batch Transform HTML to HTML5 “figure” Tag
- Elisp: Batch Script to Validate Matching Brackets
( Thanks to Rubén Berenguel for a correction.) ( thx to Phil Hudson for a tip.)
If you have a question, put $5 at patreon and message me.