The following script commands check matching the command line argument %1 against the fixed word ala
<code>
#echo off
set one=%1
set two=%2
If NOT "%one%"=="%one:ala=%" ( echo the first argument contains the word "ala")
else ( echo no matching ! )
</code>
How to replace the fixed word "ala" with an argument %2 from the command line instead.
(because the simple replacement ala with %2 doesnt work).
Is there any better solution for comparing the argument strings ?
#ECHO OFF
SETLOCAL
ECHO %~1|FIND "%~2">NUL
IF ERRORLEVEL 1 (
ECHO "%~2" NOT found IN "%~1"
) ELSE (
ECHO "%~2" WAS found IN "%~1"
)
GOTO :EOF
Use the find facility. This avoids delayedexpansion but is relatively slow.
You need to use delayed expansion to accomplish that type of string replacement.
#echo off
setlocal enabledelayedexpansion
set "one=%~1"
set "two=%~2"
If NOT "%one%"=="!one:%two%=!" (
echo the first argument contains the word "%two%"
) else (
echo no matching
)
And you could also do it without delayed expansion using a technique with the CALL command.
#echo off
set "one=%~1"
CALL set "two=%%one:%~2=%%"
If NOT "%one%"=="%two%" (
echo the first argument contains the word "%two%"
) else (
echo no matching
)
Related
I would like to know if it is possible to make a more elegant solution for a batch file accepting arguments from another script.
Looked at the solution here: Windows Bat file optional argument parsing, but can't make it work.
I have 19 arguments passed to the batch file. Arguments from the 7th are optional (come from checkboxes).
I have a working code with this structure:
REM arg7 parsing
set LOGFILE=%7
if not "%LOGFILE%" == "LOGFILE" (
set LOGFILE=
) else (
shift /7
)
REM arg8 parsing
set ARG8=%7
if not "%ARG8%" == "ARG8" (
set ARG8=
) else (
shift /7
)
REM arg9 parsing
set ARG9=%7
if not "%ARG9%" == "ARG9" (
set ARG9=
) else (
shift /7
)
And so on for each optional argument.
But now there are a lot of lines of similar code and it feels to me it could be optimized somehow. I'm not very familiar with batch scripting, so my tries of storing arguments in a list and trying to apply the above mentioned solution didn't work.
Based on what you've posted, try this:
SET "_="
FOR %%I IN (
LOGFILE ARG8 ARG9
) DO IF "%7" EQU "%%I" (SET "%%I=%7" & SET _=T)
IF DEFINED _ SHIFT /7
Just insert the other arguments on line three as is obvious.
#echo off
REM process optional parameters:
shift&shift&shift&shift&shift
rem shift /5 :: couldn't get this to work...
set narg=6
:loop
shift
set /a narg+=1
if "%1" == "" goto :done
set arg%narg%=%1
goto :loop
:done
echo no more parameters
set arg
I would like to create a batch file to check if the file name has been written following certain rules.
The file name contains some parameters (letters and numbers) splitted by an hyphen character like :
FIN73-INV-2015-ANN
I would like to check the first two parameters (department name and document type) and above all check if the hypen has been written more than 1 time by mistake . e.g. FIN73--INV-2015-ANN
I have tried with the command FINDSTR but it seems that doesn't work because even if there are two hyphens the errorlevel is always 0 like in this case:
echo FIN73--INV-2015-ANN|FINDSTR /i "^[a-z]-[a-z]"
Do you have more suggestions ?
Thank you
for <StartOfString><letter><letter><letter><number><number><hyphen><letter>
use FINDSTR /i "^[a-z][a-z][a-z][0-9][0-9]-[a-z]"
If the count of letters/numbers are not known: FINDSTR /i "^[a-z]*[0-9]*-[a-z]"
#echo off
setlocal
rem Define valid departments and types, enclosed by slashes
set "departments=/FIN73/FIN83/"
set "types=/INV/INB/"
call :CheckFilename "FIN73-INV-ANN"
call :CheckFilename "FIN73--INV-2015-ANN"
call :CheckFilename "FIN93-INV-2015-ANN"
call :CheckFilename "FIN73-INX-2015-ANN"
call :CheckFilename "FIN73-INV-2015-ANN"
goto :EOF
:CheckFilename
setlocal EnableDelayedExpansion
set "filename=%~1"
echo/
echo Checking "%filename%"
rem Separate the filename in parts at hyphen
set i=0
for %%a in ("%fileName:-=" "%") do (
set /A i+=1
set "part[!i!]=%%~a"
)
if %i% lss 4 (
echo Error: missing parts
) else if %i% gtr 4 (
echo Error: duplicated hyphen
) else if "!departments:/%part[1]%/=!" equ "%departments%" (
echo Error: invalid department: %part[1]%
) else if "!types:/%part[2]%/=!" equ "%types%" (
echo Error: invalid type: %part[2]%
) else (
echo Name correct
)
exit /B
Output example:
Checking "FIN73-INV-ANN"
Error: missing parts
Checking "FIN73--INV-2015-ANN"
Error: duplicated hyphen
Checking "FIN93-INV-2015-ANN"
Error: invalid department: FIN93
Checking "FIN73-INX-2015-ANN"
Error: invalid type: INX
Checking "FIN73-INV-2015-ANN"
Name correct
I'm trying to determine if option is define statement/option for the VC compiler (/DSOME_OPTION=1 e.g.). Here is the part of options handling loop, which return error "Unexpected at this time: =option.". I've used search substring solution from StackOverflow: Batch file: Find if substring is in string (not in a file)
setlocal enabledelayedexpansion
:loop
if not "%~1"=="" (
rem all defines
set "option=%~1"
if x%option:/D=%==x%option% (
set DEFINE_STR=%DEFINE_STR% %~1
echo "DEFINE_STR=%DEFINE_STR%"
pause
)
shift
goto :loop
)
try this:
#echo off
setlocal enableDelayedExpansion
set "DEFINE_STR="
:loop
if not "%~1"=="" (
rem all defines
set "option=%~1"
if "!option:/D=!" == "!option!" (
set "DEFINE_STR=!DEFINE_STR! %~1"
echo "DEFINE_STR=!DEFINE_STR!"
pause
)
shift
goto :loop
)
endlocal
In this question you can find more info -> Why can I not get a substring of a delayed expansion variable in an if statement?
sample input in cmd:
test.bat /p 1,3,4
expected result:
1
3
4
my codes so far:
#echo off
set arg = %1
set var = %2
if (%1)==(/p) (
... need code that will read and print each character of var
)
There is a potential problem with your question. If test.bat is:
#echo %1%
Then
test 1,2,3
Prints:
1
Because, in this context, the comma is treated as an argument delimiter.
So you either need to enclose in quotes:
test "1,2,3"
Or use a different internal delimiter:
test 1:2:3
Unless you want the parts to be placed in %2, %3, etc., in which case you problem is solved by a trivial use of SHIFT.
For my solution I have elected to require quotes around the group parameter, "1,2,3" (though this is easily adapted for a different delimiter by changing delims=, to specify the character you want to use).
#echo off
setlocal ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
set args=%~2
if "%1"=="/p" (
:NextToken
for /F "usebackq tokens=1* delims=," %%f in ('!args!') do (
echo %%f
set args=%%g
)
if defined args goto NextToken
)
Call like:
readch.bat /p "1,2,3"
%~2 is used to remove the quotes.
The FOR statement parses args, puts the first token in %f and the remainder of the line in %g.
The `goto NextToken' line loops until there are no more tokens.
#echo off
if "%1"=="/p" (
:LOOP
echo %2
shift
set arg=%2
if defined arg goto :LOOP else exit >nul
)
set params=%%~2
if (%1)==(/p) (
set params=%params:,= %
)
if "%params%" NEQ "" (
call :printer %params%
)
goto :eof
:printer
:shifting
if "%%1" NEQ "" (
echo %%1
) else (
goto :eof
)
shift
goto :shifting
goto :eof
as discussed in an other thread How to avoid cmd.exe interpreting shell special characters like < > ^
it is not easy to get all parameters from the command line.
A simple
set var=%1
set "var=%~1"
are not enough, if you have a request like
myBatch.bat abc"&"^&def
I have one solution, but it needs a temporary file, and it is also not bullet proof.
#echo off
setlocal DisableDelayedExpansion
set "prompt=X"
(
#echo on
for %%a in (4) do (
rem #%1#
)
) > XY.txt
#echo off
for /F "delims=" %%a in (xy.txt) DO (
set "param=%%a"
)
setlocal EnableDelayedExpansion
set param=!param:~7,-4!
echo param='!param!'
It fails with something like myBatch.bat %a, it display 4 not the %a
in this situation a simple echo %1 would work.
It's obviously the for-loop but I don't know how to change this.
Perhaps there exists another simple solution.
I don't need this to solve an actual problem, but I like solutions that are bullet proof in each situation, not only in the most cases.
I don't think anyone found any holes in this, except for the inability to read newlines in the parameters:
#echo off
setlocal enableDelayedExpansion
set argCnt=1
:getArgs
>"%temp%\getArg.txt" <"%temp%\getArg.txt" (
setlocal disableExtensions
set prompt=#
echo on
for %%a in (%%a) do rem . %1.
echo off
endlocal
set /p "arg%argCnt%="
set /p "arg%argCnt%="
set "arg%argCnt%=!arg%argCnt%:~7,-2!"
if defined arg%argCnt% (
set /a argCnt+=1
shift /1
goto :getArgs
) else set /a argCnt-=1
)
del "%temp%\getArg.txt"
set arg
The above comes from a lively DosTips discussion - http://www.dostips.com/forum/viewtopic.php?p=13002#p13002. DosTips user Liviu came up with the critical SETLOCAL DisableExtensions piece.
The code below is based on the rambling Foolproof Counting of Arguments topic on DosTips and this answer by jeb:
#echo off & setLocal enableExtensions disableDelayedExpansion
(call;) %= sets errorLevel to 0 =%
:: initialise variables
set "paramC=0" & set "pFile=%tmp%\param.tmp"
:loop - the main loop
:: inc param counter and reset var storing nth param
set /a paramC+=1 & set "pN="
:: ECHO is turned on, %1 is expanded inside REM, GOTO jumps over REM,
:: and the output is redirected to param file
for %%A in (%%A) do (
setLocal disableExtensions
set prompt=#
echo on
for %%B in (%%B) do (
#goto skip
rem # %1 #
) %= for B =%
:skip - do not re-use this label
#echo off
endLocal
) >"%pFile%" %= for A =%
:: count lines in param file
for /f %%A in ('
find /c /v "" ^<"%pFile%"
') do if %%A neq 5 (
>&2 echo(multiline parameter values not supported & goto die
) %= if =%
:: extract and trim param value
for /f "useBack skip=3 delims=" %%A in ("%pFile%") do (
if not defined pN set "pN=%%A"
) %= for /f =%
set "pN=%pN:~7,-3%"
:: die if param value is " or "", else trim leading/trailing quotes
if defined pN (
setLocal enableDelayedExpansion
(call) %= OR emulation =%
if !pN!==^" (call;)
if !pN!=="" (call;)
if errorLevel 1 (
for /f delims^=^ eol^= %%A in ("!pN!") do (
endLocal & set "pN=%%~A"
) %= for /f =%
) else (
>&2 echo(empty parameter values (""^) not supported & goto die
) %= if errorLevel =%
) else (
:: no more params on cmd line
set /a paramC-=1 & goto last
) %= if defined =%
:: die if param value contains "
if not "%pN:"=""%"=="%pN:"=%" (
>&2 echo(quotes (^"^) in parameter values not supported & goto die
) %= if =%
:: assign nth param, shift params, and return to start of loop
set "param%paramC%=%pN%" & shift /1 & goto loop
:last - reached end of params
:: no param values on cmd line
if %paramC% equ 0 (
>&2 echo(no parameter values found & goto die
) %= if =%
:: list params
set param
goto end
:die
(call) %= sets errorLevel to 1 =%
:end
:: exit with appropriate errorLevel
endLocal & goto :EOF
The following conditions will terminate the program immediately:
no parameters found
multiline parameter
empty parameter (""", or " is permitted for the last parameter)
one or more quotes (") in a parameter value
To ease these restrictions, simply comment out the relevant lines. Read the inline comments for more information. Do not attempt to turn off the multiline parameter trap!
I invented the syntax-error-technic to solve the problem (partially).
With this solution it's even possible to receive multiline parameters and also carriage return characters.
There is no known parameter which fails!
BUT the drawback of this solution, the main process exits and only a child process continues.
That is a consequence of the capture trick, a syntax error is created by using an invalid parenthesis block ( Prepare ) PARAMS....
But the syntax error itself outputs the complete block, including the expanded value of %*.
The output is redirected to a file by the permanent redirect technic.
And the child process can retrieve the complete parameter from the file.
This solution can be useful, when the batch file only handles the parameter and always exit afterwards.
#echo off
REM *** Thread redirector
for /F "tokens=3 delims=:" %%F in ("%~0") do goto %%F
REM *** Clear params.tmp
break > params.tmp
start "" /b cmd /k "%~d0\:StayAlive:\..\%~pnx0 params.tmp"
(set LF=^
%=empty=%
)
REM *** Change prompt for better recognition
prompt #PROMPT#
REM *** Change streams permanently
REM *** stream1 redirects to params.tmp
REM *** stream2 redirects to nul
echo on >nul 2>nul 0>nul 3>params.tmp 4>nul 5>&3
#REM *** This is the magic part, it forces a syntax error, the error message itself shows the expanded %asterix without ANY modification
( Prepare ) PARAMS:%LF%%*%LF%
echo Works
exit /b
REM *** Second thread to fetch and show the parameters
:StayAlive
:__WaitForParams
if %~z1 EQU 0 (
goto :__WaitForParams
)
REM *** Show the result
findstr /n "^" %1
It's up to the user who types the command to escape any special characters. Your program cannot do anything about what the shell does before your program even runs. There is no other "bullet proof" solution to this.