A sudo org-link and sh block

| categories: babel, orgmode, emacs | tags:

Shell blocks in org-mode are pretty useful, but they are a little limited in that it is not obvious how to run a sudo command in them.

So for example, this gives me a permission denied error.

ls /var/audit

One way to get around this is to create an org-mode link like this one:

;http://stackoverflow.com/questions/2472273/how-do-i-run-a-sudo-command-in-emacs
(org-add-link-type
 "sudo"
 (lambda (cmd)
   "Run CMD with sudo."
   (shell-command
    (concat "echo " (shell-quote-argument (read-passwd "Password? "))
            " | sudo -S " cmd))))

Now you can create a link like ls /var/audit, and when you click on it you will be prompted for a password, and then you will see a buffer containing the output. To get an actual sudo code block, you need a new org babel library. Here is an example of what it might look like. Tangle this file to generate the library. Note: This is a lightly modified version of ob-emacs-lisp.el, and I have not tested it very thoroughly.

;;; ob-sudo.el --- An org-mode source block to run shell commands as sudo

;;; Commentary:
;; Runs the block of code as a shell command with sudo.

;;; Code:

(defun org-babel-execute:sudo (body params)
  "Run BODY as a shell command using sudo."
  (let* ((passwd (shell-quote-argument (read-passwd "Password? ")))
         (result (shell-command-to-string
                  (concat "echo " passwd
                          " | sudo -S " body))))
    ;; this is verbatim from ob-emacs-lisp
    (org-babel-result-cond (cdr (assoc :result-params params))
      (let ((print-level nil)
            (print-length nil))
        (if (or (member "scalar" (cdr (assoc :result-params params)))
                (member "verbatim" (cdr (assoc :result-params params))))
            (format "%S" result)
          (format "%s" result)))
      (org-babel-reassemble-table
       result
       (org-babel-pick-name (cdr (assoc :colname-names params))
                            (cdr (assoc :colnames params)))
       (org-babel-pick-name (cdr (assoc :rowname-names params))
                            (cdr (assoc :rownames params)))))))

(provide 'ob-sudo)
;;; ob-sudo.el ends here

Let us add the current dir to our path so we can load it. If you use this a lot, you should put the library on your permanent path.

(add-to-list 'load-path (expand-file-name "."))

Now, add the sudo "language" to org-babel-load-languages.

(org-babel-do-load-languages
 'org-babel-load-languages
 '((emacs-lisp . t)
   (python . t)
   (sh . t)
   (matlab . t)
   (sqlite . t)
   (ruby . t)
   (perl . t)
   (org . t)
   (dot . t)
   (plantuml . t)
   (R . t)
   (sudo . t)))

And, here it is in action. Hopefully I am not giving away some important information here!

ls /var/audit
20141106003522.20141110021519
20141110021548.crash_recovery
20141112154126.crash_recovery
20141119201541.20141122145259
20141122145317.20141124214930
20141124215000.crash_recovery
20141126062011.20141202192451
20141202192507.crash_recovery
20141210133306.crash_recovery
20141225181819.20150106015256
20150106015325.20150111010018
20150111010121.crash_recovery
20150115195518.20150115200101
20150115200110.crash_recovery
20150123061227.20150215123411
20150215123454.crash_recovery
20150225004740.20150310201600
20150310201633.20150314214730
20150314214807.crash_recovery
20150323145600.20150329170647
20150329170721.crash_recovery
20150407215846.20150413000423
20150413000438.20150421122044
20150421122104.20150518122545
20150518122616.20150518124432
20150518124432.20150518124513
20150518124513.20150518125437
20150518125437.20150518125935
20150518125935.20150518132111
20150518132111.20150531202621
20150531202719.20150601123612
20150601123612.20150601124932
20150601124932.20150601125151
20150601125151.20150601125555
20150601125555.20150601131947
20150601131947.20150601132421
20150601132421.20150601133735
20150601133735.20150601140740
20150601140740.20150601154012
20150601154012.20150601155125
20150601155125.20150601155215
20150601155215.20150601160937
20150601160937.crash_recovery
20150613061543.20150614054541
20150614054541.20150625165357
20150625165432.20150625200623
20150625200623.20150628042242
20150628042242.20150628103628
20150628103628.20150630052100
20150630052100.20150701232519
20150702005345.20150710203212
20150710203226.not_terminated
current

Summary thoughts: I will reiterate again I have not tested this a lot, I was mostly interested in trying to make a new sh block with sudo support. Let me know if it has issues for you, and make sure you have backups of things it could mess up!

Copyright (C) 2015 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter