How to store output of .bat FIND in a variable - windows

I'm writing a batch file to find out if certain programs are currently running. Here is my code so far:
for %%x in ("notepad++.exe" "eclipse.exe") do (
tasklist /FI "IMAGENAME eq %%x" | find /I /C %%x
)
What I would like to be able to do is store the result from the "tasklist" line (which should be a number that is greater than or equal to 0) in a variable.
I guess I am really asking: is it possible to capture this output; and, if so, how?

With FOR /F:
for %%x in ("notepad++.exe" "eclipse.exe") do (
for /f %%c in ('tasklist /FI "IMAGENAME eq %%x" ^| find /I /C %%x') do echo %%c
)
Put the command whose output you want to capture inside single quotes and escape any characters with special meaning in the shell, such as the pipe, with the shell escape character ^.
Don't forget to look at FOR /? for additional options when using FOR /F.

Related

How to use tasklist command with an array?

I'm working on a cmd script and want to find some processes in the tasklist. So what I have is an array like "prog[0]=devcpp.exe, prog[1]=notepad.exe..."
And to find these processes I'm using FOR command. Ok, but when I execute the command "tasklist /fi" it seems won't recognize the array, and don't give me the expected result.
The code is:
set prog[0]=devcpp.exe
set prog[1]=notepad.exe
set prog[2]=calc.exe
FOR /l %%a IN (0,1,2) DO (
tasklist /fi "IMAGENAME eq %prog[%%a]%"
)
But the result is:
error: the search filter cannot be recognized
And of course I am running these processes...
So, any suggestions?
First, remove the trailing QUOTATION MARK character on the prog[2] setting.
Secondly, when invoking tasklist, the PERCENT character must be doubled to retain one. And, use the command line interpreter. %ComSpec%, to interpret the variable.
set prog[0]=devcpp.exe
set prog[1]=notepad.exe
set prog[2]=powershell.exe
FOR /l %%a IN (0,1,2) DO (
"%ComSpec%" /C tasklist /fi "IMAGENAME eq %%prog[%%a]%%"
)
You have given no clue as to what the end goal is about. It would likely be easier to code this in PowerShell as #Bill_Stewart suggested.
Here is my suggestion for this task with a commented batch file.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Delete all environment variables of which name starts with prog[.
for /F "delims==" %%I in ('set prog[ 2^>nul') do set "%%I="
rem Define environment variables with the executables to get listed.
set "prog[0]=devcpp.exe"
set "prog[1]=notepad.exe"
set "prog[2]=calc.exe"
rem Run TASKLIST in a loop to get output a list of those processes
rem from the list defined above which are currently running with the
rem header output on English Windows just on first running process.
set "Header=1"
for /F "tokens=1* delims==" %%I in ('set prog[') do if defined Header (
%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq %%J" 2>&1 | %SystemRoot%\System32\findstr.exe /B /I /L /V /C:"INFO:"
if not errorlevel 1 set "Header="
) else (
%SystemRoot%\System32\tasklist.exe /NH /FI "IMAGENAME eq %%J" 2>nul
)
endlocal
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
echo /?
endlocal /?
findstr /?
for /?
if /?
rem /?
set /?
setlocal /?
tasklist /?

BATCH — Store command output to variable

I would like to make a bat script that performs an action only if fewer than 2 occurrences of cmd.exe are running. I managed to find a solution that stores the occurrence count in a temporary file, but I find it very inelegant. So my question is how to do the same as below without a temporary file, but rather by storing the occurence count given by #TASKLIST | FIND /I /C "%_process%" in a variable. I saw that there may be a solution with a for loop, but I couldn’t get it to work and anyway I would really prefer a solution based on SET (if this is possible).
#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
)
Edit: This question is similar to Save output from FIND command to variable, but I wasn’t able to apply the solution to my problem and I wanted to know if a solution without a for loop is possible.
The command FOR with option /F and the command or command line specified as set (string inside parentheses) additionally enclosed by ' can be used for processing the output of a command or a command line with multiple commands on one line.
You can use this batch file:
#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
)
The command FOR runs in background without a visible console window cmd.exe /C with the command line:
C:\Windows\System32\tasklist.exe /FI "IMAGENAME eq cmd.exe" | C:\Windows\System32\find.exe /I /C "cmd.exe"
TASKLIST option /FI "IMAGENAME eq cmd.exe" filters the output of TASKLIST already to processes with image name (= name of executable) cmd.exe. This makes further processing faster and avoids that a running process with file name totalcmd.exe is counted as cmd.exe as the command line in question does.
The output of TASKLIST written to handle STDOUT is redirected to handle STDIN of command FIND which processes the lines and counts the lines containing cmd.exe anywhere in line. FIND outputs finally the number of lines containing searched string to handle STDOUT of command process running in background.
The redirection operator | must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with using a separate command process started in background.
FOR with option /F captures everything written to handle STDOUT of executed command process and processes each line. In this case just one line is captured by FOR containing just a number. Therefore no additional options are needed to assign the number assigned to loop variable I by FOR to environment variable _count using command SET.
The goal of this batch file is counting the number of cmd.exe processes already running. As the command line with TASKLIST and FIND is executed by FOR in background with using one more cmd.exe process, it is necessary to subtract the count by one to get the correct result using an arithmetic expression evaluated with SET /A _count-=1. This decrement by one is needed only for counting right the number of cmd.exe processes. It is not necessary for any other process.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
find /?
for /?
if /?
set /?
tasklist /?
You would do it like this, using TaskList in a For loop:
#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
You can also perform a similar thing using WMIC too:
#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
These could be refined further to ensure processes containing the string as opposed to matching it aren't counted:
#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
Note:If you're really checking the cmd.exe process, be aware that an the command inside the For loop parentheses is spawned within a new cmd.exe instance, (thereby increasing your count by 1)

