我是 Windows 生态系统的新手。我被要求编写一个程序,该程序将在数十万(甚至数十万)个文件中搜索特定字符串。必须匹配的字符串是仅由数字和字母组成的序列号,并且少于 20 个字符。现在,我的程序正在执行以下命令:
findstr /i /m /s "searchStr" "C:\Directory\To\Search\*.*"
上述命令可以工作,但是速度太慢了。可能包含特定序列号的文件只会在第一行显示序列号。
有人知道一种有效的方法可以递归搜索目录中仅在第一行包含特定字符串的所有文件吗?
答案1
在 PowerShell (v3.0+) 中,也许......
Get-ChildItem -Path x:\pathto\*.log `
| ForEach-Object {
if (Get-Content -LiteralPath $_ -First 1 `
| Select-String -SimpleMatch -Pattern 'serialnumber')
{
Write-Output $_
}
}
不同的参数Get-ChildItem
可以递归子文件夹等;可以Get-Content
从文件中获取更多或更少的内容;并且Select-String
可以执行更复杂的匹配(正则表达式,区分大小写等)。
答案2
如果您不需要使用,我可以建议一些选项findstr
,但首先您应该看看是否可以将搜索限制在某种文件类型的文件中,因为这肯定会加快速度。
FileLocator 精简版以我的经验来说,查找文件和检查其内容的速度更快。请务必填写“文件名”(如果适用)和“包含的文本”字段,以及起始目录。
ag -il "searchStr"
:银专为速度而构建,因此它应该能快速为您提供结果。如果可以,请务必按文件类型限制搜索,尽管默认情况下已跳过二进制文件。也可在赛格威。find -exec awk 'BEGIN {IGNORECASE=1} NR==1 && /searchStr/ {print FILENAME": "$0}' {} \;
如果您有 Cygwin 或其他类似 POSIX 的环境,请尝试此操作,以检查您关于仅搜索第一行的想法。组合find
以获取文件名(并希望过滤它们)并awk
检查第一行并将其与文件名一起打印。find | parallel 'perl -lane '\'' print "$ARGV: $_" if $. == 1 and /searchStr/i '\'' {}'
另一个尝试加快速度的想法是将可用的核心和线程投入工作:这就是GNU并行是 for。此示例运动,但它的作用与上面的perl
相同。以下是命令分解:awk
3.
find
在当前目录及其子目录中查找文件。您可以指定要查找的其他目录以及要过滤的文件模式或扩展名:find /cygdrive/c/Directory/To/Search -iname "*.txt"
。|
“管道”,即将结果列表提供给下一个命令。parallel
并行执行下一个命令。perl
擅长文本文件操作的脚本语言,可以替代sed
或awk
。-lane
对于 perl 单行命令来说有用的一组开关。'\''
转义撇号,由于我们已经在之后打开了一个撇号集,因此需要转义撇号parallel
。print "$ARGV: $_"
打印文件名($ARGV
)、冒号、空格和整行($_
)。if
仅当满足以下条件时才执行前一条指令。$. == 1
行号($.
)等于一(1
),即我们正在查看文件的第一行。and
还必须满足以下条件。/searchStr/i
被检查的行包含文本searchStr
,不区分大小写。'\''
另一个转义的撇号标志着指令的结束perl
。{}
这将被 替换为parallel
传递的每个文件名find
。'
指令结束parallel
。
更新:即使操作仅绑定到第一行,awk
和也会读取整个文件。解决方案是在第 2 行明确停止详细说明:perl
find -exec awk 'BEGIN {IGNORECASE=1} NR > 1 {exit} /searchStr/ {print FILENAME": "$0}' {} \;
find | parallel 'perl -lape '\'' exit if $. == 2; print "$ARGV: $_" if /searchStr/i '\'' {}'