escaping characters in batch using ^ - batch-file

I can get a proper output wuth the below command in the command prompt,
tasklist /fi "imagename ne siebde*" /fi "imagename eq sieb*" /svc | find "gtwyns".
But if i want to use this condition in batch files i have to do this with the below command.
for /f "tokens=2 delims= " %%a in ('tasklist /fi "imagename ne siebde*" /fi "imagename eq sieb*" /svc ^| find "gtwyns")
I need to understand the function of ^ character and how does it work actually?
I also wanna know does it open a new cmd when wi use a pipe in batch script?

Read FOR /F: loop command against the results of another command syntax:
FOR /F ["options"] %%parameter IN ('command_to_process') DO command
…
command_to_process : The output of the 'command_to_process' is passed
into the FOR parameter.
… The command_to_process can be almost any internal or external
command.
Almost any internal or external command (but the only command).
Now, read redirection syntax:
commandA | commandB Pipe the output from commandA into
commandB
For instance, in wrong for /F "delims=" %%a in ('dir /B | sort /R') do echo %%~awith unescaped | pipe:
commandA evaluates to for /F "delims=" %%a in ('dir /B and
commandB evaluates to sort /R') do echo %%~a although separate dir /B | sort /R is right command.
Hence, we need to escape (all) &, |, <, > redirection characters and (sometimes) " double quotes as follows (both ways are equivalent parsing dir /B "*.vbs" 2>NUL | sort /R command):
for /F "delims=" %%a in (' dir /B "*.vbs" 2^>NUL ^| sort /R ') do echo %%~a
for /F "delims=" %%a in ('"dir /B ""*.vbs"" 2>NUL | sort /R"') do echo %%~a
Therefore, next two loops should work the same way:
for /f "tokens=2 delims= " %%a in ('
tasklist /fi "imagename ne siebde*" /fi "imagename eq sieb*" /svc ^| find "gtwyns"
') do echo set pid_ns=%%a
and
for /f "tokens=2 delims= " %%a in ('
"tasklist /fi ""imagename ne siebde*"" /fi ""imagename eq sieb*"" /svc | find ""gtwyns"""
') do echo set pid_ns=%%a

Related

Is there a way to do this less time consuling within one check?

I have this batch code and its working perfectly well, BUT:
every line take ~60 seconds to execute and I'm wondering, if I could do this faster...
Also the if Statements.. I want to check, if every Window is closed, and if so, I want to execute something. But if at least one window is still open, then it should check it again.
:loop
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server1%" /FO Table') do set #1=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server2%" /FO Table') do set #2=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server3%" /FO Table') do set #3=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server4%" /FO Table') do set #4=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server5%" /FO Table') do set #5=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server6%" /FO Table') do set #6=%%i
if not %#1%==cmd.exe (
if not %#2%==cmd.exe (
if not %#3%==cmd.exe (
if not %#4%==cmd.exe (
if not %#5%==cmd.exe (
if not %#6%==cmd.exe (
goto backup
)
)
)
)
)
) else (
echo back to loop
goto openWindow
)
Let me suggest a slightly different approach. Instead of all those if statements, you can just loop whenever one of the tasks exist:
:wait
timeout 1 >nul
for %%a in (%server1% %server2% %server3% %server4% %server5% %server6%) do (
tasklist /nh /fi "windowtitle eq %%a" |find " " >nul && goto :wait
)
echo all closed.
or
setlocal enabledelayedexpansion
:wait
timeout 1 >nul
for /l %%a in (1,1,6) do (
tasklist /nh /fi "windowtitle eq !server%%a!" |find " " >nul && goto :wait
)
echo all closed.
Note: find " " looks for two consecutive spaces, not a TAB)
If you choose your window titles wisely, you don't even need a for loop:
:wait
timeout 1 >nul
tasklist /nh /fi "windowtitle eq MySubWindow*" |find " " >nul && goto :wait
echo all closed.
where the window titles all start with a fixed string (MySubWindow here), like MySubWindow-1, MySubWindow-2 etc. (yes, tasklist is able to use a wildcard - but only at the end of the string). This is basically "if any window exists with a title that starts with MySubWindow then loop"
little optimization of Stephan answer.
This execute faster.
:wait
timeout 1 >nul
for %%a in (%server1% %server2% %server3% %server4% %server5% %server6%) do (
if not defined v%%a tasklist /nh /fi "windowtitle eq %%a" |find " " >nul && goto :wait
set v%%a=done
)
echo all closed.
You have not explained how your 6 Batch files are "open", but if they are open via START command, then there is a much simpler way to do the same:
(
start call batch1.bat
start call batch2.bat
start call batch3.bat
start call batch4.bat
start call batch5.bat
start call batch6.bat
) | pause
echo All 6 Batch files are closed
The previous code run the 6 Batch files in parallel and then the control flow is stopped at the pause command. When all the 6 Batch files terminates, this program continue.
Note that there is not any Batch code that check if the procesess ends; this is done automatically by the Operating System. In this way, the wait state of this program does not waste any CPU time. For a further explanation, see this answer
Without being able to test this, perhaps it would be quicker to run just one tasklist command per loop:
#Echo Off
SetLocal EnableExtensions
:Loop
For /F Tokens^=17^ Delims^=^" %%G In (
'%SystemRoot%\System32\tasklist.exe /Fi "ImageName Eq cmd.exe" /Fo CSV /NH /V 2^>NUL'
) Do Set /P "=%%G" 0<NUL | %SystemRoot%\System32\findstr.exe /I ^
"\<%server1%\> \<%server2%\> \<%server3%\> \<%server4%\> \<%server5%\> \<%server6%\>" 1>NUL && GoTo Loop
:Backup
The findstr.exe options may need to be adjusted depending upon the content of those variables.

