Как отобразить и отправить консольный вывод в файл в сценарии bat?

136

У меня есть пакетный скрипт, который выполняет задачу и отправляет вывод в текстовый файл. Есть ли способ отобразить вывод в окне консоли?

Например:

c:\Windows>dir > windows-dir.txt

Есть ли способ получить вывод dirотображения в окне консоли, а также поместить его в текстовый файл?

JamesEggers
источник
Здесь объясняются перенаправления, которые вы можете сделать, и некоторые примеры. <br> Надеюсь, это поможет :)
emoSTN
Обратите внимание, @Vadzim, что вопрос, заданный 2 февраля 2009 года в 16:38, не может считаться дубликатом вопроса, заданного почти три месяца спустя 28 апреля 2009 года в 06:32.
Compo

Ответы:

216

Нет, вы не можете с чистым перенаправлением.
Но с некоторыми трюками (например, tee.bat ) вы можете.

Я пытаюсь объяснить перенаправление немного.

Вы перенаправляете один из десяти потоков с помощью > file или <file.
Это неважно, если перенаправление происходит до или после команды, поэтому эти две строки почти одинаковы.

dir > file.txt
> file.txt dir

Перенаправление в этом примере является только ярлыком для 1> , это означает, что поток 1 (STDOUT) будет перенаправлен.
Таким образом, вы можете перенаправить любой поток, добавив перед ним число, например 2> err.txt, и также можно перенаправить несколько потоков в одну строку.

dir 1> files.txt 2> err.txt 3> nothing.txt

В этом примере «стандартный вывод» будет помещен в файл files.txt, все ошибки будут в файле err.txt, а stream3 - в none.txt (DIR не использует поток 3).
Stream0 - STDIN
Stream1 - STDOUT
Stream2 - STDERR
Stream3-9 не используются

Но что произойдет, если вы попытаетесь перенаправить один и тот же поток несколько раз?

dir > files.txt > two.txt

«Может быть только один», и он всегда последний!
Так что он равен dir> two.txt

Хорошо, есть одна дополнительная возможность, перенаправление потока в другой поток.

dir 1>files.txt 2>&1 

2> & 1 перенаправляет stream2 в stream1, а 1> files.txt перенаправляет все в files.txt .
Порядок важен здесь!

dir ... 1>nul 2>&1
dir ... 2>&1 1>nul

разные. Первая перенаправляет все (STDOUT и STDERR) в NUL,
но вторая строка перенаправляет STDOUT в NUL и STDERR в «пустой» STDOUT.

В качестве одного из выводов очевидно, что примеры Otávio Décio и andynormancx не работают.

command > file >&1
dir > file.txt >&2

Оба пытаются перенаправить stream1 два раза, но «может быть только один», и это всегда последний.
Итак, вы получаете

command 1>&1
dir 1>&2

И в первом примере перенаправление stream1 на stream1 не разрешено (и не очень полезно).

Надеюсь, поможет.

Джеб
источник
24
Так что это невозможно с родной оболочкой Windows
фантастика
7
@fantastory Возможно, вы увидите это отличное решение для Windows
jeb
97
Я не могу поверить, что я просто прочитал весь этот пост, чтобы узнать, что все это можно обобщить как «Нет».
Чарльз МакКелви
1
А как насчет второго механизма «обработки дублирования»? Я экспериментировал с 3<&2(обратите внимание на LT вместо GT), а затем 3>errors.txt. Но это плохо кончилось - весь последующий вывод stderr был записан errors.txt(то есть - из других команд!).
Томаш Гандор
Вы могли бы использовать for /f "delims=" %%v in ('dir') do echo %%v>>file.txtхотя.
scriptmastere02
32

