关于 killall 和 pkill 命令的陷阱 ,推荐使用 pidof 命令

本文探讨了在Linux环境下使用killall与pgrep命令时遇到的问题,特别是当进程名称长度超过15个字符时,这些命令可能无法正确找到目标进程。文章提供了具体的示例和解决方案,并推荐使用pidof命令作为更可靠的替代方案。

      转载一同事的博文。

总结1 :尽量避免使用 killall、pgrep 、ps | xargs kill 的方式

总计2 :尽量使用 pidof 或者 pidof | xargs kill 的组合来代替上面的几个命令


平常大家 kill 进程,可能习惯使用如下的方式

1
killall bt_uinfo_memcached
1
pkill bt_uinfo_memcached
1
ps -C bt_uinfo_memcached --format=\'pid\' --noheaders | xargs kill

大部分情况下这个都是可以正常工作的,但我们来看一下下面的这个命令

1
2
3
4
5
6
root@ubuntu:~# ps -ef |grep bt_uinfo_memcached
root 8765 23103 0 14:13 pts/2 00:00:00 grep --color=auto bt_uinfo_memcached
root 26195 1 0 12:43 ? 00:00:32 ./bt_uinfo_memcached -p 20211 -u root -l 0.0.0.0 -m 3072 -d
root 26236 1 0 12:43 ? 00:00:30 ./bt_uinfo_memcached -p 20311 -u root -l 0.0.0.0 -m 3072 -d
root 26586 1 1 12:43 ? 00:01:15 ./bt_uinfo_memcached -p 20411 -u root -l 0.0.0.0 -m 3072 -d
root@ubuntu:~#
1
2
3
root@ubuntu:~# killall bt_uinfo_memcached
bt_uinfo_memcached: no process found
root@ubuntu:~#

killall 命令竟然找不到 bt_uinfo_memcached 进程? 上面 ps 命令是列出来了的 。换 pkill 试试,还是不行

1
2
3
4
5
6
7
8
root@ubuntu:~# pkill bt_uinfo_memcached
root@ubuntu:~#
root@ubuntu:~# ps -ef |grep bt_uinfo_memcached
root 17723 23103 0 14:19 pts/2 00:00:00 grep --color=auto bt_uinfo_memcached
root 26195 1 0 12:43 ? 00:00:36 ./bt_uinfo_memcached -p 20211 -u root -l 0.0.0.0 -m 3072 -d
root 26236 1 0 12:43 ? 00:00:34 ./bt_uinfo_memcached -p 20311 -u root -l 0.0.0.0 -m 3072 -d
root 26586 1 1 12:43 ? 00:01:22 ./bt_uinfo_memcached -p 20411 -u root -l 0.0.0.0 -m 3072 -d
root@ubuntu:~#

甚至连 ps 也有问题,当 -C(command) 选项的参数值超过15个字符时,实际上是会匹配到其他的进程

1
2
3
4
5
6
7
8
9
10
11
linbobo@ubuntu:~$ ps -C bt_uinfo_memcachecd
PID TTY TIME CMD
26195 ? 00:01:44 bt_uinfo_memcac
26236 ? 00:01:41 bt_uinfo_memcac
26586 ? 00:03:23 bt_uinfo_memcac
linbobo@ubuntu:~$ ps -C bt_uinfo_memcachecd123456
PID TTY TIME CMD
26195 ? 00:01:44 bt_uinfo_memcac
26236 ? 00:01:41 bt_uinfo_memcac
26586 ? 00:03:23 bt_uinfo_memcac
linbobo@ubuntu:~$

为什么会这样呢? 通过 strace 命令可以找到原因

1
2
3
4
5
6
7
8
9
10
11
12
root@ubuntu:~# strace -e trace=file pkill bt_uinfo_memcached 2>&1 | grep open | tail
open("/proc/31713/status", O_RDONLY) = 4
open("/proc/31713/cmdline", O_RDONLY) = 4
open("/proc/31716/status", O_RDONLY) = 4
open("/proc/31716/cmdline", O_RDONLY) = 4
open("/proc/31717/status", O_RDONLY) = 4
open("/proc/31717/cmdline", O_RDONLY) = 4
open("/proc/31720/status", O_RDONLY) = 4
open("/proc/31720/cmdline", O_RDONLY) = 4
open("/proc/31721/status", O_RDONLY) = 4
open("/proc/31721/cmdline", O_RDONLY) = 4
root@ubuntu:~#

pkill 命令检查的是 /proc/ 下面的 pid 目录的 cmdline 文件和 status 文件。我们找其中一个 bt_uinfo_memcached 进程 ( 26195 ) 看一下,

