
本文介绍如何使用正则表达式从 Linux /proc/[pid]/maps 类文本中精准提取每个已命名共享库(如 /lib/libc-2.31.so)所对应的第一段内存地址范围(即首次出现的 start-end 地址)。
本文介绍如何使用正则表达式从 linux `/proc/[pid]/maps` 类文本中精准提取每个已命名共享库(如 `/lib/libc-2.31.so`)所对应的第一段内存地址范围(即首次出现的 `start-end` 地址)。
在 Linux 进程内存映射分析中,/proc/[pid]/maps 输出的每行包含内存段起始地址、权限、偏移、设备号、inode 及映射文件路径。目标是:对每个有实际文件路径的条目(如 /bin/busybox.nosuid),提取其首次出现时的地址范围(例如 7d60f000-7d67b000),而非后续同名文件的其他映射段(如 r--p 或 rw-p 段)。
这完全可通过正则表达式实现,关键在于锚定行首、精确匹配地址格式、严格限定路径结构,并确保仅捕获首个匹配项。推荐使用以下正则表达式:
^([a-f0-9]{8}-[a-f0-9]{8})\s+[rwxp-]{4}\s+[a-f0-9]{8}\s+[a-f0-9]{2}:[a-f0-9]{2}\s+\d+\s+(\/(?:bin|lib|usr\/lib)(?:\/[^[:space:]]+)+)$✅ 说明与优势:
- ^([a-f0-9]{8}-[a-f0-9]{8}):捕获 8 位十六进制起始地址 + - + 8 位结束地址(如 b3dfb000-b3ebe000),作为 Group 1;
- \s+[rwxp-]{4}:匹配 4 字符权限字段(如 r-xp),支持空格冗余;
- \s+[a-f0-9]{8}\s+[a-f0-9]{2}:[a-f0-9]{2}\s+\d+:匹配 offset、dev 和 inode,确保上下文合法性;
- \s+(\/(?:bin|lib|usr\/lib)(?:\/[^[:space:]]+)+):匹配以 /bin/、/lib/ 或 /usr/lib/ 开头的完整路径(支持多级子目录与版本号,如 /usr/lib/libcrashlog.so.0.0.0),作为 Group 2;
- 行首 ^ 与行尾隐式(配合多行模式 m)确保单行匹配,避免跨行误捕。
? 使用示例(Python):
import re
text = """7d60f000-7d67b000 r-xp 00000000 fb:00 11 /bin/busybox.nosuid
7d68b000-7d68c000 r--p 0006c000 fb:00 11 /bin/busybox.nosuid
b3dfb000-b3ebe000 r-xp 00000000 fb:00 1636 /lib/libc-2.31.so
..."""
pattern = r'^([a-f0-9]{8}-[a-f0-9]{8})\s+[rwxp-]{4}\s+[a-f0-9]{8}\s+[a-f0-9]{2}:[a-f0-9]{2}\s+\d+\s+(\/(?:bin|lib|usr\/lib)(?:\/[^[:space:]]+)+)$'
matches = {}
for line in text.strip().split('\n'):
m = re.match(pattern, line)
if m:
addr, path = m.groups()
# 仅保留首次出现的路径对应地址(自动去重)
if path not in matches:
matches[path] = addr
for path, addr in matches.items():
print(f"{path} → {addr}")⚠️ 注意事项:
- 必须启用 multiline 模式(re.MULTILINE 或 (?m)),否则 ^ 无法匹配每行开头;
- 路径部分使用 (?:\/[^[:space:]]+)+ 替代原答案中较脆弱的 [^.]+,可正确处理含多个点的文件名(如 .so.0.0.0);
- 若需兼容更广路径(如 /opt/xxx),可扩展非捕获组:(?:bin|lib|usr\/lib|opt\/[^[:space:]]+);
- 实际生产中建议结合 awk '$6 ~ /^\/.*$/ {print $1, $6}' 做预过滤,再用 regex 精炼,兼顾性能与健壮性。
该方案简洁、可移植性强,适用于 Shell、Python、Perl 等支持 PCRE/POSIX 正则的环境,是解析进程内存映射的标准实践之一。

















