在Windows批处理文件的FOR循环中如何转义星号

4
在Windows批处理文件中运行以下代码时,除了包含星号的字符串被跳过之外,一切都正常。通过按数量检查传递的参数(例如echo(%~6),我可以看到星号 - 只有在传递给FOR循环时才会出现问题:
@echo off
setlocal enableextensions enabledelayedexpansion
call:Concat cmd "this is a demo" " of concat functionality." " Hopefully it will work;" " but it doesn't when I pass an" " * asterisk" " character"
echo !cmd!

@goto:end
@goto:eof


:Concat
::Concatenates a given list of strings without including their quotes
::1 - output variable
::2* - strings to concat
echo(%*
set /a xx=0
set Concat_tempFlag=0
set Concat_temp=
for %%A in (%*) do (
    set /a xx=!xx!+1
    echo !xx! - %%A
    if !Concat_tempFlag!==1 (
        set Concat_temp=!Concat_temp!%%~A
    ) else (
        set Concat_tempFlag=1
    )
)
set "%~1="%Concat_temp%""
@goto:eof

:End
echo(Bye
exit /b 0

我已经尝试过这个建议:Batch FOR loop with asterisk(以及其变体),但都没有成功。有什么想法吗?谢谢。

for /F (tokens=*) %%A in ('echo(%*') do (


1
我对你没有答案,但这里有一个不错的效果(链接:http://pastebin.com/965KhAME)。答案已经在这里了(链接:http://stackoverflow.com/a/13617328/2098699),就像你所知道的那样。 - Endoro
2个回答

6

在这里找到了解决方案:我需要使用本地Windows命令匹配或替换批处理环境变量中的星号*。这可能吗?

完整代码如下:

@echo off
setlocal enableextensions enabledelayedexpansion
set DEFAULT_AsteriskMarker=_xAsteriskMarkerx_
call:Concat cmd "this is a demo" " of concat functionality." " Hopefully it will work;" " but it doesn't when I pass an" " * asterisk" " character"
echo !cmd!

@goto:end
@goto:eof


:Concat
::Concatenates a given list of strings without including their quotes
::1 - output variable
::2* - strings to concat
set Concat_StringsToConcat=%*
echo(%Concat_StringsToConcat%
call:AsteriskFix Concat_StringsToConcat
set /a xx=0
set Concat_tempFlag=0
set Concat_temp=
for %%A in (%Concat_StringsToConcat%) do (
    set /a xx=!xx!+1
    echo !xx! - %%A
    if !Concat_tempFlag!==1 (
        set Concat_temp=!Concat_temp!%%~A
    ) else (
        set Concat_tempFlag=1
    )
)
set "%~1="!Concat_temp:%DEFAULT_AsteriskMarker%=*!"
@goto:eof

:AsteriskFix
::https://dev59.com/z2bWa4cB1Zd3GeqPYZqc
set AsteriskFix_temp=!%~1!
if "%~2"=="" (
    set AsteriskFix_marker=%DEFAULT_AsteriskMarker%
) else (
    set AsteriskFix_marker=%~2
)
call:StrLen AsteriskFix_temp AsteriskFix_len
for /l %%x in (0,1,%AsteriskFix_len%) do if not "!AsteriskFix_temp:~%%x,1!"=="" if "!AsteriskFix_temp:~%%x,1!"=="*" (
    set /a AsteriskFix_plusone=%%x+1
    for /l %%y in (!AsteriskFix_plusone!, 1, !AsteriskFix_plusone!) do (
        set AsteriskFix_temp=!AsteriskFix_temp:~0,%%x!%AsteriskFix_marker%!AsteriskFix_temp:~%%y!
    )
)
set "%~1=!AsteriskFix_temp!"
@goto:eof

:StrLen
::http://www.dostips.com/DtCodeCmdLib.php#strLen
set "StrLen_str=A!%~1!"            &:: keep the A up front to ensure we get the length and not the upper bound
                                 ::it also avoids trouble in case of empty string
set "StrLen_len=0"
for /L %%A in (12,-1,0) do (
    set /a "StrLen_len|=1<<%%A"
    for %%B in (!StrLen_len!) do if "!StrLen_str:~%%B,1!"=="" set /a "StrLen_len&=~1<<%%A"
)
IF "%~2" NEQ "" SET /a %~2=%StrLen_len%
@goto:eof

:End
echo(Bye
exit /b 0

感谢James K

你能否概括一下解决方案的关键? - johny why

4
你提供的链接指向正确答案:

在普通(无/F选项)FOR命令的集合中,没有保留星号(也没有问号)的方法(它们总是被更改为文件名); 您需要在FOR /F命令中分隔参数。 如果您还想在FOR循环中处理每个参数,则第二个FOR不能在同一上下文中,因此必须调用子例程以更改上下文。


1
谢谢验证码 - 我有一个坏习惯,就是忽略那些回答“不行”的答案,总是相信有绕过的方法。经过一番研究,在这里找到了另一个解决办法 - 不是最简洁的,但迫不得已。我点赞了你的答案,严格来说,你是正确的 - 没有简单的方法来解决这个问题。 - JohnLBevan

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