如何使用 findstr 从文件中删除与列表文件中找到的字符串匹配的行?

How to use findstr to remove lines from a file that match strings found in a list file?

我正在尝试使用 findstr 删除与在另一个文件中找到的搜索字符串相匹配的行。这是我一直在尝试使用但它似乎不起作用。

dir %ProjectDir%TypeScript\*.ts /b /s > Files.txt
findstr /v /i /g:%ProjectDir%TypeScript\strictFiles.txt Files.txt > tsFiles.txt

编辑 这似乎也不起作用:

dir %ProjectDir%TypeScript\*.ts /b /s | findstr /v /i /g:%ProjectDir%TypeScript\strictFiles.txt > tsFiles.txt

简短而不完整的答案是您没有指定 findstr/L 开关,它强制执行文字搜索。没有它,第一个搜索字符串决定是选择文字搜索还是正则表达式模式。由于搜索字符串中包含文件名,其中包含将基本名称与名称扩展名分开的句点,这也是正则表达式模式中的元字符,因此findstr最有可能选择该模式。

此外,您还应该提供 /X 开关以不过滤掉错误的项目。例如,当缺少 /X 选项时,像 D:\Data\some 这样的路径也会匹配 D:\Data\some\file.ext


长而全面的答案考虑到 findstr 并没有让生活变得那么轻松。

让我们假设命令行...:[=​​62=]

dir /S /B /A:-D "D:\Project\TypeScript\*.ts" > "Files.txt"

...生成 Files.txt 中的文件路径列表,如下所示,...:[=​​62=]

D:\Project\TypeScript\sample.ts
D:\Project\TypeScript\restricted.ts
D:\Project\TypeScript\excluded.ts
D:\Project\TypeScript\not-excluded.ts
D:\Project\TypeScript\ancillary.ts
D:\Project\TypeScript\[special].ts
D:\Project\TypeScript\data\test.ts
D:\Project\TypeScript\data\confidential.ts
D:\Project\TypeScript\data\arbitrary.ts
D:\Project\TypeScript\data\.config.ts
D:\Project\TypeScript\data\other.config.ts
D:\Project\TypeScript\data.config.ts
D:\Project\TypeScript\conf.ts\wrong.ts

...文件 strictFiles.txt 包含此...:

D:\Project\TypeScript\restricted.ts
D:\Project\TypeScript\excluded.ts
D:\Project\TypeScript\[special].ts
D:\Project\TypeScript\confidential.ts
D:\Project\TypeScript\data\.config.ts
D:\Project\TypeScript\conf.ts

...从 Files.txt.

中过滤掉

您会期望命令行...:[=​​62=]

findstr /L /X /I /V /G:"strictFiles.txt" "Files.txt" > "tsFiles.txt"

...到 return 输出文件 tsFiles.txt,...:[=​​62=]

D:\Project\TypeScript\sample.ts
D:\Project\TypeScript\not-excluded.ts
D:\Project\TypeScript\ancillary.ts
D:\Project\TypeScript\data\test.ts
D:\Project\TypeScript\data\confidential.ts
D:\Project\TypeScript\data\arbitrary.ts
D:\Project\TypeScript\data\other.config.ts
D:\Project\TypeScript\data.config.ts
D:\Project\TypeScript\conf.ts\wrong.ts

...但实际上写的是:

D:\Project\TypeScript\sample.ts
D:\Project\TypeScript\not-excluded.ts
D:\Project\TypeScript\ancillary.ts
D:\Project\TypeScript\[special].ts
D:\Project\TypeScript\data\test.ts
D:\Project\TypeScript\data\confidential.ts
D:\Project\TypeScript\data\arbitrary.ts
D:\Project\TypeScript\data\.config.ts
D:\Project\TypeScript\data\other.config.ts
D:\Project\TypeScript\conf.ts\wrong.ts

