我真的很习惯做grep -iIr
在 Unix shell 上,但我还没有能够获得等效的 PowerShell。
基本上,由于“-I”选项,上述命令递归搜索目标文件夹并忽略二进制文件。此选项也等效于 --binary-files=without-match
选项,表示“将二进制文件视为与搜索字符串不匹配”
到目前为止我一直在使用 Get-ChildItems -r | Select-String
作为我的 PowerShell grep 替换,偶尔使用 Where-Object
添加。但我还没有想出一种方法来忽略所有二进制文件,例如 grep -I
命令可以。
如何使用 Powershell 过滤或忽略二进制文件?
所以对于给定的路径,我只想要 Select-String
搜索文本文件。
编辑:在谷歌上再过几个小时产生了这个问题 How to identify the contents of a file is ASCII or Binary .问题是“ASCII”,但我相信作者的意思是“文本编码”,就像我自己一样。
编辑:似乎是isBinary()
需要编写来解决这个问题。可能是一个 C# 命令行实用程序,以使其更有用。
编辑:好像是什么grep
正在做的是检查 ASCII 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
但当然,文件扩展名并不完美。没有人喜欢输入长列表,无论如何,很多文件都被错误命名。
我认为 Unix 在文件系统中没有任何特殊的二进制与文本指示符。 (嗯,VMS 做到了,但我怀疑这就是您的 grep 习惯的来源。)我查看了 Grep -I 的实现,显然它只是基于文件第一块的快速-n-dirty 启发式方法。原来这是我的策略 a bit of experience和。所以这里是我关于选择适合 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() }
}
}
}
我所针对的使用模式是在“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 的东西。
关于忽略二进制文件的 PowerShell 搜索脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1077634/