0

I am trying to understand the for loop in batch scripting; in particular with skip and tokens parameters. I have found a great example in this answer followed by this nice read.

I would like to see how I can extract the date and time from a dir in Windows XP which has a slightly different dir output (see below example outputs) compared to Windows 7. In other words, how to extract creation date of a specific folder in Windows XP.

The following modified code from the above mentioned links correctly extracts the date and time of a DIR in Windows 7 but fails (i.e. extracts other characters) in 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!
)

In Windows 7 the dir command in the command prompt outputs something similar to:

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

In Windows XP the dir command in the command prompt outputs something similar to:

   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

The only difference (as far as I can notice) is the PM column(?) which does not exist in Windows 7 but does exist in Windows XP.

I know this is probably a trivial question but I am new in batch scripting and seeing a specific example using a complex for loop would help my understanding. Assume use of delayed expansion.

  • this depends on the time settings in the control pane. You can alter them or to use VBScript or Jscript. – npocmaka Jul 07 '17 at 08:06
  • [check this](https://github.com/npocmaka/batch.scripts/blob/master/hybrids/jscript/dirTimesJS.bat) it prints the folder times always in the same format independent from the control panel settings. – npocmaka Jul 07 '17 at 08:11
  • @npocmaka Thanks for the notes but I cannot alter them from VBScript or Jscript. This is for me to see a specific example (i.e. how the code will need to be modified to work under the XP's `dir` output as the shown in the question). –  Jul 07 '17 at 08:16
  • the link I've sent you is a jscript packed in a bat file so calling it is easy. If you need you can alter the format. Just tell me the format you need and I'll drop an example ... – npocmaka Jul 07 '17 at 08:19
  • @npocmaka sorry just noticed the link. it is very useful but for interest of me understanding the `for` loop through a specific example like the one above, this has no use for me. –  Jul 07 '17 at 08:41

3 Answers3

1

The different OS is not your problem, unfortunately the output of the DIR command is not consistent, it can differ between users. The simplest fix is to use an alternative method of retrieving the data you wish to capture, npocmaka's answer uses JScript and the following answer uses another built-in tool, 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


Edit

It seems, you were looking for data from a directory. (I was mistaken in believing you meant the dir command).

Here is some updated code to reflect that fully:

@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


From memory, the very first time you run WMIC in XP there may be an initialisation delay

The output layout can be manipulated, as I have done…

Compo
  • 36,585
  • 5
  • 27
  • 39
  • 1
    Thanks for you answer but when running your code I get nothing. I copied your code and modified the `_dp` path to point to my local machine. I tried adding my echoes for the `_pf` and `_dt` but they appear empty. Am I missing something? –  Jul 07 '17 at 11:40
  • I can confirm that the above code does not appear to work as it is.. Please consider modifying. –  Jul 07 '17 at 13:13
  • As a result of these two comments, I have tested the script on Windows Vista, 7 and 10 and found them all to work as expected. The common denominator between all three were the OS language localisation settings. The first possiblity I can think of is that the WMIC output header is language dependent. I have now changed the code to cater for that possibility, please recheck and feedback as necessary; thank you. – Compo Jul 07 '17 at 17:46
  • You are using DATAFILE, which reports on files. But the OP (@nk-fford) is trying to get info about a folder, which is why your code returns nothing. You need to use FSDIR instead. – dbenham Jul 08 '17 at 04:51
  • You can use `wmic fsdir where "name='%_dp:\=\\%'" get ...` – dbenham Jul 08 '17 at 04:54
  • Thanks @dbenham. [nk-fford](https://stackoverflow.com/users/6167676/nk-fford), I have updated my answer accordingly to correct my misunderstanding, see **Edit** section. – Compo Jul 08 '17 at 10:36
0

The dir command time format is dependent on the settings in the control panel. To get the directory creation time independent from the control panel settings you can use 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 
    )
)

To see what information dirtimejs try with dirtimejs.bat "%path_of_folder%".

npocmaka
  • 55,367
  • 18
  • 148
  • 187
  • very useful indeed, but I would prefer an example that works on the XP dir output (modification of the code I provided which works on Windows 7) by not using any 3rd party code like the ditimejs.bat –  Jul 07 '17 at 08:43
  • @nk-fford - this will work on XP - jscript is part of widows script host which is installed on every windows machine by default since Windows NT. As the `dirtimejs.bat` is not a binary you can copy it, change it and use it as you find comfortable. – npocmaka Jul 07 '17 at 08:49
  • I understand and indeed provides a fix. However, the essence of my question was to see an example code implementation to aid my understanding. That is why I hope someone will provide that. I appreciate your response either way. –  Jul 07 '17 at 09:19
0

Time formats provided in windows listings depend on user-settings. Unfortunately, you've posted doctored listings, not actual data (evidence - exactly the same time and date for each of the data elements listed, bar the PM flag, despite their being allegedly on different systems)

fix : Easy way is to align the systems' UI settings - use the same format on both machines.

code to cope:

@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

For testing, I used a file containing typical dir lines. You would need to substitute the dir command from the original for the type q44964366.txt

The caret (^) before the pipe (|) tells cmd that the pipe is part of the command to be executed. The pipe outputs the data (from the dir command) and filds all those lines which /L Literally /E end /c:"string" with the constant string - note that this is Space. which neatly filters out all but the . directoryname, so proceeding with the analysis of the processing on the . name - which is the only name the findstr will allow through...

Since we now are using tokens=1-5 then %%e can only be set to . if the line is in 12-hr format, else it's in 24-hr format. To convert to 24-hr format, we need to see whether %%c is PM (else it's AM) and if so, add 12 to the hours digits except for 12 in the hours digits, when we need to set the hours digits to 00 for AM and 12 for PM.

The last of these conversions is obvious, but for non-12:xx PM, we take the two hours digits and append them to 2 making a string 2hh. cmd mathematics treats any numeric starting 0 as octal, so 09:xx would create an error. 209 it can cope with as it's decimal. From that, subtract 88, which is 100-12. This produces a 3-digit number which batch treats as a string, and we need the last 2 of the characters.

You don't specify your preferred format, so we may need to conver to 12-hr (in the code, if that has been chosen in required_format)

In 12-hr mode, we need to subtract 12 hours if the time is PM, and take care of the special values 12:xx and 00:xx. This is again done by stringing the first 2 digits of the time with a constant to form a nice 3-digit decimal value. 100 means 12:xx AM 112 means 12:xx PM 101-111 means we simply need to add AM and if it's greater than 112 (eg 15:xx in 24-hour format) then we need to subtract 12 and take the last 2 characters of the result as the hours digits; then add PM.

And done.


type q44964366.txt replaced by the dir command from the original

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

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • Thanks for the answer - I will go through it shortly. Just a note on you saying that "Unfortunately, you've posted doctored listings, not actual data (evidence - exactly the same time and date for each of the data elements listed, bar the PM flag, despite their being allegedly on different systems)": I literally copied the first 3 lines of a `dir` output on both actual Win7 and a WinXP systems. I merely modified the dates and file names to hide 'personal' and irrelevant details... :) So, the 2 outputs I provided are only modified content-wise, the columns and layout is not doctored at all. –  Jul 07 '17 at 09:23
  • Great answer, learning a lot. Is your approach assuming the folder is in the same level as the script? I cannot wrap my head around how to use the `path_of_folder` in your code. Is the `type` need to be replaced by the `dir` along with the `path_of_folder`? –  Jul 07 '17 at 11:22