Emacs 组织模式 - 如何 运行 shell 具有后台进程的脚本而不挂起 Emacs

Emacs org-mode - How to run shell scripts with backgrounded processes without hanging Emacs

将此添加到 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

将点(光标)移动到 BEGIN_SRC 块中并使用 C-c C-c(绑定到 org-ctrl-c-ctrl-c)计算它。

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

Emacs 以某种方式试图等待脚本创建并挂在那里的所有子进程。我必须按 C-g 才能取回控制权。

这个用例是我想调用一些 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"))))

sleep 3 更改为 sleep 3000 之类的内容,它将挂起 3000 秒,直到您使用 C-g 将其杀死。

我的 emacs 版本报告:

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

这是我能想到的最接近的用法 https://github.com/jwiegley/emacs-async

    * Run shell command asynchronously

#+BEGIN_SRC sh :tangle some_cmd.sh :tangle-mode (identity #o755) :shebang #!/bin/bash
sleep 10
touch async-file
echo "done"
#+END_SRC

#+RESULTS:

#+BEGIN_SRC emacs-lisp
(require 'async)

(org-babel-tangle)

(async-start
 (lambda ()
   (shell-command (expand-file-name "some_cmd.sh")))
 (lambda (result)
   (message-box "%s" result)))

#+END_SRC

#+RESULTS:
: #<process emacs>

#+BEGIN_SRC sh
ls async-file
#+END_SRC

或您的特定用途:

(require 'async)

(async-start
 (lambda ()
   (shell-command "xterm"))
 (lambda (result)
   (message-box "%s" result)))

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

.emacs:

(require 'ob-async)

.org:

#+BEGIN_SRC sh :async
sleep 10 && echo 'Done!'
#+END_SRC

我在 mac。对于我的用例,我想使用 links。我在 sh link 的命令中添加了 && 进程在后台启动:

[[shell:afplay '/path/to/20200523-20123124.m4a' &][sample link]]

我添加了 (setq org-confirm-shell-link-function nil) b/c 我有数百个小的 m4a 文件要转录...设置不安全但现在没问题。

运行 link(with C-x C-o)打开一个新组织 shell 输出 window,但我只是忽略它。

干杯! z

我正在使用 emacs lisp start-process:

例如,打开 libreoffice calc sheet

#+BEGIN_SRC elisp :noweb yes :results output :eval no-export :exports none 
(start-process "server" "buf-server" "libreoffice"  "calc.ods")
#+END_SRC

或在 xterm

的后台启动 java 服务器(在示例表格中)
#+BEGIN_SRC elisp :noweb yes :results output :eval no-export :exports none 
(start-process "server" "buf-server" "xterm"  "-T" "TABULA" "-hold" "-e"  "bash" "-c" "java -Dfile.encoding=utf-8 -Xms256M -Xmx1024M -jar ~/java/tabula.jar")
#+END_SRC