Wildcard in taskkill windowtitle

When I want to close the following two (fictional...) applications using taskkill...
...I would use taskkill /FI "WINDOWTITLE eq Hello*".
But how about these two:
taskkill /FI "WINDOWTITLE eq * wine" gives me FEHLER: Der Suchfilter wurde nicht erkannt., which can be translated as ERROR: The search filter could not be recognized.
So, how can I filter with a wildcard at the beginning?
The wildcard at the beginning does not work. You would need to incorporate findstr using a bit of initiative.
for /f "tokens=2 delims=," %%a in ('tasklist /fi "imagename eq notepad.exe" /v /fo:csv /nh ^| findstr /r "wine"') do taskkill /pid %%a
So we search for imagenames with wine in the name. Use /fo to csv format, /nh for no header, then search for the string "wine" in imagename, then kill by process ID if found.
To not be imagename specific do:
for /f "tokens=2 delims=," %%a in ('tasklist /v /fo:csv /nh ^| findstr /r "wine"') do taskkill /pid %%a
Edit
As for the concern in killing incorrect tasks:
#echo off
set "images=notepad.exe,calc.exe,winword.exe,excel.exe"
for %%i in (%images%) do (
for /f "tokens=2 delims=," %%a in ('tasklist /fi "imagename eq %%i" /v /fo:csv /nh ^| findstr /r "wine"') do taskkill /pid %%a
)
Just add a list of possible image names that would contain the title, it will only loop these as per below and not touch the other processes/tasks:
tasklist /fi "imagename eq notepad.exe"
tasklist /fi "imagename eq calc.exe"
tasklist /fi "imagename eq winword.exe"
tasklist /fi "imagename eq excel.exe"

Batch file that identifies if a named window is open, and then closes it

I have been using the following script to check if a particular named window is open.
I got it from this thread:-
How do you test if a window (by title) is already open from the command prompt?
ideally I will expand the else part to close the window if it is found to be open.
#For /f "Delims=:" %A in ('tasklist /v /fi "WINDOWTITLE eq test.bat - Notepad"') do #if %A==INFO (echo Prog not running) else SET "BREX=Awesome" &echo %BREX%
Unfortunately when I run this script it returns three instances of my else string?
Is there any way to reduce this down to returning one instance?
You could use findstr instead. You're getting multiple lines of output as you're looping over each line of output
tasklist /v /fi "WINDOWTITLE eq test.bat - Notepad" | findstr /C:"No tasks are running"
if %errorlevel% NEQ 0 (
echo awesome
) else (
echo Prog not running
)
If you really want to do this with one line from the cmd prompt you can do this.
cmd /v:on /c "#For /f "Delims=:" %A in ('tasklist /v /nh /fi "WINDOWTITLE eq test.bat - Notepad"') do #if %A==INFO (echo Prog not running) else (SET "BREX=Awesome") &echo !BREX!"
Or use some conditional execution.
tasklist /v /nh /fi "WINDOWTITLE eq test.bat - Notepad" |findstr /B /C:"INFO: No tasks are running">nul && (echo Program not running) || (echo Awesome)

