Skip to content
claude ~ codex/28-noninteractive— 23 min read

28 · 非交互模式 codex exec:把它塞进脚本和 CI 里跑

📚 系列导航:上一篇〔27 自动化与 CI/CD 〕讲了「让 Codex 在流水线里自动干活」这件事的全貌——什么活该自动化、CI 里怎么摆。这一篇把镜头推到那条最核心的命令上:codex exec,也就是不开图形界面、一句话丢进去跑完就退的「非交互模式」。下一篇〔29 Slack / Linear 与 SDK 集成 〕再把它接到 IM 和工单系统里去。

兄弟们,今天聊一条你早晚绕不开的命令——codex exec

前面第 08 篇「命令行 CLI」我提过它一嘴,说它像「点外卖」:下单(一句提示词)、厨房关门做完直接送到(结果打到终端),全程不用你在场。但那篇只是让你「知道有这么个东西」。这一篇是把厨房后门打开,让你看清外卖是怎么做、怎么打包、怎么塞进自动化管道的。

为啥要专门拎出来讲?因为交互模式(你敲 codex 进那个全屏界面)有个死穴:它假设有个活人坐在屏幕前——盯着对话、按回车批准、看 diff。可一旦你想「每天早上自动审一遍昨天的提交」「CI 跑挂了让它自动提个修复 PR」「把构建报错管道喂给它、让它吐根因总结」——这些场景里压根没有活人。这时候交互界面不光没用,还会卡在「等你批准」那一步死等。codex exec 就是为「没活人」这件事生的。

说白了,学会 codex exec,是你从「用 Codex 这个工具」迈向「把 Codex 当成自己工作流里一个零件」的分水岭。

看完这一篇,你会拿到:

  • 一句话讲清 codex exec 和交互模式的本质区别,以及它专治哪几类「没活人」的场景
  • 看懂它最关键的设计:进度走 stderr、最终结果走 stdout——这一刀切开,管道才好接
  • --json(机器可读的过程事件)和 -o / --output-last-message(捞最终结果到文件)怎么搭配,CI 里两边都不耽误
  • 非交互模式的沙箱默认是只读、要改文件得显式放开——附一张安全档位对照表
  • stdin 管道的两种姿势(提示词 + 管道当上下文 / codex exec - 让 stdin 当整个提示词)分别啥时候用
  • 一套能照抄的最小动手流程,把「跑一次 → 拿结果 → 写进脚本批量跑」亲手走通

⚠️ 下文凡涉及具体子命令、选项、默认行为,都以 Codex 官方文档 为准;模型名、版本这类随版本变的东西,看到时以你本地实际为准,本篇不写死。


01 先想清楚:非交互模式到底为谁而生

先给结论:codex exec 解决的是「没有活人盯着」的场景——脚本、定时任务、CI 流水线里,没人能实时批准、没人盯着对话框,活儿得自己跑完、结果得能被下一个程序接住。

回想前面那么多篇,咱们基本都在「交互模式」里折腾——敲 codex 进全屏界面,给一句指令,看它一步步干,它要动手了你点个同意。这模式九成的活儿都够用,前提是你人在场

但有三类活儿,你根本不想在场、或者没法在场。

第一类,重复到让人烦的活。 比如「每天给昨天的 10 个提交生成一份发布说明」。这活儿没难度,就是烦——你不想每天早上手动开 Codex、复制提交、等它写、再粘出来。

第二类,没有图形界面的环境。 CI 流水线、云服务器、Docker 容器里压根没有终端让你「盯着」,交互式那个全屏 TUI(终端用户界面,Terminal User Interface)根本起不来。

第三类,要把 Codex 的输出喂给下一个程序。 比如让它把一段日志总结成 Markdown 表格,结果直接写进文件、或者管道接给 gh pr comment 贴到 PR 评论区。这要求 Codex 的输出干净得像个标准命令行工具,而不是一屏花花绿绿的交互界面。