Просто используйте версию для Windows UNIX tee (находится по адресу http://unxutils.sourceforge.net ) следующим образом:

mycommand > tee outpu_file.txt

Если вам также нужен выход STDERR, используйте следующее. Сочетает в себе выход STDERR в STDOUT (первичный поток).
2>&1

mycommand 2>&1 | tee output_file.txt
расширенная сеть переходов
источник
3
PowerShell Tee-Object предлагает аналогичные функциональные возможности . Get-Process | Tee-Object -file c: \ scripts \ test.txt
Кевин Оби,
Я пробовал это как в PowerShell, так и в обычной оболочке. 1>tee a.txtперенаправит стандартный вывод в файл с именем teeвместо вызова teeкоманды. Кто-нибудь может подтвердить, что этот ответ работает для них?
Мафу
@mafu Я могу это подтвердить.
Cerno
@mafu Ответ выше слегка неверен. Вы должны использовать трубу "|" вместо ">" в верхнем примере. Как ни странно, порядок вывода STDOUT и STDERR был перепутан в командной строке в этом случае. Нижний пример прекрасно работает для меня.
Черно
Кроме того, загрузка исходного кода для меня была нарушена. Я нашел альтернативный хост здесь: wzw.tum.de/public-html/syring/win32/UnxUtilsDist.html (Университет Мюнхена)
Черно,
9

Если вам не нужен вывод в режиме реального времени (то есть, когда программа его пишет), вы можете добавить

type windows-dir.txt

после этой строки.

Марк Пим
источник
или на одной и той же линии (полезно в командной строке): dir > windows-dir.txt & type windows-dir.txt. Это также относится и к блокам: ( echo %date% <NL> echo %username% <NL> echo %time% <NL> pause>CON )>test.txt & type test.txt. Однако, если выход требуется в режиме реального времени, вы можете использовать , например , через окно порт тройника инструмента , который ...
mousio
7

Решение, которое работало для меня, было: dir> a.txt | введите a.txt .

NSPKUWCExi2pr8wVoGNk
источник
2
Это работает с командой с низким выходом. С большой командой вывода это не работает, потому что показывает только первый буфер. Он запрашивает вывод в реальном времени при сохранении вывода в файл журнала.
NetVicious
Было бы проблематично, если бы вы использовали >> вместо>
Nime Cloud
6

Да, есть способ показать вывод одной команды на консоли (экране) и в файле. Используя ваш пример, используйте ...

@ECHO OFF
FOR /F "tokens=*" %%I IN ('DIR') DO ECHO %%I & ECHO %%I>>windows-dir.txt

Детальное объяснение:

Команда FORанализирует вывод команды или текста в переменную, на которую можно ссылаться несколько раз.

Для такой команды, как DIR /B, заключите в одинарные кавычки, как показано в примере ниже. Замените DIR /Bтекст желаемой командой.

FOR /F "tokens=*" %%I IN ('DIR /B') DO ECHO %%I & ECHO %%I>>FILE.TXT

Для отображения текста заключите текст в двойные кавычки, как показано в примере ниже.

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO ECHO %%I & ECHO %%I>>FILE.TXT

... и с переносом строк ...

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO (
  ECHO %%I & ECHO %%I>>FILE.TXT
)

Если у вас есть моменты, когда вы хотите, чтобы вывод выводился только на консоли (экран), и другие разы, отправленные только в файл, и другие разы, отправляемые в оба, укажите условие «DO» цикла FOR, используя переменную, как показано ниже с помощью %TOECHOWHERE%.

@ECHO OFF
FOR %%I IN (TRUE FALSE) DO (
  FOR %%J IN (TRUE FALSE) DO (
    SET TOSCREEN=%%I & SET TOFILE=%%J & CALL :Runit)
)
GOTO :Finish

:Runit
  REM Both TOSCREEN and TOFILE get assigned a trailing space in the FOR loops
  REM above when the FOR loops are evaluating the first item in the list,
  REM "TRUE".  So, the first value of TOSCREEN is "TRUE " (with a trailing
  REM space), the second value is "FALSE" (no trailing or leading space).
  REM Adding the ": =" text after "TOSCREEN" tells the command processor to
  REM remove all spaces from the value in the "TOSCREEN" variable.
  IF "%TOSCREEN: =%"=="TRUE" (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=On screen, and in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I & ECHO %%I>>FILE.TXT"
        ) ELSE (
          SET TEXT=On screen, not in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I"
      )
    ) ELSE (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=Not on screen, but in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>>FILE.txt"
        ) ELSE (
          SET TEXT=Not on screen, nor in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>NUL"
      )
  )
  FOR /F "tokens=*" %%I IN ("%TEXT%") DO %TOECHOWHERE:~1,-1%
GOTO :eof

:Finish
  ECHO Finished [this text to console (screen) only].
  PAUSE
