使用 for 循环(批处理脚本)从 Windows XP 中的目录输出中提取详细信息

Extract details from dir output in Windows XP using for loop (batch script)

我正在尝试理解批处理脚本中的 for 循环;特别是 skiptokens 参数。我在 followed by this nice .

中找到了一个很好的例子

我想看看如何从 Windows XP 中的 dir 中提取日期和时间 [=17] =] 输出(参见下面的示例输出)与 Windows 7. 换句话说,如何在 Windows XP 中提取特定文件夹的创建日期。

来自上述链接的以下修改代码在 Windows 7 中正确提取了 DIR 的日期和时间,但在 Windows XP 中失败(即提取其他字符):

SETLOCAL ENABLEDELAYEDEXPANSION
set "path_of_folder=C:\folderA\folderB"

for /f "skip=5 tokens=1,2,4 delims= " %%a in (
 'dir /ad /tc "%path_of_folder%\."') do IF "%%c"=="." (
  set "dt=%%a"
  set dirdate=%%a
  set dirtime=%%b
  echo !dirdate!, !dirtime!
  set dirday=!dirdate:~0,2!
  echo !dirday!
)

Windows 7 命令提示符中的 dir 命令输出类似于:

   Directory of C:\Windows    
12/21/2016  12:56    <DIR>          . 
12/21/2016  12:56    <DIR>          .. 
09/18/2017  07.42            678    config

Windows XP 中,命令提示符中的 dir 命令输出类似于:

   Directory of C:\WINDOWS

12/21/2016  12:56 PM    <DIR>          . 
12/21/2016  12:56 PM    <DIR>          .. 
09/18/2017  07.42 PM            678    config

唯一的区别(据我所知)是 PM 列 (?) 它在 Windows 7 中不存在,但在 [=49 中存在=] XP.

我知道这可能是一个微不足道的问题,但我是批处理脚本的新手,看到一个使用复杂 for 循环的具体示例将有助于我的理解。 假设使用延迟扩展

dir 命令时间格式取决于控制面板中的设置。 要获得独立于控制面板设置的目录创建时间,您可以使用 dirtimejs.bat:

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set "path_of_folder=C:\folderA\folderB"

for /f "tokens=1* delims=:" %%a in ('dirtimejs.bat "%path_of_folder%" ^| find "Created :"') do (
    for /f "tokens=1,2,3,4,5,6 delims=:- " %%A in ("%%b") do (
        echo dir year: %%A
        echo dir month : %%B
        echo dir day :  %%C 
    )
)

要查看什么信息 dirtimejs 尝试使用 dirtimejs.bat "%path_of_folder%"

windows 列表中提供的时间格式取决于用户设置。不幸的是,您发布的是经过篡改的列表,而不是实际数据(证据 - 列出的每个数据元素的时间和日期完全相同,禁止 PM 标志,尽管据称它们在不同的系统上)

修复:简单的​​方法是调整系统的 UI 设置 - 在两台机器上使用相同的格式。

应对代码:

@ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION

SET "required_format=12"

for /f "tokens=1-5 delims= " %%a in (
 'type q44964366.txt^|FINDSTR /L /E /c:" ."') do (
 set "dt=%%a"
 set dirdate=%%a
 set dirtime=%%b
 IF "%%e"=="." (
  REM reading 12-hr format - convert to 24-hr
  IF "!dirtime:~0,2!"=="12" (
   IF /i "%%c"=="PM" (
    SET "dirtime=12!dirtime:~2!"
   ) else (
    SET "dirtime=00!dirtime:~2!"
   )
  ) ELSE (
   IF /i "%%c"=="PM" (
    SET /a $=2!dirtime:~0,2!-88
    SET "dirtime=!$:~-2!!dirtime:~2!"
   )
  )
 ) 
 REM else is in 24-hr format already
 IF %required_format%==12 (
  SET /a $=1!dirtime:~0,2!
  IF !$!==100 SET "dirtime=12!dirtime:~2! AM"
  IF !$! gtr 100 IF !$! leq 111 SET "dirtime=!dirtime! AM"
  IF !$!==112 SET "dirtime=12!dirtime:~2! PM"
  IF !$! gtr 112 SET /a $=$-12&SET "dirtime=!$:~-2!!dirtime:~2! PM"
 )
 echo !dirdate!, !dirtime!
 set dirday=!dirdate:~0,2!
 echo !dirday!
)