类比:自动售货机 vs 有店员的柜台。 交互模式像有店员的柜台——你说要啥、店员现做、中途能问你「加不加糖」、做好递给你。codex exec 像自动售货机——你按下按钮(一条命令),机器关起门自己运转,东西「咣当」掉进取货口(结果打到 stdout),全程没有店员、不会有人问你问题、也不需要你在场。售货机的好处正是「无人值守」:半夜三点、流水线里、批量一百台,它都照跑不误。

落到真实场景,codex exec 最常出现在这几个地方:

  • 「CI 跑挂了,自动定位失败用例、提个修复补丁」——流水线里没活人,全靠它自己跑完
  • 「给最近 10 个提交生成 release notes,写进文件」——重复活,写进脚本一键出
  • 「把这段报错日志管道喂给它,让它吐根因 + 下一步排查建议」——一行命令的事,比复制粘贴进交互界面快多了

💡 一句话总结:codex exec 是为**「没活人盯着」的场景**而生(像自动售货机无人值守)——重复活、无图形界面的环境、要把输出喂给下一个程序,这三类活儿交给它,而不是开交互界面干等。


02 一上手:最简单的样子长这样

别被「非交互」「CI」这些词吓住,codex exec 最基础的用法朴素得很——codex exec 后面跟一句话当提示词,回车,它就开干

bash
codex exec "总结这个仓库的结构,列出最该警惕的 5 个地方"

它会读当前工作目录、定个计划、把过程往屏幕上滚,最后把那条总结打出来,然后退出——不进 TUI、不停在界面等你按键。这就是「非交互」三个字最直白的含义:跑完就走,不跟你来回聊。

类比:发一封带任务的邮件,等一封回信。 交互模式像打电话——你来我往、随时插话。codex exec 像发邮件——你把要办的事在一封邮件里写清楚(提示词),发出去,对方关起门把事办完,回你一封信(最终结果)。你没法在它办事的中途插嘴改需求,所以提示词得一次性写明白。

几个你立刻能上手的变体:

bash
# 短别名 codex e,跟 codex exec 完全等价
codex e "解释这个项目是干什么的"
bash
# 换个模型跑这一次(模型名以你本地实际为准,别照抄)
codex exec -m gpt-5.5 "审查当前改动,列出潜在 bug"
bash
# 不想把这次会话记录落盘,加 --ephemeral
codex exec --ephemeral "快速过一遍这个仓库,给点下一步建议"

这里要敲黑板的一点,和交互模式的最大区别:交互模式里它干到一半要动手会停下来问你「批不批准」;codex exec 是为「没活人」设计的,所以它不会在中途弹出审批等你点头。这既是它的好处(无人值守),也是它的风险点——它能动多大,全看你启动时给的沙箱档位。这一点第 04 节专门讲,先记住「它不会停下来问你」这件事。

⚠️ 一个 Git 仓库的硬性前提:Codex 硬性要求命令在一个 Git 仓库里跑(可用 --skip-git-repo-check 覆盖),这是为了防止它在没有版本管理的地方造成不可逆的破坏。要是你在一个非 Git 目录里跑 codex exec,它会直接拦下来。临时目录里想跑,加 --skip-git-repo-check 跳过这道检查——但官方原话是「只在你确信环境安全时」才这么干。

💡 一句话总结:codex exec "一句话" 就是最基础的非交互跑法(短名 codex e),像发一封带任务的邮件等回信——提示词得一次写清,它跑完就退、中途不停下来问你批不批准;还有个硬前提:硬性要求在 Git 仓库里跑,非 Git 目录加 --skip-git-repo-check 覆盖。


03 最关键的设计:进度走 stderr,结果走 stdout

这一节是整篇最该吃透的一块,也是 codex exec 能优雅接进管道的命门

先抛个问题:Codex 跑的过程中会输出一大堆东西——它在想啥、跑了哪条命令、改了哪个文件……可你真正想要的,往往只是最后那条总结。要是这些全混在一起打出来,你想「把结果写进文件」时,文件里就塞满了过程噪音,根本没法用。

Codex 的解法非常干净:把两种输出分到两条不同的「水管」里

过程噪音走 stderr(标准错误),最终结果走 stdout(标准输出)。这俩是 Unix 命令行的两条独立输出流,平时你在终端看它们混在一起,但管道 | 和重定向 > 默认只接 stdout。所以这一刀切下去,你想捞结果就格外省事。

