14

在我的一个脚本中,我需要在IF语句中使用包含括号的变量,但要么字符串缺少右括号,要么脚本过早退出* was unexpected at this time(实际上不是星号),具体取决于场景。

 

例子

@echo off

SET path=%programFiles(x86)%
echo Perfect output: %path%
IF NOT "%path%" ==  "" (
    REM Variable is defined
    echo Broken output:  %path%
)

pause >nul

输出

Perfect output: C:\Program Files (x86)
Broken output:  C:\Program Files (x86

 

我认为/知道这是因为它认为右括号C:\Program Files (x86)是语句的结尾,IF它在语句完成之前退出echo

有没有一种简单的方法来解决这个问题?最好不诉诸

  1. 单行IF语句,因为我需要在其中运行多行代码,
  2. 大量的GOTOs,因为它不实用,
  3. SETLOCAL EnableDelayedExpansion并使用!path!而不是%path%,因为我记得在某处读到该方法在操作系统中无法始终如一地工作。

如果不是,我很乐意接受所提供的最可靠的解决方案,无论它是什么。

 

(这个场景没有争议。这只是一个精炼的,集中的问题示例。结构需要像这样,因为它在我的实际脚本中,原因我不会进入。它除了点,它只会混淆事情并分散实际问题的注意力。)

4

5 回答 5

10

首先 - 您永远不应该将 PATH 变量用于自己的用途。它是一个保留的环境变量。将其用于您自己的目的可能会破坏您的脚本。

最简单的解决方案实际上是使用延迟扩展。只要您的平台使用 CMD.EXE,您就可以访问延迟扩展。

但是有一种相对简单的方法可以让它在不延迟扩展的情况下工作。您可以使用消失的引号。在解析命令时,引号作为 FOR 变量的名称存在。它在执行时间之前扩展为空。

@echo off

SET mypath=%programFiles(x86)%
echo Perfect output: %mypath%
IF NOT "%mypath%" ==  "" (
  REM Variable is defined
  for %%^" in ("") do echo fixed output:  %%~"%mypath%%%~"
)

pause >nul

编辑 - 何时使用延迟扩展:对评论的回应

我通常只在需要时使用延迟扩展(或者更准确地说,当它有利时)。话虽如此,我通常发现它在我的批处理代码的某些部分是有利的。

主要优势

  • 在代码块内,以查看块内变量的更改
  • 取消引用变量的名称时。如果将变量名作为参数传入,则可以通过延迟扩展获取变量的值:echo !%1!
  • 当使用变量作为参数进行搜索和替换或子字符串操作时:echo !var:%search%=%replace%!, echo !var:%start%,%len%!.
  • 每当我需要扩展值而不担心其中的特殊字符需要转义或引用时:set "var=A&B" & echo !var!

上面还有其他方法(除了最后一种),但延迟扩展是最简单、最有效(执行速度最快)和最可靠的选择。

主要缺点

  • !如果启用延迟扩展,任何包含其值的 FOR 变量在扩展时都将被破坏。我经常在 FOR 循环中打开和关闭延迟扩展来解决这个问题。
  • 它不适合执行“宏”(执行包含在变量值中的代码),因为命令解析的许多重要阶段发生在延迟扩展之前。通过延迟扩展执行的“宏”无法使用如此多的批处理功能。
于 2012-08-14T03:09:36.760 回答
2

我的建议是:

if (condition_TRUE) goto goodbye_parenthesis_BEGIN

goto goodbye_parenthesis_END  ----- line when previous condition is FALSE ----
:goodbye_parenthesis_BEGIN ----- line when previous condition is TRUE ----

...
variable treatment
...

:goodbye_parenthesis_END
于 2018-04-22T13:13:42.927 回答
1

语句中的已解析变量过早关闭)块。 echoIF

通常,您可以通过转义)with来解决此^)问题,但您不能修改环境变量以解析为C:\Program Files (x86^).

您可以通过用引号将变量括起来来防止此问题。

作为一个更简单的例子:

> SET bad=a)b
> IF 1 == 1 ( ECHO %bad% )
b was unexpected at this time.
> IF 1 == 1 ( ECHO "%bad%" )
"a)b"
于 2012-08-14T00:32:01.857 回答
0

正如其他人已经指出的那样,未转义和未引用的右括号)无意中结束了带括号的if块。

除了转义、引用、延迟扩展和“消失的引用”之外,还有以下更多选项:

  1. 在引用的值上使用for元变量并通过~-modifier删除引号:

     @echo off
    
     set "PATH=%ProgramFiles(x86)%"
     echo Perfect output:  %PATH%
     if not "%PATH%" == "" (
         rem Variable is defined
         for %%P in ("%PATH%") do echo Unbroken output: %%~P
     )
    
     pause > nul
    
  2. 使用call命令启动另一个变量扩展阶段,以及加倍(转义)%-symbols:

     @echo off
    
     set "PATH=%ProgramFiles(x86)%"
     echo Perfect output:  %PATH%
     if not "%PATH%" == "" (
         rem Variable is defined
         call echo Unbroken output: %%PATH%%
     )
    
     pause > nul
    
  3. 通过子字符串替换进行转义,这发生在检测到^-escaping之前:

     @echo off
    
     set "PATH=%ProgramFiles(x86)%"
     echo Perfect output:  %PATH%
     if not "%PATH%" == "" (
         rem Variable is defined
         echo Unbroken output: %PATH:)=^)%
     )
    
     pause > nul
    
于 2020-10-15T15:46:01.067 回答
-1

如果我读错了,请原谅我,但是“NOT”不是导致控件进入括号中的 if 并运行损坏的输出吗?

关于什么:

@echo off

echo Perfect output: %programFiles(x86)%
IF NOT "%programFiles(x86^)%" ==  "" (
    REM Variable is defined
    echo Broken output:  %programFiles(x86)%
) 

pause >nul

?

于 2012-08-14T00:27:47.673 回答