BATCH — 将命令输出存储到变量

nic*_*ico 5 windows cmd batch-file

我想制作一个 bat 脚本,仅当运行的 cmd.exe 出现次数少于 2 次时才执行操作。我设法找到一个将出现次数存储在临时文件中的解决方案,但我发现它非常不优雅。所以我的问题是如何在没有临时文件的情况下执行与下面相同的操作,而是通过将给出的出现次数存储@TASKLIST | FIND /I /C "%_process%"在变量中。我看到可能有一个带有 for 循环的解决方案,但我无法 \xe2\x80\x99t 让它工作,无论如何我真的更喜欢基于SET(如果可能的话)的解决方案。

\n\n
@SET _process=cmd.exe\n@SET _temp_file=tempfiletodelete.txt\n@TASKLIST | FIND /I /C "%_process%" > %_temp_file%\n@SET /p _count=<%_temp_file%\n@DEL /f %_temp_file%\n@IF %_count% LSS 2 (\n    @ECHO action 1\n) ELSE (\n    @ECHO action 2\n)\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑:这个问题类似于将FIND 命令的输出保存到变量,但我\xe2\x80\x99t 无法将解决方案应用于我的问题,我想知道是否可以使用没有 for 循环的解决方案。

\n

Mof*_*ofi 6

带有选项的命令FOR以及指定为set(括号内的字符串)/F的命令或命令行另外括起来,可用于处理一个命令或一行上有多个命令的命令行的输出。'

您可以使用此批处理文件:

@ECHO OFF
SET "_process=cmd.exe"
FOR /F %%I IN ('%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq %_process%" ^| %SystemRoot%\System32\find.exe /I /C "%_process%"') DO SET "_count=%%I"
IF /I "%_process%" == "cmd.exe" SET /A _count-=1
IF %_count% LSS 2 (
    ECHO action 1
) ELSE (
    ECHO action 2
)
Run Code Online (Sandbox Code Playgroud)

命令FOR在后台运行,没有cmd.exe /C带有命令行的可见控制台窗口:

C:\Windows\System32\tasklist.exe /FI "IMAGENAME eq cmd.exe" | C:\Windows\System32\find.exe /I /C "cmd.exe"
Run Code Online (Sandbox Code Playgroud)

TASKLIST选项已将TASKLIST/FI "IMAGENAME eq cmd.exe"的输出过滤到具有映像名称(= 可执行文件的名称)的进程。这使得进一步处理速度更快,并避免将带有文件名的正在运行的进程计为有问题的命令行。cmd.exetotalcmd.execmd.exe

写入处理STDOUT的TASKLIST输出被重定向到处理命令FINDSTDIN,该命令处理行并计算包含行中任何位置的行。FIND最终输出包含搜索字符串的行数,以处理后台运行的命令进程的STDOUT 。cmd.exe

当 Windows 命令解释器在执行命令FOR之前处理此命令行时,|重定向运算符必须^FOR命令行上使用脱字符号进行转义,以便将其解释为文字字符,该命令使用在后台启动的单独命令进程来执行嵌入的命令行。

带选项的FOR/F捕获为处理已执行命令进程的STDOUT而编写的所有内容并处理每一行。在这种情况下, FOR只捕获一行,其中仅包含一个数字。因此,不需要额外的选项来使用命令SET将FORI分配给循环变量的编号分配给环境变量。_count

该批处理文件的目标是计算cmd.exe已运行的进程数。由于TASKLISTFIND命令行是由FOR在后台执行的,多了一个cmd.exe进程,因此需要使用 计算的算术表达式将计数减一才能得到正确的结果SET /A _count-=1。仅在正确计算进程数时才需要减一cmd.exe。对于任何其他过程来说都不需要。

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

  • echo /?
  • find /?
  • for /?
  • if /?
  • set /?
  • tasklist /?


Com*_*mpo 5

你可以像这样,在循环TaskList中使用For

\n\n
@Set "_process=cmd.exe"\n@For /F %%A In (\'TaskList^|Find /C /I "%_process%"\'\n) Do @If %%A Lss 2 (Echo Action 1) Else Echo Action 2\n@Pause\n
Run Code Online (Sandbox Code Playgroud)\n\n

您还可以使用以下命令执行类似的操作WMIC

\n\n
@Set "_process=cmd.exe"\n@For /F %%A In (\'WMIC Process Get Name^|Find /C "%_process%"\'\n) Do @If %%A Lss 2 (Echo Action 1) Else Echo Action 2\n@Pause\n
Run Code Online (Sandbox Code Playgroud)\n\n

这些可以进一步细化,以确保包含该字符串而不是匹配该字符串的进程不被计算在内:

\n\n
@Set "_process=cmd.exe"\n@For /F %%A In (\'TaskList /FI "ImageName Eq "%_Process%""^|Find /C "."\'\n) Do @If %%A Lss 2 (Echo Action 1) Else Echo Action 2\n@Pause\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xc2\xa0

\n\n
@Set "_process=cmd.exe"\n@For /F %%A In (\n    \'WMIC Process Where "Name=\'%_process%\'" Get Name^|Find /C "."\'\n) Do @If %%A Lss 2 (Echo Action 1) Else Echo Action 2\n@Pause\n
Run Code Online (Sandbox Code Playgroud)\n\n

注意
如果您确实在检查cmd.exe进程,请注意循环括号内的命令For是在新cmd.exe实例中生成的(从而使您的计数增加1

\n