ExecuteExternalCommand

Last major edit (later minor edits)

Summary: Fixed broken link

Added:

> [new:PhilHudson:2014-10-06 09:22 UTC]
> I don't know of a way to do exactly what you ask for -- I'm not even sure what it would look like, given that in this scenario Emacs "owns" the terminal and the parent shell process is presumably blocking until Emacs either exits or (as you have indicated) suspends -- but if you use a terminal multiplexer like GnuScreen or [http://tmux.sourceforge.net/ tmux] there are various Emacs Lisp packages and utilities in this wiki's [[ElispArea]] and in the various ELPA-like [[http://www.emacswiki.org/emacs/CategoryPackaging#toc1 package repositories]] which enable Emacs to communicate with, and control, a shell -- or indeed any other process -- running in one of the (other) virtual terminals managed by screen/tmux.


Executing External Commands

You can execute an external shell command from within Emacs using `M-!’ (‘shell-command’). The output from the shell command is displayed in the minibuffer or in a separate buffer, depending on the output size.

When used with a prefix argument (e.g, `C-u M-!’), the shell-command output is inserted in the current buffer at point.

To provide the region text to the shell command as input, use `M-|’ (‘shell-command-on-region’). If you want the shell to replace the region text with the output from the shell command, use `C-u M-|’.

Buffer ‘*Shell Command Buffer*’ is displayed briefly whenever you run a shell command. You can switch to that buffer using ‘C-x b’.

Using the whole buffer

If you are programming using an interpreted language, such as Perl or Python, or a shell script, such as BASH, you might want to run your entire program through the interpreter. To do that, use ‘C-x h’ (‘mark-whole-buffer’), then use `M-|’ to send all of the buffer text to the interpreter.

This function runs a command with the whole buffer as input:

(defun shell-command-on-buffer ()
  "Asks for a command and executes it in inferior shell with current buffer
as input."
  (interactive)
  (shell-command-on-region
   (point-min) (point-max)
   (read-shell-command "Shell command on buffer: ")))

You can also bind this function with a key:

(global-set-key (kbd "M-\"") 'shell-command-on-buffer)

TAB Completion for `M-!' and `M-|'

Starting with Emacs 23, ‘TAB’ completion is available for `M-!’ and `M-|’. The following libraries provide such a feature for earlier Emacs versions:

Icicles Completion for `M-!' and `M-|'

Icicles enhances the vanilla ‘TAB’ completion for `M-!’ and `M-|’. Whenever there are two or more candidate completions, you can use any Icicles completion features (cycling, progressive completion, apropos completion, and so on). See Icicles - Completion in Comint Modes.

Running a Shell Command Asynchronously

You can run a shell command asynchronously by adding an ampersand (&) after it, if you have a UNIX or UNIX-like environment.

Here is a some EmacsLisp code that modifies ‘shell-command’ to allow many commands to execute asynchronously (and show the command at the top of the buffer):

(defadvice erase-buffer (around erase-buffer-noop)
  "make erase-buffer do nothing")

(defadvice shell-command (around shell-command-unique-buffer activate compile)
  (if (or current-prefix-arg
          (not (string-match "[ \t]*&[ \t]*\\'" command)) ;; background
          (bufferp output-buffer)
          (stringp output-buffer))
      ad-do-it ;; no behavior change

    ;; else we need to set up buffer
    (let* ((command-buffer-name
            (format "*background: %s*"
                    (substring command 0 (match-beginning 0))))
           (command-buffer (get-buffer command-buffer-name)))

      (when command-buffer
        ;; if the buffer exists, reuse it, or rename it if it's still in use
        (cond ((get-buffer-process command-buffer)
               (set-buffer command-buffer)
               (rename-uniquely))
              ('t
               (kill-buffer command-buffer))))
      (setq output-buffer command-buffer-name)

      ;; insert command at top of buffer
      (switch-to-buffer-other-window output-buffer)
      (insert "Running command: " command
              "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n")

      ;; temporarily blow away erase-buffer while doing it, to avoid
      ;; erasing the above
      (ad-activate-regexp "erase-buffer-noop")
      ad-do-it
      (ad-deactivate-regexp "erase-buffer-noop"))))

Asynchronous Processes

Another way to run commands asynchronously, without Emacs stopping at all when the process is started, is using [1].

Execute.el

There is a little library called Execute.el that redefines `M-!’ key for executing various external process. If you have problems when you want to execute two or more programs using `M-!’ or `M-&’, you may want to try this.

Dizzee

Alternatively, you can use the package Dizzee at [[2]]. The Dizzee package allows you to name various asynchronous subprocesses, and allows you to start, stop and reload them as needed. Also, there is the concept of process groups, which allows you to group together like processes. (For instance, you might have a “webdev” process group, which would start up an apache server, tomcat server, mysql, etc. etc.)

Executing external programs as their own process

Both commands result in the child process being killed when emacs is shutdown. For a command to have the ability to stay alive past that point you’ll need to use call-process to start the program as its own distinct process.

(call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)

Setting BUFFER to 0 runs the program asynchronously, while nil will wait for the process to exits before resuming emacs.

Discussion

Parent shell

When running Emacs in a terminal (with emacs -nw), is it possible to execute a command in the parent shell without suspending Emacs? I know that one can press ‘C-z’, type a command and then resume Emacs with fg, but I would like to communicate with the parent shell from “within” Emacs. – VegardOye

I don’t know of a way to do exactly what you ask for – I’m not even sure what it would look like, given that in this scenario Emacs “owns” the terminal and the parent shell process is presumably blocking until Emacs either exits or (as you have indicated) suspends – but if you use a terminal multiplexer like GnuScreen or tmux there are various Emacs Lisp packages and utilities in this wiki’s ElispArea and in the various ELPA-like package repositories which enable Emacs to communicate with, and control, a shell – or indeed any other process – running in one of the (other) virtual terminals managed by screen/tmux.

Return output as a string

Is there a built-in function that returns the output of a shell command as a string? For instance:

    (message (WHATEVER "echo the message"))

Would display the message:

    the message

In the status bar?

In XEmacs, use ‘exec-to-string’ and in GnuEmacs, use ‘shell-command-to-string’. For example:

 (message (exec-to-string "pwd"))
 ;; or
 (insert (exec-to-string "ls /etc"))

This executes the command in some kind of shell, and (some) normal shell magic happens:

(shell-command-to-string "echo -test! $x-")
"-test! -
"

In this case, command history is not accessed with `!’, but the shell variable ‘x’ is looked up and replaced with a space char. You can quote each “word” in your command seperately, and run the result, like this:

(defun execvp (&rest args)
  "Simulate C's execvp() function.
Quote each argument seperately, join with spaces and call shell-command-to-string to run in a shell."
  (let ((cmd (mapconcat 'shell-quote-argument args " ")))
    (shell-command-to-string cmd)))

Then, calling (execvp "touch" "'a'" "b" "$x") creates files called ‘a’, ‘b’, and `$x’ in whatever directory you happen to be in.

Automatically close the output buffer

Is it possible (desirable?) to automatically close buffer *Shell Command Output* for commands that report ‘Shell command succeeded with no output’?

Passwords

How can you use ‘shell-command’ with programs that require input such as passords? Kind of annoying having to open a new buffer just to ‘scp’ a file.

Answer:

;;Don't echo passwords when communicating with interactive programs:
(add-hook 'comint-output-filter-functions 'comint-watch-for-password-prompt)

See Also


CategoryExternalUtilities