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

时间:2018-05-05 13:47:40

标签: windows batch-file cmd

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

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

编辑:此问题类似于Save output from FIND command to variable,但我无法将解决方案应用于我的问题,我想知道是否可以使用没有for循环的解决方案。

2 个答案:

答案 0 :(得分:3)

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

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

@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
)

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

C:\Windows\System32\tasklist.exe /FI "IMAGENAME eq cmd.exe" | C:\Windows\System32\find.exe /I /C "cmd.exe"

TASKLIST 选项/FI "IMAGENAME eq cmd.exe"已将 TASKLIST 的输出过滤为具有图片名称(=可执行文件名称)cmd.exe的进程。这样可以更快地进行进一步处理,并避免将文件名为totalcmd.exe的正在运行的进程计为cmd.exe,与所涉及的命令行一样。

为处理 STDOUT 而编写的 TASKLIST 输出被重定向到处理命令 FIND STDIN 处理行和任意位置包含cmd.exe的行。 FIND 最后输出包含搜索字符串的行数,以处理在后台运行的命令进程的 STDOUT

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

带有选项/F

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

此批处理文件的目标是计算已运行的cmd.exe进程数。由于 TASKLIST FIND 的命令行在背景中由 FOR 执行并再使用一个cmd.exe进程,因此有必要使用SET /A _count-=1计算的算术表达式将计数减1以获得正确的结果。只需计算cmd.exe个进程的数量,就需要减1。没有必要进行任何其他过程。

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

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

答案 1 :(得分:3)

你会这样做,在TaskList循环中使用For

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

您也可以使用WMIC执行类似的操作:

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

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

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

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

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