Expack3
Expack3

Reputation: 23

Using a Windows Batch file to back up files in user-specified location and user-specified file extension

I'm creating a Windows Batch file which will allow me to backup files in a specific location with a specific file extension by creating a copy of the file with a .bak extension. For example, if I were to give the working Batch file the parameters "C:\Test & Folder" (which, in this example, only contains a file called MyWork.laz) and ".laz", it would switch to the correct drive, look through the specified folder, create a copy of MyWork.laz in the same folder called MyWork.laz.bak, then switch back to the drive where the batch was started from.

Currently the code looks like this:

set EXTEN = *%~2%
%~d1
cd "%~f1"
FOR %%I IN %%EXTEN DO COPY %%I %%I.bak
%~d0

However, when the batch file gets to Line 4, the following error is outputted:

%EXTEN was unexpected at this time.

How Line 4 is interpreted by Windows is also shown (I was using ".bak" as my second argument):

FOR %I IN %EXTEN DO COPY %I %I.bak

As I'm new to Windows Batch programming, and my research into this hasn't yielded anything, I'd appreciate any advice or assistance.

Upvotes: 2

Views: 1671

Answers (1)

Mofi
Mofi

Reputation: 49086

The simple batch solution:

@ECHO OFF
FOR /F "usebackq delims=" %%I IN ( `DIR /B "%~1*.%~2"` ) DO COPY "%~1%%I" "%~1%%I.bak" >nul

This simple solution runs command DIR searching for files with the extension passed as second parameter in directory specified as first parameter.

Output format of command DIR is set with option /B to simple format which means only name of found files without path are output by DIR.

This output is read next line by line in the FOR loop which executes the copy command on each file to create the backup file in same directory.

But this simple solution has some disadvantages for usage:

  1. There is no check if the batch file was called with the 2 parameters required.
  2. There is no check if the directory path passed as first parameter really ends with a backslash as required.
  3. There is no check if the extension passed as second parameter does not contain a dot as expected.

Therefore the better solution is following batch file:

@ECHO ON
SET "Folder=%~1"
SET "Extension=%~2"
IF "%Folder%"=="" GOTO Usage
IF "%Extension%"=="" GOTO Usage
IF "%Folder:~-1%"=="\" SET "Folder=%Folder:~0,-1%"
IF "%Extension:~0,1%"=="." SET "Extension=%Extension:~1%"
FOR /F "usebackq delims=" %%I IN ( `dir /b "%Folder%\*.%Extension%"` ) DO COPY "%Folder%\%%I" "%Folder%\%%I.bak" >NUL
GOTO EndBatch

:Usage
CLS
ECHO Usage: %~n0 ["][Drive:]Path["] Extension
ECHO.
ECHO Examples:
ECHO.
ECHO    %~n0 "C:\My Files\" txt
ECHO.
ECHO    %~n0 C:\Temp\ doc
ECHO.
PAUSE

:EndBatch
SET Folder=
SET Extension=

The second line assigns first parameter to an environment variable Folder with removing surrounding double quotes if present at all. The entire parameter for command SET must be in double quotes in case of directory path contains a special character like & or %.

The third line assigns second parameter to an environment variable Extension with removing surrounding double quotes if present at all (unlikely but not impossible).

The fourth and fifth line check if batch file was called with at least 2 parameters.

The check for first parameter missing can be done safely only after removing the double quotes as otherwise the execution of the batch file is breaked with a syntax error message if the directory path contains a special character like &.

IF ""C:\Test & Folder""==""

results in a syntax eror while

IF "C:\Test & Folder"==""

is correct parsed by the command line interpreter.

The sixth line checks if last character of directory path is a backslash. The backslash at end is removed if this is the case. The opposite is also possible by appending a backslash if missing at end. But using 3 times a backslash in the FOR loop below makes this line easier to read.

The seventh line removes a dot from beginning of file extension if the file extension was specified on calling the batch file with a dot.

The other lines should be self-explaining.


Addition to answer the questions by Expack3 in first comment:

Whenever a new process is started, Windows allocates memory for the environment variables and their values, and copies the environment data from the parent process to the environment memory of the called process. Therefore each process has its own environment buffer and can modify, add or delete environment variables with no impact on other running processes including the parent process.

The process cmd.exe is called on running a batch file which interprets and executes the commands in the batch file. By default cmd.exe terminates itself on end of a batch file reached. With termination of cmd.exe the environment variables buffer is also deallocated and therefore it does not really matter which variables have been added, modified or deleted by the batch file. So in general it is not necessary to delete environment variables used temporarily in a batch file.

But instead of double clicking on a batch file, or running a batch file via a shortcut (*.lnk file), or by Windows task scheduler, it is also possible to run a batch file directly from within a command prompt window which means from an already running cmd.exe process.

In this case the environment variables added by the executed batch file remain in environment buffer after processing the batch file finished. This can lead to problems if next from within same command prompt window one more batch file is executed which by chance use also one of the environment variables of first batch file, but has not initialized the environment variable before first usage. The mistake of a missing variable initialization in second batch file in combination of not removing variables in first batch file could result now in a different execution of second batch file in comparison to running only second batch file respectively running the second batch file first in command prompt window.

Another reason for deleting temporarily used environment variables is the limited memory for environment variables. The memory allocated by Windows for the environment variables before starting the process does not grow during process execution. So if one batch file is called from other batch files and none of the batch files deletes the temporarily used environment variables, it could happen that there is suddenly no more free memory for a new variable or a larger string for an existing variable during the execution of the batch hierarchy. The logon batch file in large companies is often a collection of batch files which needs more and more memory from environment buffer if each batch file itself called directly or indirectly via other batch file(s) does not remove the temporarily used environment variables.

So it is simply more safe to delete the environment variables used temporary before exiting a batch file although for most batch files it is not necessary and just increases the total batch processing time by a few microseconds.

Using a line like:

set "Folder=%~f1"

is not enough for this batch file. It removes the double quotes from passed directory path and additionally changes a relative directory path to an absolute directory path if the directory can be found.

But it does not remove the backslash from end of a directory path if this path is already an absolute path.

For this batch file it is not really necessary that the directory path is an absolute path as the commands DIR and COPY work both also with relative paths.

The expansion of a relative directory path to an absolute directory path would just require a few microseconds more on batch execution without any benefit, except the batch files is extended by inserting a line with ECHO printing name of copied file with complete path within the FOR loop for visual inspection.

Upvotes: 1

Related Questions