批处理文件:如何替换“=”(等号)和字符串变量?

8
除了SED之外,如何替换等号? 如何在字符串替换中使用字符串变量?
考虑以下示例:
For /F "tokens=*" %%B IN (test.txt) DO (
   SETLOCAL ENABLEDELAYEDEXPANSION
   SET t=is
   SET old=%%B
   SET new=!old:t=!
   ECHO !new!

   ENDLOCAL
)

:: SET new=!old:==!

两个问题:
首先,我不能在 !:=! 中使用变量 %t%。
   SET t=is
   SET old=%%B
   SET new=!old:t=!

其次,我无法在命令行中替换等号

   SET new=!old:==!

你真的在DOS上工作吗?还是说你只是指的Windows命令提示符? - Damien_The_Unbeliever
1
当然,%t%无法工作,因为它在循环运行之前就被替换了。 - Joey
Damien,这显然是 cmd - Joey
1
@Joey - 当然是这样的 - 但有时我会采用修辞风格,试图让人们意识到他们在术语上不够准确。 - Damien_The_Unbeliever
Damien,我早就放弃了,我只是默默地编辑 ;) - Joey
7个回答

8

我刚刚自己创建了一个简单的解决方案,希望能对某些人有所帮助。

缺点(或优点,取决于你想做什么)是连续多个等号会被视为单个等号处理。例如:"str==ing" 的输出与 "str=ing" 相同。

@echo off
set "x=this is=an test="
echo x=%x%

call :replaceEqualSign in x with _
echo x=%x%

pause&exit


:replaceEqualSign in <variable> with <newString>
    setlocal enableDelayedExpansion

        set "_s=!%~2!#"
        set "_r="

        :_replaceEqualSign
            for /F "tokens=1* delims==" %%A in ("%_s%") do (
                if not defined _r ( set "_r=%%A" ) else ( set "_r=%_r%%~4%%A" )
                set "_s=%%B"
            )
        if defined _s goto _replaceEqualSign

    endlocal&set "%~2=%_r:~0,-1%"
exit /B

正如您所见,您可以像这样使用该函数:

call :replaceEqualSign in variableName with newString

3

在%%B包含!的情况下,setlocal enableDelayedExpansion应该在您的old=%%B赋值之后移动。

“t”问题在循环中可以通过使用另一个FOR变量轻松解决。

For /F "tokens=*" %%B IN (test.txt) DO (
   SET t=is
   SET old=%%B
   SETLOCAL ENABLEDELAYEDEXPANSION
   for /f %%T in ("!t!") do SET new=!old:%%T=!
   ECHO !new!
   ENDLOCAL
)

替换=没有简单的本地批处理解决方案。你可以逐个字符迭代字符串,但这很慢。你最好是切换到VBScript或JScript,或使用非本地实用程序。

如果你真的想使用纯Windows批处理命令来完成这个任务,可以在http://www.dostips.com/forum/viewtopic.php?t=1485上找到一些有趣的想法。


1
我明白了。也许我需要学习VBScript、VB或C#。它们似乎是DOS命令的高级版本。如果文本是这样的:This is an apple. This is a cat.使用代码可以去掉所有的“is”。我们知道如何在VB中只替换整个单词,但在DOS命令中怎么办?这是不可能的吗?对于等号的情况也是一样吗? - Tin Amaranth
如果你只想替换整个单词,那么批处理脚本并不是一个好的选择。虽然可以近似实现,但最好使用支持正则表达式搜索和替换的工具,比如VBScript。 - dbenham
是的,我知道。谢谢你指引我使用合适的编程语言。 - Tin Amaranth
也许我需要学习VBScript、VB或C#。它们似乎是DOS命令的高级版本。另外,“C#是DOS命令的高级版本”这个说法也是正确的。 - Christian Severin

2

更新: 最新版本在这里: https://github.com/andry81/contools (https://github.com/andry81/contools/tree/HEAD/Scripts/Tools/std/)

您可以使用一些序列来临时替换特殊字符,例如?00、?01、?02和?03。我基本上使用这些脚本集:

replace_sys_chars.bat:

@echo off

rem Description:
rem   Script to replace ?, !, %, and = characters in variables by respective
rem   ?00, ?01, ?02 and ?03 placeholders.

setlocal DISABLEDELAYEDEXPANSION

set "__VAR__=%~1"

if "%__VAR__%" == "" exit /b 1

rem ignore empty variables
call set "STR=%%%__VAR__%%%"
if "%STR%" == "" exit /b 0

set ?01=!

call set "STR=%%%__VAR__%:?=?00%%"
set "STR=%STR:!=?01%"

setlocal ENABLEDELAYEDEXPANSION

set STR=!STR:%%=?02!
set "STR_TMP="
set INDEX=1

:EQUAL_CHAR_REPLACE_LOOP
set "STR_TMP2="
for /F "tokens=%INDEX% delims== eol=" %%i in ("/!STR!/") do set STR_TMP2=%%i
if "!STR_TMP2!" == "" goto EQUAL_CHAR_REPLACE_LOOP_END
set "STR_TMP=!STR_TMP!!STR_TMP2!?03"
set /A INDEX+=1
goto EQUAL_CHAR_REPLACE_LOOP

:EQUAL_CHAR_REPLACE_LOOP_END
if not "!STR_TMP!" == "" set STR=!STR_TMP:~1,-4!

(
  endlocal
  endlocal
  set "%__VAR__%=%STR%"
)

exit /b 0

restore_sys_chars.bat:

@echo off

rem Description:
rem   Script to restore ?, !, %, and = characters in variables from respective
rem   ?00, ?01, ?02 and ?03 placeholders.

setlocal DISABLEDELAYEDEXPANSION

set "__VAR__=%~1"

if "%__VAR__%" == "" exit /b 1

