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;开发者_StackOverflow社区d:\file2.js) and copy the files to destination folder specified by %1.
I need to replace the %1
parameter's string value of x
(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?
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:
http://blogs.msdn.com/b/oldnewthing/archive/2006/08/23/714650.aspx
http://www.dostips.com/DtTutoFramework.php#_Toc128587174
- On substring replacement:
- http://www.dostips.com/DtTipsStringOperations.php#Snippets.Replace
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 !
If you need to substitute several parameters in one string, just use "for /f" to set variable with previous substitution like this:
SET "output1=%1"
CALL SET output1=%%output1:%3=%4%%
for /f "tokens=1" %%a in ('echo %output1%') do set output2=%%a
CALL SET output2=%%output2:%5%6%
for /f "tokens=1" %%a in ('echo %output2') do set output3=%%a
精彩评论