类比:工地上「施工噪音」和「最终交付的房子」走两个口子。 盖房子的过程吵得很——打桩、搅拌、敲打(这些是 stderr,你能听见、但不是你要的成品);最后交付到你手里的是一栋干净的房子(这是 stdout,你真正要的东西)。施工噪音从工地侧门散出去,成品从正门交付——两个口子分开,你接「成品」的时候不会被一堆噪音灌进来

看它怎么省事。下面这条把最终结果既打到屏幕、又存进文件tee 的作用),而过程噪音照常在屏幕上滚、但不会进文件

bash
codex exec "给最近 10 个提交生成发布说明" | tee release-notes.md

预期:你在屏幕上能看到 Codex 干活的过程(这些是 stderr),跑完最终的发布说明打出来;同时 release-notes.md只有那份干净的发布说明,没有半点过程噪音。

理解这个分流,下面这些常见操作就都顺理成章了:

你想干的事怎么写原理
只把结果存进文件codex exec "..." > out.md> 只接 stdout(结果),stderr 照样在屏幕滚
结果既存又看codex exec "..." | tee out.mdtee 把 stdout 一份存盘、一份打屏
结果管道喂给下一个程序codex exec "..." | pbcopy下游只收到 stdout 那份干净结果
把过程噪音也一起留存codex exec "..." > out.md 2> log.txt2> 单独把 stderr 收进另一个文件

我自己第一次写脚本时栽过一个跟这有关的小跟头:当时想「把 Codex 的输出收进文件」,结果用了 2>&1 把 stderr 也并进了 stdout,文件里全是它「正在思考」「正在读取文件」的过程行,最终那段总结被淹在里头,下游解析直接乱套。后来才反应过来——人家专门把结果和噪音分开了,我又手贱把它们合回去了。把 2>&1 去掉,文件立刻就干净了。

💡 一句话总结:codex exec过程噪音打到 stderr、最终结果打到 stdout(像工地的施工侧门和交付正门分开),所以 > / tee / 管道默认只接到那份干净结果;别手贱用 2>&1 把噪音并回 stdout,否则文件全是过程行。


04 权限与安全:非交互模式默认是「只读」

上一节讲了输出怎么分流,这一节讲个更要紧的:codex exec 没活人盯着,那它到底能动多大?

先给结论,这也是最容易想当然写错的一点:codex exec 默认跑在只读沙箱里——它能读、能分析、能给建议,但默认不会改你的文件、也不会执行有副作用的命令。要让它真动手改东西,你得显式放开

为啥默认这么保守?因为它是为「无人值守」设计的——没人在旁边喊停。要是默认就放开写权限、又没人盯着,一个理解偏差就可能在你仓库里乱改一通。所以官方的设计哲学是:自动化里,给出工作流所需的最小权限就好。

类比:把家门钥匙交给上门服务的师傅。 你不在家,让维修师傅上门——你不会把整套钥匙连保险柜密码一起给他。默认只给他进客厅看一眼的权限(只读);确实要他修水管,才单独给他厨房和卫生间的钥匙(workspace-write,只在工作区里动手);除非是封闭隔离的场子,否则绝不给他「全屋随便动、连邻居家也能进」那种万能钥匙(danger-full-access)。权限给得越克制,无人值守才越放心。

放开权限就靠 --sandbox(短名 -s)这个开关,三档对照如下:

沙箱档位它能干啥啥时候用
read-onlyexec 默认只读、只分析,不改文件、不跑有副作用的命令代码审查、生成总结、分析报告——只产出文字
workspace-write工作区目录内读写、动手改要它真改代码 / 修 bug / 写文件,但限定在项目里
danger-full-access几乎不设限,能动整台机器只在隔离环境(独立 CI runner、容器)里用

落到命令上:

bash
# 默认只读:审查改动、只出报告,碰不到你的文件
codex exec "审查当前改动,列出潜在 bug"
bash
# 放开工作区写权限:让它真去修,但只在项目目录内动手
codex exec --sandbox workspace-write "修好失败的测试用例"
bash
# 仅限隔离环境:几乎不设限
codex exec --sandbox danger-full-access "<在隔离 runner 里的任务>"

