8

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
Melioratus
  • 4,504
  • 1
  • 25
  • 43
  • 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

1 Answers1

6

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.

Roman Grazhdan
  • 358
  • 3
  • 9