There's a file called "Settings.txt", this file contains a lot of lines including the following variable line:
X 100
The number in this line is the variable part, "X" is a fixed text.
What I need is to check if that number is (less than 100) OR (equal or greater than 100) then based on the result > goto A or B.
The script could be something like:
IF >> "X 100" in "D:\Settings.txt" GEQ 100 goto A else goto B
:A
#echo the value is equal or greater than 100
pause & goto continue
:B
#echo the value is less than 100
pause
:continue
#the rest of the script
A mechanism to read from the Settings.txt file is needed to get the number.
#ECHO OFF
FOR /F "tokens=1,2" %%A IN ('findstr.exe /B "X [:digit:]+" "Settings.txt"') DO (SET "NUM=%%~B")
ECHO NUM is set to %NUM%
IF %NUM% GEQ 100 (GOTO ALABEL) ELSE (GOTO BLABEL)
:ALABEL
ECHO Do greater than or equal stuff
GOTO TheEnd
:BLABEL
ECHO Do less than stuff
GOTO TheEnd
:TheEnd
EXIT /B 0
I am writing a batch script where I check the length of PDF file names in a dir. If the file name is greater than 3 characters long then I need to break out of the for loop. This should happen at the very first problem file. My issue is that I can't seem to find a way to break out of the loop.
This is the code that I have and the output I get. My problem is that the errorCnt variable that I am using to set between 0 and 1 never changes to 1 even though I am setting it
echo STARTING SCRIPT
setlocal
set errorCnt=0
for %%a in (test*.pdf) do (
echo %%~a
SET "fullname=%%a"
SET "name=%%~na
call :strlen result name
call :finalresult
echo Error count is %errorCnt%
if %errorCnt%==1 (
echo break
goto :break
)
)
:break
goto :EOF
:strlen <resultVar> <stringVar>
(
setlocal EnableDelayedExpansion
set "s=!%~2!#"
set "len=0"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!s:~%%P,1!" NEQ "" (
set /a "len+=%%P"
set "s=!s:~%%P!"
)
)
)
(
endlocal
set "%~1=%len%"
exit /b
)
:finalresult
echo %name% - characters: %result%
if %result% GTR 3 GOTO error1
goto :EOF
:error1
echo ERROR: There are too many characters in this PDF filename.
set errorCnt=1
goto :EOF
OUTPUT:
STARTING SCRIPT
test1.pdf
test1 - characters: 5
ERROR: There are too many characters in this PDF filename.
Error count is 0
test2.pdf
test2 - characters: 5
ERROR: There are too many characters in this PDF filename.
Error count is 0
Ok I found my answer. The problem is that DOS / Batch treats for loop as one single command. What I mean is that if you set a variable before for loop is called then it remains the same no matter if you change it elsewhere in your code.
The work around is to use EnableDelayedExpansion.
Batch script for loop won't set variable
Once I change my code to this it works great.
echo STARTING SCRIPT
setlocal enabledelayedexpansion
...
rem notice the ! signs
if !errorCnt!==1 (
echo break
goto :break
)
STARTING SCRIPT
test1.pdf
test1 - characters: 5
ERROR: There are too many characters in this PDF filename.
Error count is 1
break
I have a batch file that I use to create new project folders for clients that walks a user through the creation process and adds the appropriate files and folders to a central location. I need to add an input section so they can put a date (not always current date) in and it is included in the naming of the files.
The issue I have, and I have hunted high and low and can't find my answer, is that I need to dummy proof the date input. I want the user to input the date in the MM-DD-YYYY format including dashes. It needs to then format it into YYYY-MM-DD. It needs to be smart enough that it forces the user to use the required format of MM-DD-YYYY; has to be numbers and dashes, no slashes, the right amount of characters, and so forth.
I haven't been able to find anything close to even remotely get me where I need to be so I am asking the awesome geniuses out there for help in this regard as it is driving me up a wall. Below is my script code. I need this input to go right after the job type is selected. "Please insert date (MM-DD-YYYY format): "
#echo off
setlocal EnableDelayedExpansion
set version=7.95
set projectpath="P:"
set workbookpath="\\server2\Documents\Blanks (DO NOT EDIT)\dryingworkbook_v3r75.xls"
set questions="\\server2\Documents\Blanks (DO NOT EDIT)\Abatement and Mold Questions.txt"
set notes="\\server2\Documents\Blanks (DO NOT EDIT)\Job Notes.docx"
set info="\\server2\Documents\Blanks (DO NOT EDIT)\Job Information.docx"
set bizname=1
ECHO =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ECHO = Welcome to SERVPRO Project Creation Wizard v%version% =
ECHO =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ECHO.
:sof
ECHO.
ECHO Is this new project for a Residential or Commercial job?
:loopJobType
SET /P jobtype=Enter [r] for Residential or [c] for Commercial:
ECHO.
IF "%jobtype%" == "r" GOTO :loopResidential
IF "%jobtype%" == "R" GOTO :loopResidential
IF "%jobtype%" == "c" GOTO :loopCommercial
IF "%jobtype%" == "C" GOTO :loopCommercial
GOTO :loopJobType
:loopResidential
ECHO You have chosen to create a new Residential job project.
ECHO.
set type=1
GOTO :loopFirstName
:loopCommercial
ECHO You have chosen to create a new Commercial job project.
ECHO.
set type=2
SET /p bizname=Please enter the business name:
ECHO.
IF "%bizname%"=="" GOTO :loopCommercial
:loopFirstName
SET /P FirstName=Please enter the insured's first name:
IF "%FirstName%"=="" GOTO :loopFirstName
call :format FirstName
:loopLastName
ECHO.
SET /P LastName= Please enter the insured's last name:
IF "%LastName%"=="" GOTO :loopLastName
call :format LastName
SET FullName=%LastName%, %FirstName%
SET FullBizName=%bizname% (%FullName%)
goto :ConfirmProject
:format
set Name=!%1!
set Head=%Name:~0,1%
set Tail=%Name:~1%
for %%a in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do set Head=!Head:%%a=%%a!
for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do set Tail=!Tail:%%a=%%a!
set %1=%Head%%Tail%
GOTO :eof
:ConfirmProject
ECHO.
IF "%type%" == "1" SET /P yesno=Are you sure you want to add "%FullName%" to the Project directory? [y/n]
IF "%type%" == "2" SET /P yesno=Are you sure you want to add "%FullBizName%" to the Project directory? [y/n]
IF "%yesno%" == "y" GOTO :CreateProject
IF "%yesno%" == "Y" GOTO :CreateProject
IF "%yesno%" == "n" GOTO :sof
IF "%yesno%" == "N" GOTO :sof
GOTO :ConfirmProject
:CreateProject
IF "%type%" == "1" SET ProjectName=%FullName%
IF "%type%" == "2" SET ProjectName=%FullBizName%
:: Create a folder containing a new project.
mkdir "%projectpath%\%ProjectName%"
ECHO.
ECHO.
ECHO Creating a Project directory for "%ProjectName%" ...
:: Create a folder within said project that will contain job documents.
ECHO Creating a Documents directory for "%ProjectName%" ...
mkdir "%projectpath%\%ProjectName%\Documents"
:: (Taken out of use 7-15-13) ECHO Adding a Job Information file for "%ProjectName%" ...
:: (Taken out of use 7-15-13) copy /-Y %info% "%projectpath%\%ProjectName%\Documents\Job Information - %ProjectName%.docx"
ECHO Documents directory creation for "%ProjectName%" finished ...
:: Create a folder within said project that will contain drying workbook(s).
ECHO Creating a Drying Workbook directory for "%ProjectName%" ...
mkdir "%projectpath%\%ProjectName%\Drying Workbooks"
:: Copy a new blank workbook to the project workbook directory and give it the proper name.
ECHO Adding a Drying Workbook for "%ProjectName%" ...
copy /-Y %workbookpath% "%projectpath%\%ProjectName%\Drying Workbooks\DRY 1_%ProjectName%.xls"
ECHO Adding an Abatement and Mold Questions file for "%ProjectName%" ...
copy /-Y %questions% "%projectpath%\%ProjectName%\Drying Workbooks\Abatement and Mold Questions.txt"
ECHO Drying Workbook directory creation for "%ProjectName%" finished ...
:: Create a folder within said project that will contain original photos.
ECHO Creating a Photos directory for "%ProjectName%" ...
mkdir "%projectpath%\%ProjectName%\"Photos
:: Create a folder within said project photo folder that will contain resized photos.
mkdir "%projectpath%\%ProjectName%\Photos\Resized"
mkdir "%projectpath%\%ProjectName%\Photos\Upload"
ECHO Photos directory creation for "%ProjectName%" finished ...
:: Add in Job Notes file.
ECHO Adding a Job Notes files for "%ProjectName%" ...
copy /-Y %notes% "%projectpath%\%ProjectName%\Job Notes - %ProjectName%.docx"
:: Log the creation of the project.
FOR /F "TOKENS=1* DELIMS= " %%A IN ('DATE/T') DO SET CDATE=%%B
For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set date=%%a%%b%%c)
echo off > "%projectpath%\Logs\%ProjectName% - [Project Created %date% by %computername%].txt"
ECHO Logging "%ProjectName%" creation date and time...
ECHO Project directory creation for "%ProjectName%" finished ...
GOTO :OpenProject
:OpenProject
:: Ask if the project should be opened now. If so open and close script, else close script.
set /p reply=Do you want to open the "%ProjectName%" project now? [y/n]
if "%reply%" == "y" %SystemRoot%\explorer.exe "%projectpath%\%ProjectName%"
IF "%yesno%" == "Y" %SystemRoot%\explorer.exe "%projectpath%\%ProjectName%"
GOTO :eof
IF "%yesno%" == "n" GOTO :No
IF "%yesno%" == "N" GOTO :No
exit
:No
ECHO.
ECHO.
ECHO You have successfully created a new project for %ProjectName%.
ECHO.
ECHO Press any key to exit . . .
PAUSE>NUL
:eof
The Batch file below check that the inserted date have the right format and that it represent a valid date, that is, that have the right number of days in each month, even for February on leap years!
#echo off
setlocal EnableDelayedExpansion
set i=0
for %%a in (31 28 31 30 31 30 31 31 30 31 30 31) do (
set /A i+=1
set dpm[!i!]=%%a
)
set /P "inDate=Please insert date (MM-DD-YYYY format): "
if "%inDate:~2,1%%inDate:~5,1%" neq "--" goto invalidDate
for /F "tokens=1-3 delims=-" %%a in ("%inDate%") do set "MM=%%a" & set "DD=%%b" & set "YYYY=%%c"
ver > NUL
set /A month=1%MM%-100, day=1%DD%-100, year=1%YYYY%-10000, leap=year%%4 2>NUL
if errorlevel 1 goto invalidDate
if not defined dpm[%month%] goto invalidDate
if %leap% equ 0 set dpm[2]=29
if %day% gtr !dpm[%month%]! goto invalidDate
if %day% lss 1 goto invalidDate
echo Date correct: %YYYY%-%MM%-%DD%
goto :EOF
:invalidDate
echo Bad date
You can check whether your string is valid easily with the findstr command.
set /p date= Please insert date (MM-DD-YYYY format):
echo %date%| findstr /r "^[0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]$">nul
if errorlevel 1 (
echo invalid date
)
pause
(^ means beginning of line, while $ stands for end of line.)
Now for the reformatting MM-DD-YYYY into YYYY-MM-DD, you can split your string and than reassemble it. Since it's a fixed format, this isn't too hard either:
set yyyy=%date:~6,4%
set mm=%date:~0,2%
set dd=%date:~3,2%
set newDate=%yyyy%-%mm%-%dd%
echo %newDate%
The first number in each command resembles the position where the string will be cut.
The second number resembles the length of the substring.
I made a function :getdate who test the date try it;
It will test if the separators are correct, the value range for thr month and the day and
if the values are NUM.
#ECHO OFF
setlocal enabledelayedexpansion
:GetDate
set /p $D=Enter a date (MM-DD-YYYY) :
set $separate=%$d:~2,1% %$d:~5,1%
for %%a in (%$separate%) do (if "%%a" neq "-" (echo Wrong Separator : %%a
pause
goto:Getdate))
set $D=%$D:-= %
set $c=1
for %%a in (%$d%) do (call:test !$c! %%a
set /a $c+=1)
if !$c!==4 set $DateOK=%$month%-%$day%-%$Year%
echo This DATE IS OK %$dateOK%
exit /b
:test
if %1 equ 1 (echo %2 | findstr [0-9][0-9]
if errorlevel 1 (echo Unvalid value for Month [NOT NUM]: %2
pause
goto:getdate)
if %2 GTR 12 (echo Unvalid value for Month [VALUR RANGE +]: %2
pause
goto:getdate)
if %2 LSS 1 (echo Unvalid value for Month [VALUR RANGE -]: %2
pause
goto:getdate)
set $month=%2)
if %1==2 (echo %2 | findstr [0-9][0-9]
if errorlevel 1 (echo Unvalid value for Day [NOT NUM]: %2
pause
goto:getdate)
if %2 GTR 31 (echo Unvalid value for Day [VALUR RANGE +] : %2
pause
goto:getdate)
if %2 LSS 01 (echo Unvalid value for Day [VALUE RANGE -]: %2
pause
goto:getdate)
set $day=%2)
if %1==3 (echo %2 | findstr [0-9][0-9][0-9][0-9]
if errorlevel 1 (echo Unvalid value for Year [NOT NUM] : %2
pause
goto:getdate)
set $Year=%2)
#ECHO OFF
SETLOCAL enabledelayedexpansion
CALL :getverdate
ECHO DATE %indate% is OK.
GOTO :EOF
::
:: Get and verify date in format mm-dd-yyyy; reformat as yyyy-mmm-dd
::
:regetdate
ECHO "%indate%" is not in format "MM-DD-YYYY" or is invalid
:getverdate
SET /p indate="Please insert date (MM-DD-YYYY format): "
IF NOT "%indate:~2,1%%indate:~5,1%"=="--" GOTO regetdate
SET checkdate=9%indate:-=%
IF NOT "%checkdate:~8%"=="%checkdate:~8,1%" GOTO regetdate
FOR %%a IN (0 1 2 3 4 5 6 7 8 9) DO SET checkdate=!checkdate:%%a=!
IF DEFINED checkdate GOTO regetdate
IF %indate:~3,2%==00 GOTO regetdate
FOR %%i IN (01:31 02:29 03:31 04:30 05:31 06:30 07:31 08:31 09:30 10:31 11:30 12:31) DO (
FOR /f "tokens=1,2delims=:" %%j IN ("%%i") DO IF %%j==%indate:~0,2% if "%%k" geq "%indate:~3,2%" GOTO goodday
)
GOTO regetdate
:goodday
IF "%indate:~-4%" geq "1980" IF "%indate:~-4%" leq "2099" GOTO goodyear
GOTO regetdate
:goodyear
SET /a checkdate=%indate:~-4% %% 4
IF "%indate:~0,2%%indate:~3,2%"=="0229" IF %checkdate% neq 0 GOTO regetdate
SET indate=%indate:~-4%-%indate:~0,2%-%indate:~3,2%
GOTO :eof
Here's another 'get and validate date` routine.
Note that in your code you should never set a variable called date. %date% will return the current date - it's a "magic variable" controlled by CMD. Other such variables include %time%, %random% and %errorlevel%. Setting any of these overrides the system-established value.
You could present the user with three prompts - year, month, day.
set /p y="Please enter year (YYYY): "
set /p m="Please enter month (MM): "
set /p d="Please enter day (DD): "
set date=%y%-%m%-%d%
If you would like to verify the length of the input something like:
if [%y:~4%] NEQ [] echo year entered incorrectly & goto :getDate
You can assume if %y% is greater than four characters - i.e. if %y:~4% is not null - that it has been entered incorrectly (see Dos Tips on string manipulation). The same principal applies for day and month, except they should be two characters.
Obviously for that example you would need to add the label :getDate before the user input.
You may use ReadFormattedLine subroutine for all kind of formatted input. For example, the command below read 3 numbers in a date format; the routine just accept digits, insert the hyphens and continue automatically after read the last digit. If the user delete characters, the hyphens are also deleted automatically.
call :ReadFormattedLine myDate="##-##-####" /M "Please insert date (MM-DD-YYYY format): "
This subroutine is written in pure Batch so it does not require any additional program, and it allows several formatted input operations, like read passwords, convert letters to uppercase, etc. You may download ReadFormattedLine subroutine from Read a line with specific format.
I want to read only first two lines in a batch file and store them in two different variables. I used this code:
#echo off
for /f "delims=''" %%f in (red.txt) do (
echo file is: %%f
set /A Counter+=1
call :a %counter%
echo Counter After Increment: %Counter%
echo.
)
:a
if %Counter% equ 1 (set "file1=%f"
echo first file is: %file1%)
if %Counter% equ 2 (set "file2=%f"
echo second file is: %file2%)
if %Counter% equ 4 exit
echo Counter after for loop: %Counter%
pause
but variables 'file1' and 'file2' show blank.
Any thought on how to go about it?
Your try is a bit overkill and the syntax is wrong.
Try this instead
<red.txt (
set /p line1=
set /p line2=
)
echo line1=%line1%
echo line2=%line2%
I want to create something like this
dup.bat infile outfile times
example usage would be
dup.bat a.txt a5.txt 5
at it would create file a5.txt that has the content of a.txt repeated 5 times
however I do not know how to do for loop in batch, how to do it?
You can do the loop like this:
SET infile=%1
SET outfile=%2
SET times=%3
FOR /L %%i IN (1,1,%times%) DO (
REM do what you need here
ECHO %infile%
ECHO %outfile%
)
Then to take the input file and repeat it, you could use MORE with redirection to append the contents of the input file to the output file. Note this assumes these are text files.
#ECHO off
SET infile=%1
SET outfile=%2
SET times=%3
IF EXIST %outfile% DEL %outfile%
FOR /L %%i IN (1,1,%times%) DO (
MORE %infile% >> %outfile%
)
For command line args
set input=%1
set output=%2
set times=%3
To do a simple for loop, read in from the input file, and write to the output file:
FOR /L %%i IN (1,1,%times%) DO (
FOR /F %%j IN (%input%) DO (
#echo %%j >> %output%
)
)
Instead of taking in an output file, you could also do it via command line:
dup.bat a.txt 5 > a5.txt
sigh
Compact Design:
SETLOCAL ENABLEDELAYEDEXPANSION
SET times=5
:Beginning
IF %times% NEQ 0 (TYPE a.txt>>a5.txt & SET /a times=%times%-1 & GOTO Beginning) ELSE ( ENDLOCAL & set times= & GOTO:eof)
Easy Reading:
SETLOCAL ENABLEDELAYEDEXPANSION
SET times=5
:Beginning
IF %times% NEQ 0 (
TYPE a.txt>>a5.txt
SET /a times=%times%-1
GOTO Beginning
) ELSE (
ENDLOCAL
set times=
GOTO:eof
)
Set your counter (times=5)
Start subroutine Beginning
If your counter doesn't equal 0, read a.txt and APPEND its contents to a5.txt, then decrement your counter by 1. This will repeat five times until your counter equals 0, then it will cleanup your variable and end the script.
SET ENABLEDELAYEDEXPANSION is important to increment variables within loops.