programing

이진 파일을 무시하는 PowerShell 검색 스크립트

starjava 2023. 10. 14. 09:27
반응형

이진 파일을 무시하는 PowerShell 검색 스크립트

는 를 에 정말 익숙합니다.grep -iIr유닉스 셸에 있지만 아직 파워셸과 동등한 것을 얻을 수 없습니다.

기본적으로 위 명령은 대상 폴더를 재귀적으로 검색하고 "-I" 옵션 때문에 이진 파일을 무시합니다..--binary-files=without-match"treat 이진 파일이 검색 문자열과 일치하지 않음"이라고 표시되는 옵션

까지 를 .Get-ChildItems -r | Select-String다를 하는 PowerShell grep을 사용할 수 있습니다.Where-Object요 같은 을 다 은 아직 하지만 전 아직 모든 바이너리 파일을 무시할 방법을 찾지 못했습니다.grep -I명령은 합니다.

파워셸로 바이너리 파일을 어떻게 필터링하거나 무시할 수 있습니까?

, 만 .Select-String텍스트 파일을 검색합니다.

편집: Google에서 몇 시간 더 작업하자 파일의 내용을 식별하는 방법은 ASCII 또는 Binary입니다.질문에는 "ASCII"라고 되어 있지만, 저는 작가가 저처럼 "텍스트 인코딩"을 의미했다고 생각합니다.

편집: 그것은 우리가.isBinary()이 문제를 해결하기 위해서는 작성이 필요합니다.C# 명령줄 유틸리티를 사용하면 더 유용할 수 있습니다.

편집: 무슨 일이 있었던 것 같습니까?grepASCII NUL Byte 또는 UTF-8 Overlong을 확인하고 있습니다.만약 존재한다면, 그것은 파일 바이너리를 고려합니다.단 한번의 memchr() 통화입니다.

Windows(윈도우)에서는 일반적으로 파일 확장명이 충분합니다.

# all C# and related files (projects, source control metadata, etc)
dir -r -fil *.cs* | ss foo

# exclude the binary types most likely to pollute your development workspace
dir -r -exclude *exe, *dll, *pdb | ss foo

# stick the first three lines in your $profile (refining them over time)
$bins = new-list string
$bins.AddRange( [string[]]@("exe", "dll", "pdb", "png", "mdf", "docx") )
function IsBin([System.IO.FileInfo]$item) { !$bins.Contains($item.extension.ToLower()) }
dir -r | ? { !IsBin($_) } | ss foo

하지만 물론 파일 확장자가 완벽하지는 않습니다.긴 목록을 입력하는 것을 좋아하는 사람은 아무도 없고, 많은 파일의 이름이 잘못 지정되어 있습니다.

유닉스는 파일 시스템에 특별한 바이너리 대 텍스트 인디케이터가 없다고 생각합니다.(글쎄요, VMS는 그랬습니다만, 그것이 당신의 grep 습관의 근원이 아닌가 싶습니다.)Grep-I의 구현을 살펴보았는데 파일의 첫 번째 청크에 기반한 빠른 n-dirty 휴리스틱에 불과합니다.제가 경험이 좀 있는 전략인 것으로 드러났습니다.Windows 텍스트 파일에 적합한 휴리스틱 기능을 선택하는 방법에 대한 조언은 다음과 같습니다.

  • 1KB 이상의 파일을 검사합니다.많은 파일 형식은 텍스트처럼 보이지만 곧 구문 분석기가 실행되는 머리글로 시작합니다.현대 하드웨어가 작동하는 방식으로 50바이트를 읽는 것은 4KB를 읽는 것과 거의 같은 I/O 오버헤드를 가집니다.
  • 스트레이트 ASCII에만 관심이 있는 경우 문자 범위 [31-127 + CR 및 LF]를 벗어나는 것이 보이면 바로 종료합니다.일부 영리한 ASCII 아트를 실수로 제외할 수도 있지만, 이러한 경우를 이진 정크에서 분리하는 것은 사소한 일이 아닙니다.
  • 유니코드 텍스트를 처리하려면 MS 라이브러리에서 더러운 작업을 처리하도록 합니다.생각보다 어렵군요.Powershell에서 IMultiLang2 인터페이스(COM) 또는 Encoding에 쉽게 액세스할 수 있습니다.정적 메서드(.NET)를 가져옵니다.물론, 그들은 아직도 추측만 하고 있습니다.메모장 탐지 알고리즘(및 Michael Kaplan에 대한 링크)에 대한 Raymond의 의견은 플랫폼이 제공하는 라이브러리를 정확히 어떻게 조합하고 일치시킬지 결정하기 전에 검토할 가치가 있습니다.
  • 결과가 중요한 경우(즉, 결함으로 인해 grep 콘솔이 엉망이 되는 것보다 더 나쁜 결과가 발생하는 경우), 정확성을 위해 일부 파일 확장자를 하드 코드화하는 것을 두려워하지 마십시오.예를 들어 *.PDF 파일은 이진 형식임에도 불구하고 종종 앞에 몇 KB의 텍스트가 있어서 위에 링크된 악명 높은 버그로 이어집니다.마찬가지로 XML 또는 XML 유사 데이터를 포함할 가능성이 있는 파일 확장자가 있다면 Visual Studio의 HTML 편집기와 유사한 탐지 체계를 시도해 볼 수 있습니다. (SourceSafe 2005는 실제로 일부 경우에 대해 이 알고리즘을 차용합니다.)
  • 다른 어떤 일이 일어나더라도 합리적인 백업 계획을 세우십시오.

