Iterate folder and get filename for commandline input - windows

I am trying to iterate files in a folder and process them with another batch file inside the do loop. It works with echo but as soon as I use the variable as input to the program, it echoes the () part and everything inside.
Here's what I'm trying to do.
#echo off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
for /r %%f in (/folder/*) do (
set name="%%~nf"
echo !name! <--- ok
process.bat !name! <--- echoes () and commands inside this do loop
)
ENDLOCAL
The process.bat just capitalizes the first letter of the filename and echoes it for debug or confirmation.

A batch file must be called from within a batch file using command call as otherwise Windows command processor continues processing on other batch file with never returning back to initial batch file.
See also: How to call a batch file that is one level up from the current directory?
Please read excellent answer on batch file echo on/off not working properly written by dbenham for the reason on getting suddenly the commands executed by FOR output after first execution of process.bat without using command CALL. I cannot explain better what happens in this case.
The directory separator on Windows is the backslash character \ and not the forward slash / as on Linux or Mac. Windows supports also / in file/folder paths for compatibility reasons by automatically replacing all / by \ before accessing the Windows file systems, but a good written script uses 100% correct syntax and does not depend on automatic corrections done by other programs. / is used on Windows mainly for command line switches.
The usage of / instead of \ can result in an unexpected behavior. For example run a batch file with following content:
#echo off
echo Files in directory %SystemRoot:\=/%/:
for %%I in (%SystemRoot:\=/%/*) echo %%I
echo/
pause
echo/
echo Files in directory %SystemRoot%\:
for %%I in (%SystemRoot%\*) echo %%I
echo/
pause
The first FOR using C:/Windows/* as wildcard pattern outputs the file names with just drive letter + colon + file name + file extension. The file path \Windows\ is missing in output file names. The second FOR loop using C:\Windows\* as wildcard pattern outputs the full qualified file names, i.e. drive letter + colon + file path + file name + file extension.
A file/folder path starting with \ references a directory or file relative to root directory of current DRIVE.
This is explained by the Microsoft documentation Naming Files, Paths, and Namespaces.
It looks like folder is a subdirectory in directory of the executed batch file. In this case / or \ at beginning of folder path is definitely not correct. The backslash at beginning can be omitted or .\ is used to reference the directory folder in current directory on execution of the batch file. But the current directory on batch file execution can be also different to directory containing the executed batch file, for example on running the batch file as administrator, or on running the batch file as scheduled task, or on running the batch file from a network resource accessed using a UNC path. For that reason it is advisable to reference explicitly subdirectory folder in directory of the batch file.
Delayed environment variable expansion is not needed as long as the file name assigned currently to the loop variable does not need to be modified other than the modifiers of for support it. A command line like set name="%%~nf" does not work correct with enabled delayed expansion and file name contains one or more ! because of cmd.exe interprets the exclamation mark(s) in file name as beginning/end of a delayed expanded environment variable reference.
See also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
It looks like a recursive search for non-hidden files is not really needed as otherwise passing just file name without path and file extension would be not enough to get the right file processed by other batch file process.bat.
So the entire task can be done most likely also with:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for %%I in ("%~dp0folder\*") do call "%~dp0process.bat" "%%~nI"
endlocal
But if the other batch file process.bat expects that the passed file name without file extension and path is in current directory on execution of process.bat, it is necessary to make the subdirectory folder in directory of this batch file first the current directory.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0folder"
for %%I in (*) do call "%~dp0process.bat" "%%~nI"
popd
endlocal
Note: The batch file folder path referenced with %~dp0 always ends with a backslash. Therefore no additional backslash should be used on concatenating this path string with a file/folder name to avoid having finally on execution of the batch file \\ in full qualified file/folder name, although Windows kernel corrects such paths also automatically by removing second backslash in this case.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
popd /?
pushd /?
set /?
setlocal /?

Related

How to loop through folder names and move folders based on date in folder name?

I currently have a batch file that loops through a text file which has a list of file names and moves these files to folders based on the date in the file name.
I'm trying now to change this to do something similar but for folders. Get folder names and then move each folder to another location based on the date in the folder name.
Example of folder structure:
Before move:
k:\PLPR1
k:\PLPR1\20210910\data
k:\PLPR1\20210909\data
k:\PLPR1\20210830\data
After move:
l:\PLPR1\2021\FTP Data\September\10 September\data
l:\PLPR1\2021\FTP Data\September\09 September\data
l:\PLPR1\2021\FTP Data\September\30 August\data
The folder moving task can be done with following batch file:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "SourcePath=K:\PLPR1"
set "TargetPath=L:\PLPR1"
set "Month01=January"
set "Month02=February"
set "Month03=March"
set "Month04=April"
set "Month05=May"
set "Month06=June"
set "Month07=July"
set "Month08=August"
set "Month09=September"
set "Month10=October"
set "Month11=November"
set "Month12=December"
for /F "delims=" %%I in ('dir "%SourcePath%" /AD-L /B 2^>nul') do (
set "FolderName=%%I"
set "Year=!FolderName:~0,4!"
set "Month=!FolderName:~4,2!"
set "Day=!FolderName:~6,2!"
for %%I in (Month!Month!) do set "Month=!%%I!"
%SystemRoot%\System32\robocopy.exe "%SourcePath%\%%I" "%TargetPath%\!Year!\FTP Data\!Month!\!Day! !Month!" /E /MOVE /NDL /NFL /NJH /NJS /R:1 /W:5 >nul
)
endlocal
The first two command lines define the required execution environment which is:
command echo mode turned off
command extensions enabled
delayed environment variable expansion enabled
The enabled delayed expansion means that this batch file cannot be used without modification on source or target path containing one or more exclamation marks.
It is further expected by this batch file code that the source folder contains only subfolders with names being the date in format yyyyMMdd.
The usage of for /F with a command line enclosed in ' results in running in background one more cmd.exe with option /c and the specified command line appended as additional arguments. So executed is in background with Windows installed to C:\Windows:
C:\Windows\System32\cmd.exe /c dir "K:\PLPR1" /AD-L /B 2>nul
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
The command DIR searches
in specified directory for file system entries which
have the directory attribute set and are not reparse points (directory junctions) because of option /AD-L and
outputs in bare format just the names of the folders because of option /B without path.
The error message output by DIR on not finding any directory is suppressed by redirecting it to device NUL.
The output of DIR to handle STDOUT of background command process is captured by FOR respectively cmd.exe processing the batch file and processed line by line after started cmd.exe closed itself after finishing execution of DIR.
FOR with option /F results in always ignoring empty lines which do not occur here at all. A non-empty line would be split up by default into substrings using normal space and horizontal tab as string delimiters. That line splitting behavior would be no problem here as the folder names in format yyyyMMdd do not contain a space character, but there is nevertheless used delims= to define an empty list of string delimiters which makes the processing of the file names a very little bit faster as line splitting behavior is turned off in this case.
If the first substring being now the entire directory name would start with a semicolon, FOR would also ignore the captured line for further processing. This end of line behavior does not matter here as the directory names do not start with a semicolon.
So there is in memory of the command process processing the batch file now a list of directory names which are assigned one after the other to the specified loop variable I and it does not matter anymore what happens next in the source directory during the loop iterations. This is important, especially if the source directory is on a FAT drive (FAT32, exFAT).
The directory name without path is assigned to an environment variable and substitutions are used next with delayed expansion to split the date in name up to year, month and day in month.
There are defined twelve environment variables which hold for each month with two digit month value at end of the variable name the appropriate name of the month. A simple FOR loop is used to concatenate the fixed string Month with the month value determined from directory name do redefine the environment variable Month using delayed expansion by the month name assigned to the dynamically built environment variable name starting with Month and ending with current month value.
Now all required data are available to move everything inside the current directory with ROBOCOPY to the appropriate destination directory using the year, month and day values. ROBOCOPY creates automatically the entire destination (target) directory tree.
It is of course possible that ROBOCOPY fails to delete a file/directory in source directory, for example if a file is currently opened in source directory by another application or a directory is the current directory of a running process. But that does not matter for the FOR loop as the command FOR itself does not access anymore the file system to get next directory name because of processing a list of directory names in memory of the command process. So it is not possible that any directory is processed more than once, or that a directory is skipped by chance, or the FOR loop runs into an endless loop thanks to first getting the list of directories to process loaded into memory.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
endlocal /?
for /?
robocopy /?
set /?
setlocal /?

Batch script to rename all files with spaces [duplicate]

This question already has answers here:
Variables are not behaving as expected
(1 answer)
Example of delayed expansion in batch file
(5 answers)
At which point does `for` or `for /R` enumerate the directory (tree)?
(1 answer)
Closed 1 year ago.
I'm trying to write a batch script that'll read all the pdf files in a folder and rename them such that there are no spaces in them. So I've typed up the below code. Although most of the parts of the code seems to work in isolation, I get an error when running the code together.
for /r %%f in (*.txt) do (
set filename=%%~nxf
set new=%filename: =%
ren "%filename%" %new%
)
The filename is detected correctly by line2. But on line3, I don't get the value I've stored in line2. Interestingly enough, if I were to run the command again in the same prompt, line3 then works (filename variable is read correctly). It must be how the for loop operates in a batch script. If I run the below code exactly 3 times in the same command prompt, the code works perfectly fine (I assume because all variables are now set correctly). Can someone please help point me in the right direction? Thanks in advance.
Note: I have a filename called "filename .txt" in the working directory, which I realise wasn't the best choice of filename. :|
(error in screenshot)
Open a command prompt, run set /? and read the output help carefully and completely from top of first to bottom of last page, especially the section about delayed expansion explained also by Variables are not behaving as expected. The Windows command processor cmd.exe processes the entire command block starting with ( and ending with matching ) before executing command FOR at all. All environment variables using %...% syntax are expanded (replaced) already during this processing phase by the appropriate variable expansion result.
So executed is the following on environment variable filename not already defined:
for /R %f in (*.txt) do (
set filename=%~nxf
set new= =
ren ""
)
That can be seen on debugging the batch file by running it from within a command prompt window instead of double clicking the batch file. This results in the following error message for each *.txt file found in current directory and all its subdirectories:
The syntax of the command is incorrect.
The syntax of the command ren is of course incorrect.
One solution is using following batch code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "* *.txt" /A-D /B /S 2^>nul') do (
set "FullName=%%I"
set "FileName=%%~nxI"
setlocal EnableDelayedExpansion
ren "!FullName!" "!FileName: =!"
endlocal
)
endlocal
The first two lines define completely the required execution environment for the batch file.
There is not used a for /R loop as that can cause troubles depending on file system of current drive and the file names to modify on renaming the files with file extension .txt while the FOR loop iterates of the file system entries matching the wildcard pattern.
The usage of the for /F loop results in first starting one more command process in background with %ComSpec% /c and the specified command line appended as additional arguments. So with Windows installed in C:\Windows is executed in background:
C:\Windows\System32\cmd.exe /C dir "* *.txt" /A-D /B /S 2>nul
The second command process runs DIR which
searches in current directory and all its subdirectories because of option /S
for just files because of option /A-D (attribute not directory)
of which name matches the wildcard pattern * *.txt in long or short name
and outputs the found file names in bare format because of option /B which means just the file names with full path because of option /S.
The command DIR finds also matching file names of files with hidden attribute set which are ignored by for /R. The option /A-D could be modified to /A-D-H to ignore hidden files.
The wildcard pattern contains a space character. For that reason the command DIR outputs just the full qualified file names of files which contain at least one space character in long file name. Short 8.3 file names cannot contain a space character.
The error message output by DIR if it cannot find at least one file name matching the wildcard pattern in the entire directory tree of current directory is suppressed by redirecting the error message from handle STDERR to device NUL.
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
The command FOR respectively the cmd.exe instance processing the batch file captures all lines output by DIR to handle STDOUT of command process started in background. The processing of the list of full qualified file names starts when started cmd.exe closed itself after finishing execution of command DIR.
The list of file names to process is now completely in memory of the command process executing the batch file. The file renames done next by the loop cause multiply changes in file system, but that does not affect the list of file names processed by FOR as it is the case on using for /R. So there is surely no file name with a space in name skipped as the file system changes do not affect the processing of the files to rename.
FOR with option /F results by default in ignoring all empty lines. The command DIR does not output empty lines.
Next a non-empty line is split up by default into substrings using horizontal tab and normal space as string delimiters. That string splitting behavior is definitely not wanted here as the files to rename contain at least one space character. For that reason delims= is used to define an empty list of string delimiters which turns off the line splitting behavior completely.
There is by default ignored next a line of which first substring starts with default end of line character ;. But the command DIR with option /S outputs all file names with full path and it is therefore impossible that any full qualified file name starts with a semicolon. So it is not necessary to modify the default end of line character.
The full file name is assigned to loop variable I which is next assigned to the environment variable FullName. The file name with file extension without path is assigned to environment variable FileName. The environment variables are (re)defined while delayed environment variable expansion is disabled to process also file names correct containing one or more ! in name. If delayed expansion would be already enabled, each exclamation mark in file name assigned to loop variable I would be interpreted as beginning/end of a delayed expanded environment variable reference which of course is not wanted in this case.
Now delayed expansion is enabled to be able to rename the file using its full file name referenced delayed expanded and its new name without path with all spaces removed. Then the previous environment is restored which is necessary to avoid a stack overflow as there is much more done in background by setlocal EnableDelayedExpansion than toggling the state of delayed expansion and to process the next file name again in an environment with delayed expansion disabled. See this answer for details on what happens in background on each usage of the commands SETLOCAL and ENDLOCAL.
There is no guarantee that each file rename really works. The file rename fails if there is already a file or directory with new name in the directory of a file to rename. A file rename fails also if a file to rename is currently opened by an application which opened it with denying any access by another application.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
endlocal /?
for /?
ren /?
set /?
setlocal /?

Batch Script to copy files from a Text file

I need help with below code as it is executing in root folder only whereas I want the code to look for files within sub folders as well.
for /F "tokens=*" %%A in (documents.txt) do (
copy %%A E:\Destination\
)
I suggest to use this command line in the batch file to copy all files with duplicating directory structure from source to destination directory.
for /F "eol=| delims=" %%I in (documentation.txt) do %SystemRoot%\System32\robocopy.exe "%~dp0." "E:\Destination" "%%~I" /S /NDL /NFL /NJH /NJS
It is assumed that the file documentation.txt contains a list of file names without path.
The command FOR reads one line after the other from file documentation.txt with skipping empty lines. The end of line character is modified from default ; to | using option eol=| to be able copying also files of which name starts unusually with a semicolon. No file name can contain a vertical bar anywhere. The line splitting behavior on spaces/tabs is disabled by using option delims= which defines in this case an empty list of string delimiters. Therefore file names with one or more space even at beginning of file name read from file are assigned unmodified to loop variable I. The option tokens=* removes leading spaces/tabs from the lines read from text file. A file name can begin with one or more spaces although such file names are unusual.
FOR runs for each file name the executable ROBOCOPY with directory of the batch file as source folder path and E:\Destination as destination folder path. ROBOCOPY interprets a \ left of one more \ or " as escape character. For that reason the source and destination folder paths should never end with a backslash as this would result in " being interpreted not as end of folder path, but everything up to next " in command line. For that reason . is appended to %~dp0 because of %~dp0 always expands to batch file folder path ending with a backslash. The dot at end of batch file folder path references the current folder of batch file folder. In other words with batch file stored in C:\Temp the batch file folder can be referenced with C:\Temp\ as done with %~dp0 but not possible with ROBOCOPY or with C:\Temp\. as done with %~dp0. or with just C:\Temp or with C:\Temp\\ as done with %~dp0\ which would also work with ROBOCOPY. See the Microsoft documentation about Naming Files, Paths, and Namespaces for details.
Remove %~dp0 to use current folder as source folder instead of batch file folder.
The ROBOCOPY option /S results in searching in source folder and all its subfolders for the file and copy each found file to destination folder with duplicating the source folder structure in destination folder.
The other ROBOCOPY options are just for not printing list of created directories, list of copied files, header and summary.
Here is an alternative command line for this task copying all files from source directory tree into destination directory without creating subdirectories. So all copied files are finally in specified destination directory.
for /F "eol=| delims=" %%I in (documentation.txt) do for /F "delims=" %%J in ('dir "%~dp0%%~I" /A-D-H /B /S 2^>nul') do copy /B /Y "%%J" "E:\Destination\" >nul
The inner FOR starts for each file name assigned to loop variable I of outer FOR one more command process in background with %ComSpec% /c and the DIR command line appended as additional arguments. So executed is for each file name in documentation.txt with Windows installed into C:\Windows for example:
C:\Windows\System32\cmd.exe /c dir "C:\Batch File Path\Current File Name.ext" /A-D-H /B /S 2>nul
The command DIR executed by second cmd.exe in background searches
in directory of the batch file
and all its subdirectories because of option /S
only for non-hidden files because of option /A-D-H (attribute not directory and not hidden)
with the specified file name
and outputs in bare format because of option /B
just the names of the found files with full path because of option /S.
It is possible that DIR cannot find a file matching these criteria at all in which case it would output an error message to handle STDERR of the background command process. This error message is suppressed by redirecting it with 2>nul to device NUL.
Read the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
The inner FOR captures everything written to handle STDOUT of started background command process and processes this output line by line after started cmd.exe terminated itself after finishing execution of DIR.
The inner FOR assigns each full qualified file name to specified loop variable J without any modification because of option delims= and runs next the command COPY to copy that file as binary file to destination directory with automatically overwriting an existing file in destination directory with same file name. The success message output by COPY to handle STDOUT is redirected with >nul to device NUL to suppress it. An error message would be output by COPY. An error occurs if destination directory does not exist, or the destination directory is write-protected, or an existing file with same name is write-protected due to a read-only attribute or file permissions, or source file is opened by an application with sharing read access denied, or an existing destination file is opened by an application with sharing write access denied.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... for an explanation of %~dp0 referencing drive and path of argument 0 which is the full qualified path of the batch file currently processed by cmd.exe.
copy /?
dir /?
for /?
robocopy /?

find path of current folder - cmd

I use this script to find out the current folder with its .bat file:
for /f %%i in ("%0") do set curpath=%%~dpi
echo %curpath%
it doesn't work correctly, if the path contains spaces(D:\Scripts\All Scripts -> retrieves only D:\Scripts\, if I place in the folder, whose path doesn't have spaces it retrieves the full path). How can I fix it?
2015-03-30: Edited - Missing information has been added
To retrieve the current directory you can use the dynamic %cd% variable that holds the current active directory
set "curpath=%cd%"
This generates a value with a ending backslash for the root directory, and without a backslash for the rest of directories. You can force and ending backslash for any directory with
for %%a in ("%cd%\") do set "curpath=%%~fa"
Or you can use another dynamic variable: %__CD__% that will return the current active directory with an ending backslash.
Also, remember the %cd% variable can have a value directly assigned. In this case, the value returned will not be the current directory, but the assigned value. You can prevent this with a reference to the current directory
for %%a in (".\") do set "curpath=%%~fa"
Up to windows XP, the %__CD__% variable has the same behaviour. It can be overwritten by the user, but at least from windows 7 (i can't test it on Vista), any change to the %__CD__% is allowed but when the variable is read, the changed value is ignored and the correct current active directory is retrieved (note: the changed value is still visible using the set command).
BUT all the previous codes will return the current active directory, not the directory where the batch file is stored.
set "curpath=%~dp0"
It will return the directory where the batch file is stored, with an ending backslash.
BUT this will fail if in the batch file the shift command has been used
shift
echo %~dp0
As the arguments to the batch file has been shifted, the %0 reference to the current batch file is lost.
To prevent this, you can retrieve the reference to the batch file before any shifting, or change the syntax to shift /1 to ensure the shift operation will start at the first argument, not affecting the reference to the batch file. If you can not use any of this options, you can retrieve the reference to the current batch file in a call to a subroutine
#echo off
setlocal enableextensions
rem Destroy batch file reference
shift
echo batch folder is "%~dp0"
rem Call the subroutine to get the batch folder
call :getBatchFolder batchFolder
echo batch folder is "%batchFolder%"
exit /b
:getBatchFolder returnVar
set "%~1=%~dp0" & exit /b
This approach can also be necessary if when invoked the batch file name is quoted and a full reference is not used (read here).
for /f "delims=" %%i in ("%0") do set "curpath=%%~dpi"
echo "%curpath%"
or
echo "%cd%"
The double quotes are needed if the path contains any & characters.
Use This Code
#echo off
:: Get the current directory
for /f "tokens=* delims=/" %%A in ('cd') do set CURRENT_DIR=%%A
echo CURRENT_DIR%%A
(echo this To confirm this code works fine)

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.
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:
There is no check if the batch file was called with the 2 parameters required.
There is no check if the directory path passed as first parameter really ends with a backslash as required.
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.

Resources