批量输出重定向问题 [英] Issue with output redirection in batch

查看:29
本文介绍了批量输出重定向问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a script a.cmd that calls another script b.cmd, and redirects its output. the called script, starts an executable that is never terminated. The output of the executable is redirected to its own log file. Simplified code:

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)正在运行.我没有排除这种行为,因为我认为只有启动命令本身的输出会被重定向到 LOG_FILE_NAME 日志文件,而实际运行 RunForEver.exe 可执行文件的其他进程的输出将被写入 ANOTHER_LOG_FILE_NAME.结果,a.cmd 中的第 5 行出错,拒绝访问 LOG_FILE_NAME.

The problem I'm encountering is that line 4 in b.cmd seems to grab a handle on the initial log file (LOG_FILE_NAME) because all b.cmd output is redirected to it, and the handle is not released while the executable (and the cmd that launched it) are running. I didn't except this behavior because I thought only the output of the start command itself will be redirected to the LOG_FILE_NAME log file, and the output from the other process that is actually running the RunForEver.exe executable will be written to the ANOTHER_LOG_FILE_NAME. As a result, line 5 in a.cmd errors out with access denied to LOG_FILE_NAME.

谁能解释一下这是怎么回事?有没有办法避免这种情况?

Could someone explain what's going on? Is there a way to avoid this?

我尝试从 b.cmd 内部将输出重定向到 LOG_FILE_NAME,但随后我在 b.cmd 的第 2 行收到访问被拒绝错误.

I tried doing the output redirection to LOG_FILE_NAME from inside b.cmd, but then I get the access denied error in line 2 of b.cmd.

提前致谢!

推荐答案

哇!这是一个迷人而令人不安的发现.

Wow! That is a fascinating and disturbing discovery.

我没有解释,但我有一个解决方案.

I don't have an explanation, but I do have a solution.

在永无止境的进程开始后,只需避免任何额外的重定向到 log.txt.这可以通过只重定向一次带括号的代码块来完成.

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

或者通过重定向 CALLed 子例程的输出.

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

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

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

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

Again, the same technique could be done using a CALL instead of a parenthesized block.

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

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

主进程和 STARTed 进程都暂停,因此我可以选择哪个进程先完成.如果 STARTed 进程在主进程之前终止,那么一切都按预期进行,主控制台窗口的以下输出证明了这一点.

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>

以下是如果我允许主进程在 STARTed 进程终止之前继续执行的示例:

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>

我发现这种行为令人不安的原因是我无法理解 STARTed 进程与 LOG1.TXT 有什么关系.到 START 命令执行时,所有标准输出都已重定向到 nul,所以我不明白新进程是如何知道 LOG1.TXT 的,更不用说它如何在其上建立排他锁了.echo ignore output 没有可检测的输出这一事实证明标准输出已成功重定向到 nul.

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.

这篇关于批量输出重定向问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