Modify a string in a .properties file with batch
I am trying to modify a certain property in my csm.properties by executing a script.
I looked up a lot and in the end, came to this code.
set "search=CLASSPATH"
set "insert=CLASSPATH^=plugins^/Numbering.jar^^:"
set "textFile="%workingPlace%bincsm.properties""
FOR /f "delims=" %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
FOR /f "tokens=1*delims==" %%g IN ("%%i") DO (
IF /i "%%g" == %search% (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line:%search%=%insert%!
endlocal
)ELSE (
%%i
)
)
)
This code should read every line in my file and use =
as a delimiter. If the code gets "CLASSPATH" as property, that line should get modified.
But it seems like CLASSPATH isn't found.
This is how csm.properties looks like:
#Tue Jul 10 08:50:23 CEST 2018
JAVA_ARGS=-Xmx20000M -DLOCALCONFIG=true -splash:data/splash.png -Dmd.class.path=$java.class.path -Dcom.nomagic.osgi.config.dir=configuration -Desi.system.config=data/application.conf -Dlogback.configurationFile=data/logback.xml -Dsun.locale.formatasdefault=true -Dinitial.user.language=de
JAVA_HOME=jre1.8.0_152
BOOT_CLASSPATH=lib/xalan.jar
MAIN_CLASS=com.nomagic.osgi.launcher.ProductionFrameworkLauncher
MAC_JAVA_ARGS="-Xdock:name=Cameo Systems Modeler" -Xdock:icon=bin/md.icns -Dapple.laf.useScreenMenuBar=true
APP_ARGS=
DEFAULT_MEMORY_SETTINGS_64=-Xmx[30%,1200,4000]M
DEFAULT_MEMORY_SETTINGS_32=-Xmx800M
CLASSPATH=lib/patch.jar:lib/brand_api.jar
CONSOLE=false
After modifications, CLASSPATH
should look like this:
CLASSPATH=plugins/Numbering.jar:lib/patch.jar:lib/brand_api.jar
batch-file cmd insert
|
show 9 more comments
I am trying to modify a certain property in my csm.properties by executing a script.
I looked up a lot and in the end, came to this code.
set "search=CLASSPATH"
set "insert=CLASSPATH^=plugins^/Numbering.jar^^:"
set "textFile="%workingPlace%bincsm.properties""
FOR /f "delims=" %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
FOR /f "tokens=1*delims==" %%g IN ("%%i") DO (
IF /i "%%g" == %search% (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line:%search%=%insert%!
endlocal
)ELSE (
%%i
)
)
)
This code should read every line in my file and use =
as a delimiter. If the code gets "CLASSPATH" as property, that line should get modified.
But it seems like CLASSPATH isn't found.
This is how csm.properties looks like:
#Tue Jul 10 08:50:23 CEST 2018
JAVA_ARGS=-Xmx20000M -DLOCALCONFIG=true -splash:data/splash.png -Dmd.class.path=$java.class.path -Dcom.nomagic.osgi.config.dir=configuration -Desi.system.config=data/application.conf -Dlogback.configurationFile=data/logback.xml -Dsun.locale.formatasdefault=true -Dinitial.user.language=de
JAVA_HOME=jre1.8.0_152
BOOT_CLASSPATH=lib/xalan.jar
MAIN_CLASS=com.nomagic.osgi.launcher.ProductionFrameworkLauncher
MAC_JAVA_ARGS="-Xdock:name=Cameo Systems Modeler" -Xdock:icon=bin/md.icns -Dapple.laf.useScreenMenuBar=true
APP_ARGS=
DEFAULT_MEMORY_SETTINGS_64=-Xmx[30%,1200,4000]M
DEFAULT_MEMORY_SETTINGS_32=-Xmx800M
CLASSPATH=lib/patch.jar:lib/brand_api.jar
CONSOLE=false
After modifications, CLASSPATH
should look like this:
CLASSPATH=plugins/Numbering.jar:lib/patch.jar:lib/brand_api.jar
batch-file cmd insert
Unfortunately I am not allowed to use powershell. So pipelining the results to a new file and overriding the old file with the latest one, should do the work, I hope?
– dnsiv
Nov 15 '18 at 12:41
So, If I use my delims and tokens on the first loop, will the result be the same?
– dnsiv
Nov 15 '18 at 12:41
I can make batch work, but it will need to write to a new file, then delete old and rename the newfile.. same result you want.
– Gerhard Barnard
Nov 15 '18 at 12:42
I would love to see that solution of yours.
– dnsiv
Nov 15 '18 at 12:45
Also about my 2 for loops. I think, I need them because of line) ELSE ( %%i )
. If I dont have those 2 loops%%i
would just return the string before=
– dnsiv
Nov 15 '18 at 12:45
|
show 9 more comments
I am trying to modify a certain property in my csm.properties by executing a script.
I looked up a lot and in the end, came to this code.
set "search=CLASSPATH"
set "insert=CLASSPATH^=plugins^/Numbering.jar^^:"
set "textFile="%workingPlace%bincsm.properties""
FOR /f "delims=" %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
FOR /f "tokens=1*delims==" %%g IN ("%%i") DO (
IF /i "%%g" == %search% (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line:%search%=%insert%!
endlocal
)ELSE (
%%i
)
)
)
This code should read every line in my file and use =
as a delimiter. If the code gets "CLASSPATH" as property, that line should get modified.
But it seems like CLASSPATH isn't found.
This is how csm.properties looks like:
#Tue Jul 10 08:50:23 CEST 2018
JAVA_ARGS=-Xmx20000M -DLOCALCONFIG=true -splash:data/splash.png -Dmd.class.path=$java.class.path -Dcom.nomagic.osgi.config.dir=configuration -Desi.system.config=data/application.conf -Dlogback.configurationFile=data/logback.xml -Dsun.locale.formatasdefault=true -Dinitial.user.language=de
JAVA_HOME=jre1.8.0_152
BOOT_CLASSPATH=lib/xalan.jar
MAIN_CLASS=com.nomagic.osgi.launcher.ProductionFrameworkLauncher
MAC_JAVA_ARGS="-Xdock:name=Cameo Systems Modeler" -Xdock:icon=bin/md.icns -Dapple.laf.useScreenMenuBar=true
APP_ARGS=
DEFAULT_MEMORY_SETTINGS_64=-Xmx[30%,1200,4000]M
DEFAULT_MEMORY_SETTINGS_32=-Xmx800M
CLASSPATH=lib/patch.jar:lib/brand_api.jar
CONSOLE=false
After modifications, CLASSPATH
should look like this:
CLASSPATH=plugins/Numbering.jar:lib/patch.jar:lib/brand_api.jar
batch-file cmd insert
I am trying to modify a certain property in my csm.properties by executing a script.
I looked up a lot and in the end, came to this code.
set "search=CLASSPATH"
set "insert=CLASSPATH^=plugins^/Numbering.jar^^:"
set "textFile="%workingPlace%bincsm.properties""
FOR /f "delims=" %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
FOR /f "tokens=1*delims==" %%g IN ("%%i") DO (
IF /i "%%g" == %search% (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line:%search%=%insert%!
endlocal
)ELSE (
%%i
)
)
)
This code should read every line in my file and use =
as a delimiter. If the code gets "CLASSPATH" as property, that line should get modified.
But it seems like CLASSPATH isn't found.
This is how csm.properties looks like:
#Tue Jul 10 08:50:23 CEST 2018
JAVA_ARGS=-Xmx20000M -DLOCALCONFIG=true -splash:data/splash.png -Dmd.class.path=$java.class.path -Dcom.nomagic.osgi.config.dir=configuration -Desi.system.config=data/application.conf -Dlogback.configurationFile=data/logback.xml -Dsun.locale.formatasdefault=true -Dinitial.user.language=de
JAVA_HOME=jre1.8.0_152
BOOT_CLASSPATH=lib/xalan.jar
MAIN_CLASS=com.nomagic.osgi.launcher.ProductionFrameworkLauncher
MAC_JAVA_ARGS="-Xdock:name=Cameo Systems Modeler" -Xdock:icon=bin/md.icns -Dapple.laf.useScreenMenuBar=true
APP_ARGS=
DEFAULT_MEMORY_SETTINGS_64=-Xmx[30%,1200,4000]M
DEFAULT_MEMORY_SETTINGS_32=-Xmx800M
CLASSPATH=lib/patch.jar:lib/brand_api.jar
CONSOLE=false
After modifications, CLASSPATH
should look like this:
CLASSPATH=plugins/Numbering.jar:lib/patch.jar:lib/brand_api.jar
batch-file cmd insert
batch-file cmd insert
edited Nov 15 '18 at 15:53
dnsiv
asked Nov 15 '18 at 12:28
dnsivdnsiv
347117
347117
Unfortunately I am not allowed to use powershell. So pipelining the results to a new file and overriding the old file with the latest one, should do the work, I hope?
– dnsiv
Nov 15 '18 at 12:41
So, If I use my delims and tokens on the first loop, will the result be the same?
– dnsiv
Nov 15 '18 at 12:41
I can make batch work, but it will need to write to a new file, then delete old and rename the newfile.. same result you want.
– Gerhard Barnard
Nov 15 '18 at 12:42
I would love to see that solution of yours.
– dnsiv
Nov 15 '18 at 12:45
Also about my 2 for loops. I think, I need them because of line) ELSE ( %%i )
. If I dont have those 2 loops%%i
would just return the string before=
– dnsiv
Nov 15 '18 at 12:45
|
show 9 more comments
Unfortunately I am not allowed to use powershell. So pipelining the results to a new file and overriding the old file with the latest one, should do the work, I hope?
– dnsiv
Nov 15 '18 at 12:41
So, If I use my delims and tokens on the first loop, will the result be the same?
– dnsiv
Nov 15 '18 at 12:41
I can make batch work, but it will need to write to a new file, then delete old and rename the newfile.. same result you want.
– Gerhard Barnard
Nov 15 '18 at 12:42
I would love to see that solution of yours.
– dnsiv
Nov 15 '18 at 12:45
Also about my 2 for loops. I think, I need them because of line) ELSE ( %%i )
. If I dont have those 2 loops%%i
would just return the string before=
– dnsiv
Nov 15 '18 at 12:45
Unfortunately I am not allowed to use powershell. So pipelining the results to a new file and overriding the old file with the latest one, should do the work, I hope?
– dnsiv
Nov 15 '18 at 12:41
Unfortunately I am not allowed to use powershell. So pipelining the results to a new file and overriding the old file with the latest one, should do the work, I hope?
– dnsiv
Nov 15 '18 at 12:41
So, If I use my delims and tokens on the first loop, will the result be the same?
– dnsiv
Nov 15 '18 at 12:41
So, If I use my delims and tokens on the first loop, will the result be the same?
– dnsiv
Nov 15 '18 at 12:41
I can make batch work, but it will need to write to a new file, then delete old and rename the newfile.. same result you want.
– Gerhard Barnard
Nov 15 '18 at 12:42
I can make batch work, but it will need to write to a new file, then delete old and rename the newfile.. same result you want.
– Gerhard Barnard
Nov 15 '18 at 12:42
I would love to see that solution of yours.
– dnsiv
Nov 15 '18 at 12:45
I would love to see that solution of yours.
– dnsiv
Nov 15 '18 at 12:45
Also about my 2 for loops. I think, I need them because of line
) ELSE ( %%i )
. If I dont have those 2 loops %%i
would just return the string before =
– dnsiv
Nov 15 '18 at 12:45
Also about my 2 for loops. I think, I need them because of line
) ELSE ( %%i )
. If I dont have those 2 loops %%i
would just return the string before =
– dnsiv
Nov 15 '18 at 12:45
|
show 9 more comments
4 Answers
4
active
oldest
votes
Simpler...
@echo OFF
setlocal
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
(FOR /f "usebackq tokens=1* delims==" %%i in ("%textFile%") do (
if "%%i" equ "%search%" (
echo %search%=%insert%%%j
) else if "%%j" neq "" (
echo %%i=%%j
) else (
echo %%i
)
)) > temp.tmp
move /Y temp.tmp "%textFile%"
This might work this way, but I can't hardcode:lib/patch.jar:lib/brand_api.jar
as the classpath varies from user to user. I am writing this script for multiple people
– dnsiv
Nov 15 '18 at 15:06
Just fixed this point... So, you really are not "replacing", but "inserting" a new value, isn't it?
– Aacini
Nov 15 '18 at 15:07
Exactly. I am executing your code right now, but after execution the whole file is empty. So I guess there is still something wrong
– dnsiv
Nov 15 '18 at 15:21
Remove themove
command and the> temp.tmp
part and confirm that the output is correct...
– Aacini
Nov 15 '18 at 15:24
1
... like I did in myset "textFile=%workingPlace%bincsm.properties"
command...
– Aacini
Nov 15 '18 at 15:41
|
show 6 more comments
You can give this a go:
@echo off
setlocal enableextensions disabledelayedexpansion
set "replace=plugins^/Numbering.jar^^:"
set "textFile=%workingPlace%bincsm.properties""
for /f %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
set "line=%%i"
for /f "tokens=1* delims==" %%a in ("%%i") do (
if "%%a"=="CLASSPATH" (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!%replace%
) else (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!
endlocal
)
)
)
Similar theory, it will only replace the full string if the first token (%%i) matches CLASSMAP
Please do not change the double quotations in the set
commands.
Unfortunately I am getting a syntax error as output
– dnsiv
Nov 15 '18 at 14:11
And what is declared as%%j
?
– dnsiv
Nov 15 '18 at 14:14
Please copy and try again
– Gerhard Barnard
Nov 15 '18 at 14:14
%%j is the value after = for each line
– Gerhard Barnard
Nov 15 '18 at 14:16
Well.. it kinda worked, but now everything else from CLASSPATH has been removed. I just wanted to add a new string to CLASSPATH
– dnsiv
Nov 15 '18 at 14:29
|
show 9 more comments
Here is my solution for this string replacement task using only internal commands of cmd.exe
with exception of FINDSTR.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
if not defined workingPlace set "workingPlace=%~dp0"
set "TextFile=%workingPlace%bincsm.properties"
if not exist "%TextFile%" goto EndBatch
set "TempFile=%TEMP%csm.properties.tmp"
set "FoundInfo="
(for /F delims^=^ eol^= %%I in ('%SystemRoot%System32findstr.exe /N "^" "%TextFile%"') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
set "Line=!Line:*:=!"
if not defined FoundInfo (
if defined Line (
if /I "!Line:~0,10!" == "CLASSPATH=" (
if /I "!Line!" == "CLASSPATH=" (
echo !Line!plugins/Numbering.jar
endlocal
set "FoundInfo=1"
) else if "!Line:plugins/Numbering.jar=!" == "!Line!" (
set "Line=!Line:~0,10!plugins/Numbering.jar:!Line:~10!"
echo !Line!
endlocal
set "FoundInfo=1"
) else (
endlocal
goto DeleteTempFile
)
) else (
echo(!Line!
endlocal
)
) else (
echo/
endlocal
)
) else (
echo(!Line!
endlocal
)
))>"%TempFile%"
if not defined FoundInfo echo CLASSPATH=plugins/Numbering.jar>>"%TempFile%"
move /Y "%TempFile%" "%TextFile%"
:DeleteTempFile
if exist "%TempFile%" del "%TempFile%"
:EndBatch
endlocal
Read my answer on How to read and print contents of text file line by line? why command FINDSTR is used just to output every line in file csm.properties
including empty lines ignored by FOR by default with line number and :
to avoid that any line is ignored by FOR. The line number and the colon is removed by the command line set "Line=!Line:*:=!"
.
There is the environment variable FoundInfo
undefined at top of the batch file and which is set once a line starting case-insensitive with CLASSSPATH=
is processed by the inner code of FOR loop. Every line in file after the line starting with CLASSSPATH=
is just output without further processing including empty lines.
An empty line above line starting with CLASSSPATH=
is also output with echo/
without any further processing.
The first line starting case-insensitive with CLASSPATH=
can be processed in three different ways:
- The line contains just
CLASSPATH=
.
In this case the line is output asCLASSPATH=plugins/Numbering.jar
and that's it. - The line starts with
CLASSPATH=
and contains one or more characters, but not case-insensitive the stringplugins/Numbering.jar
.
In this case the line is output within insertingplugins/Numbering.jar:
afterCLASSPATH=
.
Please note that a line with justCLASSPATH=
and one or more trailing spaces/tabs would result also in running into second branch resulting for example in output ofCLASSPATH=plugins/Numbering.jar:
with:
and the trailing whitespaces at end. - The line starts with
CLASSPATH=
and contains already case-insensitive the stringplugins/Numbering.jar
somewhere on the line.
In this case the FOR loop is exited immediately with a jump to labelDeleteTempFile
without processing any further line from captured output of FINDSTR. So the last modification date of the file does not change because of nothing changed on file content. (I don't like a change last modification date on file content not really modified.)
After the FOR loop is checked if there was any line starting case-insensitive with CLASSPATH=
at all in the file. The line CLASSPATH=plugins/Numbering.jar
is appended to the temporary file if that was not the case.
Finally with temporary file definitely being different to csm.properties
, the temporary file is moved over existing file csm.properties
if that is possible at all and last the temporary file is deleted if it is still existing.
Note 1: The solution could be easier without usage of FINDSTR if file csm.properties
contains no empty lines or it is acceptable that empty lines are removed during the update of line with CLASSPATH=
.
Note 2: The line with CLASSPATH=
at top of file csm.properties
reduces the process time.
Summary of features of this solution:
- Does not modify the text file on containing already
CLASSPATH=
withplugins/Numbering.jar
somewhere on line. - Inserts
plugins/Numbering.jar:
afterCLASSPATH=
only if there are other class paths (or trailing whitespaces) on this line. - Appends
plugins/Numbering.jar
to existingCLASSPATH=
line not containing any other class path (and no trailing whitespaces on this line). - Appends entire
CLASSPATH=
line withplugins/Numbering.jar
to file not containing this line at all if the file exists at least. - Keeps empty lines in text file and so modifies really only line with
CLASSPATH=
at beginning. - Does not modify lines with
VARIABLE==value
(value with equal sign at beginning) toVARIABLE=value
(equal sign at beginning removed). - Does not modify spelling of
CLASSPATH=
and works for that reason also withclasspath=
orClassPath=
in file. - Does not remove lines starting with
;
being default of FOR's end of line option (eol).
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
set /?
setlocal /?
See also Why is no string output with 'echo %var%' after using 'set var = text' on command line? and How to set environment variables with spaces? These answers explain why in most cases set variable="value"
is not good and what is the difference to set "variable=value"
which is the preferred syntax for definition of an environment variable with a string value.
See also Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files explaining how string comparison works with command IF and why the operators EQU
and NEQ
designed primary for integer comparisons should be in general not used for comparing two strings although this is possible. The usage of EQU
and NEQ
for string comparisons can in some cases with not double quoted strings result in an unexpected comparison result.
add a comment |
@echo off
setlocal disabledelayedexpansion
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
for /f "usebackq delims=" %%i in ("%textFile%") do (
for /f "tokens=1* delims==" %%g in ("%%i") do (
if /i "%%g" == "%search%" (
set "token1=%%g"
set "token2=%%h"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!search!=!insert!!token2!
endlocal
) else (
set "line=%%i"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!line!
endlocal
)
)
)
move "%textFile%" "%textFile%.bak" && move "%textFile%.tmp" "%textFile%"
Insert seems needed rather than a replace.
The for loop reads each line of %textfile%
and the nested for
loop
delimits on the =
to store token 1 and token 2 with the remainder.
If %search%
is found, then !token1!
and !token2!
is set
the
token values. set
usually can handle poison characters after
it so why it is used. Expansion is delayed so poison characters
are echoed to file without being expanded into the source.
If %search%
is not found, the line is set to !line!
,
expansion is delayed, and then the line is echoed to file.
Note:
%workingPlace%
is unknown so correct the path as needed.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53319538%2fmodify-a-string-in-a-properties-file-with-batch%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
Simpler...
@echo OFF
setlocal
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
(FOR /f "usebackq tokens=1* delims==" %%i in ("%textFile%") do (
if "%%i" equ "%search%" (
echo %search%=%insert%%%j
) else if "%%j" neq "" (
echo %%i=%%j
) else (
echo %%i
)
)) > temp.tmp
move /Y temp.tmp "%textFile%"
This might work this way, but I can't hardcode:lib/patch.jar:lib/brand_api.jar
as the classpath varies from user to user. I am writing this script for multiple people
– dnsiv
Nov 15 '18 at 15:06
Just fixed this point... So, you really are not "replacing", but "inserting" a new value, isn't it?
– Aacini
Nov 15 '18 at 15:07
Exactly. I am executing your code right now, but after execution the whole file is empty. So I guess there is still something wrong
– dnsiv
Nov 15 '18 at 15:21
Remove themove
command and the> temp.tmp
part and confirm that the output is correct...
– Aacini
Nov 15 '18 at 15:24
1
... like I did in myset "textFile=%workingPlace%bincsm.properties"
command...
– Aacini
Nov 15 '18 at 15:41
|
show 6 more comments
Simpler...
@echo OFF
setlocal
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
(FOR /f "usebackq tokens=1* delims==" %%i in ("%textFile%") do (
if "%%i" equ "%search%" (
echo %search%=%insert%%%j
) else if "%%j" neq "" (
echo %%i=%%j
) else (
echo %%i
)
)) > temp.tmp
move /Y temp.tmp "%textFile%"
This might work this way, but I can't hardcode:lib/patch.jar:lib/brand_api.jar
as the classpath varies from user to user. I am writing this script for multiple people
– dnsiv
Nov 15 '18 at 15:06
Just fixed this point... So, you really are not "replacing", but "inserting" a new value, isn't it?
– Aacini
Nov 15 '18 at 15:07
Exactly. I am executing your code right now, but after execution the whole file is empty. So I guess there is still something wrong
– dnsiv
Nov 15 '18 at 15:21
Remove themove
command and the> temp.tmp
part and confirm that the output is correct...
– Aacini
Nov 15 '18 at 15:24
1
... like I did in myset "textFile=%workingPlace%bincsm.properties"
command...
– Aacini
Nov 15 '18 at 15:41
|
show 6 more comments
Simpler...
@echo OFF
setlocal
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
(FOR /f "usebackq tokens=1* delims==" %%i in ("%textFile%") do (
if "%%i" equ "%search%" (
echo %search%=%insert%%%j
) else if "%%j" neq "" (
echo %%i=%%j
) else (
echo %%i
)
)) > temp.tmp
move /Y temp.tmp "%textFile%"
Simpler...
@echo OFF
setlocal
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
(FOR /f "usebackq tokens=1* delims==" %%i in ("%textFile%") do (
if "%%i" equ "%search%" (
echo %search%=%insert%%%j
) else if "%%j" neq "" (
echo %%i=%%j
) else (
echo %%i
)
)) > temp.tmp
move /Y temp.tmp "%textFile%"
edited Nov 15 '18 at 15:06
answered Nov 15 '18 at 14:57
AaciniAacini
51.9k75278
51.9k75278
This might work this way, but I can't hardcode:lib/patch.jar:lib/brand_api.jar
as the classpath varies from user to user. I am writing this script for multiple people
– dnsiv
Nov 15 '18 at 15:06
Just fixed this point... So, you really are not "replacing", but "inserting" a new value, isn't it?
– Aacini
Nov 15 '18 at 15:07
Exactly. I am executing your code right now, but after execution the whole file is empty. So I guess there is still something wrong
– dnsiv
Nov 15 '18 at 15:21
Remove themove
command and the> temp.tmp
part and confirm that the output is correct...
– Aacini
Nov 15 '18 at 15:24
1
... like I did in myset "textFile=%workingPlace%bincsm.properties"
command...
– Aacini
Nov 15 '18 at 15:41
|
show 6 more comments
This might work this way, but I can't hardcode:lib/patch.jar:lib/brand_api.jar
as the classpath varies from user to user. I am writing this script for multiple people
– dnsiv
Nov 15 '18 at 15:06
Just fixed this point... So, you really are not "replacing", but "inserting" a new value, isn't it?
– Aacini
Nov 15 '18 at 15:07
Exactly. I am executing your code right now, but after execution the whole file is empty. So I guess there is still something wrong
– dnsiv
Nov 15 '18 at 15:21
Remove themove
command and the> temp.tmp
part and confirm that the output is correct...
– Aacini
Nov 15 '18 at 15:24
1
... like I did in myset "textFile=%workingPlace%bincsm.properties"
command...
– Aacini
Nov 15 '18 at 15:41
This might work this way, but I can't hardcode
:lib/patch.jar:lib/brand_api.jar
as the classpath varies from user to user. I am writing this script for multiple people– dnsiv
Nov 15 '18 at 15:06
This might work this way, but I can't hardcode
:lib/patch.jar:lib/brand_api.jar
as the classpath varies from user to user. I am writing this script for multiple people– dnsiv
Nov 15 '18 at 15:06
Just fixed this point... So, you really are not "replacing", but "inserting" a new value, isn't it?
– Aacini
Nov 15 '18 at 15:07
Just fixed this point... So, you really are not "replacing", but "inserting" a new value, isn't it?
– Aacini
Nov 15 '18 at 15:07
Exactly. I am executing your code right now, but after execution the whole file is empty. So I guess there is still something wrong
– dnsiv
Nov 15 '18 at 15:21
Exactly. I am executing your code right now, but after execution the whole file is empty. So I guess there is still something wrong
– dnsiv
Nov 15 '18 at 15:21
Remove the
move
command and the > temp.tmp
part and confirm that the output is correct...– Aacini
Nov 15 '18 at 15:24
Remove the
move
command and the > temp.tmp
part and confirm that the output is correct...– Aacini
Nov 15 '18 at 15:24
1
1
... like I did in my
set "textFile=%workingPlace%bincsm.properties"
command...– Aacini
Nov 15 '18 at 15:41
... like I did in my
set "textFile=%workingPlace%bincsm.properties"
command...– Aacini
Nov 15 '18 at 15:41
|
show 6 more comments
You can give this a go:
@echo off
setlocal enableextensions disabledelayedexpansion
set "replace=plugins^/Numbering.jar^^:"
set "textFile=%workingPlace%bincsm.properties""
for /f %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
set "line=%%i"
for /f "tokens=1* delims==" %%a in ("%%i") do (
if "%%a"=="CLASSPATH" (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!%replace%
) else (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!
endlocal
)
)
)
Similar theory, it will only replace the full string if the first token (%%i) matches CLASSMAP
Please do not change the double quotations in the set
commands.
Unfortunately I am getting a syntax error as output
– dnsiv
Nov 15 '18 at 14:11
And what is declared as%%j
?
– dnsiv
Nov 15 '18 at 14:14
Please copy and try again
– Gerhard Barnard
Nov 15 '18 at 14:14
%%j is the value after = for each line
– Gerhard Barnard
Nov 15 '18 at 14:16
Well.. it kinda worked, but now everything else from CLASSPATH has been removed. I just wanted to add a new string to CLASSPATH
– dnsiv
Nov 15 '18 at 14:29
|
show 9 more comments
You can give this a go:
@echo off
setlocal enableextensions disabledelayedexpansion
set "replace=plugins^/Numbering.jar^^:"
set "textFile=%workingPlace%bincsm.properties""
for /f %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
set "line=%%i"
for /f "tokens=1* delims==" %%a in ("%%i") do (
if "%%a"=="CLASSPATH" (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!%replace%
) else (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!
endlocal
)
)
)
Similar theory, it will only replace the full string if the first token (%%i) matches CLASSMAP
Please do not change the double quotations in the set
commands.
Unfortunately I am getting a syntax error as output
– dnsiv
Nov 15 '18 at 14:11
And what is declared as%%j
?
– dnsiv
Nov 15 '18 at 14:14
Please copy and try again
– Gerhard Barnard
Nov 15 '18 at 14:14
%%j is the value after = for each line
– Gerhard Barnard
Nov 15 '18 at 14:16
Well.. it kinda worked, but now everything else from CLASSPATH has been removed. I just wanted to add a new string to CLASSPATH
– dnsiv
Nov 15 '18 at 14:29
|
show 9 more comments
You can give this a go:
@echo off
setlocal enableextensions disabledelayedexpansion
set "replace=plugins^/Numbering.jar^^:"
set "textFile=%workingPlace%bincsm.properties""
for /f %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
set "line=%%i"
for /f "tokens=1* delims==" %%a in ("%%i") do (
if "%%a"=="CLASSPATH" (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!%replace%
) else (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!
endlocal
)
)
)
Similar theory, it will only replace the full string if the first token (%%i) matches CLASSMAP
Please do not change the double quotations in the set
commands.
You can give this a go:
@echo off
setlocal enableextensions disabledelayedexpansion
set "replace=plugins^/Numbering.jar^^:"
set "textFile=%workingPlace%bincsm.properties""
for /f %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
set "line=%%i"
for /f "tokens=1* delims==" %%a in ("%%i") do (
if "%%a"=="CLASSPATH" (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!%replace%
) else (
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line!
endlocal
)
)
)
Similar theory, it will only replace the full string if the first token (%%i) matches CLASSMAP
Please do not change the double quotations in the set
commands.
edited Nov 15 '18 at 20:04
answered Nov 15 '18 at 14:03
Gerhard BarnardGerhard Barnard
8,71531232
8,71531232
Unfortunately I am getting a syntax error as output
– dnsiv
Nov 15 '18 at 14:11
And what is declared as%%j
?
– dnsiv
Nov 15 '18 at 14:14
Please copy and try again
– Gerhard Barnard
Nov 15 '18 at 14:14
%%j is the value after = for each line
– Gerhard Barnard
Nov 15 '18 at 14:16
Well.. it kinda worked, but now everything else from CLASSPATH has been removed. I just wanted to add a new string to CLASSPATH
– dnsiv
Nov 15 '18 at 14:29
|
show 9 more comments
Unfortunately I am getting a syntax error as output
– dnsiv
Nov 15 '18 at 14:11
And what is declared as%%j
?
– dnsiv
Nov 15 '18 at 14:14
Please copy and try again
– Gerhard Barnard
Nov 15 '18 at 14:14
%%j is the value after = for each line
– Gerhard Barnard
Nov 15 '18 at 14:16
Well.. it kinda worked, but now everything else from CLASSPATH has been removed. I just wanted to add a new string to CLASSPATH
– dnsiv
Nov 15 '18 at 14:29
Unfortunately I am getting a syntax error as output
– dnsiv
Nov 15 '18 at 14:11
Unfortunately I am getting a syntax error as output
– dnsiv
Nov 15 '18 at 14:11
And what is declared as
%%j
?– dnsiv
Nov 15 '18 at 14:14
And what is declared as
%%j
?– dnsiv
Nov 15 '18 at 14:14
Please copy and try again
– Gerhard Barnard
Nov 15 '18 at 14:14
Please copy and try again
– Gerhard Barnard
Nov 15 '18 at 14:14
%%j is the value after = for each line
– Gerhard Barnard
Nov 15 '18 at 14:16
%%j is the value after = for each line
– Gerhard Barnard
Nov 15 '18 at 14:16
Well.. it kinda worked, but now everything else from CLASSPATH has been removed. I just wanted to add a new string to CLASSPATH
– dnsiv
Nov 15 '18 at 14:29
Well.. it kinda worked, but now everything else from CLASSPATH has been removed. I just wanted to add a new string to CLASSPATH
– dnsiv
Nov 15 '18 at 14:29
|
show 9 more comments
Here is my solution for this string replacement task using only internal commands of cmd.exe
with exception of FINDSTR.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
if not defined workingPlace set "workingPlace=%~dp0"
set "TextFile=%workingPlace%bincsm.properties"
if not exist "%TextFile%" goto EndBatch
set "TempFile=%TEMP%csm.properties.tmp"
set "FoundInfo="
(for /F delims^=^ eol^= %%I in ('%SystemRoot%System32findstr.exe /N "^" "%TextFile%"') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
set "Line=!Line:*:=!"
if not defined FoundInfo (
if defined Line (
if /I "!Line:~0,10!" == "CLASSPATH=" (
if /I "!Line!" == "CLASSPATH=" (
echo !Line!plugins/Numbering.jar
endlocal
set "FoundInfo=1"
) else if "!Line:plugins/Numbering.jar=!" == "!Line!" (
set "Line=!Line:~0,10!plugins/Numbering.jar:!Line:~10!"
echo !Line!
endlocal
set "FoundInfo=1"
) else (
endlocal
goto DeleteTempFile
)
) else (
echo(!Line!
endlocal
)
) else (
echo/
endlocal
)
) else (
echo(!Line!
endlocal
)
))>"%TempFile%"
if not defined FoundInfo echo CLASSPATH=plugins/Numbering.jar>>"%TempFile%"
move /Y "%TempFile%" "%TextFile%"
:DeleteTempFile
if exist "%TempFile%" del "%TempFile%"
:EndBatch
endlocal
Read my answer on How to read and print contents of text file line by line? why command FINDSTR is used just to output every line in file csm.properties
including empty lines ignored by FOR by default with line number and :
to avoid that any line is ignored by FOR. The line number and the colon is removed by the command line set "Line=!Line:*:=!"
.
There is the environment variable FoundInfo
undefined at top of the batch file and which is set once a line starting case-insensitive with CLASSSPATH=
is processed by the inner code of FOR loop. Every line in file after the line starting with CLASSSPATH=
is just output without further processing including empty lines.
An empty line above line starting with CLASSSPATH=
is also output with echo/
without any further processing.
The first line starting case-insensitive with CLASSPATH=
can be processed in three different ways:
- The line contains just
CLASSPATH=
.
In this case the line is output asCLASSPATH=plugins/Numbering.jar
and that's it. - The line starts with
CLASSPATH=
and contains one or more characters, but not case-insensitive the stringplugins/Numbering.jar
.
In this case the line is output within insertingplugins/Numbering.jar:
afterCLASSPATH=
.
Please note that a line with justCLASSPATH=
and one or more trailing spaces/tabs would result also in running into second branch resulting for example in output ofCLASSPATH=plugins/Numbering.jar:
with:
and the trailing whitespaces at end. - The line starts with
CLASSPATH=
and contains already case-insensitive the stringplugins/Numbering.jar
somewhere on the line.
In this case the FOR loop is exited immediately with a jump to labelDeleteTempFile
without processing any further line from captured output of FINDSTR. So the last modification date of the file does not change because of nothing changed on file content. (I don't like a change last modification date on file content not really modified.)
After the FOR loop is checked if there was any line starting case-insensitive with CLASSPATH=
at all in the file. The line CLASSPATH=plugins/Numbering.jar
is appended to the temporary file if that was not the case.
Finally with temporary file definitely being different to csm.properties
, the temporary file is moved over existing file csm.properties
if that is possible at all and last the temporary file is deleted if it is still existing.
Note 1: The solution could be easier without usage of FINDSTR if file csm.properties
contains no empty lines or it is acceptable that empty lines are removed during the update of line with CLASSPATH=
.
Note 2: The line with CLASSPATH=
at top of file csm.properties
reduces the process time.
Summary of features of this solution:
- Does not modify the text file on containing already
CLASSPATH=
withplugins/Numbering.jar
somewhere on line. - Inserts
plugins/Numbering.jar:
afterCLASSPATH=
only if there are other class paths (or trailing whitespaces) on this line. - Appends
plugins/Numbering.jar
to existingCLASSPATH=
line not containing any other class path (and no trailing whitespaces on this line). - Appends entire
CLASSPATH=
line withplugins/Numbering.jar
to file not containing this line at all if the file exists at least. - Keeps empty lines in text file and so modifies really only line with
CLASSPATH=
at beginning. - Does not modify lines with
VARIABLE==value
(value with equal sign at beginning) toVARIABLE=value
(equal sign at beginning removed). - Does not modify spelling of
CLASSPATH=
and works for that reason also withclasspath=
orClassPath=
in file. - Does not remove lines starting with
;
being default of FOR's end of line option (eol).
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
set /?
setlocal /?
See also Why is no string output with 'echo %var%' after using 'set var = text' on command line? and How to set environment variables with spaces? These answers explain why in most cases set variable="value"
is not good and what is the difference to set "variable=value"
which is the preferred syntax for definition of an environment variable with a string value.
See also Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files explaining how string comparison works with command IF and why the operators EQU
and NEQ
designed primary for integer comparisons should be in general not used for comparing two strings although this is possible. The usage of EQU
and NEQ
for string comparisons can in some cases with not double quoted strings result in an unexpected comparison result.
add a comment |
Here is my solution for this string replacement task using only internal commands of cmd.exe
with exception of FINDSTR.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
if not defined workingPlace set "workingPlace=%~dp0"
set "TextFile=%workingPlace%bincsm.properties"
if not exist "%TextFile%" goto EndBatch
set "TempFile=%TEMP%csm.properties.tmp"
set "FoundInfo="
(for /F delims^=^ eol^= %%I in ('%SystemRoot%System32findstr.exe /N "^" "%TextFile%"') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
set "Line=!Line:*:=!"
if not defined FoundInfo (
if defined Line (
if /I "!Line:~0,10!" == "CLASSPATH=" (
if /I "!Line!" == "CLASSPATH=" (
echo !Line!plugins/Numbering.jar
endlocal
set "FoundInfo=1"
) else if "!Line:plugins/Numbering.jar=!" == "!Line!" (
set "Line=!Line:~0,10!plugins/Numbering.jar:!Line:~10!"
echo !Line!
endlocal
set "FoundInfo=1"
) else (
endlocal
goto DeleteTempFile
)
) else (
echo(!Line!
endlocal
)
) else (
echo/
endlocal
)
) else (
echo(!Line!
endlocal
)
))>"%TempFile%"
if not defined FoundInfo echo CLASSPATH=plugins/Numbering.jar>>"%TempFile%"
move /Y "%TempFile%" "%TextFile%"
:DeleteTempFile
if exist "%TempFile%" del "%TempFile%"
:EndBatch
endlocal
Read my answer on How to read and print contents of text file line by line? why command FINDSTR is used just to output every line in file csm.properties
including empty lines ignored by FOR by default with line number and :
to avoid that any line is ignored by FOR. The line number and the colon is removed by the command line set "Line=!Line:*:=!"
.
There is the environment variable FoundInfo
undefined at top of the batch file and which is set once a line starting case-insensitive with CLASSSPATH=
is processed by the inner code of FOR loop. Every line in file after the line starting with CLASSSPATH=
is just output without further processing including empty lines.
An empty line above line starting with CLASSSPATH=
is also output with echo/
without any further processing.
The first line starting case-insensitive with CLASSPATH=
can be processed in three different ways:
- The line contains just
CLASSPATH=
.
In this case the line is output asCLASSPATH=plugins/Numbering.jar
and that's it. - The line starts with
CLASSPATH=
and contains one or more characters, but not case-insensitive the stringplugins/Numbering.jar
.
In this case the line is output within insertingplugins/Numbering.jar:
afterCLASSPATH=
.
Please note that a line with justCLASSPATH=
and one or more trailing spaces/tabs would result also in running into second branch resulting for example in output ofCLASSPATH=plugins/Numbering.jar:
with:
and the trailing whitespaces at end. - The line starts with
CLASSPATH=
and contains already case-insensitive the stringplugins/Numbering.jar
somewhere on the line.
In this case the FOR loop is exited immediately with a jump to labelDeleteTempFile
without processing any further line from captured output of FINDSTR. So the last modification date of the file does not change because of nothing changed on file content. (I don't like a change last modification date on file content not really modified.)
After the FOR loop is checked if there was any line starting case-insensitive with CLASSPATH=
at all in the file. The line CLASSPATH=plugins/Numbering.jar
is appended to the temporary file if that was not the case.
Finally with temporary file definitely being different to csm.properties
, the temporary file is moved over existing file csm.properties
if that is possible at all and last the temporary file is deleted if it is still existing.
Note 1: The solution could be easier without usage of FINDSTR if file csm.properties
contains no empty lines or it is acceptable that empty lines are removed during the update of line with CLASSPATH=
.
Note 2: The line with CLASSPATH=
at top of file csm.properties
reduces the process time.
Summary of features of this solution:
- Does not modify the text file on containing already
CLASSPATH=
withplugins/Numbering.jar
somewhere on line. - Inserts
plugins/Numbering.jar:
afterCLASSPATH=
only if there are other class paths (or trailing whitespaces) on this line. - Appends
plugins/Numbering.jar
to existingCLASSPATH=
line not containing any other class path (and no trailing whitespaces on this line). - Appends entire
CLASSPATH=
line withplugins/Numbering.jar
to file not containing this line at all if the file exists at least. - Keeps empty lines in text file and so modifies really only line with
CLASSPATH=
at beginning. - Does not modify lines with
VARIABLE==value
(value with equal sign at beginning) toVARIABLE=value
(equal sign at beginning removed). - Does not modify spelling of
CLASSPATH=
and works for that reason also withclasspath=
orClassPath=
in file. - Does not remove lines starting with
;
being default of FOR's end of line option (eol).
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
set /?
setlocal /?
See also Why is no string output with 'echo %var%' after using 'set var = text' on command line? and How to set environment variables with spaces? These answers explain why in most cases set variable="value"
is not good and what is the difference to set "variable=value"
which is the preferred syntax for definition of an environment variable with a string value.
See also Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files explaining how string comparison works with command IF and why the operators EQU
and NEQ
designed primary for integer comparisons should be in general not used for comparing two strings although this is possible. The usage of EQU
and NEQ
for string comparisons can in some cases with not double quoted strings result in an unexpected comparison result.
add a comment |
Here is my solution for this string replacement task using only internal commands of cmd.exe
with exception of FINDSTR.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
if not defined workingPlace set "workingPlace=%~dp0"
set "TextFile=%workingPlace%bincsm.properties"
if not exist "%TextFile%" goto EndBatch
set "TempFile=%TEMP%csm.properties.tmp"
set "FoundInfo="
(for /F delims^=^ eol^= %%I in ('%SystemRoot%System32findstr.exe /N "^" "%TextFile%"') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
set "Line=!Line:*:=!"
if not defined FoundInfo (
if defined Line (
if /I "!Line:~0,10!" == "CLASSPATH=" (
if /I "!Line!" == "CLASSPATH=" (
echo !Line!plugins/Numbering.jar
endlocal
set "FoundInfo=1"
) else if "!Line:plugins/Numbering.jar=!" == "!Line!" (
set "Line=!Line:~0,10!plugins/Numbering.jar:!Line:~10!"
echo !Line!
endlocal
set "FoundInfo=1"
) else (
endlocal
goto DeleteTempFile
)
) else (
echo(!Line!
endlocal
)
) else (
echo/
endlocal
)
) else (
echo(!Line!
endlocal
)
))>"%TempFile%"
if not defined FoundInfo echo CLASSPATH=plugins/Numbering.jar>>"%TempFile%"
move /Y "%TempFile%" "%TextFile%"
:DeleteTempFile
if exist "%TempFile%" del "%TempFile%"
:EndBatch
endlocal
Read my answer on How to read and print contents of text file line by line? why command FINDSTR is used just to output every line in file csm.properties
including empty lines ignored by FOR by default with line number and :
to avoid that any line is ignored by FOR. The line number and the colon is removed by the command line set "Line=!Line:*:=!"
.
There is the environment variable FoundInfo
undefined at top of the batch file and which is set once a line starting case-insensitive with CLASSSPATH=
is processed by the inner code of FOR loop. Every line in file after the line starting with CLASSSPATH=
is just output without further processing including empty lines.
An empty line above line starting with CLASSSPATH=
is also output with echo/
without any further processing.
The first line starting case-insensitive with CLASSPATH=
can be processed in three different ways:
- The line contains just
CLASSPATH=
.
In this case the line is output asCLASSPATH=plugins/Numbering.jar
and that's it. - The line starts with
CLASSPATH=
and contains one or more characters, but not case-insensitive the stringplugins/Numbering.jar
.
In this case the line is output within insertingplugins/Numbering.jar:
afterCLASSPATH=
.
Please note that a line with justCLASSPATH=
and one or more trailing spaces/tabs would result also in running into second branch resulting for example in output ofCLASSPATH=plugins/Numbering.jar:
with:
and the trailing whitespaces at end. - The line starts with
CLASSPATH=
and contains already case-insensitive the stringplugins/Numbering.jar
somewhere on the line.
In this case the FOR loop is exited immediately with a jump to labelDeleteTempFile
without processing any further line from captured output of FINDSTR. So the last modification date of the file does not change because of nothing changed on file content. (I don't like a change last modification date on file content not really modified.)
After the FOR loop is checked if there was any line starting case-insensitive with CLASSPATH=
at all in the file. The line CLASSPATH=plugins/Numbering.jar
is appended to the temporary file if that was not the case.
Finally with temporary file definitely being different to csm.properties
, the temporary file is moved over existing file csm.properties
if that is possible at all and last the temporary file is deleted if it is still existing.
Note 1: The solution could be easier without usage of FINDSTR if file csm.properties
contains no empty lines or it is acceptable that empty lines are removed during the update of line with CLASSPATH=
.
Note 2: The line with CLASSPATH=
at top of file csm.properties
reduces the process time.
Summary of features of this solution:
- Does not modify the text file on containing already
CLASSPATH=
withplugins/Numbering.jar
somewhere on line. - Inserts
plugins/Numbering.jar:
afterCLASSPATH=
only if there are other class paths (or trailing whitespaces) on this line. - Appends
plugins/Numbering.jar
to existingCLASSPATH=
line not containing any other class path (and no trailing whitespaces on this line). - Appends entire
CLASSPATH=
line withplugins/Numbering.jar
to file not containing this line at all if the file exists at least. - Keeps empty lines in text file and so modifies really only line with
CLASSPATH=
at beginning. - Does not modify lines with
VARIABLE==value
(value with equal sign at beginning) toVARIABLE=value
(equal sign at beginning removed). - Does not modify spelling of
CLASSPATH=
and works for that reason also withclasspath=
orClassPath=
in file. - Does not remove lines starting with
;
being default of FOR's end of line option (eol).
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
set /?
setlocal /?
See also Why is no string output with 'echo %var%' after using 'set var = text' on command line? and How to set environment variables with spaces? These answers explain why in most cases set variable="value"
is not good and what is the difference to set "variable=value"
which is the preferred syntax for definition of an environment variable with a string value.
See also Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files explaining how string comparison works with command IF and why the operators EQU
and NEQ
designed primary for integer comparisons should be in general not used for comparing two strings although this is possible. The usage of EQU
and NEQ
for string comparisons can in some cases with not double quoted strings result in an unexpected comparison result.
Here is my solution for this string replacement task using only internal commands of cmd.exe
with exception of FINDSTR.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
if not defined workingPlace set "workingPlace=%~dp0"
set "TextFile=%workingPlace%bincsm.properties"
if not exist "%TextFile%" goto EndBatch
set "TempFile=%TEMP%csm.properties.tmp"
set "FoundInfo="
(for /F delims^=^ eol^= %%I in ('%SystemRoot%System32findstr.exe /N "^" "%TextFile%"') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
set "Line=!Line:*:=!"
if not defined FoundInfo (
if defined Line (
if /I "!Line:~0,10!" == "CLASSPATH=" (
if /I "!Line!" == "CLASSPATH=" (
echo !Line!plugins/Numbering.jar
endlocal
set "FoundInfo=1"
) else if "!Line:plugins/Numbering.jar=!" == "!Line!" (
set "Line=!Line:~0,10!plugins/Numbering.jar:!Line:~10!"
echo !Line!
endlocal
set "FoundInfo=1"
) else (
endlocal
goto DeleteTempFile
)
) else (
echo(!Line!
endlocal
)
) else (
echo/
endlocal
)
) else (
echo(!Line!
endlocal
)
))>"%TempFile%"
if not defined FoundInfo echo CLASSPATH=plugins/Numbering.jar>>"%TempFile%"
move /Y "%TempFile%" "%TextFile%"
:DeleteTempFile
if exist "%TempFile%" del "%TempFile%"
:EndBatch
endlocal
Read my answer on How to read and print contents of text file line by line? why command FINDSTR is used just to output every line in file csm.properties
including empty lines ignored by FOR by default with line number and :
to avoid that any line is ignored by FOR. The line number and the colon is removed by the command line set "Line=!Line:*:=!"
.
There is the environment variable FoundInfo
undefined at top of the batch file and which is set once a line starting case-insensitive with CLASSSPATH=
is processed by the inner code of FOR loop. Every line in file after the line starting with CLASSSPATH=
is just output without further processing including empty lines.
An empty line above line starting with CLASSSPATH=
is also output with echo/
without any further processing.
The first line starting case-insensitive with CLASSPATH=
can be processed in three different ways:
- The line contains just
CLASSPATH=
.
In this case the line is output asCLASSPATH=plugins/Numbering.jar
and that's it. - The line starts with
CLASSPATH=
and contains one or more characters, but not case-insensitive the stringplugins/Numbering.jar
.
In this case the line is output within insertingplugins/Numbering.jar:
afterCLASSPATH=
.
Please note that a line with justCLASSPATH=
and one or more trailing spaces/tabs would result also in running into second branch resulting for example in output ofCLASSPATH=plugins/Numbering.jar:
with:
and the trailing whitespaces at end. - The line starts with
CLASSPATH=
and contains already case-insensitive the stringplugins/Numbering.jar
somewhere on the line.
In this case the FOR loop is exited immediately with a jump to labelDeleteTempFile
without processing any further line from captured output of FINDSTR. So the last modification date of the file does not change because of nothing changed on file content. (I don't like a change last modification date on file content not really modified.)
After the FOR loop is checked if there was any line starting case-insensitive with CLASSPATH=
at all in the file. The line CLASSPATH=plugins/Numbering.jar
is appended to the temporary file if that was not the case.
Finally with temporary file definitely being different to csm.properties
, the temporary file is moved over existing file csm.properties
if that is possible at all and last the temporary file is deleted if it is still existing.
Note 1: The solution could be easier without usage of FINDSTR if file csm.properties
contains no empty lines or it is acceptable that empty lines are removed during the update of line with CLASSPATH=
.
Note 2: The line with CLASSPATH=
at top of file csm.properties
reduces the process time.
Summary of features of this solution:
- Does not modify the text file on containing already
CLASSPATH=
withplugins/Numbering.jar
somewhere on line. - Inserts
plugins/Numbering.jar:
afterCLASSPATH=
only if there are other class paths (or trailing whitespaces) on this line. - Appends
plugins/Numbering.jar
to existingCLASSPATH=
line not containing any other class path (and no trailing whitespaces on this line). - Appends entire
CLASSPATH=
line withplugins/Numbering.jar
to file not containing this line at all if the file exists at least. - Keeps empty lines in text file and so modifies really only line with
CLASSPATH=
at beginning. - Does not modify lines with
VARIABLE==value
(value with equal sign at beginning) toVARIABLE=value
(equal sign at beginning removed). - Does not modify spelling of
CLASSPATH=
and works for that reason also withclasspath=
orClassPath=
in file. - Does not remove lines starting with
;
being default of FOR's end of line option (eol).
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
set /?
setlocal /?
See also Why is no string output with 'echo %var%' after using 'set var = text' on command line? and How to set environment variables with spaces? These answers explain why in most cases set variable="value"
is not good and what is the difference to set "variable=value"
which is the preferred syntax for definition of an environment variable with a string value.
See also Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files explaining how string comparison works with command IF and why the operators EQU
and NEQ
designed primary for integer comparisons should be in general not used for comparing two strings although this is possible. The usage of EQU
and NEQ
for string comparisons can in some cases with not double quoted strings result in an unexpected comparison result.
edited Dec 18 '18 at 15:05
answered Nov 15 '18 at 14:58
MofiMofi
28.7k83778
28.7k83778
add a comment |
add a comment |
@echo off
setlocal disabledelayedexpansion
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
for /f "usebackq delims=" %%i in ("%textFile%") do (
for /f "tokens=1* delims==" %%g in ("%%i") do (
if /i "%%g" == "%search%" (
set "token1=%%g"
set "token2=%%h"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!search!=!insert!!token2!
endlocal
) else (
set "line=%%i"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!line!
endlocal
)
)
)
move "%textFile%" "%textFile%.bak" && move "%textFile%.tmp" "%textFile%"
Insert seems needed rather than a replace.
The for loop reads each line of %textfile%
and the nested for
loop
delimits on the =
to store token 1 and token 2 with the remainder.
If %search%
is found, then !token1!
and !token2!
is set
the
token values. set
usually can handle poison characters after
it so why it is used. Expansion is delayed so poison characters
are echoed to file without being expanded into the source.
If %search%
is not found, the line is set to !line!
,
expansion is delayed, and then the line is echoed to file.
Note:
%workingPlace%
is unknown so correct the path as needed.
add a comment |
@echo off
setlocal disabledelayedexpansion
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
for /f "usebackq delims=" %%i in ("%textFile%") do (
for /f "tokens=1* delims==" %%g in ("%%i") do (
if /i "%%g" == "%search%" (
set "token1=%%g"
set "token2=%%h"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!search!=!insert!!token2!
endlocal
) else (
set "line=%%i"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!line!
endlocal
)
)
)
move "%textFile%" "%textFile%.bak" && move "%textFile%.tmp" "%textFile%"
Insert seems needed rather than a replace.
The for loop reads each line of %textfile%
and the nested for
loop
delimits on the =
to store token 1 and token 2 with the remainder.
If %search%
is found, then !token1!
and !token2!
is set
the
token values. set
usually can handle poison characters after
it so why it is used. Expansion is delayed so poison characters
are echoed to file without being expanded into the source.
If %search%
is not found, the line is set to !line!
,
expansion is delayed, and then the line is echoed to file.
Note:
%workingPlace%
is unknown so correct the path as needed.
add a comment |
@echo off
setlocal disabledelayedexpansion
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
for /f "usebackq delims=" %%i in ("%textFile%") do (
for /f "tokens=1* delims==" %%g in ("%%i") do (
if /i "%%g" == "%search%" (
set "token1=%%g"
set "token2=%%h"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!search!=!insert!!token2!
endlocal
) else (
set "line=%%i"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!line!
endlocal
)
)
)
move "%textFile%" "%textFile%.bak" && move "%textFile%.tmp" "%textFile%"
Insert seems needed rather than a replace.
The for loop reads each line of %textfile%
and the nested for
loop
delimits on the =
to store token 1 and token 2 with the remainder.
If %search%
is found, then !token1!
and !token2!
is set
the
token values. set
usually can handle poison characters after
it so why it is used. Expansion is delayed so poison characters
are echoed to file without being expanded into the source.
If %search%
is not found, the line is set to !line!
,
expansion is delayed, and then the line is echoed to file.
Note:
%workingPlace%
is unknown so correct the path as needed.
@echo off
setlocal disabledelayedexpansion
set "search=CLASSPATH"
set "insert=plugins/Numbering.jar:"
set "textFile=%workingPlace%bincsm.properties"
for /f "usebackq delims=" %%i in ("%textFile%") do (
for /f "tokens=1* delims==" %%g in ("%%i") do (
if /i "%%g" == "%search%" (
set "token1=%%g"
set "token2=%%h"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!search!=!insert!!token2!
endlocal
) else (
set "line=%%i"
setlocal enabledelayedexpansion
>> "%textFile%.tmp" echo(!line!
endlocal
)
)
)
move "%textFile%" "%textFile%.bak" && move "%textFile%.tmp" "%textFile%"
Insert seems needed rather than a replace.
The for loop reads each line of %textfile%
and the nested for
loop
delimits on the =
to store token 1 and token 2 with the remainder.
If %search%
is found, then !token1!
and !token2!
is set
the
token values. set
usually can handle poison characters after
it so why it is used. Expansion is delayed so poison characters
are echoed to file without being expanded into the source.
If %search%
is not found, the line is set to !line!
,
expansion is delayed, and then the line is echoed to file.
Note:
%workingPlace%
is unknown so correct the path as needed.
answered Nov 15 '18 at 15:45
michael_heathmichael_heath
2,8772617
2,8772617
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53319538%2fmodify-a-string-in-a-properties-file-with-batch%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Unfortunately I am not allowed to use powershell. So pipelining the results to a new file and overriding the old file with the latest one, should do the work, I hope?
– dnsiv
Nov 15 '18 at 12:41
So, If I use my delims and tokens on the first loop, will the result be the same?
– dnsiv
Nov 15 '18 at 12:41
I can make batch work, but it will need to write to a new file, then delete old and rename the newfile.. same result you want.
– Gerhard Barnard
Nov 15 '18 at 12:42
I would love to see that solution of yours.
– dnsiv
Nov 15 '18 at 12:45
Also about my 2 for loops. I think, I need them because of line
) ELSE ( %%i )
. If I dont have those 2 loops%%i
would just return the string before=
– dnsiv
Nov 15 '18 at 12:45