예를 들어, 빠른 ASCII 검출기는 다음과 같습니다.

function IsAscii([System.IO.FileInfo]$item)
{
    begin 
    { 
        $validList = new-list byte
        $validList.AddRange([byte[]] (10,13) )
        $validList.AddRange([byte[]] (31..127) )
    }

    process
    {
        try 
        {
            $reader = $item.Open([System.IO.FileMode]::Open)
            $bytes = new-object byte[] 1024
            $numRead = $reader.Read($bytes, 0, $bytes.Count)

            for($i=0; $i -lt $numRead; ++$i)
            {
                if (!$validList.Contains($bytes[$i]))
                    { return $false }
            }
            $true
        }
        finally
        {
            if ($reader)
                { $reader.Dispose() }
        }
    }
}

제가 대상으로 하는 사용 패턴은 "dir"와 "ss" 사이의 파이프라인에 삽입된 where-object 절입니다.스크립팅 스타일에 따라 다른 방법이 있습니다.

제안된 경로 중 하나를 따라 탐지 알고리즘을 개선하는 것은 독자에게 맡깁니다.

edit : 당신의 댓글에 나만의 댓글로 답장을 시작했는데 너무 길어졌어요...

위에서, 저는 알려진 좋은 시퀀스를 화이트리스트에 올리는 POV에서 문제를 보았습니다.I가 유지한 응용 프로그램에서 이진 파일을 텍스트로 잘못 저장하는 것은 그 반대보다 훨씬 더 나쁜 결과를 초래했습니다.사용할 FTP 전송 모드 또는 전자 메일 서버로 전송할 MIME 인코딩의 종류를 선택하는 경우에도 마찬가지입니다.

다른 시나리오에서는 명백하게 가짜를 블랙리스트에 올리고 다른 모든 것을 텍스트라고 부르는 것을 허용하는 것도 마찬가지로 유효한 기술입니다.U+0000은 유효한 코드 포인트이지만 실제 텍스트에서는 거의 찾아볼 수 없습니다.한편, \00은 구조화된 이진 파일에서 매우 흔하므로(즉, 고정 바이트 길이 필드에 패딩이 필요할 때마다) 훌륭한 간단한 블랙리스트가 됩니다.VSS 6.0은 이 체크만 사용하고 잘 했습니다.

별도: *.zip 파일은 \0을 확인하는 것이 더 위험한 경우입니다.대부분의 쌍성과 달리 구조화된 "헤더"(footer?) 블록은 시작이 아니라 끝에 있습니다.이상적인 엔트로피 압축을 가정할 때, 처음 1KB에서 \0이 없을 확률은 (1-1/256)^1024 또는 약 2%입니다.다행히 알고리즘을 변경하거나 다른 특별한 경우를 작성할 필요 없이 4KB 클러스터 NTFS 읽기의 나머지 부분을 스캔하기만 해도 위험이 0.00001%로 낮아집니다.

