批处理文件:查找子字符串是否在字符串中(不在文件中)

272
在批处理文件中,我有一个字符串abcdefg。 我想检查字符串中是否存在bcd
不幸的是,似乎我找到的所有解决方案都是在文件中搜索子字符串,而不是在字符串中搜索子字符串。
是否有简便的方法来解决这个问题?

7
顺便说一下,通常是使用“Windows”和“cmd”,或者使用“ms-dos”。很长一段时间以来,MSDOS不再是Windows的一部分。 - paxdiablo
13个回答

352

是的,您可以使用替换并检查原始字符串:

if not x%str1:bcd=%==x%str1% echo It contains bcd

%str1:bcd=% 位将把 str1 中的一个 bcd 替换为空字符串,这将使其与原始字符串不同。

如果原始字符串中不包含 bcd 字符串,则修改后的版本将与原始版本相同。

使用以下脚本进行测试,可以看到它的效果:

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

各次运行的结果如下:

c:\testarea> testprog hello

c:\testarea> testprog abcdef
It contains bcd

c:\testarea> testprog bcd
It contains bcd

几个注意事项:

  • if语句是这个解决方案的核心,其他都是支持性质的东西。
  • 等式两边加上x是为了确保字符串bcd能够正常工作。它还可以防止某些“不当”的起始字符。

9
如果你想在 FOR 循环中进行字符串替换,可以参考这个链接:https://dev59.com/80XRa4cB1Zd3GeqPtaf3#6310580。 - Czarek Tomczak
80
这很不错,但是当搜索值不是一个常量(比如bcd)而是一个变量时,我很难让它工作。经过很长时间的尝试,我最终找到了解决方法。假设搜索值已被声明为searchVal,“x!str1:%searchVal%=!”==“x%str1%”。 - Gary Brunton
10
@Gary,由于这个问题不需要那个要求,你可能应该提出另一个问题,可能会链接回这个问题作为参考。有很多人愿意帮忙。事实上,既然你已经弄清楚了,你仍然应该提出那个问题并自己回答它,以便将来搜索者可以受益。自我回答被认为是可以接受的。 - paxdiablo
16
很好的解决方案,但你需要用双引号将其括起来,否则对于变量的值中带有空格的情况它不会起作用,例如:如果不是 "x%str1:bcd=%" == "x%str1%" 就输出 It contains bcd。 - Helge Klein
6
“在此时,'=str1' 是意外的。” - Berit Larsen
显示剩余21条评论

120

您可以将源字符串导入到findstr并检查ERRORLEVEL的值,以查看是否找到了模式字符串。值为零表示成功并且已找到模式。以下是一个示例:

::
: Y.CMD - Test if pattern in string
: P1 - the pattern
: P2 - the string to check
::
@echo off

echo.%2 | findstr /C:"%1" 1>nul

if errorlevel 1 (
  echo. got one - pattern not found
) ELSE (
  echo. got zero - found pattern
)

当在CMD.EXE中运行时,我们会得到:

C:\DemoDev>y pqrs "abc def pqr 123"
 got one - pattern not found

C:\DemoDev>y pqr "abc def pqr 123" 
 got zero - found pattern

FINDSTR:/C 后缺少参数。已有一个 - 未找到匹配项。 - Berit Larsen
我能够轻松地在for循环中使其工作。但是,我无法将被接受的答案改为for循环(尽管我没有花太多精力去看为什么它不起作用)。 - Ben Jasperson
这个解决方案非常易读。我建议查看这个答案以了解其中的一些陷阱。 - ASB
注意!在某些情况下,findstr命令无法正常工作,例如,echo c:\_ | findstr /C:"\_"会返回匹配结果,但echo c:\_ | findstr /C:":\_"无法找到匹配结果,同样echo c:\_ | findstr /C:"c:\_"也无法找到匹配结果。解决方法是使用find命令代替findstr命令。 - undefined

62

我通常会做这样的事情:

Echo.%1 | findstr /C:"%2">nul && (
    REM TRUE
) || (
    REM FALSE
)

例子:

Echo.Hello world | findstr /C:"world">nul && (
    Echo.TRUE
) || (
    Echo.FALSE
)

Echo.Hello world | findstr /C:"World">nul && (Echo.TRUE) || (Echo.FALSE)

输出:

TRUE
FALSE

我不确定这是否是最佳方法。


我需要递归查找和比较文件名。这也是唯一对我起作用的解决方案!非常方便和简单。 - SirJames

35

为了兼容性和易用性,通常最好使用FIND来完成这项任务。

您还必须考虑是否要区分大小写。

78点方法(我相信我指的是paxdiablo的帖子)只会区分大小写,因此您必须为每个可能需要匹配的迭代放置单独的检查以进行每种情况的变化。

(真是太痛苦了!仅有3个字母就意味着需要进行9种不同的测试才能完成检查!)

此外,许多时候最好匹配命令输出、循环中的变量或批处理/CMD中指针变量的值,这并不那么直接。

出于这些原因,这是一种更可取的替代方法:

使用:Find [/I] [/V] “要匹配的字符”

[/I](不区分大小写) [/V](不包含该字符)

作为单行:

ECHO.%Variable% | FIND /I "ABC">Nul && ( Echo.Found "ABC" ) || ( Echo.Did not find "ABC" )

