How could I modify the following example code to check if the input parameter was given when starting the batch file?
Because the check IF NOT %MYDIR%==test fails and terminates the batch process if no paramter was provided.
SET MYDIR=%1
IF {no parameter given} OR NOT %MYDIR%==test (
ECHO dir is not "test"
)
It is surprisingly difficult to handle all possibilities when dealing with passed parameters. But the following strategy works under most "ordinary" situations.
if "%~1" equ "" echo arg 1 was not passed
It is important that the ~ modifier is used because you have no way of knowing if the passed argument is already enclosed in quotes. If an argument like "this&that" is passed and you don't first remove the quotes before adding your own, then you get if ""this&that"" equ "". The & is no longer quoted and your command no longer parses properly.
Strings cannot be completely empty, a common way to work around this constraint is to enclose strings in quotes like this
... OR NOT "%MYDIR%"=="test"
or you can add something meaningless without enclosing the string (ugly!)
... OR NOT XXX%MYDIR%==XXXtest
Related
I'm creating a simple program that will echo variables from SET /p strings into a nice, neat list. However, I am having trouble creating 2 working IF statements, one using NOT, and one using == to detect if one of my variables, %pwad%, is empty, or contains values. I want to use what the IF statement returns to set variable %finalpwad% to either "No pwad detected" or %pwad%.
How should I properly write this statement? Where might I need corrections, fixing the IF statements or maybe even the part where it sets %pwad% to %finalpwad%?
I have already tried fixing my call part and what they call from, but to no avail. I'm almost sure this is an IF statement issue, as I'm not too good with them, and always struggle reading the notes about the command from IF /?.
Here's a snippet of my code and the source of the problem I am having:
set /p pwad=Set a pwad (or none):
if %pwad% NOT [] call :yespwad & pause
if %pwad% == [] :nopwad & pause
:nopwad
set finalpwad=No pwad detected
goto :printout
:yespwad
set finalpwad=%pwad%
goto :printout
I expect the output to continue onto :printout, where it echoes all the variables the user enters, but it instead exits the program, and makes it so I can't find out whether it properly read my IF NOT or IF == statements. I rudimentarily added pauses to snuff out the problem and see where the source was, and I concluded it must the IF statements.
The help file clearly shows the proper syntax for comparing strings.
IF [NOT] string1==string2 command
It is recommended that you use quotes as well when comparing strings.
IF "string1"=="string2" command
IF comparisons are literal. Each side of the comparison has to match. Using brackets does not check for an empty string.
There also is an option to check if a variable is defined.
IF DEFINED VAR command
Looking at your logic you could essentially do this:
#echo off
set /p "pwad=Set a pwad (or none): "
IF DEFINED pwad (
set "finalpwad=%pwad%"
) ELSE (
set "finalpwad=No pwad detected"
)
The Problem
In a main batch file, values are pulled from a .txt file (and SET as values of variables within this batch file). These values may each contain % characters.
These are read from the .txt file with no issues. However, when a variable with a value containing a % character is passed to a second batch file, the second batch file interprets any % characters as a variable expansion. (Note: There is no control over the second batch file.)
Example
echo %PERCENTVARIABLE%
Output: I%LOVE%PERCENT%CHARACTERS%
When passed to a second file and then echo'ed, would (probably) become IPERCENT, as it interprets %LOVE% and %CHARACTERS% as unset variables.
Research
I found the syntax to find and replace elements within a string in a batch file, as I thought I could potentially replace a % character with %% in order to escape it. However I cannot get it to work.
The syntax is -
set string=This is my string to work with.
set string=%string:work=play%
echo %string%
Where the output would then be This is my string to play with..
Questions
Is it possible to escape % characters using the find and replace syntax
in a variable? (If not, is there another way?)
Is it advisable to do so? (Could using these escape characters cause any issue in the second batch file which (as mentioned above) we would have no control over?)
Is there another way to handle this issue, if the above is not possible?
There are no simple rules that can be applied in all situations.
There are a few issues that make working with string literals in parameters difficult:
Poison characters like &, |, etc. must be escaped or quoted. Escaping is difficult because it can be confusing as to how many times to escape. So the recommendation is to usually quote the string.
Token delimiters like <space>, <tab>, =, ; and , cannot be included in a parameter value unless it is quoted.
A CALL to a script will double any quoted % characters, and there is no way to prevent this. Executing a script without CALL will not double the % characters. But if a script calls another script and expects control to be returned, then CALL must be used.
So we have a catch-22: On the one hand, we want to quote parameters to protect against poison characters and spaces (token delimiters). But to protect percents we don't want to quote.
The only reliable method to reliably pass string literals without concern of value corruption is to pass them by reference via environment variables.
The value to be passed should be stored in an environment value. Quotes and/or escapes and/or percent doubling is used to get the necessary characters in the value, but it is very manageable.
The name of the variable is passed in as a parameter.
The script accesses the value via delayed expansion. For example, if the first parameter is the name of a variable containing the value, then it is accessed as !%1!. Delayed expansion must be enabled before that syntax can be used - simply issue setlocal enableDelayedExpansion.
The beauty of delayed expansion is you never have to worry about corruption of poison characters, spaces, or percents when the variable is expanded.
Here is an example that shows how the following string literal can be passed to a subroutine
"<%|,;^> This & that!" & the other thing! <%|,;^>
#echo off
setlocal enableDelayedExpansion
set "parm1="^<%%^|,;^^^^^> This ^& that^^!" & the other thing^! <%%|,;^^^>"
echo The value before CALL is !parm1!
call :test parm1
exit /b
:test
echo The value after CALL is !%1!
-- OUTPUT --
The value before CALL is "<%|,;^> This & that!" & the other thing! <%|,;^>
The value after CALL is "<%|,;^> This & that!" & the other thing! <%|,;^>
But you state that you have no control over the 2nd called script. So the above elegant solution won't work for you.
If you were to show the code of the 2nd script, and show exactly what value you were trying to pass, then I might be able to give a solution that would work in that isolated situation. But there are some values that simply cannot be passed unless delayed expansion is used with variable names. (Actually, another option is to put the value in a file and read the value from the file, but that also requires change to your 2nd script)
may be...?
input.txt
I%LOVE%PERCENT%CHARACTERS%
batch1.bat
#echo off
setlocal enableDelayedExpansion
set/P var=<input.txt
echo(In batch 1 var content: %var%
set "var=!var:%%=%%%%!"
call batch2.bat "%var%"
endlocal
exit/B
batch2.bat
#echo off
set "var=%~1"
echo(In batch 2 var content: %var%
exit/B
So I'm having trouble passing an argument with a period to a batch script file.
./myScript.bat 23.97
In my script, if I do
arg1 = %1
echo %arg1%
This will display 23.97 but if I do a comparison
arg1 = %1
if "%arg1%" == "23.97"
echo %arg1%
then it doesn't display at the argument at all. Fyi, i'm not trying to treat it at a float number, just a normal string. I'm no sure why it doesn't work, any help is appreciated. Thank you.
You can, in fact, have a dot (.) passed to a batch file as an argument. The section of your code that is causing you issue is the syntax that you use when setting the variable and using the if statement.
The correct syntax for setting a variable , as described by executing help set on the command line, is
Displays, sets, or removes cmd.exe environment variables.
SET [variable=[string]]
variable Specifies the environment-variable name.
string Specifies a series of characters to assign to the variable.
With this in mind, the correct way to set arg1 to the first argument passed to your batch file is
set arg1=%1
Your issue with the if statement is that you are trying to add a new line after the Boolean expression and before the next statement. The correct syntax is described by help if as
Performs conditional processing in batch programs.
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
Your if statement could be reveised to read like this:
if "%arg1%"=="29.37" echo arg1
Have seen passing argument to a batch file something like
filename.bat argument1 argument2 ..
But i want to pass something like
filename.bat username=argument1 password=argument2
As i dont want to depend on any order , user can pass password first and then username.
Look here : processing switches
Although this is oriented toward using the format /username argument1 it's relatively easy to adapt to username=argument1 but there is a problem with = when passed within "a" parameter - it's seen as a separator, so the receiving routine would see two parameters, but they'd be paired (username and argument1.)
Really depends on quite how you want to process the data. You can, if you so desire, pass the parameter "quoted" to get over the = is a separator problem, then use
for /f "tokens=1,*delims==" %%a in ("%~1") do set "%%a=%%b"
but remembering to use the quoting may be a stumbling block.
Note: using the procedure I've pointed to is not restricted by parameter-count.
I dont think you are able to pass parameters in a random order, as they are not identified by a parameter name, but by %0 - %9
see http://www.robvanderwoude.com/parameters.php
As mentioned here, you can use up tp 9 parameters when calling a batch file..
You could achieve this by using a variable substring since username= and password= are both 9 character long.
For example
set temp=%0
set temp=%temp:~0,9%
if %temp%=="username=" (
set tmpUser=%0
set username=%tmpUser:~9%
set tmpPass=%1
set password=%tmpPass:~9%
)
if %temp%=="password=" (
set tmpPass=%0
set password=%tmpPass:~9%
set tmpUser=%1
set username=%tmpUser:~9%
)
Within my batch file I have a variable that contains a file path:
SET VAR1=C:\Folder1\Folder2\File.txt
I would like to extract on the directory structure and retreive:
C:\Folder1\Folder2\
I have read threads like this where I need to use %~dp0 where 0 I believe is passed as a parameter. I have tried %~dpVAR1 but that doesn't work. How can I get the output I'm looking for, but with a variable containing the file path?
Also, to make matters difficult, I have to perform all of this within an IF condition which means that once the variable is declared, I will need to refer to it with ! instead of % (I have declared setlocal enableextensions enabledelayedexpansion at the beginning of my script to allow for this).
Any help is much appreciated!
Thanks!
Andrew
You are attempting to use parameter expansion syntax on an environment variable - that cannot work. But it is relatively easy to do what you want.
Using a CALL (relatively slow):
(...
call :getPath "!var!" var
...
)
exit /b
:getPath
set "%2=%~dp1"
exit /b
Using FOR, assuming the variable does not contain any wildcards (fast)
(...
for %%F in ("!var!") do set "var=%%~dpF"
...
)
Using FOR, if the variable may contain wildcards (also fast)
(...
for /f "delims=" %%F in ("!var!") do set "var=%%~dpF"
...
)
Note 1: If the variable does not contain the full path, then all the solutions will attempt to resolve the name into an absolute path and will return the full absolute path. For example, if var contains foobar\test.txt, then the solutions will include the full path to the current directory, even if the file is not found. Something like c:\pathToCurrentDirectory\foobar\.
Note 2: All solutions above will remove all quotes from the path.
Note 3: A path could include the ! character, which will cause problems when expanding %~dp1 or %%~dpF because you have delayed expansion enabled. The delayed expansion will corrupt both ^ and ! if the value contains !. There is a solution that involves protecting both ! and ^. Here is a demonstration applied to the last solution above. The protection requires normal expansion, and since you are within a code block, it requires at least one CALL. It could be done without a subroutine, but it is easier with a subroutine. The subroutine assumes the variable is named var.
(...
call :getPath
...
)
exit /b
:getPath
set "var=!var:"=!"
set "var=!var:^=^^^^!"
set "var=%var:!=^^^!%" !
for /f "delims=" %%F in ("!var!") do set "var=%%~dpF" !
exit /b
I do believe (once again) many questions are on the same topic (string constraints, or splitting strings).
Instead of giving you the whole code, I'm going to give you a template and explain why %~dpVAR! didn't work.
Firstly, why %~dpVAR! did't work.
Before I get into modifiers, let's discuss parameters. You may know that batch files can parse parameters to each other. These parameters can be called by using a single percent sign (%) in front of the numbers 0-9. As far as I'm aware (someone might have made a way for more to be parsed), only 9 parameters can be parsed. You may think that is wrong (there's 10 parameters right?). Parameters 1-9 are parsed to the batch file (or function within one), %0 is the file path of the batch file (or function name). If you look, %~dp0 shares some (not really) resemblance to %0. This will be discussed below.
Secondly, the term %~dp0 has modifiers in it. Modifiers are things that modify variables (only in the case of parameters and those declared in for loops, you know the ones with double percent signs like %%i) and parameters. The modifier d expands the parameter to a drive letter only while p expands the parameter to a path only. You may think that these would contradict themselves, but parameters can be combined to create extremely wacky formats.
So, as you can see, you attempt at replacing 0 with your variable name failed because it's not specified for those sort of things.
Now, on to the template.
You can constrain variables (and put them into other variables) like this:
set variable=!variable:~offset,amount!
Don't worry if that seems confusing, I'm about to explain the components.
Firstly, notice that there is no /a switch. This is because this is not a mathematical function (don't really know why I added this). So, before I explain it, here's an example of what it would do to a variable name numbers that has the value of 0123456789.
set numbers=!numbers:~5,1!
By using that line of code, numbers would now equal 5. This is because it is recreating the variable with a smaller version of the original value (gee this is hard to explain). As you can see, there is a 5 where offset was on the template above. This is because it is skipping the first 5 characters and setting the variable as the next amount, or 1 character (I really hope you're getting this).
So basically, it sets a variable as a shorter value of a different (or the same) variable determined by the offset and the amount of characters to contain in it.
I really hope this helps because I probably wouldn't understand a word of this.
Can someone redirect this poor guy to a link explaining this better (I tried, ok!)?
Complete example of extracting paths from variable:
#echo off
set /p Fullpath="Specify full path: "
call :getPath %Fullpath% filename folder
echo %filename%
echo %folder%
pause
exit /b
:getPath
set "%2=%~nx1"
set "%3=%~dp1"
exit /b
Would this work:
SET VAR1=C:\Folder1\Folder2\File.txt
echo %var1%
Where Echo is the name of your exe.
%CD% may work as well: Echo %CD%