ProgramingTip

바이너리 파일 및 UTF16 grepping

bestdevel 2020. 12. 1. 19:09
반응형

바이너리 파일 및 UTF16 grepping


Standard grep/ pcregrepetc.는 ASCII 또는 UTF8 데이터 용 바이너리 파일과 함께 편리하게 사용할 수 있습니다. UTF16도 시도해 볼 수있는 방법이 있습니다 (동시에 간단한 대신 수행 할 것)?

내가 원하는 데이터는 어쨌든 모두 ASCII입니다.

의미 론적으로 수행 할 수있는 방법은 없지만 명령 줄에서 쉽게 사용할 수 있지만 점을 제외하면 00은 트릭을 수행해야합니다.


가장 쉬운 방법은 텍스트 파일을 utf-8로 변환하고 grep으로 파이프하는 것입니다.

iconv -f utf-16 -t utf-8 file.txt | grep query

나는 (내 쿼리를 utf-16으로 변환) 시도했지만 grep이 좋아하지 않을 것입니다. 엔디안과 관련이 확실한 생각이 확실하지 않습니다.

grep이 utf-16 인 쿼리를 utf-8 / ascii로 변환하는 것처럼 보입니다. 내가 시도한 것은 다음과 같습니다.

grep `echo -n query | iconv -f utf-8 -t utf-16 | sed 's/..//'` test.txt

test.txt가 utf-16 파일이면 작동하지 않지만 test.txt가 ascii이면 작동합니다. grep이 내 쿼리를 ascii로 변환하고 결함 만 내릴 수 있습니다.

편집 : 여기에 정말 미친 짓이 유용한 유용한 정보를 제공하지 않습니다.

hexdump -e '/1 "%02x"' test.txt | grep -P `echo -n Test | iconv -f utf-8 -t utf-16 | sed 's/..//' | hexdump -e '/1 "%02x"'`

어떻게 작동합니까? 파일을 16 진수로 변환합니다 (일반적으로 hexdump가 적용하는 추가 형식없이). 그것은 grep으로 파이프합니다. Grep은 쿼리 (줄 바꿈없이)를 utf-16으로 변환하는 iconv로 에코하여 구성된 쿼리를 사용합니다. 그런 다음 sed로 파이프되어 BOM (엔디안을 결정하는 데 사용되는 utf-16 파일의 처음 2 바이트)을 제거합니다. 그런 다음 쿼리와 입력이 동일하게 hexdump로 파이프됩니다.

불행히도 단일 일치가 전체 파일을 인쇄하게 될 생각합니다. 또한 바이너리 파일의 utf-16이 컴퓨터와 다른 엔디안에 저장되어 있으면 작동하지 않습니다.

EDIT2 : 알았어 !!!!

grep -P `echo -n "Test" | iconv -f utf-8 -t utf-16 | sed 's/..//' | hexdump -e '/1 "x%02x"' | sed 's/x/\\\\x/g'` test.txt

Test파일에서 16 진수 버전의 디렉토리 (utf-16)을 검색합니다.test.txt


검색 패키지에 null (00s)을 명시 적으로 포함 할 수 있고 null로 결과를 얻을 수 있으므로 출력을 파일로 리디렉션하여 합리적인 편집기로 보거나 sed를 통해 파이프를 통해 널을 대체하십시오. * .utf16.txt에서 "bar"를 검색하려는 광고 :

grep -Pa "b\x00a\x00r" *.utf16.txt | sed 's/\x00//g'

"-P"는 grep에게 \ x00이 널로 확장 할 수있는 Perl regexp 구문을 허용하도록 지시하고 -a는 유니 코드가 바이너리처럼 보인다는 사실을 무시 지시합니다.


https://www.splitbits.com/2015/11/11/tip-grep-and-unicode/ 에서 아래 솔루션이 나에게 가장 그렇다는 것을 알았습니다.

Grep은 유니 코드에서 잘 작동하지 않지만 해결 될 수 있습니다. 예를 들어, 통화면

Some Search Term

UTF-16 파일에서 정규식을 사용하여 각 문자의 첫 번째 바이트를 무시합니다.

S.o.m.e. .S.e.a.r.c.h. .T.e.r.m 

또한 grep에게 '-a'를 사용하여 파일을 텍스트로 처리 지시하면 최종 명령은 다음과 같습니다.

grep -a 'S.o.m.e. .S.e.a.r.c.h. .T.e.r.m' utf-16-file.txt

출력이 유니 코드를 Windows 표준을 사용합니다. 이것은 Cygwin에서 실행 중입니다.