多行:

ECHO.%Variable%| FIND /I "ABC">Nul && ( 
  Echo.Found "ABC"
) || (
  Echo.Did not find "ABC"
)

正如提到的,这对于那些不在允许字符串替换的变量中的内容非常适用:

FOR %A IN (
  "Some long string with Spaces does not contain the expected string"
  oihu AljB
  lojkAbCk
  Something_Else
 "Going to evaluate this entire string for ABC as well!"
) DO (
  ECHO.%~A| FIND /I "ABC">Nul && (
    Echo.Found "ABC" in "%A"
  ) || ( Echo.Did not find "ABC" )
)

Output From a command:

    NLTest | FIND /I "ABC">Nul && ( Echo.Found "ABC" ) || ( Echo.Did not find "ABC" )

As you can see this is the superior way to handle the check for multiple reasons.

针对大小写敏感问题,您可以使用 setlocal EnableExtensions 然后使用 IF /I 进行大小写不敏感的比较。 - cychoi
1
这并不是一个可行的选项,因为您仍然需要隔离字符进行“IF”比较。 IF在“Like”术语中不匹配,因为OP和我回复的特定解决方案正在寻找这种匹配。 - Ben Personick
3
嗨,本,请不要根据其他回答的得分来引用它们。那���可能会改变。请更新你的答案,通过那个答案的作者名字或一个描述那个答案中使用的技术的简短短语来引用其他的答案。 - phonetagger
嗨,Phone Tagger,如果你在三年前我写原始帖子时留下这个有用的评论,那会很有帮助。但是正如你所提到的,现在所有的点数价值都已经改变了。我不再记得我当时是在参考哪篇帖子,而且今天我也不会根据点数价值来引用它们。无论如何,还是谢谢你。 - Ben Personick
我四处查看,我相信我是在提到paxdiablo,所以我已经修改了文本以显示这一点。 - Ben Personick

12

如果您正在检测是否存在,这里是最简单的解决方案:

SET STRING=F00BAH
SET SUBSTRING=F00
ECHO %STRING% | FINDSTR /C:"%SUBSTRING%" >nul & IF ERRORLEVEL 1 (ECHO CASE TRUE) else (ECHO CASE FALSE)

这对于将Windows命令的输出放入布尔变量非常有效。只需用您想要运行的命令替换echo即可。您还可以使用管道串联Findstr以进一步限定语句。例如,适用于服务控制(SC.exe)。

SC QUERY WUAUSERV | findstr /C:"STATE" | FINDSTR /C:"RUNNING" & IF ERRORLEVEL 1 (ECHO case True) else (ECHO CASE FALSE)

该命令用于评估Windows更新服务的SC查询输出,它以多行文本形式呈现,找到包含“state”字样的行,然后查看该行中是否包含“running”单词,并相应地设置错误级别。


8
你的 IF 语句反了。看着原始代码中的 abcdefg,你把逻辑搞反了。这样是可以工作的,但按照你的方式则不行。SET STRING=abcdefgh SET SUBSTRING=bcd ECHO %STRING% | FINDSTR /C:"%SUBSTRING%" >nul & IF ERRORLEVEL 1 (ECHO CASE FALSE) else (ECHO CASE TRUE) - Leptonator
2
即便 @Leptonator 使用了反转逻辑且正确,A+1 也是应该的。这是一个简单易用的解决方案。 - András Aszódi

8

在变量中查找文本,例如:

var_text="demo string test"
Echo.%var_text% | findstr /C:"test">nul && (
    echo "found test" 
    ) || Echo.%var_text% | findstr /C:"String">nul && (
             echo "found String with S uppercase letter" 
    ) || (
             echo "Not Found " 
    )

图例:

  1. & 执行"execute_that"和"execute_this"
  2. || 如果"execute_that"执行失败,则执行"execute_this"
  3. && 如果"execute_that"执行成功,则执行"execute_this"
  4. >nul 不在命令行中显示结果
  5. findstr
  6. /C: 把字符串作为字面搜索字符串使用

你能否在回答中加入一些背景信息? - Unbranded Manchester

6

我可能来得有点晚,但是接受的答案只适用于检查“硬编码字符串”是否是搜索字符串的一部分。

对于动态搜索,您需要执行以下操作:

SET searchString=abcd1234
SET key=cd123

CALL SET keyRemoved=%%searchString:%key%=%%

IF NOT "x%keyRemoved%"=="x%searchString%" (
    ECHO Contains.
)

注意:您可以将这两个变量作为参数。

6

对我而言最好的方法是这样的:

call :findInString "HelloWorld" "World"

:findInString
ECHO.%1 | FIND /I %2>Nul && ( 
  Echo.Found
) || (
  Echo.Not found
)

2
ECHO %String%| FINDSTR /C:"%Substring%" && (Instructions)

1
搜索文件中的子字符串的解决方案也可以用于搜索字符串,例如findfindstr
在您的情况下,简单的解决方案是将一个字符串传递到命令中,而不是提供文件名,例如:
区分大小写的字符串:
echo "abcdefg" | find "bcd" 忽略字符串大小写:
echo "abcdefg" | find /I "bcd" 如果没有找到匹配项,则CMD会返回一个空行响应,%ERRORLEVEL%设置为1。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接