GOTO :EOF

为了测试,我使用了一个包含典型 dir 行的文件。您需要用原来的 dir 命令替换 type q44964366.txt

竖线 (|) 之前的插入符号 (^) 告诉 cmd 竖线是要执行的命令的一部分。管道输出数据(来自 dir 命令)并用常量字符串填充所有 /L 字面上 /E 结束 /c:"string" 的行 - 请注意这是 Space. 它巧妙地过滤掉了 . 目录名以外的所有内容,因此继续分析 [=22] 上的处理=] 名称 - 这是 findstr 允许通过的唯一名称...

既然我们现在使用的是tokens=1-5,那么如果线路是12小时格式,那么%%e只能设置为.,否则是24小时格式。要转换为 24 小时格式,我们需要查看 %%c 是否为 PM(否则为 AM),如果是,则将小时数加 12 except for 12 in the hours digits, 当我们需要将 hours digits 设置为 00 for AM12 for PM.

这些转换中的最后一个很明显,但对于非 12:xx PM,我们采用两个小时数字并将它们附加到 2,从而形成一个字符串 2hhcmd 数学将任何以 0 开头的数字视为八进制,因此 09:xx 会产生错误。 209 它可以应付十进制。从中减去 88,即 100-12。这将生成一个 3 位数字,批处理将其视为字符串,我们需要最后 2 个字符。

您未指定首选格式,因此我们可能需要转换为 12 小时制(在代码中,如果已在 required_format 中选择)

在12小时模式下,如果时间是下午,我们需要减去12小时,并注意特殊值12:xx00:xx。这也是通过将时间的前 2 位数字串成一个常量以形成一个漂亮的 3 位十进制值来完成的。 100 表示 12:xx AM 112 表示 12:xx PM 101-111 表示我们只需要添加 AM 如果它大于 112(例如 15:xx 24 小时格式)那么我们需要减去 12 并将结果的最后 2 个字符作为小时数字;然后添加 PM.

完成。


type q44964366.txt 由原来的

中的 dir 命令替换

'dir /ad /tc "%path_of_folder%."^|FINDSTR /L /E /c:" ."') 做 (

不同的 OS 不是你的问题,不幸的是 DIR 命令的输出不一致,它可能因用户而异 。最简单的解决方法是使用另一种方法来检索您希望捕获的数据, 使用 JScript,以下答案使用另一个内置工具,WMIC.exe.

@Echo Off

Set "_dp=C:\folderA\folderB"

Echo  Directory of %_dp% & Echo(
For %%A In ("%_dp%\*") Do (Set "_pf=%%~fA"
    SetLocal EnableDelayedExpansion
    For /F "UseBackQ Skip=1 Delims=" %%B In (`WMIC DataFile Where^
        "Drive='%%~dA' And Name='!_pf:\=\!'" Get CreationDate^,FileSize`
    ) Do For /F "Tokens=1-2*" %%C In ("%%~B") Do (Set "_dt=%%~nxC"
        Set "_d=!_dt:~4,2!/!_dt:~6,2!/!_dt:~,4!"
        Set "_t=!_dt:~8,2!:!_dt:~10,2!" & Echo !_d! !_t!    %%D "%%~nxA")
        EndLocal)
Pause


编辑

看来,您正在寻找来自 dir 目录的数据。 (我误以为你指的是 dir 命令).

下面是一些更新的代码以充分反映这一点:

@Echo Off

Set "_dp=C:\folderA\folderB"

Echo  Directory of %_dp% & Echo(
For /D %%A In ("%_dp%\*") Do (Set "_pf=%%~fA"
    SetLocal EnableDelayedExpansion
    For /F "Skip=1 Delims=" %%B In ('
        "WMIC FSDir Where (Drive='%%~dA' And Name='!_pf:\=\!') Get CreationDate"
    ') Do For /F %%C In ("%%~B") Do (Set "_dt=%%~nxC"
        Set "_d=!_dt:~4,2!/!_dt:~6,2!/!_dt:~,4!"
        Set "_t=!_dt:~8,2!:!_dt:~10,2!" & Echo !_d! !_t!    "%%~nxA")
        EndLocal)
Pause


据我所知,第一次在 XP 中 运行 WMIC 可能会有初始化延迟

可以操纵输出布局,正如我所做的那样……