1

I am trying to format the output of a command in JSON as such:

echo "patches" : {
set patches="wmic qfe get HotfixID"
for /f "skip=1" %%i in (' %patches% ') do (
    set /a count=count+1
    call echo "!count!" : "%%i",
)
echo }

Everything is fine until I hit the end of the list of patches where it reads the line after the last patch and then prints "".

How can I make it stop when it is supposed to?

If possible, I would like to avoid using text files.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
KH17
  • 111
  • 11
  • 2
    Inside the `for /f` loop, place another one `for /f "delims=" %%j in ("%%i") do` and use `%%j` in your `echo`; since `wmic` returns Unicode output and `for /f` is not perfect for handling that, `for /f` outputs artefacts like orphaned carriage-returns, leading to the effect you encounter; placing another `for /f` loop inside and hence double-processing each item removes such artefacts... – aschipfl Jun 08 '16 at 15:20
  • there is a [bunch of different methods](http://stackoverflow.com/search?q=wmic+line+endings) to get around those `wmic` line endings. Although I think, the second `for` is the most generic of them. – Stephan Jun 08 '16 at 16:29
  • Yes, @Stephan, but the double-`for /f`-loop method is the simplest and most secure one as it can handle strings with any sequences of special characters... (I know you can query another item and dismiss it later, which is as secure, but this is not so generic as it works only for `/TABLE` output but not for `/VALUE` output...) – aschipfl Jun 08 '16 at 16:31

2 Answers2

5

Inside the for /f loop, place another one:

for /f "skip=1" %%i in ('%patches%') do for /f "delims=" %%j in ("%%i") do (
    rem // use `%%j` in the loop body
)

The wmic command returns Unicode output. Since for /f is not perfect for handling such, it produces artefacts like orphaned carriage-returns (CR), leading to the effect you encounter (the last line does not appear empty to your for /f %%i loop as it contains such a CR; remember that for /f skips lines that are really empty). Placing another for /f loop inside and hence double-processing each item removes such artefacts.

Here is the fixed script:

echo "patches" : {
set "patches=wmic qfe get HotfixID"
for /f "skip=1" %%i in ('%patches%') do for /f "delims=" %%j in ("%%i") do (
    set /a count=count+1
    echo "!count!" : "%%j",
)
echo }

Since I did not get the purpose of the call command, I simply removed it.


The double-parsing method is actually credited to dbenham -- see his answer to Why is the FOR /f loop in this batch script evaluating a blank line? and also his external article WMIC and FOR /F : A fix for the trailing <CR> problem.

Community
  • 1
  • 1
aschipfl
  • 33,626
  • 12
  • 54
  • 99
1

Skipping last empty line of WMIC command output in batch

The simplest solution is to use findstr to remove the blank lines:

for /f "skip=1" %%i in ('%patches% ^| findstr /r /v "^$"')

No extra for loop required.


Further Reading

DavidPostill
  • 7,734
  • 9
  • 41
  • 60