如何使用萬用字元 grep 十六進制模式?
我正在嘗試在文件中查找十六進制模式的偏移量。這適用於一個特定的值:
$ grep -obUaP -m1 "\x00\x50\x53\x46\x01\x01\x00\x00\x34\x01\x00\x00" file.bin 3088:PSF4
但是,此模式包含一些會更改的字節,因此我需要在我的 grep 中包含萬用字元。我不知道該怎麼做。到目前為止,這是我嘗試過的所有內容:
\x.., \x., ..,
我能想到的每一個相似的形式都不匹配\x[0-9][0-9]
不匹配\x.*
不匹配- just
.*
(ie.,\x00.*\x01
)確實匹配,但它是貪婪的並且比模式匹配更多可能忽略了一些愚蠢的事情,但我在這裡撞到了一堵牆。
如何在十六進制中指定萬用字元,或者至少在使用 grep 和 perl-regex 搜尋十六進制時如何?
grep -P '\xAB'
不尋找十六進製字元。沒有像十六進製字元這樣的東西。\xAB
是 PCRE語法,用於匹配以十六進製表示的程式碼點值為 0xAB(十進制為 171)的字元。這裡的程式碼點是使用 UTF-8 的語言環境中的Unicode程式碼點和使用單字節字元集的語言環境中的字節值(GNU
grep -P
不支持 UTF-8 以外的多字節字元集)。因此
\xAB
將匹配 UTF-8 語言環境中的 U+00AB 字元 («)(該字元在 2 個字節上編碼:0xc2 和 0xab)和單字節語言環境中的 0xAB 字節(例如,它Ћ
表示使用 iso8859-5 字元集的語言環境)。如果你想匹配字節值,你應該確保語言環境使用單字節字元集,
C
語言環境可能是你最好的選擇。LC_ALL=C grep -P '\xAB'
匹配 0xAB (171) 字節,無論它在任何字元集中表示什麼字元。
同樣,要匹配任何單個字節,您可以使用
.
(假設 C 語言環境或任何每個字元集單個字節的本地)。要匹配一個範圍內的字節值,正如@Angle115 已經說過的那樣:(
[\x01-\x45]
這裡是字節值 1 到 0x45 / 69)但請記住,
grep
匹配文本行¹ 的**內容,因此它永遠不會找到作為行分隔符的換行符,並且無論語言環境如何,始終具有值 0x0A²(十進制為 10)。因此
LC_ALL=C grep -P '\x23.\xab'
將匹配 3 個字節的序列,第一個字節的值為 0x23,第二個字節的值為除 0xA 之外的任何值,第三個字節的值為 0xAB。為了能夠搜尋具有任意值(包括 0xA)的字節,您需要將整個輸入視為一個整體,而不是像這樣一次處理一行或以 nul 分隔的記錄
grep
。為此,您可以將
pcregrep
其-M
(multiline) 選項與(?s)
標誌一起使用(換行不被 特殊處理.
)或perl
與它的 slurp 模式一起使用:LC_ALL=C pcregrep --file-offsets -Ma '(?s)\x23.\xab' < file
(
pcregrep
沒有-b
選項,--file-offsets
列印偏移量和長度可能是最接近的)。perl -l -0777 -ne 'print "$-[0]:$_" while /\x23.\xab/gs' < file
或者:
perl -l -0777 -ne 'print $-[0] if /\x23.\xab/s' < file
只列印第一個匹配的字節偏移量。
perl
將整個文件載入到記憶體中,pcregrep
但內部限制可能會阻止您處理 0xA 字節相距很遠的文件。¹ 或 NUL 分隔的記錄與
--null
/-z
¹ 在基於 ASCII 的系統上。我什至不知道 libpcre 是否曾經移植到 EBCDIC 系統,我懷疑現在很多人會遇到其中的一些。