Emacs org-mode - 如何在不挂起Emacs的情况下使用后台进程运行shell脚本

bgo*_*odr 6 emacs hang background-process org-mode

将其添加到emacs .org文件中:

#+BEGIN_SRC sh :results verbatim
  #!/bin/bash

  exec 2>&1  # <-- Because Emacs treats stderr output as an error and doesn't show it in the RESULT

  echo before 

  # This nohup should just run in the background and continue to exit
  # the script, but emacs hangs and waits on it anyhow:
  nohup sleep 10 &

  # Failed attempts at working around the hang are:
  #   setsid nohup sleep 10 &
  #   nohup sleep 10 </dev/null & 

  # Do see /tmp/ps.out being updated here so the hang is in Emacs:
  ps -ef --forest --cols=10000 >/tmp/ps.out

  echo after 

  exit 0
#+END_SRC
Run Code Online (Sandbox Code Playgroud)

将点(光标)移动到BEGIN_SRC块并使用Cc Cc(绑定到org-ctrl-c-ctrl-c)进行评估.

看看会发生什么.Emacs坐在那里并挂起.我想要它做的是运行该命令(sleep 10在这个简单的例子中)并继续.

不知何故,Emacs正试图等待脚本创建并挂起的所有子进程.我必须击中Cg以获得控制权.

这个用例是我想调用一些GUI应用程序(xterm等)并让它在后台运行但是立即将控制权交还给Emacs.

我怎样才能做到这一点?看看我上面的失败尝试.

编辑:我将问题隔离到最低限度的Emacs Lisp代码.在你的*scratch*(Lisp Interactive)缓冲区内评估以下内容,看它挂起3秒钟:

(let ((shell-file-name "/bin/bash")
      (input-file "/tmp/tmpscript.sh")
      (error-file "/tmp/tmperror")
      (shell-command-switch "-c")
      (command "sh")
      exit-status)
  (with-temp-file input-file
    (insert "#!/bin/bash") (newline)
    (insert "nohup sleep 3 &") (newline)
    (insert "exit 0") (newline))
  (setq exit-status
        (apply 'call-process "/bin/bash"
                      input-file
                      (list t error-file)
                      nil
                      (list "-c" "sh"))))
Run Code Online (Sandbox Code Playgroud)

更改sleep 3为类似的东西sleep 3000,它将挂起3000秒,直到你用Cg杀死它.

我的emacs版本报告:

GNU Emacs 24.4.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 3.4.2) of 2014-09-14 on hungover
Run Code Online (Sandbox Code Playgroud)

小智 3

我使用MELPA 中的ob-async来启用异步执行。

.emacs:

(require 'ob-async)
Run Code Online (Sandbox Code Playgroud)

.org:

#+BEGIN_SRC sh :async
sleep 10 && echo 'Done!'
#+END_SRC
Run Code Online (Sandbox Code Playgroud)