유효하지 않은 UTF-8을 제외하려면 블랙리스트에 \C0-C1 및 \F8-FD 및 \FE-FF(가능한 BOM을 통과한 경우)를 추가합니다.시퀀스를 실제로 검증하는 것이 아니라 목적에 맞게 충분히 가깝기 때문에 매우 불완전합니다.이보다 더 멋진 모습을 보여주고 싶다면, IMultiLang2와 같은 플랫폼 라이브러리에 전화해 볼 때입니다.DetectInputCode페이지.

왜 \C8(소수점 200)이 그렙의 목록에 있는지 확실하지 않습니다.너무 긴 인코딩이 아닙니다.예를 들어, 수열 \C8 \80은 ȁ(U+0200)을 나타냅니다.유닉스에 특정한 것일 수도 있습니다.

네, 몇 시간 더 조사한 결과 해결책을 찾았다고 생각합니다.정답으로 표시하지는 않겠습니다.

Pro Windows Powershell도 이와 매우 유사한 예를 가지고 있습니다.저는 제가 이렇게 훌륭한 참고 자료를 가지고 있다는 것을 까맣게 잊고 있었습니다.파워쉘에 관심이 있으시면 구매해주시기 바랍니다.Get-Content와 Unicode BOM에 대해 자세히 설명했습니다.

이와 유사한 질문에 대한 답변은 유니코드 식별에도 많은 도움이 되었습니다.

여기 대본이 있습니다.혹시 문제가 있을 수 있는 사항을 알고 계시면 알려주시기 바랍니다.

# The file to be tested
param ($currFile)

# encoding variable
$encoding = ""

# Get the first 1024 bytes from the file
$byteArray = Get-Content -Path $currFile -Encoding Byte -TotalCount 1024

if( ("{0:X}{1:X}{2:X}" -f $byteArray) -eq "EFBBBF" )
{
    # Test for UTF-8 BOM
    $encoding = "UTF-8"
}
elseif( ("{0:X}{1:X}" -f $byteArray) -eq "FFFE" )
{
    # Test for the UTF-16
    $encoding = "UTF-16"
}
elseif( ("{0:X}{1:X}" -f $byteArray) -eq "FEFF" )
{
    # Test for the UTF-16 Big Endian
    $encoding = "UTF-16 BE"
}
elseif( ("{0:X}{1:X}{2:X}{3:X}" -f $byteArray) -eq "FFFE0000" )
{
    # Test for the UTF-32
    $encoding = "UTF-32"
}
elseif( ("{0:X}{1:X}{2:X}{3:X}" -f $byteArray) -eq "0000FEFF" )
{
    # Test for the UTF-32 Big Endian
    $encoding = "UTF-32 BE"
}

if($encoding)
{
    # File is text encoded
    return $false
}

# So now we're done with Text encodings that commonly have '0's
# in their byte steams.  ASCII may have the NUL or '0' code in
# their streams but that's rare apparently.

# Both GNU Grep and Diff use variations of this heuristic

if( $byteArray -contains 0 )
{
    # Test for binary
    return $true
}

# This should be ASCII encoded 
$encoding = "ASCII"

return $false

이 스크립트를 Binary.ps1 그대로 저장

이 스크립트는 내가 수정하려고 시도한 모든 텍스트나 이진 파일을 받았습니다.

다른 답변들이 더 '완전하다'는 것에는 동의하지만 폴더 내에서 어떤 파일 확장자를 만나게 될지 모르기 때문에 모든 파일 확장자를 훑어보고 싶기 때문에 이것이 저에게 가장 쉬운 해결책입니다.바이너리 파일을 통해 검색하는 것을 피하는 대신 바이너리 파일을 통해 검색할 때 발생하는 오류를 무시하는 것은 어떻습니까?
검색 중인 폴더 내에 이진 파일이 있더라도 검색 실행에 오래 걸리지 않습니다. 내부의 을 찾을 은 거의 ).결국에는 패턴과 일치하는 문자열만 신경 쓸 뿐입니다(이진 파일 내부의 패턴과 일치하는 문자열을 찾을 가능성은 거의 없습니다).

GCI -Recurse -Force -ErrorAction SiliousContinue | 각 개체의 경우 {GC $_ -ErrorAction SiliousContinue | 선택 문자열 -패턴 "패턴" } | 파일 외부 -파일 경로 C:\temp\grep.txt -폭 9999999

언급URL : https://stackoverflow.com/questions/1077634/powershell-search-script-that-ignores-binary-files

반응형