几个一定要单独点清楚的坑:

坑一:--full-auto 别再用了。 老脚本里你可能见过 codex exec --full-auto,它现在是已弃用的兼容标志,用了 Codex 会打一条警告。官方明说:新脚本里直接用 --sandbox workspace-write 替代它,意图更明确。

坑二:danger-full-access 只在隔离环境用。 这档几乎等于「随便动」,官方原话是「只在受控环境(比如隔离的 CI runner 或容器)里用」。在你自己日常的开发机上对着重要项目甩这一档,跟把万能钥匙交出去没区别。

坑三:要让自动化「干净启动」,还有两个忽略开关。 --ignore-user-config 让这次跑不加载 $CODEX_HOME/config.toml(避免被本机或队友的个人配置干扰);--ignore-rules 让它跳过用户级和项目级的 execpolicy .rules 文件。这俩是给「受控自动化环境」用的,想要每台机器跑出来行为一致时用得上。

我去年配一个 CI 任务时就吃过「权限想当然」的亏:以为 codex exec 跟我交互时用的是同一套配置(我本地常开着写权限),结果它在 CI 里跑了半天啥也没改——一脸懵。翻文档才明白,非交互模式默认就是只读,跟我交互时的环境是两码事。补上 --sandbox workspace-write 之后它才真动手。这个默认值,新手十有八九会踩。

💡 一句话总结:codex exec 默认只读沙箱(像只给上门师傅进客厅的权限),要改文件得显式 --sandbox workspace-write、几乎不设限的 danger-full-access 只在隔离环境用;老的 --full-auto 已弃用别再写,受控自动化还能用 --ignore-user-config / --ignore-rules 干净启动。


05 让输出机器可读:--json-o 这对搭档

第 03 节解决了「结果怎么不被噪音污染」,但还有个更进一步的问题:脚本要解析 Codex 的输出,纯文本不好啃。比如你想知道「它这次跑成功了没」「跑了哪几条命令」「花了多少 token」,从一段自然语言里抠这些信息既别扭又不稳。

Codex 给了两个互补的工具,新手务必分清它俩管的不是一件事

第一个,--json:把整个过程变成机器能读的事件流。 加上 --json(官方还有个等价别名 --experimental-json),stdout 就从「一段自然语言」变成 JSON Lines(JSONL,每行一个独立 JSON 对象)的事件流——Codex 干活时每发生一个状态变化,就吐一行 JSON。

类比:从「看一场演出」变成「拿到一份带时间戳的演出流水账」。 不加 --json 像现场看演出——好看,但散场你说不清「第几分钟换了第几个节目」。加了 --json 像拿到一份逐条记录的流水账:几点几分开场、第几个节目上、几点谢幕——每一步都是结构化的一条,程序能逐行读、逐条判断

bash
codex exec --json "总结这个仓库的结构" | jq

它吐出来的每一行都是一个事件对象,类型包括 thread.started(线程开始)、turn.started / turn.completed / turn.failed(一轮的开始 / 完成 / 失败)、item.*(具体动作,如执行命令、改文件、调用 MCP 工具、联网搜索、更新计划等)、以及 error。长这样(每行是一个独立 JSON):

jsonl
{"type":"thread.started","thread_id":"0199a213-81c0-7800-8aa1-bbab2a035a53"}
{"type":"turn.started"}
{"type":"item.completed","item":{"id":"item_3","type":"agent_message","text":"仓库包含 docs、sdk、examples 三个目录。"}}
{"type":"turn.completed","usage":{"input_tokens":24763,"output_tokens":122}}

有了这个,脚本里判断成功失败、提取它干了哪些事、统计 token 用量,全都有结构化字段可抓。

第二个,-o / --output-last-message:只把最终那条消息单独存一份。 很多时候你不关心过程流水账,只想要最后那段总结,落进一个文件好给下一步用。加 -o <文件路径>(长名 --output-last-message)就行:

