I am trying to make a batch script, that creates a new batch script called MigrateOldStickyNotes.bat with a couple of simple commands in it.
#echo SET CP=%~dp0> "%cp%\%ME%\%ME%\MigrateOldStickyNotes.bat"
#echo SET ME=%Username%>> "%cp%\%ME%\%ME%\MigrateOldStickyNotes.bat"
But insteadt of creating af new batchfile with these to lines that looks exactly like this.
SET CP=%~dp0
SET ME=%Username%
It will create a new file and use the variable as input. which will result i these to lines.
SET CP=\\sosy-nas\Backup\
SET ME=itcebrha
How do i make the script treat the variable as string insteadt of treating it as a variale.
Escape the percent signs with a percent sign, like SET CP=%%~dp0.
All other (special) characters are escaped with a caret ^.
The cause is that percent signs are handled in another phase of the batch parser than all other charaters.
That's also the cause why escaping of percent signs works only in batch files, but not on the command line, as there the cmd-line parser have different expansion rules for percent signs.
Related
I am writing a bat file to automate the process of the below Codeception command.
php vendor/bin/codecept run tests/acceptance/SigninCest.php:^anonymousLogin$
The problem is that I cannot output the ^ character for example:
set functionNamePrefix=^^
set output=php vendor/bin/codecept run tests/acceptance/SigninCest.php:
set functionName=anonymousLogin
set functionNamePostFix=$
set command=%output%%functionNamePrefix%%functionName%%functionNamePostFix%
the $ symbol is correctly displayed but the ^ is not.
Any advice?
Thanks
Enclose the variable in quotes:
set "functionNamePrefix=^^"
Now the variable %functionNamePrefix% will contain ^.
Special characters such as the %|^ are seen as operators to cmd.
When you set functionNamePrefix=^^ and try to echo it, you effectively allow cmd to utilize the special character. Therefore, echo %functionNamePrefix% will give the more prompt, as cmd is expecting the next input line because of the ^.
When however you double quote a string, you are excluding the character in the current cmd run. It is however also recommended to double quote strings when using set to ensure you eliminate unwanted whitespace. For instance:
set var=value
Note the accidental space after value, this space will form part of the value as long as it exists, so enclose everything in double quotes to play safe and to ensure the special characters are not becoming functions in the current batch run.
set "functionNamePrefix=^^"
set "output=php vendor/bin/codecept run tests/acceptance/SigninCest.php:"
set "functionName=anonymousLogin"
set "functionNamePostFix=$"
set "command=%output%%functionNamePrefix%%functionName%%functionNamePostFix%"
I'm trying to pass through caret chars through batch.
Escaping them once would be easy, but I need to do it twice.
I have an executable that will back up tables based on a Regex expression (not my code).
I want to back up all tables with an exclusion list.
Using ^(?!tableName$).* works for a single table.
Batch File 1 (called from command line)
SET ignoreTables=tableName
:: Call the backup script
CALL SecondBatch.bat %ignoreTables%
Batch File 2
:: Passthrough ignoreTables
Executable.exe --ignoreTablesPattern="^(?!%1$).*"
But I'd like to ignore multiple tables. In Regex this means using the | (pipe) character eg; tableOne|tableTwo would require;
SET ignoreTables=tableOne^|tableTwo
Which is correct at the SET but not when passed to the CALL
The correct output that works from the command line is;
Executable.exe --ignoreTablesPattern="^(?!tableOne|tableTwo$).*"
How can I get this result out of the batch file?
In batch file 1 use:
SET "ignoreTables=tableOne|tableTwo"
:: Call the backup script
CALL SecondBatch.bat "%ignoreTables%"
And in batch file 2 use:
:: Passthrough ignoreTables
Executable.exe --ignoreTablesPattern="^(?!%~1).*$"
Run in a command prompt window cmd /? and read the output help pages, especially the last paragraph on last help page which is about when surrounding a directory/file name or parameter string with double quotes is required.
The first line of batch file 1 contains the command SET with the parameter string variable=value. By enclosing this parameter string in double quotes the pipe character is not interpreted anymore as operator. For more details about using double quotes on assigning a string to an environment variable see answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line?
The value of the environment variable is passed next expanded as first parameter to batch file 2. Again surrounding double quotes are needed to pass the string containing | as literal string to the second batch file.
In the second batch file it is necessary to reference the first argument without surrounding quotes. Therefore %~1 is used now instead of %1 as explained in help of command CALL output on running in a command prompt window call /?.
BTW: I'm quite sure $ should be at end of the regular expression and not inside the negative lookahead.
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
I need to run a command in a DOS batch file that contains a double colon AND set the output to a variable. Like this
set /a TDR = C:\InCharge\CONSOLE\smarts\bin\dmctl -s SSA-SAM invoke SM_System::SM-System nameToAddr %SM_OBJ_InstanceName%
I keep getting "Missing operator". I assume that is due to those double-colons. How do I escape these? I tried back-slashes but that didn't work. I've tried putting the whole command in double-quotes and that also didn't work.
I can run the command by itself, ie without the "set /a TDR" and the output is correct. But I need to use that output as the value of a variable hence the "set /a"
Normal output for dmctl is this
{ "10.28.112.74" }
I am using dmctl to get the ip address for the hostname. I figured once I got the output I could strip off the brackets and quotations, but I haven't figured out how to grab the output.
Thank you in advance.
Colons do not need to be escaped. See Batch files - Escape Characters for details on what characters need to be escaped, and how to escape them.
"Missing operator" is being returned because SET /A only works with arithmetic operations, so it is looking for an arithmetic operator.
To assign the output of a command to a variable, you have to use the FOR command, similar to the following:
for /f "delims=" %%i in ('C:\InCharge\CONSOLE\smarts\bin\dmctl -s SSA-SAM invoke SM_System::SM-System nameToAddr %SM_OBJ_InstanceName%') do set myresult=%%i
See Reading the output of a command into a batch file variable
To trim 3 characters from the beginning and end of a string:
set mystring=%mystring:~3,-3%
This will remove the curly braces, spaces, and quotation marks that delimit the IP address in the output.
I found this at DOS - String Manipulation.
I don't know how to describe exactly what I'm trying to do but here's an example batch file that demonstrates what I can't figure out.:
I've got a batch file. Inside that batch file I'm trying to create a directory:
Set CopyFrom = %~dp0
if Exist "%ProgramFiles(x86)" (
Set TargetDir = %ProgramFiles(x86)%\My Directory Name has spaces
)
md %TargetDir%\NewSubFolder
copy %CopyFrom%\SourceFile.zip %TargetDir%\NewSubFolder
My batch file is failing on line 4 Set TargetDir =... with:
\My was unexpected at this time
I'm assuming this is because I have spaces in my path name. I thought I could just wrap my variable with quotes:
Set TargetDir = "%ProgramFiles(x86)%\My Directory Name has spaces"
But then when I get to the line that creates the directory it fails because %TargetDir% is now wrapped in quotes. md "%TargetDir%"\NewSubFolder
Can this be fixed or should I just write a VBScript to sort things out?
Just put your expression in quotes like this:
C:\>Set "TargetDir=%ProgramFiles%\My Directory Name has spaces"
C:\>echo %TargetDir%
C:\Program Files\My Directory Name has spaces
Note: It will expand the variable within the quotes, and if it too has spaces, it will need to be quoted.
Now you can quote it to perform your operation:
md "%TargetDir%\NewSubFolder"
The problem in question here are not the spaces as others suggested, but rather the closing parenthesis in the environment variable ProgramFiles(x86) This causes the parser to think that the block ends prematurely (shameless self-promotion).
Quotes do help in this case because they make the parser jump over the whole quoted part and rightly assume the following parenthesis to be the actual closing one. but the fix might be much easier than that:
if Exist "%ProgramFiles(x86)%" Set TargetDir=%ProgramFiles(x86)%\My Directory Name has spaces
Why use a parenthesized block at all if all you do it put exactly one command into it?
set itself doesn't need any quotes, except when its arguments contain special characters like <, >, |, & which the shell itself aready handles. It isn't a panacea, though which makes handling user input or file contents correctly a pain at times.
Also, please never ever put spaces around the = in a set command. This will cause an environment variable to be created with its name ending in a space and its contents starting with a space. This was partially corrected in Windows 7 by silently creating both the variable with the space at the end and one without:
> set foo = bar
> set foo
foo=bar
foo = bar
But in previous versions of Windows this didn't happen so just never use spaces around the = unless you know this is what you want :-)