Sổ tay kỹ thuật

Regex cho log và config mạng – IP, MAC, interface

cheatsheet#regex#python#linux· cập nhật 2026-11-06

Tra nhanh regex hay dùng để lọc IP, prefix, MAC, interface IOS XR/Junos, timestamp và sự kiện BGP trong log/config, kèm cú pháp grep -E, grep -P và Python re.

Sửa trang này
Mục lục

Mọi pattern dưới đây đã test bằng Python re và GNU grep 3.7. Lưu ý: grep -E (ERE) không hiểu \d, (?:...), lookahead, nên viết [0-9] và (...). Cần \d, \K, lookaround thì dùng grep -P. Muốn kiểm tra IP hợp lệ thì dùng module ipaddress thay vì regex.

Cú pháp cơ bản

Ký hiệu Nghĩa Có trong grep -E?
. * + ? {m,n} Ký tự bất kỳ, lặp 0+, 1+, 0-1, m đến n lần có
^ $ Đầu, cuối dòng có
[0-9a-f] [^ ] Lớp ký tự, phủ định có
(a|b) Nhóm, hoặc có
\b Ranh giới từ có (GNU)
[[:space:]] [[:digit:]] Lớp POSIX có
\d \s \w Số, khoảng trắng, chữ/số/_ không, dùng -P
(?:...) Nhóm không bắt không, dùng -P
(?=...) (?<!...) Lookahead, lookbehind không, dùng -P
*? +? Lặp non-greedy không, dùng -P

Địa chỉ IP, prefix

Mục đích Regex (Python / grep -P)
IPv4 dạng lỏng (bắt cả 999.1.1.1) \b(?:\d{1,3}\.){3}\d{1,3}\b
IPv4 chặt (0-255 mỗi octet) \b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b
IPv4 prefix /0-/32 \b(?:\d{1,3}\.){3}\d{1,3}/(?:3[0-2]|[12]?\d)\b
Ứng viên IPv6 (rồi kiểm bằng ipaddress) (?<![\w:])(?:[0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}(?![\w:])
Mục đích Lệnh grep -E
Lấy mọi IPv4 trong log grep -Eo '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' app.log
Top IP xuất hiện nhiều nhất grep -Eo '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' app.log | sort | uniq -c | sort -rn | head
Lấy prefix có mask grep -Eo '\b([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}\b' config.txt
Che IP trước khi gửi log cho người khác sed -E 's/\b([0-9]{1,3}\.){3}[0-9]{1,3}\b/x.x.x.x/g' app.log

MAC address

Mục đích Regex
Dạng 00:1a:2b:3c:4d:5e hoặc 00-1A-... \b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b
Dạng Cisco 001a.2b3c.4d5e \b(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4}\b
grep -E, không phân biệt hoa thường grep -Eio '\b([0-9a-f]{2}[:-]){5}[0-9a-f]{2}\b' arp.txt
grep -E dạng Cisco grep -Eio '\b([0-9a-f]{4}\.){2}[0-9a-f]{4}\b' mac-table.txt

Interface

Mục đích Regex
IOS XR (Gi/TenGigE/HundredGigE/Bundle-Ether/Loopback, có sub-if) \b(?:(?:Gigabit|TenGig|TwentyFiveGig|FortyGig|HundredGig|FourHundredGig)E(?:thernet)?|Bundle-Ether|Loopback)\d+(?:/\d+)*(?:\.\d+)?\b
Junos (ge-0/0/0.100, et-0/0/0:1, ae0.0, lo0, irb.100) \b(?:(?:ge|xe|et|mge)-\d+/\d+/\d+(?::\d+)?|ae\d+|lo0|irb)(?:\.\d+)?\b
grep -E nhanh cho IOS XR grep -Eo '(TenGigE|HundredGigE|GigabitEthernet|Bundle-Ether)[0-9/.]+' run.txt

Log, timestamp, sự kiện

Mục đích Regex / lệnh
Timestamp syslog Nov 6 08:01:02 ^[A-Z][a-z]{2} [ \d]\d \d{2}:\d{2}:\d{2}
Timestamp ISO 8601 \d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}
Neighbor BGP đổi trạng thái (IOS XR ADJCHANGE) neighbor (\S+) (Up|Down)
Chỉ lấy IP neighbor bị Down grep -Po 'neighbor \K\S+(?= Down)' syslog
Đếm số lần flap grep -Ec 'ADJCHANGE.*Down' syslog
Tách cặp key=value (value có thể trong ngoặc kép) (\w+)=("[^"]*"|\S+)
Version dạng v7.11.2 \bv?(\d+)\.(\d+)\.(\d+)\b

Config và giá trị

Mục đích Regex / lệnh
Bỏ dòng trống và comment (#, !) grep -Ev '^[[:space:]]*(#|!|$)' config.txt
VLAN ID hợp lệ 1-4094 (cả chuỗi) ^(?:409[0-4]|40[0-8]\d|[1-3]\d{3}|[1-9]\d{0,2})$
ASN 16-bit private 64512-65534 (cả chuỗi) ^(?:6451[2-9]|645[2-9]\d|64[6-9]\d\d|65[0-4]\d\d|655[0-2]\d|6553[0-4])$
Xem khối config quanh một dòng grep -E -B2 -A10 '^interface Bundle-Ether100' run.txt

Python re

parse_log.py
import ipaddress
import re
 
IPV4 = re.compile(r"\b(?:\d{1,3}\.){3}\d{1,3}\b")
BGP_ADJ = re.compile(r"neighbor (?P<peer>\S+) (?P<state>Up|Down)")
 
 
def is_ip(s: str) -> bool:
    try:
        ipaddress.ip_address(s)
        return True
    except ValueError:
        return False
 
 
line = "%ROUTING-BGP-5-ADJCHANGE : neighbor 198.51.100.1 Down - Hold timer expired, peer 999.1.1.1"
 
m = BGP_ADJ.search(line)
if m:
    print(m["peer"], m["state"])  # 198.51.100.1 Down
 
# regex lỏng để tìm, ipaddress để kiểm tra
print([s for s in IPV4.findall(line) if is_ip(s)])  # ['198.51.100.1']
Hàm Dùng khi
re.search(p, s) Tìm match đầu tiên ở bất kỳ đâu
re.match(p, s) / re.fullmatch(p, s) Match từ đầu chuỗi / toàn bộ chuỗi
re.findall(p, s) Lấy tất cả (trả tuple nếu có nhiều nhóm)
re.finditer(p, s) Duyệt từng match, lấy được m.start(), m["name"]
re.sub(p, repl, s) Thay thế, repl dùng \1 hoặc \g<name>
re.compile(p, re.I | re.M) Biên dịch một lần, cờ không phân biệt hoa thường / đa dòng

Luôn viết pattern Python dạng raw string r"..." để \b, \d không bị Python hiểu thành escape. Trong shell, bọc pattern bằng nháy đơn '...'.