批处理文件 - 如何将 FindStr 与百分比一起使用

Batch file - How to use FindStr with percent

我有一个包含以下内容的批处理文件 header:

@Echo off
SETLOCAL EnableDelayedExpansion EnableExtensions

在括号 () 中的 If 语句中,我有以下代码:

Echo SOME_VAR|FindStr /r /C:"^.*SOME.*$"
Echo Error: !errorlevel!
Echo %%SOME_VAR%%|FindStr /r /C:"^.*SOME.*$"
Echo Error: !errorlevel!

这将打印:

SOME_VAR
Error: 0
Error: 1

如果SOME_VAR是一个现有的环境变量,这就是我得到的。如果我删除变量,我会得到预期的成功。

这里发生了什么?我还需要逃避什么吗?如果变量存在,我怎样才能在第二个上成功找到?我只对搜索文本包含 % 字符并且恰好与现有变量名称匹配的文本搜索感兴趣。

顺便说一句,用于比较的源最终也将是一个变量,我已经在其中加载了从 Windows 注册表中读取的 PATH。所以最终,我要搜索的字符串将变成 /C:"^.%%SOME_VAR%%;.*$"

我的 PATH 变量如下所示:

%SOME_VAR%;C:\Windows\system32...................etc

是的,还需要另一层转义,因为管道的每一侧都是通过 CMD /C 使用命令行上下文而不是批处理上下文执行的。初始批解析器将 %%SOME_VAR%% 转换为 %SOME_VAR%。如果变量未定义,命令行解析器将保持 %SOME_VAR% 不变。如果定义了变量,我们需要防止扩展。将百分比加倍在命令行上下文中不起作用。解决方案是在百分比之间的某处插入一个消失的插入符号,例如 %^SOME_VAR%。插入符号被视为变量名称的一部分,因此它可以防止变量扩展(除非您有一个名为 ^SOME_VAR 的变量)。扩展失败后,插入符被正常的转义过程消耗掉。必须转义插入符号,以便批处理解析器将插入符号传递给 CMD /C 命令行上下文。

最终批处理行变为:

Echo %%^^SOME_VAR%% | FindStr SOME_VAR

注意:我将 FINDSTR 命令简化为更简单但等效的搜索。

当您修改右侧的搜索以包括百分比时,您还需要插入转义插入符号。

更新以回应评论中的问题
以下代码演示了一些使用变量的可能方法:

@echo off
setlocal disableDelayedExpansion

:: Put both the text you want to search, as well as the search itself, in variables
set "text=%%SOME_VAR%%;C:\Windows\system32...................etc"
set "search=%%SOME_VAR%%"
echo text=%text%
echo search=%search%
echo(

echo(
echo Starting with delayed expansion disabled
echo -----------------------------------------
echo(

:: Use delayed expansion to safely expand any variable without worrying about content.
:: Both sides of the pipe are executed in a command line context with delayed expansion disabled.
:: You must use CMD /V:ON to enable delayed expansion within the pipe.

echo Test when SOME_VAR is undefined:
set "SOME_VAR="
if 1==1 (
  cmd /v:on /c echo !text!|cmd /v:on /c findstr "!search!"
)
echo(

echo Test when SOME_VAR is defined:
set "SOME_VAR=DEFINED"
if 1==1 (
  cmd /v:on /c echo !text!|cmd /v:on /c findstr "!search!"
)
echo(


setlocal enableDelayedExpansion
echo(
echo(
echo Now try with delayed expansion enabled
echo -----------------------------------------
echo(

:: Even though delayed expansion is enabled within the batch script, it is still disabled
:: within the pipe, so we still have to explicitly enable it via CMD /V:ON.
:: But now we must prevent expansion of the variables while in the batch context.
:: You have two options:

:: 1) Escape the !. The escape syntax changes depending on whether it is inside quotes or not:
echo Escape test:
if 1==1 (
  cmd /v:on /c echo ^^!text^^!|cmd /v:on /c findstr "^!search^!"
)
echo(

:: 2) Enclose both sides of the pipe within parentheses (very weird, but it works)
echo Parentheses test:
if 1==1 (
  (cmd /v:on /c echo !text!)|(cmd /v:on /c findstr "!search!")
)

--输出--

text=%SOME_VAR%;C:\Windows\system32...................etc
search=%SOME_VAR%


Starting with delayed expansion disabled
-----------------------------------------

Test when SOME_VAR is undefined:
%SOME_VAR%;C:\Windows\system32...................etc

Test when SOME_VAR is defined:
%SOME_VAR%;C:\Windows\system32...................etc



Now try with delayed expansion enabled
-----------------------------------------

Escape test:
%SOME_VAR%;C:\Windows\system32...................etc

Parentheses test:
%SOME_VAR%;C:\Windows\system32...................etc