Parsing the output of wmic in shell script

2020-04-30 02:35发布

问题:

I am trying to parse the output of WMIC and then to get the PID.

My script is as following:

@echo off

setLocal enableExtensions enableDelayedExpansion

FOR /F "tokens=1* delims=" %%A IN ('"wmic process where(name="java.exe") get ProcessID,commandline| FINDSTR /v "CommandLine" | FINDSTR "TestServer""') DO (
     set "line=%%A"
     @REM echo "%%A"
     for /F "tokens=* delims= " %%C in ("%%A") do (
         echo "%%C"
         echo "%%D"
  )
)

The output is as follows:

"java  com.test.TestServer                                       7560       "
"%D"
"java  com.test.TestServer                                       7380       "
"%D"

My target here is to grab the Process ID.

I have tried with space as the delims in the FOR loop. Yet no luck.

So my question is how to format the columns of the WMIC and to get the columns?

回答1:

WMIC uses a subset of SQL syntax. You can functionally put the FINDSTR tests in the WMIC WHERE clause by using the LIKE operator with % as the wildcard. Since it is in a batch script, the % needs to be doubled.

It is much easier to parse out the ProcessID since the CommandLine value is no longer needed in the WMIC output. I added the SessionID to put an unused value at the end to make it easier to parse the value without worrying about the unwanted carriage return character that FOR /F somehow introduces when it converts the WMIC unicode output into ANSI.

@echo off
setlocal
set "pid="
for /f "skip=1" %%A in (
  'wmic process where "name='java.exe' and commandline like '%%TestServer%%' and not commandline like '%%CommandLine%%'" get processid^, sessionid'
) do if not defined pid set "pid=%%A"

EDIT in response to question in comment

The FOR /F conversion of WMIC unicode also introduces unwanted lines that look to be empty but actually contain a single carriage return. In my code above I assume you expect a single line, so I use an IF DEFINED to effectively ignore the unwanted trailing "blank" line.

Another approach is needed if you expect multiple values. An extra FOR /F loop will remove the unwanted carriage returns, so the lines truly become empty and are therefore ignored. Based on your comment, it looks like you no longer need to ignore command lines that contain "CommandLine".

I don't know what you need to do with the values, so the code below simply echoes each value. I use SKIP=1 in place of piping the result through FINDSTR to avoid the header line.

@echo off
for /f "skip=1" %%A in (
  'wmic process where "name='java.exe' and commandline like '%%TestServer%%'" get processid'
) do for /f %%B in ("%%A") do echo %%B


回答2:

The delims parameter will be ignored when using tokens=*

As you need the third token, you should use token=3



回答3:

This worked on my system to get the PID of the single running process.

@echo off
FOR /F %%A IN ('"wmic process where name="java.exe" get ProcessID,commandline |findstr [0-9] " ') DO echo "%%A"
pause


回答4:

for /f "tokens=1*delims==" %%a in ('wmic process where 'name^="java.exe" AND CommandLine like "%%TestServer%%"' get ProcessID /format:list^|find /i "ProcessID"') do set "ProcessID=%%b"
echo %ProcessID%