Elisp: Start External Process
Start External Process, Wait for it to Finish. Input from File or None
call-process-
(call-process PROGRAM &optional INFILE DESTINATION DISPLAY &rest ARGS)Call PROGRAM in separate process, wait for it to finish. (unless DESTINATION is 0). PROGRAM is searched in exec-path
Return the exist status of the external program. (typically, unix commands return 0 if successful. In emacs, that 0 is returned as integer.)
- INFILE
nilor a filepath. The content is passed to stdin. - DESTINATION is a buffer for output (including standard error.).
- Or
tfor current buffer. - Or
nilfor discard output. - Or
0for don't wait for the program to terminate. - Or
(:file FILE) means write to file. (overwrite existing) - Or
(REAL-BUFFER STDERR-FILE). (See elisp manual.)
- Or
- DISPLAY non-nil means redisplay buffer as output is inserted.
- ARGS are strings passed as command arguments to PROGRAM. (each is a string).
If you have a list, use
apply. 〔see Elisp: Apply Function (List to Args), identity〕
;; example of call-process on linux ;; passing it a file path (cond ((eq system-type 'gnu/linux) (call-process shell-file-name nil 0 nil shell-command-switch (format "xdg-open %s" (file-name-directory buffer-file-name))))) Example. Unknown Number of Args
;; example of call-process when you need to feed it a lot file names, known at runtime ;; the file names is a list ;; besides filenames, you may have many args. make it a list ;; then use append to join them ;; then use apply to feed it to call-process as args (let ((xoutbuf (get-buffer-create "*my output*"))) (apply 'call-process (append (list "exiftool" nil xoutbuf t "-all=" "-overwrite_original") xfilelist nil))) more examples:
- INFILE
Start External Process, Wait for it to Finish. Input from Region to STDIN
call-process-region-
(call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &rest ARGS)Call a external program, send input to stdin. Wait for it to finish.
Return the exist status of the external program. (typically, unix commands return 0 if successful. In emacs, that 0 is returned as integer.)
- START and END are region positions. If START is string, use that and ignore END.
- PROGRAM is the program name to call. If not full file path, search in exec-path
- DELETE if true, delete the input region.
- BUFFER is the buffer to display output. If BUFFER is 0, returns immediately with value nil. Can also be a list of 2 items, one for STDOUT and one for STDERR. But STDERR must be a file. See doc.
- DISPLAY if true, update buffer as input comes in.
- ARGS the args passed to the external command.
💡 TIP: Don't blindly set DELETE to true because the external program may fail. Best to check the external program exit status first. If success, replace region with its output.
💡 TIP: For some external program, you can pass the command as STDIN. e.g. PowerShell. That way, you don't have to deal with complicated string escape.
;; 2024-12-22 ;; call powershell to list dir ;; if you use shell-command, emacs calls cmd.exe ;; but you want to call powershell ;; it's very difficult if the argument is a complicated string involving quote or backslashes or in filename arguments ;; best solution, is use call-process-region, and passing the powershell args as stdin ;; powershell can take stdin as args. by ;; powershell -Command - (let ((xoutbuf (get-buffer-create "*my PowerShell output*"))) (call-process-region (format "dir %s" (expand-file-name "~/Downloads/")) nil "powershell" nil xoutbuf t "-Command" "-") (display-buffer xoutbuf)) ;; 2024-11-23 ;; example of calling powershell .net to get image width and height ;; if you use shell-command, emacs calls cmd.exe ;; but you want to call powershell ;; it's very difficult if the argument is a complicated string involving quote or backslashes or in filename arguments ;; best solution, is use call-process-region, and passing the powershell args as stdin (let ((my-img-path (expand-file-name "~/Downloads/2024-10-18_image.jpg")) (xoutbuf (get-buffer-create "*my PowerShell output*")) xcmd xoutput ) (setq xcmd (concat "Add-Type -AssemblyName System.Drawing; $ximg=[System.Drawing.Image]::FromFile('" my-img-path "'); Write-Output $ximg.Width , $ximg.Height " )) (call-process-region xcmd nil "PowerShell" nil xoutbuf t "-Command" "-") (setq xoutput (with-current-buffer xoutbuf (buffer-string))) ;; (pop-to-buffer xoutbuf) (kill-buffer xoutbuf) (split-string xoutput)) ;; sample output ;; ("4032" "3024")
Start External Process, No Wait
start-process-
(start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)Start a program in a subprocess. (do not wait for it to finish) Return the process object for it.
- NAME is name for process. Can be any.
- BUFFER is the buffer (or buffer name)
for process output (both standard output and standard error streams).
Or
nil. - PROGRAM is the program file name to start. It is searched for in exec-path. If nil, just associate a pty with the buffer.
- PROGRAM-ARGS are arguments (each is a string).
If you have a list, use
apply. 〔see Elisp: Apply Function (List to Args), identity〕
;; 2024-11-25 ;; example of opening a file on windows using default app (let ((xpath (expand-file-name "~/Downloads/2024-10-18_image.jpg")) (xoutbuf (get-buffer-create "*my output*")) (xcmdlist (list "PowerShell" "-Command" "Invoke-Item" "-LiteralPath"))) (apply 'start-process (append (list "xah open file" xoutbuf) xcmdlist (list xpath) nil))) ;; example of start-process when you need to feed it a lot file names, known at runtime (let ((xoutbuf (get-buffer-create "*my output*"))) (let ((process-connection-type nil)) (apply 'start-process (append (list "exiftool" xoutbuf "exiftool" "-all=" "-overwrite_original") FileList nil)))) ;; example of start-process ;; open a list of files in windows default app (cond ((eq system-type 'windows-nt) (let ((xoutbuf (get-buffer-create "*my open in external app*")) (xcmdlist (list "PowerShell" "-Command" "Invoke-Item" "-LiteralPath"))) (mapc (lambda (x) (message "%s" x) (apply 'start-process (append (list "my open in external app" xoutbuf) xcmdlist (list (format "'%s'" (if (string-match "'" x) (replace-match "`'" t t x) x))) nil))) xfileList))) (t nil)) start-process-shell-command-
(start-process-shell-command NAME BUFFER COMMAND)similar to
start-process, but starting a shell to start the command. make-process-
(make-process &rest ARGS)The core function for creating process. similar to
start-process. See elisp manual.
call-process vs shell-command
Advantage of call-process
- It is more efficient to launch external app directly than launch a shell to launch it.
- No need to deal with complicated string escapes in args or file name, involving apostrophe, quote, backslash.
- Much more flexible in controlling input and output and argument passing.
Disadvantage is that you need to handle the process and output, and a bit harder to code.
Advantage of shell-command
- Much easier to code a
shell-commandcall. - Shell command is more compatible across different operating systems, e.g. Microsoft Windows vs linux and MacOS.