在BASH管道中,能否从右侧命令内部获取左侧命令的PID?
答案
结论
可以实现,以下是Linux环境下的具体方案:
实现原理
Linux系统中所有管道都会分配唯一的inode编号,管道左侧进程的标准输出(文件描述符为1)和右侧进程的标准输入(文件描述符为0)指向同一个inode的管道文件。我们可以通过/proc文件系统匹配对应inode找到上游进程PID。
代码实现
你可以在b.sh(也就是你的cachepoint脚本)中加入以下代码获取左侧进程PID:
#!/bin/bash # 获取当前进程标准输入对应的管道inode pipe_inode=$(readlink /proc/self/fd/0 | sed -n 's/^pipe:\[\([0-9]\+\)\]$/\1/p') # 遍历所有进程,找到标准输出对应上述inode的进程PID LEFT_PID=$(find /proc -maxdepth 2 -type l -path "/proc/[0-9]*/fd/1" -lname "pipe:[$pipe_inode]" | cut -d'/' -f3 | head -n1) # 测试输出 echo $LEFT_PID # 后续你的cachepoint逻辑 cat
多级管道适配
如果你的cachepoint处于多级管道中(比如a.sh | b.sh | cachepoint | c.sh),上述代码默认拿到的是直接上游b.sh的PID,如果你需要获取整条上游管道的所有命令,可以递归查询:
# 递归获取所有上游进程PID get_all_upstream_pids() { local current_pid=$1 local pids=() while true; do # 获取当前进程标准输入的管道inode local inode=$(readlink /proc/$current_pid/fd/0 2>/dev/null | sed -n 's/^pipe:\[\([0-9]\+\)\]$/\1/p') if [ -z "$inode" ]; then break fi # 查找上游进程 local upstream_pid=$(find /proc -maxdepth 2 -type l -path "/proc/[0-9]*/fd/1" -lname "pipe:[$inode]" | cut -d'/' -f3 | head -n1 2>/dev/null) if [ -z "$upstream_pid" ] || [ "$upstream_pid" = "$current_pid" ]; then break fi pids+=($upstream_pid) current_pid=$upstream_pid done echo ${pids[@]} } # 调用示例,第一个参数是当前cachepoint的PID upstream_pids=($(get_all_upstream_pids $$)) # 读取所有上游进程的启动命令,用于生成哈希 for pid in ${upstream_pids[@]}; do cmd=$(tr '\0' ' ' < /proc/$pid/cmdline) # 把cmd加入哈希计算即可 done
注意事项
- 该方案依赖Linux特有的
/proc文件系统,不适用于macOS、BSD等其他类Unix系统。 - 你需要提前终止上游进程时,直接关闭当前进程的标准输入即可,上游进程写入管道时会收到
SIGPIPE信号自动退出,无需额外发送信号。 - 生成缓存哈希时,建议把上游所有命令的完整参数、当前工作目录等信息也加入计算,避免不同上下文的相同命令误命中缓存。
内容的提问来源于stack exchange,提问作者Seán Healy
相关产品推荐
相关产品推荐

