批处理脚本在文件名与模式列表不匹配时删除文件



我想删除目录中的所有文件,除了名称与特定模式匹配的文件。此目录中文件类型的典型示例如下:

  • 书签.xml ----删除
  • 下载元.xml ----删除
  • 日志文件.log ----删除
  • 1745388844.idx----删除
  • TS1.c.泡菜----删除
  • TS1.prm.bak ----删除
  • !清除.bat ----保持
  • .gitignore ----Keep
  • BookFlight.c ----保留
  • 检查行程.c----保留
  • combined_TS1.c----保持
  • pre_cci.c ----保留
  • TS1.prm ----保持
  • TS1.usr ----保留
  • vuser_end.c ----保留
  • vuser_init.c ----保持
  • globals.h ----Keep
  • 脚本上传元数据.xml ----保留

我想将带有名称的文件保存在模式列表中:

list_to_ignore = ["!clear.bat", ".gitignore", "*.usr", "default.cfg", 
"default.usp", "*.c", "*lobals.h", "*custom_body.h", 
"*body_variables.txt", "*loadMetadata.xml", "*.prm" ]

例如:

  • 文件TS2.c.pickle与列表中的任何项目都不匹配,因为它以 .pickle 扩展名结尾。应将其删除。

  • 文件somefile.c匹配"*.c"模式,因为它以 .c 结尾。它应该被保留。

  • 文件元数据.xml不匹配任何模式,因为它在开头缺少前缀"load"。应将其删除。

  • 文件 Globals.h 匹配 ">lobals.h模式。它应该被保留。

这是我尝试过的:

@echo off
FOR /d %%a in ("./*") DO rd "%%a" /q /s
FOR %%i in (*.*) DO ^
if not "%%i"=="!clear.bat" ^
if not "%%i"==".gitignore" ^
if not "%%i"=="*.usr" ^
if not "%%i"=="default.cfg" ^
if not "%%i"=="default.usp" ^
if not "%%i"=="*.c" ^
if not "%%i"=="*lobals.h" ^
if not "%%i"=="*custom_body.h" ^
if not "%%i"=="*body_variables.txt" ^
if not "%%i"=="*ploadMetadata.xml" ^
if not "%%i"=="*.prm" ^
DEL /s /q "%%i"
pause

以下是本地目录中所有文件的列表,带有复选标记

希望这是有道理的。如果这不是一个合适的问题,请告诉我。

非常感谢

这可以使用批处理文件中的以下命令行来完成:

@for /F "eol=| delims=" %%I in ('dir "%~dp0" /A-D /B 2^>nul ^| %SystemRoot%System32findstr.exe /I /L /X /V /C:"!clear.bat" /C:".gitignore" /C:"BookFlight.c" /C:"CheckItinerary.c" /C:"combined_TS1.c" /C:"pre_cci.c" /C:"TS1.prm" /C:"TS1.usr" /C:"vuser_end.c" /C:"vuser_init.c" /C:"globals.h" /C:"ScriptUploadMetadata.xml" /C:"%~nx0"') do @del /A /F "%~dp0%%I"

此命令行导致在后台启动另一个命令进程,%ComSpec% /c'之间的命令行追加为附加参数。因此,在安装Windows的情况下执行C:WindowsC:TempTest.bat批处理文件的完整限定文件名:

C:WindowsSystem32cmd.exe /c dir "C:Temp" /A-D /B 2>nul | C:WindowsSystem32findstr.exe /I /L /X /V /C:"!clear.bat" /C:".gitignore" /C:"BookFlight.c" /C:"CheckItinerary.c" /C:"combined_TS1.c" /C:"pre_cci.c" /C:"TS1.prm" /C:"TS1.usr" /C:"vuser_end.c" /C:"vuser_init.c" /C:"globals.h" /C:"ScriptUploadMetadata.xml" /C:"Test.bat"

用于处理标准输出的DIR输出(标准输出)

  • 由于选项/A-D(属性不是目录),只是文件名
  • 匹配默认通配符模式*(任何文件名)
  • 在指定的目录C:Temp中找到
  • 裸格式,因为选项/B这意味着只是文件名和文件扩展名。

在这种情况下,命令DIR实际上不可能输出错误消息,因为找不到与这些条件匹配的目录条目来处理STDERR(标准错误),因为此目录中必须有批处理文件。但是2>nul会重定向此错误消息以处理在后台启动的命令进程的STDERR以禁止它。

DIR的输出通过|重定向到FINDSTR 的 STDIN(标准输入),后者搜索

  • 由于选项/I不区分大小写
  • 从字面上看,因为选项/L
  • 对于由于选项/X而完全匹配的行
  • 使用选项指定的搜索字符串之一/C:
  • 和输出来处理后台命令的STDOUT处理反转结果,因为选项/V这意味着所有行都不完全是任何搜索的字符串。

另请阅读有关使用命令重定向运算符的Microsoft文章,了解2>nul|的说明。当 Windows 命令解释器在执行命令 FOR 之前处理此命令行时,重定向运算符>|必须使用插入符号^转义,以便在执行命令FOR之前将此命令行解释为文字字符,该命令执行嵌入的dir命令行,findstr使用在后台启动的单独命令进程。

FOR捕获输出以处理后台命令进程的STDOUT,并在启动后逐行处理此输出,cmd.exe在完成命令行执行后终止自身。

