跳转到内容

包含文件

include 指令把另一个文件读入账本,这样一个账本就可以拆分成多个文件,例如每年或每月一个文件。带 * 的模式会包含所有匹配的文件。

include "<Path>"
部分 必填 说明
"<Path>" 是 要读取的文件,写在双引号中。相对路径相对于包含这条 include 的文件所在的目录。路径的任何一部分都可以含有 *,见通配符。

include 没有日期,也没有元数据。它可以写在账本的任何文件、任何位置。

include "accounts.zhang"
include "data/2024/*.zhang"
include "data/*/*.zhang"

主文件位于账本根目录时,这几行会读取根目录下的 accounts.zhang、data/2024 中所有名称匹配 *.zhang 的文件,以及 data 下每个目录中的匹配文件。

  • 相对路径相对于包含这条 include 的文件所在的目录解析:data/2024.zhang 中的 include "sibling.zhang" 读取 data/sibling.zhang。
  • 每个被包含的文件都按主文件的格式读取,不论它自己的扩展名是什么:主文件为 main.zhang 的账本把每个文件都当作 zhang 文本读取,主文件为 main.bean 的账本把每个文件都当作 Beancount 文本读取。
  • 不存在的文件被当作空文件读取,不会报错。它仍会出现在网页界面的文件列表中。如果某个被包含文件中的条目没有显示出来,请检查路径。

* 代表路径某一部分中任意一段不含 / 的字符(可以为空),可以用在路径的任何一部分,需要时一部分里也可以出现多次(2024-*-*.zhang)。其他字符都按字面匹配,而且一部分要匹配整个名称:*.zhang 匹配 01.zhang,不匹配 01.zhang.bak;report(*).zhang 匹配 report(1).zhang。

  • data/*.zhang 匹配直接位于 data 中的文件;账本根目录的主文件中的 *.zhang 匹配它旁边的文件。
  • data/*/*.zhang 匹配 data 下一级目录中的文件。不带 * 的部分可以在带 * 的部分之前或之后,例如 data/*/archive/*.zhang 或 data/*/accounts.zhang。
  • 最后一部分匹配文件,之前的部分匹配目录。位于一部分开头的 * 不匹配隐藏名称(以 . 开头的名称),和 shell 一样:*.zhang 不会匹配编辑器留下的 .#01.zhang。
  • 匹配的文件按名称顺序读取。
  • 没有匹配任何文件的模式什么也不包含,不会报错。

不论一个文件被包含多少次,都只读取一次。文件包含主文件,或者两个文件互相包含,都不会出问题。

指令按日期排序,所以文件的顺序只对没有日期的指令有影响。张记账先读主文件,然后按顺序读取它包含的文件,再读取这些文件包含的文件,依此类推。同一个选项在多个文件中设置时,以最后读到的值为准。

账本在本地磁盘上时,zhang serve 会监视账本根目录,并在账本的某个文件发生变化时重新加载账本。匹配某个模式的新文件,或者新创建的、原本缺失的被包含文件,会在下一次重新加载时读取:即账本的某个文件发生变化时,或者你在网页界面中选择重新加载账本时。存放在 S3、WebDAV 或 GitHub 上的账本不会被监视;请在网页界面中重新加载它们。包含和模式在所有数据源上的用法都相同。

网页界面把新条目写入 directive_output_path 选项所选的文件。如果这个文件还不属于账本,张记账会创建它,并在主文件末尾追加一条包含它的 include。

include 不会产生账本错误。无法解析的文件会让账本无法加载,错误信息会指出文件、行和列。

Beancount 的 include 语法相同,也接受模式。张记账的不同之处:

  • Beancount 会报告没有匹配任何文件的 include。张记账把不存在的文件当作空文件读取,不会报错。
  • Beancount 的模式遵循 Python 的 glob 规则。张记账的 * 用法相同,但 ? 和 [...] 在张记账中没有特殊含义:它们只匹配自身。