批量输出重定向问题

时间:2013-12-30 23:55:35

标签: cmd io-redirection

我有一个脚本a.cmd,它调用另一个脚本b.cmd,并重定向其输出。被调用的脚本,启动永不终止的可执行文件。可执行文件的输出重定向到其自己的日志文件。简化代码:

a.cmd:

[1] @ECHO OFF
[2] SET LOG_FILE_NAME="log.txt"

[3] REM Start the b.cmd redirecting all output
[4] CALL b.cmd >> %LOG_FILE_NAME% 2>&1
[5] ECHO returned to a.cmd >> %LOG_FILE_NAME% 2>&1
[6] EXIT /B 0

b.cmd:

[1] @ECHO OFF

[2] SET ANOTHER_LOG_FILE_NAME="log2.txt"
[4] ECHO RunForEver.exe redirecting all output
[5] START CMD /C "RunForEver.exe >> %ANOTHER_LOG_FILE_NAME% 2>&1"
[6] ECHO b.cmd execution complete
[7] EXIT /B 0

(为方便起见添加了行号)

我遇到的问题是b.cmd中的第4行似乎抓住了初始日志文件(LOG_FILE_NAME)上的句柄,因为所有b.cmd输出都被重定向到它,并且在可执行文件时没有释放句柄(以及启动它的cmd)正在运行。 我没有这个行为,因为我认为只有start命令本身的输出将被重定向到LOG_FILE_NAME日志文件,而实际运行RunForEver.exe可执行文件的另一个进程的输出将被写入ANOTHER_LOG_FILE_NAME。 因此,a.cmd中的第5行错误输出,拒绝访问LOG_FILE_NAME。

有人可以解释发生了什么吗?有没有办法避免这种情况?

我尝试从b.cmd中将输出重定向到LOG_FILE_NAME,但后来我在b.cmd的第2行中得到了拒绝访问错误。

提前致谢!

1 个答案:

答案 0 :(得分:7)

哇!这是一个令人着迷和令人不安的发现。

我没有解释,但我确实有解决方案。

在永不结束的进程开始后,简单地避免对log.txt进行任何额外的重定向。这可以通过将带括号的代码块重定向一次来完成。

@ECHO OFF
SET LOG_FILE_NAME="log.txt"

>>%LOG_FILE_NAME% 2>&1 (
  CALL b.cmd
  ECHO returned to a.cmd
)
EXIT /B 0

或者改为重定向CALLed子例程的输出。

@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

如果您需要有选择地重定向a.cmd中的输出,那么只需将非标准流重定向到您的文件一次,然后在该块内选择性地将输出重定向到非标准流。

@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

同样,可以使用CALL而不是带括号的块来完成相同的技术。


我开发了一个简单的,自包含的TEST.BAT脚本,任何人都可以运行来演示这个问题。我在我的机器上称它为TEST.BAT。

@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

主要和STARTed进程都暂停,因此允许我选择首先完成哪个进程。如果STARTed进程在master之前终止,那么一切都按预期工作,如主控制台窗口的以下输出所示。

C:\test>test
Press any key to continue . . .

C:\test>type log*

LOG1.TXT


begin
before start
after start
end

LOG2.TXT


start result

C:\test>

以下是在STARTed进程终止之前允许主进程继续时会发生什么情况的示例:

C:\test>test
Press any key to continue . . .
The process cannot access the file because it is being used by another process.

C:\test>type log*

LOG1.TXT


begin
before start
after start

LOG2.TXT


start result

C:\test>

我发现行为令人不安的原因是我无法理解STARTed进程与LOG1.TXT有何关系。当START命令执行时,所有标准输出都被重定向到nul,所以我不明白新进程如何知道LOG1.TXT,更不用说它如何建立对它的独占锁定。 echo ignored output没有可检测输出的事实证明标准输出已成功重定向到nul。

相关问题