正则表达式来识别大括号内的DOS环境变量

时间:2022-09-13 00:20:00

The following DOS script snippet has a bug:

以下DOS脚本片段有一个错误:

if not exist %MyFolder% (
    mkdir %MyFolder%
    if %errorlevel% GEQ 1 (
        rem WARNING: the line above has a bug! 
        rem %errorlevel% will be the errorlevel 
        rem of the if statement because of the (parentheses)
        echo Error: Could not create folder %MyFolder%
        goto AnErrorOccurred
    )
)

The fix is to use setlocal enabledelayedexpansion as follows:

解决方法是使用setlocal enabledelayedexpansion,如下所示:

setlocal enabledelayedexpansion
if not exist %MyFolder% (
    mkdir %MyFolder%
    if !errorlevel! GEQ 1 (
        rem WARNING: the line above has a bug! 
        rem !errorlevel! will be the errorlevel 
        rem of the if statement because of the (parentheses)
        echo Error: Could not create folder %MyFolder%
        endlocal & goto AnErrorOccurred
    )
)
endlocal

A full explanation of why is available here: Batch file fails to set environment variable within conditional statement

有关原因的完整说明:批处理文件无法在条件语句中设置环境变量

I want to audit my code to find instances of this bug, I figure a Regex would be an appropriate match, but haven't managed to get one working...

我想审核我的代码以找到这个bug的实例,我认为一个正则表达式将是一个合适的匹配,但还没有设法让一个工作...

I think the ingredients should be: Match an environment variable surrounded with %percentsigns% That is inside (parentheses)

我认为成分应该是:匹配一个环境变量包围%percentntsigns%里面(括号)

Any suggestions?

4 个解决方案

#1


grepWin

I would use grepWin. Depending on the number of instances you have to find, you could write a regex that will give you all of them, plus some false positives.

我会用grepWin。根据您必须找到的实例数量,您可以编写一个正则表达式,它将为您提供所有这些实例,以及一些误报。

Example: bug.bat

if not exist %MyVar% echo Hi!

if not exist %MyFolder% (
    mkdir %MyFolder%
    if %errorlevel% GEQ 1 (
        rem WARNING: the line above has a bug!
        rem %errorlevel% will be the errorlevel
        rem of the if statement because of the brackets
        echo Error: Could not create folder %MyFolder%
        goto AnErrorOccurred
    )
)

Then use a regular expression to match all lines that start with if and have an open parenthesis:

然后使用正则表达式匹配以if开头且具有左括号的所有行:

