Wow! That is a fascinating and disturbing discovery.
I don't have an explanation, but I do have a solution.
Simply avoid any additional redirection to log.txt after the never ending process has started. That can be done by redirecting a parenthesized block of code just once.
@ECHO OFF
SET LOG_FILE_NAME="log.txt"
>>%LOG_FILE_NAME% 2>&1 (
CALL b.cmd
ECHO returned to a.cmd
)
EXIT /B 0
Or by redirecting the output of a CALLed subroutine instead.
@ECHO OFF
SET LOG_FILE_NAME="log.txt"
call :redirected >>%LOG_FILE_NAME% 2>&1
EXIT /B 0
:redirected
CALL b.cmd
ECHO returned to a.cmd
exit /b
If you need to selectively redirect output in a.cmd, then redirect a non-standard stream to your file just once, and then within the block, selectively redirect output to the non-standard stream.
@ECHO OFF
SET LOG_FILE_NAME="log.txt"
3>>%LOG_FILE_NAME% (
echo normal output that is not redirected
CALL b.cmd >&3 2>&1
ECHO returned to a.cmd >&3 2>&1
)
EXIT /B 0
Again, the same technique could be done using a CALL instead of a parenthesized block.
I've developed a simple, self contained TEST.BAT script that anyone can run to demonstrate the problem. I called it TEST.BAT on my machine.
@echo off
del log*.txt 2>nul
echo begin >>LOG1.TXT 2>&1
call :test >>LOG1.TXT 2>&1
echo end >>LOG1.TXT 2>&1
exit /b
:test
echo before start
>nul 2>&1 (
echo ignored output
start "" cmd /c "echo start result >LOG2.TXT 2>&1 & pause >con"
)
echo after start
pause >con
exit /b
Both the master and the STARTed process are paused, thus allowing me to choose which process finishes first. If the STARTed process terminates before the master, then everything works as expected, as evidenced by the following output from the main console window.
C:est>test
Press any key to continue . . .
C:est>type log*
LOG1.TXT
begin
before start
after start
end
LOG2.TXT
start result
C:est>
Here is an example of what happens if I allow the main process to continue before the STARTed process terminates:
C:est>test
Press any key to continue . . .
The process cannot access the file because it is being used by another process.
C:est>type log*
LOG1.TXT
begin
before start
after start
LOG2.TXT
start result
C:est>
The reason I find the behavior disturbing is that I can't fathom how the STARTed process has any relationship with LOG1.TXT. By the time the START command executes, all standard output has been redirected to nul, so I don't understand how the new process knows about LOG1.TXT, let alone how it establishes an exclusive lock on it. The fact that echo ignored output
has no detectable output is proof that the standard output has been successfully redirected to nul.