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,689
  • 4
  • 38
  • 84
  • 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
    Possible duplicate of [How can I run an async process in the background without popping up a buffer?](https://emacs.stackexchange.com/questions/299/how-can-i-run-an-async-process-in-the-background-without-popping-up-a-buffer) – Basil May 10 '18 at 15:10

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,012
  • 29
  • 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,095
  • 1
  • 13
  • 25
  • 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
  • 21,803
  • 1
  • 65
  • 97
  • Using `(setq display-buffer-alist '(("\\`\\*Async Shell Command\\*\\'" display-buffer-no-window)))` I get the error `apply: 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 executing `my-view-pdf`, emacs splits the window and `*Async 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
  • [Link to a similar QnA thread on emacs.SE](http://emacs.stackexchange.com/a/5554/115) – Kaushal Modi Jul 06 '15 at 13:56