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

标签 string batch-file

我最近找到了Find if substring is in string (not in a file)帖子,其中指出

@setlocal enableextensions enabledelayedexpansion
@echo off
set str1=%1
if not x%str1:bcd=%==x%str1% echo It contains bcd
endlocal


然后


等式两侧的x是为了确保字符串bcd可以正常工作。它还可以防止某些“不合适的”起始字符。


但是,我尚未找到有关此x实际效果的任何解释。那么x"%string%""%string%"有什么区别?

最佳答案

那简直是一个非常糟糕的编码字符串比较。两侧的x都可以比较两个字符串,即使Windows命令处理器在执行命令IF之前用空字符串解析整个命令行时也用Windows命令处理器替换了%str1:bcd=%%str1%

但是,由于在环境变量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


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

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

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

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

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

if "test_bcd"" == "" goto EndBatch


错误的指定参数字符串的尾随"不会被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


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

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

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "str1=%~1"
if not "!str1:bcd=!" == "!str1!" echo It contains bcd
endlocal


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

解决方案是:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "str1=%~1"
setlocal EnableDelayedExpansion
if not "!str1:bcd=!" == "!str1!" echo It contains bcd
endlocal
endlocal


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

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


cmd.exe ...解释call /?,不如此处完成。
%~1
echo /?
endlocal /?
goto /?
if /?
set /?


也可以看看:


How does the Windows Command Interpreter (CMD.EXE) parse scripts? ...一个很长的答案,每个批处理文件编写者都应从上至下仔细阅读。
forfiles - FALSE vs. false (doesn't work with lower case?) ...这个答案是关于命令IF的参数处理的。
Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files ...此答案详细说明了命令IF如何完成字符串比较。
Why is no string output with 'echo %var%' after using 'set var = text' on command line? ...此答案说明了为什么应普遍使用setlocal /?而不是其他变体。
Single line with multiple commands using Windows batch file ...说明了双引号参数字符串之外的set "variable=value"&如何由||解释。
Microsoft关于Using command redirection operators的文章介绍了cmd.exe如何解释双引号参数字符串之外的<>|&

关于string - Windows批处理文件中的IF条件下的“…”和x“…”之间有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52414721/

相关文章:

python - 根据标签列表中单词的索引位置查找字符串中单词的开始和结束位置

java - 如何在批处理文件中传递 java -jar 参数?

batch-file - 无法将 "wmic csproduct get vendor/format:list | findstr/c="的输出存储为变量

node.js - 如何在 Windows 和 Unix 上运行 npm sh 脚本

C - 将字符数组与字符串进行比较

C++ 从字符串发送字节?

string - 寻找基于 Lua 的解决方案,将字符串拆分为两个或多个组件

c - 从动态分配的指针数组打印错误

windows - 批处理不会执行,只是重新打印其内容

windows - 如何终止运行时间超过 30 分钟的 Windows 进程