Як я можу повторювати та надсилати консольний вихід у файл у сценарії bat?


136

У мене є пакетний сценарій, який виконує завдання і відправляє вихід у текстовий файл. Чи є спосіб відобразити висновок і у вікні консолі?

Наприклад:

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

Чи є спосіб вивести dirдисплей у вікно консолі, а також помістити його в текстовий файл?


Тут пояснюються переспрямовування, які ви можете зробити, та кілька прикладів. <br> Сподіваюся, це допомагає :)
emoSTN


Зауважте, @Vadzim, що питання, задане 2 лютого 2009 року о 16:38, не можна вважати дублікатом запитання, заданого майже через три місяці, 28 квітня 2009 р. О 06:32.
Компо

Відповіді:


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

У цьому прикладі "стандартний вихід" перейде до файлів.txt, всі помилки будуть у err.txt, а stream3 перейде у Nothing.txt (DIR не використовує потік 3).
Stream0 is STDIN
Stream1 is STDOUT
Stream2 is STDERR
Stream3-9 не використовуються

Але що станеться, якщо ви спробуєте перенаправити один і той же потік кілька разів?

dir > files.txt > two.txt

"Може бути тільки один", і це завжди останній!
Отже, це дорівнює dir> two.txt

Гаразд, є одна додаткова можливість - перенаправити потік на інший.

dir 1>files.txt 2>&1 

2> & 1 перенаправляє stream2 до stream1 та 1> files.txt перенаправляє всі до файлів.txt .
Тут важливий порядок!

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

різні. Перший перенаправляє всі (STDOUT та STDERR) до NUL,
але другий рядок перенаправляє STDOUT на NUL, а STDERR на "порожній" STDOUT.

Як один з висновків, очевидно, чому приклади Отавіо Дечіо та Андінорманка не можуть працювати.

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

Обидва намагаються перенаправити stream1 два рази, але "Може бути лише один", і це завжди останній.
Так ви отримуєте

command 1>&1
dir 1>&2

І в першому зразку перенаправлення потоку1 на потік1 не дозволено (і не дуже корисно).

Сподіваюся, це допомагає.


24
Так що неможливо з рідною оболонкою windows
фантастична історія

7
@fantastory Це можливо, побачити це велике рішення dbenham Windows , пакета: команда «трійник»
Джеб

97
Я не можу повірити, що я просто прочитав увесь цей пост, щоб дізнатися, що все це може бути узагальнено як "Ні".
Чарльз МакКелві

1
А як щодо другого механізму "обробляти дублювання"? Я експериментував 3<&2(зверніть увагу на LT замість GT), а потім 3>errors.txt. Але це закінчилося погано - усі наступні більш жорсткі виводи були захоплені 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: \
scriptpts

Я спробував це як в powerhell, так і в звичайній оболонці. 1>tee a.txtбуде перенаправляти stdout у файл, названий teeзамість виклику teeкоманди. Чи може хтось підтвердити, що ця відповідь працює на них?
мафу

@mafu Я можу це підтвердити.
Черно

@mafu Відповідь вище дещо неправильна. Ви повинні використовувати трубу "|" замість ">" у верхньому прикладі. Дивно, що в такому випадку в командному рядку було змішано порядок виводу STDOUT та STDERR. Нижній приклад для мене прекрасно працює.
Черно

Крім того, для мене було порушено завантаження sourceforge. Тут я знайшов альтернативного хоста: 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. Однак, якщо потрібен вихід у режимі реального часу, ви можете використовувати, наприклад, порт Windows для інструмента « трійник » для цього…
mousio

7

Для мене працювало рішення: dir> a.txt | введіть a.txt .


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

Ви повинні використовувати delims=замість цього.
scriptmastere02

3
command > file >&1

Це відбувається швидше, коли ви не записуєте дані на екран, оскільки ваш не заповнює буфер дерьмом, а швидше дозволяє вам запускати пакетну роботу. якщо ви налагоджуєте, я не використовував би синтаксис> файл.
Випадковий розробник

@andynormancx yup забув набрати це замість того, щоб вирізати та вставити з CMD.
Випадковий розробник

Я не міг змусити синтаксис працювати під командним рядком Windows і замість цього пішов із командою type.
JamesEggers

& 2 працює, проте файл зараз не створюється, коли я тестую його.
JamesEggers

5
якщо я не створюю файл "dir> file.txt> & 2", файл.txt не створюється. Виведення каталогу відображається в консолі, але файл не створюється. Файл створюється, коли "> & 2" немає.
JamesEggers

2

Якщо ви хочете додати замість заміни вихідного файлу, ви можете скористатися

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

або

dir 1>> files.txt 2>>&1

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

Якщо ви додасте змінну до повідомлення, обов'язково видаліть цитати в ній, перш ніж надсилати її в підпрограму, інакше вона може накрутити вашу партію. Звичайно, це працює лише на лунку.


ЯК ТАК! Мені це дуже подобається !! Я вніс три зміни, але, сподіваюся, вони вам сподобаються 1) Я використовую setlocal enabledelayedexpansionзамість лише setlocal 2) Я використовую затримку розширення для змінної logfile, тому >> !logfile!замість >> %logfile%підпрограми. Таким чином, він працює при виклику з блоку коду (наприклад, в операторі if). 3) Я видалив рядок "встановити повідомлення", оскільки немає необхідності в додатковій змінній. У нас це вже є, $~1тому я маю echo $~1для обох команд ехо.
Нейт

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 (корисно, якщо ви просто хочете трійник, а не весь набір утиліт Unix). Про це я дізнався з відповіді Davor на " Відображення виводу командного рядка Windows та перенаправлення його у файл , де ви також знайдете посилання на утиліти unix.


0

Рішення, яке надає "Томаш Р", ідеально підходить для запитання про ОП, і воно є в наявності.

Спробуйте: chkdsk c:> output.txt | введіть output.txt

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


-3

Я думаю, ви хочете щось подібне:

echo Your Msg> YourTxtFile.txt

Або якщо ви хочете новий рядок:

echo Your Msg>> YourTxtFile.txt

Ці команди чудово підходять для журналів.

Примітка. Іноді це виблискує і замінює весь текстовий файл на моєму комп’ютері.

Ще одна примітка: Якщо файл не існує, він створить файл.


1
ні, ОП хотів мати вихід у файл та на екран. Твій просто пише у файл. (І >це призначене для перезапису файлу використання. >>Для додавання )
Stephan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.