windows batch to split string on first occurrence of a delimiter - batch-file

I have a parameter string read from a properties file. One of the properties is as below:
"CUSTOM_JAVA_OPTIONS=-Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080"
I need to split this string on the first occurrence of "=" and set a parameter with the value:
-Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080
I am trying to split the string first on the = token and then remove the fist sub-string token from the original string.
In the below code %%G will be set to "CUSTOM_JAVA_OPTIONS" and I am trying to remove this from the original string "TESTSTR"
#echo off
set "TESTSTR=CUSTOM_JAVA_OPTIONS=-Dhttp.proxyHost=webcache.example.com
-Dhttp.proxyPort=8080"
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "tokens=1,2 delims==" %%G IN ("%TESTSTR%") DO (
echo Name=%%G
echo Value=%%H
set removestr=%%G
echo TESTSTR=!TESTSTR!
echo removestr=!removestr!
set "str=!TESTSTR:%removestr%=!"
echo str=!str!
)
pause
The above does not seem to work, it produces:
Name=CUSTOM_JAVA_OPTIONS
Value=-Dhttp.proxyHost
TESTSTR=CUSTOM_JAVA_OPTIONS=-Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080
removestr=CUSTOM_JAVA_OPTIONS
str=TESTSTR:=
Expected result needs to be:
str=-Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080

This could be simplified to:
#echo off
set "TESTSTR=CUSTOM_JAVA_OPTIONS=-Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080"
FOR /F "tokens=1* delims==" %%G IN ("%TESTSTR%") DO set "str=%%H"
echo TESTSTR=%TESTSTR%
echo.str=%str%
pause
There are 2 tokens:
1. Text up to 1st delimiter
2. Everything else after first delimiter (*)
Note that by echoing the variables outside of the FOR loop you don't need to enable delayed expansion.

Your code fails entirely because %removestr% is expanded when the command is initially parsed, and your entire loop (code block) is parsed all at once. So %removestr% expands to the value that existed before your loop was entered. In your case, the variable is undefined. So !TESTSTR:%removestr%=! becomes !TESTSTR:=!, which finally becomes TESTSTR:=.
You get closer if you use %%G directly, instead of assigning an environment variable.
set str=!TESTSTR:%%G=! yields =-Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080
You can then use set str=!str:~1!" to remove the leading =.
set str=!TESTSTR:%%G==! will not work because the search strings stops at the first occurrence of =, so the result is ==-Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080
The RGuggisberg answer is the most convenient method to get your desired result. (You may want both %%G and %%H).
However, it technically does not break at the first =. It actually breaks at the first string of contiguous = because FOR /F does not parse empty tokens.
So for /f "tokens=1* delims==" %%G in ("A==B==C") yields A for %%G (correct), and B==C (incorrect) for %%H. The correct value should be =B==C.

If the first character after the = character is always a -, then the following method may also work for you:
#Echo Off
Set "TESTSTR=CUSTOM_JAVA_OPTIONS=-Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080"
Set "REST=-%TESTSTR:*-=%"
Set "FIRST=%TESTSTR:-="&:"%"
Set "FIRST=%FIRST:~,-1%"
Echo [%FIRST%] [%REST%] & Pause
The bottom line is simply to show you the information.

Related

BATCH: How to properly use a %% variable within a for loop