Missing operator error using batch file

I've been trying to create a little batchscript to get the usages of your browser. So far so good everything works, it does what it should. Then I moved the file to another pc and now I'm getting "Missing Operator" errors eventho the program runs like it should. Any idea's?
#echo off
set date = %date
set time = %time
set sum=0
for /f "tokens=5 delims=," %%x in ('tasklist /fo csv /fi "imagename eq firefox.exe"') do (
for /f "tokens=1-5 delims=.K " %%a in ("%%~x") do set /a sum+=%%a%%b%%c%%d
)
echo %date%, %time%, firefox.exe, %sum%K > FirefoxDumpResult.csv
pause
:start
set date = %date
set time = %time
set sum=0
for /f "tokens=5 delims=," %%x in ('tasklist /fo csv /fi "imagename eq firefox.exe"') do (
for /f "tokens=1-5 delims=.K " %%a in ("%%~x") do set /a sum+=%%a%%b%%c%%d
)
echo %date%, %time%, firefox.exe, %sum%K >> FirefoxDumpResult.csv
set choice=
set /p choice="Do you want to log another one? Press 'y' and enter for Yes: "
if not '%choice%'=='' set choice=%choice:~0,1%
if '%choice%'=='y' goto start
You have not placed the closing percent characters on your %DATE% and %TIME% variables.
Additionally you shouldn't be creating variables which already exist and which don't need setting anyhow.
You have also pointlessly repeated a section of your code.
Finally you have not used the simpler code I provided for you in an earlier reply to another similar question using chrome.exe.
Try this:
#Echo Off
If /I Not "%CD%\" Equ "%~dp0" CD /D %~dp0
>FirefoxDumpResult.csv Type Nul
:Start
Set "_sum=0"
For /F "Tokens=6-7 Delims=., " %%a In (
'TaskList /NH /FI "ImageName Eq firefox.exe"') Do Set/A _sum+=%%a%%b
Echo=%DATE%, %TIME%, firefox.exe, %_sum%K>>FirefoxDumpResult.csv
Echo=
Echo=Firefox process information logged
Echo=
Choice /M "Do you want to log another one?"
If ErrorLevel 2 Exit/B
GoTo :Start
These are the outputs from both your and my versions:
::-------------------------------- Akorna Output -------------------------------
Type Nul 1>FirefoxDumpResult.csv
Set _sum=0
For /F "Tokens=6-7 Delims=., " %a In ('TaskList /NH /FI "ImageName Eq firefox.exe"') Do Set/A "_sum+=%a%b"
Set/A "_sum+=414 032K" Missing operator.
Echo=wo 07/09/2016, 16:39:43,48, firefox.exe, 414K 1>>FirefoxDumpResult.csv
::------------------------------------------------------------------------------
::-------------------------------- Compo Output --------------------------------
Type Nul 1>FirefoxDumpResult.csv
Set "_sum=0"
For /F "Tokens=6-7 Delims=., " %a In ('TaskList /NH /FI "ImageName Eq firefox.exe"') Do Set/A _sum+=%a%b
Set/A _sum+=333232
Echo=09/09/2016, 10:23:22.56, firefox.exe, 333232K 1>>FirefoxDumpResult.csv
::------------------------------------------------------------------------------
You have clearly altered the script; please make sure, at least, that line five in the script you're using matches the one I posted.

How to list a process that contains spaces in the name

I'm making a batch that checks whether the process is active and if it is closed it ... the point is that when the process has spaces in the name it is not found.
Set "EXE=Process name.exe">nul 2>&1
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% Taskkill /F /IM "%EXE%" >nul 2>&1
This should handle the spaces in the code, depending on what the first tasklist prints:
Set "EXE=Process name.exe"
FOR /F "delims=" %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF /i "%%x" == "%EXE%" Taskkill /F /IM "%EXE%" >nul 2>&1
This is another way of doing it:
Set "EXE=Process name.exe"
tasklist|find /i "%EXE%" >nul && Taskkill /F /IM "%EXE%" >nul 2>&1
and this is functionally equivalent: it will only kill the task if it exists.
Set "EXE=Process name.exe"
Taskkill /F /IM "%EXE%" >nul 2>&1
wmic process where name="Process name.exe" get Name,ProcessId
?
Try, putting quotes around your process name like
Set EXE="Process name.exe" >nul 2>&1

Resources