Windows Batch thinks 2AM is after 5PM - windows

Bit of a weird one. I've been messing around with windows batch and time comparisons to schedule a task. Now I know there's a million better ways to do it, but our work machines are pretty locked down, so a batch script seems like the easiest way to actually achieve what I needed without some crazy workaround. I'm also well aware that the idea behind this is pretty gross. I'm not looking for perfection here, I'm just looking for it to work.
Basically at 17:00 on the 23rd November, I needed to move a file from one place to another. Problem is that I wouldn't actually be physically present at that time due to some other commitments, so I figured a batch script that was stuck in a loop of nothing until a certain date/time would work. So I cobbled together the following quickly the night before:
:dateloop
if %date% LSS 23/11/2019 goto dateloop
:timeloop
if %time% LSS 17:00 goto timeloop
<xcopy operation goes here>
And ran it overnight. So imagine my surprise when I came to my machine the next morning to check my emails and noticed that the file had been moved. Thankfully I was able to revert the file and rescheduled my day to do it manually.
I ran some tests last night, making sure that the script didn't exit upon completion so I could read the echo output. And it turns out that it was all running fine until 2:00, when the script decided "yes, this is after 17:00".
I could test it again tonight, and I do plan to, with the time format written out the long way (17:00:00:00) but I was wondering if anyone could confirm before I do, as that's a good while away, if this is the cause of my problem?

If you type IF /? at the command prompt, the help text will include this:
If Command Extensions are enabled IF changes as follows:
IF [/I] string1 compare-op string2 command
IF CMDEXTVERSION number command
IF DEFINED variable command
where compare-op may be one of:
EQU - equal
NEQ - not equal
LSS - less than
LEQ - less than or equal
GTR - greater than
GEQ - greater than or equal
and the /I switch, if specified, says to do case insensitive string
compares. The /I switch can also be used on the string1==string2 form
of IF. These comparisons are generic, in that if both string1 and
string2 are both comprised of all numeric digits, then the strings are
converted to numbers and a numeric comparison is performed.
As you can see, comparison is on strings unless the strings to compare contain only numeric digits. As time contains the non-numeric characters ":" and ".", the time is treated as a string, and of course "2" comes after the "1" from "17:00".
However, with the command echo [%time%] you'll notice that if the time is less than 10, it adds a space at the front. Therefore, you can get correct results with a string comparison as long as you take the space into account. So replace your problematic statement with the following one:
if "%time%" LSS "17:00" goto timeloop
That should fix it.

If compares strings alphabetically or numbers.
You need to rework your code and compare times as numbers. So you also need a reliable way to get date parts as numbers - date and time variables are not suitable because they can be in different formats depending on your settings.
Try this instead:
#echo off
::GOTO comment macro
set "[:=goto :]%%"
::brackets comment macros
set "[=rem/||(" & set "]=)"
for /f %%# in ('wMIC Path Win32_LocalTime Get /Format:value') do #for /f %%# in ("%%#") do #set %%#
%[:%
echo %day%
echo %DayOfWeek%
echo %hour%
echo %minute%
echo %month%
echo %quarter%
echo %second%
echo %weekinmonth%
echo %year%
%:]%
:dateloop
if %year%%month%%day% LSS 20191132 goto dateloop
:timeloop
if %hour%%minute% LSS 1700 goto :timeloop

Related

Inside a Windows batch file, how can I break a for-loop after the time is larger than a certain hour of the day?

