21

My ~/.emacs contains the following settings for opening certain files with certain applications (Ubuntu 12.10; Emacs 24):

(setq dired-guess-shell-alist-user
      '(("\\.pdf\\'" "okular ? &")
    ("\\.djvu\\'" "okular ? &")
        ("\\.mp3\\'" "vlc ? &")
    ("\\.mp4\\'" "vlc ? &")
    ))

When I navigate to a .pdf in dired-mode and hit !, it opens the .pdf in Okular, but the dired-buffer is split into two parts, the second one now being a useless *Async Shell Command* buffer containing content like

okular(25393)/kdecore (KConfigSkeleton) KCoreConfigSkeleton::writeConfig:
okular(25393)/kdecore (KConfigSkeleton) KCoreConfigSkeleton::writeConfig:
okular(25393)/kdecore (KConfigSkeleton) KCoreConfigSkeleton::writeConfig:
okular(25393)/kdecore (KConfigSkeleton) KCoreConfigSkeleton::writeConfig:

How can I prevent this buffer from being opened? (except for, maybe, if there was an error and this information is useful).

I found related questions here and here, but they seem to deal with specific commands executed asynchronously, instead of the *Async Shell Command* in general (if possible, I would like to change the behaviour in general for asynchronous processes, not only for certain file types)

Community
  • 1
  • 1
Marius Hofert
  • 6,546
  • 10
  • 48
  • 102
  • Take a look at the actual functions inside the source of `.../lisp/simple.el` -- i.e., `defun shell-command` and `defun async-shell-command`. You can even create your own custom functions and/or use `defalias`. When using `start-process`, the second argument is the output buffer name -- using `nil` for the second argument prevents an output buffer from being created. You can use `set-process-sentinel` in conjunction with `start-process`. – lawlist Oct 03 '13 at 15:19
  • The doc string of `async-shell-command` states:  `... In Elisp, you will often be better served by calling 'start-process' directly, since it offers more control and does not impose the use of a shell (with its need to quote arguments).` – lawlist Oct 03 '13 at 15:30

8 Answers8

26

Found this here:

(call-process-shell-command "okular&" nil 0)

Works for me. No stderr gobbledygook.

Jackson
  • 9,188
  • 6
  • 52
  • 77
  • 1
    Actually this was the only answer that indeed full works: no log at messages and no weird popups. – Manoel Vilela May 13 '18 at 17:16
  • Could anyone elaborate on that? Do I put this function inside `dired-guess-shell-alist-user`? How? I just tried: `(add-to-list 'dired-guess-shell-alist-user '("\\.pdf$" (call-process-shell-command "evince" nil 0)))`, and it does not work - it opens evince, but not the file at point. – kotchwane May 23 '20 at 09:33
14

The question was asked in 2012, and at the time of my writing, the most recent answer is dated 2015. Now, in 2017, I can say that the answer is simple:

