Quotes in variable - comparison and substitution - windows

I define variable like:
set LOGGING_MANAGER=-Djuli-logback.configurationFile=file:"%CATALINA_HOME%\conf\logback.xml"
Notice, that I wrap %CATALINA_HOME%\conf\logback.xml in double quotes, because path may contain spaces. And at execution step this variable will substitute to java program.
Example of substitution:
path_to_jre/java.exe %LOGGING_MANAGER%
Next code I can't change: (it's from catalina.bat file from Apache Tomcat)
if not "%LOGGING_MANAGER%" == "" ...
This if statement will fail, because variable contains quotes.
There I have one of 2 problems:
if statement fail (error occured).
without quotes when substitute to java program have problems (space is delimiter).
How can I change variable definition so that the path may contain spaces and if statement will work fine?

note: Not tested, but after reading the catalina.bat this is a way to deal with the problem.
If you are running this from a batch file, you can use
set LOGGING_MANAGER_FILE="%CATALINA_HOME%\conf\logback.xml"
set LOGGING_MANAGER=-Djuli-logback.configurationFile=file:%%LOGGING_MANAGER_FILE%%
set _RUNJAVA=CALL "%JRE_HOME%\bin\java.exe"
call catalina.bat
What it does is
Save the file name with quotes in a separate variable
Set the LOGGING_MANAGER variable using a escaped reference of the previous variable. As it will not be expanded, the final content of the LOGGING_MANAGER variable is -Djuli-logback.configurationFile=file:%LOGGING_MANAGER_FILE%
That way, when the if "%LOGGING_MANAGER%"=="" ... is executed, there will be not any problematic quote.
And now the set _RUNJAVA line. Inside catalina.bat, the contents of the _RUNJAVA are used to initialize the _EXECJAVA variable that will launch the server. _RUNJAVA is initialized in setclasspath.bat IF it has not been initialized by the user (code from setclasspath.bat).
rem Don't override _RUNJAVA if the user has set it previously
if not "%_RUNJAVA%" == "" goto gotRunJava
rem Set standard command for invoking Java.
rem Also note the quoting as JRE_HOME may contain spaces.
set _RUNJAVA="%JRE_HOME%\bin\java.exe"
The default value is "%JRE_HOME%\bin\java.exe", we just add a CALL batch command before to force a second iteration of the batch parser that will expand the quoted %LOGGING_MANAGER_FILE% variable in the final command line.

for %%a in ("%CATALINA_HOME%\conf\logback.xml") do set "LOGGING_MANAGER=-Djuli-logback.configurationFile=file:%%~sa"
should set logging_manager appropriately so that you don't have to "quote the filename"
for %%a in ("%CATALINA_HOME%\conf") do net use o: "\\%userdomain%\sharenameforthedrivewherecatalina_homeisresident%%~pa"
set "LOGGING_MANAGER=-Djuli-logback.configurationFile=file:o:\conf\logback.xml"
may also work - if you know the share name for the drive where catalina_home is resident and assuming o: is an unused drive.

Related

Windows bacth scripting: Problem exporting variable to txt

