16.4 Environment of a Code Block

Passing arguments

使用 ‘var’ 向源代码块传递参数。代码块中变量的具体用法因语言而异,详见各语言专属文档,但 ‘var’ 的语法对所有语言统一,包括变量声明与默认值赋值。

使用 ‘var’ 头部参数向代码块传递参数的语法格式为:

:var NAME=ASSIGN

NAME 为代码块主体中绑定的变量名。ASSIGN 可以是字面量(字符串、数字)、表格引用、列表、字面量示例、其他代码块(可带参数),或是某代码块的执行结果。ASSIGN 也可通过冒号分隔文件名与引用目标,指定外部文件中的元素。

:var NAME=FILE:REFERENCE

若 ‘FILE’ 不存在,则直接在当前文件中按原引用名称查找。因此 ‘:var table=tbl:example’ 会在当前缓冲区中查找对应表格。

以下为按引用传递值的示例:

table

使用 ‘NAME’ 关键字命名的表格。

#+NAME: example-table
| 1 |
| 2 |
| 3 |
| 4 |

#+NAME: table-length
#+BEGIN_SRC emacs-lisp :var table=example-table
  (length table)
#+END_SRC

#+RESULTS: table-length
: 4

传递表格时,可对包含列名/行名的行或列进行特殊处理。

colnames’ 头部参数可取值 ‘yes’ 、 ‘no’ 或 ‘nil’ ,默认 ‘nil’ :若输入表格存在列名(第二行为横线),Org 会先移除列名,处理表格后再恢复列名并写入结果。取值 ‘yes’ 时,即使表格无横线,也会对首行非横线内容执行相同逻辑。取值 ‘no’ 时则完全不预处理列名。

#+NAME: less-cols
| a |
|---|
| b |
| c |

#+BEGIN_SRC python :var tab=less-cols :colnames nil
return [[val + '*' for val in row] for row in tab]
#+END_SRC

#+RESULTS:
| a  |
|----|
| b* |
| c* |

同理, ‘rownames’ 头部参数可取 ‘yes’ 或 ‘no’ 。取值 ‘yes’ 时,Org 会移除首列,处理表格后恢复并写入结果;默认 ‘no’ ,即不处理首列。注意 Emacs Lisp 代码块会忽略 ‘rownames’ 参数,因其表格操作较为简便。

#+NAME: with-rownames
| one | 1 | 2 | 3 | 4 |  5 |
| two | 6 | 7 | 8 | 9 | 10 |

#+BEGIN_SRC python :var tab=with-rownames :rownames yes
return [[val + 10 for val in row] for row in tab]
#+END_SRC

#+RESULTS:
| one | 11 | 12 | 13 | 14 | 15 |
| two | 16 | 17 | 18 | 19 | 20 |

引用其他文件中的表格,可使用冒号连接文件名与表名,例如: ‘:var table=other-file.org:example-table’ 。

list

简单的命名列表。

#+NAME: example-list
- simple
  - not
  - nested
- list

#+BEGIN_SRC emacs-lisp :var x=example-list
  (print x)
#+END_SRC

#+RESULTS:
| simple | list |

注意仅顶层列表项会被传递,嵌套列表项会被忽略。

无参数代码块

由 ‘NAME’ 关键字命名的代码块,后可接空括号。

#+BEGIN_SRC emacs-lisp :var length=table-length()
  (* 2 length)
#+END_SRC

#+RESULTS:
: 8
带参数代码块

由 ‘NAME’ 关键字指定的代码块名称,后接括号,并可在括号内传入可选参数。 执行该代码块时,光标会定位在其所在位置。

#+NAME: double
#+BEGIN_SRC emacs-lisp :var input=8
  (* 2 input)
#+END_SRC

#+RESULTS: double
: 16

#+NAME: squared
#+BEGIN_SRC emacs-lisp :var input=double(input=1)
  (* input input)
#+END_SRC

#+RESULTS: squared
: 4
字面示例或代码块内容

使用 ‘NAME’ 关键字命名的代码块或字面示例块,后接方括号(示例块可省略)。

#+NAME: literal-example
#+BEGIN_EXAMPLE
  A literal example
  on two lines
#+END_EXAMPLE

#+NAME: read-literal-example
#+BEGIN_SRC emacs-lisp :var x=literal-example[]
  (concatenate #'string x " for you.")
#+END_SRC

#+RESULTS: read-literal-example
: A literal example
: on two lines for you.

通过索引可引用变量的部分内容。索引从 0 开始,负数表示从末尾倒数。逗号分隔的索引对应后续维度。注意索引操作在 ‘hlines’ 、 ‘colnames’ 、 ‘rownames’ 等表格相关参数生效 之前 执行。下面示例将表格 ‘example-table’ 首行最后一个单元格赋值给变量 ‘data’ :

#+NAME: example-table
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |

#+BEGIN_SRC emacs-lisp :var data=example-table[0,-1]
  data
#+END_SRC

#+RESULTS:
: a

两个整数以冒号分隔表示取值范围,包含起止位置。下面示例将 ‘example-table’ 的中间三行赋值给 ‘data’ :

#+NAME: example-table
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
| 5 | 3 |

#+BEGIN_SRC emacs-lisp :var data=example-table[1:3]
  data
#+END_SRC

#+RESULTS:
| 2 | b |
| 3 | c |
| 4 | d |

使用空索引或单个 ‘*’ 表示选取全部范围, ‘0:-1’ 效果相同。下面示例仅引用第一列:

#+NAME: example-table
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |

#+BEGIN_SRC emacs-lisp :var data=example-table[,0]
  data
#+END_SRC

#+RESULTS:
| 1 | 2 | 3 | 4 |

索引引用适用于表格与代码块,支持任意维度,逗号分隔多维索引,示例如下:

#+NAME: 3D
#+BEGIN_SRC emacs-lisp
  '(((1  2  3)  (4  5  6)  (7  8  9))
    ((10 11 12) (13 14 15) (16 17 18))
    ((19 20 21) (22 23 24) (25 26 27)))