1
2
3
4
5
6
7
root@ubuntu:~# cat /proc/26195/cmdline | tr \'\0\' \' \'
./bt_uinfo_memcached -p 20211 -u root -l 0.0.0.0 -m 3072 -d root@ubuntu:~#
root@ubuntu:~#
root@ubuntu:~# cat /proc/26195/status | tr \'\0\' \' \'
Name: bt_uinfo_memcac
State: S (sleeping)
.....

可以看到 cmdline 是记录完整命令行的 (pgrep 默认是部分匹配),而 status 这个文件里面的 Name 字段的值是 bt_uinfo_memcac 而不是 bt_uinfo_memcached ,也就是被截断了(15个字符,OS 的限制) !!!
虽然 cmdline 文件里面记录的命令是正确的,但我估计 pgrep 会对比 cmdline 第一个字段和 status 文件的 Name 字段的值是否相同,如果不同则跳过,所以虽然 cmdline 是对的,但 pkill 并不杀死该进程
下面再来看 killall 命令的

1
2
3
4
5
6
7
8
9
10
11
12
linbobo@ubuntu:~$ strace -e trace=file killall bt_uinfo_memcached 2>&1 | grep open | tail
open("/proc/31705/stat", O_RDONLY) = 3
open("/proc/31708/stat", O_RDONLY) = 3
open("/proc/31709/stat", O_RDONLY) = 3
open("/proc/31712/stat", O_RDONLY) = 3
open("/proc/31713/stat", O_RDONLY) = 3
open("/proc/31716/stat", O_RDONLY) = 3
open("/proc/31717/stat", O_RDONLY) = 3
open("/proc/31720/stat", O_RDONLY) = 3
open("/proc/31721/stat", O_RDONLY) = 3
open("/proc/32553/stat", O_RDONLY) = 3
linbobo@ubuntu:~$

killall 命令跟 pkill(pgrep) 不同,它查看的不是 /proc/pid/{cmdline,status} 文件,而是另外一个文件 /proc/pid/stat ,这个文件的内容

1
2
3
4
linbobo@ubuntu:~$ cat /proc/26195/stat
26195 (bt_uinfo_memcac) S 1 26195 26195 0 -1 4202560 42735 0 0 0 3517 5339 0 0 20 0 6 0 293270594 475316224
36956 18446744073709551615 1 1 0 0 0 0 0 4097 2 18446744073709551615 0 0 17 9 0 0 0 0 0
linbobo@ubuntu:~$

可以看到也是一样被截断了,所以 killall 没杀死进程就是这个导致的。

把 killall 和 pkill 命令改为下面就可以了

1
2
3
4
5
linbobo@ubuntu:~$ pgrep bt_uinfo_memcac
26195
26236
26586
linbobo@ubuntu:~$

既然如此,那么有没有 可靠一点的命令呢? 有,那就是 pidof 命令 。pidof 命令除了查找 cmdline 和 stat 文件外,还查找了 /proc/pid/exe 这个symbol link

