如何修改Bash脚本以获取重复Python进程的完整脚本路径
问题描述
我在树莓派上编写Bash脚本,用来查找重复运行的Python(排除Python3)进程。目前脚本能识别重复进程并获取PID,但无法正确获取脚本完整路径,反而把参数-u当成了脚本路径。
现有运行进程示例
bms 9189 0.0 0.1 10592 7248 ? S 09:11 0:00 python -u /home/bms/Dev/APItest/APItest.py bms 9192 0.0 0.1 10592 7188 ? S 09:12 0:00 python -u /home/bms/Dev/APItest/APItest.py
当前脚本输出
Found 2 instances of -u: PID: 9189, Script path: -u PID: 9192, Script path: -u Finished checking for duplicate Python scripts.
期望输出
PID: 9189, Script path: /home/bms/Dev/APItest/APItest.py PID: 9192, Script path: /home/bms/Dev/APItest/APItest.py
现有脚本
#!/bin/bash # Get a list of all running Python processes PYTHON_PROCESSES=$(ps aux | grep '[p]ython' | grep -v 'python3' | awk '{print $2}') # Loop through the Python processes and count how many times each script is running declare -A SCRIPT_COUNTS declare -A SCRIPT_PIDS for PID in $PYTHON_PROCESSES; do CMD=$(ps -p $PID -o comm=) if [ "$CMD" == "python" ]; then SCRIPT_ARGS=$(ps -p $PID -o args=) SCRIPT_PATH=$(echo "$SCRIPT_ARGS" | awk '{print $2}') SCRIPT_NAME=${SCRIPT_PATH##*/} if [ -z "${SCRIPT_COUNTS[$SCRIPT_NAME]}" ]; then SCRIPT_COUNTS[$SCRIPT_NAME]=0 fi ((SCRIPT_COUNTS[$SCRIPT_NAME]++)) if [ -z "${SCRIPT_PIDS[$SCRIPT_NAME]}" ]; then SCRIPT_PIDS[$SCRIPT_NAME]="" fi SCRIPT_PIDS[$SCRIPT_NAME]="${SCRIPT_PIDS[$SCRIPT_NAME]}$PID:$SCRIPT_PATH " fi done # Loop through the script counts and print the names of any scripts that have duplicates for SCRIPT_NAME in "${!SCRIPT_COUNTS[@]}"; do COUNT=${SCRIPT_COUNTS[$SCRIPT_NAME]} if [ $COUNT -gt 1 ]; then echo "Found $COUNT instances of $SCRIPT_NAME:" for INSTANCE in ${SCRIPT_PIDS[$SCRIPT_NAME]}; do PID=${INSTANCE%%:*} SCRIPT_PATH=${INSTANCE#*:} echo "PID: $PID, Script path: $SCRIPT_PATH" done fi done echo "Finished checking for duplicate Python scripts."
解决方案
问题核心是脚本路径提取逻辑错误:你固定取了args的第2个字段,但当Python命令带有-u这类参数时,脚本路径实际是第3个(或更靠后)的字段。同时原脚本用错误的路径片段作为统计重复的键,导致识别错误。
核心修改点
- 替换脚本路径提取逻辑:不再固定取某个位置的字段,而是从命令参数中匹配实际的Python脚本路径(比如以
/开头的路径,或带有.py后缀的文件)。 - 调整重复统计的键:改用完整的脚本路径作为统计键,确保同一脚本的不同实例被正确归类。
修改后的完整脚本
#!/bin/bash # Get a list of all running Python processes PYTHON_PROCESSES=$(ps aux | grep '[p]ython' | grep -v 'python3' | awk '{print $2}') # Loop through the Python processes and count how many times each script is running declare -A SCRIPT_COUNTS declare -A SCRIPT_PIDS for PID in $PYTHON_PROCESSES; do CMD=$(ps -p $PID -o comm=) if [ "$CMD" == "python" ]; then SCRIPT_ARGS=$(ps -p $PID -o args=) # 提取脚本路径:遍历参数,找到第一个以/开头的路径(适配带参数的情况) SCRIPT_PATH=$(echo "$SCRIPT_ARGS" | awk '{for(i=1;i<=NF;i++) if(substr($i,1,1)=="/") {print $i; exit}}') # 若脚本用相对路径,可改用匹配.py后缀的逻辑: # SCRIPT_PATH=$(echo "$SCRIPT_ARGS" | awk '{for(i=1;i<=NF;i++) if($i ~ /\.py$/) {print $i; exit}}') # 跳过无有效脚本路径的进程(如交互式Python会话) if [ -z "$SCRIPT_PATH" ]; then continue fi # 用完整脚本路径作为统计键 if [ -z "${SCRIPT_COUNTS[$SCRIPT_PATH]}" ]; then SCRIPT_COUNTS[$SCRIPT_PATH]=0 fi ((SCRIPT_COUNTS[$SCRIPT_PATH]++)) # 存储对应PID if [ -z "${SCRIPT_PIDS[$SCRIPT_PATH]}" ]; then SCRIPT_PIDS[$SCRIPT_PATH]="" fi SCRIPT_PIDS[$SCRIPT_PATH]="${SCRIPT_PIDS[$SCRIPT_PATH]}$PID " fi done # 输出重复进程的PID和脚本路径 for SCRIPT_PATH in "${!SCRIPT_COUNTS[@]}"; do COUNT=${SCRIPT_COUNTS[$SCRIPT_PATH]} if [ $COUNT -gt 1 ]; then for PID in ${SCRIPT_PIDS[$SCRIPT_PATH]}; do echo "PID: $PID, Script path: $SCRIPT_PATH" done fi done
修改说明
- 路径提取逻辑:通过
awk遍历所有命令参数,找到第一个绝对路径(以/开头),完美适配带有-u等参数的场景;如果你的脚本会用相对路径运行,可切换为匹配.py后缀的逻辑。 - 统计键优化:用完整脚本路径作为统计和存储PID的键,确保同一脚本的不同实例被正确识别为重复。
- 无效进程过滤:跳过没有有效脚本路径的进程(比如直接运行
python进入交互模式的情况),避免无效统计。 - 输出简化:直接输出你需要的PID和路径格式,去掉了原脚本中多余的提示信息,若需保留可自行添加。
内容的提问来源于stack exchange,提问作者FeliceM
相关产品推荐
相关产品推荐

