批量操作技巧
随着笔记数量增加,单条操作效率低下。掌握批量操作技巧,可以大幅提升笔记管理效率。
批量重命名
内置重命名
文件重命名:
- 在文件列表中右键点击文件
- 选择「重命名」
- 输入新名称
- 自动更新所有链接
批量重命名:
- 选择多个文件(
Ctrl+点击) - 右键选择「重命名」
- 使用模板批量修改
使用插件重命名
File Cleaner 插件:
yaml
功能:
- 删除空文件
- 删除未使用的附件
- 批量重命名Templater 脚本重命名:
javascript
<%*
// 批量重命名文件夹下的文件
const folder = app.vault.getAbstractFileByPath("笔记文件夹");
const files = app.vault.getMarkdownFiles()
.filter(f => f.path.startsWith("笔记文件夹/"));
for (const file of files) {
const newName = "前缀_" + file.name;
await app.fileManager.renameFile(file, file.parent.path + "/" + newName);
}
%>正则表达式重命名
使用「Rename Note」插件:
yaml
规则示例:
原名: (\d{4}-\d{2}-\d{2})-(.*)
新名: 日记/$1/$2
原名: (.*)\.md
新名: 归档/$1批量移动
文件夹操作
拖拽移动:
- 选择多个文件
- 拖拽到目标文件夹
- 确认移动操作
剪切粘贴:
- 选择文件,
Ctrl+X - 打开目标文件夹
Ctrl+V粘贴
按条件移动
使用 Dataview 查询后移动:
dataview
LIST
FROM ""
WHERE file.mtime < date(today) - dur(90 days)使用脚本批量移动:
javascript
<%*
// 移动 90 天未修改的文件到归档
const archivePath = "归档";
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - 90);
const files = app.vault.getMarkdownFiles();
for (const file of files) {
if (file.stat.mtime < cutoffDate.getTime()) {
const newPath = archivePath + "/" + file.name;
await app.fileManager.renameFile(file, newPath);
}
}
%>批量修改内容
查找替换
内置查找替换:
Ctrl+H打开查找替换- 输入查找内容
- 输入替换内容
- 点击「全部替换」
多文件查找替换:
Ctrl+Shift+H全局查找替换- 设置搜索范围
- 执行批量替换
使用正则表达式
yaml
常用正则:
删除空行: ^\s*$ → (空)
统一日期格式: (\d{4})/(\d{2})/(\d{2}) → $1-$2-$3
添加标签: ^# (.*) → # $1\n#标签名批量添加 Frontmatter
使用 Templater:
javascript
<%*
// 为所有笔记添加属性
const files = app.vault.getMarkdownFiles();
for (const file of files) {
const content = await app.vault.read(file);
// 检查是否已有 frontmatter
if (!content.startsWith("---")) {
const frontmatter = `---
created: ${file.stat.ctime}
modified: ${file.stat.mtime}
---\n\n`;
await app.vault.modify(file, frontmatter + content);
}
}
%>批量添加标签
使用搜索替换
查找: ^# (.*)
替换: # $1\n#新标签使用插件
Tag Wrangler 插件功能:
- 批量重命名标签
- 合并标签
- 删除标签
Templater 脚本
javascript
<%*
// 为特定文件夹的文件添加标签
const folder = "项目";
const files = app.vault.getMarkdownFiles()
.filter(f => f.path.startsWith(folder));
for (const file of files) {
const content = await app.vault.read(file);
if (!content.includes("#项目")) {
await app.vault.append(file, "\n\n#项目");
}
}
%>批量创建笔记
从模板创建
使用 Templater:
javascript
<%*
// 批量创建日记
const startDate = new Date("2024-01-01");
const endDate = new Date("2024-12-31");
for (let d = startDate; d <= endDate; d.setDate(d.getDate() + 1)) {
const dateStr = d.toISOString().split('T')[0];
const fileName = `日记/${dateStr}.md`;
if (!await app.vault.adapter.exists(fileName)) {
await app.vault.create(fileName, `# ${dateStr}\n\n`);
}
}
%>从 CSV 创建
使用 Dataview:
dataviewjs
// 从 CSV 读取数据创建笔记
const csv = await app.vault.adapter.read("data.csv");
const rows = csv.split("\n").slice(1); // 跳过标题行
for (const row of rows) {
const [title, content] = row.split(",");
const fileName = `笔记/${title}.md`;
await app.vault.create(fileName, `# ${title}\n\n${content}`);
}批量删除
删除空文件
使用 File Cleaner 插件:
yaml
配置:
删除空文件: true
删除空文件夹: true
保留特定文件: false删除未使用的附件
查找未使用的附件:
dataview
LIST
FROM "附件"
WHERE !file.outlinksTemplater 清理脚本:
javascript
<%*
// 删除未被引用的图片
const images = app.vault.getFiles()
.filter(f => f.extension.match(/png|jpg|jpeg|gif/));
for (const image of images) {
const backlinks = app.metadataCache.getBacklinksForFile(image);
if (backlinks.size === 0) {
await app.vault.trash(image);
console.log(`已删除: ${image.path}`);
}
}
%>批量导出
导出为 PDF
使用命令:
- 选择要导出的文件
- 右键 → 导出为 PDF
- 选择输出位置
导出为 Markdown
保留链接关系:
javascript
<%*
// 导出笔记及关联笔记
const startFile = app.workspace.getActiveFile();
const exported = new Set();
async function exportWithLinks(file, depth = 0) {
if (exported.has(file.path) || depth > 2) return;
exported.add(file.path);
const content = await app.vault.read(file);
const exportPath = `导出/${file.name}`;
await app.vault.adapter.write(exportPath, content);
// 获取链接的文件
const links = app.metadataCache.getFileCache(file)?.links || [];
for (const link of links) {
const targetFile = app.metadataCache.getFirstLinkpathDest(link.link, file.path);
if (targetFile) {
await exportWithLinks(targetFile, depth + 1);
}
}
}
await exportWithLinks(startFile);
%>批量格式化
统一格式
使用 Linter 插件:
yaml
规则:
- 标题格式: 统一标题层级
- 列表格式: 统一列表符号
- 空行: 统一空行数量
- 标签格式: 统一标签位置批量调整标题
Templater 脚本:
javascript
<%*
// 将所有标题提升一级
const file = app.workspace.getActiveFile();
let content = await app.vault.read(file);
content = content.replace(/^#{1,6} /gm, match => {
const level = match.length - 1;
return level > 1 ? '#'.repeat(level - 1) + ' ' : match;
});
await app.vault.modify(file, content);
%>批量操作工具对比
| 工具 | 适用场景 | 学习曲线 |
|---|---|---|
| 内置搜索替换 | 简单文本替换 | 低 |
| 正则表达式 | 复杂模式匹配 | 中 |
| Templater | 自定义脚本 | 高 |
| Dataview | 数据查询操作 | 中 |
| 专用插件 | 特定功能 | 低 |
安全操作建议
操作前备份
yaml
备份方式:
1. 使用 [文件恢复核心插件](/basics/file-recovery)
2. Git 版本控制
3. 手动复制库文件夹小批量测试
- 先在少量文件上测试
- 确认结果正确
- 再执行批量操作
使用撤销
Ctrl+Z撤销最近操作- 注意:某些批量操作无法撤销
实用脚本集合
批量添加创建日期
javascript
<%*
const files = app.vault.getMarkdownFiles();
for (const file of files) {
const content = await app.vault.read(file);
if (!content.includes("created:")) {
const frontmatter = `---\ncreated: ${new Date(file.stat.ctime).toISOString().split('T')[0]}\n---\n\n`;
await app.vault.modify(file, frontmatter + content);
}
}
%>批量整理附件
javascript
<%*
// 按年份整理附件
const files = app.vault.getFiles()
.filter(f => f.extension.match(/png|jpg|jpeg|gif|pdf/));
for (const file of files) {
const year = new Date(file.stat.ctime).getFullYear();
const newPath = `附件/${year}/${file.name}`;
if (file.path !== newPath) {
await app.fileManager.renameFile(file, newPath);
}
}
%>批量生成索引
javascript
<%*
// 为每个文件夹生成索引
const folders = app.vault.getAllFolders();
for (const folder of folders) {
const files = app.vault.getMarkdownFiles()
.filter(f => f.parent.path === folder.path);
if (files.length > 0) {
let content = `# ${folder.name || "根目录"} 索引\n\n`;
for (const file of files) {
content += `- [[${file.basename}]]\n`;
}
const indexPath = folder.path + "/索引.md";
await app.vault.adapter.write(indexPath, content);
}
}
%>提示
批量操作前务必备份!复杂的批量操作建议先用小规模数据测试。
注意
某些批量操作(如删除)可能无法撤销,请谨慎操作。