最近使用 AI Agent 开发时,你可能会发现一个很有意思的现象:Agent 经常在终端里执行 grep、sed,还会把好几个命令用管道符 | 串起来。
例如:
grep -n "TODO" src/app.ts
sed -n '20,60p' src/app.ts
grep -RIn "createOrder" src/ | head -20
如果你平时主要在 IDE 里写代码,这些命令看起来可能有点“古早”。既然 AI 已经能理解整个项目,为什么还需要这些命令?
答案是:Agent 不只是生成代码,它还需要不断观察项目、定位信息、验证结果。终端命令是它与文件系统、代码和工具交互的一种基础接口。
理解这些命令,不是为了和 AI 比谁敲得快,而是为了看懂它正在做什么、判断结果是否可信,并在它操作失误时及时发现问题。
本文以 Linux 和 macOS 为主,整理一套日常开发中最值得掌握的终端命令。大部分命令在两种系统上都能使用,但少数参数存在差异,文中会特别说明。
一、先理解终端命令是怎么工作的
可以先把一次命令执行理解成三个部分:
- 命令:要运行的程序,例如
grep。 - 参数:告诉程序如何工作,例如
-n表示显示行号。 - 输入与输出:命令读取什么内容,又把结果输出到哪里。
例如:
grep -n "error" app.log
这里,grep 是命令,-n 和 "error" 是参数,app.log 是输入文件。它会输出包含 error 的行,并显示行号。
终端里最重要的三个概念
| 符号 | 含义 | 示例 |
|---|---|---|
| ` | ` | 管道:把左侧命令的标准输出传给右侧命令的标准输入 |
> | 重定向:把输出写入文件,覆盖原内容 | echo hello > a.txt |
>> | 追加重定向:把输出追加到文件末尾 | echo hello >> a.txt |
其中,管道符是理解 Agent 命令组合的关键。先记住一句话:
左边负责产生结果,右边负责继续处理结果。
二、文件与目录:先知道自己在哪里
这些命令看起来基础,却是终端操作的起点。
1. pwd:查看当前目录
pwd
输出可能是:
/Users/samoy/work/my-project
当 Agent 执行相对路径命令时,当前目录会影响路径的实际含义。如果它说“读取 src/main.ts”,但当前目录并不是项目根目录,就可能读错文件或报错。
2. ls:列出文件
ls
ls -la
ls -lh
ls:列出当前目录内容。ls -la:包括隐藏文件,并显示详细信息。ls -lh:以更容易阅读的形式显示文件大小。
在项目里,ls -la 常用于确认是否存在 .git、.env、配置文件等隐藏内容。
3. cd:切换目录
cd src
cd ..
cd ~
cd src:进入当前目录下的src。cd ..:返回上一级目录。cd ~:回到用户主目录。
4. mkdir、cp、mv、rm
mkdir -p src/utils
cp config.example.json config.json
mv old-name.ts new-name.ts
rm temp.txt
这些命令分别用于创建目录、复制、移动/重命名和删除文件。
AI 时代尤其需要注意: rm、覆盖式重定向、批量移动等命令可能造成真实的数据损失。看到 Agent 准备执行 rm -rf 或批量改写文件时,应先弄清楚目标路径和影响范围,不要只看它给出的解释。
三、grep:从大量文本中搜索线索
grep 是 Agent 经常调用的命令之一。它擅长在文件中查找匹配某个文本或正则表达式的行。
1. 搜索某个关键词
grep "createOrder" src/order.ts
这会输出 src/order.ts 中包含 createOrder 的行。
2. 显示行号:-n
grep -n "createOrder" src/order.ts
输出类似:
18:export function createOrder() {
42: return createOrder(payload);
行号很重要:它能帮助你快速跳转到对应代码,也方便 Agent 在进一步读取文件时缩小范围。
3. 递归搜索目录:-R
grep -RIn "createOrder" src/
常用参数:
-R:递归搜索目录。-I:忽略二进制文件。-n:显示行号。
这个命令可以帮助 Agent 追踪函数在哪里定义、在哪里调用,或查找配置项、错误提示和 TODO。
如果想忽略大小写,可以加上 -i:
grep -RIn "timeout" src/ -i
如果只想知道哪些文件匹配,而不需要打印具体行,可以使用 -l:
grep -RIl "API_BASE_URL" src/
4. 搜索时排除目录
项目里通常有 node_modules、构建产物、依赖锁文件等内容,不一定适合全部搜索。简单场景可以指定目标目录:
grep -RIn "TODO" src/
如果需要复杂的忽略规则,可以使用项目已有的搜索工具,或安装 ripgrep(命令名 rg)。它通常能自动遵循 .gitignore,非常适合代码库搜索:
rg -n "createOrder" src/
rg -n "TODO|FIXME" src/
rg -l "API_BASE_URL" .
注意:rg 并非每台 Linux/macOS 机器都默认安装;grep 则更常见。Agent 选用哪个命令,往往取决于运行环境里有哪些工具。
四、sed:按规则读取或处理文本
如果说 grep 擅长“找出哪些行符合条件”,那么 sed 更擅长“按规则筛选或替换文本”。
1. 只查看指定行:-n 与 p
sed -n '20,60p' src/app.ts
这条命令表示:只打印第 20 行到第 60 行。
这里有两个关键点:
-n:默认不打印每一行。'20,60p':对第 20 至第 60 行执行打印操作,p是 print。
所以 Agent 经常先搜索某个函数:
grep -n "function createOrder" src/app.ts
找到它大概在第 120 行后,再查看附近内容:
sed -n '110,160p' src/app.ts
这比一次性把几千行文件全部输出到上下文里更有针对性,也更容易审查。
2. 替换文本:s
sed 's/oldName/newName/g' input.txt
这里的 s 表示替换,g 表示替换每一行中所有匹配项。
默认情况下,这条命令只把替换结果输出到终端,并不会直接修改原文件。
如果要将输出保存到另一个文件:
sed 's/oldName/newName/g' input.txt > output.txt
3. 为什么 sed -i 值得特别小心
-i 通常用于直接修改文件,但 Linux 常见的 GNU sed 与 macOS 自带的 BSD sed 在参数上有差异。
macOS 常见写法:
sed -i '' 's/oldName/newName/g' file.txt
GNU/Linux 常见写法:
sed -i 's/oldName/newName/g' file.txt
如果希望保留备份文件,两种环境也有各自的参数细节。因此,不要假设某台机器上的 sed -i 命令可以不加修改地在另一台机器上运行。对于重要文件,先预览替换结果、查看 Git diff,再执行修改会更稳妥。
如果只是查看代码,通常使用 sed -n 就足够了,并不需要 -i。
五、管道符 |:把命令组合成一条处理链
这是终端最值得理解的概念之一。
先看一个简单例子:
grep -n "ERROR" app.log | head -20
它并不是把两个命令的结果随意拼在一起,而是:
grep找出包含ERROR的行,并显示行号。- 管道符把这些行传给
head。 head -20只显示前 20 行。
可以把它想象成一条小型流水线:
flowchart LR
A["app.log 日志文件"] --> B["grep 搜索 ERROR"]
B --> C["管道 | 传递输出"]
C --> D["head 取前 20 行"]
D --> E["终端显示结果"]
每个命令只负责一件相对简单的事,通过组合完成更复杂的任务。这种思想常被概括为 Unix 哲学:让小工具协同工作。
常见的管道组合
统计某个关键词出现了多少行:
grep -c "ERROR" app.log
这里其实不需要管道,因为 grep -c 已经能直接统计匹配行数。如果想统计多个文件的匹配行,可以:
grep -R "TODO" src/ | wc -l
注意,wc -l 统计的是输入中的行数;在这个例子里,它通常对应匹配结果的行数,而不是关键词在每行出现的总次数。
只查看最近 50 行日志中的错误:
tail -50 app.log | grep "ERROR"
查看某个进程是否存在:
ps aux | grep "node"
这种写法可能也会匹配到搜索命令自身;在不同系统中,更合适的进程查询方式可能不同。不要仅凭这条命令的输出就认定目标进程一定在运行。
管道传递的通常是标准输出,不是所有输出
命令行中常见的输出流包括:
- 标准输入(stdin):通常记为文件描述符
0。 - 标准输出(stdout):通常记为文件描述符
1。 - 标准错误(stderr):通常记为文件描述符
2。
普通管道 | 默认传递左侧命令的标准输出。错误信息通常走标准错误流,因此不一定会进入右侧命令。
例如:
some-command 2>&1 | grep "error"
2>&1 会把标准错误重定向到标准输出,再由管道传给 grep。重定向顺序会影响结果,刚开始只需先理解它的目的:需要搜索错误信息时,要确认错误究竟输出到了哪个流。
六、其他值得认识的高频命令
不需要一次记住全部参数。知道每个命令适合解决什么问题,已经很有帮助。
| 命令 | 主要用途 | 示例 |
|---|---|---|
cat | 输出文件内容,适合较短文件 | cat package.json |
less | 分页阅读长文件,可搜索和上下翻页 | less app.log |
head | 查看开头若干行 | head -20 app.log |
tail | 查看末尾若干行;-f 可持续跟踪日志 | tail -f app.log |
wc | 统计行数、单词数或字节数 | wc -l app.log |
find | 按名称、类型等条件查找文件 | find src -name "*.ts" |
sort | 排序文本行 | sort names.txt |
uniq | 处理相邻的重复行,通常先配合排序 | sort names.txt | uniq |
cut | 按分隔符或字符位置提取字段 | cut -d ',' -f 1 data.csv |
awk | 按字段和规则处理文本 | awk -F ',' '{print $1}' data.csv |
xargs | 把输入项转换成命令参数 | printf '%s\\n' a.txt b.txt | xargs -n 1 wc -l |
一个实用的 find 示例
查找 src 下所有 TypeScript 文件:
find src -type f -name "*.ts"
其中:
-type f:只查找普通文件。-name "*.ts":文件名匹配.ts结尾的模式。
如果后续要对查找到的文件批量执行操作,应该先检查匹配列表。处理可能包含空格或特殊字符的文件名时,优先考虑 find ... -print0 与支持 -0 的 xargs,不要简单地用空格拼接文件名。
sort | uniq 为什么经常一起出现?
uniq 主要消除相邻的重复行,不会自动把文件中所有相同内容都找出来。所以常见组合是:
sort names.txt | uniq
如果还想统计每种内容出现的次数:
sort names.txt | uniq -c
这也是管道的典型用法:先排序,再把排序结果交给下一个命令统计。
七、把命令组合起来:几个真实开发场景
了解单个命令后,更重要的是看它们如何解决具体问题。
场景一:在项目中定位函数定义
grep -RIn "createOrder" src/
如果输出太多,只看前 20 条:
grep -RIn "createOrder" src/ | head -20
定位到文件和行号后,再读取局部代码:
sed -n '100,150p' src/services/order.ts
这组操作体现了 Agent 常见的工作方式:先搜索,再缩小范围,然后读取相关上下文。
场景二:快速检查日志
grep -n "ERROR" app.log | tail -30
这会从匹配结果中取最后 30 行,而不是先取日志文件最后 30 行。两种写法含义不同:
# 先取文件末尾 30 行,再过滤错误
tail -30 app.log | grep "ERROR"
# 找出所有错误,再取最后 30 条匹配结果
grep -n "ERROR" app.log | tail -30
命令顺序决定了处理逻辑。阅读管道时,可以从左到右逐个解释每一步,通常就不难理解了。
场景三:检查改动是否意外影响了其他文件
如果 Agent 修改了代码,可以使用 Git 查看改动:
git status --short
git diff -- src/
git diff --check
git status --short:快速查看工作区改动。git diff -- src/:检查指定目录的代码差异。git diff --check:检查差异中常见的空白字符问题。
这比只听 Agent 说“已经修改完成”更可靠。让工具报告结果,再由你检查差异,是 AI 辅助开发中非常值得养成的习惯。
八、AI Agent 时代,为什么更应该懂这些命令?
过去,开发者学习命令行,主要是为了自己更快地完成工作。现在,即使你不打算成为命令行高手,也值得理解 Agent 执行的命令。
1. 你需要审查它的操作范围
看到:
grep -RIn "token" .
就应该知道它会从当前目录开始递归搜索。假如当前目录是项目根目录,搜索范围可能相当大,甚至可能碰到不希望扫描的文件。
看到:
sed -i 's/old/new/g' config.txt
就应该意识到这是直接修改文件的操作,而不是单纯查看内容。
2. 你需要判断输出是否真的支持结论
如果 Agent 执行:
grep -RIn "validateUser" src/
没有找到结果,并不一定说明项目里没有这个逻辑。可能是函数换了名字、使用了动态调用、搜索目录不对,或者相关代码位于其他文件类型中。
命令没有返回结果,只能说明这次搜索没有匹配到;它不一定证明目标不存在。
3. 你需要知道什么时候让它缩小上下文
一次性读取巨大的日志文件或源码文件,会产生大量无关输出。相比之下:
grep -n "关键函数" src/app.ts
sed -n '120,180p' src/app.ts
先定位、再读取局部内容,往往更有效率,也能让人更容易复核。
4. 你需要在关键操作前设置安全边界
对 AI Agent 来说,命令执行不只是“生成一段字符串”,而可能是真正读取、修改或删除本地文件。以下几条习惯很实用:
- 先读后写:修改前先查看目标文件和相关代码。
- 先预览后批量处理:确认匹配范围,再执行替换、移动或删除。
- 优先查看 diff:不要只依赖 Agent 的文字总结。
- 注意当前目录:相对路径的含义取决于执行位置。
- 谨慎处理密钥文件:不要随意把
.env、凭证、私钥等内容输出到日志或发送给不可信工具。 - 理解命令再授权:特别关注
rm -rf、覆盖重定向、批量替换、联网下载后执行脚本等高影响操作。
九、初学者最容易踩的几个坑
坑一:把管道当成“把所有东西都传过去”
普通的 | 主要传递标准输出,不会自动传递所有错误信息。如果下游命令看不到报错,要留意标准错误流。
坑二:认为 uniq 会自动统计所有重复项
它只处理相邻的重复行。要统计所有相同项,通常先 sort 再 uniq。
坑三:认为 sed 在 macOS 和 Linux 完全一样
尤其是直接修改文件的 -i 参数,BSD sed 与 GNU sed 的行为有差异。跨平台脚本要明确目标环境,避免未经验证地执行修改命令。
坑四:把搜索结果当作完整事实
搜索工具只能找到符合当前模式和搜索范围的内容。没有结果,不代表逻辑不存在;有结果,也需要查看上下文,避免把注释、测试代码或无关字符串当作实际调用。
坑五:盲目复制网上的命令
有些命令包含删除、覆盖或执行远程脚本的操作。即使命令来自 AI,也应先理解它会对哪些文件、目录或系统资源产生影响。
十、建议的学习顺序
如果你是为了看懂 AI Agent 的终端操作,不必从 Shell 脚本编程开始。可以按下面的顺序逐步掌握:
- 目录与文件:
pwd、ls、cd、cat、less。 - 定位内容:
grep、find、rg。 - 读取和处理文本:
head、tail、sed、wc、sort、uniq。 - 组合命令:理解
|、>、>>、2>&1。 - 安全检查:
git status、git diff、文件备份与命令影响范围。 - 进阶自动化:再学习
awk、xargs、Shell 变量、条件判断和脚本。
不需要把每个参数背下来。遇到一个命令时,能回答三个问题就已经很不错了:
- 它读取什么?
- 它会输出或修改什么?
- 如果把它接到另一个命令后面,会改变什么?
写在最后
AI Agent 让我们不必手动敲出每一条命令,但没有让命令行本身变得不重要。
恰恰相反,当 Agent 可以直接操作项目文件、搜索代码、运行测试甚至修改环境时,理解它的工具调用就成了一种新的开发基本功。
grep 帮我们搜索,sed 帮我们筛选或转换文本,管道符把简单工具连接起来。它们看似朴素,却构成了大量自动化工作流的基础。
在 AI 时代,掌握命令行不一定是为了自己完成所有操作,而是为了知道 AI 正在做什么、为什么这么做,以及怎样判断它做得对不对。
欢迎在评论区留下您的见解~