Background
I run a batch file at night (after 0:00) that needs to be run for a few hours.
For this, there is a simple loop:
for /l %%t in (1, 1, %1) do (
REM some commands that take a few minutes
)
REM some more commands that take a few minutes
The problem
When I reach a certain hour of the day, in the morning (say, 6:05), I want to break the loop and do something else.
What I've found
Sadly the only thing I've found about time is this one:
How do I get current date/time on the Windows command line in a suitable format for usage in a file/folder name?
But I don't understand how I can use the current time, compare it to a given time, and check which is larger.
As for breaking a loop, I'm not sure what's the official one, as I've found multiple solutions. Maybe "goto" is the best one, as shown here:
https://stackoverflow.com/a/60401897/878126
The question
Inside the loop, how can I compare the current time to a specific time of my choice (6:05 in the morning for this case), and break the loop, going further to other commands?
for /l %%t in (1, 1, %1) do (
REM some commands that take a few minutes
CALL :shouldistop
if defined breakloop echo Loop broken when T=%%t&goto nextstep
)
:nextstep
REM some more commands that take a few minutes
....
GOTO :eof
:shouldistop
:: Assume time format is h:mm:ss.cc (24hr; suppressed-leading-zero for hours)
set "breakloop=%time::=%"
set /a breakloop=%breakloop:.=% / 10000
if %breakloop% gtr 605 goto :eof
set "breakloop="
goto :eof
Much depends on your time format. My time format is, eg 23:12:06.26 and that's the string that appears in the magic variable time for me.
This code assumes that you use suppressed-leading-zero for the hour. Suppose we use 6:12:17.22 to trace how it works.
breakloop is initialised to 6:12:17.22 with the colons removed = 61217.22 (see set /? from the prompt for documentation, or there are thousands of examples on SO)
breakloop then has its . removed, yielding 6121722 and this is divided by 10000, setting breakloop to 612
Compare 612 to 605 - this is true, so goto end-of-file; otherwise, "set" the value of breakloop to nothing which removes it from the environment (it becomes undefined).
Note that if you want to include seconds, then you'd use /100 and 60530.
If you have leading-zeroes for the hour, then set breakloop to 1%time::=% initially, and use 10605 for the time (ie force-prefix the time with a 1 to ensure the calculation is performed in decimal, not octal)
=== without using subroutine
for /l %%t in (1, 1, %1) do (
REM some commands that take a few minutes
setlocal enabledelayedexpansion
set "now=!time!"
rem see whether hours is less than 10
if "!now:~1,1!==":" set "now=0!now!"
if "!now:~0,5!" gtr "06:05" endlocal& goto nextstep
endlocal
)
:nextstep
REM some more commands that take a few minutes
Use !now:~0,8! to compare against 06:05:30
The issue here is that a string comparison needs to be invoked if the data contains anything other than numeric characters and therefore we need to leading-zero-pad any time before 10:00 since a string-comparison is done character-by-character so 11:20 is LESS than 6:05 as 1 is less than 6.
The compare time must be in HH:MM format.
And we need to deal with extracting current time within a block, hence we need to invoke setlocal to allow !var! syntax and keep the endlocal commands balanced with the setlocal.
Much easier to use a subroutine, IMHO.

Batch file gives different values based on machine? [duplicate]

