如何在Shell脚本中获取timeout与tcpdump的两个Linux进程ID
获取timeout和tcpdump的进程ID的两种实现方法
方法一:利用GNU timeout的父子进程关系获取PID
原脚本中你拿到的是tcpdump的PID,可能是因为使用的timeout版本(比如busybox的timeout)默认会exec替换自身进程为tcpdump,导致两者PID相同。如果是GNU timeout,默认不会这么做,此时可以通过以下步骤获取两个PID:
#!/bin/bash TIMEOUT_DURATION=3600 TIMEOUT=${v_TIMEOUT:-$TIMEOUT_DURATION} FILTER=${v_FILTER:-} # 过滤器含特殊符号时需URI编码 FILENAME=$(date +%s).log # 启动timeout后台进程,捕获timeout的PID timeout "$TIMEOUT" tcpdump -i eth0 -w "$FILENAME" $FILTER > /dev/null 2>&1 & TIMEOUT_PID=$! # 短暂等待tcpdump启动完成,避免pgrep找不到进程 sleep 0.1 # 通过timeout进程的PID查找其子进程(tcpdump)的PID TCPDUMP_PID=$(pgrep -P "$TIMEOUT_PID") echo "TIMEOUT_PID=$TIMEOUT_PID" echo "TCPDUMP_PID=$TCPDUMP_PID"
说明:
pgrep -P $TIMEOUT_PID会列出所有父进程ID为$TIMEOUT_PID的子进程,这里对应的就是tcpdump进程- 加入
sleep 0.1是为了确保tcpdump完成启动初始化,避免因进程未就绪导致pgrep返回空
方法二:手动实现超时逻辑(通用兼容版本)
如果你的timeout版本存在进程替换问题,或者需要更通用的实现,可以自己用sleep和后台进程实现超时监控,这样能明确获取两个进程的PID:
#!/bin/bash TIMEOUT_DURATION=3600 TIMEOUT=${v_TIMEOUT:-$TIMEOUT_DURATION} FILTER=${v_FILTER:-} FILENAME=$(date +%s).log # 启动tcpdump后台进程,捕获其PID tcpdump -i eth0 -w "$FILENAME" $FILTER > /dev/null 2>&1 & TCPDUMP_PID=$! # 启动一个后台监控进程,到达超时时间后杀死tcpdump ( sleep "$TIMEOUT" && kill "$TCPDUMP_PID" 2>/dev/null ) & TIMEOUT_MONITOR_PID=$! echo "TCPDUMP_PID=$TCPDUMP_PID" echo "TIMEOUT_MONITOR_PID=$TIMEOUT_MONITOR_PID"
说明:
- 这里的
TIMEOUT_MONITOR_PID是负责超时逻辑的后台进程PID,你可以通过杀死它来取消超时机制 - 如果提前手动杀死tcpdump,监控进程执行
kill时会因进程不存在报错,2>/dev/null用于屏蔽该无意义错误
内容的提问来源于stack exchange,提问作者Yogi
相关产品推荐
相关产品推荐

