AI 해결 노트 · 2026-09-17 · 실측 2026-09-17

codex exec 결과를 파일로 받기 — -o와 --json 윈도우 실측 (Codex CLI)

한 줄로

codex exec의 마지막 답만 필요하면 -o 파일, 진행 과정까지 기계로 읽으려면 --json > 파일을 씁니다. 둘은 같이 쓸 수 있습니다. 이번 실험에서는 -o에 없는 폴더를 주자 파일 저장에 실패했는데 종료 코드는 0이었으니, 저장 결과를 따로 확인하는 편이 좋습니다.

이런 분께

실측 환경

항목
OSWindows 11 Home (10.0.26200)
Git Bash, PowerShell 7.6.6
codexcodex-cli 0.153.4
모델(실행 머리말 표시)gpt-6-astra
질문Reply with the single word OK. (모든 회차 같음)
공통 옵션-s read-only --skip-git-repo-check (Git Bash 1~4회차는 < /dev/null로 stdin을 닫음)

이 글에는 stdin을 닫지 않았을 때의 비교가 없습니다. 에이전트 셸처럼 stdin이 파이프로 열려 있을 때 codex exec가 끝나지 않던 실측은 codex exec가 stdin 대기에서 안 끝날 때에 따로 적었습니다.

도움말에 있는 옵션

codex exec --help에서 이 글과 관련된 두 줄입니다.

      --json
          Print events to stdout as JSONL

  -o, --output-last-message <FILE>
          Specifies file where the last message from the agent should be written

--json은 파일 옵션이 아닙니다. 표준출력으로 내보내므로 파일로 받으려면 >로 돌려야 합니다.

1. -o로 마지막 답만 받기

codex exec -s read-only --skip-git-repo-check -o last.txt "Reply with the single word OK." < /dev/null

종료 코드 0, 8.4초 걸렸습니다. 출력이 두 갈래로 나뉩니다. 표준출력에는 답 OK 한 줄만 나왔고, 머리말과 진행 기록은 모두 표준오류로 갔습니다.

Reading additional input from stdin...
OpenAI Codex v0.153.4
--------
workdir: C:\Users\User\AppData\Local\Temp\longtail_A\exec
model: gpt-6-astra
provider: openai
approval: never
sandbox: read-only
...
codex
OK
tokens used
6,707

last.txt는 2바이트였습니다. 끝에 줄바꿈이 없어서 wc -l로 세면 0줄로 나옵니다.

0 2 last.txt
--- cat -A ---
OK

cat -A로 봐도 줄 끝 표시($)가 없습니다. 파일을 다른 파일에 이어 붙이거나 줄 수로 성공을 판정하는 스크립트라면 이 점을 감안해야 합니다.

2. --json으로 이벤트 전체 받기

codex exec -s read-only --skip-git-repo-check --json "Reply with the single word OK." < /dev/null > events.jsonl

종료 코드 0, 6.1초. 표준오류에는 Reading additional input from stdin... 한 줄만 남았고 머리말은 나오지 않았습니다. 파일은 4줄, 345바이트였습니다.

{"type":"thread.started","thread_id":"01a0ae78-dd26-7ce2-8b79-6da03f94ac20"}
{"type":"turn.started"}
{"type":"item.completed","item":{"id":"item_0","type":"agent_message","text":"OK"}}
{"type":"turn.completed","usage":{"input_tokens":18453,"cached_input_tokens":12416,"cache_write_input_tokens":0,"output_tokens":5,"reasoning_output_tokens":0}}

답은 typeitem.completed이고 item.typeagent_message인 줄의 text에 있습니다. 토큰 사용량은 마지막 turn.completed 줄의 usage에 들어 있습니다.

실행한 셸에서 command -v jq가 경로를 출력하지 않아, Node로 답만 뽑았습니다.

node -e 'const fs=require("fs");for(const l of fs.readFileSync("both_events.jsonl","utf8").split(/\r?\n/)){if(!l)continue;const e=JSON.parse(l);if(e.type==="item.completed"&&e.item.type==="agent_message")console.log(e.item.text)}'
OK

3. 둘을 같이 쓰기

codex exec -s read-only --skip-git-repo-check --json -o both_last.txt "Reply with the single word OK." < /dev/null > both_events.jsonl

종료 코드 0. both_last.txt는 2바이트 OK, both_events.jsonl은 4줄 345바이트로, 1·2절과 같은 모양이 한 번에 나왔습니다.

4. PowerShell 7에서

codex exec -s read-only --skip-git-repo-check --json -o ps_last.txt "Reply with the single word OK." > ps_events.jsonl
"codex exit=$LASTEXITCODE"
Get-Content ps_events.jsonl | ForEach-Object { $_ | ConvertFrom-Json } |
  Where-Object { $_.type -eq 'item.completed' } | ForEach-Object { $_.item.text }

이 스크립트는 pwsh -NoProfile -File로 돌렸습니다. 바깥에서 stdin이 어떤 상태였는지는 기록하지 않았습니다. codex exit=0, ps_last.txt 2바이트, ps_events.jsonl 4줄에 OK가 뽑혔습니다. 파일 첫 3바이트는 7B 22 74({"t)로 BOM이 붙지 않았습니다.

크기는 달랐습니다. 같은 4줄인데 PowerShell 쪽은 349바이트였습니다. CR 문자를 세어 봤습니다.

CR count:
events.jsonl 0
ps_events.jsonl 4

PowerShell 회차 파일에서만 CR 문자가 4개 나왔고, 크기도 Git Bash 쪽보다 4바이트 컸습니다. 이 기록만으로는 PowerShell의 >가 줄바꿈을 바꿨는지까지는 가릴 수 없습니다. 어쨌든 JSONL을 읽는 쪽이 \n으로만 자른다면 줄 끝에 \r이 남으니, 위 Node 예시처럼 /\r?\n/로 자르는 편이 안전합니다. -o 파일은 두 셸 모두 2바이트로 같았습니다.

결과

회차옵션종료 코드걸린 시간만들어진 파일
1Git Bash-o last.txt08.4초last.txt 2바이트, 0줄(줄바꿈 없음)
2Git Bash--json > events.jsonl06.1초4줄, 345바이트
3Git Bash--json -o 함께08.4초2바이트 + 4줄 345바이트
4Git Bash-o nodir/last.txt (없는 폴더)06.1초없음
5PowerShell 7--json -o 함께08.3초2바이트 + 4줄 349바이트(CR 4개)

실패한 것

4회차가 이 글에서 가장 조심할 부분입니다. -o에 존재하지 않는 폴더를 줬더니 답은 표준출력에 OK로 나왔지만 파일 쓰기는 실패했습니다. 표준오류에만 이 줄이 남았습니다.

Failed to write last message file "nodir/last.txt": 지정된 경로를 찾을 수 없습니다. (os error 3)

그런데 codex의 종료 코드는 0이었습니다(codex exit=0). 종료 코드만 보고 성공으로 처리하는 스크립트는 빈손으로 넘어갑니다. 폴더를 미리 만들고, 실행 뒤 파일이 생겼는지 확인하는 줄을 넣는 편이 낫습니다.

mkdir -p out
codex exec -s read-only --skip-git-repo-check -o out/last.txt "질문" < /dev/null
test -s out/last.txt || echo "last message file missing"

(위 세 줄 묶음 자체는 돌리지 않았고, 4회차 결과를 보고 붙인 제안입니다.)

확인하지 않은 것

함께 보기