-1
@echo off

:prep
cls
for /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c-%%a-%%b)
:for /l %A in (1,1,100) do copy "C:\some folder\file.ext" "C:\some folder\file-%%A.ext"
set choice=

:: test to see if directory exists
if EXIST "../delivery_%mydate%.txt" (
    goto overwrite
) else (
    goto start
)

:overwrite
echo.
echo delivery note already exists - continue?
set /p choice='y / n ?'
if '%choice%'=='' ECHO "%choice%" is not valid please try again
if '%choice%'=='y' goto start
if '%choice%'=='n' goto end
echo.

:start
echo.
for /l %A in (1,1,100) do copy "C:\some folder\delivery_%mydate%.ext" "C:\some folder\delivery_%mydate%.ext"
echo Choose the following:
echo 1. Directories
echo 2. Files
echo 3. quit
echo.
set /p choice=
if '%choice%'=='1' goto directory
if '%choice%'=='2' goto file
if '%choice%'=='3' goto end
cls
ECHO "%choice%" is not valid please try again
goto start

:directory
dir /ad /on /b > ../delivery_%mydate%.txt
echo.
goto checksuccess

:file
dir /a-d /on /b > ../delivery_%mydate%.txt
echo.
goto checksuccess

:checksuccess

I need to add a line of code to this batch file I have created above. I need this code to save an existing file to a higher version without deleting the previous one. This will also need to be embedded into the code I created. For example it will start saving them like: filev001, filev002, etc.

Mofi
  • 46,139
  • 17
  • 80
  • 143
lpjk
  • 33
  • 5

1 Answers1

1

1. Some general advice for writing batch files

A list of commands is output on executing in a command prompt window help. It is advisable to use in batch files for environment variables and labels not a string which is also a command. It is possible, but not advisable.

start is a command to start an application in a separate process. So it is better to use for example Begin instead of start as label.

choice is a command for a choice which is better for single character choices than using set /P. So it is better to use for example UserChoice instead of just choice as environment variable name.

It is better to use echo/ instead echo. to output an empty line. The reason is explained by DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/.

Environment variable names and labels are easier to read on using CamelCase and can be more easily searched case-sensitive and if necessary replaced in a batch file than a name/label which can exist as word also in comments and in strings output with echo.

The answer on question Why is no string output with 'echo %var%' after using 'set var = text' on command line? explains in detail why the usage of the syntax set "Variable=string value" is recommended in batch files on assigning a string to an environment variable.

The directory separator on Windows is the backslash character \. The slash character / is the directory separator on Unix/Linux/Mac. On Windows / is used for options/parameters. The Windows kernel functions support also directory and file paths with / as directory separator by automatically correcting them to \ internally in path. But it is nevertheless recommended to use in a batch file \ in paths.

rem is the command for a comment in a batch file. :: is an invalid label and not really a comment. Lines with a label at begin are ignored for command execution. But a label cannot be used in a command block. For that reason it is recommended to use command rem because :: in a command block results often in unexpected behavior on execution of the batch file.


2. Get current date in a specific format

Let us look on the command line:

for /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c-%%a-%%b)

date /t is a command which for executes in a background command process with the command line cmd.exe /C date /t for capturing the output of this command process written to standard output handle STDOUT and process the captured output line by line.

Can this be optimized?

Yes, because on running in a command prompt window set /? and reading the output help from first to last page it can be read that there is the environment variable DATE which expands to current date. So there is no need to run the command date to get current date as string.

The command date with option /t outputs the current date in the format defined for the used user account in Windows Region and Language settings. In your case it looks like the region dependent date format is MM/dd/yyyy with the weekday abbreviation at beginning (with no comma) before the date. The date format on my computer is just dd.MM.yyyy without weekday. The environment variable DATE is in same region dependent format as output of command date /t.

So the region dependent date in format ddd, MM/dd/yyyy could be also modified to yyyy-MM-dd using the command line:

for /F "tokens=2-4 delims=/, " %%a in ("%DATE%") do set "MyDate=%%c-%%a-%%b"

It is also possible to use string substitution:

set "MyDate=%DATE:~-4%-%DATE:~-10,2%-%DATE:~-7,2%"

String substitution is also explained by help output on running set /? and read the answer on
What does %date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2% mean?

