Reputation: 474
I've a code like below:
FOR /F "tokens=*" %%B IN ('%*') DO (
ECHO %%B
SET data=%%B
ECHO %data%
)
The %%B contains one or more than one | character, for example the value of %%B is First | Second | Third. The SET data=%%B or SET data="%%B" function doesn't work. When %data% is called back, it shows Echo is off.
I need to remove the | character from %%B and save it to a %data% variable. But I don't know how?
I will be grateful if any solution has been provided from anyone....
Upvotes: 1
Views: 3261
Reputation: 49096
The first solution is using:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /F delims^=^ eol^= %%B in ('%*') do (
set "data=%%B"
set "data=!data:|=!"
echo(!data!
)
endlocal
tokens=*
results in getting assigned to loop variable B
the entire line with leading spaces/tabs removed while delims=
results in getting assigned to the loop variable B
the entire line including leading spaces/tabs. So the definition of an empty list of delimiters is better in general.
FOR ignores by default empty lines and lines starting with a semicolon because of ;
is interpreted by default as end of line character. For that reason the uncommon, not double quoted option string delims^=^ eol^=
is used here to define an empty list of delimiters and no end of line character. The caret character ^
is used to escape the next character to get it interpreted as literal character and not as argument separator although not enclosed in a double quoted argument string.
But there is one problem with this solution: A line containing one or more exclamation marks !
is not processed correct because Windows command processor interprets on command line set "data=%%B"
each !
as begin/end of a delayed environment variable reference and replaces the string between two exclamation marks by the current value of the environment variable with that name or nothing on no variable existing with such a name and removes everything after !
if there is no more !
.
There are at least three solutions.
The first one is enabling and disabling delayed expansion within the loop.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F delims^=^ eol^= %%B in ('%*') do (
set "data=%%B"
setlocal EnableDelayedExpansion
set "data=!data:|=!"
echo(!data!
endlocal
)
endlocal
Please read this answer for details about the commands SETLOCAL and ENDLOCAL as they do much more than just toggling delayed expansion on/off in the loop.
(
between echo
and value of environment variable data
is used in case of a line contains only |
without or with additionally just spaces/tabs resulting in data
becoming either undefined or a string consisting only of spaces/tabs. A space between echo
and !data!
would be on execution just the command echo
with an ignored space and 0 or more spaces/tabs resulting in getting output ECHO is off.
instead of an empty line or a line with just spaces/tabs. The opening round bracket prevents that and is interpreted by cmd.exe
as separator between command echo
and its argument string which begins in this case always with (
. ECHO ignores the first character of the argument string on output as long as the argument string is not /?
and so (
is never output.
The second solution is using a subroutine:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F delims^=^ eol^= %%B in ('%*') do (
set "data=%%B"
call :ProcessLine
)
endlocal
goto :EOF
:ProcessLine
set "data=%data:|=%"
echo(%data%
goto :EOF
Note: echo %data%
can result in unexpected behavior if the line contains characters like the redirection operators <
and >
or the operator &
as Windows command processor executes echo(%data%
after substituting %data%
with current string of environment variable data
. Even set "data=%data:|=%"
can be problematic depending on line containing "
and <>&
. So this solution is really not safe.
See also Where does GOTO :EOF return to?
The third solution is using a "double percent" environment variable reference and using command CALL to force a double parsing of the command line containing %%variable%%
instead of just %variable%
as usual.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F delims^=^ eol^= %%B in ('%*') do (
set "data=%%B"
call set "data=%%data:|=%%"
call echo(%%data%%
)
endlocal
Note Also this solution is not really safe depending on the data as the second solution.
See also How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Windows command processor is designed for executing commands and applications and not for reformatting or processing CSV files using vertical bar as delimiter/separator.
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.
call /?
echo /?
endlocal /?
for /?
goto /?
set /?
setlocal /?
And read also answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? for the reason using the syntax set "variable=value"
instead of set variable=value
or set variable="value"
.
Upvotes: 2