【问题标题】:Extract details from dir output in Windows XP using for loop (batch script)使用 for 循环(批处理脚本)从 Windows XP 中的 dir 输出中提取详细信息
【发布时间】:2017-12-11 08:57:54
【问题描述】:

我正在尝试理解批处理脚本中的for 循环;特别是 skip 和 tokens 参数。我在这个answer 中找到了一个很好的例子,然后是这个很好的read。

我想看看如何从 Windows XP 中的 dir 中提取日期和时间,与 Windows 7 相比,dir 的输出(见下面的示例输出)略有不同. 换句话说,如何提取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 中不存在,但在 Windows XP 中存在。

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

【问题讨论】:

  • 这取决于控制面板中的时间设置。您可以更改它们或使用 VBScript 或 Jscript。
  • check this 它始终以与控制面板设置无关的相同格式打印文件夹时间。
  • @npocmaka 感谢您的注释,但我无法从 VBScript 或 Jscript 更改它们。这是让我看一个具体的例子(即如何修改代码以在 XP 的 dir 输出下工作,如问题所示)。
  • 我发给你的链接是一个打包在bat文件中的jscript,所以调用它很容易。如果需要,您可以更改格式。告诉我你需要的格式,我会举个例子......
  • @npocmaka 抱歉刚刚注意到链接。它非常有用,但为了让我了解for 循环,通过像上面这样的特定示例,这对我没有用。

标签: batch-file for-loop windows-7 windows-xp


【解决方案1】:

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%"。

【讨论】:

  • 确实非常有用,但我更喜欢一个适用于 XP dir 输出的示例(修改我提供的适用于 Windows 7 的代码),不使用任何 3rd 方代码,如 ditimejs.bat
  • @nk-fford - 这将适用于 XP - jscript 是寡妇脚本主机的一部分,自 Windows NT 以来默认安装在每台 Windows 机器上。由于dirtimejs.bat 不是二进制文件,您可以复制、更改和使用它。
  • 我理解并且确实提供了修复。但是,我的问题的本质是查看示例代码实现以帮助我理解。这就是为什么我希望有人会提供。无论哪种方式,我都感谢您的回应。
【解决方案2】:

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 . 它巧妙地过滤掉除. 目录名之外的所有目录名,因此继续对. 名称的处理进行分析 - 这是findstr 允许通过的唯一名称...

既然我们现在使用tokens=1-5,那么%%e 只能设置为.,如果该行是12 小时格式,否则它是24 小时格式。要转换为 24 小时格式,我们需要查看 %%c 是否为 PM(否则为 AM),如果是,则将 12 添加到小时数字 except 中的 12小时数字,当我们需要将小时数字设置为 00 时为 AM 和 12 为 PM。

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

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

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

完成了。


type q44964366.txt 替换为原来的dir 命令

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

【讨论】:

  • 感谢您的回答 - 我会尽快完成。只是一个关于你说“不幸的是,你发布了篡改列表,而不是实际数据(证据 - 列出的每个数据元素的时间和日期完全相同,禁止 PM 标志,尽管据称它们在不同的系统上) ":我在实际的 Win7 和 WinXP 系统上复制了 dir 输出的前 3 行。我只是修改了日期和文件名以隐藏“个人”和不相关的细节...... :) 所以,我提供的 2 个输出只是在内容方面进行了修改,列和布局根本没有被篡改。
  • 很好的答案,学到了很多东西。您的方法是否假设文件夹与脚本处于同一级别?我无法理解如何在您的代码中使用path_of_folder。 type 是否需要替换为 dir 以及 path_of_folder?
【解决方案3】:

不同的操作系统不是你的问题,不幸的是DIR 命令的输出不一致,它可能因用户而异。最简单的解决方法是使用另一种方法来检索您希望捕获的数据,npocmaka's answer 使用 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


编辑

看来,您正在寻找来自directory 的数据。 (我误以为你指的是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 时可能会有初始化延迟

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

【讨论】:

  • 感谢您的回答,但是在运行您的代码时,我什么也得不到。我复制了您的代码并修改了_dp 路径以指向我的本地计算机。我尝试为_pf 和_dt 添加我的回声,但它们看起来是空的。我错过了什么吗?
  • 我可以确认上面的代码似乎不能正常工作。请考虑修改。
  • 作为这两个 cmets 的结果,我已经在 Windows Vista、7 和 10 上测试了脚本,发现它们都可以按预期工作。这三者之间的共同点是操作系统语言本地化设置。我能想到的第一个可能性是 WMIC 输出标头取决于语言。我现在已经更改了代码以适应这种可能性,请根据需要重新检查和反馈;谢谢。
  • 您正在使用 DATAFILE,它报告文件。但是 OP (@nk-fford) 正在尝试获取有关文件夹的信息,这就是您的代码不返回任何内容的原因。您需要改用 FSDIR。
  • 你可以使用wmic fsdir where "name='%_dp:\=\\%'" get ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多