减少循环次数、避免无效IO:Shell脚本性能优化实战
同样处理100万行访问日志的任务我手里一份老脚本跑了1分56秒优化完重写一遍只要7秒多。差别就两条循环里塞了太多外部命令每个循环迭代都在fork子进程日志逐行写磁盘每次迭代都在重复open/close文件。这两个坑叠加起来哪怕逻辑再简单性能也会被拖垮。这篇内容适合谁看日常维护Shell脚本、写定时任务、做日志分析、跑数据批处理的人。只要你的脚本处理的是文本文件、逐行数据就绕不开循环和IO。标题里说的减少循环次数、避免无效IO听起来像两句正确的废话但拆开看全是细节循环里的哪一行命令最贵为什么awk一个进程能干翻while循环里一堆命令重定向和文件描述符怎么用才能避免百万次open/close优化前怎么测量才不被假象骗了我会按实际定位问题的顺序把这些讲透。1. 先搞懂Shell慢在哪fork/exec和文件IO这笔账1.1 外部命令是脚本里最贵的单品Shell脚本里几乎所有性能问题都能归结到一件事进程创建。bash执行一条外部命令时要先fork一个子进程再exec加载对应的可执行文件。这个forkexec的开销通常在几百微秒到几毫秒量级。听起来不多但乘上循环次数就吓人了。举个例子你写一个最简单的空循环time for i in {1..10000}; do :; done:是bash内建命令不fork耗时基本可以忽略。但你把循环体改成执行一条外部命令time for i in {1..10000}; do /bin/true; done/bin/true大概就是空程序啥也不干但这个耗时可能立刻涨到1秒以上。为什么它每次循环都要fork一个新进程1万次循环就是1万次fork。如果把循环体换成grep、awk、cut这种稍微干点活的命令再叠加每次循环读取输入10万行日志跑出几十秒就太正常了。我见过一个典型的失败案例循环里用echo $line | awk {print $9}取状态码再嵌套一个if echo $line | grep -q ...做判断。处理一行日志bash至少fork了4次echo一次、awk一次、echo一次、grep一次。一行40微秒的活被放大到几百微秒。百万行下来光是fork开销就把脚本拖死了。所以要记住一个判断标准如果循环体里出现了外部命令循环次数和外部命令数量的乘积就是你的fork次数。这个数字一旦上了百万量级脚本几乎没有优化空间只能重构。1.2 无效IO往往比循环本身更致命进程创建是显性的慢文件IO是隐性的慢。很多人写脚本时根本意识不到自己在做无效IO。最常见的一种无效IO是循环内逐行写文件while read -r line; do ... echo $line /tmp/result.log done input.log每次执行重定向shell都要打开一次文件、写数据、关闭文件。100万行就是100万次open/close系统调用。就算每次打开关闭只有几微秒100万次也是好几秒的纯开销而且这些系统调用还会和page cache、磁盘回写纠缠在一起产生连锁延迟。还有一种无效IO是重复读同一份数据。比如说你要从日志里统计状态码分布还要统计TOP URL代码写成cat access.log | awk {print $9} | sort | uniq -c cat access.log | awk {print $7} | sort | uniq -c看起来挺正常但access.log被你完整读了两遍。文件小还没感觉文件一旦超过几百MB多读一遍就意味着多等一次磁盘IO时间。awk其实完全支持单遍扫描、多个统计变量同时维护为什么非要读两遍无效IO的本质是你用M次IO做了N次本来可以1次完成的工作而IO恰恰是脚本性能的硬瓶颈——CPU快、内存快、磁盘相对慢管道还有调度开销。理解了这两笔账优化方向就很清晰了。2. 减少循环次数从逐行处理到一次扫描2.1 三层取舍去循环、换内建、改结构减少循环次数不是一句口号而是有一套先后顺序的取舍逻辑。我自己的思路一般是三层第一层先想能不能去掉循环。awk、sed、sort、uniq、paste这些文本工具本身就是按行处理的专用程序它们内部用C实现单进程扫描文件比bash的while循环不知快到哪里去。能用awk解决的事尽量不要用while。第二层如果必须保留循环把循环体里的外部命令全部换成bash内建能力。判断字符串用[[ ]]、case切字段用参数扩展算数用(( ))读文件用mapfile。内建命令不fork子进程开销少两三个数量级。第三层如果连内建命令都嫌慢重新审视数据结构。是不是每次循环都在重复扫描同一个文件能不能提前把数据加载到关联数组里能不能一次循环把多个统计指标都算完这个顺序很重要。很多人一上来就在第二层做微优化结果循环结构本身是烂的改几个命令也就快20%。真正让性能起飞的是第一层和第三层。2.2 实战案例状态码统计从whilegrep到awk数组拿一个最常见的场景举例统计Nginx访问日志里各HTTP状态码的数量。初版代码长这样while read -r line; do code$(echo $line | awk {print $9}) echo $code done access.log | sort | uniq -c这段代码逻辑没错但性能灾难。每行循环做了两件最贵的事fork一个echo、fork一个awk。我拿一个约200MB的日志实测跑完大概2分多钟。如果日志里还有异常行管道中断、子shell上下文切换还会进一步拖慢。用awk重写awk {codes[$9]} END {for (c in codes) print codes[c], c} access.log | sort -rn这版只有一个外部程序在跑。awk单进程单遍扫描状态码作为数组下标出现一次计数器加一内存里聚合文件读完直接输出结果最后sort只对有限个状态码排序。同样200MB日志实测几秒跑完性能差距两个数量级。区别在哪里awk是C写的它的逐行循环发生在进程内部没有fork、没有管道、没有子shell而bash的while循环每行都在创建新进程。循环次数从每行一次进程创建变成了整个文件只创建2个进程awk和sort。这才是减少循环次数的真正含义——不是少写几个for而是别让循环体内出现外部命令。2.3 循环内的内建替代外部替换表不是所有场景都能用awk解决比如你要对每一行做复杂的业务判断就绕不开循环。这种情况下把外部命令换成内建命令能做多少优化我用一张表总结常见替换任务低效写法高效写法说明判断字符串包含子串echo $x | grep -q abc[[ $x *abc* ]]前者fork一次后者纯内建多条件字符串匹配echo $x | grep -E A|Bcase $x in *A*|*B*) ...;; esaccase是模式匹配不fork取冒号前的字段echo $line | cut -d: -f1user${line%%:*}参数扩展零fork取路径文件名basename $pathname${path##*/}参数扩展注意尾斜杠边界情况数值累加sum$(expr $sum 1)((sum))expr是外部命令逐行读入数组while read...; donemapfile -t arr filemapfile批量读减少循环迭代字符串转大写echo $x | tr a-z A-Zy${x^^}bash4内建我在实际项目里用这套替换把一个逐行处理配置文件的脚本从每行3次fork降到了0次fork。原来处理120万行配置要6分多钟改成纯内建版本后40秒左右跑完。性能提升主要不是来自命令本身快而是把每行3次fork这个乘法因子彻底消掉了。这里有一个很重要的坑要提醒bash内建echo也不一定总是内建。如果shopt开启了xpg_echo或者你用了/bin/echo的绝对路径echo也会变成外部命令。排查性能问题时先确认你调用的命令真的是内建版本。3. 避免无效IO文件描述符、缓冲与临时文件3.1 逐行写文件百万次open/close的开销循环内逐行重定向写文件是我在线上脚本里吃过亏最多的模式。以清理程序为例while read -r line; do if [[ $line *ERROR* ]]; then echo $line /var/log/error.log fi done app.log这段代码表面看没啥问题条件过滤后才写。但一旦app.log很大ERROR行很多每一次echo error.log都是一次openwriteclose。系统调用次数瞬间爆炸。我实测过一个类似场景文件里20万条匹配行光写文件这块就多花了十几秒——磁盘根本没满系统CPU被open/close和文件系统锁拖住了。这时候先别急着上缓冲库Shell自带的两个方案就够用。3.2 提前打开fd和批量重定向第一个方案也是最简单的把重定向从循环内移到循环外。while read -r line; do if [[ $line *ERROR* ]];then echo $line fi done app.log /var/log/error.log整个循环的stdout一次性指向目标文件循环体里的echo只是写标准输出shell只在循环结束时打开一次文件、写入全部内容、关闭一次。这一处改动可能就省掉几十万次open/close。第二个方案是提前打开文件描述符。有些场景下你把stdout重定向给文件了循环内部还要读到别的管道输出就会乱这时候用fd更干净exec 3 /var/log/error.log while read -r line; do if [[ $line *ERROR* ]]; then echo $line 3 fi done app.log exec 3-exec 3 file在循环开始前把fd 3绑定到文件循环内3只做write不重复open/close循环结束后exec 3-关闭fd。这个模式在脚本里同时写多个输出文件时特别有用你可以定义fd 3、fd 4分别指向不同日志按需写入互不干扰。用fd要记住两个注意事项bash里fd 0、1、2已被标准输入输出占用自定义fd用3到9fd必须显式关闭否则脚本结束时还开着可能影响后续命令对同一文件的操作。我在一个脚本里就是因为忘了关fd后面mv目标文件一直报Text file busy排查了半天才发现。3.3 /dev/shm与避免重复读同一文件临时文件位置也有讲究。默认/tmp在普通磁盘上如果你的脚本频繁创建删除几十MB的中间文件磁盘IO会很心疼。Linux提供了/dev/shm这是内存文件系统读写走的是内存页比磁盘快一个量级。用法很简单tmpfile$(mktemp -p /dev/shm) ... rm -f $tmpfile注意两点/dev/shm空间受内存大小限制默认通常是物理内存的一半别把几个GB的大文件往里塞内存文件系统断电即失仅供临时使用。我在日志分析脚本里把中间排序文件放/dev/shm整条流水线从十几秒降到3秒成本只是一行mktemp参数。另一个和IO相关的高频坑是重复读文件。很多人写统计脚本时习惯先grep过滤出一个子集再用awk统计或者同一个文件被多段脚本反复读。实际上awk支持在单次扫描中同时完成过滤、统计、分支判断。我重新组织了统计逻辑后文件从被读3次变成了只读1次IO成本直接除以3。关于缓冲还有一条经验没必要迷信stdbuf。shell的文本工具默认对stdout做全缓冲写入磁盘时是攒一批写一批这本身就是好的行为。stdbuf -oL改成行缓冲适合实时日志场景但会显著增加write次数非实时处理的脚本强行加行缓冲反而是性能倒退。我见过有人给awk套stdbuf -oL处理大文件性能反而掉了20%纯属画蛇添足。4. 不测量就没资格谈优化性能定位的几条实测路径4.1 从time到strace快速定位瓶颈优化Shell脚本最大的误区是凭感觉。你觉得循环慢也许慢在IO你觉得IO慢也许慢在管道阻塞。正确的顺序永远是先测量再动手。第一件趁手工具是bash内建time加上TIMEFORMATTIMEFORMATreal %R user %U sys %S time bash script.shuser是CPU在用户态花的时间sys是内核态花的时间。如果一个脚本user占了大头多半是外部命令和计算太多sys占了大头通常是系统调用太多比如反复open/close、read/write。这个粗略定向能帮你决定先优化哪边。第二件工具是strace -c。它能统计脚本运行期间所有系统调用的次数strace -c -f bash script.sh跑完看输出如果fork、wait4、openat、close这几个调用的次数高得离谱瓶颈就一目了然。我第一次用strace查一个慢脚本发现clone进程创建次数接近500万次瞬间就明白问题全在循环内部的命令调用上。第三件是/usr/bin/time -v注意用绝对路径避免bash内建time干扰/usr/bin/time -v bash script.sh输出里会有Maximum resident set size可以同时监控脚本峰值内存。Shell脚本通常内存不是瓶颈但如果你用了mapfile把超大文件整进数组内存就可能爆。4.2 优化要建立基线一次只改一处做性能优化时我有一条铁律先保存原版本运行时间和输出然后一次只改一处每改一处都重新跑时间、记录结果。为什么要这样因为性能问题的成因经常是交互的。你同时改了循环内部命令和重定向方式脚本快了但到底是哪个改动生效的不知道。下次再遇到类似问题你还是得重新猜。我见过团队里有人优化脚本一次改了四五个点测出来快了很多但上线后某天数据量大了又慢回原形因为真正起效的那个优化点在特定数据量下失效了其他改动其实没用没人能说清楚。建议维护一个简单的基线表版本处理行数realusersys峰值内存备注v0 原始版100万34.2s3.1s31.0s2.1MB基准v1 去cat管道100万28.7s2.9s25.5s2.2MB有效v2 while改awk100万2.1s1.4s0.6s4.8MB大幅提升v3 改用mapfile100万2.1s1.4s0.6s5.1MB无变化回退v3这个例子很典型我用mapfile替代while read跑完发现时间没变化说明这个循环本身不是瓶颈改动没必要保留。有了基线表每个改动的价值都清清楚楚。4.3 别被并行绑架xargs -P的适用边界聊性能优化一定会有人提并行。循环慢上xargs -P跑满CPU啊。这话一半对一半错。xargs -P确实能把任务分发到多个进程并行执行适合那些CPU密集、任务间完全独立的场景。比如批量压缩一堆日志文件find logs/ -name *.log -print0 | xargs -0 -P 4 -I {} gzip {}每个文件独立压缩互不干扰4个进程并行压缩时间接近单进程的1/4这种并行是实打实的收益。但并行不是万能药。如果你的瓶颈在IO比如awk单进程已经把磁盘读满了开4个并行只会让多个进程同时争抢同样的磁盘带宽还额外增加上下文切换和内存开销。我曾经试过用xargs -P 8并行统计8个日志文件结果总耗时和串行几乎一致内存还翻了几倍最后老老实实改回单进程串行批量处理。判断能不能并行的标准就一句话任务除以数据量到底是CPU在等数据还是数据在等CPU。Shell脚本里绝大多数文本处理都是数据在等CPU并行空间很小真正适合并行的是那些每个任务内部有大量独立计算的场景。5. 完整优化记录一条百万行统计命令的34秒到2.1秒5.1 初版while循环里塞了四个外部命令最后用一个完整的优化案例收尾。任务统计100万行访问日志的状态码分布以及TOP 10的请求URL。最早的版本是这个#!/bin/bash logfile$1 while read -r line; do code$(echo $line | awk {print $9}) url$(echo $line | awk {print $7}) echo $code $url done $logfile /tmp/stat.tmp sort -k1,1n /tmp/stat.tmp | uniq -c | sort -rn | head -10这段脚本的问题一眼就能看出来每行运行了两次awk每次还带一次echo一共4次fork。处理100万行就是400万次进程创建。我实测下来的时间惨不忍睹real 34秒多sys高达31秒。sys这么高完全是被fork和文件操作拖的。5.2 改版awk单遍扫描加两个临时文件重写版本把统计全部放进awk里一次扫描同时维护状态码和URL两个计数器#!/bin/bash logfile$1 awk { codes[$9] urls[substr($7,1,100)] } END { for (c in codes) print codes[c], c /tmp/codes.txt for (u in urls) print urls[u], u /tmp/urls.txt } $logfile sort -rn /tmp/codes.txt echo --- TOP URL --- sort -rn /tmp/urls.txt | head -10 rm -f /tmp/codes.txt /tmp/urls.txtawk单进程处理100万行几个条件分支和数组累加耗时大概1秒多两个sort排序总共几万条记录加起来不到1秒。整个脚本实测2.1秒。从34秒到2.1秒提升16倍。这里用两个临时文件不是我懒而是故意让awk的统计结果先落盘再交给sort做全局排序。awk在END块里直接往sort管道灌数据也可以但管道一旦被sort的缓冲塞住awk会被阻塞多路统计互相干扰调试起来很麻烦。先写临时文件再排序逻辑清晰性能差别微乎其微。优化不是追求理论极限而是在可读性和性能之间找平衡。5.3 优化前后对比与取舍复盘把两版数据并排看指标初版重写版real时间34.2s2.1ssys时间31.0s0.6s外部进程创建次数约400万次3次awk、sort、sort磁盘读次数2次awk各扫一遍1次代码行数8行14行峰值内存2.1MB4.8MB代码从8行变成14行变长了但换来的是时间和系统负载的指数级下降。sys从31秒降到0.6秒释放出来的系统CPU对同一台机器上的其他服务都是实实在在的福报。内存从2.1MB涨到4.8MB在今天的服务器上完全不值一提。如果统计维度更多、字段更长内存会进一步上升但一般文本统计需求下bash的关联数组不会构成压力。真遇到几十GB的超大文件就该考虑换Go、Rust或Python streaming方案了那不是Shell脚本的战场。我在实际优化中还有一条心得脚本优化从来不是把复杂写到极致而是花最少的改动换取最大的收益。像这个案例我甚至不需要优化掉所有fork——只要把每行4次fork变成每行0次fork性能已经质变了。与其纠结循环内部最后一点微优化不如先回头想想这个循环本身能不能直接整个去掉。另外别忘记给临时文件设置清理和防冲突机制。两个并发跑了同一脚本/tmp/codes.txt会被互相覆盖。生产环境里要么用mktemp要么在脚本开头清理旧文件。我一般会把工作文件放到/dev/shm既快又减少磁盘写然后用trap rm -f $tmpdir/* EXIT保证退出时清理干净。这个小习惯帮我避免过不只一次线上事故。

相关新闻

反转链表核心思路详解:从指针操作到递归迭代全掌握

反转链表核心思路详解:从指针操作到递归迭代全掌握

链表这类题目,说不上难,但十几年里每次面试、每次带新人、每次看线上代码,我都能碰到把反转写错的例子。写链表反转,最考验的就是对指针(或引用)操作的清晰度——你有没有理清“谁指向谁、什么时候断链、断…

2026/10/3 3:00:56 阅读更多 →
Spring Boot毕业设计:电子产品销售平台从0到1完整开发指南

Spring Boot毕业设计:电子产品销售平台从0到1完整开发指南

又到毕业设计季,后台私信里问电子产品销售平台相关内容的最多。今年我不打算重复“跟着视频敲一遍”的老话,而是站在一个过来人的角度,把这类平台从0到1真正需要想清楚的几件事一次讲透:技术栈怎么选、库表怎么设计、下单链路怎么…

2026/10/3 3:00:56 阅读更多 →
奈奎斯特定理与香农定理:数字通信的采样边界与信道容量极限

奈奎斯特定理与香农定理:数字通信的采样边界与信道容量极限

1. 为什么数字世界里绕不开这两个公式做通信、音频、图像处理这行,只要跟“信号”沾边,奈奎斯特定理和香农定理就是躲不开的两块基石。我在做嵌入式音频采集的时候第一次正面撞上它们,当时只是照抄别人的采样率设置,结果换了一个传…

2026/10/3 2:59:55 阅读更多 →

最新新闻

Scratch离线部署实战:从静态资源托管到页面异常排查

Scratch离线部署实战:从静态资源托管到页面异常排查

1. 部署前的思路梳理:先搞清楚你的Scratch离线版到底是什么形态Scratch离线部署这件事,听起来像是“下个安装包装一下”那么简单,但真到实操环节,你会发现坑比想象中多得多。尤其当你想做的是“把Scratch部署到内网服务器&#xf…

2026/10/3 3:43:34 阅读更多 →
程序员接单避坑指南:从需求分析到项目交付的完整流程

程序员接单避坑指南:从需求分析到项目交付的完整流程

先说实话:我刚入行那两年,也做过“接单月入过万”的梦。当时觉得,写代码嘛,需求给我,我写完收钱,天经地义。可真等自己被需求文档、改稿、跑单、烂尾这些事磨过几轮之后,才琢磨明白——程序员接…

2026/10/3 3:43:34 阅读更多 →
FPGA查表法NCO设计:相位累加、SFDR优化与工程实战

FPGA查表法NCO设计:相位累加、SFDR优化与工程实战

前阵子做一套中频信号源,要求输出频率能从几百kHz连续切到几十MHz,步进还要小。一开始想用FPGA内部的PLL搞定,做了两天就放弃了——PLL本质是分频/倍频,不是用来做任意连续频率合成的。后来老老实实写了一个NCO(数字控…

2026/10/3 3:43:34 阅读更多 →
Agent记忆架构实战:从Working Memory到MCP与Docker编排

Agent记忆架构实战:从Working Memory到MCP与Docker编排

1. 为什么“记忆”才是 Agent 落地的真正分水岭1.1 从“无状态调用”到“有状态协作”的认知转变如果你最近半年在折腾 LLM 应用,大概率会有一种强烈的割裂感:模型能力每隔几个月就上一个台阶,但真正落到业务里,Agent 依然像个“金…

2026/10/3 3:43:34 阅读更多 →
宠物区块源码从部署到调优:区块猫链式记录与运营后台完整链路

宠物区块源码从部署到调优:区块猫链式记录与运营后台完整链路

简介:这份资源是面向区块链宠物类项目开发者与运营团队的一站式源码包,聚焦宠物区块链与区块猫升级版玩法,适合具备PHP与前端基础、希望快速搭建或二次开发数字宠物养成平台的技术人员。压缩包共3个文件,包含1个zip源码包、1个sql…

2026/10/3 3:43:34 阅读更多 →
OpenShell开源工具:一键还原经典开始菜单,深度定制Windows UI布局

OpenShell开源工具:一键还原经典开始菜单,深度定制Windows UI布局

如果你和我一样,是从Windows 7、Windows XP时代一路用过来的老用户,大概率会对Windows 10/11那个全屏磁贴开始菜单有点意见。切换用户图标藏得深,常用软件列表被一堆系统推荐位挤没,右键菜单一层套一层……今天要聊的OpenShell&am…

2026/10/3 3:42:34 阅读更多 →

日新闻

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南 【免费下载链接】ex-skill 前任 skill 项目地址: https://gitcode.com/gh_mirrors/exsk/ex-skill 前任.skill 是一个运行在 Claude Code 上的开源 Skill:导入微信、iMessage、短信、…

2026/10/3 0:00:27 阅读更多 →
45个经典Linux面试题:从命令到网络排障的完整考点解析

45个经典Linux面试题:从命令到网络排障的完整考点解析

刚开始带应届生的时候,我最头疼的就是他们拿着一摞Linux面试题背得滚瓜烂熟,一上机全露馅。后来自己从被面的人变成面别人的人,才慢慢摸清楚:Linux面试题考的根本不是答案本身,而是你面对一个不确定的系统问题时&#…

2026/10/3 0:01:28 阅读更多 →
SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成

SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成

简介:本资源是一份面向SAP ABAP开发人员、生产计划专员及ERP实施顾问的实操型操作指南,聚焦SAP生产预留核心业务场景,系统解决物料预留创建、查询、校验与批量处理等高频问题。文档以结构化方式覆盖预留背景原理、OMC2编码规则、工厂级参数配…

2026/10/3 0:01:28 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 19:40:48 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/1 19:41:40 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/10/1 20:05:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 5:26:06 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 6:09:11 阅读更多 →