How to sort the (possibly empty) output of a for loop?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

How to sort the (possibly empty) output of a for loop?

#1 Post by jfl » 10 Nov 2016 09:12

In the same script, but independent from the previous question:
I have a routine that parses the output of another command, then outputs results on stdout:

Code: Select all

for /f "delims=" %%l in ('that command') do (
  :# Parse each line (non trivial, requires many lines of code)
  echo digested results for that line
)

Now I need the output sorted, before using it in another routine.
So I tried this seemingly simple change:

Code: Select all

(for /f "delims=" %%l in ('that command') do (
  :# Parse each line
  echo digested results for that line
)) | sort

Works fine, except in one case: If 'that command' outputs nothing (which IS a valid output), cmd.exe crashes!

Any idea on how to do that, even when there's no data?

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: How to sort the (possibly empty) output of a for loop?

#2 Post by Squashman » 10 Nov 2016 09:33

jfl wrote:Works fine, except in one case: If 'that command' outputs nothing (which IS a valid output), cmd.exe crashes!

Any idea on how to do that, even when there's no data?


If that were true would not these scripts cause cmd.exe to crash.

Code: Select all

@echo off
(for /f "delims=" %%G in ('type nul') do (
  echo %%G
)) | sort
pause


Code: Select all

@echo off
(for /f "delims=" %%G in ('dir /b H:\empty') do (
  echo %%G
)) | sort
pause

jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

Re: How to sort the (possibly empty) output of a for loop?

#3 Post by jfl » 10 Nov 2016 09:45

Try this in a cmd console if you don't believe me :-)

Code: Select all

(for %i in () do @echo.%i) | sort

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: How to sort the (possibly empty) output of a for loop?

#4 Post by Squashman » 10 Nov 2016 10:02

jfl wrote:Try this in a cmd console if you don't believe me :-)

Code: Select all

(for %i in () do @echo.%i) | sort

But now you are changing your example.

jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

Re: How to sort the (possibly empty) output of a for loop?

#5 Post by jfl » 10 Nov 2016 10:07

No, it's the same: I just simplified it to show the horrible things that happens when the for loop is run 0 times.

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: How to sort the (possibly empty) output of a for loop?

#6 Post by Squashman » 10 Nov 2016 10:16

jfl wrote:No, it's the same: I just simplified it to show the horrible things that happens when the for loop is run 0 times.

Having an empty set is not the same as having no output from a command.

jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

Re: How to sort the (possibly empty) output of a for loop?

#7 Post by jfl » 10 Nov 2016 11:05

OK, let me rephrase this in more details:
  • My goal is to filter line-by-line the output of an outside command, then sort the output of that filtering, then send the sorted output to another batch block for further operations.
  • I'm hitting a severe cmd.exe bug when the output of that outside command is empty: cmd crashes!
  • While trying to debug this, I noticed the same cmd bug actually occurs for ANY for loop that's executed 0 times and piped into something else. My initial problem is just a special case of this: When 'command' has no output, then the for /f loop runs 0 times. I only mentioned that as a simple way to demonstrate how cmd crashes. (Which is frightfully simple to reproduce!)
  • I'm not interested in fixing all cmd.exe for loops that commit suicide. I'm interested in finding a work around suitable for use in my initial use case.

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: How to sort the (possibly empty) output of a for loop?

#8 Post by Aacini » 10 Nov 2016 11:24

This does not crash:

Code: Select all

(cmd /C "for %i in () do @echo.%i") | sort

Antonio

jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

Re: How to sort the (possibly empty) output of a for loop?

#9 Post by jfl » 10 Nov 2016 11:42

Well it definitely does on mine :shock:

Meanwhile, I've found the workaround I was looking for. The idea is to append an extra line with uniquely formatted data that cannot be part of the real data, sort everything, then filter-out that extra data. Equivalent to this test:

Code: Select all

(for %n in (LINE1 LINE3 LINE2 REMOVE_THIS) do @echo.%n) | sort | findstr /v REMOVE_THIS

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: How to sort the (possibly empty) output of a for loop?

