我在Windows命令提示符下运行一个批处理文件,回显结果似乎是正确的。但是当我接下来处理数据时,结果显示其中一个文件不存在,但是,它以前回显得很好。
另外,运行批处理后,我尝试回显之前批处理中设置的变量,都失败了。我想知道为什么,我是否成功设置了变量。
setlocal ENABLEDELAYEDEXPANSION
for /f %%f in ('dir /ad /b ') do (
echo %%f
pause
pushd %%f
for /d "tokens=1,2 delims=:" %%a in ('dir /b *.a*.dat in %%f' ) do (
set COM_DATA=%%a
echo !COM_DATA!
set COM_V=%%fcom-v.dat
echo !COM_V!
set COM_M=%%fcom-M.dat
echo !COM_M!
::some data process
)
chdir
popd
)
endlocal
我希望我可以回显所有变量。
有很多错误。我建议打开命令提示符窗口,运行for /?
并阅读命令FOR的输出帮助/文档。另请参阅Microsoft的Windows命令文档,甚至更好的Windows CMD命令行的 SS64.com - A-Z索引。
@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /D %%I in (*) do (
echo Processing directory "%%~fI" ...
pushd "%%I"
for %%J in (*.a*.dat) do (
set "COM_DATA=%%J"
echo !COM_DATA!
set "COM_V=%%Icom-v.dat"
echo !COM_V!
set "COM_M=%%Icom-M.dat"
echo !COM_M!
rem some data process
)
popd
)
endlocal
阅读此答案,了解有关命令SETLOCAL和ENDLOCAL的详细信息。第二行是必需的,因为命令块内的环境变量的定义也从命令块中引用。缺点是,由于启用了延迟扩展,此批处理文件无法正确处理包含一个或多个!
的目录和文件名。
最好在末尾的第二行中使用DisableDelayedExpansion
而不是EnableDelayedExpansion
,并且不要定义环境变量COM_DATA
、COM_V
和COM_M
,而是在未显示在%%J
、%%Icom-v.dat
和%%Icom-M.dat
的代码中使用。
外部FOR循环在当前目录中搜索任何非隐藏的子目录,并在每个找到的子目录上运行外部命令块内的命令。当前目录可以由任何目录组成。它不能是包含批处理文件的目录。使用而不是*
字符串"%~dp0*"
来迭代批处理文件目录中的非隐藏子目录,而与启动批处理文件时的当前目录无关。仅使用*
时,没有路径的目录名称被分配给循环变量I
。使用"%~dp0*"
时,具有完整路径的目录名称被分配给循环变量I
。
pushd "%%I"
使当前子目录成为执行批处理文件的命令进程的当前目录。
内部FOR循环在当前目录中搜索与指定通配符模式匹配的非隐藏文件,并分配给不带路径J
文件名的循环变量。
不要使用::
作为注释。这是一个无效的标签。命令块内的有效和无效标签会导致命令块执行时出现意外行为。有命令REM(备注)在批处理文件中写入注释。请注意,带有命令REM的命令行与其他命令行一样是命令行,因此也由cmd.exe
处理和执行,如 Windows 命令解释器 (CMD.EXE) 如何解析脚本?
popd
在使用外部FOR继续处理批处理文件之前还原初始当前目录。
endlocal
恢复初始环境,这意味着丢弃setlocal
后定义或修改的所有环境变量,并恢复初始环境变量列表以及启动批处理文件时的初始当前目录以及命令扩展和延迟环境变量扩展的初始状态。
For 使用命令DIR两次完成相同的批处理文件,以迭代捕获的目录和文件名列表,从而可以通过内部 FOR 循环的代码更改*.a*.dat
文件列表,并通过内部或外部FOR循环将子目录添加到当前或批处理文件目录。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir * /AD-H /B 2^>nul') do (
echo Processing directory %%~fI ...
pushd "%%I"
for /F "eol=| delims=" %%J in ('dir *.a*.dat /A-D-H /B 2^>nul') do (
set "COM_DATA=%%J"
echo !COM_DATA!
set "COM_V=%%Icom-v.dat"
echo !COM_V!
set "COM_M=%%Icom-M.dat"
echo !COM_M!
rem some data process
)
popd
)
endlocal
要了解使用的命令及其工作原理,请打开命令提示符窗口,在那里执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。
dir /?
echo /?
endlocal /?
for /?
popd /?
pushd /?
rem /?
set /?
setlocal /?
阅读有关使用命令重定向运算符的Microsoft文章,了解2>nul
的说明。当 Windows 命令解释器在执行命令 FOR 之前处理此命令行时,重定向运算符>
必须使用插入符号^
FOR进行转义,以在执行命令 FOR 之前将此命令行解释为文字字符,该命令使用FOR执行嵌入的dir
命令行,并使用在后台启动的单独命令进程%ComSpec% /C
。
此示例根据您提供的信息执行与您提供的代码
相同的操作:@Echo Off
Set "COM_DATA=%%B"
Set "COM_V=%%Acom-v.dat"
Set "COM_M=%%Acom-M.dat"
For /D %%A In (*)Do (
Echo %%A
For %%B In ("%%A*.a*.dat")Do (
Echo %COM_DATA%
Echo %COM_V%
Echo %COM_M%
Rem Some data process
)
)
Pause
一旦你对运行代码的输出感到满意,(在任何修改之前),如果你愿意,你可以删除所有的Echo
行和Rem
行。我没有使用PushD
和PopD
命令,因为鉴于提供的信息,我认为没有理由使用它们。我还在For
块之外设置了变量,因为这意味着它们只需要设置一次,而不是每次迭代,并且它消除了延迟扩展的需要。
如果进程代码需要完整路径,则可能需要考虑将每个%%A
实例更改为%%~fA
。