10

Is it possible to run a shell command silently (in background)? When I use async-shell-command, emacs split the windows. I would like that an specific shell command to be totally in background (without any visual effect).

As an explicit example, I have the following code (borrowed from https://emacs.stackexchange.com/a/7932). It opens the pdf version of the tex-file I working on. When running it, it splits the window, I would like to prevent it from this behavior in this particular situation.

 (defun my-view-pdf ()
  (interactive)
  (async-shell-command
    (concat "SumatraPDF " (file-name-base (buffer-file-name)) ".pdf")))
Name
  • 7,849
  • 4
  • 41
  • 87
  • 3
    Not about the abstract question, but the specific use case: Are you using AUCTeX? Any particular reason you're not using TeX-view (C-c C-v)? – Dan Jul 03 '15 at 15:29
  • @Dan the problem is that when I do C-c C-v nothing happens. I don't understand why. If you know a simple customization in the .emacs which makes C-c C-v works , I would be happy to use it. My OS is Windows and my pdf viewer is located at C:\Program Files\SumatraPDF\sumatrapdf.exe. In that link lawlist has provided a comprehensive link. I am only interested to make TeX-viewer works. – Name Jul 03 '15 at 19:26
  • Not on Windows, so can't say why you're having problems. You might try working with TeX-view-program-list. – Dan Jul 03 '15 at 19:31
  • This question has very good answers so I will hate for this to get closed. But this is a duplicate of this question: http://emacs.stackexchange.com/q/5553/115 – Kaushal Modi Jul 06 '15 at 13:52
  • 4

3 Answers3

10

save-window-excursion is a macro for running a piece of code without altering the window configuration. Something like this should work:

 (defun my-view-pdf ()
  (interactive)
  (save-window-excursion
   (async-shell-command
     (concat "SumatraPDF " (file-name-base (buffer-file-name)) ".pdf"))))

Note the warning in the docstring of save-window-excursion:

BEWARE: Most uses of this macro introduce bugs.
E.g. it should not be used to try and prevent some code from opening a new window, since that window may sometimes appear in another frame, in which case save-window-excursion cannot help.

In this case I think it should be fine, though, as it is an interactive function that doesn't really interact with any other code.

legoscia
  • 6,072
  • 30
  • 54
  • Nice macro, I confirm that your solution works. – Name Jul 03 '15 at 15:19
  • 2
    @legoscia You were looking for save-window-excursion, which is nearly identical to your implementation. – bmag Jul 04 '15 at 06:50
  • @bmag I am interested to know about the difference between save-window-excursion and save-window-configuration. It seems that both work in this situation. – Name Jul 07 '15 at 09:21
  • 1
    @Name No difference, except that save-window-excursion uses some macro best practices to avoid introducing variables into the environment of the body. Also, save-window-excursion is built-in to Emacs. I was looking for that macro, but didn't find it, so I wrote my own version. Fortunately bmag knew the real one. – legoscia Jul 07 '15 at 09:29
10

If you just would like to spawn a process in the background you don't need all the bells an whistles that shell command functions provide.

Instead, you can use the function call-process. For example:

(call-process
 "a_command"
 nil
 0                                  ; <- Discard and don't wait
 nil
 "arg1"
 "arg2")

Concretely, this mean that you can implement you command as:

(defun my-view-pdf ()
    (interactive)
    (call-process "SumatraPDF" nil 0 nil
                  (concat (file-name-base (buffer-file-name)) ".pdf")))
Lindydancer
  • 6,150
  • 1
  • 15
  • 26
  • I tried to apply your suggestion for my specific example (defun my-pdf-viewer () (interactive) (call-process (async-shell-command (concat "SumatraPDF " (file-name-base (buffer-file-name)) ".pdf")) nil 0 ; <- Discard and don't wait nil "arg1" "arg2") ) I get the error Wrong type argument: stringp, comint-output-filter. I am not sure if the syntax I used is correct. – Name Jul 03 '15 at 20:52
  • You should drop async-shell-command all together. It should be something like (defun my-pdf-viewer () (interactive) (call-process "SumatraPDF" nil 0 nil (concat (file-name-base (buffer-file-name)) ".pdf")). – Lindydancer Jul 03 '15 at 20:58
  • 1
    Thank you, your solution works perfectly, there was only a missing brace, so the correct code should be : (defun my-view-pdf () (interactive) (call-process "SumatraPDF" nil 0 nil (concat (file-name-base (buffer-file-name)) ".pdf"))). – Name Jul 03 '15 at 21:05
  • @Name, thanks, I've updated the answer to include the concrete function. – Lindydancer Jul 06 '15 at 09:01
8

Use display-buffer-alist with the display-buffer-no-window if you're on Emacs 24.4 or later.

(setq display-buffer-alist '(("\\`\\*Async Shell Command\\*\\'" display-buffer-no-window)))

Alternatively, use shackle:

(setq shackle-rules '(("*Async Shell Command*" :ignore t)))
wasamasa
  • 22,178
  • 1
  • 66
  • 99
  • Using (setq display-buffer-alist '(("\\\*Async Shell Command\*\'" display-buffer-no-window)))I get the errorapply: Wrong type argument: sequencep, display-buffer-no-window`. – Name Jul 03 '15 at 15:35
  • Oh right, display-buffer-no-window was introduced in Emacs 24.4, so that won't work. My package on the other hand should work on 24.3. – wasamasa Jul 03 '15 at 15:38
  • Backporting display-buffer-no-window is a third option, just insert (defun display-buffer-no-window (_buffer alist) (when (cdr (assq 'allow-no-window alist)) 'fail)) in your Emacs configuration. – wasamasa Jul 03 '15 at 20:32
  • I tried to apply your last comment by putting the things all together `(defun display-buffer-no-window (_buffer alist) (when (cdr (assq 'allow-no-window alist)) 'fail))

    (setq display-buffer-alist '(("\`\*Async Shell Command\*\'" display-buffer-no-window)))

    (defun my-view-pdf () (interactive) (progn (async-shell-command (concat "SumatraPDF " (file-name-base (buffer-file-name)) ".pdf")))) . But after executingmy-view-pdf, emacs splits the window andAsync Shell Command` is shown.

    – Name Jul 03 '15 at 21:38
  • I confirm that your solution perfectly works for the version 24.4 or later. – Name Jul 04 '15 at 11:40