org-mode 系列——org-mode 基本操作
文章摘要: 本文深入探讨了org-mode在个人知识管理中的优势与使用方法。第一部分对比了org与markdown的差异,指出org虽然学习曲线陡峭但功能更强大统一,适合复杂知识管理。第二部分提出使用org-roam-daily建立日志文件作为知识原料库,通过互联构建活的知识体系。第三部分详细介绍了org-mode的文本编辑功能,包括标题操作、属性设置、文本修饰等核心功能。第四、五部分分别讲解了列
目录
1 为什么选择 org ?
org 通常与 markdown 进行比较。与 org 相比,markdown 是一种轻量级标记语言的开放标准,是一种通用的“世界语”。由于语法极简,标记少,上手几乎零门槛,所以通用性高,几乎所有笔记软件、博客平台、代码仓库都支持。而 org 只能在 Emacs 的 org-mode 模式内使用,功能繁多,掌握起来有一定难度,还需要了解一些 Emacs 的配置技术,所以学习曲线陡峭,使用范围受限。从这个角度来说,markdown 完胜。
但是,上面所说的 markdown 的优点,只是最基础的 markdown 语法,而几乎所有流行的平台(如Typora、Obsidian、Notion、语雀、GitHub、pandoc)都加入了大量自有语法。这导致了严重的碎片化,在一款软件里精心编写的笔记,换到另一个平台很可能渲染异常。而反观 org,与 markdown 的基础语法相比,并不会更复杂,但 org 的扩展性极强,可以实现 markdown 无论怎么扩展都无法实现的功能,比如任务管理、日程管理、文学编程或者其他任何功能,这些都是在一个环境里都可以完成的。
所以,对于严肃的、复杂的、追求极致效率的个人知识管理而言,org 在技术上是远比 markdown 更优越和更具竞争力的解决方案。它的竞争力不在于用户数量,而在于为深度用户提供的、markdown 生态难以企及的深度、统一和自动化能力。
2 应该怎么使用 org-mode
今天忽然想到,我以前使用 org-mode 的方式可能是有问题的。org-mode 应该压根没有考虑过做一个严肃的文档处理工具的事,它的强项是“万物互联”,通过链接把各种片断串在一起,从而成为一个知识的管理工具。
为了能够做到这一点,我们需要给它准备一个“原料库”,这个原料库应该是 journal 或者 org-roam-daily 生成的日志文件。以前的 journal 模板是把日志放在一个文件里,现在来看是不合适的,当日志越来越长的时候,journal 文件经常导致 Emacs 无法正常启动。所以还是应该每天一个文件,可以容纳更多的内容,不容易出问题。
org-agenda 的 capture 功能应该建立在 journal 的基础上,自动链接到相应的 journal 文件,这样每一个任务、日程都可以查到来自于哪里,每一个笔记也都会有相应的 journal 文件链接过来。journal 文件不需要删除或更改,因为它是原料,是最原始的东西,要更改的是基于它生成的日程、笔记等。org-roam-daily 提供了较好的每天一个文件的基础设施,不用再自己折腾,所以就用 org-roam 吧,反正笔记管理也基本靠它了。当我们把多条散落的日志整理成笔记的时候,也可以再在日志上添加到笔记的链接,这样就可以更完整地追溯整个思考过程了。
所以当要 capture 一个任务、一条笔记的时候,先写下日志吧,为什么会 capture?它的背景是什么?
我想通过这样的互联,我积累下来的笔记才会是活的,以前也记过很多笔记,脑图、org-mode 都用过,但时间一长,记录的笔记也慢慢地吃灰了,因为它没有跟现在的我联结起来。特别是看到康奈尔笔记法后,我觉得有些重要的东西用康奈尔笔记法来复习是非常有必要的,不然真的是学了做了又忘了。
3 org-mode 的文本编辑
3.1 标题
标题是 org-mode 文档的精华所在,是许多功能得以实现的载体。org-mode 的标题以 * 开头,几级标题就用几个连续的 * 。 * 之间不能有空格,但 * 与后面的文字之间一定要有空格。标题是分级的,org-mode 可以有无限级标题。
3.1.1 插入标题
插入一个同级标题用 M-RET ( org-meta-return ,其含义随环境而变)或者用 C-RET ( org-insert-heading-respect-content ,意义更唯一),在插入同级标题的同时还要添加上 TODO 标记用 M-S-RET ( org-insert-todo-heading )。
3.1.2 更改标题级别
我们可以方便地改变标题的级别:
M-<right>(org-metaright)和M-<left>(org-metaright)可以将当前光标所在标题下移或上移一个层级M-S-<right>(org-shiftmetaright)和M-S-<left>(org-shiftmetaright)可以将当前光标所在标题及其所属标题都下移或上移一个层级
3.1.3 标题属性
标题属性可以为文档中的标题附加任意的键值对数据,这些数据可以用于查询、链接、视图、排版等,是实现个人知识管理和工作流自动化的核心工具之一。org-mode 内置了一些标准属性,如 ID, CUSTOM_ID, CATEGORY 等,除了标准属性,我们可以添加任意属性键值对,记录下非标准信息。标题属性放在标题的 PROPERTIES 抽屉里:
* 我的任务
:PROPERTIES:
:PROPERTY_NAME: property_value
:ANOTHER_PROP: another_value
:END:
可以用快捷键 C-c C-x p 快速插入一个属性键值对。
标题属性是可以继承的,也就是子标题可以继承父标题的属性。但是如果所有属性都继承,会导致严重的性能下降,所以默认情况下,只有 CATEGORY , ARCHIVE, COLUMNS 和 以 “_ALL” 结尾的属性才会被继承。如果要修改属性继承的运作方式,请参考 help:org-use-property-inheritance 。
3.1.4 标题抽屉
抽屉是 Org mode 中用于封装特定类型文本内容的区块,它们不会在导出时显示,主要用于在 Org 文件内部存储元数据或辅助信息。 PROPERTIES 是抽屉的一种,除此之外,还有 LOGBOOK 抽屉用于存储待办事项的状态变更记录, CLOCK 抽屉可用于存储时钟数据。我们可以创建任意名称的抽屉来存放内容,内容不必按键值对组织:
* 我的笔记
:NOTES:
这是一个自定义抽屉
我可以在这里存放任何不想在导出时显示的内容
比如临时的想法、参考资料等
:END:
可以用快捷键 C-c C-x d ( org-insert-drawer )快速插入一个抽屉。
3.1.5 tag(标签)
标签在 org-mode 中可以用于控制输出(如export、noexport),便于查找,或用于特定作用(如crypt)。添加标签可按 C-c C-q ( org-set-tags-command ),多个标签之间用 ; 隔开。
3.2 文本修饰(粗体、斜体、下划线、等宽字体等)
org-mode 提供了一些文本修饰标记用于文本的装饰,包括 *粗体* ( 粗体 )、 /斜体/ ( 斜体 )、 +删除线+ ( 删除线 )、 _下划线_ ( 下划线 )、 =等宽字体= ( 等宽字体 )、 ~等宽字体~ ( 等宽字体 )。添加文本修饰用 org-emphasis ( C-c C-x C-f ),然后选择一个修饰符号。
另外org-mode 还提供了上下标: H_{2}O ( H2O )、 E=mc^{2} ( E=mc2 )。
注意在中文中因为没有空格间隔,这些标记会不起作用,必须加空格才行,如果嫌空格难看,可以加零宽度空格(见 [3.3](#* 特殊字符的处理) )。
如果 org-mode 提供的修饰不够用,需要自定义修饰,可以考虑使用 [11](#* 宏替换) 来实现。
3.3 特殊字符的处理
org-mode 没有通用的特殊字符的 escape 机制,如果遇到问题,试试插入一个零宽度空白(Zero Width Space) C-x 8 RET 200B,如果不能解决,再查 manual 看有没有解决方案。
4 列表
列表是表达步骤、列举的常用方式。org-mode 支持多种列表类型,支持列表的嵌套和高级排序,还支持复选框。
列表分为无序列表和有序列表,另外还有一种描述列表。无序列表使用 -, + 作为列表标记,有序列表使用 1., 1) 或者字母 a., A) 等。Org-mode 会对有序列表的编号自动调整。
列表可以嵌套,通过缩进来创建子列表。所以列表也是有层级的,调整列表层级的方法和调整标题层级的方法相同,可参考 [3.1.2](#* 更改标题级别) 。
* 无序列表
- 第一项
- 第二项
- 子列表
- 第三项
* 有序列表
1. 第一步
2. 第二步
3. 第三步
* 描述列表
- 苹果 :: 一种红色的水果,通常很甜。
- 香蕉 :: 一种黄色的水果,富含钾。
5 链接
Org mode 的链接功能非常强大,它允许你链接到文件、网页、其他标题、ID,甚至是执行代码。
所有类型的链接都遵循相同的基本格式,如果想显示“描述文本”而不是链接本身,用第一种格式,否则用第二种格式:
1. [[链接地址][描述文本]]
2. [[链接地址]]
描述文本本身可以是带各种格式的文本,甚至可以包含图片链接。
链接的基本操作有:
C-c C-l(org-insert-link):插入链接C-c C-o(org-open-at-point):打开光标处的链接C-c &(org-mark-ring-goto):返回到上一个链接位置org-store-link:存储当前位置的链接
如果要插入的链接是 org 文件的特定位置,先使用 org-store-link 存储链接,再调用 org-insert-link 会更方便,免得自己手敲链接。所以对它定义快捷键:
("C-c l" . org-store-link)
Tips:如果在编辑链接的时候遇到闹心的小问题,可以用 org-toggle-link-display 切换链接显示方式,修改好了再切换回去。
5.3 内部引用
内部引用可以有3种方式:
[[* heading]]:引用文中标题[[#custom_id]]:引用带有custom_id属性的条目[[anchor_name]]:引用形如<<anchor_name>>的 anchor,或者图表的name。
如果找不到,org-mode 还会试图去匹配缓冲区中元素的名称。
5.4 文件链接
文件链接的作用是链接到本地文件或目录,如:
[[file:~/documents/notes.org][我的笔记]]
[[file:./images/photo.jpg]] ;; 图片
[[file:./projects/][项目目录]] ;; 目录
特别的,插入图片也是用的链接。图片链接不能有描述文本,如果有描述文本,就不会显示图片,而是显示一个指向图片的链接。
5.5 链接到其他 org 文件的特定位置
在链接到其他 org 文件时,也可以指定链接到该文件的某个标题、某一行或者某个锚点,甚至可以用上正则表达式自动搜索特定内容:
[[file:foo.org::*heading][XXXX]]
[[file:~/code/main.c::255][XXXX]]
[[file:~/xx.org::anchor_name][XXXX]]
[[file:/path/to/file.txt::/hello/][在 file.txt 中搜索 “hello”]]
使用标题链接好像难以解决链接的有效性,因为不同的 org 文件并不会同时编译输出,导致它们输出的 html 里的链接和对应的锚点对不上,但在操作 org 文件时是没有问题的。
如果要链接的某个标题具有 ID 或者 CUSTOM_ID 属性,则可以使用如下形式:
[[id:1234-5678-90AB-CDEF][相关条目]]
[[file:projects.org::#项目A][项目A详情]]
ID 之所以不需要文件名,是因为 ID 是全局唯一的。可以在使用 org-store-link 命令时给标题添加 ID 属性:
(setq org-id-link-to-org-use-id 'create-if-interactive) ; 使用 org-store-link 命令时给标题添加ID属性
但是要使用 ID,必须要有一个数据库存储 ID 的位置且能及时更新,org-mode 使用 ~/.emacs.d/.org-id-locations 文件跟踪 ID 的变化,并提供了一系列的工具。而 org-roam 包则提供了不同的解决思路,它把 ID 等链接相关的数据存入一个 sqlite 数据库,以更有效率地管理大量链接。
5.6 网页链接
链接到网站,例如:
[[https://www.orgmode.org][Org mode官网]]
[[http://example.com]] ;; 无描述文本
5.7 其他类型的链接
org-mode 支持各种链接类型,如邮件、ftp、news等,如:
[[mailto:john@doe.com][给 John 发邮件]]
5.8 链接缩写
对于文档中频繁使用的链接,可以在文档头定义链接缩写,链接缩写可以带有一个参数:
...
#+LINK: bing https://www.bing.com/search?q=%s
或者,我们可以把链接缩写写进配置文件:
(org-link-abbrev-alist
'(("bing" . "https://www.bing.com/search?q=%s")))
然后可以在文档中使用链接缩写:
[[bing:Org-mode 教程][搜索org-mode教程]]
它相当于点击了链接 https://www.bing.com/search?q=:Org-mode 教程 ,其效果如下:[搜索org-mode教程](https://www.bing.com/search?q=Org-mode 教程) 。
5.9 高级用法
org-mode 的链接其实是一个框架,我们可以使用的各种高级链接类型都是用 org-link-set-parameters 函数来定义。通过它,我们可以把链接转变为一个强大的、可编程的集成框架,实现比“多媒体”更多媒体的高级文本。但这些功能不能脱离 Emacs 使用。该函数可以定义链接的若干个操作,其中最重要的两个操作是: :follow (当点击链接时做什么)和 :export (如何导出该链接)。
org-mode 预定义的高级链接类型包括: shell, elisp, attach 等,我们也可以创建自定义的链接类型,具体操作参考相关文档。
6 表格操作
6.9 新建表格
创建表格可以使用 C-c | ( org-table-create-or-convert-from-region )创建,它既可以创建一个新表格,也可以将一个文本区域(用逗号或者其他分隔符分隔)转换成表格。
再按 TAB 键,就会生成表格。
如果自动创建表格不方便,也可以手动创建:将第一行各列用“|”隔开,如:
| a | b | c |
然后在中间任意位置按一下 TAB 键,就可以生成一个表格。
6.10 表格的导航和编辑
我们可以在表格的单元格之间移动,也可以调换行、列顺序,或者增删表格的行和列:
C-c `(org-table-edit-field):编辑当前单元格S-return(org-table-copy-down):填充单元格Tab/S-Tab: 左移/右移一个单元格Enter:下移一个单元格M-<up>/<down>/<left>/<right>:移动行或列M-S-<up> / =<down>/<left>/<right>:移动行或列,重叠则删,空出则添C-c Enter(org-ctrl-c-minus):插入分隔横线,也可以在新行上输入|-,然后按 TAB 键C-c C-c:表格重排或计算结果刷新C-c ^(org-sort):表格排序
如果需要跨行或跨列合并单元格,可以参考 https://emacs.stackexchange.com/questions/7299/multicolumn-cells-in-org-mode-tables 或者 https://orgmode.org/manual/Cooperation.html#Cooperation。
6.11 表格计算
Org-mode 的表格计算功能非常强大,它内置了一个类似于电子表格的公式系统,可以在不离开 Org-mode 环境的情况下进行复杂的数据处理。
- 单元格命名,用 “@” 来表示行,用 “$” 来表示列,如
@3$2,如果只给一个坐标,则另一个坐标会被设为"当前行"或者"当前列"; - 表示区域,用 “…” 来表示,如:
@2$1..@4$3,$1..$3; - 可以用 “@#” 表示当前行的行号,用 “$#” 表示当前列的列号;
- 可以定义常量,如:#+CONSTANTS: pi=3.14 eps=2.4e-6;
如下表所示,光标移动到 @2$4 ,用 C-c ' (org-edit-special),在弹出的输入框中输入 $2*$3 ,回车后,表格下面会出现 #+TBLFM: $4=$2*$3 。然后再在这一行后面接着输入公式 @4$4=vsum(@2..@3) ,两个公式间用两个冒号 :: 隔开。接着在公式这一行按 C-c C-c ,就会在正确的位置填入计算结果。
| 物品 | 单价 | 数量 | 总价 |
|---|---|---|---|
| 苹果 | 5 | 3 | 15 |
| 香蕉 | 4 | 2 | 8 |
| 总计 | 23 |
#+TBLFM: $4=$2*$3::@4$4=vsum(@2..@3)
#+TBLFM: $4=$2*$3::@4$4=vsum(@2..@3)
这两个公式,第一个是列公式,第二个是单元格公式,单元格公式会覆盖列公式。另外,表头下面一定要有分隔线,否则,列公式会出错。
如果要修改公式,可以在 #+TBLFM: 这一行按 C-c ' ,即可对公式进行修改,修改完记得再按 C-c C-c 重新计算。
我们还可以在表格的前面添加一行 #+NAME: <table-name> 对表格命名,使表格数据可用于其他功能(如作为程序源代码的参数)。
7 图表标题及标签
在正式出版物中,图表往往需要添加标题。图表标题(caption)可以有一个可选项(短标题),用于图表列表,长标题则用于正文:
#+CAPTION[Short caption]: Long caption.
#+NAME: tbl:table1
#+attr_html: :width 100%
注意标题(caption)和名称(name)是不同的,名称用于引用这个图表(相当于 latex 中的 label),标题则用于排版。
attr_org, attr_html 和 attr_latex 属性来设置图片的尺寸,便于生成 html 或 latex 时使用。对于输出 latex,可以通过 org-latex-image-default-width, org-latex-image-default-height 变量设置图片的默认宽度和高度。
对标签的引用方法可以参考 [5](#* 链接) 。
8 结构模板
结构模板用于生成具有特殊含义的文本块,插入结构模板用 C-c C-, ( org-insert-structure-template ),然后选择相应的块类型,如果选择了 src ,还需要在后面输入语言名称,比如,如果是 org-mode 代码块,就输入 org ,相当于不要后面的 mode ,编辑器在显示或编辑代码时会调用相应的 major mode。
内置代码块中以 export 开头的几个块,其含义是,只在调用 export 输出某种类型的格式时才输出其中的内容,比如 export html 表示只在输出为 html 文档时才把这个块里的内容输出,输出为 latex 或 text 之类的格式就不输出,因为块里面是 html 代码,输出会导致内容混乱。
除此之外,内置的文本块还支持:
- 原文块(VERSE):块内内容原样显示,不会对特殊字符和命令进行处理
- 缩进块(QUOTE):通常用于引用,与默认格式相比左右都会留出缩进
- 居中块(CENTER):输出时内容居中显示
- 注释块(COMMENT):块中内容为注释,不会被导出
如果这些内置结构模板还不能满足需求,还可以自定义结构模板。这些结构模板在输出时会加上默认的处理,比如输出为 latex 时会作为一个自定义环境,输出为 html 时会作为一个自定义类名(class)。
9 注释
如果 org 文档中有些内容暂时不想要了,但又不想删掉,或者有些内容只打算自己看,不打算输出出来,则可以将它们“注释”掉。
注释有两种方式:
- 以
#(井号加空格)开头的行被看作注释,不会被导出 - 放在注释块中的内容被作为注释,不会被导出
示例:
# 这是一行注释
#+begin_comment
这是一个注释块,里面无论放多少内容都不会被导出
#+end_comment
10 程序代码
org-mode 中的程序源代码不仅仅用于输出,结合 org-babel 可以在 org-mode 中直接运行多种语言的源程序。
10.11 代码块
#+begin_src python
print('abc')
#+end_src
或者:
#+include: "somefile.py" src python
10.12 行内代码
=print('abc')= 或者 ~print('abc')~ 或者 src_python[:exports code]{print('abc')} 。最后一种是可以输出与代码块一样的格式化代码的。
11 宏替换
宏在导出的过程中替换文本片段。宏可以在全局变量 org-export-global-macros 中定义,也可以在文档中定义。在全局变量中定义的格式参考帮助文档,在文档中定义的格式是:
#+MACRO: name replacement text; $1, $2 are arguments
使用的方式: {{{name(arg1, arg2)}}} 。
特别地,我们可以在宏定义中使用 eval 函数:
#+MACRO: gnustamp (eval (concat "GNU/" (capitalize $1)))
org 可以识别段落、标题、诗句块、表格单元格和列表中的宏引用,还能识别关键字中的宏引用,如“CAPTION”、“TITLE”、“AUTHOR”、“DATE”,以及某些后端特定的导出选项。
org 还预定义了一些宏,如 title, author, email, date 等,具体参考 Org Manual 第13 章 Exporting。
12 markdown 格式粘贴为 org 格式
现在流行 markdown 格式,如果要将 markdown 格式的文本粘贴到 org-mode 中,网上传说可以使用 markdown-to-org 包,但实际使用发现该包实在太烂,转换错误多,还使用 minor mode 的方式占据内存,只要是复制到 org文档的内容都会被它处理,把想转的不想转的全都转得乱七八糟。还不如自己写个调用 pandoc 的函数:
(defun my-pandoc-convert (text from-format to-format)
"使用 pandoc 将 TEXT 从 FROM-FORMAT 转换为 TO-FORMAT。"
(with-temp-buffer
(insert text)
(let ((exit-status (call-process-region
(point-min) (point-max)
"pandoc"
t t nil
"-f" from-format
"-t" to-format)))
(if (zerop exit-status)
(buffer-string)
nil))))
(defun my-paste-mmd-to-org-pandoc ()
"从系统剪贴板读取 MMD 文本,使用 pandoc 转换为 Org 格式后插入到光标位置。"
(interactive)
(let ((text (gui-get-selection 'CLIPBOARD 'UTF8_STRING)))
(when text
(if (executable-find "pandoc")
(let ((result (my-pandoc-convert text "markdown" "org")))
(if result
(insert result)
(message "Pandoc 转换失败")))
(message "未找到 pandoc 命令,请先安装 pandoc")))))
完整的模块文件见下面的附录。
(use-package markdown-to-org
:bind
((:map org-mode-map
(("C-c M-y c" . org-yank-from-mmd-to-org))))
)
13 org 文档加密与解密
有时候,我们可能需要将 org 文档中的部分内容加密,我们可以使用 org-crypt 功能包,它会调用系统里的 gpg 命令,使用 gpg 的加解密功能来完成 org 文档某个子标题的加解密。
(use-package org-crypt
:defer t
:custom
(org-crypt-tag-matcher "crypt") ;设置要加密的 TAG 为 crypt
(org-tags-exclude-from-inheritance '("crypt")) ;防止子 TAG 也为 crypt,进行再次加密
(org-crypt-key "28348E2F6F84605BD72343BED5E53E83E09DE108")
:config
(org-crypt-use-before-save-magic)
)
更多推荐


所有评论(0)