$ grep "^[ \t]*if.*(" bug.bat
if not exist %MyFolder% (
    if %errorlevel% GEQ 1 (

grepWin will show you all the files that match.

grepWin将显示所有匹配的文件。

Percent Symbols

By request:

grep "^[ \t]*if.*%.*%.*(" bug.bat

#2


You can't solve it with Regex, because you can't count the parenthesis with a regular language. For example:

您无法使用Regex解决此问题,因为您无法使用常规语言计算括号。例如:

Stuff (
More Stuff (
Less Stuff )
A %var%
Less Stuff )

There is no ( between the last ) and the variable. Since I can't count how many `( appear before to know if there's one open, I can't do this with regular expressions.

没有(在最后一个之间)和变量。因为我无法计算多少`(以前知道是否有一个打开,我不能用正则表达式做到这一点。

#3


As you can see, he is using ! rather than % even in the rootlevel of the batch. So basically you should be able to alternate every % to an ! for your environmental variables.

如你所见,他正在使用!而不是%甚至在批次的根级别。所以基本上你应该能够将每个%交替到一个!为你的环境变量。

#4


One other way is to use the AND (&&) and OR (||) tests for success (errorlevel 0) or error (errorlevel > 0), as in:

另一种方法是使用AND(&&)和OR(||)测试成功(错误级别0)或错误(错误级别> 0),如:

if not exist %MyFolder% mkdir %MyFolder%|| (
        echo Error: Could not create folder %MyFolder%
        goto AnErrorOccurred
)

I hope this can help.

我希望这可以提供帮助。

And by the way, you do not fail to set the variable, you fail to read it back.

顺便说一句,你没有设置变量,你无法读回它。

What happen is, within parenthesis, using %%'s give you the states which was before you entered the said parenthesis. The only thing I knows work well is the math "set /a toto+=1" which will correctly increment the variable. Otherwise you have two options:

所发生的是,在括号内,使用%%'s给出你进入所述括号之前的状态。我知道唯一合适的工作是数学“set / a toto + = 1”,这将正确地增加变量。否则你有两个选择:

Either use a called function to set the variable or use the setlocal ENABLEDELAYEDEXPANSION statement, as previously stated, and use !!'s within the parenthesis.

如前所述,使用被调用函数来设置变量或使用setlocal ENABLEDELAYEDEXPANSION语句,并在括号内使用!!'。

#1


grepWin

I would use grepWin. Depending on the number of instances you have to find, you could write a regex that will give you all of them, plus some false positives.

我会用grepWin。根据您必须找到的实例数量,您可以编写一个正则表达式,它将为您提供所有这些实例,以及一些误报。

Example: bug.bat

if not exist %MyVar% echo Hi!

if not exist %MyFolder% (
    mkdir %MyFolder%
    if %errorlevel% GEQ 1 (
        rem WARNING: the line above has a bug!
        rem %errorlevel% will be the errorlevel
        rem of the if statement because of the brackets
        echo Error: Could not create folder %MyFolder%
        goto AnErrorOccurred
    )
)

Then use a regular expression to match all lines that start with if and have an open parenthesis:

然后使用正则表达式匹配以if开头且具有左括号的所有行:

$ grep "^[ \t]*if.*(" bug.bat
if not exist %MyFolder% (
    if %errorlevel% GEQ 1 (

grepWin will show you all the files that match.

grepWin将显示所有匹配的文件。

Percent Symbols

By request:

grep "^[ \t]*if.*%.*%.*(" bug.bat

#2


You can't solve it with Regex, because you can't count the parenthesis with a regular language. For example:

您无法使用Regex解决此问题,因为您无法使用常规语言计算括号。例如:

Stuff (
More Stuff (
Less Stuff )
A %var%
Less Stuff )

There is no ( between the last ) and the variable. Since I can't count how many `( appear before to know if there's one open, I can't do this with regular expressions.

没有(在最后一个之间)和变量。因为我无法计算多少`(以前知道是否有一个打开,我不能用正则表达式做到这一点。

#3


As you can see, he is using ! rather than % even in the rootlevel of the batch. So basically you should be able to alternate every % to an ! for your environmental variables.

如你所见,他正在使用!而不是%甚至在批次的根级别。所以基本上你应该能够将每个%交替到一个!为你的环境变量。

#4


One other way is to use the AND (&&) and OR (||) tests for success (errorlevel 0) or error (errorlevel > 0), as in:

另一种方法是使用AND(&&)和OR(||)测试成功(错误级别0)或错误(错误级别> 0),如:

if not exist %MyFolder% mkdir %MyFolder%|| (
        echo Error: Could not create folder %MyFolder%
        goto AnErrorOccurred
)

I hope this can help.

我希望这可以提供帮助。

And by the way, you do not fail to set the variable, you fail to read it back.

顺便说一句,你没有设置变量,你无法读回它。

What happen is, within parenthesis, using %%'s give you the states which was before you entered the said parenthesis. The only thing I knows work well is the math "set /a toto+=1" which will correctly increment the variable. Otherwise you have two options:

所发生的是,在括号内,使用%%'s给出你进入所述括号之前的状态。我知道唯一合适的工作是数学“set / a toto + = 1”,这将正确地增加变量。否则你有两个选择:

Either use a called function to set the variable or use the setlocal ENABLEDELAYEDEXPANSION statement, as previously stated, and use !!'s within the parenthesis.

如前所述,使用被调用函数来设置变量或使用setlocal ENABLEDELAYEDEXPANSION语句,并在括号内使用!!'。