Linux下如何获取/bin/bash进程正在执行的命令?
这个问题问得很实际!其实完全有办法获取bash进程当前正在跑的命令,咱们来一步步拆解清楚:
先搞懂核心原因
为啥你看/proc/[pid]/cmdline只看到/bin/bash?因为当你在交互式bash里敲命令时,外部命令都是bash fork出的子进程来执行的,bash本身的进程启动参数就是/bin/bash,所以它的cmdline不会跟着子命令变。而像ssh这种进程,它本身就是独立的执行体,所以ps能直接读出它的完整命令参数。
方法1:直接看bash的子进程(最常用)
既然外部命令都是bash的子进程,那咱们直接找它的子进程就行:
用
pstree看进程树,一目了然:pstree -p <你的bash进程PID>比如bash的PID是1234,执行后会看到类似这样的输出:
bash(1234)───ssh(5678)后面的
ssh(5678)就是bash当前正在运行的命令。用
ps精准过滤子进程:ps -o pid,ppid,cmd --ppid <你的bash进程PID>这个命令会列出所有父进程是目标bash的进程,
cmd列就是你要找的命令。
方法2:对付内置命令(比如cd、echo这类)
如果bash正在执行内置命令(不需要fork子进程的那种),上面的方法就抓不到了。这时候可以用strace跟踪bash的系统调用,或者用gdb看它的内部变量:
用strace跟踪
strace -e execve -p <你的bash进程PID>
当bash执行外部命令时,你会看到类似这样的输出,直接就能拿到命令:
execve("/usr/bin/ssh", ["ssh", "name@127.0.0.1"], 0x7ffcxxxxxx /* 50 vars */) = 0
对于内置命令,strace可能捕不到execve,但可以试试跟踪其他调用,不过更直接的是用gdb。
用gdb看bash内部变量
bash有个内部变量$BASH_COMMAND,专门存当前正在执行的命令。你可以用gdb附到bash进程上查看:
gdb -p <你的bash进程PID>
进入gdb后,敲这行命令:
p (char *) bash_command
就能输出当前的命令,比如:
$1 = 0x55xxxxxx "ssh name@127.0.0.1"
注意:有些系统的bash可能没编译调试符号,这方法就用不了,但大多数主流发行版的bash都支持。
写个自动识别的脚本
我给你写了个简单的脚本,输入bash的PID就能自动找当前命令:
#!/bin/bash if [ -z "$1" ]; then echo "用法:$0 <bash进程PID>" exit 1 fi BASH_PID=$1 # 先检查有没有子进程(外部命令) CHILD_CMD=$(ps -o cmd --no-header --ppid "$BASH_PID") if [ -n "$CHILD_CMD" ]; then echo "Bash进程 $BASH_PID 正在运行:$CHILD_CMD" else # 没有子进程,尝试用gdb查内置命令 echo "正在检查内置命令(需要gdb权限)..." gdb -p "$BASH_PID" -ex 'p (char *) bash_command' -batch 2>/dev/null | grep -E '".*"' | sed 's/^.*"\(.*\)".*$/\1/' fi
使用的时候直接运行:
./check_bash_cmd.sh <你的bash进程PID>
注意:运行这个脚本需要足够权限(比如root),因为附到其他用户的进程需要权限哦。
内容的提问来源于stack exchange,提问作者redcore