How to insert multiple commands into a batch file using a batch file

I am making a batch file (Let's call it Create.bat) that will create a batch file (Let's call it Created.bat) that will get multiple commands inserted in it.
One of the commands is as follows:
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %TEST%"') DO IF %%%x == %TEST% goto ProgramON
But when I open Created.bat to edit after running Create.bat, I see the following code inserted:
FOR /F %%x == %TEST% goto ProgramON
Why does it cut out a portion of the code, and how can I fix it?
Some characters have to be escaped. Most of them (&<>|) with a caret (^). Percent signs are escaped with another percent sign:
>>created.bat echo DIR ^>nul
>>created.bat echo FOR /F %%%%x IN ('tasklist /NH /FI "IMAGENAME eq %%TEST%%"') DO IF %%%%x == %%TEST%% goto ProgramON

How to identify IMAGENAME with spaces in a batch file (tasklist)?

Right now, I'm writing a batch file with a line that is identifying if a process is running from my process list.
The line I'm referring to:
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% goto ProcessFound
EXE is defined beforehand as EXE= My Process Here.exe
My batch file works with normal processes, but as you can see with My Process Here.exe, there is a space between My and Process and Here.exe and this is not recognizable.
Is there any way to fix this? The process I am looking for has spaces and I can't change the process name as the program it is related to will not run if I do.
Thanks.
#ECHO OFF
SETLOCAL
SET "exe=7+ Taskbar Tweaker.exe"
FOR /F %%x IN ('tasklist ^|FINDSTR /i /b /L /c:"%EXE%"') DO IF NOT ERRORLEVEL 1 goto ProcessFound1
ECHO "%exe%" not found
GOTO again
:Processfound1
ECHO "%exe%" found!
:again
SET "exe=I dont exist.exe"
FOR /F %%x IN ('tasklist ^|FINDSTR /i /b /L /c:"%EXE%"') DO IF NOT ERRORLEVEL 1 goto ProcessFound1
ECHO "%exe%" not found
GOTO :eof
:Processfound2
ECHO "%exe%" found!
GOTO :EOF
This may work for you. You'd need to fix the process names of course.
#echo off
setlocal enableextensions disabledelayedexpansion
set "exe=My Process Here.exe"
set "processFound="
for /f "tokens=5 delims=," %%a in ('
tasklist /fi "imagename eq %exe%" /fo:csv /nh
') do set "processFound=1"
if defined processFound (
echo %exe% is running
) else (
echo %exe% is NOT running
)
The tasklist will retrieve the list of processes for for the indicated image name and in csv format, without headers.
There are two options: the process is not running and then there are not csv records in the output, or the process is running and there are csv records in the ouptut.
The for command will try to tokenize the output of tasklist and retrieve the 5th token in the line using commas as delimiters.
If the output from tasklist is a csv record, this token will exist, the replaceable parameter will get data and the code in the do clause will be executed. If the output is not a csv record, the token will not exist, and the code in the do clause will not be executed.
Neither of the prior answers worked for me for identifying imagenames with embedded spaces. What did work for me was to use "delims=tab" where tab is the actual tab character as in:
FOR /F "delims=tab" %%X IN ('tasklist /NH /FI "IMAGENAME eq !EXE!"') DO (...
The resulting %%X will either be the entire tasklist entry corresponding to the !EXE! imagename, if found, or "INFO: No tasks are running which match the specified criteria", if not found, that can be acted on by something like:
SET TASKLINE=%%X
IF "!TASKLINE!"=="!TASKLINE:No tasks are running=!" (
ECHO !EXE! FOUND IN !TASKLINE!
) ELSE (
ECHO !EXE! NOT FOUND IN !TASKLINE!))

Pass PIDs from tasklist and kill processes with tasklist

I am trying to get windows processes matching some certain criteria, e.g. they are like "123456.exe" and trying to kill them with tasklist. I am trying to do it like that:
FOR /F "usebackq tokens=2 skip=2" %i IN (`tasklist |findstr /r "[0-9].exe") DO taskkill /PID %i
which is not right and I don't know why.... Can anyone give me a hint?
Thanx in advance!
FOR /F "usebackq tokens=2" %i IN (`tasklist ^| findstr /r /b "[0-9][0-9]*[.]exe"`) DO taskkill /pid %i
Several changes:
The command_to_process needs back quotes (``) on both sides of the command.
Pipes ("|") inside of the command_to_process need to be escaped with a caret ("^").
Your findstr command would match all processes that have a digit before the ".exe". For example, "myapp4.exe" would also have been killed. The version I provide will match process names solely containing numbers.
The "skip=2" option would skip the first two lines output from findstr, not tasklist. Since the regular expression won't match anything in the first two lines output from tasklist, you're safe to remove the skip option.
By the way, if you place this command in a batch script, remember to use "%%i" instead of "%i" for your parameters, or you'll get an error message like i was unexpected at this time.
FOR /F documentation
Findstr documentation
If the processes name difference is not very complex, e.g. if the name is always the same
you can use the /FI option of taskkill directly
taskkill /FI "IMAGENAME eq your_image_name_here.exe"
==> taskkill documentation
I used this in command line:
name variable can contains blank surround with "
SET name="process name you want to kill" && FOR /F "tokens=2,* delims=," %f IN ('TASKLIST /fo csv /v ^| FINDSTR /i /c:!name!') DO #TASKKILL /f /t /pid %f

Resources