But if yyyy-MM-dd is the wanted date format for current date independent on region settings of the used user account is advisable to use the command lines

for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "MyDate=%%I"
set "MyDate=%MyDate:~0,4%-%MyDate:~4,2%-%MyDate:~6,2%"

This region independent solution is really much slower than the above command lines. It is explained in detail by the answer on Why does %date% produce a different result in batch file executed as scheduled task? But it has the big advantage of being region independent.


3. Prompting user for a single character choice

The usage of set /P variable=prompt is not recommended for a single character choice because

  • the user can just hit RETURN or ENTER without entering anything at all resulting in variable keeping its current value or still not being defined if not defined before set /P command line;
  • the user can make a typing mistake and presses for example Shift+2 instead of just 2 resulting (on German keyboard) to enter " as string which most batch files using set /P breaks because of a syntax error on next command line evaluating the user input;
  • the user can enter anything instead of one of the characters asked for including strings which on next command line results in deletion of files and folders.

The solution is using the command choice if that is possible (depends on Windows version). choice waits for the key press of a character specified in the command options and immediately continues after one of these keys is pressed. And choice exits with the index of the pressed character in list as specified in batch file. This exit code is assigned to ERRORLEVEL which can be evaluated next also within a command block without using delayed expansion or used directly in a single goto instruction.


4. Rewritten batch file

Here is the rewritten batch file:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem set "Folder=C:\some folder"
set "Folder=F:\Temp\Test"

:Prepare
cls
rem Get current date region independent in format yyyy-MM-dd.
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "MyDate=%%I"
set "MyDate=%MyDate:~0,4%-%MyDate:~4,2%-%MyDate:~6,2%"

set "FileNumber=0"
for %%I in ("%Folder%\file-*.ext") do call :GetFileNumber "%%~nI"
goto IncrementNumber

rem Subroutine to find out highest file number without using delayed
rem environment variable expansion for number range 0 to 2147483647.

rem Numbers starting with 0 are interpreted as octal number in number
rem comparison which makes it necessary to remove leading 0 from the
rem number string get from file name starting with 5 characters.

:GetFileNumber
set "Number=%~1"
set "Number=%Number:~5%

:RemoveLeadingZero
if "%Number%" == "" goto :EOF
if "%Number:~0,1%" == "0" set "Number=%Number:~1%" & goto RemoveLeadingZero
if %Number% GTR %FileNumber% set "FileNumber=%Number%"
goto :EOF

rem Make sure the file number has at least 3 digits.
:IncrementNumber
set /A FileNumber+=1
if %FileNumber% GEQ 100 goto ExistDelivery
set "FileNumber=00%FileNumber%"
set "FileNumber=%FileNumber:~-3%"

rem Test to see if file exists already.
:ExistDelivery
if not exist "..\delivery_%MyDate%.txt" goto Begin
echo/
%SystemRoot%\System32\choice.exe /C YN /N /M "Delivery note already exists, continue (Y/N)? "
if errorlevel 2 goto :EOF

:Begin
set "FileName=file-%FileNumber%.ext"
copy "%Folder%\file.ext" "%Folder%\%FileName%" >nul
echo/
echo Choose the following:
echo/
echo    1. Directories
echo    2. Files
echo    3. Quit
echo/
%SystemRoot%\System32\choice.exe /C 123 /N /M "Your choice? "
if errorlevel 3 goto :EOF
if errorlevel 2 goto GetFileList

dir * /AD /ON /B >"..\delivery_%MyDate%.txt"
echo/
goto CheckSuccess

:GetFileList
dir * /A-D /ON /B >"..\delivery_%MyDate%.txt"
echo/

:CheckSuccess
rem More commands.
endlocal

It was not really clear for me what the entire batch code is for at all.

It would have been also easier to write the determination of highest number in a file name on knowing the possible number range like 001 to 100. So I wrote a general solution for 001, 002, ..., 099, 100, 101, ..., 1000, ..., 2147483647.

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 /?
  • cls /?
  • copy /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • rem /?
  • set /?
  • setlocal /?
  • wmic /?
  • wmic os /?
  • wmic os get /?
  • wmic os get localdatetime /?

See also answer on Single line with multiple commands using Windows batch file for an explanation of & operator and read the Microsoft article about Using command redirection operators.

Mofi
  • 46,139
  • 17
  • 80
  • 143