原因是 findstr,尽管由于 /L 选项而处于文字搜索模式,但仍会检测正则表达式模式的元字符,并允许通过在前面加上\strictFiles.txt上面的示例内容中的句点.和左括号[就是这样的元字符,并且都在前面加了路径分隔符\,所以它们是被视为转义,因此被解释为 .[,或者换句话说,前面的 \ 被忽略。

要解决这个问题,您需要在 strictFiles.txt 中转义每个 \,在前面加上另一个 \,以避免元字符看起来转义为 [=20] =] -- 请参阅此脚本以了解可能的方法:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_ROOT=D:\Project\TypeScript"    & rem // (path of root directory)
set "_MASK=*.ts"                     & rem // (file search pattern)
set "_LIST=.\Files.txt"              & rem // (path to file list)
set "_EXCL=.\strictFiles.txt"        & rem // (path to exclusion list)
set "_TEMP=%TEMP%\%~n0_%RANDOM%.tmp" & rem // (temporary exclusion list)
set "_FILT=.\tsFiles.txt"            & rem // (path to filtered file list)
if not defined _FILT set "_FILT=con"

rem // Generate list of files:
dir /S /B /A:-D "%_ROOT%\%_MASK%" > "%_LIST%"

rem // Modify exclusion list:
rem /* replace every path separator `\` by an escaped one `\`,
rem    so no other characters can appear escaped to `findstr`: */
> "%_TEMP%" (
    for /F "usebackq delims= eol=|" %%F in ("%_EXCL%") do (
        set "FILE=%%F"
        setlocal EnableDelayedExpansion
        echo(!FILE:\=\!
        endlocal
    )
)

rem // Filter out files that occur in modified exclusion list:
findstr /L /X /V /I /G:"%_TEMP%" "%_LIST%" > "%_FILT%"

rem // Clean up temporary files:
del "%_LIST%" "%_TEMP%"

endlocal
exit /B

如果您的排除列表,比如这次 strictFileNames.txt,包含纯文件名而不是完整的文件路径,例如,...:[=​​62=]

restricted.ts
excluded.ts
[special].ts
confidential.ts
.config.ts
conf.ts

...方法略有不同,因为只考虑文件列表的最后一个路径元素 Files.txt。为此,您需要在排除列表的每个文件名之前加上一个路径分隔符,同样是一个像 \ 这样的转义分隔符,以避免错误匹配;例如,file.ext 将匹配 D:\Data\file.extD:\Data\X-file.ext,但 \file.ext 将仅匹配前者,因为 /X 选项已替换为 [=53] =]这次。

这是一个完成该任务的脚本:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_ROOT=D:\Project\TypeScript"    & rem // (path of root directory)
set "_MASK=*.ts"                     & rem // (file search pattern)
set "_LIST=.\Files.txt"              & rem // (path to file list)
set "_EXCL=.\strictFileNames.txt"    & rem // (path to exclusion list)
set "_TEMP=%TEMP%\%~n0_%RANDOM%.tmp" & rem // (temporary exclusion list)
set "_FILT=.\tsFiles.txt"            & rem // (path to filtered file list)
if not defined _FILT set "_FILT=con"

rem // Generate list of files:
dir /S /B /A:-D "%_ROOT%\%_MASK%" > "%_LIST%"

rem // Modify exclusion list:
rem /* precede every file with an escaped path separator `\`,
rem    so no other characters can appear escaped to `findstr`: */
> "%_TEMP%" (
    for /F "usebackq delims= eol=|" %%F in ("%_EXCL%") do (
        echo(\%%F
    )
)

rem // Filter out files that occur in modified exclusion list:
findstr /L /E /V /I /G:"%_TEMP%" "%_LIST%" > "%_FILT%"

rem // Clean up temporary files:
del "%_LIST%" "%_TEMP%"

endlocal
exit /B

选择了以上所有示例文件内容,以便您可以轻松地使用它们并查看使用选项 /X/E 以及加倍路径分隔符时的差异 \与否。