课程大纲 › 领域 2:工具设计与 MCP
2.5 有效选择并运用内置工具(Read、Write、Edit、Bash、Grep、Glob)
タスクステートメント2.5:組み込みツール(Read、Write、Edit、Bash、Grep、Glob)を効果的に選択し適用する
官方大纲原文(日文):知识 4 条 · 技能 5 条
需要掌握的知识
- コンテンツ検索のためのGrep(関数名、エラーメッセージ、import文などのパターンをファイルの内容から検索する)
- ファイルパスのパターンマッチングのためのGlob(名前や拡張子のパターンでファイルを見つける)
- ファイル全体の操作のためのRead/Write。一意のテキストマッチングを使用した的を絞った変更のためのEdit
- テキストの一致が一意でないためにEditが失敗した場合に、確実なファイル変更のためのフォールバックとしてRead + Writeを使用すること
需要能做到的事
- コードベース全体でコードの内容を検索するためにGrepを選択する(例:ある関数のすべての呼び出し元を見つける、エラーメッセージの場所を特定する)
- 命名パターンに一致するファイルを見つけるためにGlobを選択する(例:**/*.test.tsx)
- Editが一意のアンカーテキストを見つけられない場合に、Readでファイルの内容全体を読み込んでからWriteを使用する
- 最初にすべてのファイルを読むのではなく、Grepでエントリーポイントを見つけることから始め、次にReadでimportをたどってフローを追跡することで、コードベースの理解を段階的に構築する
- まずエクスポートされたすべての名前を特定し、次にコードベース全体で各名前を検索することで、ラッパーモジュールをまたぐ関数の使用箇所を追跡する
课程讲解 · AI 草稿,未经人工审核 以官方文档为准
这一条考什么
考你能否针对具体任务选对 Claude Code / Agent SDK 的内置工具:搜内容用 Grep,按文件名找文件用 Glob,整文件读写用 Read/Write,局部精确修改用 Edit;Edit 因匹配不唯一失败时知道用 Read + Write 兜底。更高阶的是“探索策略”:先用 Grep 找入口再沿 import 逐步阅读,以及追踪经过包装模块改名后的函数调用方。
核心概念
Grep:搜索文件“内容”
Grep 基于正则在文件内容中查找匹配行,返回文件路径、行号和上下文。适用场景:
- 找某个函数的所有调用方:
processRefund\( - 定位错误信息出自哪里:日志里的
SYNC_CONFLICT、entity version mismatch - 找所有导入某个包的文件:
from ['"]@company/auth - 安全扫描危险调用:
eval\(
判断关键词:题目说的是“包含某段文本 / 调用 / import / 报错信息”的文件,就是 Grep。
Glob:匹配文件“路径”
Glob 按路径模式找文件,不看内容。适用场景:
- 所有测试文件:
**/*.test.tsx - 某目录下的所有配置:
config/**/*.yaml - 名字里带 migration 的文件:
**/*migration*
判断关键词:题目说的是“文件名 / 扩展名 / 目录结构符合某模式”,就是 Glob。用 Glob 找 **/eval* 来找 eval 调用是典型错误——文件名里没有 eval 的文件里同样可能调用 eval。
Read / Write / Edit
- Read:读取整个文件(可指定行范围),是理解代码、编辑前确认内容的基础。
- Write:整文件写入或覆盖,适合新建文件或彻底重写。
- Edit:用
old_string→new_string做精确替换。要求old_string在文件中唯一匹配,否则失败(除非显式使用replace_all替换所有出现处)。Edit 的优点是改动小、可审查、不会误伤其他部分。
{
"name": "Edit",
"input": {
"file_path": "/repo/src/booking.py",
"old_string": "def validate_booking(booking):\n if booking.guests < 1:",
"new_string": "def validate_booking(booking):\n if booking.date <= date.today():\n raise ValueError(\"date must be in the future\")\n if booking.guests < 1:"
}
}Edit 失败时:Read + Write 兜底
文件里充满重复的 docstring、相同的变量名和结构,找不到唯一锚点文本时,Edit 会反复失败。可靠的兜底方案:用 Read 读入整个文件,在完整内容中确定插入位置,再用 Write 写回完整文件。 不要用 replace_all 去替换一个常见模式(会改动所有出现处),也不要用 Bash heredoc 追加到文件末尾(位置不对,且绕开了编辑工具的追踪)。在可行时,先尝试扩展 old_string 加入足够的上下文使其唯一,也是合理的第一步;但大纲强调的兜底是 Read + Write。
增量式理解代码库
不要一上来就把所有文件 Read 一遍——那会迅速耗尽上下文,而且大部分内容无关。推荐流程:
- 用 Grep 找到入口点(路由定义、main 函数、报错文本、关键函数名)。
- Read 入口文件,看它 import 了什么。
- 沿 import 链有选择地 Read 下一层文件,逐步构建流程图。
- 需要时再用 Grep 横向确认“还有谁用了它”。
追踪经过包装模块的函数
库函数 calculateTax 被 orders 模块包装成 computeOrderTax 再导出,只 Grep 原名会漏掉通过别名调用的地方。可靠做法:先 Read 库模块和包装模块,列出该函数对外暴露的所有名字(原名、re-export、别名),再对每个名字在全仓库 Grep。 只 Grep 所有 import 了库的文件再逐个阅读,代价高且仍可能漏掉二次包装。
# 第一步:找出所有导出名
grep -rn "calculateTax" src/lib src/orders/index.ts
# 发现:export const computeOrderTax = calculateTax
# 第二步:对每个名字搜索调用方
grep -rn -E "calculateTax\(|computeOrderTax\(" src/Bash 的定位
Bash 很强大,但对于内容搜索和文件查找,专用的 Grep/Glob 更合适:输出结构化、权限更好控制、不依赖平台命令差异。ls -R | grep eval 只搜文件名,find -name "*auth*" 只按名字找目录,都无法回答“谁在代码里用了它”。
正确做法与反模式
- 正确:用 Grep 找某函数的所有调用方、定位报错信息来源。反模式:Read README 和配置后逐个服务读源码;用 Glob 按“errors/exceptions”目录名猜位置。
- 正确:用 Glob
**/*.test.tsx找所有测试文件。反模式:用 Grep 搜内容来间接判断哪个文件是测试文件。 - 正确:Edit 找不到唯一锚点时,Read 全文再 Write 写回。反模式:
replace_all替换常见模式、Bash 追加到文件末尾。 - 正确:Grep 找入口,Read 沿 import 逐步追踪。反模式:一开始就把整个代码库 Read 进上下文。
- 正确:先识别包装模块导出的所有名字,再逐个 Grep。反模式:只 Grep 原函数名,漏掉别名调用。
常见陷阱
- 把“内容”问题当成“文件名”问题:例如用 Glob
**/*auth*找导入@company/auth的文件。导入语句在文件内容里,文件名不一定含 auth。 - “从 package.json / README 开始读”:听起来系统,实则低效,题目问“最有效”时几乎总是 Grep 一段独特文本。
- Grep 一个“模块”而不是具体文本:如 Grep 所有导入错误处理模块的文件再逐个阅读,范围过大;应直接 Grep 报错信息中的独特字符串。
- Edit 失败后的花式补救:
replace_all、Bash heredoc、手工拼超长正则,都可能改错位置。记住大纲给出的兜底:Read + Write。 - 只搜原始函数名:在有包装/重命名的题干里,这个选项是“看起来对但不完整”的陷阱。
- 用 Bash `ls -R | grep` 或 `find` 代替 Grep:只匹配路径,不匹配内容。
实操练习
目标:用 Claude Code 的无头模式,观察模型在受限工具集下如何选择 Grep/Glob/Read,并体验 Edit 的唯一性约束。
- 准备一个小仓库:
src/lib/tax.ts导出calculateTax,src/orders/index.ts中export const computeOrderTax = calculateTax,另有两三个文件分别调用这两个名字;再建几个*.test.tsx文件。 - 只开放只读工具,让 Claude 找出所有调用方。
- 查看输出中它是否先读取包装模块再按多个名字搜索。
- 再让它在一个满是重复 docstring 的文件中插入新函数,观察 Edit 是否失败并改用 Read + Write。
claude -p "找出仓库中所有调用 calculateTax 的地方,包括通过包装模块改名后的调用。先说明你识别出的所有导出名,再列出 文件:行号。" \
--allowedTools "Read,Grep,Glob" \
--output-format json | jq -r '.result'
claude -p "列出所有 .test.tsx 文件的路径" --allowedTools "Glob" --output-format text检查结果:第一条命令的结果应同时包含 calculateTax 和 computeOrderTax 的调用位置;第二条应只用 Glob 就返回测试文件列表。若想看工具调用过程,可改用 --output-format stream-json --verbose 观察每次 tool_use 的工具名。
自测清单
- “找出所有调用
eval()的位置”和“找出所有*.spec.ts文件”分别用什么工具?为什么不能互换? - Edit 工具对
old_string有什么要求?失败时可靠的兜底方案是什么? - 为什么不应该在理解代码库时先 Read 所有文件?推荐的增量流程是怎样的?
- 函数经过包装模块改名导出时,怎样确保找到所有调用方?
- 日志里出现一条陌生报错,不知道来自哪个服务,最快的定位方法是什么?
对应题目(5)
题目归类由 AI 判断,仅供参考。
练习这 5 道题