0

I have the following code sample in C:\myscript.bat

for /f %%i in ('dir "C:\files" /b /a-d /o-d') do (
if /i "%%~xi"==".vib" (
gsutil cp c:\files\%%i gs://mybucket
call :GetDate
echo %dt% File %%i was uploaded )
)
:done

:GetDate
set X=
for /f "skip=1 delims=" %%x in ('wmic os get localdatetime') do if not defined X set X=%%x
set DATE.YEAR=%X:~0,4%&set DATE.MONTH=%X:~4,2%&set DATE.DAY=%X:~6,2%&set DATE.HOUR=%X:~8,2%&set DATE.MINUTE=%X:~10,2%&set DATE.SECOND=%X:~12,2%
set dt=%DATE.MONTH%-%DATE.DAY%-%DATE.YEAR%_%DATE.HOUR%-%DATE.MINUTE%-%DATE.SECOND%
exit /b

My problem is getting the current date in 'echo %dt% File %%i was uploaded' when calling GetDT inside the FOR loop. As long as I call :GetDate outside the FOR loop it works fine. I've already spent probably 4+ hrs and can't seem to get it to print the 'current' date inside the FOR loop without some kind of error.

I also tried just throwing the entire date code from :GetDate inside the FOR loop but that doesn't work either. I guess it doesn't like the FOR loop inside a FOR loop. Your help would be appreciated.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
yorkman
  • 119
  • 2
  • 16
  • 1
    `echo !d! File %%i was uploaded` ([recommended read](https://stackoverflow.com/questions/30282784/variables-are-not-behaving-as-expected/30284028#30284028)). Btw: if you use `...in ('dir "C:\files\*.vib" /b /a-d /o-d') do...` you can skip the `if` command. And better quote `"c:\files\%%i"` to take care of possible spaces in the filename. Or even better: `gsutil cp "%%~fi" ...` – Stephan Feb 04 '21 at 10:27

1 Answers1

6

I see no need for delayed expansion whatsoever.

Just create your DateTime string %dt%, before the Dir loop: The time of the script will of course be the same for each, but IMO the exact time of each individual gsutil command ending shouldn't be mission critical, the batch run time should be.

@Echo Off
SetLocal EnableExtensions
Set "sd=C:\files"
Set "fg=*.vib"
For /F EOL^=L %%G In ('%SystemRoot%\System32\wbem\WMIC.exe OS GET LocalDateTime'
) Do For %%H In (%%~nG) Do Set "dt=%%H"
Set "dt=%dt:~4,2%-%dt:~6,2%-%dt:~,4%_%dt:~8,2%-%dt:~10,2%-%dt:~-2%"
For /F "EOL=? Delims=" %%G In ('Dir "%sd%\%fg%" /B /A:-D /O-D 2^> NUL') Do (
    gsutil.exe cp "%sd%\%%G" "gs://mybucket"
    Echo %dt% file %%G was uploaded)
Pause
GoTo :EOF

If you really do need to record the time just after each file was processed individually, just do it directly in the same for loop:

@Echo Off
SetLocal EnableExtensions
Set "sd=C:\files"
Set "fg=*.vib"
For /F %%G In ('Dir "%sd%\%fg%" /B /A:-D /O-D 2^> NUL') Do (
    gsutil.exe cp "%sd%\%%G" "gs://mybucket" && (
        For /F "Tokens=1-6 Delims=/: " %%H In (
            '%SystemRoot%\System32\Robocopy.exe \: . /NJH /L ^
             ^| %SystemRoot%\System32\find.exe " 123"') Do (
            Echo %%I-%%J-%%H_%%K-%%L-%%M file %%G was uploaded)))
Pause
GoTo :EOF

[Edit /]

Just in case your gsutil does not carry an .exe extension and with an expectaion that it returns an error level of 0 for a successful cp here's a slight modification of the same code.

@Echo Off
SetLocal EnableExtensions
Set "sd=C:\files"
Set "fg=*.vib"
For /F %%G In ('Dir "%sd%\%fg%" /B /A:-D /O-D 2^> NUL') Do (
    gsutil cp "%sd%\%%G" "gs://mybucket"
    If Not ErrorLevel 1 For /F "Tokens=1-6 Delims=/: " %%H In (
        '%SystemRoot%\System32\Robocopy.exe \: . /NJH /L ^
         ^| %SystemRoot%\System32\find.exe " 123"') Do (
        Echo %%I-%%J-%%H_%%K-%%L-%%M file %%G was uploaded))
Pause
GoTo :EOF

As a courtesy only, (I see no reason why you cannot use Robocopy.exe), here's a version which uses cscript.exe for generating your DateTime stamp via JScript instead.

@if (@X) == (@Y) @end /*
@Echo Off
SetLocal EnableExtensions
Set "sd=C:\files"
Set "fg=*.vib"
For /F %%G In ('Dir "%sd%\%fg%" /B /A:-D /O-D 2^> NUL') Do (
    gsutil cp "%sd%\%%G" "gs://mybucket"
    If Not ErrorLevel 1 For /F %%H In (
        '%SystemRoot%\System32\cscript.exe /NoLogo /E:JScript "%~f0"') Do (
        Echo %%H file %%G was uploaded))
Pause
GoTo :EOF */
var d = new Date();
WScript.Echo (("0" + (d.getMonth() + 1)).slice(-2) + "-" +
  ("0" + d.getDate()).slice(-2) + "-" + d.getFullYear() + "_" +
  ("0" + d.getHours()).slice(-2) + "-" + 
  ("0" + d.getMinutes()).slice(-2) + "-" + ("0" + d.getSeconds()).slice(-2));

[Edit2 /] Based upon new question criteria, in the comments below

@Echo Off
SetLocal EnableExtensions
Set "sd=C:\files"
Set "fg=*.vib *.vbk"
PushD "%sd%" 2> NUL || GoTo :EOF
For /F %%G In ('Dir %fg% /B /A:-D /O-D 2^> NUL') Do (
    If /I "%%~xG" == ".vbk" GoTo Done
    gsutil cp "%%G" "gs://mybucket"
    If Not ErrorLevel 1 For /F "Tokens=1-6 Delims=/: " %%H In (
        '%SystemRoot%\System32\Robocopy.exe \: . /NJH /L ^
         ^| %SystemRoot%\System32\find.exe " 123"') Do (
        Echo %%I-%%J-%%H_%%K-%%L-%%M file %%G was uploaded))
:Done
PopD
Pause
GoTo :EOF
Compo
  • 36,585
  • 5
  • 27
  • 39
  • @Compo. I have the script working almost perfectly but I am missing one thing. Before I had if /i "%%~xi"==".vib" (... in there because when it comes across the first file with ext .vbk it's supposed to goto :done. Without this it'll try to upload all .vbk files it finds right? So how do I add this to your code with the robocopy? I think it should go before each gsutil cmd but I probably have to replace the %%~xi to what you use...I tried %%~xG since the %%G is in the FOR loop but that's not working. How do I get only the filename ext? It's ok to cp all .vbk and .vib but I need only one .vbk. – yorkman Feb 04 '21 at 23:54
  • It looks like ..~xi is correct but I think the %% in front is what's wrong. I just need the IF statement to check the file extension of each file it finds in folder and I don't know what the %% means or why it doesn't work in your code sample. – yorkman Feb 05 '21 at 00:20
  • @yorkman, there was no mention whatsoever of `.vbk` files in your question, or any subsequent comments. You're now asking something completely different to your posted question, which, IMO, I have throughly dealt with. The code I've posted, which was based upon your own, was not designed to touch `.vbk` files, so will do nothing with them at all, and will not be affected by them. I have added yet another example to the bottom of my answer, based upon my understanding of what you're now asking. Please however do not ask me for more changes, I believe I've more than fulfilled your question now. – Compo Feb 05 '21 at 00:27
  • It doesn't matter what extension I use. The point is that it should depend on the extension in the IF statement just like you have in the FOR loop but you didn't include the IF statement in your code. In my original question I had .vib because that was just one example. The other 2 I deal with are .vbk and .vbm. In any case like you said you've helped me a LOT and I am sorry for the misunderstandings. You deserve full credit and then some so here you go! – yorkman Feb 05 '21 at 03:17
  • @yorkman, I didn't initially include an `If` statement because I didn't need one, and you didn't tell anyone you were working with more than one extension! Please open a Command Prompt window, type `dir /?`, and press the `[ENTER]` key, to read the simple usage of the `Dir` command I used. It should show you that against a glob of `*.vib`, it will only list those files. When it only lists `.vib` files, an `If` statement would be superfluous. My new modification uses `*.vib *.vbk`, which suprisingly returns items using both those extensions, and can, and does, therefore, use an `If` statement. – Compo Feb 05 '21 at 11:08