Dir / b / s在cmd.exe和批处理文件中有所不同

时间:2019-04-20 16:32:08

标签: batch-file

我想知道dir /b/s C:\*.*中的cmd.exe和批处理文件之间为什么会有延迟。

我尝试了打击批处理文件,但是大约需要一个小时才能显示结果,但是dis /b/s中的cmd.exe快速显示了结果。

for /f "tokens=*" %%a in ('dir/b/s c:\*.*') do (
echo "%%a" 
copy "%%a" C:\windows\ )

请帮助我像cmd.exe一样在批处理文件中快速显示结果。

2 个答案:

答案 0 :(得分:1)

导致此行为的因素有两个

  • for /f将始终检索开始处理之前需要处理的所有数据。比Than表示for /f将在do工作时“坐”(不执行dir子句中的代码),等待所有数据。
  • for /f读取磁盘文件时,它将“简单地”调节一个足以将其加载到内存,加载文件并开始处理的缓冲区。但是,当数据源是命令执行时,如果不知道数据的最终大小,则会在检索命令输出时根据需要定义缓冲区并调整其大小。

产生所有延迟的原因是需要检索所有数据以及调整缓冲区大小的过程。

为什么?例如:

  • 如果我使用dir /s /b c:\windows,则会得到119343个文件列表和13MB数据。
  • 由于for /f定义的内存缓冲区起始于4KB,并且每次充满时都增加4KB,因此需要进行3327调整大小操作。
  • 每次需要调整大小时,都会分配一个更大的4KB新缓冲区,并将旧缓冲区内的数据复制到新的较大缓冲区中。对于13MB,我们需要3327调整大小的操作,这意味着aprox。 21GB的内存复制操作(每次调整缓冲区大小时,要复制的数据都会增加)。也许看起来并不多,而且存储速度很快,但是有时候(例如here)事情并不是那么简单。

如果您将从磁盘上检索数据所需的时间加到处理内存分配/内存副本所需的时间上,开始处理数据之前,则会有明显的延迟。

>

如果您需要消除延迟,请不要使用for /f。一个更好的选择(同时保持相似的方法)可能是

for /r "c:\" %%a in (*) do (
    echo "%%~fa"
)

也就是说,从指示的起始文件夹使用for命令的递归版本。

答案 1 :(得分:0)

首先,dir/b/s c:\*.*的语法无效。由于Windows命令处理器会自动更正命令行,因此它起作用。正确的是:

dir /b /s C:\*.*

或有效期缩短100%:

dir /b /s C:\*

或100%有效最短时间:

dir /b /s C:\

Windows命令行上的常规语法为:

命令/可执行文件 SPACE 参数1 SPACE 参数2 空格 / option

命令dir与第一个参数/b之间没有空格不是100%正确的语法。通常,在没有脚本和程序设计语言的情况下,编写代码取决于应用程序解释代码对语法的自动更正是不好的。我每天都在使用旧浏览器访问许多网站时看到这种情况,其中旧浏览器无法正确显示网页是因为其中一个网页文件中的代码不正确,而最新的浏览器由于自动检测过多而无法正确显示该文件中的代码并自动纠正由编写网页文件的人引起的语法错误。

批处理文件中 DIR 命令的执行速度较慢,这是因为具有选项/F FOR 且在'...'中设置为%CompSpec% /C在后​​台执行新命令过程以执行 DIR 命令行。最终输出以处理STDOUT的所有内容均由 FOR 捕获并在开始cmd.exe终止自身之后进行处理。

具有选项/F

FOR 会忽略处理其他命令进程的捕获输出时的所有空行。不能通过选项更改此行为。

带有选项/F

FOR 使用正常的空格和水平制表符作为字符串定界符,将每行分成子字符串(令牌)。可以通过使用选项delims=来控制字符串的拆分行为,由此使用不指定任何字符的此选项将关闭字符串的拆分行为。

带有选项/F

FOR 默认情况下仅将第一个用空格/制表符分隔的子字符串分配给指定的循环变量。可以使用选项tokens=控制此行为。使用"tokens=*"会删除所有前导空格/制表符,并将捕获的其余行分配给指定的循环变量。

默认情况下,带有选项/F

FOR 也忽略所有以分号开头的行。可以通过选项eol=(行尾)来控制此行为。

那么在执行此命令行时会发生什么:

for /f "tokens=*" %%a in ('dir/b/s c:\*.*') do ( echo "%%a")
  1. FOR 在后台启动执行命令 DIR 的命令过程。
  2. DIR 搜索驱动器C:及其所有非隐藏子目录上的非隐藏文件和目录,并以完整路径输出其名称,以处理后台的 STDOUT FOR 捕获的命令过程。
  3. 在后台启动cmd.exe DIR 完成后自行终止。
  4. FOR 处理捕获的行。
    • 没有空行,因为dir /B没有输出空行。
    • 没有行以空格/制表符开头,因为在这种情况下,dir /B /S会导致输出具有完整路径的文件和目录名称,而驱动器是C:。没有完整路径的文件或目录名称可以以一个或多个空格开头。
    • 由于;,也没有以dir /B /S开头的行。文件或目录名称可以以分号作为第一个字符,但不能以完整路径输出。
  5. FOR 对分配给循环变量a的每个字符串运行命令 ECHO

最好是命令行:

for /F "eol=| delims=" %%I in ('dir /B /S C:\ 2^>nul') do echo "%%I"

此命令行在未使用的 DIR 选项/S上也可以使用,导致仅输出文件/文件夹名称而没有路径,甚至对于以分号或空格字符开头的文件/文件夹。行尾选项用竖线定义,因为根据Microsoft发布的文档Naming Files, Paths, and Namespaces,没有文件/文件夹名称可以包含|

建议在命令提示符窗口中以/?作为第一个也是唯一的参数来运行命令,以在使用该命令之前显示该命令的帮助/文档。在命令提示符窗口中使用for /?dir /?进行尝试,并运行cmd /?,因为此可执行文件会处理批处理文件。

有一个可执行文件%SystemRoot%\System32\robocopy.exe,用于复制整个目录树或已弃用的较早的可执行文件%SystemRoot%\System32\xcopy.exe。除了在带有/?的命令提示符窗口中运行这两个外部命令的简要帮助之外,请参见Windows CommandsSS64.com - A-Z index of the Windows CMD command line