Why does windows shell's for command replace semicolons?

Viewed 140

I'm trying to write a small script which replaces a value in windows' path. Using some sed to replace it is fine (I've got the proper variable):

echo %path% | sed "s/jvms\\[^^\]\+/jvms\\%1/"

This works fine. However, I want to assign that to a new path variable. The way to do that should be

for /f "delims=" %%B in ('echo %path% ^| sed "s/windows/C64/"' ) do call set replaced=%%B
echo %replaced%

Note that the | is escaped as it should. However, the new replaced variable has all the semicolons replaced by spaces. Hence, the output of echo %replaced% is something like c:\C64 c:\program files c:\otherdirectory instead of c:\C64;c:\program files;c:\otherdirectory

This already happens when I don't use any sed, so

for /f "delims=" %%B in ('echo %path%' ) do call set replaced=%%B
echo %replaced%

then returns c:\Windows c:\program files c:\otherdirectory

How can I ensure that the semicolon is not replaced by spaces?

2 Answers

The cmd parser considers semicolons (as well as commas, equal signs and TABs) as token separators. The for /f command undergoes one round of parsing, where the separators are replaced with spaces. For example, for /f "delims=" %%B in ('echo a;b==c,,,d') do echo %%B results in a b c d.

One way to avoid the replacement is to quote the argument, then unquote the %%~B token. For the second example, for /f "delims=" %%B in ('echo "%path%"' ) do set "replaced=%%~B" will work as expected.

As already mentioned in the comments, there's no need for a third party stream editor, or find and replace utility, for this task. You can use variable expansion and substitution, and this will also negate the need for a too:

Example:

Set "replaced=%PATH::\Windows=:\C64%"

If the replacement string is being received as the first input argument then, you'd use delayed variable expansion.

Example:

@Echo Off
SetLocal EnableDelayedExpansion
Set "replaced=!PATH::\Windows=:\%~1!"
Echo %replaced%
Related