#+END_SRC

#+BEGIN_SRC emacs-lisp :var data=3D[1,,1]
  data
#+END_SRC

#+RESULTS:
| 11 | 14 | 17 |

注意行名与列名在索引前不会被移除,即使 ‘colnames’ 或 ‘rownames’ 参数后续会处理,索引时也需将其计入位置。

Emacs Lisp 代码也可直接为变量赋值。为区分普通值与 Lisp 代码,Org 会将以 ‘(’ 、 ‘[’ 、 ‘'’ 或 ‘`’ 开头的值当作 Emacs Lisp 代码执行,执行结果赋值给变量。下面示例展示如何可靠地获取当前 Org 缓冲区文件名并传递给代码块:

#+BEGIN_SRC sh :var filename=(buffer-file-name) :exports both
  wc -w $filename
#+END_SRC

注意从表格与列表中读取的值不会被误解析为 Emacs Lisp 代码,如下例所示:

#+NAME: table
| (a b c) |

#+HEADER: :var data=table[0,0]
#+BEGIN_SRC perl
  $data
#+END_SRC

#+RESULTS:
: (a b c)

Using sessions

两个代码块可共享同一运行环境。 ‘session’ 头部参数用于让多个源代码块在同一会话中运行,同名会话的代码块会在同一个解释器进程中执行。

none

默认值。每个代码块启动独立解释器进程,执行完毕后进程终止。

STRING

除 ‘none’ 外的任意字符串作为会话名称。例如 ‘:session STRING’ 会将会话命名为 ‘STRING’ 。若 ‘session’ 未设值,会话名由源代码语言标识符生成。后续同语言代码块复用该会话。根据语言不同,状态变量、其他块代码与整体解释环境可能共享。部分解释型语言支持通过修改会话名创建并发会话。

仅支持交互式执行的语言可使用会话功能,C、ditaa 等语言不支持。即使是 Python、Haskell 这类支持交互的语言,也对可交互式运行的语法结构有限制,Org 会话中的代码块会继承这些限制。

Choosing a working directory

dir’ 头部参数指定代码块执行时的工作目录。未设置时使用当前缓冲区所在目录。即 ‘:dir DIRECTORY’ 的效果等价于临时执行 M-x cd RET DIRECTORY。底层实现中, ‘dir’ 仅设置 Emacs 变量 default-directory 。将 ‘mkdirp’ 设为非 nil 值可在需要时自动创建目录。

将 ‘dir’ 设为符号 attach 或字符串 "'attach" ,会自动将目录 ‘dir’ 设为 (org-attach-dir) 返回路径,并开启 ‘:mkdirp yes=;使用 =:results file’ 生成的文件路径会以 ‘attachment:’ 链接形式插入,而非普通 ‘file:’ 链接;位于附件目录外的路径仍使用 ‘file:’ 链接。

例如将绘图文件保存至主目录 ‘Work/’ 文件夹(波浪号会自动展开):

#+BEGIN_SRC R :file myplot.png :dir ~/Work
  matplot(matrix(rnorm(100), 10), type="l")
#+END_SRC

如需在远程机器执行代码块,可使用 Tramp 格式指定远程目录,示例:

#+BEGIN_SRC R :file plot.png :dir /scp:[email protected]:
  plot(1:10, main=system("hostname", intern=TRUE))
#+END_SRC

Org 会先正常捕获文本结果插入 Org 文件,再借助 Emacs Tramp 插入远程文件链接,路径由 ‘dir’ 与 default-directory 组合生成:

[[file:/scp:[email protected]:/home/dand/plot.png][plot.png]]

当 ‘dir’ 与 ‘session’ 同时使用时,仅对新会话设置初始目录,不会修改已存在会话的工作目录。

请勿将 ‘dir’ 与 ‘:exports results’ 或 ‘:exports both’ 共用,避免 Org 生成错误的远程文件链接,原因是 Org 不会展开 default-directory 以规避底层兼容性问题。

Inserting headers and footers

prologue’ 头部参数用于在代码块执行前追加内容,常用于执行重置指令。例如可在 Gnuplot 代码块中使用 ‘:prologue "reset"’ ,或全局配置:

(add-to-list 'org-babel-default-header-args:gnuplot
             '((:prologue . "reset")))

同理, ‘epilogue’ 头部参数的值会在代码块执行末尾追加执行。