Gouranga Das
Gouranga Das

Reputation: 474

How remove the | character from variable

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

Answers (1)

Mofi
Mofi

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

Related Questions