0

I have a batch script that goes into a folder's subfolders (excluding one folder) gets .log files, archives them, and then deletes the originals.

Folder structure:

\Logs\logs1
\Logs\logs2
\Logs\logs3

Originally, I had this loop as just one line, which worked and looked like this:

FOR /F "usebackq tokens=* delims=" %%A IN (`DIR "%LogsFilespec%" /B /S ^|find ^"logs3^" /v `)  DO %zipCommand% >> %ProcessLog% & DEL "%%~fA" & ECHO Deleting "%%~fA"  >> %ProcessLog% & ECHO. >> %ProcessLog%

But, I was instructed to turn it into a simpler-looking FOR DO CALL, and as a result I am stuck, unsure of whats wrong. %targetDate% is YYYYMMDD.

**Edited for fuller code trying rojo's suggestion:

SET ProcessLog=C:\Users\Me\Documents\batch_files\%~n0_%jobLog%.txt

:DetermineArchiveApp
:: Create specifics for ITD Logs collection
SET ITDLogsLocation=C:\Users\Me\Documents\fakeG
SET ITDLogsName=trace*%targetDate%.log
SET ITDLogsFilespec=%ITDLogsLocation%\%ITDLogsName%

:: ********************************************************************************
:: * Check if server has WinZip or 7-Zip installed. setup environment variable    *
:: * accordingly with executable path and name, and with any required parameters. *
:: ********************************************************************************

SET PathWinZip="C:\Program Files\WinZip\wzzip.exe"
SET Path7Zip_64bit="C:\Program Files\7-Zip\7z.exe"
SET Path7Zip_32bit="C:\Program Files (x86)\7-Zip\7z.exe"
SET Path7Zip_true="C:\Users\Me\Documents\batch_files\7za.exe"

:: Check for 32-bit version of 7-Zip. If found, configure
:: its command line parameter to produce a .zip file
IF EXIST %Path7Zip_32bit% SET zipCommand=%Path7Zip_32bit% a

::Check for WinZip
IF EXIST %PathWinZip% SET zipCommand=%PathWinZip% -a

:: Check for 64-bit version of 7-Zip. If found, configure
:: its command line parameter to produce a .zip file
IF EXIST %Path7Zip_64bit% SET zipCommand=%Path7Zip_64bit% a

:: Check for 64-bit version of 7-Zip. If found, configure
:: its command line parameter to produce a .zip file
IF EXIST %Path7Zip_true% SET zipCommand=%Path7Zip_true% a


:ArchiveProcess
ECHO ***************************************************** >> %ProcessLog%
::Write the date and time of job starting to a log
ECHO %DATE% %TIME% START >> %ProcessLog%
::Loop through the list that DIR gives for the given folder, and for each folder do zipCommand, excluding ITD\Data\AFS, and write to log
FOR /F "delims=" %%A IN (
    'DIR "%LogsFilespec%" /B /S ^|find /v "logs3"'
) DO CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%ProcessLog%"
::Write end to log
ECHO %DATE% %TIME% %~nx0 END >> %ProcessLog%
ECHO ***************************************************** >> %ProcessLog%

:DoZip
setlocal
SET "archiveName=%~1"
SET "SourceFileSpec=%~2"
SET "zipCommand=%~3"
SET "RunLog=%~4"

>>"%RunLog%" (

    echo Archiving %SourceFileSpec%...
    "%zipCommand%" "%archiveName%.zip" "%SourceFileSpec%"

    echo %TIME% Deleting %SourceFileSpec%...
    DEL "%SourceFileSpec%"

    echo;
)
GOTO :EOF

The errors I get from the cmd NOW are:

'""' is not recognized as an internal or external command, operable program or batch file.

Whats wrong with the syntax of either!?

EDIT 2: Heading home now, cant work remotely yet so I'll be back at it tommorow. The current issue is that: the 7zip command line does not like

"C:\Users\Me\Documents\batch_files\7za.exe" a

and also the >>"%RunLog%" block doesn't work, if comment out just the archival and deletion lines to see what's happening, I just get thrown