bash
codex exec "提炼项目元信息" -o ./summary.md

这里有个官方明确写了、但容易忽略的细节-o 会把最终消息写进那个文件,同时还照常打到 stdout——也就是说它不抢 stdout,你想再管道接给别人也不耽误。

那这俩到底咋选?一张表说清:

你想要的用哪个形态
程序逐步读它的每个动作 / 判断成败 / 统计用量--jsonstdout 变成 JSONL 事件流
只要最终那段总结,落一个文件-o <path>最终消息写进文件,且仍打到 stdout
CI 里两样都要--json + -o 一起上事件流喂程序,文件捞干净的最终总结

最后这条是官方专门推荐的 CI 黄金搭配——在 CI 里把 --json--output-last-message 配在一起,既拿到机器可读的进度,又拿到一份最终的自然语言总结。

我自己一个每日代码审查的脚本就是这么配的:--json 那条流喂给一个小解析器,判断「这次有没有发现高危问题、跑成功没」来决定要不要告警;-o 落的那份 Markdown 总结,则直接贴进团队群当「今日审查摘要」。一次跑,机器要的和人要的两头都齐了,再没有从一坨文本里抠字段的别扭。

还有个更进阶的 --output-schema:给它一个 JSON Schema 文件,让最终结果严格按你定义的字段结构产出(比如固定的「项目名 + 语言列表」这种),下游程序拿到的字段稳定可靠。需要结构化数据喂给后续步骤时再深入,本篇先知道有这么个东西。

💡 一句话总结:--json 把 stdout 变成 JSONL 事件流(像一份逐条流水账,程序好逐行读、判断成败统计用量),-o / --output-last-message最终那段总结单独落一个文件且仍打到 stdout;CI 里官方推荐两个一起上——机器要的和人要的一次拿齐。


06 stdin 管道:把上一个命令的输出直接喂给它

到这儿你已经会「让 codex exec 的输出接给下游」了。反过来——怎么把上一个命令的输出,喂给 codex exec 当输入? 这就是 stdin(标准输入)管道,也是 codex exec 在命令行工作流里最顺手的一招。

为啥需要它?因为太多真实场景是「先有一坨数据,再让 Codex 处理它」:构建挂了有一段报错日志、一次请求拿到一段 JSON、CI 跑完有一段输出……你不想手动复制粘贴进交互界面,而是想一行命令直接「管道」过去。

这里有个新手特别容易混的分叉,官方把两种姿势分得很清楚,我用一句话先点破区别:指令是你写好的、数据当上下文 → 用「提示词 + 管道」;整个提示词都由上一个命令动态生成 → 用 codex exec -

类比:给秘书交代任务的两种方式。 第一种,你口头交代「把这份材料整理成表格」,同时把一摞材料递过去——指令在你嘴里,材料是附件(提示词 + 管道)。第二种,你把一张写好全部要求的纸条直接递过去,说「照这上面办」——连指令带内容全在纸条上codex exec -)。两种都行,看你的「指令」是现写的、还是早就写在「纸条」(上游命令的输出)里了。

姿势一:提示词 + 管道(指令你写,管道内容当上下文)

当你心里已经清楚要它干啥,只是想把某个命令的输出当材料喂进去时用这个。官方的规则很明确:

如果 stdin 是管道进来的,同时你又给了提示词参数,Codex 会把提示词当指令、把管道内容当额外上下文

最典型的——构建/测试挂了,把报错管道喂给它要根因:

bash
npm test 2>&1 \
  | codex exec "总结失败的测试,提出最小改动的修复方案" \
  | tee test-summary.md

预期npm test 的全部输出(2>&1 把报错也并进来)作为上下文喂给 Codex,你写的那句话作为指令;Codex 的总结打到屏幕、同时存进 test-summary.md。排查构建挂掉时,就这么一行甩过去,比复制报错粘进会话快太多。

再比如把一段长日志喂给它做根因分析:

bash
tail -n 200 app.log \
  | codex exec "找出最可能的根因,引用最关键的几条报错,给出接下来三步排查建议" \
  > log-triage.md

