---
date: 2026-05-11
tags: [bash, pkill, claude-code]
status: documented
---

# `pkill -f "<pattern>"` 会匹配自己的 bash 进程

## 现象

在 Claude Code 的 Bash 工具里跑：

```bash
pkill -f "next.*dev" && sleep 2 && ...
```

bash 进程被 SIGTERM 杀掉，整个命令 exit 144（128 + 16 = SIGTERM），后续步骤未执行。

## 根因

`pkill -f` 匹配进程的**完整命令行**（`/proc/<pid>/cmdline`）。
Claude Code 的 Bash 工具会启动一个 bash 进程，其 cmdline **包含被执行的完整命令字符串**，
所以 `pkill -f "next.*dev"` 的 cmdline 本身就含 `next.*dev` 子串，被自己匹配，自杀。

## 解决

三选一：

1. **用更精确的字面匹配**：`pkill -f "next dev -p"`（空格 + 后续参数，命令行里不会出现这串字符）
2. **指定 PID 而非模式**：`pkill -P <ppid>` 或先 `pgrep -f "..." | grep -v $$ | xargs kill`
3. **匹配实际 binary 路径**：`pkill -f "node.*\.bin/next"`（pkill 的命令行不会含这串）

例：

```bash
# 杀掉 next dev，避免自杀
NPID=$(pgrep -f "next dev -p 3300" | head -1)
[ -n "$NPID" ] && kill "$NPID"
```

## 触发条件

- 在 Claude Code Bash 工具里
- 用 `pkill -f` / `pgrep -f` 杀进程
- pattern 是普通词（"node" / "next" / "npm"）—— 容易在自己 cmdline 里也出现

## 防御性写法

如果一定要用 `pkill -f`，把进程过滤限制到非当前 bash：

```bash
pkill -f "next dev" --signal TERM 2>/dev/null
# 或
ps -eo pid,args | awk '/[n]ext dev/{print $1}' | xargs -r kill
# [n]ext 让 awk 自身在 ps 输出里不匹配自己
```
