
简介Pandoc 是一个广泛使用的开源文档格式转换工具支持 Markdown、HTML、LaTeX、DOCX、EPUB、ODT 等数十种格式的相互转换无论是技术笔记、论文草稿还是纯文本内容都能借助统一命令行界面完成格式转换因此特别适合有文档排版、批量生成等需求的写作者、开发者和研究者。这份 Windows 版资源包共收录 4 个文件主体为可直接运行的可执行程序另附用于查询命令参数和格式映射的 HTML 手册以及 txt、rtf 格式的版权与许可说明压缩包整体约 36MB。包体结构精简解压后即可使用对新手友好无需预先搭建复杂的排版环境配合 HTML 手册中的参数说明能快速上手将 Markdown 笔记转为 Word 报告、HTML 网页或 EPUB 电子书等工作流也能把 LaTeX 论文转为 DOCX 以方便协作修改显著减少手动复制和重复排版的时间。当前已有 829 人学习/下载适合需要频繁产出多格式文档的内容运营者、教务人员、技术博主和科研工作者对于缺少完整 Office 环境或希望用命令行批量处理文档的用户这份工具尤其能提升效率。作为较新的 3.6.4 版本它在保持原有功能完整性的同时对转换性能与兼容性做了进一步优化从日常的课程讲义、产品说明书到个人博客与电子出版物都能从中获得稳定高效的转换体验还可以借助内置手册探索自定义模板与样式控制满足更高要求的输出场景。 这段时间我陆陆续续把团队的文档规范从 Word 转向 Markdown但对外交付还是得交 docx、PDF一开始大家都在找各种在线转换工具传文件上传下载烦得要死后来我干脆把 pandoc 3.6.4 装到了所有人的机器上所有转换直接用命令行完成几分钟就能跑完一批。这篇文章就把我实际使用 pandoc 的完整经验写下来从安装、常用命令到各种绕不开的坑适合那些想把 Markdown 转成 Word/PDF/HTML、又不想被在线工具绑架的人。1. pandoc 的真实定位它不是转换工具是文档界的通用语言层1.1 pandoc 到底解决了什么问题很多人对 pandoc 的第一印象是“一个格式转换器”但这个理解太浅了。拿我自己的经历来说我需要同时维护一份产品文档的 Markdown 源文件、一份给客户看的 Word 版、一份发到官网的 HTML 版偶尔还要出一个带目录的 PDF 版。如果靠传统做法相当于同一份内容维护四份改一个参数要同步四处早晚要漏。pandoc 的思路完全不同它把“源格式”和“目标格式”彻底解耦。你只需要维护一份源文件让 pandoc 去处理中间的所有转换逻辑。而且它支持的格式列表长得吓人Markdown、HTML、LaTeX、DOCX、ODT、EPUB、Jupyter Notebook、reStructuredText、AsciiDoc、甚至 Jira 的 wiki 标记等等。它更像是一个“文档界的通用语言层”而不是单一格式的转换脚本。单看某一个方向的转换其他工具也能做到但能做到“几乎所有格式都能互转”、并且转换结果可控、可定制、可脚本化的目前我还没找到第二个。这也是为什么我用 pandoc 用了这么多年换了好几个项目始终没有把它从工具链里拿掉。1.2 为什么 3.6.4 这个版本值得盯一眼pandoc 3.6.4 是 3.6 系列的维护版本。熟悉 pandoc 的都知道2.x 时代它已经非常稳定而进入 3.x 之后官方把重心放在了两件事上一是把内部 API 和 JSON 表示方式往更规范的方向调整二是把 Lua 过滤器的机制做扎实。3.6.4 这种小版本虽然没有大张旗鼓的新功能但它把上一轮改动带来的边角问题基本收拾干净了。我自己升到 3.6.4 之后的直接感受是旧版本里某些 Markdown 表格的解析毛刺、docx 读写时偶发的结构异常、以及某些特殊符号在 PDF 输出时的转义问题都在这个版本里消停了。所以如果你之前被某个诡异 bug 卡住又正好卡在 3.5 或 3.6.0 附近直接升到 3.6.4 是当前最稳妥的选择。提示pandoc 的升级路径一直很激进大版本之间确实可能有破坏性变更。但从 3.6.4 反过来看如果你还在用 2.x升上来之前至少要把自己写的旧版 Lua 滤镜检查一遍因为 3.x 的过滤器 API 变了很多老脚本直接跑会报错。2. 安装与命令行基础从拿到安装包到跑通第一条转换2.1 各平台的安装方式pandoc 的安装在各平台都很简单选择权在你自己手里。Windows最省事的是直接去官网下载安装包双击安装。如果你用 winget 或者 Chocolatey一条命令也能搞定winget install pandoc。我习惯用 winget因为后续升级只需要再跑一遍同名命令。macOSbrew install pandocHomebrew 用户基本没有第二种选择。LinuxDebian/Ubuntu 系可以用apt install pandocCentOS/RHEL/Fedora 系对应dnf install pandoc。但要注意发行版仓库里的版本可能偏旧如果你想始终用最新版建议从 GitHub Releases 下载静态二进制包解压出来就能用。安装完验证一下版本pandoc --version能看到pandoc 3.6.4开头的一串信息说明环境已经准备好了。这一步没什么技术含量但我见过太多人装完不驗证结果后面报错半天才发现 PATH 里跑的是旧版。2.2 第一条命令和第二个命令默认情况下pandoc 的用法非常直白pandoc input.md -o output.html它做的事情是猜测输入格式是 Markdown猜测输出格式是 HTML然后转换。这就是 pandoc 最典型的“自动模式”——你不告诉它格式它会根据文件后缀自行判断。但在正式使用的时候我强烈建议你养成显式指定格式的习惯pandoc input.md -f markdown -t html5 -s -o output.html这里的-f是输入格式-t是输出格式-s是 standalone独立成文的意思。如果不加-spandoc 默认只输出一个内容片段不会有完整的html、head结构。这个细节是新手最容易忽略的转出来是个不完全的 HTML然后满世界找原因。第二条值得记住的命令是把 Markdown 转成 Wordpandoc input.md -o output.docxdocx 是 pandoc 里支持得特别好的一种格式也是日常办公场景里最常用的一类转换。这里同样先不展开样式定制等后面专门讲。2.3 参数优先级与常用开关用一段时间后你会发现pandoc 真正的威力不在“能转格式”而在“能用参数控制转换行为”。下面这几个开关是我每个项目里几乎必带的基础项--toc自动生成目录。搭配--toc-depth3控制目录层级。--number-sections给章节自动编号适合技术文档。--resource-path./images指定图片等资源的查找路径后面讲到图片坑的时候会再提。--metadata titlexxx往文档里塞元数据比如标题、作者、日期。--reference-doctemplate.docx使用自定义 Word 模板解决“转换出来的 Word 样式太丑”的问题。这些参数可以叠加使用没有数量限制。另外要注意一点pandoc 的参数解析是 GNU 风格-o后面跟输出文件参数顺序一般情况下没有强制要求但为了可读性我习惯把输入文件放在命令末尾。pandoc -s --toc --number-sections -f markdown -t html5 \ --metadata title测试文档 input.md -o output.html这种写法一眼就能看出“输入是什么、输出是什么、做了哪些加工”后续维护脚本的时候会省很多力气。3. 日常文档工作流里的三个高频场景3.1 Markdown 转 DOCX默认很丑但模板能救Markdown 转 DOCX 是 pandoc 用得最广泛的功能没有之一。默认转换出来的 Word 文档能看但离“能直接交付给客户”还有差距——标题字体、正文间距、表格样式都和公司规范对不上。解决思路不是手工去 Word 里一张一张改而是做一个 reference.docx 参考模板。先让 pandoc 生成一份默认的参考文档pandoc --print-default-data-file reference.docx custom-reference.docx把custom-reference.docx打开在 Word 里手动调整标题样式、正文字体、行距、表格样式保存。之后每次转换都带上它pandoc input.md -o output.docx --reference-doccustom-reference.docx这样做一次的收益是长期的模板定了之后团队所有人只要把命令里模板路径固定下来产出的 Word 都是统一风格。我自己就是把这份custom-reference.docx放进了 Git 仓库整个团队共用一份。3.2 Markdown/HTML 转 PDF中文字体是个老大难转 PDF 是 pandoc 里最让新手血压升高的一条路因为 pandoc 本身不渲染 PDF它本质上只是把文档转成 LaTeX再借 by LaTeX 引擎生成 PDF。默认引擎 pdflatex 在中文环境下基本是灾难必须换引擎换字体。我的固定方案是使用 XeLaTeX 配合系统字体pandoc input.md -o output.pdf \ --pdf-enginexelatex \ -V mainfontNoto Serif CJK SC \ -V CJKmainfontNoto Sans CJK SC \ -V geometry:margin2.5cm--pdf-enginexelatex指定引擎必须用它来支持中文。-V mainfont指定英文/正文西文字体。-V CJKmainfont指定中文衬线字体具体字体名以你系统里装的字体为准。-V geometry:margin2.5cm控制页面边距。如果你主要生成简体中文的 PDF我建议提前把上面这段存成一个脚本或者 Makefile以后每次转换只改文件名其他全部固定。注意Linux 上如果没装中文字体无论怎么指定都渲染不出中文只会出现一片方框。先用fc-list :langzh检查系统有没有可用的中文字体没有就先apt install fonts-noto-cjk。3.3 批量转换脚本化才是效率的分水岭单文件转换谁都会真正让 pandoc 发挥价值的是批量处理。我之前整理过一批几十篇 Markdown 文档需要一次性全部生成为 docx于是用了一个很简单的 for 循环for f in *.md; do pandoc $f -o ${f%.md}.docx --reference-doccustom-reference.docx --toc done这里${f%.md}是 Bash 的语法意思是去掉文件名末尾的.md这样生成的新文件会继承原文件名。整个命令跑完几十个 docx 批量产出中途不需要人工干预。再配合 cron、Jenkins或者 GitHub Actions就完全可以把“文档内容更新→自动转换→发布成品”这条链路自动化。还有一个小技巧值得分享用find配合循环处理子目录里的文件或者用xargs做并行转换。不过对大多数场景上面的 for 循环已经够用不要一开始就上复杂的自动化框架。4. 在项目里踩过的坑图片路径、目录、公式与表格4.1 图片相对路径为什么经常丢我最早用 pandoc 转 docx 的时候碰到最频繁的问题是Markdown 里明明有图片转出来的 Word 里图片位置全是空的。查了一圈发现pandoc 在工作时会以“当前工作目录”为基准去解析相对路径如果你的 Markdown 放在docs/下面图片放在docs/images/下面直接在项目根目录执行 pandoc它找不到images/xxx.png。解决办法有两种。一种是在执行 pandoc 之前先进入 Markdown 所在目录。另一种更稳妥使用--resource-path参数指定资源根目录。pandoc docs/input.md -o output.docx --resource-pathdocs这样 pandoc 会去docs/目录下找images/xxx.png同时它也会保留原路径的拼接逻辑。经验是如果项目目录结构比较复杂尽量在脚本里把--resource-path显式传进去不要依赖“当前目录碰巧正确”。4.2 TOC 目录为什么有时“不刷新”转 DOCX 时加了--toc生成的文档里确实有目录但你会发现目录页数是空的或者标题变了目录没变。这不是 pandoc 没生成而是 Word 的目录字段需要手动刷新一次右键点击目录选择“更新域”。这个行为经常被当成 bug其实原理很简单——pandoc 写在 docx 里的目录是一个 Word 域fieldWord 不会在打开文档时自动重算域内容。批量交付 Word 文档之前我一般会用一个小脚本把域刷新掉或者干脆接受“让用户手动刷新”这种操作。至少现在你已经知道它不是转换失败。4.3 表格转换的兼容性Markdown 里写表格很轻松但转出来往往有两种问题一是表格过宽二是合并单元格、复杂表头丢失。pandoc 对 Markdown 表格的支持是有边界的它支持 pipe table、grid table 等风格但如果你在 Markdown 里用了复杂嵌套表格转 docx 时大概率会变成一个简单的二维表样式信息丢掉。我的处理习惯是如果文档核心是复杂表格我不会把 Markdown 当唯一源而是先转成 docx再在 Word 里对表格做“高难度”排版。反过来如果表格本身简单那 pandoc 默认输出就够用。不要把 pandoc 当作一个能够无损应对所有排版的万能工具它的定位始终是“内容转换器”不是“排版引擎”。4.4 公式的坑技术文档里数学公式很常见。pandoc 的公式支持其实相当不错Markdown 里的$...$行内公式和$$...$$块级公式转 docx 时会被转换成 Word 原生的 OMML 公式在 Word 里可以正常编辑转 PDF 时交给 LaTeX 渲染。真正麻烦的是转 HTML。默认情况下 HTML 输出不会加载任何数学渲染库公式显示为原始 LaTeX 代码。这时候要给输出参数加上--mathjaxpandoc input.md -o output.html --mathjax加了之后HTML 会引入 MathJax 的 CDN 脚本在浏览器里把公式渲染出来。离线环境不方便用 CDN 就把 MathJax 本地部署然后把--mathjax本地路径传进去。这个参数卡了我不少时间现在算记住了。5. 进阶玩法定制 reference.docx、Lua 滤镜与元数据5.1 定制 reference.docx 再从细节上抠样式前面说过生成custom-reference.docx的方法但这里有个容易被忽略的点reference 模板里只改字体还不够Word 里的“样式”其实是一套完整定义包括各级标题的编号方式、段前段后间距、表格边框套用等。你在 Word 里手动修改“标题 1”样式保存后 pandoc 转换时就会使用这个样式。如果你需要公司级统一的排版规范可以找一个已经符合规范的 docx 文档把整个文件作为模板复制过来然后在 Word 里清理掉正文内容保留样式定义。这样做出来的 reference 模板比从零新建一个再慢慢设置要快得多。5.2 用 Lua 滤镜做细节调整当某些转换逻辑无法通过参数完成时Lua 滤镜是 pandoc 给你留的“后门”。Lua 滤镜的本质是在转换过程中截获文档的中间表示对元素做修改后再交还给 pandoc。举个例子我之前需要在所有 Markdown 图片输出时默认加上一个宽度限制于是写了一个非常小的滤镜function Image(el) el.attributes.width 50% return el end保存为set-img-width.lua然后执行pandoc input.md -o output.html --lua-filterset-img-width.lua这么一来所有图片在 HTML 输出里都会被加上width50%的属性。为什么用 Lua因为 Lua 滤镜不需要编译环境pandoc 内置了解释器脚本写错会直接报错告诉你问题在哪相比写一个完整的 Haskell 过滤器Lua 的上手成本低得多。注意 3.x 版本的滤镜 API 和 2.x 有差异你从网上抄旧脚本的时候如果报类似attempt to call field pandoc.utils的错大概率是 API 迁移导致的。先确认脚本是在哪个 pandoc 大版本下写的再决定改法。5.3 元数据与变量替换pandoc 里的 metadata 机制很适合做“一份模板多处填充”的场景。比如团队里多个模块的文档结构相同只是模块名、版本号、作者不同这时可以在转换命令里传入变量pandoc template.md -o output.docx \ -M module订单系统 \ -M version2.1.0 \ -M author王工然后在 Markdown 模板里通过$module$、$version$、$author$引用这些变量。这个机制可以用在周报、接口文档、发布说明等重复性文档上。我自己会把一批发布说明做成模板发版时只改几个变量值再批量生成效率和准确性都比手抄修改高很多。结尾pandoc 3.6.4 这个版本我用下来最大的感受是稳。它没有给人“哇新功能好酷”的冲击感但把以前那些恼人的边角问题都收拾干净了。如果你正要开始用 pandoc我的建议很明确先跑通一个最简单的 Markdown 到 docx 转换然后马上花时间定制一份属于自己的 reference.docx再把常用命令固化成脚本。前两个动作做完你已经能用得很顺手了。最后多提一句pandoc 的官方 changelog 写得非常详细升级版本前哪怕只扫一遍上面提到你正在用的功能也能避免大部分兼容性翻车事故。本文还有配套的精品资源点击获取