批处理 - Ghost 文件通过 'If Not Exist' 检查
Batch - Ghost File Passing 'If Not Exist' Check
我的代码
下面是一些直接的代码:
- 检查我的目录中是否存在文件
- 运行 for 循环以获取第一个文件名
- 根据文件名做事
- 删除文件
检查目录中是否存在任何其他文件(如果存在,重复,如果不存在,继续)
:MYLOOP
IF NOT EXIST "%mypath%\*.*" GOTO nofile
FOR %%F IN ("%mypath%\*.*") DO (
set filenameWithExt=%%~nxF
set filename=%%~nF
set filepath=%%~pF
)
do other filename specific tasks
del "%mypath%\%filenameWithExt%"
IF NOT EXIST "%mypath%\*.*" GOTO nofile
GOTO MYLOOP
:nofile
我的问题
我反复使用了这段代码,它的效果非常好,但在我最近的使用中,它看起来像是找到了一个 'ghost' 文件。当目录中 no FILES(只有一个归档文件夹)时,上面第 1 步的 if not exist
检查仍然通过。结果,for 循环中的 set
代码导致:
The system cannot find the file specified.
然后它似乎试图删除我的目录,说:
\mypath*, Are you sure (Y/N)?
然后我必须手动终止一个自动批处理。
我的问题
为什么它通过了 if not exist
检查,而不是跳到 :nofile?
我如何解释这个 'ghost' 文件(或者如果它正在检测存档文件夹——我还能如何忽略它)?
if exist
测试在目录中查找 任何内容。
我会重组你的代码:
:MYLOOP
set "found1="
FOR %%F IN ("%mypath%\*.*") DO (
set filenameWithExt=%%~nxF
set filename=%%~nF
set filepath=%%~pF
set "found1=Y"
)
if not defined found1 goto nofile
do other filename specific tasks
del "%mypath%\%filenameWithExt%"
GOTO MYLOOP
:nofile
如果 for
没有找到文件,found1
将保持未定义状态,所以我们转到 :nofile
标签,否则我们有一个文件要处理。删除文件后,回到开头,清除标志并重复...
Windows 内核,因此 Windows 命令解释器也像 *
一样解释通配符模式 *.*
,这意味着任何文件或文件夹。使用通配符模式 *.*
并不意味着必须有名称中带有点的文件(或文件夹)。
因此,使用条件 IF NOT EXIST "%mypath%\*.*"
与使用 IF NOT EXIST "%mypath%\*"
相同。
IF EXIST "%mypath%\*"
常用于批处理文件中,以验证 %mypath%
指定的是文件夹而不是文件,因为此条件检查是否存在文件夹 %mypath%
。如果该文件夹存在,则条件为 true,与该文件夹中文件和文件夹的数量无关。
因此批处理文件顶部的条件不会检查文件夹 %mypath%
中是否至少有 1 个文件,它会检查此文件夹是否根本不存在。
您可以使用以下批处理代码,通过子例程避免使用延迟扩展。
@echo off
for /F "delims=" %%I in ('dir /A-D /B /ON "%mypath%\*" 2^>nul') do call :ProcessFile "%mypath%\%%I"
goto :EOF
:ProcessFile
set "FilenNmeWithExt=%~nx1"
set "FileName=%~n1"
set "FilePath=%~p1"
rem do other filename specific tasks
del "%~1"
goto :EOF
命令FOR执行命令行
dir /A-D /B /ON "%mypath%\*" 2>nul
在后台的单独命令进程中捕获 DIR 的输出以处理 STDOUT.
如果目录根本不存在或不包含任何文件,DIR 将输出一条错误消息来处理 STDERR。通过使用 2>nul
将其重定向到设备 NUL 可以抑制此错误消息。重定向运算符 >
必须在此处使用脱字符 ^
进行转义,以便 Windows 命令解释器在解析整个 FOR 时首先将其解释为文字字符命令行,否则会导致语法错误。
Option /A-D
意味着 DIR 应该输出所有没有设置目录属性的目录条目,即只输出文件,不输出文件夹。 /B
将 DIR 的输出更改为裸格式,这意味着只有文件名而没有任何其他数据。 /ON
导致在 DIR 输出整个列表之前按文件名对列表进行排序。此处实际上不需要此选项。
FOR 现在处理 DIR 的捕获输出。因此,当 FOR 为 运行 时,删除该目录中的文件并不重要。 FOR 处理 DIR.
输出的初始列表
对于每个由 DIR 输出的文件名,执行子例程 ProcessFile
这就像调用另一个具有该名称的批处理文件。传递给子例程的是文件名及其路径。 DIR 仅输出不带路径的文件名,不使用另外 /S
获取指定目录及其所有子目录中所有文件名的列表。
在 FOR 循环之后需要命令 goto :EOF
以避免在 DIR[= 输出所有文件名后跳转到子例程78=] 已处理。
如果上面一行是批处理文件的最后一行,则不需要子例程后的命令goto :EOF
。但是,在像下面的另一个子例程一样添加更多命令行的情况下,通常最好总是以 goto :EOF
结束子例程。对于 Windows 命令解释器,以其标签开头的子程序在文件中的位置并不重要。
我的代码
下面是一些直接的代码:
- 检查我的目录中是否存在文件
- 运行 for 循环以获取第一个文件名
- 根据文件名做事
- 删除文件
检查目录中是否存在任何其他文件(如果存在,重复,如果不存在,继续)
:MYLOOP IF NOT EXIST "%mypath%\*.*" GOTO nofile FOR %%F IN ("%mypath%\*.*") DO ( set filenameWithExt=%%~nxF set filename=%%~nF set filepath=%%~pF ) do other filename specific tasks del "%mypath%\%filenameWithExt%" IF NOT EXIST "%mypath%\*.*" GOTO nofile GOTO MYLOOP :nofile
我的问题
我反复使用了这段代码,它的效果非常好,但在我最近的使用中,它看起来像是找到了一个 'ghost' 文件。当目录中 no FILES(只有一个归档文件夹)时,上面第 1 步的 if not exist
检查仍然通过。结果,for 循环中的 set
代码导致:
The system cannot find the file specified.
然后它似乎试图删除我的目录,说:
\mypath*, Are you sure (Y/N)?
然后我必须手动终止一个自动批处理。
我的问题
为什么它通过了 if not exist
检查,而不是跳到 :nofile?
我如何解释这个 'ghost' 文件(或者如果它正在检测存档文件夹——我还能如何忽略它)?
if exist
测试在目录中查找 任何内容。
我会重组你的代码:
:MYLOOP
set "found1="
FOR %%F IN ("%mypath%\*.*") DO (
set filenameWithExt=%%~nxF
set filename=%%~nF
set filepath=%%~pF
set "found1=Y"
)
if not defined found1 goto nofile
do other filename specific tasks
del "%mypath%\%filenameWithExt%"
GOTO MYLOOP
:nofile
如果 for
没有找到文件,found1
将保持未定义状态,所以我们转到 :nofile
标签,否则我们有一个文件要处理。删除文件后,回到开头,清除标志并重复...
Windows 内核,因此 Windows 命令解释器也像 *
一样解释通配符模式 *.*
,这意味着任何文件或文件夹。使用通配符模式 *.*
并不意味着必须有名称中带有点的文件(或文件夹)。
因此,使用条件 IF NOT EXIST "%mypath%\*.*"
与使用 IF NOT EXIST "%mypath%\*"
相同。
IF EXIST "%mypath%\*"
常用于批处理文件中,以验证 %mypath%
指定的是文件夹而不是文件,因为此条件检查是否存在文件夹 %mypath%
。如果该文件夹存在,则条件为 true,与该文件夹中文件和文件夹的数量无关。
因此批处理文件顶部的条件不会检查文件夹 %mypath%
中是否至少有 1 个文件,它会检查此文件夹是否根本不存在。
您可以使用以下批处理代码,通过子例程避免使用延迟扩展。
@echo off
for /F "delims=" %%I in ('dir /A-D /B /ON "%mypath%\*" 2^>nul') do call :ProcessFile "%mypath%\%%I"
goto :EOF
:ProcessFile
set "FilenNmeWithExt=%~nx1"
set "FileName=%~n1"
set "FilePath=%~p1"
rem do other filename specific tasks
del "%~1"
goto :EOF
命令FOR执行命令行
dir /A-D /B /ON "%mypath%\*" 2>nul
在后台的单独命令进程中捕获 DIR 的输出以处理 STDOUT.
如果目录根本不存在或不包含任何文件,DIR 将输出一条错误消息来处理 STDERR。通过使用 2>nul
将其重定向到设备 NUL 可以抑制此错误消息。重定向运算符 >
必须在此处使用脱字符 ^
进行转义,以便 Windows 命令解释器在解析整个 FOR 时首先将其解释为文字字符命令行,否则会导致语法错误。
Option /A-D
意味着 DIR 应该输出所有没有设置目录属性的目录条目,即只输出文件,不输出文件夹。 /B
将 DIR 的输出更改为裸格式,这意味着只有文件名而没有任何其他数据。 /ON
导致在 DIR 输出整个列表之前按文件名对列表进行排序。此处实际上不需要此选项。
FOR 现在处理 DIR 的捕获输出。因此,当 FOR 为 运行 时,删除该目录中的文件并不重要。 FOR 处理 DIR.
输出的初始列表对于每个由 DIR 输出的文件名,执行子例程 ProcessFile
这就像调用另一个具有该名称的批处理文件。传递给子例程的是文件名及其路径。 DIR 仅输出不带路径的文件名,不使用另外 /S
获取指定目录及其所有子目录中所有文件名的列表。
在 FOR 循环之后需要命令 goto :EOF
以避免在 DIR[= 输出所有文件名后跳转到子例程78=] 已处理。
如果上面一行是批处理文件的最后一行,则不需要子例程后的命令goto :EOF
。但是,在像下面的另一个子例程一样添加更多命令行的情况下,通常最好总是以 goto :EOF
结束子例程。对于 Windows 命令解释器,以其标签开头的子程序在文件中的位置并不重要。