Windows批处理文件中的IF条件下的“ ...”和x“ ...”之间有什么区别?

Tsa*_*gua 3 string batch-file

我最近在文章“ 查找子字符串是否在字符串中(而不是在文件中)”中发现

@setlocal enableextensions enabledelayedexpansion
@echo off
set str1=%1
if not x%str1:bcd=%==x%str1% echo It contains bcd
endlocal
Run Code Online (Sandbox Code Playgroud)

然后

x平等的双方之前是要确保字符串bcd工作好。它还可以防止某些“不合适的”起始字符。

但是,我还没有找到关于this实际效果的任何解释x。那么x"%string%"和之间有什么区别"%string%"

Mof*_*ofi 6

那简直是一个非常糟糕的编码字符串比较。的x两侧使得能够即使两个字符串比较%str1:bcd=%%str1%通过Windows命令处理器上取代命令的执行之前通过一个空字符串解析整个命令行IF

但是cmd.exe,如果环境变量的值str1包含空格或,则会由于语法错误而立即退出批处理文件的执行"&<>|

将参数字符串括在双引号中会导致获得除百分号以外的所有字符,并且启用了延迟的环境变量扩展,还会将感叹号解释为文字字符,包括在双引号字符串之外的空格,该空格被解释为参数字符串分隔符。

更好的是:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
if "%~1" == "" goto EndBatch
set "str1=%~1"
if not "%str1:bcd=%" == "%str1%" echo It contains bcd
:EndBatch
endlocal
Run Code Online (Sandbox Code Playgroud)

首先比较批处理文件的第一个参数,而不用双引号引起来的空字符串。因此,如果启动的批处理文件没有任何自变量,或者仅""具有第一个自变量字符串,则Windows命令处理器将执行命令GOTO,以恢复使用SETLOCAL命令压入堆栈的先前环境,并退出该批处理文件。

否则,批处理文件实际上是使用参数字符串调用的。将此参数字符串分配给环境变量,str1并删除周围的双引号(如果有的话)。因此,在使用参数调用批处理文件时,test将值test分配给环境变量,str1并在使用不带双引号"another test"的值调用它时将another test其分配给str1。即使在使用错误的编码参数字符串"bcd test(缺少第二个")调用批处理文件时,也只是bcd test将其分配给环境变量str1

IF条件比较环境变量的值str1与所有出现bcd与未修饰的可变值中移除。即使在包含空格或与号或重定向运算符的情况下,两个字符串周围的双引号也可以比较两个字符串<>|。命令IF在比较两个字符串时包括双引号。

那么这段代码现在安全吗?

不,不是有人将批处理文件test_bcd"称为带有第一个双引号的参数字符串无效的情况。在这种情况下,执行的第一个IF命令行为cmd.exe

if "test_bcd"" == "" goto EndBatch
Run Code Online (Sandbox Code Playgroud)

"错误的指定参数字符串的尾部不会被删除,cmd.exe并在执行时在此命令行上引起语法错误,因为可以在命令提示符窗口中运行批处理文件并将其第一行修改为时看到该错误@echo on

不使用延迟的环境变量扩展的一种解决方案是:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "str1=%~1"
if not defined str1 goto EndBatch
set "str1=%str1:"=%"
if not defined str1 goto EndBatch
if not "%str1:bcd=%" == "%str1%" echo It contains bcd
:EndBatch
endlocal
Run Code Online (Sandbox Code Playgroud)

这段代码确保str1在执行IF命令比较字符串之前不包含任何双引号。

另一个解决方案是使用延迟的环境变量扩展:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "str1=%~1"
if not "!str1:bcd=!" == "!str1!" echo It contains bcd
endlocal
Run Code Online (Sandbox Code Playgroud)

在不使用延迟的环境变量扩展的情况下,上述代码看起来更好。但是,如果参数字符串是例如,它将无法按预期方式工作,"!Hello!"因为在这种情况下,if not条件也为true,因此It contains bcd尽管字符串!Hello!不包含,但输出还是消息bcd

解决方案是:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "str1=%~1"
setlocal EnableDelayedExpansion
if not "!str1:bcd=!" == "!str1!" echo It contains bcd
endlocal
endlocal
Run Code Online (Sandbox Code Playgroud)

在将参数字符串分配给环境变量时str1,未启用延迟扩展,这会导致将字符串中的感叹号"!Hello!"解释为文字字符。然后使用延迟的环境变量扩展来启用延迟扩展以进行字符串比较,从而避免了cmd.exe在执行IF命令之前修改命令行本身。

为了了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • call /?...解释%~1,不如这里做的好。
  • echo /?
  • endlocal /?
  • goto /?
  • if /?
  • set /?
  • setlocal /?

也可以看看:


DYZ*_*DYZ 5

x在字符串前面添加(或任何其他字母字符)可确保关系语句在语法上有效,即使当/如果字符串为空。

假设str1是一个空字符串。然后%str1:bcd=%==%str1%替换后的比较退化为==,这在语法上是无效的。

但是,x在前面,比较成为x==x并且可以评估。自然地,为两个字符串中的每一个添加相同的前缀不会影响它们的(不)相等性。

  • 不,它没有(但责怪原来的帖子!)。为此,一对双引号就足够了。 (2认同)

归档时间:

查看次数:

1278 次

最近记录:

5 年,12 月 前