How to replace string inside a bat file with command line parameter string
Solution 1
First of all, you'll have to store %1
into a variable, then you will be able to perform the replacements.
Basically, the syntax for the replacement is this:
%variable:str1=str2%
which means: 'replace every str1
in variable
with str2
'.
In your case both str1
and str2
are parameters, not literal strings. Using the above template directly you might end up with this expression:
%variable:%3=%4%
.
But that would confuse the parser, as it wouldn't know that %3
and %4
should be evaluated first. In fact, it would first try to evaluate %variable:%
(and fail).
One of the solutions in this case could be to use a method called 'lazy' delayed evaluation. Basically, you are passing the command where you are evaluating a variable, to the CALL command. The transformation of the original command to its 'CALL version' is like so:
ECHO %var%
==> CALL ECHO %%var%%
.
Note the double %
s. At parse time they are evaluated to single %
s. The resulting command would be parsed again by CALL, and the ultimate effect would be the same as in case of the original command, ECHO %var%
.
So it works the same as the original command (which is good), and what we are gaining here is the later time of evaluation, I mean the final evaluation, when the variable is actually replaced with its value. Knowing about that effect, we can construct our expression in such a way that %3
and %4
are evaluated first, and then the entire resulting expression. Specifically, like this:
%%variable:%3=%4%%
After the first parse this expression would become something like this:
%variable:x=y%
That would be parsed again, and the output would be variable
's modified contents.
For better illustration, here's a simple working example:
SET "output=%1"
CALL SET output=%%output:%3=%4%%
ECHO %output%
UPDATE
There's another method of doing the same thing, which I should probably have mentioned first.
The Windows command shell supports a proper delayed expansion. It is simpler in use, but has some caveats.
First, how to use it. The syntax for delayed expansion is !var!
instead of %var%
for immediate expansion (which remains valid and can be used alongside with the delayed expansion syntax).
Probably !var!
will not work in your script until you enable the syntax with the command:
SETLOCAL EnableDelayedExpansion
The ENDLOCAL
command closes the block within which the delayed expansion syntax is valid and interpreted by the command shell.
The above example script could be rewritten like this:
SET "output=%1"
SETLOCAL EnableDelayedExpansion
SET output=!output:%3=%4!
ECHO !output!
ENDLOCAL
So how this works in case of the SET output=!output:%3=%4!
command:
-
%3
and%4
are evaluated immediately, i.e. at the parse time – they are replaced withx
andy
respectively; -
the command becomes this:
SET output=!output:x=y!
; -
the command is about to execute – the
!
expression is evaluated (x
s are replaced withy
s); -
the command is executed – the
output
variable is modified.
Now about the caveats. The first thing to remember is that the !
becomes part of the syntax and is consumed and interpreted whenever encountered. So you'll need to escape it where you want to use it as a literal (like ^!
).
Another caveat is the primary effect of a SETLOCAL/ENDLOCAL block. The thing is, all the changes to environment variables within such a block are, well, local. Upon exiting the block (upon executing ENDLOCAL
) the variable is set to the value it had prior to entering it (prior to executing SETLOCAL
). This means for you that the changed value of output
will only be valid within the SETLOCAL
block which you had to initiate for using the delayed expansion in the first place. Possibly this may not be a problem in your particular case, if you just need to modify the value and then use it right away, but you should probably have to remember it for the future.
Note: As per jeb's comment, you can save the modified value and leave the SETLOCAL block using this trick:
ENDLOCAL & SET "output=%output%"
The &
operator simply delimits the commands when they are placed on the same line. They are executed one after the other, in the same order they are specified. The thing is, by the moment of parsing the line, the SETLOCAL block hasn't been left yet, so %output%
evaluates to the modified value, which is still valid. But the assignment is actually executed after ENDLOCAL
, i.e. after leaving the block. So you are effectively storing the modified value after leaving the block, thus preserving the changes. (Thanks, jeb!)
More information:
- On delayed expansion:
- On substring replacement:
Solution 2
I've tried below code in windows 7 batch file:
SET output=%1
CALL SET output=%output:unsigned=signed%
CALL SET output=%output:.apk=-aligned.apk%
It works !
DSharper
Updated on March 16, 2021Comments
-
DSharper about 3 years
I have following in a cmd batch file:
for /f %%l in (%2) do (for %%f in (%%l) do copy "%%f" %1))
note : this script basically does is read a text file that contains semicolon delimited txt file whose path is given by %2(eg which contains c:\test1\file1.cs;d:\file2.js) and copy the files to destination folder specified by %1.
I need to replace the
%1
parameter's string value ofx
(which is also passed to batch file e.g.%3
) with%4
value which is also passed as parameter to batch file.e.g.:
if %1 = 'test replace x with y' %3=x %4=y
so the output should be 'test replace y with y'
How can I achieve this using Windows CMD batch interpreter?
-
jeb about 13 years+1, But why you show the 'lazy' delayed evaluation, but not the (simpler) delayed expansion?
-
Andriy M about 13 years@jeb: Thanks for the question! For some reason, don't know why, this didn't work for me when I was making tests (on Win7):
set "output=%1"; setlocal EnableDelayedExpansion; set "output=!output:%3=%4!"; endlocal; echo %output%
. Strangely,!output:%3=%4!
worked in ECHO, but refused to have any effect with SET. The variable just wouldn't change. -
jeb about 13 yearsBut that's ok, as you change the output var in the
setlocal
block, after theendlocal
the output var has it's original value. Not a problem of Win7 -
Andriy M about 13 years@jeb: Why, of course, how foolish of me! Thank you. But... the fact that the changed value expires after exiting the
setlocal
block means, you'll have to have the delayed expansion enabled for the entire block of commands where you need to use the modified value. Possibly not the problem with the OP's case. All right, I'll add that to my answer then. Thanks again! -
jeb about 13 yearsYou can leave the block and hold the safe the modified value with
( endlocal & set "output=%output%")
-
jeb over 9 yearsBut that doesn't solve the question. The question was about replacing a string with unknown parameters in
%3
and%4
-
dgo over 5 yearsOne caveat if you are using this to remove strings (like you might do with
newvariable=!variable:str1=!)
, I could not get this to work without setting a variable for the empty string likeset "str2="
. Then if I didCALL SET newvariable=!!variable:%str1%=%str2%!!
, it would removestr1
just as if I had passed an empty string instead of%str2%
(which was an empty variable). Go figure. -
Andriy M over 5 years@dgo: That's curious. I've just tested your first method in Win 7, seemed to work as expected for me (the
ECHO test--test
line in the screenshot wasECHO %var2%
in the script). Maybe I missed or misunderstood something. -
dgo over 5 years@AndriyM - You might be right. I'll look again when I have a minute - I was also inside a for loop (which may or may not make a difference). I'll look again a bit later, and then clean up my comments.
-
Andriy M over 5 years@dgo: Ah yes, if it's a parenthesised block (for loop's body, if/else branch etc.) then "it depends". At least if I was both doing the removal and using the resulting value in the same block, I would be resolving
var2
as!var2!
instead of%var2%
. I don't know if that's applicable to your specific scenario but it's just one of the more common gotchas I thought I'd mention just in case.