(add-to-list 'display-buffer-alist
  (cons "\\*Async Shell Command\\*.*" (cons #'display-buffer-no-window nil)))
juan.facorro
  • 9,791
  • 2
  • 33
  • 41
user1404316
  • 463
  • 6
  • 11
  • 2
    This still creates a buffer, but at least it doesn't pop into view and take up half of the screen. I'm sticking to this one, it's the simplest solution. – Nikaoto Jan 09 '19 at 21:32
6

I am piggybacking off of user1404316's answer, but here is another generic way to achieve the desired outcome.

(defun async-shell-command-no-window
    (command)
  (interactive)
  (let
      ((display-buffer-alist
        (list
         (cons
          "\\*Async Shell Command\\*.*"
          (cons #'display-buffer-no-window nil)))))
    (async-shell-command
     command)))
  • This is the simplest answer! Avoids the buffer only for specific commands. Used it to code the command that creates the TAGS file `(defun mktags-here () (interactive) ... (async-shell-command (message (format "ctags -e -R ."))))`. – Andreas Spindler Nov 07 '18 at 08:58
  • call-process-shell-command and adding an & to the command was the simplest for me. – RichieHH Jun 23 '21 at 12:14
1

I'm not entirely sure about doing it for asynchronous processes in general, but for anything that goes through async-shell-command, this should work:

    (defadvice async-shell-command (around hide-async-windows activate)
       (save-window-excursion
          ad-do-it))
Dan LaManna
  • 3,431
  • 4
  • 23
  • 35
  • But then you are forcing all uses of `async-shell-command` to lose the buffer. I'd think that would be overkill; there will certainly be situations where you do want to see the output. Changing the advice to add a parameter which specifies whether or not to do `save-window-excursion` should not be too hard, but then why use advice in the first place; use a simple wrapper function instead. – tripleee Dec 17 '12 at 04:40
  • ... I do realize OP asked for a fix to `async-shell-command` specifically, but the caveats for messing with it should be emphasized. – tripleee Dec 17 '12 at 04:47
  • This did not work for me. I still get the Async Shell Command buffer. – Marius Hofert May 17 '13 at 11:33
  • That's because `async-shell-command` calls `shell-command` to do its magic. – lawlist Oct 03 '13 at 15:26
1

Sadly there is no good way to avoid this buffer as it's called directly by 'shell-command' function ('async-shell-command' is just a wrapper).

So, a much better way is to replace 'async-shell-command' with 'start-process'. You should start process with 'set-process-sentinel' to detect the moment when process emits 'exit signal. Then kill process.

neutrico
  • 19
  • 1
  • start-process is fundamentally different in that you cant pass a SHELL command that executes in the context of the current directory. – RichieHH Feb 23 '20 at 12:30
0

A slightly more complicated incantation should get you what you want. Just use a shell command like: (okular ? >& /dev/null &).

I haven't tested this with okular, but I can do M-! ((echo foo; sleep 10; echo bar) >& /dev/null &) and Emacs returns immediately without creating a new buffer.

Sean
  • 29,130
  • 4
  • 80
  • 105
  • Nice. However, the *Async Shell Command* buffer still pops up (just empty now). If I try your `M-! ...` command, I get "shell command succeeded with no output" – Marius Hofert Dec 18 '12 at 12:24
0

I solved the problem, using this method:

;list of programs, corresponding to extensions
(setq alist-programs
      '(("pdf" ."okular")
        ("djvu" . "okular")
        ("mp3" . "xmms")))

(defun my-run-async-command (command file)
  "Run a command COMMAND on the file asynchronously.
   No buffers are created"
  (interactive
   (let ((file (car (dired-get-marked-files t current-prefix-arg))))
     (list
      ;last element of alist-programs, contains COMMAND
      (cdr
       (assoc
        (file-name-extension file)
        alist-programs))
      file)))
  ;begin of function body
  (if command ;command if not nil?
      (start-process "command" nil command file)
    )
)

;attach function to <f2> key
(add-hook 'dired-mode-hook
      (lambda ()
    (define-key dired-mode-map (kbd "<f2>") 'my-run-async-command)))
user4035
  • 22,508
  • 11
  • 59
  • 94
0

The suggestions to use start-process are ok if he is running a distinct program on the path of course. But if you want run some shell command in a specific directory (eg your project directory) then simply quell the popup - you frequently want the buffer but just dont want it jumping up in your face. eg I run a webserver and I want to see the output, just not now...

  (use-package php-mode
    :config
    (add-to-list 'display-buffer-alist
    (cons "\\*Symfony Web Server\\*.*" (cons #'display-buffer-no-window nil)))
    (defun php-mode-webserver-hook ()
      (if (projectile-project-root) (let ((default-directory (projectile-project-root)))
        (unless (get-buffer "*Symfony Web Server*" )
          (async-shell-command "bin/console server:run" "*Symfony Web Server*")))))
    :hook (php-mode . php-mode-webserver-hook))
RichieHH
  • 2,116
  • 4
  • 28
  • 30