如何删除|变量中的字符

时间:2018-08-26 15:52:31

标签: batch-file

我有如下代码:

    FOR /F "tokens=*" %%B IN ('%*') DO (
    ECHO %%B
    SET data=%%B
    ECHO %data%
    )        

%% B包含一个或多个|字符,例如%% B的值是 First |第二|第三 SET data = %% B SET data =“ %% B” 功能不起作用。回叫%data%时,它表明Echo已关闭。

我需要删除| %% B中的字符并将其保存到%data%变量中。但是我不知道怎么办?

如果有人提供任何解决方案,我将不胜感激。

1 个答案:

答案 0 :(得分:2)

第一个解决方案是使用:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

for /F delims^=^ eol^= %%B in ('%*') do (
    set "data=%%B"
    set "data=!data:|=!"
    echo(!data!
)

endlocal

tokens=*导致将整个行分配给循环变量B,并且删除前导空格/制表符,而delims=导致将分配给整个循环变量B行,包括前导空格/制表符。因此,一般来说,定义一个空的定界符列表会更好。

FOR 默认情况下会忽略空行和以分号开头的行,因为;在默认情况下会被解释为行尾字符。因此,此处使用不常见的,不是双引号的选项字符串delims^=^ eol^=来定义一个空的定界符列表,并且没有行尾字符。插入符号^用于转义下一个字符,以使它被解释为原义字符,而不是参数分隔符,尽管它没有包含在双引号引起来的字符串中。

但是此解决方案存在一个问题:包含一个或多个感叹号!的行未正确处理,因为Windows命令处理器在命令行set "data=%%B"上将每个!解释为开始/延迟的环境变量引用的结尾,并用该名称的环境变量的当前值替换两个感叹号之间的字符串,或者使用该名称的不存在的变量将其替换为空,并删除!之后的所有内容(如果没有)更多!

至少有三种解决方案。

第一个是在循环中启用和禁用延迟扩展。

@echo off
setlocal EnableExtensions DisableDelayedExpansion

for /F delims^=^ eol^= %%B in ('%*') do (
    set "data=%%B"
    setlocal EnableDelayedExpansion
    set "data=!data:|=!"
    echo(!data!
    endlocal
)

endlocal

请阅读this answer,以获取有关命令 SETLOCAL ENDLOCAL 的详细信息,因为它们的作用不只是切换循环中的延迟扩展开/关。 / p> 如果行仅包含(,而行中仅包含echo,而行中仅包含空格或制表符,则使用{p} data和环境变量|之间的

data 1}}变为未定义或仅由空格/制表符组成的字符串。 echo!data!之间的空格将仅在命令echo 上执行,该命令带有忽略的空格和0个或多个空格/制表符,从而导致获得输出ECHO is off.而不是空行或仅包含空格/制表符的行。右方括号防止出现这种情况,并由cmd.exe解释为命令echo及其参数字符串之间的分隔符,在这种情况下,该字符串始终以(开始。 ECHO 会忽略输出中参数字符串的第一个字符,只要参数字符串不是/?且永远不会输出(

第二种解决方案是使用子例程:

@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

注意:如果行中包含重定向操作符echo %data%<或操作符>之类的字符,&可能导致意外行为Windows命令处理器将环境变量echo(%data%的当前字符串替换为%data%后执行data。根据包含set "data=%data:|=%""的行,甚至<>&也会有问题。因此,此解决方案确实不安全。

另请参阅Where does GOTO :EOF return to?

第三个解决方案是使用“双百分数”环境变量引用并使用命令 CALL 强制对包含%%variable%%而不是%variable%的命令行进行双重解析像往常一样。

@echo off
setlocal EnableExtensions DisableDelayedExpansion

for /F delims^=^ eol^= %%B in ('%*') do (
    set "data=%%B"
    call set "data=%%data:|=%%"
    call echo(%%data%%
)

endlocal

注意另外,根据作为第二种解决方案的数据,该解决方案并不十分安全。

另请参阅How does the Windows Command Interpreter (CMD.EXE) parse scripts?

Windows命令处理器设计用于执行命令和应用程序,而不用于使用竖线作为分隔符/分隔符来重新格式化或处理CSV文件。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • call /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • set /?
  • setlocal /?

由于使用语法set "variable=value"而不是set variable=valueset variable="value"的原因,还请阅读Why is no string output with 'echo %var%' after using 'set var = text' on command line?上的答案。