所以对于那些二进制名超过 15 个字符,甚至启动后改名的都可以找到, 最常见就是 myshard 的东东

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
open("26195/stat", O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1c95e9d000
read(4, "26195 (bt_uinfo_memcac) S 1 2619"..., 1024) = 251
close(4) = 0
munmap(0x7f1c95e9d000, 4096) = 0
open("26195/cmdline", O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1c95e9d000
read(4, "./bt_uinfo_memcached\0-p\00020211\0-u"..., 1024) = 60
close(4) = 0
munmap(0x7f1c95e9d000, 4096) = 0
stat("/proc/26195/exe", {st_mode=S_IFREG|0755, st_size=325966, ...}) = 0
open("26236/stat", O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1c95e9d000
read(4, "26236 (bt_uinfo_memcac) S 1 2623"..., 1024) = 250
close(4)
1
2
3
4
5
6
7
8
9
linbobo@ubuntu:~$ ps -ef |grep shard
linbobo 9741 9722 0 14:59 pts/0 00:00:00 grep --color=auto shard
root 27628 1 0 May02 ? 00:27:09 ./shard_2013_115_d
root 27732 1 0 May02 ? 00:16:17 ./shard_2013_116_d
linbobo@ubuntu:~$ pidof shard_2013_115_d
27628
linbobo@ubuntu:~$ sudo ls -l /proc/27628/exe
lrwxrwxrwx 1 root root 0 2013-05-29 16:00 /proc/27628/exe -> /home/dspeak/myshard/2013/room_1_0/bin/shard_d
linbobo@ubuntu:~$

    

<think>我们正在讨论的是adb命令中的`killall`。根据用户的要求,我们需要提供`adb killall`的用法示例。 注意:在标准的adb命令中,并没有直接名为`killall`的命令。但是,我们可以通过`adb shell`来执行设备上的`killall`命令(如果设备支持的话)。 在Android设备上,`killall`通常是一个可执行程序,用于通过进程名来杀死进程。它可能不是所有设备都预装,但很多设备(尤其是通过BusyBox提供了更多Unix工具的设备)支持。 因此,我们讨论的实际上是:通过`adb shell`来运行设备上的`killall`命令。 用法: ```bash adb shell killall [选项] <进程名> ``` 常见选项: - `-s SIGNAL` 或 `--signal SIGNAL`:发送指定的信号(如9代表SIGKILL) - `-q`:安静模式,不输出错误信息 - `-v`:详细模式,显示更多信息 示例: 1. 杀死名为`com.example.app`的进程: ```bash adb shell killall com.example.app ``` 2. 强制杀死进程(发送SIGKILL信号): ```bash adb shell killall -9 com.example.app ``` 3. 杀死所有名为`my_process`的进程(如果有多个): ```bash adb shell killall my_process ``` 注意: - 需要设备支持`killall`命令(通常通过BusyBox提供)。如果设备没有`killall`,可以尝试安装BusyBox。 - 需要root权限才能杀死其他用户的进程(除非进程属于当前用户)。 替代方法:如果设备没有`killall`,可以使用`adb shell pkill`或`adb shell am kill`(针对应用包名)等命令。 例如,使用`am kill`杀死应用: ```bash adb shell am force-stop com.example.app ``` 或者使用`pkill`(如果支持): ```bash adb shell pkill com.example.app ``` 因此,虽然`adb killall`不是一个直接的adb命令,但我们可以通过`adb shell killall`来使用设备上的`killall`功能。 相关问题: 1. 如何在Android设备上安装BusyBox? 2. 如何通过包名杀死Android应用? 3. 如何通过进程名查找进程ID(PID)? 4. 在没有root权限的情况下,如何杀死后台进程?</think>### ADB `killall` 命令详解 `killall` 是通过 ADB 强制终止 Android 设备上指定进程的命令,常用于调试或解决进程卡死问题。需通过 `adb shell` 执行,完整用法如下: --- #### 📌 **基础语法** ```bash adb shell killall [选项] <进程名> ``` - **常用选项**: `-l` 列出所有信号名称 `-s SIGNAL` 发送指定信号(默认 SIGTERM) `-v` 显示详细信息 `-q` 安静模式(不报错) - **信号类型**: `SIGTERM` (15):优雅终止(默认) `SIGKILL` (9):强制终止(最常用) --- #### 🔧 **常用示例** 1. **终止指定进程**(如浏览器): ```bash adb shell killall com.android.chrome # 包名形式 adb shell killall chrome # 进程名形式 ``` 2. **强制终止卡死进程**(发送 SIGKILL): ```bash adb shell killall -9 com.example.app ``` 3. **批量终止同类型进程**(如后台服务): ```bash adb shell killall -v service_provider # -v 显示终止详情 ``` 4. **终止系统核心进程**(需 root): ```bash adb root adb shell killall -9 system_server # 重启系统服务 ``` --- #### ⚠️ **注意事项** 1. **权限要求**: - 终止用户应用:需 USB 调试权限 - 终止系统进程:**必须 root** 设备 - 部分厂商进程受保护(如 `systemui`) 2. **进程名规则**: - 使用完整包名(`com.package.name`) - 或通过 `adb shell ps` 查询进程名 ```bash adb shell ps | grep "chrome" # 查找浏览器进程 ``` 3. **风险提示**: - 强制终止系统进程可能导致设备重启 - 误杀关键进程(如 `zygote`)会触发系统崩溃 --- #### 💡 **替代方案** 1. **通过 `am` 命令终止应用**(无需 root): ```bash adb shell am force-stop com.android.chrome ``` 2. **通过进程 ID 终止**: ```bash # 获取 PID pid=$(adb shell pidof com.example.app) # 终止进程 adb shell kill -9 $pid ``` 3. **重启系统服务**(替代终止 `system_server`): ```bash adb shell stop && adb shell start ``` --- #### 📚 **相关问题** 1. 如何通过 ADB 查看 Android 设备当前所有运行中的进程?[^1] 2. `killall -9` `am force-stop` 命令有何本质区别? 3. 终止系统进程 `zygote` 会造成什么后果? 4. 如何防止关键进程被意外终止? 5. 设备无 root 权限时,如何强制重启卡死的系统服务? > 提示:更多进程管理命令可参考: > ```bash > adb shell ps --help # 查看进程管理帮助 [^1] > ``` [^1]: ADB 基础命令解析,涵盖进程管理操作指南 [^2]: Android 系统进程层级与权限管理机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值