我真的习惯grep -iIr在Unix shell 上做,但我还没有能够获得PowerShell等价物.
基本上,上面的命令递归搜索目标文件夹并忽略二进制文件,因为"-I"选项.此选项也等同于--binary-files=without-match选项,其中显示"将二进制文件视为与搜索字符串不匹配"
到目前为止,我一直在使用Get-ChildItems -r | Select-String我的PowerShell grep替换偶尔Where-Object添加.但我还没有找到一种方法来忽略grep -I命令所做的所有二进制文件.
如何使用Powershell过滤或忽略二进制文件?
所以对于给定的路径,我只想Select-String搜索文本文件.
编辑: 在Google上再制作几个小时这个问题如何识别文件的内容是ASCII还是二进制.问题是"ASCII",但我相信作者的意思是"文本编码",就像我自己一样.
编辑:似乎isBinary()需要编写一个来解决这个问题.可能是一个C#命令行实用程序,使其更有用.
编辑:似乎grep正在做的是检查ASCII NUL字节或UTF-8 Overlong.如果存在,则认为文件是二进制文件.这是一个memchr()调用.
Ric*_*erg 32
在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
Run Code Online (Sandbox Code Playgroud)
但当然,文件扩展名并不完美.没有人喜欢输入长列表,而且还有大量文件被错误命名.
我不认为Unix在文件系统中有任何特殊的二进制vs文本指示符.(好吧,VMS确实如此,但我怀疑这是你的grep习惯的来源.)我看了一下Grep -I的实现,显然它只是一个基于文件第一块的快速n-dirty启发式算法.事实证明这是我有一点经验的策略.所以我的建议是选择适合Windows文本文件的启发式函数:
例如,这是快速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() }
}
}
}
Run Code Online (Sandbox Code Playgroud)
我所针对的使用模式是在"dir"和"ss"之间的管道中插入的where-object子句.还有其他方法,具体取决于您的脚本风格.
沿着建议的路径之一改进检测算法留给读者.
编辑:我开始在自己的评论中回复你的评论,但它太长了......
上面,我从POV中查看了白名单已知良好序列的问题.在我维护的应用程序中,错误地将二进制文件存储为文本的结果远比反之亦然.对于要选择使用哪种FTP传输模式,要将哪种MIME编码发送到电子邮件服务器等的情况,情况也是如此.
在其他情况下,将明显虚假列入黑名单并允许其他所有内容称为文本是一种同样有效的技术.虽然U + 0000是一个有效的代码点,但在真实世界的文本中几乎找不到它.同时,\ 00在结构化二进制文件中很常见(即,每当固定字节长度的字段需要填充时),因此它就是一个非常简单的黑名单.VSS 6.0单独使用此检查并且确实可以.
旁白:*.zip文件是检查\ 0风险较大的情况.与大多数二进制文件不同,它们的结构化"标题"(页脚?)块在最后,而不是开头.假设理想的熵压缩,前1KB中没有\ 0的概率是(1-1/256)^ 1024或大约2%.幸运的是,只需扫描剩余的4KB群集NTFS读取就可以将风险降低到0.00001%,而无需更改算法或编写其他特殊情况.
要排除无效的UTF-8,请将\ C0-C1和\ F8-FD以及\ FE-FF(一旦找到可能的BOM)添加到黑名单.非常不完整,因为您实际上并未验证序列,但足够接近您的目的.如果你想获得比这更漂亮的人,那么就该调用其中一个平台库,比如IMultiLang2 :: DetectInputCodepage.
不知道为什么\ C8(200十进制)在Grep的列表中.这不是一个过长的编码.例如,序列\ C8\80表示Ȁ(U + 0200).也许是Unix特有的东西.
好的,经过几个小时的研究后,我相信我找到了解决方案.我不会将此标记为答案.
Pro Windows Powershell有一个非常相似的例子.我完全忘了我有这个很好的参考.如果您对Powershell感兴趣,请购买.它详细介绍了Get-Content和Unicode BOM.
这回答了类似的问题也都符合Unicode识别非常有帮助.
这是脚本.如果您知道它可能有任何问题,请告诉我.
# 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
Run Code Online (Sandbox Code Playgroud)
将此脚本另存为isBinary.ps1
这个脚本得到了我试过的每个文本或二进制文件.
| 归档时间: |
|
| 查看次数: |
6864 次 |
| 最近记录: |