I have a variable with html code (having major, minor symbols)
and I need it to be exported and appended to a txt
set WORD1=^<p^>^<strong^>PROBLEM^</strong^> with something;n^</p^>
I can't echo the variable like this
echo %WORD1%
And I need to export it/append it to a file. I used:
echo %WORD1% >body.txt
But this generates an error as the variable has minor/Major symbol
If I double quote the variable, the exported text is exported with double quotes (and obviusly this is not what i need)
To define the variable, use:
set "WORD1=<p><strong>PROBLEM</strong> with something;n</p>"
To "export" the variable, use:
(
set /P "=%WORD1%"
echo/
) > body.txt < NUL
To define a variable in a safe way you need to enclose the whole assignment expression in quotation marks:
set "WORD1=<p><strong>PROBLEM</strong> with something;n</p>"
This avoids the need of escaping, unless the string itself contains quotation marks on its own.
Note that this syntax only works with command extensions enabled, but this is the default in Command Prompt anyway.
To return/expand an arbitrary string in a safe manner, even when it contains quotation marks on its own, is to use delayed variable expansion:
echo(!WORD1!
To safely write the output to a file, place the redirection expression at the front:
> "body.txt" echo(!WORD1!
You can also do this on one line:
set "WORD1=<p><strong>PROBLEM</strong> with something;n</p>"&&>body.txt cmd/v/cecho.!WORD1!
rem :: Or, without defining a previous variable, if it is not necessary:
>body.txt <nul set/P "=<p><strong>PROBLEM</strong> with something;n</p>"

How to assign a command line parameter which contains ! and & to a variable?

Please consider the following very simple batch script (the file is named test.cmd):
#echo off
set "var1=%~1"
echo %var1%
The script should be called with one command line parameter, should assign the string which is contained in that parameter to a variable, and should output the variable.
As expected, I get an error message when I call this script with a command line parameter which contains an ampersand (&):
C:\Batch>test "a&b"
a
'b' is not recognized as an internal or external command,
operable program or batch file.
The reason for this has been discussed in some other questions here and elsewhere, for example that one; the usual remedy is to use delayed expansion. So I changed the script accordingly:
#echo off
setLocal enableDelayedExpansion
set "var1=%~1"
echo !var1!
Now it works with the parameter from before:
C:\Batch>test "a&b"
a&b
But there is a new problem. When the command line parameter contains an exclamation mark (!), it will be dropped from the output:
C:\Batch>test a!b
ab
This behavior also has been discussed at several places, for example here; the crucial thing to note is that dropping the exclamation mark happens during the assignment, not during the echo.
Despite a lot of research, I did not find a question here which provided an elegant solution for both problems at once. That is, is there an elegant way to assign a command line parameter to a variable when that parameter contains an ampersand AND an exclamation mark?
It seems that I need the delayed expansion to treat the ampersand correctly, but this destroys the exclamation mark.
The only solution I currently see is to not use delayed expansion and to add code to explicitly quote all ampersands in the input string. This would be so ugly that I seriously think that I am missing something here.
As a side note, the reason for the problem actually seems to be that there (IMHO!) is no way to get the command line parameter in a delayed-expanded fashion. The syntax for the first parameter is %~1, there is no such thing as !~1.
Move the setLocal enableDelayedExpansion after the the set„ that's all.
#echo off
set "var1=%~1"
setLocal enableDelayedExpansion
echo !var1!

Replace %~db1 using SET

I'm trying to replace a string passed as an argument to a batch file.
This works:
set PWD="%~dp1"
set "PWD=%PWD:\=/%"
Which puts the passed argument's parent directory path inside PWD variable, and then replaces \ characters to / characters.
Is there a way to achieve this one liner by execution of just one command instead of two?
Something like this: set "PWD=%~dp1:\=/%, however, that doesn't obviously work.
Please elaborate both methods, using DelayedExpansion and not using it.
Did you test this before posting it?
Your code will produce
PWD=\=/
If it produces the "correct result" then it's because you're not clearing pwd at the end of each run (usually by a setlocal directly after the #echo off) and hence the result will be NOT of the current %~dp1 but of the previous setting of pwd.
Your code first sets pwd to be "c:\whatever..." (including the quotes) PLUS the Space before the & and then sets pwd again to the prior value of pwd with \ replaced by /.
cmd will resolve any expression involving %var% first, and then executes the result. With delayedexpansion, !var! is evaluated at run-time and %var% at parse-time.
Since string-manipulation is not allowed on metavariables, the required operation cannot be condensed into a single statement; the value must be passed through an ordinary environment variable first.
To fix your statement, use
set "PWD=%~dp1" & CALL set "PWD=%%PWD:\=/%%"
which will perform the string-manipulation in a subshell after first assigning the value to pwd - moving the quote delimits the command that will be executed - following spaces after the closing quote will not be included in the value assigned.

Special Characters in Batch File

Special characters in batch files are a pain, but I haven't found the right workaround for properly escaping the first two characters of this particular string I'm trying to pass the application.
SET pass=^&AntiBatchfileString
A_Program.exe /pass=%pass%
Things I have tried:
:: Escaping the escape twice, first for ^, second for &.
SET pass=^^^^&AntiBatchfileString
echo %pass%
:: Combining escapes.
SET first=^^
SET second=^^&AntiBatchfileString
SET pass=%first%%second%
echo %pass%
:: Preventing expansion
SET first=^^
SET second=^^&AntiBatchfileString
SET pass=!first!%second%
echo %pass%
:: I got this to print correctly
SET "pass=^&AntiBatchfileString"
echo ^^%pass%
Still when passing the last one it doesn't accept the login, I don't know what the final output is. That got me thinking maybe it was trying to do another expansion when passing the parameter to the application, so I quoted that as well.
SET "pass=^&AntiBatchfileString"
A_Program.exe "/pass=^^%pass%"
It's still not working, I'm not sure what I'm missing at this point.
Supposing you want the string ^&AntiBatchfileString literally, this is the best set syntax, as most special characters (^ & ( ) < > | and also the standard delimiters , ; = SPACE TAB) lose their particular meaning as soon as ther are placed in between "", and the "" themselves do not become part of the variable value:
set "pass=^&AntiBatchfileString"
This works only as long as the command extensions are on, which is the Windows default anyway (type cmd /? and see the /E option).
When expanding (reading) a variable like "%pass%" (with enclosing ""), special characters are still treated literally.
However, as soon as you expand it like %pass% (no ""), they get back their special meaning. So you have the following options:
Use set "pass=^^^&AntiBatchfileString", where ^^ escapes the literal ^ and ^& the literal & when reading like %pass%.
Enable delayed expansion (see set /? about how it works and setlocal /? or cmd /? about how to enable it), where the variable value is expanded (read) at a point of time where parsing of special characters has already been completed.
I prefer the latter approach, because no special escaping is necessary, and it can also deal with " appearing in the string value (even if unsymmetrically present).
By the way, " can also be escaped by ^", as long as this does not appear within unescaped "".
Nevertheless, % signs cannot be escaped like ^% in a batch file, because percent expansion happens before escaping, but you need to double them like %% to get one literal one each, independent whether or not the string is in between "".
Note that on the console, %% does not work.
Finally, literal ! are consumed by the delayed expansion feature when enabled, therefore you need to pay particular attention to those in case, by escaping them like ^!, or also by intelligently toggling delayed expansion (hence to enable it only when it is actually needed and to disable it otherwise, when a literal string is provided, like in a set command line, for instance, when expanding a standard variable like %pass% and when reading a for variable like %%I (batch file) or %I (console), for example). Of course this is also not the ultimate solution, because you need setlocal and endlocal to enable/disable delayed expansion, which are intended to localise environment changes, so any variable changes since the most recent setlocal command are lost as soon as endlocal is executed (there are some tricks for passing a variable value over the endlocal barrier though).
If you want to use % as a string without escaping in a batch file:
Like %20, you can use %%%20.
git clone "https:// abc.com /D%%%220an"

if statement is excuted even the conditions is wrong in batch

SET var=%6
IF NOT "%var%"=="" (
#ECHO "ijklkmn"
EXIT
IF %var:~-2,1%==\ SET var=%var:~0,-2%"
)
If %6 is not defined, then #ECHO "ijklkmn" and is not executed.
But why I still get There should be no 1var:~0。 error???
There are a few batch complexities that are causing your problem.
1) Parenthesized blocks are parsed in one pass. Your entire IF block must parse into valid syntax before the IF test is executed.
2) Substring expansion does weird things if the variable is undefined. The parser expands %var: into nothing, leaving the remainder of the substring expression, and the line parsing becomes entirely out of sync.
IF %var:~-2,1%==\ SET var=%var:~0,-2%"
First %var: expands to nothing, leaving IF ~-2,1%==\ SET var=%var:~0,-2%"
Next %==\ SET var=% is expanded into nothing, leaving IF ~-2,1var:~0,-2%"
Finally, the lone % is not paired, so it is stripped.
The final line after expansion is now IF ~-2,1var:~0,-2", which is invalid syntax.
See https://stackoverflow.com/a/7970912/1012053 for a detailed explanation of how % expansion works.
Your code could be "fixed" by 2 very non-intuitive changes: 1) Reverse the order of the comparison, 2) Add escaped quotes around the SET statement, and 3) add some additional text:
if "\"=="%var:~-2,1%" SET ^"var=%var:~0,-2%"^" ignore
If var is undefined, the above expands to:
if "\" == "~-2,1var:~0,-2"" ignore
The important thing is that the parsed syntax is valid. The ignore is needed because an IF statement needs a command after the condition in order for the parser to see it as valid. It would cause an error if executed because ignore is not a valid command. But it will never get executed because the condition is FALSE (also the outer IF condition is also false).
If var is defined, say with a value of "test\", then the line is expanded as you would think:
if "\" == "\" SET "var=test" ignore
The above executes perfectly because of the way the SET assignment is quoted. Anything after the final quote is ignored.
I say the above will "fix" your code, but I believe there are much better ways to completely restructure your code.
Update: Suggestions for restructuring
It looks to me as though you simply want to set a variable to the value of a quoted parameter, and if the last character in the value (not including quote) is \, then remove that character. It looks like you also have some test code inserted to try to diagnose why your code did not work. Ditching the test code, I recommend the following:
set var=%6
set "test=%var:~-2,1%"
if "%test%"=="\" set var=%var:~0,-2%"
I understand how file names and paths must be quoted to preserve spaces. But I don't like to include the quotes in my variable values. I like to strip the enclosing quotes from my parameters and then add them back only when needed. So my code would look like:
set "var=%~6"
set "test=%var:~-1,1%"
if "%test%"=="\" set "var=%var:~0,-1%"
If delayed expansion is enabled, then a simple solution no longer needs a test variable:
set var=%6
setlocal enableDelayedExpansion
if "!var:~-2,1!"=="\" set "var=!var:~0,-2!""
Or if stripping enclosing quotes:
set "var=%~6"
setlocal enableDelayedExpansion
if "!var:~-1,1!"=="\" set "var=!var:~0,-1!"
I would recommend using the Extension ability defined and everything that dbenham said.
#ECHO off
SET "var=%6"
IF NOT DEFINED var (
ECHO "ijklkmn"
EXIT
)
IF "%var:~-2,1%"=="\" SET "var=%var:~0,-2%""

Resources