姿势二:codex exec -(让 stdin 当整个提示词)

当整个提示词都是上一个命令动态拼出来的——比如提示词存在文件里、或用脚本现拼——这时候你不想自己再写指令,而是让 stdin 的内容直接当成完整提示词。省略提示词参数时 Codex 就会从 stdin 读;想强制这个行为、写清楚意图,就用 - 这个「哨兵」符号:

bash
# 把一个文件里的内容当成整个提示词
cat prompt.txt | codex exec -
bash
# 用脚本现拼一个完整提示词,再整个喂进去
printf "用 3 条要点总结这段错误日志:\n\n%s\n" "$(tail -n 200 app.log)" \
  | codex exec -

什么时候非得用 -?当你把提示词存成文件、或用 shell 脚本组装提示词、或把实时命令输出和指令拼成一整段再丢给 Codex 时——这几种都是 codex exec - 的主场。

我自己维护着几个「提示词模板文件」(比如一个标准的 PR 审查提示词),需要时 cat 模板.txt | codex exec - 直接跑,改提示词只改那个文件、不用动脚本。指令和脚本解耦,这点在团队里特别值。

💡 一句话总结:喂数据给 codex exec 看「指令从哪来」——指令你现写、管道内容当上下文 用「提示词 + 管道」(像口头交代任务 + 递材料);整个提示词由上游动态生成codex exec -(像直接递一张写好全部要求的纸条)。


07 接着上次跑:codex exec resume

非交互不代表「只能一锤子买卖」。有时候一个流程得分两段跑——先让它分析,再基于分析结果让它动手。这种「两阶段流水线」,靠 resume 子命令把前后两次串起来。

类比:接力赛的交接棒。 第一棒跑完(第一次 codex exec)把棒子交出去,第二棒接着这个位置往下跑(codex exec resume)——不用从起点重来,上一棒的上下文直接接上。要是没有 resume,第二次跑就得把第一次的结论重新喂一遍,既费 token 又容易丢细节。

最常见的两阶段写法,官方给的例子:

bash
# 第一阶段:先让它找问题
codex exec "审查这处改动有没有竞态条件"

# 第二阶段:接着上一次,让它修掉刚找到的问题
codex exec resume --last "把你发现的竞态条件修掉"

--last 的意思是「接着当前工作目录下最近的那次会话」。要是你想精确接某一次特定会话,把会话 ID 跟在后面:

bash
codex exec resume <SESSION_ID> "继续上次的任务"

补两个细节:想跨目录找最近的会话,加 --allresume 后面的提示词是可选的——你可以只 resume 不带新指令,也可以带一句新指令接着干。

注意:第 02 节说过 --ephemeral 不把会话落盘,那种「阅后即焚」的跑法自然就没法 resume(都没存,接什么)。要用两阶段流水线,就别加 --ephemeral

💡 一句话总结:codex exec resume --last 接着当前目录最近一次会话往下跑(像接力赛交接棒,不用从起点重来),也能用会话 ID 精确接某次;但加了 --ephemeral 不落盘的跑法没法 resume。


08 动手:把「跑一次 → 拿结果 → 批量跑」走通

光看不练明天就忘。下面给一套最小验证流程,在任意一个 Git 仓库里就能跟着走(没有就先 git init 一个空目录)。命令真实可跑,每步都给了预期输出。

需要装好 Codex CLI(没装回第 03 篇)、且在一个 Git 仓库里跑。下面命令不依赖魔法上网。涉及的模型名 / 具体输出以你本地实际为准。

第一步:跑最基础的一次(只读,不会动你文件)

bash
codex exec "用一句话说清这个项目是干什么的"

预期:屏幕上滚一阵过程(这些走 stderr),最后打出一句话总结(这条走 stdout),然后自动退出回到普通终端——不进交互界面。看到「跑完就退」= 非交互模式生效了。

第二步:把结果存进文件,验证 stdout / stderr 分流

bash
codex exec "用一句话说清这个项目是干什么的" > result.txt

预期:屏幕上还是能看到过程(stderr 没被重定向),但跑完去看 result.txt,里面只有那句干净的总结,没有过程噪音。这就证明了第 03 节讲的分流——> 只接住了 stdout。

