6

History


Recently, I cobbled together a shell script that can execute a named code block from inside an org-mode file using the command-line.

I copied source code directly from the org-mode manual and the org-babel-open-src-block-result function in ob-core.el.

At the moment, the shell script only works with elisp code blocks.

  # Shell Command
  ./call-named-code-block-examples.sh ./call-named-code-block-examples.org "get-org-version" 2>/dev/null
  # Returns Expected Results
  # org-mode version: 9.0

The script displays an error when calling code blocks written in other languages, e.g. ruby.

  # Shell Command
 ./call-named-code-block-examples.sh ./call-named-code-block-examples.org "get-emacs-version"
  # Returns Error Message
  # No org-babel-execute function for ruby!

Question


How to execute named code blocks written in any language using a shell script?

Below is the shell script and org-mode code needed to reproduce the issue:


Shell Script


Save as file named: call-named-code-block-examples.sh

#!/bin/sh
# -*- mode: shell-script -*-
#
# Call named code block in org-mode file
#
DIR=`pwd`
FILE=$1
CODE_BLOCK=$2

emacs -Q --batch \
  --eval "
(progn
  (require 'org)(require 'ob)(require 'ob-table)(setq org-confirm-babel-evaluate nil)
  (mapc (lambda (file)
        (find-file (expand-file-name file \"$DIR\"))
        (let ((re-run (quote t))
          (results (quote \"ERROR: Did not call code block: $CODE_BLOCK\")))
    (save-excursion
      (org-babel-goto-named-src-block \"$CODE_BLOCK\")
      (let ((info (org-babel-get-src-block-info 'light)))
        (when info
          (save-excursion
        ;; go to the results, if there aren't any then run the block
        (goto-char (or (and (not re-run) (org-babel-where-is-src-block-result))
                   (progn (org-babel-execute-src-block)
                      (org-babel-where-is-src-block-result))))
        (end-of-line 1)
        (while (looking-at \"[\n\r\t\f ]\") (forward-char 1))
        ;; open the results
        (if (looking-at org-bracket-link-regexp)
            ;; file results
            (org-open-at-point)
          (let ((r (org-babel-format-result
                (org-babel-read-result) (cdr (assq :sep (nth 2 info))))))
            (pop-to-buffer (get-buffer-create \"*Org-Babel Results*\"))
            (delete-region (point-min) (point-max))
            (insert r)
            (setq results (buffer-string))))
        t)))
      t)
    (princ (format \"%s\" results))
    )

      (kill-buffer))
    '(\"$FILE\"))
  )
"

Named Code Block Examples


Save as file named: call-named-code-block-examples.org

#+NAME: get-org-version
#+BEGIN_SRC elisp 
(format "org-mode version: %s" (org-version))
#+END_SRC

#+RESULTS: get-org-version
: org-mode version: 9.0

#+NAME: get-emacs-version
#+BEGIN_SRC ruby  :var emacs_version=(format "Emacs Version: %s" (substring (version) 10 16))
  emacs_version
#+END_SRC

#+RESULTS: get-emacs-version
: Emacs Version: 24.5.1
  • I also like the question. I do have some handy pieces of code in my org files and maybe running them like this might turn out useful for me. – Roman Grazhdan Nov 14 '16 at 15:36
  • @RomanGrazhdan - Thanks for your help! One of my goals when I asked this question was to inspire others and to provide a glimpse about how org-mode might be integrated into other automation tools like Jenkins, Chef, BladeLogic and Puppet. – Melioratus Nov 14 '16 at 16:07
4

In you progn, you do load org-babel, but don't load any extra languages:

http://orgmode.org/worg/org-contrib/babel/languages.html#configure

It does work in your regular Emacs session because these are obviously loaded somewhere in your init.el

So I've saved your script and edited it like this:

#!/bin/sh
# -*- mode: shell-script -*-
#
# Call named code block in org-mode file
#
DIR=`pwd`
FILE=$1
CODE_BLOCK=$2

emacs -Q --batch \
  --eval "
(progn
  (require 'org)(require 'ob)(require 'ob-table)(setq org-confirm-babel-evaluate nil)
;; Don't forget to load languages
;; ------8<------------------
(org-babel-do-load-languages
   'org-babel-load-languages
   '((sh . t)
     (ruby . t)
     (emacs-lisp . t)
     ))
;; ------8<------------------
  (mapc (lambda (file)
        (find-file (expand-file-name file \"$DIR\"))
        (let ((re-run (quote t))
          (results (quote \"ERROR: Did not call code block: $CODE_BLOCK\")))
    (save-excursion
      (org-babel-goto-named-src-block \"$CODE_BLOCK\")
      (let ((info (org-babel-get-src-block-info 'light)))
        (when info
          (save-excursion
        ;; go to the results, if there aren't any then run the block
        (goto-char (or (and (not re-run) (org-babel-where-is-src-block-result))
                   (progn (org-babel-execute-src-block)
                      (org-babel-where-is-src-block-result))))
        (end-of-line 1)
        (while (looking-at \"[\n\r\t\f ]\") (forward-char 1))
        ;; open the results
        (if (looking-at org-bracket-link-regexp)
            ;; file results
            (org-open-at-point)
          (let ((r (org-babel-format-result
                (org-babel-read-result) (cdr (assq :sep (nth 2 info))))))
            (pop-to-buffer (get-buffer-create \"*Org-Babel Results*\"))
            (delete-region (point-min) (point-max))
            (insert r)
            (setq results (buffer-string))))
        t)))
      t)
    (princ (format \"%s\" results))
    )

      (kill-buffer))
    '(\"$FILE\"))
  )
"

I then created a test Org file:

#+NAME: test-ruby-block
#+BEGIN_SRC ruby :results output
puts "HELLO"
#+END_SRC

#+RESULTS: test-ruby-block
: HELLO

And checked your script on it:

hoodoo@T450s [06:32:51 PM] [~/Org] [master *]
-> % bash org-babel-run.sh test-script.org test-ruby-block
Position saved to mark ring, go back with C-c &.
executing Ruby code block (test-ruby-block)...
Code block evaluation complete.
HELLO%
hoodoo@T450s [06:32:59 PM] [~/Org] [master *]
-> %

EDIT: Don't use this code as is, it's potentially dangerous:

hoodoo@T450s [06:32:59 PM] [~/Org] [master *]
-> % bash org-babel-run.sh test-script.org no-such-block
source-code block ‘no-such-block’ not found in this buffer
executing Ruby code block (test-ruby-block)...
Code block evaluation complete.
HELLO% 

The code block is evaluated anyway, if you have unlink somewhere in your file it might result in a huge mess.

  • That's just what I needed! Thank you! – Melioratus Nov 14 '16 at 15:39
  • 1
    BTW I've noticed that if you mistype code block name it would execute it anyway. Not sure you really want this. – Roman Grazhdan Nov 14 '16 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.