1
;;; org-babel-sh.el --- org-babel functions for shell evaluation
3
;; Copyright (C) 2009 Eric Schulte
5
;; Author: Eric Schulte
6
;; Keywords: literate programming, reproducible research
7
;; Homepage: http://orgmode.org
12
;; This program is free software; you can redistribute it and/or modify
13
;; it under the terms of the GNU General Public License as published by
14
;; the Free Software Foundation; either version 3, or (at your option)
17
;; This program is distributed in the hope that it will be useful,
18
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
;; GNU General Public License for more details.
22
;; You should have received a copy of the GNU General Public License
23
;; along with GNU Emacs; see the file COPYING. If not, write to the
24
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25
;; Boston, MA 02110-1301, USA.
29
;; Org-Babel support for evaluating shell source code.
35
(org-babel-add-interpreter "sh")
37
(add-to-list 'org-babel-tangle-langs '("sh" "sh" "#!/usr/bin/env sh"))
39
(defun org-babel-execute:sh (body params)
40
"Execute a block of Shell commands with org-babel. This
41
function is called by `org-babel-execute-src-block'."
42
(message "executing Shell source code block")
43
(let* ((processed-params (org-babel-process-params params))
44
(session (org-babel-sh-initiate-session (first processed-params)))
45
(vars (second processed-params))
46
(result-type (fourth processed-params))
48
(mapconcat ;; define any variables
52
(org-babel-sh-var-to-sh (cdr pair))))
53
vars "\n") "\n" body "\n\n"))) ;; then the source block body
54
(org-babel-sh-evaluate session full-body result-type)))
56
(defun org-babel-prep-session:sh (session params)
57
"Prepare SESSION according to the header arguments specified in PARAMS."
58
(let* ((session (org-babel-sh-initiate-session session))
59
(vars (org-babel-ref-variables params))
60
(var-lines (mapcar ;; define any variables
64
(org-babel-sh-var-to-sh (cdr pair))))
66
(org-babel-comint-in-buffer session
68
(insert var) (comint-send-input nil t)
69
(org-babel-comint-wait-for-output session)) var-lines))
72
(defun org-babel-load-session:sh (session body params)
73
"Load BODY into SESSION."
74
(save-window-excursion
75
(let ((buffer (org-babel-prep-session:sh session params)))
76
(with-current-buffer buffer
77
(goto-char (process-mark (get-buffer-process (current-buffer))))
78
(insert (org-babel-chomp body)))
83
(defun org-babel-sh-var-to-sh (var)
84
"Convert an elisp var into a string of shell commands
85
specifying a var of the same value."
87
(concat "[" (mapconcat #'org-babel-sh-var-to-sh var ", ") "]")
90
(defun org-babel-sh-table-or-results (results)
91
"If the results look like a table, then convert them into an
92
Emacs-lisp table, otherwise return the results as a string."
94
(if (string-match "^\\[.+\\]$" results)
96
(replace-regexp-in-string
97
"\\[" "(" (replace-regexp-in-string
98
"\\]" ")" (replace-regexp-in-string
99
", " " " (replace-regexp-in-string
100
"'" "\"" results)))))
103
(defun org-babel-sh-initiate-session (&optional session)
104
(unless (string= session "none")
105
(save-window-excursion
106
(or (org-babel-comint-buffer-livep session)
107
(progn (shell session) (get-buffer (current-buffer)))))))
109
(defvar org-babel-sh-eoe-indicator "echo 'org_babel_sh_eoe'"
110
"Used to indicate that evaluation is has completed.")
111
(defvar org-babel-sh-eoe-output "org_babel_sh_eoe"
112
"Used to indicate that evaluation is has completed.")
114
(defun org-babel-sh-evaluate (session body &optional result-type)
115
"Pass BODY to the Shell process in BUFFER. If RESULT-TYPE equals
116
'output then return a list of the outputs of the statements in
117
BODY, if RESULT-TYPE equals 'value then return the value of the
118
last statement in BODY."
120
;; external process evaluation
121
(save-window-excursion
124
;; (message "buffer=%s" (buffer-string)) ;; debugging
125
(shell-command-on-region (point-min) (point-max) "sh" 'replace)
127
(output (buffer-string))
128
(value ;; TODO: figure out how to return non-output values from shell scripts
129
(let ((tmp-file (make-temp-file "org-babel-sh"))
130
(results (buffer-string)))
131
(with-temp-file tmp-file (insert results))
132
(org-babel-import-elisp-from-file tmp-file))))))
133
;; comint session evaluation
134
(flet ((strip-empty (lst)
135
(delq nil (mapcar (lambda (el) (unless (= (length el) 0) el)) lst))))
136
(let ((tmp-file (make-temp-file "org-babel-sh"))
139
org-babel-sh-eoe-output
142
(mapcar #'org-babel-sh-strip-weird-long-prompt
143
(mapcar #'org-babel-trim
144
(org-babel-comint-with-output
145
session org-babel-sh-eoe-output t
146
(mapc (lambda (line) (insert line) (comint-send-input))
147
(strip-empty (split-string body "\n")))
148
(insert org-babel-sh-eoe-indicator)
149
(comint-send-input))))))))))
150
;; (message (replace-regexp-in-string
151
;; "%" "%%" (format "processed-results=%S" results))) ;; debugging
154
(output (org-babel-trim (mapconcat #'org-babel-trim
155
(reverse results) "\n")))
156
(value (with-temp-file tmp-file
157
(insert (car results)) (insert "\n"))
158
(org-babel-import-elisp-from-file tmp-file))))
161
(defun org-babel-sh-strip-weird-long-prompt (string)
162
(while (string-match "^% +[\r\n$]+ *" string)
163
(setq string (substring string (match-end 0))))
166
(provide 'org-babel-sh)
167
;;; org-babel-sh.el ends here