$ regedit /e registry.data.out
$ file registry.data.out
registry.data.out: Little-endian **UTF-16 Unicode text**, with CRLF line terminators

$ sed 's/\x00//g' registry.data.out | egrep "192\.168"
"Port"="192.168.1.5"
"IPSubnetAddress"="192.168.189.0"
"IPSubnetAddress"="192.168.102.0"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Print\Monitors\Standard TCP/IP Port\Ports\192.168.1.5]
"HostName"="192.168.1.5"
"Port"="192.168.1.5"
"LocationInformation"="http://192.168.1.28:1215/"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"StandaloneDhcpAddress"="192.168.173.1"
"ScopeAddressBackup"="192.168.137.1"
"ScopeAddress"="192.168.137.1"
"DhcpIPAddress"="192.168.1.24"
"DhcpServer"="192.168.1.1"
"0.0.0.0,0.0.0.0,192.168.1.1,-1"=""
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\Standard TCP/IP Port\Ports\192.168.1.5]
"HostName"="192.168.1.5"
"Port"="192.168.1.5"
"LocationInformation"="http://192.168.1.28:1215/"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"StandaloneDhcpAddress"="192.168.173.1"
"ScopeAddressBackup"="192.168.137.1"
"ScopeAddress"="192.168.137.1"
"DhcpIPAddress"="192.168.1.24"
"DhcpServer"="192.168.1.1"
"0.0.0.0,0.0.0.0,192.168.1.1,-1"=""
"MRU0"="192.168.16.93"
[HKEY_USERS\S-1-5-21-2054485685-3446499333-1556621121-1001\Software\Microsoft\Terminal Server Client\Servers\192.168.16.93]
"A"="192.168.1.23"
"B"="192.168.1.28"
"C"="192.168.1.200:5800"
"192.168.254.190::5901/extra"=hex:02,00
"00"="192.168.254.190:5901"
"ImagePrinterPort"="192.168.1.5"

이 작업을 재귀해야합니다.

find -type f | while read l; do iconv -s -f utf-16le -t utf-8 "$l" | nl -s "$l: " | cut -c7- | grep 'somestring'; done

이것은 절대적으로 끔찍하고 매우 느립니다. 나는 더 나은 방법이 확신하고 누군가가 그것을 확신하고 있습니다. 그러나 나는 서둘 렀습니다 : P

조각이하는 일 :

find -type f

현재에 최빈 인 경로가있는 파일 이름의 재귀 목록을 제공합니다.

while read l; do ... done

배쉬 루프; 파일 경로 목록의 각 행에 대해 경로를 넣고 $l루프에서 작업을 수행하십시오. (왜 xargs 대신 셸 루프를 사용했는데 훨씬 더 빨 랐을 것입니다. 출력의 각 줄에 현재 파일의 이름을 접두사로 지정해야합니다. 한 번에 여러 파일을 iconv에 추가하고 어쨌든 한 번에 하나의 파일을 수행 할 것이므로 쉘 루프가 더 쉬운 구문 / 이스케이프입니다.)

iconv -s -f utf-16le -t utf-8 "$l"

in $l: 라는 파일을 변환합니다 . 입력 파일이 utf-16 little-endian이라고 가정하고 utf-8로 변환합니다. -s차종은 어떤 변환 오류에 대해 조용히의 iconv (이 디렉토리 구조의 일부 파일이 UTF-16이 아니기 때문에, 많이있을 것입니다). 이 변환의 출력은 stdout으로 이동합니다.

nl -s "$l: " | cut -c7-

이것은 해킹입니다. nl줄 번호를 삽입하지만 "이 임의의 문자열을 사용하여 줄에서 번호를 분리"매개 변수가 있으므로 여기에 파일 이름 (콜론과 공백이 이어짐)을 입력합니다. 그런 다음 cut줄 번호를 제거하고 파일 이름 접두사 만 남겨 둡니다. (왜 사용하지 않았다 sed:.. 탈출 훨씬 쉽게이 방법은 내가 나오지도 표현을 사용하는 경우에, 나는 많은 내 경우가 있었다 파일 이름에서 정규 표현식 문자, 거기에 대해 걱정할 필요가 nl보다 더 멍청하다 sed, 매개 변수를 -s완전히 문자 그대로 취하고 쉘이 이스케이프를 처리합니다.)

그래서,이 파이프 라인이 끝날 무렵, 저는 파일 이름이 접두사로 붙은 utf-8 라인으로 여러 파일을 변환 한 다음 grep합니다. 일치하는 항목이 있으면 접두사에서 어떤 파일에 있는지 알 수 있습니다.

