この記事についてClaude(Anthropic)との共同編集により作成されました。
要約
- ローカルに残っていたClaude Codeのトランスクリプト607ファイルから、Bashツール呼び出し13,564件を全件抽出して集計した。一般論ではなく実データの話
- 1コールあたりの結合演算子(パイプ・
&&・;)は平均4.76個。単発コマンドを叩くのではなく調査シーケンスを1コールに丸ごと詰め込むのが基本形だったtail -fは13,564件中わずか3件。代わりにuntil grep -q ...; do sleep ...; doneでポーリングしている。しかも失敗マーカーも一緒に待つecho "=== 見出し ==="が25.7%のコールに入っている。自分が後で読むためのマークアップを出力に埋め込んでいるjqは全体で1回だけ。JSON加工や構造的置換は全部python3のヒアドキュメントに逃がしている
はじめに
きっかけは「シェル芸人こそ最強なのでは?」という、わりとどうでもいい思いつきだった。
AIコーディングツールを触っていると、結局あれこれ調べる速度がそのまま作業の速度になる。ログを掘る、設定値を探す、ビルドが終わったか確認する。この手の作業を一番速くこなせるのは、いつの時代もシェル芸が達者な人だ。ならばClaude Codeはどうなのか。あれだけBashを叩いているのだから、そのシェル芸から学べる部分があるのではないか。
そう思って「Claude Codeが多用するシェル芸を調べて」と投げた。返ってくるのはgrepとsedの一般的な解説だろうと予想していた。
ところが実際に始まったのは、ローカルの~/.claude/projects/配下に溜まっていたトランスクリプトを全部パースして、過去に実行されたBashコマンドを数え上げる作業だった。つまり「一般にAIはこう書くらしい」ではなく、「この環境で実際に13,564回叩かれたコマンドはこうだった」というデータが出てきた。
これが想像以上に面白かったので、記事にしておく。
集計の前提
先に素性を出しておく^1。
| 項目 | 値 |
|---|---|
| 解析対象 | ~/.claude/projects/**/*.jsonl |
| セッションファイル数 | 607 |
| 抽出したBashツール呼び出し | 13,564件 |
| 1コールあたり平均文字数 | 443文字(中央値278、最大9,694) |
| 1コールあたり平均の結合演算子数 | 4.76個(中央値3) |
抽出方法は単純で、各JSONL行のmessage.content[].type == "tool_use"かつname == "Bash"からinput.commandを取り出しているだけ。パースエラーは0件だった。
ひとつ先に断っておくと、この数字には筆者の環境バイアスが強く乗っている。あとで注意点としてまとめるが、adbが2,568回も出てくるのはAndroid開発をしていたからで、一般的なClaude Code利用でこうはならない。一方で、構文的な傾向(詰め込み方・出力の絞り方・待ち方)のほうはタスク領域にほぼ依存しないはずなので、そちらを主に見ていく。
全体像:1コールに調査シーケンスを詰め込む
まず驚いたのが、構文の分布だった。
| 特徴 | 該当コール数 | 割合 |
|---|---|---|
&&チェーン | 8,608 | 63.5% |
パイプ(|)を含む | 8,138 | 60.0% |
stderr操作(2>&1または2>/dev/null) | 6,591 | 48.6% |
| 複数行コマンド | 3,573 | 26.3% |
リダイレクト(>) | 2,829 | 20.9% |
ヒアドキュメント(<<) | 1,223 | 9.0% |
コマンド置換($(...)) | 933 | 6.9% |
forループ | 777 | 5.7% |
追記(>>) | 87 | 0.6% |
バックグラウンド(&) | 0 | 0.0% |
結合演算子が0個、つまり本当に単発のコマンドはわずか6.9%しかない。逆に10個以上詰め込んでいるケースが11.4%ある。
人間がターミナルで作業するときは、lsして、cdして、catして、と対話的に1つずつ叩く。画面を見て次を決められるからそれで困らない。しかしエージェントは1回のツール呼び出しごとに往復のレイテンシとトークンを払うので、「見てから決める」を減らして「まとめて投げて結果から推測する」ほうが合理的になる。その圧力が、この63.5%と60.0%という数字に出ている。
もうひとつ象徴的なのが、バックグラウンド化(&)がゼロだったこと。これはClaude Codeがシェルの&ではなく、Bashツール側のrun_in_backgroundパラメータを使う設計だからだ。シェルでできることを、あえてシェルの外の仕組みに寄せているわけで、ここは人間の作法と明確に分岐している。
原則1:出力量を必ず自衛する
エージェントにとって、コマンドの出力はそのままコンテキストを食う。ここに一番強い最適化圧力がかかっていて、上位のイディオムはほぼ全部これに関係していた。
head と tail の役割分担がはっきりしている
| イディオム | コール数 | 割合 |
|---|---|---|
tail -n N | 3,414 | 25.2% |
head -N / head -n N | 3,139 | 23.1% |
grep ... | head または | tail | 2,515 | 18.5% |
面白いのはNの選び方に癖があったことだ。
headのNは20(615回)、40(531回)、30(478回)、60(258回)と、20の倍数が好まれているtailのNは1(671回)、2(631回)、3(618回)、5(354回)と、極端に小さい値が主流
つまり、headは探索、tailは確認と役割が完全に分かれている。
# 探索:候補を広く見たいので20〜40行grep -rn "def train" --include='*.py' . | head -40
# 確認:終わったかどうかだけ知りたいので3行tail -3 run.log言われてみれば当たり前なのだが、人間はここを無意識にやっているので明文化されていない。「一覧は20行、結果確認は3行」と決めておくのは、そのまま真似できる作法だと思う。
sed をエディタではなくページャとして使う
sedの使われ方が一番意外だった。1,304回のうち、範囲プリントの-nが1,125回に対して、インプレース編集の-iはわずか54回。
sed -n '185,196p' docs/SPEC.mdsed -n '990,1110p' "$SP/base.py"sedといえば置換のイメージが強いが、ここではファイルの一部だけを読むためのページャとして使われている。しかもgrep -nで行番号を取ってから周辺を抜く、という二段構えが定番になっている。grep -nが1,912コール(14.1%)でgrepオプション中の最頻なのはこのためだった。
# 1段目:位置を特定するgrep -n "class Trainer" model.py# → 342:class Trainer:
# 2段目:その周辺だけを読むsed -n '342,420p' model.pyファイル全体をcatすれば確実だが、1,000行のファイルを読めば1,000行ぶんコンテキストが減る。「どこにあるか」と「その周辺を読む」を分けることで、読む量を数十行に抑えている。
echo ”===” というセパレータ注入
これは完全にエージェント特有の作法で、個人的に一番感心した部分。
3,485コール(25.7%)がecho "===..."系のセパレータを含んでいた。
echo "=== ファイル構成 ==="; find exp -type f | head -20echo "=== 設定値 ==="; grep -n "LEARNING_RATE\|BATCH" config.pyecho "=== 直近ログ ==="; tail -20 run.log1コールに複数の調査を詰め込む以上、出力のどこからどこまでが何なのか区切らないと自分でも読めなくなる。だから出力に見出しを埋め込んでいる。
人間のシェル芸にはほぼ存在しない発想だと思う。人間は対話的に1つずつ叩くので、そもそも区切る必要がない。裏を返せば、「1コールに詰め込む」を採用した瞬間に、セパレータは必須になるということでもある。この2つはセットだった。
2>&1 と 2>/dev/null の使い分け
| コール数 | 割合 | 意図 | |
|---|---|---|---|
2>&1 | 4,259 | 31.4% | エラーも読みたい(実行系) |
2>/dev/null | 2,801 | 20.7% | エラーを捨てたい(探索系) |
# 実行系:失敗の理由が知りたいのでstderrを混ぜてから絞るnpm run build 2>&1 | grep -iE "error|warn" | head -25
# 探索系:存在しないパスのPermission deniedはノイズなので捨てるfind / -name "libcuda*" 2>/dev/null | head実行するときはstderrを拾い、探索するときはstderrを捨てる。 これも言語化されると当たり前に見えるが、この使い分けが3割と2割で綺麗に分かれているのは面白い。
ノイズは二段階で落とす
grepを多段に繋ぐケースが593コール、grep -v(反転)が559コール。
# 定番:ps aux から grep 自身を除くps aux | grep -E "sweep_spatial" | grep -v grep | awk '{print $2, $9, $11}'
# 拾いすぎた語をsecond-passで削るgrep -iE 'error|fail' app.log | grep -viE 'errors=|error_bad|failsafe' | head -10最後の例が実務的で、まず広く拾って、次に既知の偽陽性を名指しで削るという順序になっている。最初から完璧な正規表現を組もうとしない、というのは真似する価値がある。
原則2:ブロックせずポーリングする
ここが一番の目玉。「ログが出てくるのを待つ」という動作について、人間とはっきり違う設計思想が出ていた。
| コール数 | 割合 | |
|---|---|---|
tail -f(follow) | 3 | 0.02% |
untilループ | 359 | 2.65% |
while + sleep | 189 | 1.39% |
sleep Nを含む | 2,043 | 15.1% |
13,564件のうちtail -fはたったの3件。 人間なら真っ先にtail -fする場面で、エージェントはほぼ使っていない。
理由は明確で、tail -fは終わらないのでタイムアウトするまでツールをブロックする。しかもその間、流れてくる出力を逐次判断できない。エージェントにとっては「結果を返さないまま時間だけ溶ける」最悪の選択肢になる。
標準形はこれ
LOG="/private/tmp/.../scratchpad/task039_full_ab.log"until grep -q "VERIFY039_DONE" "$LOG" 2>/dev/null; do sleep 60; doneecho "=== RUN COMPLETE ==="grep -E "score|elapsed" "$LOG" | tail -20構成要素がどれも意味を持っている。
| 要素 | 理由 |
|---|---|
grep -q | 出力せず終了コードだけ返す。ポーリング中に画面を汚さない(-qは457コール) |
2>/dev/null | ログファイルがまだ存在しない間のNo such fileを黙らせる。これが無いとループが毎回エラーを吐く |
until | 「〜になるまで待つ」を素直に書ける。while ! grep -qも併用される |
ループ後のechoと要約 | 待ち終わったことと結果を1コールで返しきる |
とくに2>/dev/nullが地味に効いている。ジョブを投げた直後はログファイルがまだ生成されていないので、素直に書くと最初の数回は必ずエラーが出る。ここを黙らせておかないとポーリングが破綻する。
失敗マーカーも一緒に待つ
これが実用上の肝で、ここは素直にうまいと思った。
until grep -q "VERIFY041_DONE\|Traceback" "$LOG" 2>/dev/null; do sleep 120; done成功マーカーだけを待つと、ジョブが異常終了したときに永久にハングする。だからTracebackのような失敗側の文字列も\|で並べて、どちらが出ても抜けるようにしてある。
もっと徹底した例だとこうなる。
f="$SCRATCH/build.output"until grep -qE "BUILD FAILED|FAILURE: |Error: |CommandError|Starting: Intent|Opening on " "$f" 2>/dev/null; do sleep 10donegrep -nE "BUILD SUCCESSFUL|FAILURE" "$f" | tail -5成功も失敗も含めて、終わったと判断できる文字列を全部列挙してから待っている。人間ならtail -fして目で見て気づけばいい部分を、条件として明文化しているわけである。
EXIT=のような自前の終端マーカーをあらかじめ仕込んでおいてそれを待つ形も定番だった。
until grep -qE "EXIT=" /tmp/submit_push.log 2>/dev/null; do sleep 20; donetail -8 /tmp/submit_push.logログにマーカーが無いときはプロセスを見る
# プロセスが消えるまで待つuntil ! pgrep -f "arena.py /tmp/ab_land" >/dev/null; do sleep 20; done; echo DONE
# 複数条件until ! pgrep -f "harv_sweep" >/dev/null && ! pgrep -f "land_sweep2" >/dev/null; do sleep 20; donePIDが分かっているならkill -0(シグナルを送らず生存確認するイディオム)が27コール。ファイルの出現待ちなら[ -f ... ]が94コール。
while kill -0 $PID 2>/dev/null; do sleep 20; donewhile [ ! -f "$SCRATCH/wait.txt" ]; do sleep 2; done; echo finished無限ループを避ける回数上限つき
untilの無条件ループはそれ自体がハングリスクなので、回数を切ってタイムアウトさせる形も使われていた。
i=0until [ $i -ge 110 ]; do S=$(kaggle kernels status user/my-kernel 2>&1 | tail -1) echo "[$(date -u +%H:%M:%S)] $S" case "$S" in *COMPLETE*|*ERROR*|*CANCEL*) break ;; esac i=$((i+1)); sleep 30donedate -u +%H:%M:%Sでタイムスタンプを打つのが190コール。長時間ポーリングの進捗を後から追えるようにするためで、これも自分で自分のログを読む前提の作法だった。
なおsleepの秒数は1〜5秒が1,423回と圧倒的に多い。sleep Nのあとに確認コマンドを続ける形が1,710コール(12.6%)あって、これは「投げてちょっと待って様子を見る」という、最も軽いポーリングにあたる。
原則3:シェルの限界を越えたらPythonに落とす
これも数字がはっきり出ていた。
python3 - <<'PY'形式のヒアドキュメント:717コール(5.3%)python3 -cワンライナー:1,432コール(10.6%)awk:246回sort:298回 /uniq:68回xargs:47回jq:全13,564コール中1回
シェル芸人的にはjqが1回というのが衝撃だと思う。JSONを触る場面はいくらでもあったはずなのに、ほぼ全部Python側で処理している。
python3 - <<'PY'import jsonnb = json.load(open('notebooks/exp005.ipynb'))print(''.join(nb['cells'][3]['source']))PY判断基準は「シェル芸で頑張れる境界を越えたら、迷わずPythonに切り替える」に集約される。JSON操作、正規表現による構造的置換、複数ファイルにまたがる集計は、ほぼ全部Pythonだった。
awkが246回、xargsが47回と少ないのも同じ話で、シェル芸の中級テクを駆使するくらいならPythonを書いたほうが確実という判断が働いている。
ここは正直、シェル芸人としての矜持みたいなものを問われる部分だと思う。ただエージェントは「読みやすさ」ではなく「一発で正しく動く確率」で選んでいるので、この割り切りには合理性がある。人間も、jqのクエリを3回書き直すくらいなら最初からPythonにしたほうが速い場面は多い。
原則4:防御的に書く
エージェントは失敗したらリトライされることが前提なので、書き方が全体的に防御的だった。
毎回 cd し直す
7,489コール(55.2%)がcdから始まっている。 cd自体は7,924回で全コマンド中1位。
cd "/Users/new/.../kaggle_experiments/arc-prize-2026" && grep -n "spatial" exp/exp004/dp_core.py | head -60理由は、Bashツールの作業ディレクトリが呼び出し間で保持されない前提で動いているから。実際、この解析をしている最中にもShell cwd was reset to ...という通知が出ていた。毎コール絶対パスから入り直すのが唯一安全、という結論になる。
パスにスペースや日本語(マイドライブなど)が入りうるので、必ずダブルクォートで囲うのも徹底されていた。
長いパスは変数に退避する
882コール(6.5%)がVAR=/path/...という形で始まる。同じ長大パスを1コール内で何度も使うときの定石。
SP="/private/tmp/claude-501/-Users-new-.../scratchpad/src"grep -n "def solve" -A 25 "$SP/ls20.py"sed -n '1,40p' "$SP/util.py"|| true と || echo でガードする
372コール(2.7%)。&&チェーンが63.5%もあるので、途中の1コマンドが非ゼロ終了すると残り全部が実行されない。それを避けるためのガードになっている。
# 「無い」ことも情報として出力するadb shell which sqlite3 2>/dev/null || echo "no sqlite3"
# 真偽を人間可読な文字列に変換するpgrep -f "train.py" >/dev/null && echo "[実行中]" || echo "[終了]"
grep -rn "old_api" --include='*.md' . || echo " なし ✅"3つ目が地味に重要で、grepはノーマッチだと終了コード1を返す。つまり「見つからなかった」が「失敗」として扱われて、&&チェーンが止まってしまう。これは人間もよく踏むやつで、|| echo "なし"を付けておくのは覚えておいて損がない。
ヒアドキュメントのデリミタは必ずクォートする
ヒアドキュメントは1,223コール(9.0%)。そのうちcat > file <<形式が209コール。
cat > "$D/astar_sc25.py" <<'EOF'"""sc25 L0: A* with patched dedup hash."""from __future__ import annotationsimport heapq, sys, timeEOFデリミタをシングルクォートで囲む(<<'EOF')のが徹底されている。 クォートを付けないと本文中の変数記号やバッククォート、バックスラッシュがシェルに展開されて、PythonコードやJSONが壊れる。逆にシェル変数を意図的に埋め込みたいときだけクォートを外す、という使い分けになっていた。
拡張子に合わせてデリミタ名を変える(<<'JSON'、<<'PY'、<<'SH')のも慣習化していて、これはネストしたときの衝突を避けられる。
追記ではなく全置換
リダイレクト(>)が2,829コールに対して、追記(>>)はわずか87コール。
ファイルは「部分的に追記する」のではなく「全部書き直す」のが基本になっている。理由は冪等性で、追記は同じコマンドを再実行すると内容が二重化する。リトライされる前提のエージェントにとって、>による全置換のほうが事故らない。
これは人間にもそのまま効く教訓だと思う。手順書に「このファイルに追記してください」と書くより、「この内容で置き換えてください」と書いたほうが、2回実行されたときに壊れない。
検索の芸:候補をまとめて投げる
grepのオプション使用頻度も出しておく。
| オプション | 出現数 | 用途 |
|---|---|---|
-n | 1,912 | 行番号。sed -nでの再読み込みに繋ぐ |
-E | 1,332 | 拡張正規表現。候補を並べるため実質必須 |
-r / -R | 606 | 再帰検索 |
-v | 559 | ノイズ除去 |
-q | 457 | 終了コードのみ(ポーリング用) |
-i | 310 | 大文字小文字無視 |
-c | 234 | ヒット数のみ |
-A / -B / -C | 207 | 前後の文脈 |
--include= | 153 | 拡張子で絞る |
-o | 128 | マッチ部分のみ抽出 |
-Eが多いのは、当たりそうな語を一度に全部投げるからだった。
grep -n "gs\b\|GR\|nan\|isfinite\|interp\|fillna" exp/exp004/dp_core.py | head -60grep -iE "payload|contract|error|traceback|candidate|written|rows" run.log | head -401語ずつ試すと、外すたびにツール呼び出しが1往復増える。だから10語まとめて投げてheadで切るほうが効率がいい。人間のシェル芸との差がはっきり出る部分で、人間は「まずerrorで引いてみて、ダメならfailで」と1つずつ試す。
これは真似する価値があると思っている。ターミナルで1語ずつ試している時間より、思いつく限り並べて一発で投げたほうが速い場面は普通にある。
-oで構造抽出する使い方も見られた。jqが使えない相手に対する擬似パーサになっている。
kaggle kernels status user/k 2>&1 | grep -oE 'KernelWorkerStatus\.[A-Z]+'grep -o 'resource-id="[^"]*"[^>]*bounds="[^"]*"' ui.xml | tail -40なおfindは597回あるが、-execやxargsとの組み合わせは43回だけ。ほとんどがツリー構造の把握に使われていて、-not -path '*__pycache__*'のようなノイズ除去や-maxdepth 2での深さ制限がよく付いていた。ここでも出力量の自衛が効いている。
人間のシェル芸との差分
まとめると、こういう対比になる。
| 観点 | 人間 | Claude Code |
|---|---|---|
| ログ監視 | tail -fで目視 | until grep -qでポーリング |
| 出力量 | 端末スクロールで対処 | head/tailで必ず切る |
| 区切り | 不要(対話的に分けて叩く) | echo "==="を注入 |
| JSON処理 | jq | Pythonヒアドキュメント |
| ファイル編集 | sed -i / vim | >で全置換、または専用ツール |
| 検索語 | 1つずつ試行錯誤 | -Eで10語まとめ投げ |
| 作業ディレクトリ | cdして居座る | 毎コール絶対パスで入り直す |
そして最終的に、実データから読み取れる原則は5つに集約された。
| # | 原則 | 根拠となる数字 |
|---|---|---|
| 1 | 1コールに調査シーケンスを詰め込む | 結合演算子 平均4.76個、&& 63.5%、パイプ 60.0% |
| 2 | 出力量を必ず自衛する | head/tailが各23〜25%、grep | headが18.5% |
| 3 | 自分が読むための構造を出力に埋め込む | echo "==="セパレータが25.7% |
| 4 | ブロックせずポーリングする | tail -f 0.02%に対しuntil+sleep系 |
| 5 | シェルの限界を越えたらPythonに落とす | python3ヒアドキュメント717回、jqは1回 |
で、人間は何を盗めるのか
最初の問い(シェル芸人こそ最強では?)に戻る。集計を眺めた結論としては、エージェントのシェル芸は人間より上手いわけではないが、制約が違うぶん違う最適解に着地しているという感じだった。
そのうえで、人間がそのまま盗めると思ったのは次の4つ。
1. headは20行、tailは3行と決めておく
探索と確認で見る行数を分ける、というだけの話だが、意識するとログ掘りが明確に速くなる。「とりあえず全部出して目で追う」が一番遅い。
2. grepは候補をまとめて投げる
grep -E "error|fail|traceback|exception"と最初から並べる。1語ずつ試して外す時間のほうが、正規表現を組む時間より長い。
3. 完了待ちはuntil grep -qにする
tail -fで画面を眺めている時間は、実は何もしていない時間である。マーカーを決めてuntilで待てば、その間ほかのことができる。成功マーカーと失敗マーカーの両方を待つのを忘れないこと。ここを忘れると、ジョブが死んだのに待ち続けることになる。
until grep -qE "DONE|Traceback|FAILED" build.log 2>/dev/null; do sleep 30; donetail -20 build.log4. jqで粘らずPythonに逃げる
これは人によって好みが分かれると思うが、jqのクエリを3回書き直した時点でPythonに切り替えたほうが速い、というのは経験的にも正しい。
逆に、真似しなくていいものもある。echo "==="のセパレータ注入は、対話的に叩く人間には不要だ。毎回cdし直すのも、シェルの状態が保持される人間の環境では冗長でしかない。これらはエージェント固有の制約から出てきた作法であって、良い書き方だから採用されているわけではない。
注意点:この数字をどこまで信じるか
最後に、集計の限界も書いておく。数字だけ一人歩きすると困るので。
環境バイアスが強い。 コマンド頻度トップの中にはadb(2,568回、Android開発)、kaggle(1,266回)、backlog(1,127回、タスク管理ツール)が入っている。これは筆者の環境固有で、Web開発中心の環境ならnpmやdockerやcurlの比率がもっと高くなるはず。「コマンド頻度」は汎用的な代表値ではない。
長時間バッチが多い環境である点も効いている。 untilポーリングの2.65%という比率は、機械学習ジョブやモバイルビルドを頻繁に回すこの環境ゆえにやや高めの可能性がある。ただし、tail -fを使わないという事実自体は比率と無関係に成立する。
集計方法の粗さもある。 コマンド頻度はセグメント先頭トークンの単純集計なので、ヒアドキュメント本文の行(defが486、constが98など)が混入している。主要コマンドの相対順位には影響しないが、絶対数は数%の過大側になっている。>の2,829件も>/dev/nullを含むため、「ファイル書き込み」より広い集合を数えている。傾向(全置換優位)は確実だが、絶対数はやや盛られていると見たほうがいい。
時系列は追っていない。 全期間を一括集計しているので、Claude Codeのバージョン更新に伴う作法の変化はこのデータからは読み取れない。
そのうえで、汎用的に妥当なのは構文的特徴(詰め込み度・出力抑制・ポーリング作法・Pythonへの委譲)のほうだと考えている。これらはタスク領域ではなく「エージェントであること」から導かれる制約なので、他の環境でも再現するはずである。
まとめ
- 実トランスクリプト607ファイル・Bash呼び出し13,564件を全件集計した。一般論ではなく実データ
- 単発コマンドはわずか6.9%。
&&とパイプで調査シーケンスを1コールに詰め込むのが基本形 tail -fは3件(0.02%)しかない。until grep -q ...; do sleep ...; doneでポーリングし、失敗マーカーも一緒に待つheadは探索用で20の倍数、tailは確認用で1〜3行。役割が完全に分かれているsedは-nの範囲プリントが1,125回に対し-iは54回。エディタではなくページャとして使われているecho "==="が25.7%。自分が後で読むための見出しを出力に埋め込むエージェント固有の作法jqは全体で1回。シェルの限界を越えたら迷わずPythonに落としている- ただしコマンド頻度は環境依存が強い。構造的な傾向のほうを見るべき
「シェル芸人こそ最強なのでは?」という当初の問いに答えるなら、最強なのはシェル芸そのものではなく、制約を理解したうえでコマンドを選べることだった。エージェントは「出力はコンテキストを食う」「ブロックすると何も返せない」「リトライされる前提」という制約から逆算して、人間とは違う作法に着地している。
そう考えると、人間側の制約(目で追える、対話的に叩ける、状態が保持される)も、意識してみる価値がある。そこを疑うと、tail -fで画面を眺めている時間が本当に必要だったのか、みたいなところから見直せる。少なくとも筆者は、あの日以来until grep -qをよく書くようになった。
参考文献
- 解析対象データ:ローカルのClaude Codeトランスクリプト
~/.claude/projects/**/*.jsonl(607ファイル、Bashツール呼び出し13,564件、2026-08-04時点の集計) - Claude Code 公式ドキュメント https://docs.claude.com/en/docs/claude-code/overview
- GNU Grep マニュアル https://www.gnu.org/software/grep/manual/grep.html
- GNU Sed マニュアル https://www.gnu.org/software/sed/manual/sed.html
- Bash Reference Manual — Here Documents https://www.gnu.org/software/bash/manual/bash.html#Here-Documents