Elisp: Start External Process
Start External Process, Wait for it to Finish
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
- INFILE nil or a filepath. The content is passed to stdin. Use
call-process-region
if you want to pass a region from buffer. - DESTINATION is a buffer for output (including standard error.).
- Or t for current buffer.
- Or nil for discard output.
- Or
0
for 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.)
- 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)〕
;; example of call-process on linux ;; passing it a file path (cond ((eq system-type 'windows-nt) nil) ((eq system-type 'darwin) nil) ((eq system-type 'gnu/linux) (call-process shell-file-name nil 0 nil shell-command-switch (format "%s %s" "xdg-open" (file-name-directory xpath)))))
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") FileList nil)))
more examples:
- INFILE nil or a filepath. The content is passed to stdin. Use
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.
- START and END are region positions. If START is string, use that. 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.
- DISPLAY if true, update buffer as input comes in.
- ARGS the args passed to the external command.
;; 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)〕
;; 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-command
call. - Shell command is more compatible across different operating systems, e.g. Microsoft Windows vs linux and MacOS.