开发工具

AI Agent 时代的终端生存指南:从 grep、sed 到管道符

最近使用 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

它并不是把两个命令的结果随意拼在一起,而是:

  1. grep 找出包含 ERROR 的行,并显示行号。
  2. 管道符把这些行传给 head。
  3. 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 脚本编程开始。可以按下面的顺序逐步掌握:

  1. 目录与文件:pwd、ls、cd、cat、less。
  2. 定位内容:grep、find、rg。
  3. 读取和处理文本:head、tail、sed、wc、sort、uniq。
  4. 组合命令:理解 |、>、>>、2>&1。
  5. 安全检查:git status、git diff、文件备份与命令影响范围。
  6. 进阶自动化:再学习 awk、xargs、Shell 变量、条件判断和脚本。

不需要把每个参数背下来。遇到一个命令时,能回答三个问题就已经很不错了:

  • 它读取什么?
  • 它会输出或修改什么?
  • 如果把它接到另一个命令后面,会改变什么?

写在最后

AI Agent 让我们不必手动敲出每一条命令,但没有让命令行本身变得不重要。

恰恰相反,当 Agent 可以直接操作项目文件、搜索代码、运行测试甚至修改环境时,理解它的工具调用就成了一种新的开发基本功。

grep 帮我们搜索,sed 帮我们筛选或转换文本,管道符把简单工具连接起来。它们看似朴素,却构成了大量自动化工作流的基础。

在 AI 时代,掌握命令行不一定是为了自己完成所有操作,而是为了知道 AI 正在做什么、为什么这么做,以及怎样判断它做得对不对。

更早的文章

53个开源AI Agent行为测试报告:发现37个缺陷背后的技术启示

欢迎在评论区留下您的见解~