rem ignore empty variables
call set "STR=%%%__VAR__%%%"
if "%STR%" == "" exit /b 0

setlocal ENABLEDELAYEDEXPANSION

set STR=!STR:?02=%%!
set STR=!STR:?03==!

(
  endlocal
  set "STR=%STR%"
)

set "STR=%STR:?01=!%"
set "STR=%STR:?00=?%"

(
  endlocal
  set "%__VAR__%=%STR%"
)

exit /b 0

例子:

@echo off

setlocal DISABLEDELAYEDEXPANSION

for /F "usebackq tokens=* delims=" %%i in ("test.txt") do (
  set VALUE=%%i
  call :PROCESS
)
exit /b 0

:PROCESS
if "%VALUE%" == "" exit /b 0

set "VALUE_=%VALUE%"
call replace_sys_chars.bat VALUE_

rem do variable arithmetic here as usual
if not "%VALUE_:?00=%" == "%VALUE_%" echo."%VALUE%" having ?
if not "%VALUE_:?01=%" == "%VALUE_%" echo."%VALUE%" having !
if not "%VALUE_:?02=%" == "%VALUE_%" echo."%VALUE%" having %%
if not "%VALUE_:?03=%" == "%VALUE_%" echo."%VALUE%" having =

rem restore it
call restore_sys_chars.bat VALUE_
echo "VALUE=%VALUE_%"

echo.---

test.txt:

111/222
AAA=BBB
CCC=%DDD%
EEE=!FFF!
FFF=?00?01?02?03

结果:

"VALUE=111/222"
---
"AAA=BBB" having =
"VALUE=AAA=BBB"
---
"CCC=%DDD%" having %
"CCC=%DDD%" having =
"VALUE=CCC=%DDD%"
---
"EEE=!FFF!" having !
"EEE=!FFF!" having =
"VALUE=EEE=!FFF!"
---
"FFF=?00?01?02?03" having ?
"FFF=?00?01?02?03" having =
"VALUE=FFF=?00?01?02?03"
---

特点:

  • 您可以在转换之间继续使用标准批处理变量算术运算
  • 您可以将字符占位符(?00、?01、?02、?03)用作普通变量值

1
为什么不使用Edlin?我找不到一种方法来使用一个初始文件并且没有从Edlin返回错误,但只需使用NUL:忽略它们。 奇怪的是,即使在=和!之间有文件结束字符,TYPE %0也会包括整个文件,在运行后对批处理文件使用TYPE将无法以相同的方式工作。
@ECHO OFF
GOTO skip
1,1r=!
e
:skip

SET "new==old============="

ECHO %new% > %TEMP%\var.tmp
TYPE %0 > %TEMP%\edlin.tmp

EDLIN %TEMP%\var.tmp < %TEMP%\edlin.tmp > NUL:

SET /P newnew=<%TEMP%\VAR.TMP
ECHO %newnew%

ERASE %TEMP%\VAR.TMP
ERASE %TEMP%\VAR.BAK
ERASE %TEMP%\edlin.tmp

当我发帖时,文件结尾的字符被删除了。它应该位于第三行的等号和感叹号之间。 - Erbert

0

我借鉴了Bosj的想法,得出了这个解决方案。它很有效。

set s=Abra=Cadabra
echo now you see it  %s%
call :ReplaceEqual %s%
echo  now you don't  %s%
exit /b
:ReplaceEqual
set s=%1_%2
exit /b

2
但是如果你有Abra Cadabra或者Abra;Cadabra或者Abra,Cadabra,它也可以“工作”,但对于Abra Abra=CadabraAbra====Cadabra则不起作用。 - Magoo

0

我正在研究这个问题,因为我需要从字符串“test=goingon”中去掉等号。 我发现可以使用test=goingon作为参数调用下一个批处理文件,在那个批处理文件中,我可以得到参数1,“test”和参数2,“goingon”。

所以: 批处理文件1:

@echo off
call test2.bat test=goingon

批处理文件2:

echo arg1: %1
echo arg2: %2

结果:

arg1: test
arg2: goingon

-1

这是我在另一篇帖子中的回答,但它也适用于这里:

有一个更简单的替代方案。不要传递包含等号的值,而是尝试使用冒号之类的符号。然后,通过修改该值(即冒号),您可以将其转换回等号。以下是一个示例:

@echo off
set VALUE1=%1
set VALUE2=%VALUE1::==%
echo value1 = %VALUE1%
echo value2 = %VALUE2%

当你运行批处理文件时,像这样调用它:

C:\>myBatch name:someValue

输出将会是:

value1 = name:someValue
value2 = name=someValue

如果名称或值包含空格,您将需要解决其他问题。您需要用双引号将整个字符串括起来。但是,接着你还需要将其去掉。可以这样处理:

@echo off
cls
set PARAM=%1
set BASE=%PARAM:"=%
set PAIR=%BASE::==%

rem Either of these two lines will do the same thing - just notice the 'delims'
rem for /f "tokens=1,2 delims=:" %%a in ("%BASE%") do set NAME=%%a & set VALUE=%%b
rem for /f "tokens=1,2 delims==" %%a in ("%PAIR%") do set NAME=%%a & set VALUE=%%b

for /f "tokens=1,2 delims=:" %%a in ("%BASE%") do set NAME=%%a & set VALUE=%%b

echo param = %PARAM%
echo base  = %BASE%
echo pair  = %PAIR%
echo name  = %NAME%
echo value = %VALUE%

当像这样运行批处理文件时:

C:\>myBatch "some name:another value"

输出结果为:

param = "some name:another value"
base  = some name:another value
pair  = some name=another value
name  = some name
value = another value

希望这能帮助其他人在与批处理文件的斗争中取得胜利。
Mike V.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接