#10 Post by Squashman » 10 Nov 2016 11:51

Aacini wrote:This does not crash:

Code: Select all

(cmd /C "for %i in () do @echo.%i") | sort

Antonio

jfl wrote:Well it definitely does on mine :shock:

Tested successfully on Windows 7 Pro from the cmd prompt and batch file.

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: How to sort the (possibly empty) output of a for loop?

#11 Post by Squashman » 10 Nov 2016 12:04

jfl wrote:
  • I'm not interested in fixing all cmd.exe for loops that commit suicide. I'm interested in finding a work around suitable for use in my initial use case.

Your initial use case was using a FOR /F that was actually running a command within the IN clause but now you changed it to a FOR command with an empty IN clause.

Your last example had no empty IN clause so it most definitely will never crash.

jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

Re: How to sort the (possibly empty) output of a for loop?

#12 Post by jfl » 10 Nov 2016 12:06

I just tried that on several other machines, and indeed it does not crash on any of them. :?
The only thing unique about mine is that's it's a laptop with Windows 10 build 14393.
(A beta build I installed for getting the Ubuntu Linux subsystem)
This could be a bug in that particular version?
I have no other Windows 10 system at hand right now.

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: How to sort the (possibly empty) output of a for loop?

#13 Post by Squashman » 10 Nov 2016 15:11

jfl wrote:The only thing unique about mine is that's it's a laptop with Windows 10 build 14393.
(A beta build I installed for getting the Ubuntu Linux subsystem)

Why are you still running the beta? That was released a normal updated to Windows 10 months ago.

jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

Re: How to sort the (possibly empty) output of a for loop?

#14 Post by jfl » 11 Nov 2016 04:20

I just checked on my wife's computer. It is also running build 14393. And I've never customized this one.
So, contrary to what I told you, my build is not a beta anymore. It was a beta obtained through the "slow ring" (supposedly less risky than the "fast ring"), but apparently has since been updated to the Windows 10 "anniversary update" that everybody should now have.
And the bad news is that on her computer, the 0-times for loop crashes as well. :(
Everybody will have to implement workarounds for this case in their scripts. :cry:

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: How to sort the (possibly empty) output of a for loop?

#15 Post by jeb » 11 Nov 2016 06:07

I suppose you tested different things.

I retested it on Win7x64

Code: Select all

for /F %%i in ("") do echo empty | more
echo 1. Works

(for /F %%i in ("") do echo empty) | more
echo 2. Works

(for /F %%i in ('type nul') do echo empty) | more
echo 3. Works

for %%a in () do echo empty | more
echo 4. Works

timeout /t 2
(for %%a in () do echo empty) | more
echo 5. Crashes

Only sample #5 crashes.
I expect the same results on any Windows version.

Where is the problem?
First I tried to examine it with the cmdcmdline trick, but it crashes always when the EMPTY-FOR is present, independent if the code would be executed at all.

Code: Select all

(
call showCmdCmdLine.bat
exit
for %%a in () do echo CRASH WITHOUT EXECUTION
) | more

It crashes, even when the FOR loop will be REMarked
(SET LF=^
%=EMPTY=%
)
set "XREM=REM "
(
call showCmdCmdLine.bat
%%XREM%% for %%a in () do echo empty ^%%LF%%%%LF%% echo After comment
) | more


The problem isn't the execution of the block, it's crashes while preparing for starting the new cmd.exe instance.
I tested it with

Code: Select all

echo dummy > log1.log | (for %%a in () do echo empty) | echo dummy > log2.log

In this case only log1.log will be created, the second cmd.exe instance will never be invoked.

But how to get an empty "standard" FOR-LOOP to work?

It's obvious :D
The parser needs a none empty expression that is empty :!:

Code: Select all

( for %%a in (%%__CD__:~0^,0%%) do echo empty ) | more

The invoked cmd instance will be called with:
cmdcmdline: C:\Windows\system32\cmd.exe /S /D /c" ( FOR %a in (%__CD__:~0,0%) do echo empty )"

And as long as __CD__ exists, then zero characters from the front are in the most cases empty.

Post Reply