从批处理文件中重定向输出

我用一些简单的命令创建了一个批处理文件,用于从系统中收集信息。批处理文件包含获取时间、 IP 信息、用户等的命令。

我将所有命令组装在一个批处理文件中,它运行,但是我希望在运行批处理文件时将结果输出到一个文本文件(log)中。是否有一个命令,我可以添加到批处理,这样做?

请记住,我不希望从 cmd 运行批处理,然后重定向输出; 如果可能的话,我希望从批处理内部重定向输出。

377384 次浏览
echo some output >"your logfile"

或者

(
echo some output
echo more output
)>"Your logfile"

应该够了。

如果您想要 APPEND的输出,使用 >>而不是 >.>将启动一个新的日志文件。

简单朴素的方法很慢,因为它多次打开并定位到文件结束的文件指针。

@echo off
command1 >output.txt
command2 >>output.txt
...
commandN >>output.txt

更好的方法——更容易编写,而且更快,因为文件只打开和定位一次。

@echo off
>output.txt (
command1
command2
...
commandN
)

另一个好的和快速的方法,只打开和定位文件一次

@echo off
call :sub >output.txt
exit /b


:sub
command1
command2
...
commandN

编辑2020-04-17

您可能需要不时地重复写入两个或多个文件。您可能还希望在屏幕上显示不同的消息。通过重定向到带括号的块或子例程之外的未定义句柄,然后使用 &表示法引用已打开的文件,仍然可以有效地完成这项工作。

call :sub 9>File1.txt 8>File2.txt
exit /b


:sub
echo Screen message 1
>&9 echo File 1 message 1
>&8 echo File 2 message 1
echo Screen message 2
>&9 echo File 1 message 2
>&8 echo File 2 message 2
exit /b

我选择按相反的顺序使用句柄9和8,因为这样在同一个命令上执行多个重定向时,更有可能避免由于 微软重定向实现设计缺陷而导致的潜在永久重定向。这是非常不可能的,但是如果您足够努力的话,即使是这种方法也可能暴露 bug。如果您阶段重定向比您保证避免问题。

3>File1.txt ( 4>File2.txt call :sub)
exit /b


:sub
etc.
@echo off
>output.txt (
echo Checking your system infor, Please wating...


systeminfo | findstr /c:"Host Name"
systeminfo | findstr /c:"Domain"


ipconfig /all | find "Physical Address"


ipconfig | find "IPv4"
ipconfig | find "Default Gateway"


)


@pause

如果您希望同时执行 out 和 err 流重定向

dir >> a.txt 2>&1

有一个很酷的小程序可以用来将输出重定向到文件和控制台

some_command  ^|  TEE.BAT  [ -a ]  filename

@ECHO OFF
:: Check Windows version
IF NOT "%OS%"=="Windows_NT" GOTO Syntax


:: Keep variables local
SETLOCAL


:: Check command line arguments
SET Append=0
IF /I [%1]==[-a] (
SET Append=1
SHIFT
)
IF     [%1]==[] GOTO Syntax
IF NOT [%2]==[] GOTO Syntax


:: Test for invalid wildcards
SET Counter=0
FOR /F %%A IN ('DIR /A /B %1 2^>NUL') DO CALL :Count "%%~fA"
IF %Counter% GTR 1 (
SET Counter=
GOTO Syntax
)


:: A valid filename seems to have been specified
SET File=%1


:: Check if a directory with the specified name exists
DIR /AD %File% >NUL 2>NUL
IF NOT ERRORLEVEL 1 (
SET File=
GOTO Syntax
)


:: Specify /Y switch for Windows 2000 / XP COPY command
SET Y=
VER | FIND "Windows NT" > NUL
IF ERRORLEVEL 1 SET Y=/Y


:: Flush existing file or create new one if -a wasn't specified
IF %Append%==0 (COPY %Y% NUL %File% > NUL 2>&1)


:: Actual TEE
FOR /F "tokens=1* delims=]" %%A IN ('FIND /N /V ""') DO (
>  CON    ECHO.%%B
>> %File% ECHO.%%B
)


:: Done
ENDLOCAL
GOTO:EOF


:Count
SET /A Counter += 1
SET File=%1
GOTO:EOF


:Syntax
ECHO.
ECHO Tee.bat,  Version 2.11a for Windows NT 4 / 2000 / XP
ECHO Display text on screen and redirect it to a file simultaneously
ECHO.
IF NOT "%OS%"=="Windows_NT" ECHO Usage:  some_command  ³  TEE.BAT  [ -a ]  filename
IF NOT "%OS%"=="Windows_NT" GOTO Skip
ECHO Usage:  some_command  ^|  TEE.BAT  [ -a ]  filename
:Skip
ECHO.
ECHO Where:  "some_command" is the command whose output should be redirected
ECHO         "filename"     is the file the output should be redirected to
ECHO         -a             appends the output of the command to the file,
ECHO                        rather than overwriting the file
ECHO.
ECHO Written by Rob van der Woude
ECHO http://www.robvanderwoude.com
ECHO Modified by Kees Couprie
ECHO http://kees.couprie.org
ECHO and Andrew Cameron

我知道这是一篇较早的文章,但是有人会在谷歌搜索中偶然发现它,而且看起来 OP 在评论中提出的一些问题并没有得到特别的解决。另外,请对我宽容,因为这是我的第一个答案张贴在 SO。:)

要使用动态生成的文件名将输出重定向到一个文件,我的 go-To (read: fast & Dirty)方法是@dbenham 提供的第二种解决方案。举个例子:

@echo off
> filename_prefix-%DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.log (
echo Your Name Here
echo Beginning Date/Time: %DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.log
REM do some stuff here
echo Your Name Here
echo Ending Date/Time: %DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.log
)

将创建一个类似于您在此 目标目录中文件的屏幕截图中看到的文件

它将包含这个输出:

Your Name Here
Beginning Date/Time: 2016-09-16_141048.log
Your Name Here
Ending Date/Time: 2016-09-16_141048.log

还要记住,这个解决方案是依赖于区域设置的,所以在使用它时要小心。

@echo OFF
[your command] >> [Your log file name].txt

我在批处理文件中使用了上面的命令,它可以工作。在日志文件中,它显示了我的命令的结果。

将这两行添加到批处理文件顶部附近,之后的所有 stdout 和 stderr 都将被重定向到 log.txt:

if not "%1"=="STDOUT_TO_FILE"  %0 STDOUT_TO_FILE %*  >log.txt 2>&1
shift /1

在输入中出现“有毒”字符的情况下,这可能会失败。 考虑像这样的输入 IsAnIn ^ ^ ^ put 是理解发生了什么的好方法。 当然有一个规则,输入字符串必须在双引号内,但我有一种感觉,这个规则是一个有效的规则,只有当输入的意义是一个位置在 NTFS 分区(也许这是一个规则的网址,我不确定)。 但是它当然不是任意输入字符串的规则(它是“一种好的做法”,但是你不能用它来计数)。

在批处理文件的底部添加以下代码行,将获取 CMD 窗口中显示的所有内容,并导出到一个文本文件中:

powershell -c "$wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys('^a')
powershell -c "$wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys('^c')
powershell Get-Clipboard > MyLog.txt

它基本上执行 选择所有-> 复印到剪贴板上-> 粘贴到文本文件中