This is the very first time i tried batch scripting so please bear with me.
I just wanted to read each line of my hosts file, and replace the line if it contains/matches a substring. I've seen a lot of answered questions about substrings here but I just can't make it work by using the provided solutions.
I have this code:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "hostspath=%SystemRoot%\System32\drivers\etc\hosts"
set "hostsbackuppath=c:\hosts"
>"%hostsbackuppath%.new" (
rem Parse the hosts file, skipping the already present hosts from our list.
rem Blank lines are preserved using findstr trick.
for /f "delims=: tokens=1*" %%a in ('%SystemRoot%\System32\findstr.exe /n /r /c:".*" "%hostspath%"') do (
set str1=%%b
if not x!str1:mydomainname=!==x!str1! (
rem Match found, replace this line.
echo "match!"
set matched=false
)
// Didn't match, do not replace
if not "!matched!"=="true" echo.%%b
)
)
I was trying out this solution to check for substring match among other else: Batch file: Find if substring is in string (not in a file)
Can someone help me? Thanks
SETLOCAL ENABLEDELAYEDEXPANSION
set "matched=true"
>"%hostsbackuppath%.new" (
for /f "delims=: tokens=1*" %%a in ('%SystemRoot%\System32\findstr.exe /n /r /c:".*" "%hostspath%"') do (
set "str1=%%b"
if not "!str1:mydomainname=!"=="!str1!" (
rem Match found, replace this line.
echo "match at %%b in line %%a"
set matched=false
)
// Didn't match, do not replace
if not "!matched!"=="true" echo.%%b
)
)
Hooley-dooley! Someone needs to learn to name variables appropriately.
First, you need to use setlocal enabledelayedexpansion - please see a thousand-and-one SO articles about delayed expansion.
Since str1 is varied within the loop, you need to use setlocal enabledelayedexpansion and !var! to access the varying value of var as %var% is the value at the time the for was encountered.
The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned. set /a can safely be used "quoteless".
FOr the same reason, quoting each side of a comparison is preferred as it makes a single token of a string containing separators like spaces.
Then you have a comment "match found" after which you set matched to false ?? Therefore you need to initialise match (to true)
Now quite what you want to do is obscure. On re-reading, you probably want to set "matched=true" as the first line within the loop, not outside as I have it, so that the value is re-set to true for each line found and then set to false if a match is found.
All this negative logic is insane. I need a strong cup of coffee.

For /f delims: ignore second occurance of delim-character in a line

I am using for /f to set variables in a batch file from a txt-file:
for /f "tokens=1,2 delims==" %%V IN (conf.txt) DO set %%V=%%W
Unfortunately the string after the delim might again contain one or more times the delim character. E.g. the contents of the textfile might look like this:
_uploadfile=/file=upload.zip
_password=/passphrase=ab1=cd2:def
Right now all text after the second occurance of the delim is not passed. So the variables when running my batch contain only
_uploadfile=/file
_password=/passphrase
Is there any option to make for ignoring the second occurance of the delim? Or is there a workaround?
Chosing another character as delim seems to be no good idea as virtually all printable characters can and should be used as password.
Thanks!
Use tokens=1,* instead.
The * takes in the second parameter all remaining characters from the line.
This is explained in for /?
jeb's answer is fine, unless there appear consecutive delimiters in the string, because such are treated as a single one by for /F. For instance, supposing conf.txt contains the following string...:
str==abc
..., the command line...:
for /F "tokens=1,* delims==" %%V IN (conf.txt) do set "%%V=%%W"
...would return this...:
str=abc
..., so the second = sign is lost.
To fix the code to not fail in such situations, simply disable the delimiters at all...:
for /F "delims=" %%V IN (conf.txt) do set "%%V"
..., so the output was...:
str==abc
..., meaning that variable str was set to value =abc.
To ensure that only lines are processed that contain at least one = sign, use this code:
for /F "delims=" %%V IN ('find "=" ^< conf.txt') do set "%%V"

How to do this %x:~0,1% in %%x (for) batch-file

