1

I have a .txt file of which name is used as a reference with the format AS2204-1 according to the naming scheme ASyymm-sn with yy being the current year without century, mm being the current month and sn being a serial number with the current month. I try to get the current file name and increment the serial number by 1 on year and month unchanged, copy the new file name to the clipboard and then rename the text file.

This is my code so far:

@echo off
set yy=%date:~12,2%
set mm=%date:~4,2%
set /a sn=0

for %%a in ('dir *.txt') do (set filename=%%a)
set Fmm=%filename:~5,2%
if %Fmm%==%mm% (set /a sn=sn+1) else (set /a sn=1)
echo AS%yy%%mm%^-%sn% |clip 
ren "%filename%.txt"  "AS%yy%%mm%^-%sn%.txt"

I can't get the file name assigned to the variable filename.

What is wrong with my code and what would be a correct FOR loop?

Mofi
  • 46,139
  • 17
  • 80
  • 143
  • Your `for` syntax is off. See `for /?`. To evaluate a command, you need the `/f` switch. `"delims="` would be safer and the `dir` command needs the `/b` switch to output only the name and the `/a-d` switch to exclude folder names. Also see [npocmaca's answer](https://stackoverflow.com/a/19799236/2152082) for a list of safe methods to get a reliable and portable date/time string. – Stephan Apr 03 '22 at 09:08
  • first of all thanks for your answer! the reason my syntax is wrong is because i have no idea what im doing. can you pleas write the correct way of the for loop? – Avi Elishakov Apr 03 '22 at 12:58
  • `cd /d "H:\ere is\the folder\containing the text file\"` and `for /f "delims=" %%a in ('dir /a-d /b *.txt') do ...` – Stephan Apr 03 '22 at 15:30
  • `Fmm` is `set` incorrectly. It should be `4,2` as batch defines the first character as character 0. You are defining `sn` as zero, then if the last `.txt` file find in the directory matches the current month, adding `1` to `sn` and if not, you are setting `sn` to 1. So `sn` will always acquire the same number - `1`. You don't say whether `sn` should be 1 or 2-digits, but you probably need to set `sn` to whatever follows `-`, then add 1 - and if no filenames match for the month, start at `1`. Oh, my! such possibilities. Easier to write **that** part as an answer... – Magoo Apr 03 '22 at 15:56

3 Answers3

0

There could be used the following batch file for this task:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /F "tokens=1,2 delims=/" %%G in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do set "YearMonth=%%G%%H" & goto SearchFile
:SearchFile
set "SerialNumber=0"
set "FileNameScheme=AS%YearMonth:~2%-"
for %%G in ("%FileNameScheme%*.txt") do for /F "tokens=2 delims=-" %%H in ("%%~nG") do if %%H GTR !SerialNumber! (set "SerialNumber=%%H" & set "FileName=%%G")
set /A SerialNumber+=1
echo %FileNameScheme%%SerialNumber%| %SystemRoot%\System32\clip.exe
if defined FileName (
    ren "%FileName%" "%FileNameScheme%%SerialNumber%.txt"
) else (
    rem del /Q "AS????-*.txt" >nul 2>nul
    echo %FileNameScheme%%SerialNumber%>"%FileNameScheme%%SerialNumber%.txt"
)
endlocal

The first two lines define the required execution environment completely which is:

  • command echo mode turned off
  • command extensions enabled
  • delayed variable expansion enabled

Please read the chapter Usage of ROBOCOPY to get current date/time in my answer on Time is set incorrectly after midnight for an explanation of the FOR command line which uses ROBOCOPY to get current year and month independent on which country (region) is configured for the used account which determines the date format of the dynamic variable DATE.

The environment variable SerialNumber is defined first with default value 0.

The environment variable FileNameScheme is defined with AS at beginning, the current year without the century with always two digits, the current month with always two digits and - which results today in the string AS2204-.

The command FOR is used to search in current directory (can by any directory) for one or more non-hidden files matching the wildcard pattern AS2204-*.txt.

It is unclear how my files can be in the current directory matching the wildcard pattern AS????-*.txt. Therefore the code is written to work also with multiple files matching this wildcard pattern in the current directory.

For each file name matching the wildcard pattern with current year and month already included one more FOR loop is used to get the string between the hyphen and the file extension which is hopefully always a number in range 0 to 2147483647 without leading zeros.

This number string is compared with the current value of the environment variable SerialNumber. Delayed variable expansion must be enabled because of this number comparison. If the number of the current file is greater the current serial number, the greater number is used further as serial number and the name of the current file is assigned to the environment variable FileName.

Please note that GTR does not work on number in file has a leading zero as in this case the number would be interpreted as an octal instead of a decimal number which means 08 and 09 would be interpreted as invalid octal numbers with using in this case value 0 for the number comparison.

The default value 0 or the greatest number of files matching AS2204-*.txt is next incremented by one using an arithmetic expression.

The file name with the incremented serial number is copied without file extension to the clipboard for whatever purpose.

If there was really found a file with current year and month in its name, this file is now renamed to contain the serial number incremented by one. Otherwise a new file is created with the new file name and containing the file name without file extension as data, for example AS2204-1.

There is a line commented out with command REM which would delete all files matching the wildcard pattern AS????-*.txt, except hidden files ignored by command DEL by default and read-only files which are not deleted by command DEL by default and matching files being currently opened by an application. It is not clear what to do with the other file(s) matching this pattern from former month(s).

The batch file code could be optimized to following command lines if there is either no or always just one file matching the wildcard pattern AS????-*.txt in the current directory:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=1,2 delims=/" %%G in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do set "YearMonth=%%G%%H" & goto SearchFile
:SearchFile
set "SerialNumber=0"
set "FileNameScheme=AS%YearMonth:~2%-"
for %%G in ("%FileNameScheme%*.txt") do for /F "tokens=2 delims=-" %%H in ("%%~nG") do set "SerialNumber=%%H"
set /A SerialNumber+=1
echo %FileNameScheme%%SerialNumber%| %SystemRoot%\System32\clip.exe
if exist "AS????-*.txt" (
    ren "AS????-*.txt" "%FileNameScheme%%SerialNumber%.txt"
) else (
    echo %FileNameScheme%%SerialNumber%>"%FileNameScheme%%SerialNumber%.txt"
)
endlocal

Delayed variable expansion is no longer needed which makes the processing of the batch file a very little bit faster. Serial numbers with one or more leading zeros would be still a problem because of command SET on evaluation of an arithmetic expression converts the number string also to an integer with interpreting the number as octal number on having the character 0 at beginning of the number string.

To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.

  • del /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • rem /?
  • robocopy /?
  • set /?
  • setlocal /?

See also:

Mofi
  • 46,139
  • 17
  • 80
  • 143
0
@echo off
setlocal
pushd "?:\whichever\directory\contains your\target files"
set "yy=%date:~12,2%"
set "mm=%date:~4,2%"

set "filename="    
for /f %%a in ('dir /b /a-d /od AS%yy%%mm%-*.txt 2^>nul') do (set "filename=%%~na")
rem use this line if you use suppressed leading zero
if defined filename (set /a "sn=%filename:*-=%+1") else (set /a sn=1)
rem use this line if you use 2-digit
if defined filename (set /a "sn=1%filename:~-2%+1") else (set /a sn=101)

IF %sn% gtr 100 SET "sn=%sn:~-2%"

echo AS%yy%%mm%-%sn%
ren "whatever.txt"  "AS%yy%%mm%-%sn%.txt"
POPD
goto :eof

The setlocal ensures that the environment changes (new variables) are removed when the batch terminates.

pushd switches to the specified directory. I've no idea what your directory is.

The syntax SET "var=value" (where value may be empty; in which case var becomes undefined) is used to ensure that any stray trailing spaces are NOT included in the value assigned.

The for /f assigns each line of the dir "report" to %%a in turn. In consequence, filename will be set to the name part only (%%~na) of the filename found. dir /b produces a list of files to be processed, in basic form (filename only). /a-d excludes directorynames, /od produces the list in date order. The filemask AS%yy%%mm%-*.txt asks for all .txt files which match AS+thecurrentyearnumber+thecurrentmonthnumber+-, so it's not necessary to check the year/month part. The 2^>nul suppresses error messages should no filename matching the mask be found.

If a filename was found, filename will be defined. That's why it's set to nothing (which undefines it) before the for loop.

The filenames must be produced in date order because ASyymm-10 will sort before ASyymm-2 in the default name-order list.

Well, I've no idea whether you use 1- or 2-digit serial numbers - the processing is different.

If you use the first if defined... then sn is set to 1 more than (that part of filename that exists when all characters up to the - are removed) or 1 if no prior file was found.

If you use the second if defined... then sn is set to 1 more than (1+the last 2 characters of filename) or 101 if no prior file was found, so ASyymm-07 would produce sn=108. This is necessary because batch interprets a numeric string beginning 0 as OCTAL in calculations.

if the result is >100, then use the last 2 characters of sn.

I've just echoed the required string to the screen. Echo to the clipboard if you wish.

Well - the rename. It's unclear what the file to be renamed to the calculated name is, so I've used whatever. Possibly it's a file named ASyymm.txt - if so, replace whatever with AS%yy%%mm%.

The popd returns to the original directory.

Documentation can be obtained by executing commandname /? for most commands but it can be a little cryptic at times. Simply search SO for examples.

Magoo
  • 77,302
  • 8
  • 62
  • 84
0

first of all thanks for all the answers! I did it that way - it works fine until the renaming part that just doesn't work - any idea why?

set "yy=%date:~12,2%"
set "mm=%date:~4,2%"

set "filename=\root\*.txt"

for %%A in (%filename%) do (set x=%%~nA)

set Fmm=%x:~4,2%
set sn=%x:7.1%

if %Fmm%==%mm% (set /a sn=sn+1) else (set /a sn=1)


echo AS%yy%%mm%^-%sn% |clip

set newfilename=AS%yy%%mm%-%sn%.txt
set oldfilename=%x%.txt

ren %oldfilename% %newfilename%