1. 几万行日志里的空行,vi 一条命令就能清干净
如果你手里有一份几万行的文件名清单、日志导出或者配置文件,中间夹着大量空行,用图形编辑器打开会卡到怀疑人生,滚动条拖半天还找不到规律。这种场景其实特别适合回到终端,用 vi(或 vim)的 ex 命令一次性处理。核心命令就一条::g/^$/d,意思是「全局匹配所有空行,然后删除」。它不依赖鼠标、不依赖插件,在服务器上、在 AIX 上、在任何有 vi 的环境里都能跑。
这篇内容面向需要批量整理日志、配置文件和代码文件的开发者,重点不是讲 vi 有多强,而是把「删除空行」这件事拆成可复制、可校验的动作:先确认文件状态,再执行命令,最后用行数对比验证结果。同时我会给出一套 TaoToken 统一 Key 通道下的配置骨架,把模型调用和本地编辑流程串起来,方便你在整理文件时顺手让模型帮你做二次检查。整套流程实测下来,从打开文件到验证完成,几分钟就能搞定。
2. 为什么用 vi 处理空行,而不是图形编辑器
图形编辑器处理大文件时,常见问题是加载慢、搜索卡、批量替换容易误伤。vi 的优势在于它是流式处理思维:命令直接作用于缓冲区,不需要渲染每一行。对于「删除所有空行」这种规则明确的任务,vi 的:g全局命令比手动查找替换更稳。
这里要先区分两个容易混淆的写法。:g/^$/d匹配的是真正的空行,也就是行内没有任何字符。而:g/^s*$/d这种写法在不同环境里含义不一样,s在部分正则里被当作普通字符,真正表示空白字符应该用\s。所以更稳妥的写法是:
" 删除真正的空行(行内无任何字符) :g/^$/d " 删除只包含空格或 Tab 的行 :g/^\s*$/d如果你只是想删掉完全空的行,用第一条就够了。如果文件里还有「看起来是空行、其实带了几个空格」的行,用第二条。我试过在几万行的清单文件上跑:g/^$/d,执行瞬间完成,保存后行数直接少了一大截。
TaoToken 在这里的角色是统一 Key 通道:当你需要让模型帮你检查清理后的文件、生成校验脚本或者解释某段配置时,不用在多个平台之间切换 Key,一个通道就能覆盖模型对话、编码计划和 API 调用。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api ,配置时注意 API 地址不加 UTM 参数。
3. TaoToken 统一 Key 通道的配置骨架
在动手清理文件之前,先把模型通道配好,这样后面验证和二次处理都能直接调用。TaoToken 的配置分两种常见形式:一种是给支持 OpenAI 兼容接口的工具用的settings.json,另一种是给偏工程化的工具用的config.toml。下面给出可直接复制的骨架。
3.1 settings.json 配置骨架
{ "api_key": "你的_TaoToken_Key", "base_url": "https://taotoken.net/api", "model": "claude-sonnet-4-20250514", "timeout": 60, "max_retries": 3 }这里base_url填 https://taotoken.net/api ,不要带任何查询参数。api_key从控制台的 API Keys 页面获取,地址是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。model字段按你实际要用的模型填,如果只是做文本校验,选一个响应快的就行。
3.2 config.toml 配置骨架
[provider] name = "taotoken" api_key = "你的_TaoToken_Key" base_url = "https://taotoken.net/api" [model] default = "claude-sonnet-4-20250514" max_tokens = 4096 temperature = 0.2 [retry] max_attempts = 3 backoff_seconds = 2temperature设低一点,做文件校验和命令解释时输出更稳定。max_tokens按你的文件片段长度调整,如果只是让模型看几行配置,4096 足够。
3.3 长期编码场景用 Coding Plan
如果你不只是偶尔校验文件,而是长期做编码、Agent 任务,可以走 Coding Plan,入口是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。它适合把模型调用嵌进日常开发流程,比如让模型帮你生成 vi 命令、检查清理结果、写行数对比脚本。
4. 可复制的 vi 删除空行操作步骤
下面按「打开文件 → 确认状态 → 执行删除 → 保存 → 验证」的顺序走一遍。每一步都给命令和预期结果。
4.1 打开文件并确认行数
先用 vi 打开目标文件:
vi filenames.txt进入后先不要急着删,按Esc确保在普通模式,然后输入:
:set number这会把行号显示出来,方便你观察空行分布。接着记录当前总行数:
:$光标会跳到最后一行,状态栏会显示行号,比如35000。把这个数字记下来,后面验证要用。
4.2 执行删除空行命令
在普通模式下输入:
:g/^$/d回车后 vi 会立即处理整个缓冲区。如果文件很大,可能会有一瞬间的停顿,这是正常的,不要以为卡死了就中断。处理完成后,你会看到行号重新排列,空行消失。
如果文件里存在「带空格的空行」,改用:
:g/^\s*$/d4.3 保存并退出
确认结果无误后保存:
:wq如果只是想先看看效果、不保存,可以用:
:q!4.4 用行数对比验证结果
保存后回到终端,用wc -l对比清理前后的行数:
wc -l filenames.txt假设清理前是 35000 行,清理后是 28000 行,说明删掉了 7000 个空行。这个数字应该和你之前在 vi 里观察到的空行数量大致吻合。如果差异很大,说明可能误删了非空行,需要检查命令是否写错。
更严谨的做法是先把原文件备份,再对比:
cp filenames.txt filenames.bak vi filenames.txt # 执行 :g/^$/d 后保存 wc -l filenames.bak filenames.txt输出会同时显示两个文件的行数,差值就是删除的空行数。
5. 验证请求与成功结果
清理完成后,除了行数对比,还可以用模型做一次语义校验。把清理后的文件片段发给模型,让它确认没有误删有效内容。调用时用前面配好的 TaoToken 通道。
5.1 用模型对话验证清理结果
打开模型对话页面,地址是 https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。把清理前后的行数、以及文件的前几行和后几行贴进去,问它:「这个文件清理空行后,行数从 35000 变成 28000,前后内容是否连续,有没有明显断裂?」模型会帮你判断是否存在误删。
5.2 用 API 做自动化校验
如果你想把校验做成脚本,可以用 curl 调 API:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer 你的_TaoToken_Key" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "messages": [ {"role": "user", "content": "文件清理空行后行数从35000变为28000,请判断是否合理,并给出校验建议。"} ] }'返回结果里会包含模型的判断。如果它认为行数变化合理,说明清理动作基本正确。注意 API 地址是 https://taotoken.net/api ,不要加 UTM 参数。
5.3 成功结果的判断标准
一次成功的空行清理应该满足三个条件:第一,行数减少量等于空行数量;第二,文件首行和末行内容没有变化;第三,用grep -c '^$' filenames.txt检查剩余空行数为 0。三条都满足,就可以确认清理完成。
6. 本篇常见错误排查
6.1 命令输入后没反应
很多人第一次用:g/^$/d时,输入完回车发现没动静,以为命令错了。其实 vi 正在处理缓冲区,文件越大停顿越明显。这时候不要重复输入命令,也不要按 Ctrl+C,等它处理完就行。如果确实卡住超过十几秒,可能是文件太大或者正则匹配范围过广,可以按 Esc 后重新检查命令。
6.2 误删了非空行
最常见的原因是正则写错。比如把:g/^$/d写成了:g/^s*$/d,在某些环境里s被当作普通字符,匹配的是「以 s 开头、后面任意字符、以 s 结尾」的行,结果删掉了不该删的内容。正确写法是:g/^\s*$/d,\s才表示空白字符。如果已经误删,用u撤销,或者从备份文件恢复。
6.3 保存后行数没变化
可能是命令没有真正执行。检查一下是否在普通模式下输入的命令,是否按了回车。另外,如果文件是只读的,:wq会失败,需要用:w !sudo tee %或者先改权限。
6.4 API 调用返回 401
说明 Key 不对或者没带上。检查Authorization头里的 Bearer 后面是否是你的 TaoToken Key,Key 是否从 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 正确复制。另外确认base_url是 https://taotoken.net/api ,没有多余斜杠或参数。
6.5 模型返回内容不完整
如果max_tokens设得太小,模型输出会被截断。把max_tokens调到 4096 或更高。如果还是不行,检查网络是否稳定,或者换一个响应更快的模型。
7. 把清理流程固化下来
清理空行这件事,单次操作很简单,但如果每周都要处理日志,最好把流程固化。我的做法是写一个 shell 脚本,把 vi 命令、行数对比和 API 校验串起来:
#!/bin/bash FILE=$1 cp "$FILE" "$FILE.bak" vi -c ':g/^$/d' -c ':wq' "$FILE" echo "清理前: $(wc -l < "$FILE.bak") 行" echo "清理后: $(wc -l < "$FILE") 行" echo "剩余空行: $(grep -c '^$' "$FILE")"这个脚本用vi -c直接执行命令,不需要手动进入交互模式。跑完之后,行数和剩余空行数一目了然。如果还想让模型做二次确认,可以在脚本最后加一行 curl 调用,把结果发给模型判断。
TaoToken 的接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有完整的接口说明和示例。ClaudeCode 相关的配置可以参考 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claude_code&utm_campaign=rewrite ,适合把模型能力嵌进编码流程。
整套流程跑通之后,你会发现 vi 删除空行只是一个小动作,真正有价值的是「命令 + 验证 + 模型校验」这个闭环。下次再遇到几万行的文件,不用再一个个手动删了。