Emacs org-mode - How to run shell scripts with background processes without hanging Emacs
Add this to your emacs.org file:
#+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
Move point (cursor) to the BEGIN_SRC block and evaluate it with Cc Cc (anchored to org-ctrl-c-ctrl-c
).
See what happens. Emacs sits there and hangs. What I want to do is run this command ( sleep 10
in this trivial example) and continue.
Somehow Emacs tries to wait in all the subprocesses that the script creates and hangs. I need to hit Cg to get control.
In this case, I want to call some GUI application (xterm, etc.) and run it in the background, but go back to Emacs right away.
How can i do this? See my failed attempts above.
EDIT : I've highlighted the problem down to the minimal Emacs Lisp code. Evaluate the following inside the buffer *scratch*
(Lisp Interactive) and see it hang for 3 seconds:
(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"))))
Change sleep 3
to something like sleep 3000
and it will hang for 3000 seconds until you kill it with Cg.
My emacs version releases:
GNU Emacs 24.4.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 3.4.2) of 2014-09-14 on hungover
source to share
Here is the closest I can think of 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
or for your specific use:
(require 'async)
(async-start
(lambda ()
(shell-command "xterm"))
(lambda (result)
(message-box "%s" result)))
source to share