How to escape variables with parentheses inside if-clause in a batch file?

前端 未结 4 2024
天涯浪人
天涯浪人 2020-12-16 10:54

Running this batch file

@echo off
set a=some value with (parentheses) inside
if 1 == 1 (
    set PATH=%a%
)

gives inside was unexpect

相关标签:
4条回答
  • 2020-12-16 11:21

    Using delayed expansion will fix that:

    @echo off
    setlocal enabledelayedexpansion
    set a=some value with (parentheses) inside
    if 1 == 1 (
        set PATH=!a!
    )
    

    Without delayed expansion the if block (from the if to the ending ), %a% is replaced first and then the block is parsed and run. With delayed expansion !a! isn't expanded after the block parsed. So the parsing logic won't see the ) in a and won't cause it issues.

    0 讨论(0)
  • 2020-12-16 11:30

    Brackets and variables are always a pain to mix. Use a subroutine instead.

    @Echo Off
    Set a=some value with (parentheses) inside
    If 1 == 1 Call :SetPath
    Echo %Path%
    Exit /B
    
    :SetPath
    Set "Path=%a%"
    SetX "Path" "%a%"
    Exit /B
    

    I set the variable twice, once using Set for the current shell session, and one using SetX to set it system-wide for future shell sessions. Remove either if they're unneeded.

    0 讨论(0)
  • 2020-12-16 11:41

    The ) in %a% is the problem here. You can just do some substitution to escape the ).

    @echo off
    set a=some value with (parentheses) inside
    if 1 == 1 (
        set PATH=%a:)=^)%
    )
    
    0 讨论(0)
  • 2020-12-16 11:45

    You can use two different ways

    Use the extended syntax of set with quotes set "var=content" will set var with content, content is quoted so special characters aren't problematic and it uses the content till the last quote (without the quote itself)

    @echo off
    set a=some value with (parentheses) inside
    if 1 == 1 (
        set "PATH=%a%"
    )
    

    Use delayed expansion (like the answer of shf301) but also transfer the value to the main scope.

    @echo off
    setlocal enabledelayedexpansion
    set a=some value with (parentheses) inside
    if 1 == 1 (
        set "localScope_PATH=!a!"
        rem now transfer it to the global scope
        FOR /F "delims=" %%A in ("!localScope_PATH!") DO (
           endlocal
           set "path=%%A"
        )
    )
    

    In this case the extended set-syntax is not necessary, I used it only to avoid hidden spaces at the line end.

    EDIT: Can I combine this with setlocal EnableDelayedExpansion and using ! instead of % to lazy evaluate variable's value? When I tried I got )! was unexpected at this time.

    You can, but it's contra productive, as

    @echo off
    Setlocal EnableDelayedExpansion
    set a=some value with (parentheses) inside
    if 1 == 1 (
        set PATH=!a:^)=^^^)!
        set path
    )
    

    Then your path contains carets in front of the ) like C:\programs (x86^)

    To understand how expansion works you can read SO:How does the Windows Command Interpreter (CMD.EXE) parse scripts?

    EDIT2: More problems with the path (containing quotes)
    According to this question there can occour another problem with parenthesis when the path contains quotes.

    Sample
    path="C:\Program Files (x86)";C:\Program Files (x86)\Skype

    This is allowed, even it's not necessary to use quotes here, but this destroys the extended SET syntax, as now set "newPath=%path%" expands to

    set "newPath="C:\Program Files (x86)";C:\Program Files (x86)\Skype"
    

    Now at least one parenthesis is not inside quotes and is able to break a command block.

    But you can simply remove all quotes from the path variable, as said, quotes aren't necessary here.

    set "newPath=%path:"=%"
    
    0 讨论(0)
提交回复
热议问题