我在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=%%f\com-v.dat
echo !COM_V!
set COM_M=%%f\com-M.dat
echo !COM_M!
::some data process
)
chdir
popd
)
endlocal
我希望我可以回显所有变量。
答案 0 :(得分:1)
有很多错误。我建议打开命令提示符窗口,运行for /?
并阅读命令 FOR 的输出帮助/文档。另请参阅Microsoft文档,以了解Windows Commands甚至更好的SS64.com - A-Z index of the Windows CMD command line。
@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=%%I\com-v.dat"
echo !COM_V!
set "COM_M=%%I\com-M.dat"
echo !COM_M!
rem some data process
)
popd
)
endlocal
阅读this answer,以获取有关命令 SETLOCAL 和 ENDLOCAL 的详细信息。第二行是必需的,因为在命令块中定义的环境变量也从该命令块中引用。缺点是由于启用了delayed expansion,此批处理文件无法正确处理包含一个或多个!
的目录和文件名。
最好在结尾DisableDelayedExpansion
的第二行而不是EnableDelayedExpansion
,并且不要定义环境变量COM_DATA
,COM_V
和COM_M
,但在未显示的代码%%J
,%%I\com-v.dat
和%%I\com-M.dat
中使用。
外部 FOR 循环在当前目录中搜索任何未隐藏的子目录,并在每个找到的子目录上运行外部命令块中的命令。当前目录可以是任何目录。它不能是包含批处理文件的目录。使用而不是*
字符串"%~dp0*"
来遍历批处理文件目录中的非隐藏子目录,而与启动批处理文件时的当前目录无关。仅使用*
时,不带路径的目录名将分配给循环变量I
。使用"%~dp0*"
时,具有完整路径的目录名将分配给循环变量I
。
pushd "%%I"
将当前子目录作为执行批处理文件的命令进程的当前目录。
内部 FOR 循环在当前目录中搜索与指定的通配符模式匹配的非隐藏文件,并将没有路径的文件名分配给循环变量J
。
请勿使用::
作为注释。这是无效的标签。命令块内的有效和无效标签会导致命令块执行时出现意外行为。有命令 REM (备注)在批处理文件中写注释。请注意,带有命令 REM 的命令行是与其他命令行一样的命令行,因此也由cmd.exe
处理和执行,如How does the Windows Command Interpreter (CMD.EXE) parse scripts?
popd
恢复初始当前目录,然后继续使用外部 FOR 处理批处理文件。
endlocal
恢复初始环境,这意味着setlocal
之后定义或修改的所有环境变量都将被丢弃,初始环境变量列表将被恢复,并且在启动批处理文件和命令的初始状态时将恢复初始的当前目录扩展和延迟的环境变量扩展。
For使用两次命令 DIR 来完成同一批处理文件,以遍历捕获的目录和文件名列表,从而可以通过内部< strong> FOR 循环,并通过内部或外部 FOR 循环将子目录添加到当前或批处理文件目录中。
*.a*.dat
要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。
@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=%%I\com-v.dat"
echo !COM_V!
set "COM_M=%%I\com-M.dat"
echo !COM_M!
rem some data process
)
popd
)
endlocal
dir /?
echo /?
endlocal /?
for /?
popd /?
pushd /?
rem /?
set /?
阅读有关Using Command Redirection Operators的Microsoft文章,以获取setlocal /?
的解释。当Windows命令解释器在执行命令之前处理此命令行时,重定向操作符2>nul
必须在 FOR 命令行上使用脱字符号>
进行转义,才能被解释为文字字符。 FOR ,它在以^
为背景的单独命令过程中执行嵌入式dir
命令行。
答案 1 :(得分:0)
此示例与您提供的代码意图相同,基于您提供的信息:
@Echo Off
Set "COM_DATA=%%B"
Set "COM_V=%%A\com-v.dat"
Set "COM_M=%%A\com-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
和{{1} }行。我没有使用Rem
和PushD
命令,因为给出了所提供的信息,我认为没有理由使用它们。我还在PopD
块之外设置了变量,因为这意味着它们只需要设置一次,而不是每次迭代都设置 ,并且消除了延迟扩展的需要。
如果您的过程代码需要完整路径,则可能需要考虑将For
的每个实例更改为%%A
。