The system cannot find the drive specified.
The system cannot find the drive specified.
The system cannot find the drive specified.
The system cannot find the drive specified.
The system cannot find the path specified.
  • Please, [edit](http://stackoverflow.com/posts/28327760/edit) your question and _Include just enough code to allow others to reproduce the problem_. For help with this, read [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). – JosefZ Feb 04 '15 at 18:46
  • Okay, I think I've done it appropriately now. – driftandwander Feb 04 '15 at 20:26

1 Answers1

1

The biggest difference I see is that in your successful one-liner, you have stuff properly quoted; whereas in your call both in the caller and the subroutine, you quote nothing. If any of your paths include spaces or special characters, calamity ensues. Try this:

FOR /F "delims=" %%A IN (
    'DIR "%LogsFilespec%" /B /S ^|find /v "logs3"'
) DO CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%ProcessLog%"

...

:DoZip <basename> <fqpath> <zipcmd> <log>
setlocal
SET "archiveName=%~1"
SET "SourceFileSpec=%~2"
SET "zipCommand=%~3"
SET "RunLog=%~4"

>>"%RunLog%" (

    echo Archiving %SourceFileSpec%...
    "%zipCommand%" "%archiveName%.zip" "%SourceFileSpec%"

    echo %TIME% Deleting %SourceFileSpec%...
    DEL "%SourceFileSpec%"

    echo;
)
GOTO :EOF

By the way, did you know you could zip without 3rd party software?


This whole ordeal is turning into a mess. I hope you'll allow me to offer some general scripting advice and receive it as benevolence rather than criticism.

Whenever you set a variable to a string in batch scripting, it helps to set "var=value" with the var=value pair quoted. When you need your variable to be evaluated within quotes, call it as "%var%". This removes any ambiguity about your intentions, and saves you from having to remember which variable values you've quoted and which you haven't.

To directly address your most recent problem, I suggest either adding a 5th argument to your call for "a|-a" (for 7za or wzzip), or determine within the loop whether you should use a or -a based on whether the archiver is 7za or wzzip.

Try this:

@echo off
setlocal

SET "ProcessLog=%USERPROFILE%\Documents\batch_files\%~n0_%jobLog%.txt"

:DetermineArchiveApp
:: Create specifics for ITD Logs collection
SET "ITDLogsLocation=%USERPROFILE%\Documents\fakeG"
SET "ITDLogsName=trace*%targetDate%.log"
SET "ITDLogsFilespec=%ITDLogsLocation%\%ITDLogsName%"

:: ********************************************************************************
:: * Check if server has WinZip or 7-Zip installed. setup environment variable    *
:: * accordingly with executable path and name, and with any required parameters. *
:: ********************************************************************************

for %%I in ("%PROGRAMFILES%" "%PROGRAMFILES(x86)%") do (
    for %%z in ("%%~I\WinZip\wzzip.exe" "%%~I\7-Zip\7z.exe") do (
        if exist "%%~z" set "zipCommand=%%~z"
    )
)

if not defined zipCommand set "zipCommand=%USERPROFILE%\Documents\batch_files\7za.exe"
if not exist "%zipCommand%" (
    echo Unable to locate 7z.exe, 7za.exe, or wzzip.exe
    exit /b 1
)


:ArchiveProcess
::Write the date and time of job starting to a log
>> "%ProcessLog%" (
    ECHO *****************************************************
    ECHO %DATE% %TIME% START
)

::Loop through the list that DIR gives for the given folder, and for each folder do zipCommand, excluding ITD\Data\AFS, and write to log
FOR /F "delims=" %%A IN (
    'DIR "%ITDLogsFilespec%" /B /S ^| find /v "logs3"'
) DO CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%ProcessLog%"

::Write end to log
>> "%ProcessLog%" (
    ECHO %DATE% %TIME% %~nx0 END
    ECHO *****************************************************
)

::End main runtime
goto :EOF


:DoZip
setlocal
SET "archiveName=%~1"
SET "SourceFileSpec=%~2"
SET "zipCommand=%~3"
SET "RunLog=%~4"

if "%zipCommand%"=="%zipCommand:7z=%" (
    rem then this is WinZip.
    set "switch=-a"
) else set "switch=a"

>>"%RunLog%" (

    echo Archiving %SourceFileSpec%...
    "%zipCommand%" %switch% "%archiveName%.zip" "%SourceFileSpec%"

    echo %TIME% Deleting %SourceFileSpec%...
    DEL "%SourceFileSpec%"

    echo;
)
GOTO :EOF
Community
  • 1
  • 1
rojo
  • 24,000
  • 5
  • 55
  • 101
  • Thanks for the response! I did not know I could zip without 3rd party software, that's neat. The reason I tried removing quotes was because I tried your solution, and CMD spits out an error I've been encountering a lot in tinkering with this: ' " " ' (spaces added for visibility) is not recognized as an internal or external command, operable program or batch file... – driftandwander Feb 04 '15 at 20:04
  • I investigated what the problem was by echoing the value of each variable in your DoZip, and saw very strange results... archiveName became the first file in the directory of batch_files, where the script is run from. SourceFileSpec did the same thing. However, runlog correctly points to the .cmd's .txt log. – driftandwander Feb 04 '15 at 20:36
  • At the top of your script (line 7) you've got `SET ITDLogsFilespec=%ITDLogsLocation%\%ITDLogsName%` but in your `for /f` loop (line 41) you've got `dir "LogsFilespec"`. Looks like you might've changed your mind about a variable name, but didn't get it replaced everywhere. There is no actual `set LogsFilespec` anywhere. – rojo Feb 04 '15 at 20:40
  • Strange, none of the other versions of the script have that problem, I wonder if that was in the original post. Okay, so all the variables except zipCommand are appearing appropriately now. zipcommand remains blank – driftandwander Feb 04 '15 at 20:50
  • Around line 34 try `echo zipCommand: %zipCommand%` and a `pause` to see whether there's a logic problem there. – rojo Feb 04 '15 at 20:55
  • It's blank there! What the... My 7za is gone? – driftandwander Feb 04 '15 at 21:02
  • \* whistles innocently \* – rojo Feb 04 '15 at 21:04
  • Okay, so the zipCommand value is "C:\Users\314029026\Documents\batch_files\7za.exe" a, but CMD spits an error saying it doesnt recognize that... How am I supposed to write it properly? – driftandwander Feb 04 '15 at 21:12
  • @driftandwander See answer edit above. I think the problem involved your including `a` or `-a` along with the path to `7z.exe`. The fix I'm suggesting is more a suggestion of a behavior change than a band-aid for this specific problem. I understand if you don't agree with my advice. – rojo Feb 04 '15 at 21:44
  • sorry rojo, gotta ask another question: whats happening with `if "%zipCommand%"=="%zipCommand:7z=%" (` i understand what it's purpose is, but not whats actually happening given the syntax... it looks kind of like ternary? – driftandwander Feb 05 '15 at 18:47
  • `%haystackvar:needle=replacement%`. It's a way to replace a substring within a string. So `if "%zipCommand%"=="7z.exe"` and you replace `7z` with nothing, then left no longer equals right. On the other hand, `if "%zipCommand%"=="wzzip.exe"` and you replace `7z` with nothing, `wzzip.exe` still equals `wzzip.exe` because there was no match to replace. Does that make sense? – rojo Feb 05 '15 at 20:22