批量查找给定字符串条件的文件
Posted
技术标签:
【中文标题】批量查找给定字符串条件的文件【英文标题】:find a file given string criteria in batch 【发布时间】:2020-12-13 00:34:44 【问题描述】:我有一个包含一些单词的变量,例如KEYWORDS ="Blue Blond Brown White Black Eyes Hair Skin"
,另一个只包含其中一些单词,例如
MYWORDS="BLUE BROWN EYES HAIR"
我的目录中有一些文件,例如
BlueEyesBlondHair.txt
BrownEyesBlondHair.txt
BlueEyesBrownHair.txt
BlueEyesBrownHairWhiteSkin.txt
BlueEyes.txt
BrownHair.txt
BrownEyes.txt
GreenEyesBlondHair.txt
如何检索名称包含变量MYWORDS
中所有单词的文件,而不是其他?
注意:这是一个完全虚构的例子,但我认为它与我的现实非常吻合。请把所有内容都当作大写字母。
【问题讨论】:
本网站并非真正为您提供执行整个任务的方法。 @Compo 地狱,你是对的。我试图尽可能接近困扰我的任务部分,但后来我不断添加解释,现在太多了。我要重构这个。 您打算在使用 grep 时对文件内容使用完全匹配,还是文件名本身?换句话说,是做:grep -l BlueEyesBrownHair *.txt
还是做:grep -l %STRING% BlueEyesBrownHair.txt
?
@Gerhard:不确定我是否理解你的问题。我正在使用 grep 来获取包含该字符串的所有 txt 文件的文件名,所以 grep -l %STRING% *.txt
。我不知道我需要的是 BlueEyesBrownHair,因为此信息由 %STRING% 提供
这是一个虚构的问题,@Gerhard,没有解决方案。举个例子,如果%STRING%
可以被拆分,就像使用find.exe
一样,例如dir "*.txt" | find /i "blue" | find /i "hair" | find /i "brown" | find /i "eyes"
,您只能通过 BlueEyesBrownHair.txt
和 BlueEyesBrownHairWhiteSkin.txt
。但似乎不需要BlueEyesBrownHairWhiteSkin.txt
,因为它带有不在%STRING%
中的字符。我们可以假设要求是检索文件名中字符最少的文件吗?
【参考方案1】:
我找到了另一种不需要检查文件名长度的方法:findstr 有一个 /v 选项,允许它搜索与模式不匹配的内容。
由于我同时拥有KEYWORDS
和MYWORDS
变量,我可以轻松创建第三个名为BADWORDS
的变量,其中包含KEYWORDS
中但MYWORDS
中没有的所有单词。
按照示例,我们有BADWORD= BLOND WHITE BLACK SKIN
那么做一个简单的就足够了:
dir /b *.txt | findstr /i /C:"BLUE" /C:"BROWN" /C:"HAIR" /C:"EYES" | findstr /i /v "%BADWORDS%"
获取包含来自MYWORDS
的所有单词但不包含其他单词的文件名。
但是,这仍然需要拆分变量MYWORDS
,就像在@Gerhard 回答中一样。
另一种方法是像这样修改MYWORDS
:
set MYNEWWORDS=%MYWORDS: =.*%
然后做
dir /b *.txt | findstr /i /R /C:"%MYNEWWORDS%" | findstr /i /v "%BADWORDS%"
这将搜索包含来自MYWORDS
的所有单词的文件名,但顺序相同。这意味着这还不足以解决我的案子。
【讨论】:
遗憾的是,它会为您找到包含 至少一个%mywords%
并且缺少 至少一个 %badwords%
的文件名。这与问题中所述的标准不符。 (“缺失”部分是可以的,但你想要 all of %mywords%
)
该死,你是对的。现在我记得为什么我昨天没有使用它-_-【参考方案2】:
有趣的谜题。
你的白名单词显然可以以任何顺序出现,这使得它有点困难,但并非无法解决:
@echo off
setlocal enabledelayedexpansion
REM ---- only to generate testfiles: ---
for %%a in (
BlueEyesBlondHair.txt
BrownEyesBlondHair.txt
BlueEyesBrownHair.txt
BlueEyesBrownHairWhiteSkin.txt
BlueEyes.txt
BrownHair.txt
BrownEyes.txt
GreenEyesBlondHair.txt
LongHairBlueShirtBrownEyes.txt
CompletelyUnrelatedFile.txt
) do break>"%%a"
REM ---- end generate testfiles ----
set "KEYWORDS=Blue Blond Brown White Black Eyes Hair Skin"
set "MYWORDS=BLUE BROWN EYES HAIR"
REM generate exclude-list:
set "NONWORDS=%KEYWORDS%"
for %%a in (%MYWORDS%) do set "NONWORDS=!NONWORDS:%%a=!"
rem echo %NONWORDS%
for %%a in (*.txt) do (
set /a c1=c2=0
set "name=%%~na"
for %%b in (%MYWORDS%) do (
REM increment counter1 [number of words in MYWORDS]:
set /a c1+=1
REM increment counter2 [number of those words in the filename]
if not "!name:%%b=!" == "!name!" set /a c2+=1
)
if !c1! == !c2! (
echo %%a has all of MYWORDS
echo %%a|findstr "%NONWORDS%" >nul|| (
echo %%a has none of NONWORDS
) && (
echo +++ %%a has all of MYWORDS and none of NONWORDS
)
) else (
echo %%a has not all of MYWORDS
)
)
这段代码的输出:
BlueEyes.txt has not all of MYWORDS
BlueEyesBlondHair.txt has not all of MYWORDS
BlueEyesBrownHair.txt has all of MYWORDS
BlueEyesBrownHair.txt has none of NONWORDS
+++ BlueEyesBrownHair.txt has all of MYWORDS and none of NONWORDS
BlueEyesBrownHairWhiteSkin.txt has all of MYWORDS
BrownEyes.txt has not all of MYWORDS
BrownEyesBlondHair.txt has not all of MYWORDS
BrownHair.txt has not all of MYWORDS
CompletelyUnrelatedFile.txt has not all of MYWORDS
GreenEyesBlondHair.txt has not all of MYWORDS
LongHairBlueShirtBrownEyes.txt has all of MYWORDS
LongHairBlueShirtBrownEyes.txt has none of NONWORDS
+++ LongHairBlueShirtBrownEyes.txt has all of MYWORDS and none of NONWORDS
显然,根据您的需要调整 echo
s 或跳过您根本不需要的那些(为了更好地进行故障排除,我把它写得有点冗长)。
【讨论】:
这太棒了! :) 我太专注于获取所有单词和一个好的正则表达式,然后在一个命令中进行搜索,从没想过只是一个接一个地测试文件名......谢谢! REGEX 在cmd
中非常有限,所以这里不是一个真正的选择。上面的方法感觉很尴尬而且不优雅,但我想不出更好的逻辑来做到这一点。 Gerhard 处理find...|find...|find...etc.
的方法会更快,但这意味着,您必须将单词列表硬编码到代码中——这不是一个好主意。【参考方案3】:
不过,只要把一个方法放在那里,你就可以使用findstr
s 正则表达式来代替所有的`find 命令。这实际上只是一个演示:
@echo off & set prev=100
setlocal enabledelayedexpansion
for /f "delims=" %%i in ('dir /b *.txt ^|find /i "blue" ^|find /i "brown"^|find /i "eyes"^|find /i "hair"') do echo %%i>_&for %%a IN (_) do (
set /a len=%%~za-2
if !len! lss !prev! (
set prev=!len!
set "file=%%i"
)
)
echo !file! & (del _ /Q)>nul 2>&1
【讨论】:
谢谢。但是,这需要拆分我的变量;我知道如何在 FOR 循环中执行此操作,但我不确定我是否可以设置包含第一个单词的每个单词的多个变量,特别是因为我不知道我的变量中有多少单词......但它是仍然是一个开始,感谢您的时间。你能解释一下set /a len=%%~za-2
中的za
吗?
然后使用findstr
的正则表达式为您进行搜索。这只是示范。要了解变量扩展,请参阅for /?
ofc,我试图了解如何使用 findstr 进行操作,然后我发现多个搜索字符串必须用空格分隔 -_- 又浪费了一个小时。无论如何,找到za
的东西,谢谢。即使在将来,这也会有很大的帮助:)以上是关于批量查找给定字符串条件的文件的主要内容,如果未能解决你的问题,请参考以下文章