주의 사항

  • 이 훨씬 낮은 속도보다 많이 grep -R나는의 새 복사본을 산란하고 있습니다 때문에, iconv, nl, cut, 및 grep모든 단일 파일. 끔찍합니다.
  • 입력이 'somestring'이 포함 된 일반 ASCII 파일 거기에 만약 그렇다면, 완전한 쓰레기로 나올 것 UTF-16LE 아닌 모든 것은,이 명령은이를보고하지 않습니다 - 당신이 정상을 할 필요가 grep -R(물론이 명령으로 일부 빅 엔디안 및 리틀 엔디안 파일과 같은 여러 유니 코드 인코딩 유형이있는 경우이 명령을 조정하고 각 인코딩에 대해 다시 실행해야합니다).
  • 이름에 'somestring'이 포함 된 파일은 내용이 일치하지 않더라도 출력에 표시됩니다.

ripgrep

ripgrep유틸리티사용 하여 UTF-16 파일을 grep하십시오.

ripgrep은 UTF-16, latin-1, GBK, EUC-JP, Shift_JIS 등과 같이 UTF-8 이외의 텍스트 인코딩으로 파일 검색을 지원합니다. (UTF-16을 자동으로 감지하기위한 일부 지원이 제공됩니다. 기타 텍스트 인코딩은 -E/ 로 구체적으로 지정해야합니다. --encoding flag.)

구문 예 :

rg sometext file

모든 라인을 덤프하려면 다음을 실행하십시오 rg -N . file..


sed 진술은 내가 머리를 감쌀 수있는 것 이상이다. 내 테스트 포인트 1로 정상 작동한다고 생각하는 단순하고 완벽하지 않은 TCL 스크립트가 있습니다.

#!/usr/bin/tclsh

set insearch [lindex $argv 0]

set search ""

for {set i 0} {$i<[string length $insearch]-1} {incr i} {
    set search "${search}[string range $insearch $i $i]."
}
set search "${search}[string range $insearch $i $i]"

for {set i 1} {$i<$argc} {incr i} {
    set file [lindex $argv $i]
    set status 0
    if {! [catch {exec grep -a $search $file} results options]} {
        puts "$file: $results"
    }
}

위의 답변에 대한 주석으로 추가했지만 더 쉽게 읽을 수 있습니다. 이렇게하면 여러 파일에서 텍스트를 검색하는 동시에 텍스트를 찾는 파일 이름도 표시 할 수 있습니다. 내 보낸 Windows 레지스트리 파일을 검색하기 때문에 이러한 모든 파일의 확장자는 .reg입니다. .reg를 파일 확장자로 바꾸십시오.

// Define grepreg in bash by pasting at bash command prompt
grepreg ()
{
    find -name '*.reg' -exec echo {} \; -exec iconv -f utf-16 -t utf-8 {} \; | grep "$1\|\.reg"
}

// Sample usage
grepreg SampleTextToSearch

다음 Ruby의 한 줄을 사용할 수 있습니다.

ruby -e "puts File.open('file.txt', mode:'rb:BOM|UTF-16LE').readlines.grep(Regexp.new 'PATTERN'.encode(Encoding::UTF_16LE))"

단순화를 위해 다음과 같이 쉘 함수로 정의 할 수 있습니다.

grep-utf16() { ruby -e "puts File.open('$2', mode:'rb:BOM|UTF-16LE').readlines.grep(Regexp.new '$1'.encode(Encoding::UTF_16LE))"; }

그런 다음 grep과 유사한 방식으로 사용됩니다.

grep-utf16 PATTERN file.txt

출처 : UTF-16 파일에 Ruby의 readlines.grep을 사용하는 방법은 무엇입니까?


ugrep (Universal grep)은 유니 코드, UTF-8 / 16 / 32 파일을 지원하고 잘못된 유니 코드를 감지하여 적절한 결과를 보장하고 텍스트 및 이진 파일을 표시하며 빠르고 무료입니다.

ugrep은 UTF-8 / 16 / 32 입력 및 기타 형식을 검색합니다. 옵션 --encoding을 사용하면 ISO-8859-1, EBCDIC 및 코드 페이지 437, 850, 858, 1250 ~ 1258과 같은 다른 많은 파일 형식을 검색 할 수 있습니다.

GitHub에서 ugrep 다운로드

참고 URL : https://stackoverflow.com/questions/3752913/grepping-binary-files-and-utf16

반응형