I am compressing files using WinZip on the command line. Since we archive on a daily basis, I am trying to add date and time to these files so that a new one is auto generated every time.
I use the following to generate a file name. Copy paste it to your command line and you should see a filename with a Date and Time component.
echo Archive_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.zip
Output
Archive_20111011_ 93609.zip
However, my issue is AM vs PM. The AM time stamp gives me time 9 (with a leading blank space) vs. 10 naturally taking up the two spaces.
I guess my issue will extend to the first nine days, first 9 months, etc. as well.
How do I fix this so that leading zeroes are included instead of leading blank spaces so I get Archive_20111011_093609.zip?
Another solution:
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set datetime=%%I
It will give you (independent of locale settings!):
20130802203023.304000+120
( YYYYMMDDhhmmss.<milliseconds><always 000>+/-<minutes difference to UTC> )
From here, it is easy:
set datetime=%datetime:~0,8%-%datetime:~8,6%
20130802-203023
For Logan's request for the same outputformat for the "date-time modified" of a file:
for %%F in (test.txt) do set file=%%~fF
for /f "tokens=2 delims==" %%I in ('wmic datafile where name^="%file:\=\\%" get lastmodified /format:list') do set datetime=%%I
echo %datetime%
It is a bit more complicated, because it works only with full paths, wmic expects the backslashes to be doubled and the = has to be escaped (the first one. The second one is protected by surrounding quotes).
Extract the hour, look for a leading space, if found replace with a zero;
set hr=%time:~0,2%
if "%hr:~0,1%" equ " " set hr=0%hr:~1,1%
echo Archive_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%hr%%time:~3,2%%time:~6,2%.zip
You should search; you can simply replace all spaces with zero set hr=%hr: =0% – jeb Oct 11 '11 at 14:16
So I did:
set hr=%time:~0,2%
set hr=%hr: =0%
Then use %hr% inside whatever string you are formatting to always get a two-digit hour.
(Jeb's comment under the most popular answer worked the best for me and is the simplest. I repost it here to make it more obvious for future users.)
As Vicky already pointed out, %DATE% and %TIME% return the current date and time using the short date and time formats that are fully (endlessly) customizable.
One user may configure its system to return Fri040811 08.03PM while another user may choose 08/04/2011 20:30.
It's a complete nightmare for a BAT programmer.
Changing the format to a firm format may fix the problem, provided you restore back the previous format before leaving the BAT file. But it may be subject to nasty race conditions and complicate recovery in cancelled BAT files.
Fortunately, there is an alternative.
You may use WMIC, instead. WMIC Path Win32_LocalTime Get Day,Hour,Minute,Month,Second,Year /Format:table returns the date and time in a invariable way. Very convenient to directly parse it with a FOR /F command.
So, putting the pieces together, try this as a starting point...
SETLOCAL enabledelayedexpansion
FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
SET /A FD=%%F*1000000+%%D*100+%%A
SET /A FT=10000+%%B*100+%%C
SET FT=!FT:~-4!
ECHO Archive_!FD!_!FT!.zip
)
I found the best solution for me, after reading all your answers:
set t=%date%_%time%
set d=%t:~10,4%%t:~7,2%%t:~4,2%_%t:~15,2%%t:~18,2%%t:~21,2%
echo hello>"Archive_%d%"
If AM I get 20160915_ 150101 (with a leading space and time).
If PM I get 20160915_2150101.
#For /F "tokens=1,2,3,4 delims=/ " %%A in ('Date /t') do #(
Set DayW=%%A
Set Day=%%B
Set Month=%%C
Set Year=%%D
Set All=%%D%%B%%C
)
"C:\Windows\CWBZIP.EXE" "c:\transfer\ziptest%All%.zip" "C:\transfer\MB5L.txt"
This takes MB5L.txt and compresses it to ziptest20120204.zip if run on 4 Feb 2012
You can add leading zeroes to a variable (value up to 99) like this in batch:
IF 1%Var% LSS 100 SET Var=0%Var%
So you'd need to parse your date and time components out into separate variables, treat them all like this, then concatenate them back together to create the file name.
However, your underlying method for parsing date and time is dependent on system locale settings. If you're happy for your code not to be portable to other machines, that's probably fine, but if you expect it to work in different international contexts then you'll need a different approach, for example by reading out the registry settings:
HKEY_CURRENT_USER\Control Panel\International\iDate
HKEY_CURRENT_USER\Control Panel\International\iTime
HKEY_CURRENT_USER\Control Panel\International\iTLZero
(That last one controls whether there is a leading zero on times, but not dates as far as I know).
From the answer above, I have made a ready-to-use function.
Validated with french local settings.
:::::::: PROGRAM ::::::::::
call:genname "my file 1.txt"
echo "%newname%"
call:genname "my file 2.doc"
echo "%newname%"
echo.&pause&goto:eof
:::::::: FUNCTIONS :::::::::
:genname
set d1=%date:~-4,4%
set d2=%date:~-10,2%
set d3=%date:~-7,2%
set t1=%time:~0,2%
::if "%t1:~0,1%" equ " " set t1=0%t1:~1,1%
set t1=%t1: =0%
set t2=%time:~3,2%
set t3=%time:~6,2%
set filename=%~1
set newname=%d1%%d2%%d3%_%t1%%t2%%t3%-%filename%
goto:eof
As others have already pointed out, the date and time formats of %DATE% and %TIME% (as well as date /T and time /T) are locale-dependent, so extracting the current date and time is always a nightmare, and it is impossible to get a solution that works with all possible formats since there are hardly any format limitations.
But there is another problem with a code like the following one (let us assume a date format like MM/DD/YYYY and a 12 h time format like h:mm:ss.ff ap where ap is either AM or PM and ff are fractional seconds):
rem // Resolve AM/PM time:
set "HOUR=%TIME:~,2%"
if "%TIME:~-2%" == "PM" if %HOUR% lss 12 set /A "HOUR+=12"
if "%TIME:~-2%" == "AM" if %HOUR% equ 12 set /A "HOUR-=12"
rem // Left-zero-pad hour:
set "HOUR=0%HOUR%"
rem // Build and display date/time string:
echo %DATE:~-4,4%%DATE:~0,2%%DATE:~3,2%_%HOUR:~-2%%TIME:~3,2%%TIME:~6,2%
Each instance of %DATE% and %TIME% returns the date or time value present at the time of its expansion, therefore the first %DATE% or %TIME% expression might return a different value than the following ones (you can prove that when echoing a long string containing a huge amount of such, preferrably %TIME%, expressions).
You could improve the aforementioned code to hold a single instance of %DATE% and %TIME% like this:
rem // Store current date and time once in the same line:
set "CURRDATE=%DATE%" & set "CURRTIME=%TIME%"
rem // Resolve AM/PM time:
set "HOUR=%CURRTIME:~,2%"
if "%CURRTIME:~-2%" == "PM" if %HOUR% lss 12 set /A "HOUR+=12"
if "%CURRTIME:~-2%" == "AM" if %HOUR% equ 12 set /A "HOUR-=12"
rem // Left-zero-pad hour:
set "HOUR=0%HOUR%"
rem // Build and display date/time string:
echo %CURRDATE:~-4,4%%CURRDATE:~0,2%%CURRDATE:~3,2%_%HOUR:~-2%%CURRTIME:~3,2%%CURRTIME:~6,2%
But still, the returned values in %DATE% and %TIME% could reflect different days when executed at midnight.
The only way to have the same day in %CURRDATE% and %CURRTIME% is this:
rem // Store current date and time once in the same line:
set "CURRDATE=%DATE%" & set "CURRTIME=%TIME%"
rem // Resolve AM/PM time:
set "HOUR=%CURRTIME:~,2%"
if "%CURRTIME:~-2%" == "PM" if %HOUR% lss 12 set /A "HOUR+=12"
if "%CURRTIME:~-2%" == "AM" if %HOUR% equ 12 set /A "HOUR-=12"
rem // Fix date/time midnight discrepancy:
if not "%CURRDATE%" == "%DATE%" if %CURRTIME:~0,2% equ 0 set "CURRDATE=%DATE%"
rem // Left-zero-pad hour:
set "HOUR=0%HOUR%"
rem // Build and display date/time string:
echo %CURRDATE:~-4,4%%CURRDATE:~0,2%%CURRDATE:~3,2%_%HOUR:~-2%%CURRTIME:~3,2%%CURRTIME:~6,2%
Of course the occurrence of the described problem is quite improbable, but at one point it will happen and cause strange unexplainable failures.
The described problem cannot occur with the approaches based on the wmic command as described in the answer by user Stephan and in the answer by user PA., so I strongly recommend to go for one of them. The only disadvantage of wmic is that it is way slower.
Your question seems to be solved, but ...
I'm not sure if you take the right solution for your problem.
I suppose you try to compress each day the actual project code.
It's possible with ZIP and 1980 this was a good solution, but today you should use a repository system, like subversion or git or ..., but not a zip-file.
Ok, perhaps it could be that I'm wrong.
I realise this is a moot question to the OP, but I just brewed this, and I'm a tad proud of myself for thinking outside the box.
Download gawk for Windows at http://gnuwin32.sourceforge.net/packages/gawk.htm .... Then it's a one liner, without all that clunky DOS batch syntax, where it takes six FOR loops to split the strings (WTF? That's really really BAD MAD AND SAD! ... IMHO of course)
If you already know C, C++, Perl, or Ruby then picking-up AWK (which inherits from the former two, and contributes significantly to the latter two) is a piece of the proverbial CAKE!!!
The DOS Batch command:
echo %DATE% %TIME% && echo %DATE% %TIME% | gawk -F"[ /:.]" "{printf(""""%s%02d%02d-%02d%02d%02d\n"""", $4, $3, $2, $5, $6, $7);}"
Prints:
Tue 04/09/2012 10:40:38.25
20120904-104038
Now that's not quite the full story... I'm just going to be lazy and hard-code the rest of my log-file-name in the printf statement, because it's simple... But if anybody knows how to set a %NOW% variable to AWK's output (yeilding the guts of a "generic" now function) then I'm all ears.
EDIT:
A quick search on Stack Overflow filled in that last piece of the puzzle, Batch equivalent of Bash backticks.
So, these three lines of DOS batch:
echo %DATE% %TIME% | awk -F"[ /:.]" "{printf(""""%s%02d%02d-%02d%02d%02d\n"""", $4, $3, $2, $5, $6, $7);}" >%temp%\now.txt
set /p now=<%temp%\now.txt
echo %now%
Produce:
20120904-114434
So now I can include a datetime in the name of the log-file produced by my SQL Server installation (2005+) script thus:
sqlcmd -S .\SQLEXPRESS -d MyDb -e -i MyTSqlCommands.sql >MyTSqlCommands.sql.%now%.log
And I'm a happy camper again (except life was still SOOOOO much easier on Unix).
I prever to use this over the current accepted answer from Stephan as it makes it possible to configure the timestamp using named parameters after that:
for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do set %%x
It will provide the following parameters:
Day
DayOfWeek
Hour
Milliseconds
Minute
Month
Quarter
Second
WeekInMonth
Year
You can then configure your format like so:
SET DATE=%Year%%Month%%Day%
So you want to generate date in format YYYYMMDD_hhmmss.
As %date% and %time% formats are locale dependant you might need more robust ways to get a formatted date.
Here's one option:
#if (#X)==(#Y) #end /*
#cscript //E:JScript //nologo "%~f0"
#exit /b %errorlevel%
#end*/
var todayDate = new Date();
todayDate = "" +
todayDate.getFullYear() +
("0" + (todayDate.getMonth() + 1)).slice(-2) +
("0" + todayDate.getDate()).slice(-2) +
"_" +
("0" + todayDate.getHours()).slice(-2) +
("0" + todayDate.getMinutes()).slice(-2) +
("0" + todayDate.getSeconds()).slice(-2) ;
WScript.Echo(todayDate);
and if you save the script as jsdate.bat you can assign it as a value :
for /f %%a in ('jsdate.bat') do #set "fdate=%%a"
echo %fdate%
or directly from command prompt:
for /f %a in ('jsdate.bat') do #set "fdate=%a"
Or you can use powershell which probably is the way that requires the less code:
for /f %%# in ('powershell Get-Date -Format "yyyyMMdd_HHmmss"') do set "fdate=%%#"
Adding other options to this list of answers.
you could have replaced empty space with a 0 something like echo %time: =0%
but that is still dependent, move that code to a buddy's PC in some other random place and you'll get funny outputs. So you can incorporate powershell's Get-Date:
for /f "tokens=*" %%i in ('PowerShell -Command "Get-Date -format 'yyyymmdd_HHmmss'"') do echo %%i.zip"
A space is legal in file names. If you put your path and file name in quotes, it may just fly. Here's what I'm using in a batch file:
svnadmin hotcopy "C:\SourcePath\Folder" "f:\DestPath\Folder%filename%"
It doesn't matter if there are spaces in %filename%.