my %%x are
a=23
b=56
c=89
in a .txt called hi.txt
for %%x in (hi.txt) do (echo %%x:~0,1 %%x)
but it failed....
thank you
i want to echo "the first character" in each line, but i cant use %%x:~0,1...
I'm not exactly sure what you are trying to do... I'm assuming that you want to parse the file hi.txt and pull out the variables (a,b,c) and the number they are equal to..
#echo off
setlocal ENABLEEXTENSIONS
for /f "tokens=1,2 delims==" %%i in (hi.txt) do (
echo %%i has value %%j
)
this will output
a has value 23
b has value 56
c has value 89
See "help for" if you need more info.
Also note, my example is parsing on the = sign, so it doesn't matter how wide each variable is. You could have a line like "MyText=100" and it would work too. Your ~0,1 assumes each value is only 1 character wide.
I hope this helps.
If all you need to do is print the first character of a line, then the following script should work. I believe your original issue may have been with Delayed Variable Expansion. See "help setlocal" and "help set" for more information.
This version of the script reads each line into a temp variable and snips the first character into another variable named firstCharacter. The ! are used for the delayed variable expansion feature of CMD scripts.
#echo off
setlocal ENABLEEXTENSIONS,ENABLEDELAYEDEXPANSION
for /f %%i in (hi.txt) do (
set wholeLine=%%i
set firstCharacter=!wholeLine:~0,1!
echo First Character is !firstCharacter!
)
endlocal
and the output is...
First Character is a
First Character is b
First Character is c
I wasn't able to find a way to use %%i directly for this, hence the temporary variable wholeLine. I added the variable firstCharacter for clarity, but it doesn't need to exist for this to work. I could have echoed !wholeLine:~0,1! directly.
Have fun.

BAT-file: FOR %%x variable incorrect expansion

I have bat-script with following code:
FOR /F "tokens=1,2 delims==" %%g in ("%CFGFILE%") do (
SET firstChar=%%g
SET firstChar=!firstChar:~1,1!
if /I "!firstChar!"=="#" (
echo %%g>>"%INSTALL_PATH%\tmp.cfg"
)else (
if /I "%%g"=="document.folder" (
SET path_written=TRUE
echo %%g=%DOC_FOLDER%>>"%INSTALL_PATH%\tmp.cfg"
)else (
rem next line is buggy
echo %%g=%%h>>"%INSTALL_PATH%\tmp.cfg"
)
)
)
The point is parsing cfg-file %CFGFILE% contents and copying every string without changes to new config-file, except only one string starting with "document.folder". This line must be changed. Problem is that the line after "next line is buggy" comment gives "c:\program files\myApp\original.cfg=" which is content of %CFGFILE% variable plus equals sign. Is this a bug or i've done something wrong? Is this connected with %%x variables visibility?
You have mis-identified the source of the problem! :-)
Your problem is in the very first line - your FOR statement is processing a string, not a file, because the IN() clause is enclosed by double quotes. If you want the IN() clause to be treated as a quoted file name, then you need to add USEBACKQ to your FOR options.
FOR /F "usebackq tokens=1,2 delims==" %%g in ("%CFGFILE%") do (
Just a heads up - even after the fix above, your code will not give the correct results if any of the following conditions appear
If any line contains ! then expansion of %%g or %%h will be corrupted because delayed expansion is enabled
Commented # line will be incomplete if the original contained =
Your normal lines will not be complete if there is a 2nd = in the original
My suggestion:
Use FART...
http://sourceforge.net/projects/fart-it/

Applying substring operation to FOR token value (batch file)

(Edited question for clarity)
Applying substring operation to a token value in a FOR does not work:
for /F "tokens=1 delims=" %%G in ("tokenvalue ") do (
Echo %%G:~-1
)
The substring operation does not delete the space at the end. Instead, :~-1 gets appended to the echoed result to produce:
tokenvalue :~-1
I cannot reproduce your problem here. Only when I append a space to the input file it also appears in the output file.
If you do
echo %%G >> D:\newfile.txt
then a space gets appended, obviously. This might be the case if you simplified your code before posting here.
If you indeed start out with a space in the input, then use the following:
setlocal enabledelayedexpansion
for /f "tokens=1 delims=" %%G in (D:\originalFile.txt) do (
set "line=%%G"
echo !line:~-1!>>D:\newfile.txt
)
You apply substring operations only to environment variables as the help already states.
In any case, if you're sure that the input file does not contain the trailing space, then you don't actually need the loop. A simple
type D:\originalFile.txt >> D:\newfile.txt
should suffice.

Resources