如何在不继承子进程中的句柄的情况下使用"start"命令?

Aar*_*ron 5 windows cmd batch-file

这是一个说明我问题的最小例子:

:: test.bat
@echo off
call test2.bat 2>&1 | findstr foo
echo done calling test2

:: test2.bat
@echo off
start /B notepad >NUL
echo done starting child process
Run Code Online (Sandbox Code Playgroud)

在此示例中,在记事本关闭之前,findstr将无法完成,可能是因为记事本已从父cmd进程继承了stdout.如何修改test2.bat以便test.bat不挂起?

dbe*_*ham 4

我相信我可以在没有任何批处理文件的情况下说明问题。只有在关闭 notepad.exe 后,以下管道构造才会完成:

start notepad | findstr "^"
Run Code Online (Sandbox Code Playgroud)

我希望记事本将在一个与 cmd.exe 管道完全分离的新进程中执行,并且唯一通过管道传输的内容是 START 命令本身的输出(没有)。START 命令“立即”返回,但只要记事本运行,管道就保持打开状态。

我不知道是否是继承的 I/O 流使管道保持打开状态,但我可以证明记事本进程正在以可能是问题根源的方式继承流。这基本上与Issue with output redirection in batch中提出的问题相同。

这是一个简单的批处理脚本:test.bat

@echo off
call :test >nul
echo done calling test.bat
exit /b

:test
start notepad
Run Code Online (Sandbox Code Playgroud)

请注意,当记事本启动时,由于 .stdout 的重定向,stdout 已被重定向到 NUL call :test >nul

现在看看当我从命令行发出一系列命令时会发生什么,从 test.bat 开始,将 stdout 重定向到文件:

C:\test>test.bat >test.txt

C:\test>REM The command returns immediately, and notepad remains open

C:\test>type test.txt
done calling test.bat

C:\test>echo This fails as long as notepad remains open >test.txt
The process cannot access the file because it is being used by another process.

C:\test>type test.txt
done calling test.bat

C:\test>REM Now I close notepad

C:\test>echo This works once notepad is closed >test.txt

C:\test>type test.txt
This works once notepad is closed

C:\test>
Run Code Online (Sandbox Code Playgroud)

我至今仍对这种行为感到震惊。这似乎完全不合逻辑。

我认为没有任何方法可以阻止 cmd.exe 的流继承。

也许 Harry Johnston 的建议可以解决这个问题(来自问题评论):“我会编写一个非常简单的可执行文件来调用 CreateProcess 并禁用继承。”