Look for a file name from a set of files (in CMD)

I would like to find a video file name in a folder (it has ~1000 files) using Windows command line. But... there is a problem, I do not remember the video file name, I have some clues: The video was created between 2019/02/01 to 2019/05/31 (format: Year/Month/Day) and the hour was between 09:00:00 to 13:00:00 (format: Hour/Minute/Second).
The format about this video file name is: VID_YEARMONTHDAY_HOURMINUTESECOND.3gp , example: VID_20190226_155112.3gp . Sometimes the video file name could has this format: VID_YEARMONTHDAY_HOURMINUTESECOND WORDS.3gp , example: VID_20190226_155112 EJEMPLO1.3gp
I read for command from Microsoft Docs and I built this:
for %A in (VID_201902* VID_201903* VID_201904* VID_201905*) do (for %B in (090000,1,130000) do (if %A:~0,19%==%A:~0,13%%B% echo %A%))
I do not know why it does not work. I will explain the code: I get set of files from February to May, a nested for goes from 090000 to 130000 (it represents the hour) then I compare between actual file name %A AND file name %A with hour %B, because as I told I want hours between 09:00:00 to 13:00:00. Finally if my condition is accomplished I show video file name (%A).
I know that the code is not efficient. I ask: Why doesn't the code work?
To find the desired video files I would go for a totally different approach:
dir /B /A:-D "VID_*.3gp" | findstr /I /R /C:"^VID_20190[2-5][0-3][0-9]_09[0-5][0-9][0-5][0-9]" /C:"^VID_20190[2-5][0-3][0-9]_1[0-2][0-5][0-9][0-5][0-9]" /C:"^VID_20190[2-5][0-3][0-9]_130000"
The dir command returns all files (/A:-D) whose names begin with VID_ and end with .3gp as a bare list (/B) of file names, so no extra information is output. This list is piped (|) into the findstr command, which has got three case-insensitive (/I) search expressions (like regular expressions, /R, although findstr does not really support true regular expressions but only a tiny excerpt of them) defined, all of which cover the beginning (^) of the file name (VID_), the specified date range (Feb. to May 2019), _ and:
to cover time range 09:00:00 to 09:59:59: ^VID_20190[2-5][0-3][0-9]_09[0-5][0-9][0-5][0-9];
to cover time range 10:00:00 to 12:59:59: ^VID_20190[2-5][0-3][0-9]_1[0-2][0-5][0-9][0-5][0-9];
to cover the time 13:00:00: ^VID_20190[2-5][0-3][0-9]_130000;
Concerning your code: you are confusing for meta-variables with normal environment variables; the former look like %A, %B and do not support sub-string expansion (like ~0,19); the latter look like %A%, %VAR%, can be defined by set and do support something like %VAR:~0,19%. And the second loop should be for /L, by the way.
I would first extend the file name patterns a bit and use something like VID_201902??_*.3gp rather than VID_201902*, but this of course depends on what file names may actually occur.
I also would reduce the string portion to compare by if, because the first 13 characters of the left and the right expression are always equal, so they could be removed to get if "%VAR:~14,6%"=="%B" (let me recommend to use quotation for this string comparison).
Another problem is the value 090000 in for /L %B in (090000,1,130000) do, which is going to be treated as an octal value rather than a decimal one due to the leading 0 (see set). You could state 90000 instead and add a leading zero to %B later then when required though.
Since the for /L loop has to iterate 40001 times for each file, your code will be slow. As a better alternative, you could do for /L %B in (9,1,13) do and just compare the hour value, unless it is 13, where only 130000 is acceptable according to your specifications.
You are coming closer to a working variant in a comment of yours, but it lacks of delayed variable expansion, which is required when a variable is written and read within the same line or (parenthesised) block of code.
Anyway, to put all of the above together, the fixed code would be something like this, given that the Command Prompt has been started by cmd /V:ON before in order to enable delayed expansion:
for %A in ("VID_201902??_*.3gp" "VID_201903??_*.3gp" "VID_201904??_*.3gp" "VID_201905??_*.3gp") do #(set "STR=%~A" & for /L %B in (9,1,13) do #(set "NUM=%B" & (if !NUM! lss 10 set "NUM=0!NUM!") & if !NUM! lss 13 (if "!STR:~13,2!"=="!NUM!" echo/!STR!) else if "!STR:~13,6!"=="130000" echo/!STR!))
The same code would look like this in a batch script:
#echo off
setlocal EnableDelayedExpansion
for %%A in ("VID_201902??_*.3gp" "VID_201903??_*.3gp" "VID_201904??_*.3gp" "VID_201905??_*.3gp") do (
set "STR=%%~A"
for /L %%B in (9,1,13) do (
set "NUM=%%B"
if !NUM! lss 10 set "NUM=0!NUM!"
if !NUM! lss 13 (if "!STR:~13,2!"=="!NUM!" echo/!STR!) else if "!STR:~13,6!"=="130000" echo/!STR!
)
)
endlocal

