为什么带有问号(?)的字符串不会打印在for batch语句中

时间:2018-01-17 14:10:03

标签: batch-file for-loop

为什么不打印带问号的字符串(从命令提示符开始)?

代码示例: FOR %A IN (--eval string?) DO ECHO %A

代码仅打印--eval但忽略string?

是否有解决方法来打印它?

我试过:

  • 将其用双引号"string?"
  • 括起来
  • 试图逃脱它"string^?""string^^^?"与bang !
  • 一样
  • 试图将??
  • 加倍
  • 尝试了这些
  • 的组合

似乎没什么用。这似乎是一个错误。

编辑根据评论时的答案和问题。

  • 我期待什么? 我希望有两个选项--eval string?打印。

  • 我想要实现的目标? 我试图简化我的最终目标。

最后,我希望!temp_string!变量中包含两个字符串(在下面的test.bat示例中)。

基于真实代码的示例:

test.bat示例:

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

ECHO "First argument outside FOR statement: %~1"
ECHO "Second argument outside FOR statement: %~2"

FOR %%A IN (%*) DO (
    ECHO "First inside FOR argument: %~1"
    ECHO "Second inside FOR  argument: %~2"

    SET "temp_string=%%~A"
    ECHO !temp_string!
)

如果执行text.bat而没有问题?,请执行以下操作:

test.bat --eval --test它会正确显示两个字符串。

结果:

"First argument outside FOR statement: --eval"
"Second argument outside FOR statement: --test"
"First inside FOR argument: --eval"
"Second inside FOR  argument: --test"
--eval
"First inside FOR argument: --eval"
"Second inside FOR  argument: --test"
--test

但是,如果使用相同的参数运行它,但包含?

test.bat --eval --test?

结果不正确:

"First argument outside FOR statement: --eval"
"Second argument outside FOR statement: --test?"
"First inside FOR argument: --eval"
"Second inside FOR  argument: --test?"
--eval

如果您希望看到真实的代码,这是简化的,您可以在第783行找到它here

第二次修改

我现在正试图从@dbenham的拟议解决方案中获取%%A的值。

%test%变量在两种情况下仍为空:

@echo off

setlocal disableDelayedExpansion

set "string=--eval string? ;hello <&|>! "^<^&^|^>!""
set string
echo(

setlocal enableDelayedExpansion
for %%n in (^"^
%= This results in a quoted newline character =%
^") do for /f delims^=^ eol^= %%A in ("!string: =%%~n!") do (
    if "!!" equ "" endlocal set "test=%%~A"
    echo "A value:" %%A
    echo "Test value:" %test%
)

echo %test%

输出:

string=--eval string? ;hello <&|>! "<&|>!"

"A value:" --eval
"Test value:"
"A value:" string?
"Test value:"
"A value:" ;hello
"Test value:"
"A value:" <&|>!
"Test value:"
"A value:" "<&|>!"
"Test value:"
ECHO is off.

第三和第四编辑 - 答案。

基于dbenham&amp;&amp;斯蒂芬我正在发布我满意的工作代码。 注意:dbenham肮脏的"^<^&^|^>!"在这里不起作用,但我认为我不需要它。

@echo off
REM works for all!!! --> *.bat -string? :hello "<&|>!"

setlocal disableDelayedExpansion

:process_arguments
:: Process all arguments in the order received
if defined %1 (
    ECHO %1
    SET "string=%string% %~1"
    shift
    goto:process_arguments
)

echo(

setlocal enableDelayedExpansion
for %%n in (^"^
%= This results in a quoted newline character =%
^") do for /f "eol= delims=" %%A in ("!string: =%%~n!") do (
    if "!!" equ "" endlocal 
    set "test=%%~A"
    echo "In for loop - a value: %%A"
    CALL :testing_value "%%A"
)
:: END
goto :eof

:: echo "Outside test:" %test%
setlocal disableDelayedExpansion

:testing_value
  set "test=%~1"
  set test
  echo "Calling Subroutine: %test%"
  echo:

谢谢你的指导!

3 个答案:

答案 0 :(得分:3)

当您使用通配符时,

for会尝试查找匹配的文件。并且?恰好是“一个字符”的通配符。也许,你没有匹配的文件...
 要处理此类字符串,请使用for /f

FOR /f "delims=" %A IN ("--eval string?") DO ECHO %A

编辑找到了一种拆分方法,但是有一个临时文件:

@echo off
setlocal enabledelayedexpansion

REM create a linefeed:
set ^"LF=^

^" The above empty line is critical - DO NOT REMOVE

set "string=--eval string? hello"
(echo %string: =!LF!%) >tmp
for /f "delims=" %%A in (tmp) do echo %%A

Edit2 dbenham向我展示了一种没有临时文件的方法(有时候我会考虑过多的角落):

@echo off
setlocal enabledelayedexpansion

REM create a linefeed:
set ^"LF=^

^" The above empty line is critical - DO NOT REMOVE

set "string=--eval string? hello"
for /f "delims=" %%A in ("%string: =!LF!%") do echo %%A

答案 1 :(得分:3)

Stephan's last answer有效,但可能会出现并发症:

  • 延迟扩展会导致!文字出现问题。
    • 通过有条件地在循环内切换延迟扩展来解决
  • 毒药角色可能会有问题,特别是如果有些被引用,有些则不是。
    • 通过延迟扩展扩展解决,并结合<LF>替换术语的FOR变量
  • EOL可能是个问题,具体取决于每个字符串的起始字符。
    • 通过使用一些神秘的语法
    • 禁用DELIMS和EOL来解决

这是一种可以解决所有问题的强大技术:

@echo off
setlocal disableDelayedExpansion

set "string=--eval string? ;hello <&|>! "^<^&^|^>!""
set string
echo(

setlocal enableDelayedExpansion
for %%n in (^"^
%= This results in a quoted newline character =%
^") do for /f delims^=^ eol^= %%A in ("!string: =%%~n!") do (
    if "!!" equ "" endlocal
    echo %%A
)

- 输出 -

string=--eval string? ;hello <&|>! "<&|>!"

--eval
string?
;hello
<&|>!
"<&|>!"

<强> 修改

由于我们用[LF]替换了所有[space],我们知道一条线永远不能以[space]开头。

因此,如果我们将EOL设置为[space],则更简单。 FOR / F选项可简化为:

for /f "eol= delims=" ...

答案 2 :(得分:1)

使用标签并移动参数的循环可以处理?作为文字。 要防止转移主脚本参数,请调用标签,例如:args below。

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

CALL :args %*

ECHO "First outside argument: %~1"
ECHO "Second outside argument: %~2"

GOTO :eof

:args
ECHO "First inside argument: %~1"
ECHO "Second inside argument: %~2"
:args_loop
SET "temp_string=%~1"
IF NOT DEFINED temp_string GOTO :end_args_loop
ECHO !temp_string!
SHIFT
GOTO :args_loop
:end_args_loop
SET "temp_string="
GOTO :eof

一个已知问题是%*中有/?call可能会输出call的帮助。