FOR跳过此处未出现的所有空行。FOR接下来将使用字符普通空格和水平制表符作为字符串分隔符将每行拆分为子字符串。FOR将忽略第一个子字符串上的行,以;开头是行字符的默认结尾。否则,只有第一个空格/制表符分隔的字符串将被分配给循环变量I以进行进一步处理。

此处不需要这种换行行为,因为文件名可以包含一个或多个空格,并且可以在 0 或多个前导空格之后以分号开头。出于这个原因,选项eol=|用于将竖线定义为任何文件名都不能包含的行尾字符,选项delims=用于定义字符串分隔符的空列表,以关闭将文件名拆分为子字符串。

因此,DIR输出的每个文件名不是指定为FINDSTR搜索字符串的字符串之一,将完全分配给循环变量I并且FOR执行命令DEL,该命令删除文件,该命令独立于隐藏文件,因为使用选项/A,甚至由于选项/F而成为只读文件。

重写的命令行,以使用带有正则表达式的FINDSTR来筛选出与搜索模式之一匹配的文件名:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BatchFileName=%~nx0"
set "BatchFileName=%BatchFileName:.=.%"
for /F "eol=| delims=" %%I in ('dir "%~dp0" /A-D /B 2^>nul ^| %SystemRoot%System32findstr.exe /I /R /X /V /C:"!clear.bat" /C:".gitignore" /C:"^.*.usr" /C:"default.cfg" /C:"default.usp" /C:"^.*.c" /C:"^.*lobals.h" /C:"^.*custom_body.h" /C:"^.*body_variables.txt" /C:"^.*ploadMetadata.xml" /C:"^.*.prm" /C:"%BatchFileName%"') do @del /A /F "%~dp0%%I"
endlocal

注意:FINDSTR选项/R用于正则表达式搜索,而不是/L,正则表达式搜索要求.转义解释为文字字符,*修改为^.*以匹配第 0 行开头的任何字符或更多次。

对于不包含空格字符的批处理文件名,也可以通过使用:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BatchFileName=%~nx0"
set "BatchFileName=%BatchFileName:.=.%"
for /F "eol=| delims=" %%I in ('dir "%~dp0" /A-D /B 2^>nul ^| %SystemRoot%System32findstr.exe /I /R /X /V "!clear.bat .gitignore ^.*.usr default.cfg default.usp ^.*.c ^.*lobals.h ^.*custom_body.h ^.*body_variables.txt ^.*ploadMetadata.xml ^.*.prm %BatchFileName%"') do @del /A /F "%~dp0%%I"
endlocal

FINDSTR将仅使用"..."指定的搜索字符串中的空格解释为 OR 表达式,而使用/C:"..."指定的搜索字符串中的空格按字面解释为空格字符。

要了解使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,然后完整而仔细地阅读每个命令的显示帮助页面。

  • call /?......解释%~dp0...参数 0 的驱动器和路径,始终是 Windows 命令处理器当前执行的批处理文件的完整路径,并且始终以反斜杠和%~nx0结尾......带有批处理文件扩展名的文件名。
  • del /?
  • dir /?
  • endlocal /?
  • findstr /?
  • for /?
  • set /?
  • setlocal /?

根据您提供的信息以及.gitignore中提供的信息,我建议您使用忽略列表,添加一些您自己的列表。

我假设!clear.bat是您正在寻求帮助的文件,所以我会将其作为其内容。

@CD /D "%~dp0"
@For /F "EOL=? Delims=" %%G In ('Dir /B /S /A:D') Do @RD /S /Q "%%G"
@(Del /A /F /Q *.bak *.c.pickle *.ci *.dat *.db *.idx *.sdf combined_*.c ^
Breakpoints.xml CompilerLogMetadata.xml logfile.log mdrv.log mdrv_cmd.txt ^
options.txt output.txt pre_cci.c ReplaySummaryReport.xml ThumbnailsCache.tmp ^
UserTasks.xml)

如前所述,您会注意到,虽然您希望保留.c文件,但combined_*.cpre_cci.c都是在编译期间创建的,不是必需的。如果您希望保留它们,请根据需要从行35中删除它们。

这个命令的帮助可能会让你走上正确的方向 findstr/?

/G:StringsFile从文件中获取搜索字符串(/代表控制台)。

您需要将所有字符串放入一个文件中并使用以下语法:

findstr /G:"Filter_File.txt"

/V Print only lines that do NOT contain a match.

/I Case-insensitive search.

所以你可以写这样的东西:

@echo off
Title Batch script delete files when file name does not match list of patterns
Set "Files2Keep=%~dp0Files2Keep.txt"
>"%Files2Keep%" (
echo    !clear.bat
echo    .gitignore
echo    BookFlight.c
echo    CheckItinerary.c
echo    combined_TS1.c
echo    pre_cci.c
echo    TS1.prm
echo    TS1.usr
echo    vuser_end.c
echo    vuser_init.c
echo    globals.h
echo    ScriptUploadMetadata.xml
)
@for /f "delims=" %%a in ('dir /b /a:-d ^|findstr /I /V /G:"%Files2Keep%"') do ( 
If "%%~nxa" NEQ "%~nx0" (
IF "%%~dpnxa" NEQ "%Files2Keep%" (
Echo DEL /s /q "%%a"
)
)
)
pause

相关内容

最新更新