How can I pad numbers with leading zeros, to a fixed length?

I've tried so sort this for the better part of the morning.
It is actually the same question as this one from 2013, to which no one replied:
batch script with FOR does not work
I'll do my best to format the code so that it is easy to follow and maybe I'll get an answer...
I am doing an archive project from our help desk ticket system.
For sorting purposes, the files will have the ticket number and the date.
However, the ticket number varies in length. To fix this, all ticket numbers are to be 6 digits, with the shorter numbers padded with preceding zeroes (i.e. 1234 becomes 001234).
I can get the ticket number, but I need to find its length to know how many zeroes to add.
This works:
echo off
set my_str=12345
set length=0
:Loop
if defined my_str (
set my_str=%my_str:~1%
set /A "length+=1"
goto Loop)
echo the string is %length% characters long
However, I get a bunch of ticket numbers in a list.
So, I read through this:
set statements don't appear to work in my batch file
And got lost reading this:
http://www.computing.net/howtos/show/batch-script-variable-expansion-win200-and-up/248.html
And I tried this:
setlocal enabledelayedexpansion
echo off
for /f %%a IN (test.txt) do (
set my_str=%%a
set length=0
:Loop
if defined my_str (
set my_str=!my_str:~1!
set /A "length+=1"
echo %length%
goto Loop)
echo the string is %length% characters long
)
But it only reads the FIRST line of test.txt
Why does the FOR /F loop fail?
How do I get it to work?
You do not need to know the length of the ticket number string (when you can assure it won't be longer than 6 characters), you can prefix 5 zeros and split off the last 6 characters then:
set my_str=12345
set my_str=00000%my_str%
set my_str=%my_str:~-6%
echo %my_str%
If you still want to get the string length, consult this post.
You cannot use goto within the for body as goto breaks the for loop context. However, you can call a sub-routine within for, which in turn may contain goto.
Your batch script does exactly what you are describing: reading the first line of a number of files (in your case, only the one file) and determining the length of the first line. I.e. you got the inner part of your for loop wrong.
I don't know the correct solution either but I think that this page may be of some help to you:
http://ss64.com/nt/for_f.html
I hope that helps.
This seems like a XY problem. Instead of worrying about calculating the length of a string, just use the built-in substring methods to create a padded string.
#echo off
setlocal enabledelayedexpansion
for /f %%a IN (test.txt) do (
set my_str=000000%%a
#echo !my_str:~-6!
)
The end result echo'ed will be a six-digit number left-padded with zeroes.

Batch Sorting System

So my batch file is supposed to do this:
I have a few hundred WinRAR generated "(NAME).part???.rar" files that i want to put into a generated folder tree.
It should put the first 10 files (from 001 to 010) into a new folder named 001 (not just 1).
Then it takes the next ten (011-020) and put them into 002.
I i have fixed everything with adding the zeros automaticly, and i tested all variables but i can't get the actual file movement to work.
Here is what i'm trying to execute:
move "%FILENAME%" %LOOP2%\
%LOOP2% and is just the var %LOOP% (which starts at 1 and goes +1 every tenth loop) with all needed zeros in front of it (so 007, 035 and 455 etc.).
%FILENAME% comes from some more variables:
set FILENAME=%NAME%.part%COUNT2%.rar
%NAME% holds the name of the file/files/filepack (?) i want to move,
e.g. "Splitted file.part001.rar" would be "Splitted file"
(entered by user)
%COUNT2% starts at 1 and increases every loop until it matches the user-entered %NUMBER% var, which is the last file number (e.g. 468). It comes from %COUNT% which i don't want to change, so i created %COUNT2%.
I tried almost everything but sometimes cmd tells me the file or directory wasn't found or it suddenly closes displaying something with "can't syntacticly be used here" for a brief moment.
(Also the message is translated from German!)
People talk lot about putting double percent signs or double quotes or no quotes and so on and i tried most combinations but still i can't get it to work.
Can someone give me the right syntax and tell me where and how i have to use quotes and double percent signs?
I know my code and this text is pretty messy but i'm still learning :)
Ofc i asked Dr. Google and Stackoverflow but i think my case is a bit specific.
You have not shown your code and there is no way to guess what the problem is, so I created my own:
#echo off
setlocal EnableDelayedExpansion
set /P "NAME=Enter name of file/files/filepack (NO quotes): "
set /P "NUMBER=Enter number of files to copy: "
set /A COUNT2=1000, LOOP2=1000
for /L %%i in (1,1,%NUMBER%) do (
set /A COUNT2+=1, COUNT2mod10=COUNT2 %% 10
if !COUNT2mod10! equ 1 (
set /A LOOP2+=1
md !LOOP2:~1!
)
move "%NAME%.part!COUNT2:~1!.rar" !LOOP2:~1!
)

Resources