第三步:加 --json 看机器可读的事件流

bash
codex exec --json "列出这个项目里的文件类型"

预期:stdout 变成一行行 JSON(JSONL),开头能看到 {"type":"thread.started",...},中间是 item.* 各种动作,结尾通常是 turn.completed 带 token 用量。看到这串逐行 JSON = 机器可读模式生效。(装了 jq 的话,在后面接 | jq 看得更清楚。)

第四步:用 -o 把最终消息单独落一份

bash
codex exec "用一句话总结这个项目" -o last.md

预期:屏幕照常打出那句总结(stdout 没被抢),同时 last.md 里也存了同一句话。验证了 -o 既写文件、又仍打 stdout。

第五步:把它拼成「批量」——对一批文件各跑一遍

真正的批量,是拿 shell 循环把单条 codex exec 套起来。比如给当前目录每个 .md 文件各生成一句话说明(--ignore-user-config 让每次干净启动、行为一致):

bash
for f in *.md; do
  echo "=== $f ==="
  codex exec --ignore-user-config "用一句话说明 $f 写的是什么"
done

预期:循环对每个 .md 文件各跑一次 codex exec,逐个打印文件名 + 它的一句话说明。这就是「无人值守批量」的雏形——循环 + codex exec,再没有活人盯着。

跑通这五步,你就把「跑一次 → 看分流 → 拿 JSON → 落文件 → 批量套循环」这条非交互主链亲手走了一遍。以后真要塞进脚本或 CI,本质都是这套,无非换成真实任务、加上 --sandbox workspace-write 让它动手、再接进流水线。

💡 一句话总结:动手链路就五步——codex exec 跑一次 → > 存文件看分流 → --json 拿事件流 → -o 落最终消息 → for 循环拼批量;走通一遍,「把 Codex 当脚本零件」这件事你就有肌肉记忆了。


09 小结

这一篇把 codex exec 非交互模式,从「它为谁而生」一路讲到「怎么塞进脚本批量跑」,中间最该带走的是那几个「想当然会写错」的点。

把核心收成一张表,揣兜里:

你想干的事怎么做关键点
跑一次非交互任务codex exec "..."(短名 codex e跑完就退、中途不停下来问你批准
只把干净结果存文件codex exec "..." > out.md结果走 stdout、过程噪音走 stderr,> 只接结果
让它真改文件--sandbox workspace-write默认是只读,不显式放开它不动手
拿机器可读的过程--jsonstdout 变 JSONL 事件流,程序好逐行读
捞最终总结到文件-o <path>写文件且仍打到 stdout;CI 里和 --json 配着用
把上游输出喂给它提示词 + 管道 / codex exec -看指令是你现写的、还是上游动态生成的
接着上次跑codex exec resume --last "..."两阶段流水线;--ephemeral 没法 resume

你现在应该能:讲清 codex exec 专治哪几类「没活人」的场景;看懂「进度走 stderr、结果走 stdout」这一刀切开后,管道和重定向为啥那么顺;分清 --json-o 各管啥、CI 里为啥要一起上;记住那个最容易栽的默认值——非交互模式默认只读,要动手得显式 --sandbox workspace-write;还能用两种 stdin 姿势把上游数据喂进去、用 resume 串起两阶段流程。

最该带走的一句话codex exec 不是「阉割版的交互模式」,而是让 Codex 从一个你盯着用的工具,变成你工作流里一个能被脚本、管道、CI 自由调用的标准零件——这一步迈过去,自动化的大门才算真打开。


下一篇 29 Slack / Linear 与 SDK 集成:这一篇你已经会把 Codex 接进脚本和 CI 了,但还都是「命令行里」的接法。下一篇换个方向——把它接进你天天用的协作工具:在 Slack 里 @ 一下就让它干活、Linear 上的工单自动派给它、或者用 SDK 把它的能力嵌进你自己的程序里。想想看:codex exec 把输出管道给了 gh pr comment,那把它接到 Slack、接到工单系统,中间又少了哪几步手动操作?咱们下篇接着聊。