批处理中的输出重定向问题 [英] Issue with output redirection in batch

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

问题描述

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



a.cmd:

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

[3] REM启动b.cmd重定向所有输出
[4 ] CALL b.cmd>> %LOG_FILE_NAME%2>& 1
[5] ECHO返回到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重定向所有输出
[5] START CMD / CRunForEver.exe>%ANOTHER_LOG_FILE_NAME%2& 1
[6] ECHO b.cmd执行完成
[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,但是我得到访问拒绝错误在第2行b .cmd。



提前感谢!

解决方案

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



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



在永不停止进程开始后,只需避免对log.txt的任何其他重定向。这可以通过重定向括号内的代码块一次来完成。

  @ECHO OFF 
SET LOG_FILE_NAME =log .txt

>>%LOG_FILE_NAME%2& 1(
CALL b.cmd
ECHO返回a.cmd

EXIT / B 0

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

  @ECHO OFF 
SET LOG_FILE_NAME =log.txt

call:redirected> LOG_FILE_NAME%2>& 1
EXIT / B 0

:重定向
CALL b.cmd
ECHO返回到a.cmd
退出/ b

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

  @ECHO OFF 
SET LOG_FILE_NAME =log.txt

3>>%LOG_FILE_NAME%(
回显未重定向的正常输出
CALL b.cmd>& 3 2> ;& 1
ECHO返回到a.cmd>& 3 2>& 1

EXIT / B 0
pre>

再次,使用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
startcmd / cecho start result> LOG2.TXT 2>& 1& pause> con

echo after start
pause> con
exit / b

主程序和STARTed进程都暂停,该过程首先完成。如果STARTed进程在master之前终止,那么一切都按预期工作,如主控台窗口的以下输出所示。

  C:\test> test 
按任意键继续。 。 。

C:\test> type log *

LOG1.TXT


开始
开始前
开始后
结束

LOG2.TXT


开始结果

C:\test>

这里是一个例子,如果我允许主进程在STARTed进程终止之前继续:

  C:\test> test 
按任意键继续。 。 。
进程无法访问该文件,因为它正被另一个进程使用。

C:\test> type log *

LOG1.TXT


开始
开始前
开始后

LOG2.TXT


开始结果

C:\test>

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


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

(Line numbers were added for convenience)

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?

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.

Thanks in advance!

解决方案

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:\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>

Here is an example of what happens if I allow the main process to continue before the STARTed process terminates:

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>

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天全站免登陆