Amazinate
источник
Вы должны использовать delims=вместо этого.
scriptmastere02
3
command > file >&1
Otávio Décio
источник
Это быстрее, когда вы не выводите данные на экран, поскольку вы не заполняете буфер дерьмом, а скорее позволяете запускать пакетное задание. если вы отлаживаете, я бы не использовал синтаксис> файла.
Случайный разработчик
@andynormancx ага забыл набрать это вместо вырезать и вставить из CMD.
Случайный разработчик
Я не мог заставить синтаксис работать в командной строке Windows, и вместо этого пошел с командой типа.
JamesEggers
& 2 действительно работает, однако файл теперь не создается, когда я его тестирую.
JamesEggers
5
если я делаю "dir> file.txt> & 2" file.txt не создается. Вывод каталога отображается в консоли, но файл не создается. Файл создается, когда "> & 2" отсутствует.
JamesEggers
2

Если вы хотите добавить вместо замены выходной файл, вы можете использовать

dir 1>> files.txt 2>> err.txt

или

dir 1>> files.txt 2>>&1
Jochen
источник
2

Мой вариант был такой:

Создайте подпрограмму, которая принимает сообщение и автоматизирует процесс отправки его как в консоль, так и в файл журнала.

setlocal
set logfile=logfile.log

call :screenandlog "%DATE% %TIME% This message goes to the screen and to the log"    

goto :eof

:screenandlog
set message=%~1
echo %message% & echo %message% >> %logfile%
exit /b

Если вы добавляете переменную к сообщению, обязательно удалите кавычки в нем, прежде чем отправить его в подпрограмму, иначе он может испортить вашу партию. Конечно, это работает только для эха.

JPZ
источник
ВАУ ДА! Мне действительно это нравится!! Я сделал три изменения, хотя, надеюсь, они вам понравятся. 1) Я использую setlocal enabledelayedexpansionвместо просто setlocal 2) Я использую отложенное расширение для переменной logfile, >> !logfile!а не >> %logfile%внутри подпрограммы. Таким образом, он работает, когда вызывается из блока кода (как внутри оператора if). 3) Я удалил строку «set message», потому что нет необходимости в дополнительной переменной. У нас уже есть, $~1так что я имею echo $~1для обеих команд эха.
Nate
2

Я сделал простую консоль C #, которая может обрабатывать вывод в режиме реального времени на экран cmd и журнал

class Tee
{
    static int Main(string[] args)
    {
        try
        {
            string logFilePath = Path.GetFullPath(args[0]);

            using (StreamWriter writer = new StreamWriter(logFilePath, true))
            {
                for (int value; (value = Console.In.Read()) != -1;)
                {
                    var word = Char.ConvertFromUtf32(value);
                    Console.Write(word);
                    writer.Write(word);
                }
            }
        }
        catch (Exception)
        {
            return 1;
        }
        return 0;
    }
}

Использование командного файла такое же, как использование Unix tee

foo | tee xxx.log

А вот репозиторий, в который входит Tee.exe, если у вас нет инструмента для компиляции https://github.com/iamshiao/Tee

Круг Сяо
источник
1

Мне нравится ответ atn, но его загрузка была не такой тривиальной, как wintee , которая также имеет открытый исходный код и дает только функциональность tee (полезно, если вы просто хотите использовать tee, а не весь набор утилит unix). Я узнал об этом из ответа Давора на Отображение вывода командной строки Windows и перенаправление его в файл , где вы также найдете ссылку на утилиты Unix.

шалфей
источник
0

Решение, предоставленное «Tomas R», идеально подходит для вопроса ОП и доступно изначально.

Попробуйте: chkdsk c:> output.txt | введите output.txt

Вывод этой команды включает в себя процент выполнения, который последовательно выводится в файл, следовательно, он будет выглядеть немного грязно (т.е. текст будет добавляться по мере продвижения). Это не происходит с битами, которые выводятся на STDOUT (экран). Так будет, если вы просто выполните ту же команду без перенаправления.

J0N
источник
-3

Я думаю, что вы хотите что-то вроде этого:

echo Your Msg> YourTxtFile.txt

Или, если вы хотите новую строку:

echo Your Msg>> YourTxtFile.txt

Эти команды отлично подходят для журналов.

Примечание. Это иногда приводит к сбоям и замене всего текстового файла на моем компьютере.

Другое примечание: если файл не существует, он создаст файл.

Gladius125
источник
1
нет, OP хотел иметь вывод в файл и на экране. Ваш просто пишет в файл. (И >это предназначено для перезаписи файла использование. >>Для добавления )
Stephan